/*
  RepoBridge stylesheet.

  Hand-written, one file, no build step, no framework -- the constraint that has held for
  ten milestones. What changed in this pass is that the values are now *named* rather than
  scattered: every colour, space, radius and type size is a custom property at the top, so
  the page has a rhythm instead of a collection of one-off numbers.

  **The rule this pass works under.** Several elements on these pages exist because a
  specific failure was found live and recorded in `smoke.md` -- the scope lines, the state
  flags, the accounting identity, the provenance block, the coverage sentences, the
  diagnostics banner. Restyling them is allowed. Making them quieter is not. Where this
  file touches one, it makes it *more* prominent, never less, and the wording is untouched
  throughout: `tests/test_ui.py` pins the sentences, and it passed unchanged.
*/

/* ==========================================================================
   tokens
   ========================================================================== */

:root {
  /* surfaces, coolest to warmest */
  --bg:            #f4f6f8;
  --surface:       #ffffff;
  --surface-sunk:  #f8fafc;
  --border:        #e3e8ee;
  --border-strong: #cfd7e0;

  /* text */
  --text:        #1c2430;
  --text-muted:  #5b6672;
  --text-faint:  #8794a1;

  --accent:       #1f6feb;
  --accent-hover: #1856bd;
  --accent-tint:  #eaf1fd;

  /* status tints. Each pairs a background, a border and a text colour dark enough to
     read on the background -- the text colour is what carries the meaning when the
     background is invisible (high contrast mode, printing, a colour-blind reader). */
  --ok-bg:     #e8f5ec;  --ok-border:     #b3ddc1;  --ok-text:     #125c2a;
  --warn-bg:   #fdf4e3;  --warn-border:   #ecd5a4;  --warn-text:   #7a4a05;
  --bad-bg:    #fdecec;  --bad-border:    #f0bfbf;  --bad-text:    #8a1b1b;
  --info-bg:   #eef1f6;  --info-border:   #d3dae5;  --info-text:   #414d5f;

  /* spacing scale, 4px base */
  --s1: 0.25rem;  --s2: 0.5rem;   --s3: 0.75rem;
  --s4: 1rem;     --s5: 1.5rem;   --s6: 2rem;     --s7: 3rem;

  --radius:    8px;
  --radius-sm: 5px;

  --shadow:    0 1px 2px rgba(20, 30, 45, 0.05);
  --shadow-md: 0 2px 8px rgba(20, 30, 45, 0.07);

  --font: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

/* ==========================================================================
   base
   ========================================================================== */

* { box-sizing: border-box; }

body {
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.6;
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

/* One type scale, so headings relate to each other instead of each picking a size. */
h1, h2, h3 {
  margin: 0 0 var(--s2);
  line-height: 1.25;
  letter-spacing: -0.011em;
  font-weight: 650;
}
h1 { font-size: 1.15rem; letter-spacing: -0.02em; }
h2 { font-size: 1.3rem; }
h3 {
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  margin-top: var(--s5);
}
p { margin: 0 0 var(--s3); }
p:last-child { margin-bottom: 0; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-hover); }

.muted { color: var(--text-muted); }
.small { font-size: 0.83rem; }
.mono {
  font-family: var(--font-mono);
  font-size: 0.88em;
  word-break: break-word;
}
code.mono {
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.08em 0.35em;
}

/* ==========================================================================
   layout
   ========================================================================== */

header {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: var(--s3) var(--s5);
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  flex-wrap: wrap;
}
header h1 { margin: 0; }
header h1 a { color: var(--text); text-decoration: none; }
header h1 a:hover { color: var(--accent); }
header p { margin: 0; color: var(--text-faint); font-size: 0.83rem; }
header hr { display: none; }   /* the border-bottom does this job now */

main {
  padding: var(--s5) var(--s5) var(--s7);
  max-width: 1040px;
  margin: 0 auto;
}
main:focus { outline: none; }

footer {
  border-top: 1px solid var(--border);
  padding: var(--s4) var(--s5);
  color: var(--text-faint);
  text-align: center;
}
footer hr { display: none; }

/* Sections are cards. This is the single change that gives the pages a rhythm: content
   was previously a flat stack with only whitespace separating one idea from the next. */
section, .card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--s4) var(--s5);
  margin: 0 0 var(--s4);
}
.card-title { margin-bottom: var(--s3); }

/* ==========================================================================
   tables
   ========================================================================== */

table {
  border-collapse: collapse;
  width: 100%;
  background: transparent;
  margin: var(--s3) 0;
  font-size: 0.92rem;
}

thead th {
  background: transparent;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-faint);
  border-bottom: 1px solid var(--border-strong);
  padding: 0 var(--s3) var(--s2);
  text-align: left;
  white-space: nowrap;
}

td {
  padding: var(--s3);
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td { background: var(--surface-sunk); }

th { text-align: left; padding: var(--s3); vertical-align: top; }
/* key/value tables (the Repository block) rather than column tables */
tbody th {
  font-weight: 600;
  color: var(--text-muted);
  font-size: 0.88rem;
  white-space: nowrap;
  width: 11rem;
  border-bottom: 1px solid var(--border);
}

td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.tree td { font-size: 0.88rem; }

/* ==========================================================================
   badges and state flags
   ========================================================================== */

.badge {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 650;
  border: 1px solid transparent;
  white-space: nowrap;
  vertical-align: middle;
}

.badge-selected   { background: var(--ok-bg);   color: var(--ok-text);   border-color: var(--ok-border); }
.badge-skipped    { background: var(--warn-bg); color: var(--warn-text); border-color: var(--warn-border); }
.badge-directory  { background: var(--info-bg); color: var(--info-text); border-color: var(--info-border); }
.badge-failed     { background: var(--bad-bg);  color: var(--bad-text);  border-color: var(--bad-border); }
.badge-completed  { background: var(--ok-bg);   color: var(--ok-text);   border-color: var(--ok-border); }
.badge-degraded   { background: var(--warn-bg); color: var(--warn-text); border-color: var(--warn-border); }
.badge-chunk      { background: var(--accent-tint); color: #1c4a94; border-color: #c7dbf8; }

/*
  State flags: CAPPED, TRUNCATED, READ ERRORS, NO SUMMARY.

  These carry meaning that colour must not carry alone, so they are deliberately the
  loudest small element on the page: a square-cornered block against the pill-shaped
  badges beside them, uppercase, tracked out, bolder, and with a text colour dark enough
  to read with no background at all. Distinguishable from a status badge by *shape*
  before colour, which is the point -- a reader scanning the runs list needs to see that
  two `completed` runs are not the same kind of completed.
*/
.flag {
  display: inline-block;
  padding: 0.1rem 0.4rem;
  border-radius: 3px;
  font-size: 0.66rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border: 1px solid;
  vertical-align: middle;
  white-space: nowrap;
  margin-left: 0.15rem;
}
.flag-warn  { background: var(--warn-bg); color: var(--warn-text); border-color: var(--warn-border); }
.flag-bad   { background: var(--bad-bg);  color: var(--bad-text);  border-color: var(--bad-border); }
.flag-muted { background: var(--info-bg); color: var(--info-text); border-color: var(--info-border); }

/* ==========================================================================
   notices
   ========================================================================== */

.notice {
  padding: var(--s3) var(--s4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  border-left: 4px solid var(--border-strong);
  margin: var(--s3) 0;
  background: var(--surface-sunk);
}
.notice strong { font-weight: 700; }
.notice p { margin: var(--s2) 0 0; }
.notice ul { margin: var(--s2) 0 0; padding-left: 1.15rem; }
.notice li { margin: 0.15rem 0; }

.notice-error {
  border-color: var(--bad-border);
  border-left-color: #d13438;
  background: var(--bad-bg);
  color: var(--bad-text);
}
.notice-warn {
  border-color: var(--warn-border);
  border-left-color: #c88a04;
  background: var(--warn-bg);
  color: var(--warn-text);
}
.notice-error .mono, .notice-warn .mono { color: inherit; }

/* The shared-demo banner: informational, so neither the warning amber nor the error red.
   It states a condition of the instance, not a problem with a run. */
.notice-demo {
  border-color: #c7dbf8;
  border-left-color: var(--accent);
  background: var(--accent-tint);
  color: #17365f;
}

.limit-list { margin: var(--s2) 0 var(--s3); padding-left: 1.15rem; }
.limit-list li { margin: 0.2rem 0; }

.warn-inline {
  display: inline-block;
  color: var(--warn-text);
  background: var(--warn-bg);
  border: 1px solid var(--warn-border);
  padding: 0.05rem 0.4rem;
  border-radius: var(--radius-sm);
  font-weight: 600;
}

/* ==========================================================================
   scope line: how much of the whole is on screen

   Every page has one and it is load-bearing -- "showing 100 of 37,393" is the difference
   between a page a reader can trust and one they cannot. It is styled as a distinct
   band rather than a paragraph so it reads as a statement about the page, not as prose
   inside it, and it sits above the content it qualifies.
   ========================================================================== */

.scope {
  background: var(--accent-tint);
  border: 1px solid #cfe0fa;
  border-radius: var(--radius-sm);
  padding: var(--s3) var(--s4);
  margin: var(--s3) 0 var(--s4);
  font-size: 0.93rem;
  color: #1a3f77;
}
.scope strong { font-weight: 700; color: #12305c; }
.scope .warn-inline { margin-left: var(--s1); }

/* ==========================================================================
   counts and filters
   ========================================================================== */

.counts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  margin: var(--s4) 0;
}

.count-card {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  align-items: flex-start;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--s3) var(--s4);
  min-width: 7rem;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.12s, box-shadow 0.12s;
}
a.count-card:hover { border-color: var(--accent); box-shadow: var(--shadow-md); }
.count-card .count {
  font-size: 1.6rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.count-card .badge { white-space: nowrap; }
.count-card.level-partial  { border-color: var(--warn-border); }
.count-card.level-degraded { border-color: #f0c48a; }
.count-card.level-error    { border-color: var(--bad-border); }

.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
  margin: var(--s3) 0;
}

.chip {
  display: inline-block;
  padding: 0.15rem 0.65rem;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  font-size: 0.82rem;
  text-decoration: none;
  color: var(--text-muted);
  white-space: nowrap;
}
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip-on {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 600;
}
.chip-on:hover { color: #fff; }

/* ==========================================================================
   forms
   ========================================================================== */

form label { font-weight: 550; }

input, select {
  font: inherit;
  font-size: 0.93rem;
  padding: 0.45rem 0.6rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
}
input::placeholder { color: var(--text-faint); }
input:hover, select:hover { border-color: #b6c1cd; }

button {
  font: inherit;
  font-size: 0.93rem;
  font-weight: 600;
  padding: 0.45rem 1.1rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
  transition: background 0.12s;
}
button:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
button:disabled {
  background: #9dbaea;
  border-color: #9dbaea;
  cursor: progress;
}

input.wide { width: 100%; max-width: 30rem; }

.field { margin: 0 0 var(--s4); }
.field label { display: block; margin-bottom: var(--s1); }
.field .small { display: block; margin-top: var(--s1); }

.field-inline { display: inline-flex; align-items: center; gap: var(--s1); }
.field-inline label { font-size: 0.82rem; color: var(--text-muted); font-weight: 600; }

.form-actions { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }

/* ==========================================================================
   configuration panel
   ========================================================================== */

.key-list { list-style: none; margin: 0 0 var(--s3); padding: 0; }

.key-row {
  display: flex;
  gap: var(--s3);
  align-items: flex-start;
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--border);
}
.key-row:last-child { border-bottom: none; }

/* The state reads as a word first. "not set" is amber rather than red on purpose: it is
   a setting a person has not chosen yet, not a fault. */
.key-state {
  flex: 0 0 auto;
  min-width: 6.5rem;
  text-align: center;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.15rem 0.45rem;
  border-radius: 3px;
  border: 1px solid;
  margin-top: 0.1rem;
}
.key-on  .key-state { background: var(--ok-bg);   color: var(--ok-text);   border-color: var(--ok-border); }
.key-off .key-state { background: var(--warn-bg); color: var(--warn-text); border-color: var(--warn-border); }

.key-body { flex: 1; min-width: 0; }
.key-name { margin: 0 0 var(--s1); font-weight: 600; }
.key-body p { margin: 0 0 var(--s1); }
.key-body p:last-child { margin-bottom: 0; }

/* ==========================================================================
   run navigation
   ========================================================================== */

.run-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
  margin: 0 0 var(--s4);
  padding: var(--s2) var(--s4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  font-size: 0.9rem;
}
.run-nav a { text-decoration: none; }
.run-nav a:hover { text-decoration: underline; }
.run-nav-sep { color: var(--border-strong); }
/* weight and colour, plus `aria-current` in the markup: never colour alone */
.run-nav-here { font-weight: 700; color: var(--text); }
.run-nav-repo { margin-left: auto; font-size: 0.85rem; }

/* ==========================================================================
   summary
   ========================================================================== */

.summary-text {
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--s2) var(--s4);
  line-height: 1.65;
  font-size: 0.97rem;
}
.summary-text p { margin: var(--s3) 0; }

/* ==========================================================================
   pager
   ========================================================================== */

.pager {
  display: flex;
  align-items: center;
  gap: var(--s4);
  margin: var(--s4) 0 0;
}

.button-link {
  display: inline-block;
  padding: 0.35rem 0.85rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  text-decoration: none;
  color: var(--accent);
  font-size: 0.9rem;
  font-weight: 550;
}
.button-link:hover { border-color: var(--accent); background: var(--accent-tint); }
.button-link.disabled {
  color: var(--text-faint);
  background: var(--surface-sunk);
  border-color: var(--border);
}

.row-links a { margin-right: var(--s3); font-size: 0.85rem; white-space: nowrap; }

/* ==========================================================================
   diagnostics timeline

   Level is carried by a left border rather than a background wash: a timeline is read
   top to bottom, and a stripe scans faster than a fill.
   ========================================================================== */

.timeline { list-style: none; padding: 0; margin: var(--s4) 0 0; }
.timeline-event {
  border: 1px solid var(--border);
  border-left: 4px solid var(--border-strong);
  background: var(--surface-sunk);
  padding: var(--s3) var(--s4);
  margin: 0 0 var(--s2);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.timeline-event.level-info     { border-left-color: #b7c4d6; }
.timeline-event.level-partial  { border-left-color: #c88a04; background: #fdfaf2; }
.timeline-event.level-degraded { border-left-color: #d97706; background: #fdf5ec; }
.timeline-event.level-error    { border-left-color: #d13438; background: #fdefef; }

.timeline-head { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.timeline-message { margin: var(--s2) 0 0; }
.timeline-time { margin-left: auto; font-variant-numeric: tabular-nums; }
.stage-name {
  color: var(--text-muted);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.badge-level-info     { background: var(--info-bg); color: var(--info-text); border-color: var(--info-border); }
.badge-level-partial  { background: var(--warn-bg); color: var(--warn-text); border-color: var(--warn-border); }
.badge-level-degraded { background: #fde8d3;        color: #8a4b06;         border-color: #f0c48a; }
.badge-level-error    { background: var(--bad-bg);  color: var(--bad-text);  border-color: var(--bad-border); }

.details {
  display: grid;
  grid-template-columns: minmax(9rem, auto) 1fr;
  gap: 0.1rem var(--s3);
  margin: var(--s2) 0 0;
  font-size: 0.83rem;
}
.details dt { color: var(--text-faint); font-weight: 600; }
.details dd { margin: 0; word-break: break-word; }

/* ==========================================================================
   accessibility
   ========================================================================== */

/* Visible to assistive tech, not on screen. Used for table captions and for the per-row
   link labels, so a column of identical "files" links is distinguishable out of context. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--surface);
  padding: var(--s2) var(--s4);
  border: 2px solid var(--accent);
  border-radius: 0 0 var(--radius-sm) 0;
  z-index: 10;
}
.skip-link:focus { left: 0; }

/* One visible focus treatment for everything interactive. Before this the app relied on
   whatever each browser drew by default, which on links styled `text-decoration: none`
   -- the chips, the count cards, the pager, the nav -- was easy to lose. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
.chip:focus-visible,
.button-link:focus-visible,
.count-card:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ==========================================================================
   responsive
   ========================================================================== */

@media (max-width: 760px) {
  body { font-size: 14.5px; }
  header { padding: var(--s3) var(--s4); }
  main { padding: var(--s4) var(--s3) var(--s6); }
  section, .card { padding: var(--s4); }

  .run-nav-repo { margin-left: 0; width: 100%; }
  .field-inline { width: 100%; }
  .field-inline input, .field-inline select { flex: 1; min-width: 0; }
  .field-inline label { min-width: 4rem; }

  .key-row { flex-direction: column; gap: var(--s2); }
  .key-state { min-width: 0; }

  tbody th { width: auto; }
  table { font-size: 0.86rem; }
  td, th { padding: var(--s2); }
  .details { grid-template-columns: 1fr; }
  .details dt { margin-top: var(--s1); }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
