/*
 * The QuietCI app. Tokens are in tokens.css (docs/20-design/03-design-system.md).
 *
 * Here are exactly the six components from §2 of the design system and the
 * layout rules from §3. No UI kit: §5 explicitly says "do not hand over a
 * component library", because anything beyond six components and four screens
 * we will not maintain.
 *
 * The status-color rule (see tokens.css) is followed literally here: the
 * --passed/--failed/--flaky classes appear only on status elements.
 */

/* ─────────────────────────────── base ─────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--fs-body);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; line-height: var(--lh-tight); font-weight: 600; }
.h1 { font-size: var(--fs-h1); }
.h2 { font-size: var(--fs-h2); }
.h3 { font-size: var(--fs-h3); }
p { margin: 0; }
a { color: var(--info); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Data from the test is monospaced. Everything we wrote is regular.
   The reader must tell data from our conclusion at a glance
   (03-design-system §1.2). */
.mono { font-family: var(--font-mono); font-size: var(--fs-small); line-height: var(--lh-mono); }

.muted { color: var(--text-muted); }
.small { font-size: var(--fs-small); }
.micro { font-size: var(--fs-micro); color: var(--text-muted); }
.right { text-align: right; }
.nowrap { white-space: nowrap; }

/* Numbers and time are right-aligned (03-design-system §3). */
.num { text-align: right; font-variant-numeric: tabular-nums; }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--surface); color: var(--text);
  padding: var(--space-2) var(--space-4); border: 1px solid var(--border-strong);
  border-radius: var(--radius);
}
.skip-link:focus { left: var(--space-4); top: var(--space-4); }

/* Focus is always visible: never `outline: none` without a replacement (§4). */
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}

/* ─────────────────────────────── shell ─────────────────────────────── */

.container {
  max-width: var(--maxw-content);
  margin: 0 auto;
  padding: var(--space-5) var(--space-5) var(--space-8);
}

.topbar {
  position: sticky; top: 0; z-index: 10;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.topbar__inner {
  max-width: var(--maxw-content); margin: 0 auto;
  display: flex; align-items: center; gap: var(--space-5);
  padding: var(--space-3) var(--space-5);
  min-height: 56px;
}
.brand {
  font-weight: 600; letter-spacing: .01em; color: var(--text);
  font-size: var(--fs-h3);
}
.brand:hover { text-decoration: none; }
.nav { display: flex; gap: var(--space-4); margin-left: var(--space-2); }
.nav a { color: var(--text-muted); font-size: var(--fs-small); }
.nav a[aria-current='page'] { color: var(--text); }
.topbar__spacer { flex: 1; }
.topbar__account { color: var(--text-muted); font-size: var(--fs-small); }

.page-head {
  display: flex; align-items: center; gap: var(--space-4);
  margin-bottom: var(--space-5); flex-wrap: wrap;
}
.page-head__grow { flex: 1; min-width: 0; }
.crumbs { color: var(--text-muted); font-size: var(--fs-small); margin-bottom: var(--space-2); }
.crumbs a { color: var(--text-muted); }

.section { margin-top: var(--space-6); }
.section__title {
  font-size: var(--fs-small); color: var(--text-muted);
  text-transform: none; margin-bottom: var(--space-3);
  display: flex; align-items: center; gap: var(--space-3);
}

/* ─────────────────────── 2.5 Table-panel ─────────────────────── */

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.panel--pad { padding: var(--space-5); }
.panel__row {
  display: flex; align-items: center; gap: var(--space-4);
  min-height: 40px; padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  color: inherit; text-decoration: none;
  transition: background var(--t-fast);
}
.panel__row:last-child { border-bottom: none; }
.panel__row:hover { background: var(--surface-hover); text-decoration: none; }
.panel__row--link { cursor: pointer; }
.panel__row--stack { flex-direction: column; align-items: stretch; gap: var(--space-1); }

/* ─────────────────────── 2.1 Status badge ─────────────────────── */
/* The product's main component. Icon + word are required: the status must
   be readable without color (§2.1, accessibility). */

.badge {
  display: inline-flex; align-items: center; gap: var(--space-1);
  height: 22px; padding: 2px 8px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: transparent;
  font-family: var(--font-mono); font-size: var(--fs-micro);
  line-height: 1; white-space: nowrap;
}
.badge--passed  { color: var(--passed);  border-color: color-mix(in srgb, var(--passed) 40%, transparent); }
.badge--failed  { color: var(--failed);  border-color: color-mix(in srgb, var(--failed) 40%, transparent); }
.badge--flaky   { color: var(--flaky);   border-color: color-mix(in srgb, var(--flaky) 40%, transparent); }
.badge--unknown { color: var(--unknown); border-color: color-mix(in srgb, var(--unknown) 40%, transparent); }
.badge--neutral { color: var(--text-muted); border-color: var(--border); }

/* Project indicator: only three states — ● green / ◐ running / ✗ red. */
.dot { font-size: var(--fs-h3); line-height: 1; }
.dot--passed  { color: var(--passed); }
.dot--failed  { color: var(--failed); }
.dot--running { color: var(--unknown); }
.dot--unknown { color: var(--text-muted); }

/* Triage verdict — uppercase, monospaced: the customer reads this first (§2.2). */
.verdict { font-family: var(--font-mono); font-size: var(--fs-micro); letter-spacing: .02em; }
.verdict--regression { color: var(--failed); }
.verdict--flaky      { color: var(--flaky); }
.verdict--selector,
.verdict--data       { color: var(--text-muted); }
.verdict--unknown    { color: var(--unknown); }

/* ─────────────────────── 2.2 Test row ─────────────────────── */
/* A design-system component. Not used yet: it is needed for the list of ALL
   tests in a run, and there is no such route in the API — screen 3 shows only
   failures (`.failure` below). The class is kept deliberately, because it is
   described in §2.2 of the design system, and "six components" is a
   requirement, not a set by taste. */

.test-row {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) 120px 64px;
  align-items: center; gap: var(--space-3);
  min-height: 40px; padding: var(--space-2) var(--space-4);
  border-bottom: 1px solid var(--border);
  color: inherit; text-decoration: none;
  transition: background var(--t-fast);
}
.test-row:last-child { border-bottom: none; }
.test-row:hover { background: var(--surface-hover); text-decoration: none; }
.test-row__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.test-row__file { color: var(--text-muted); }

/* The failure row on the run screen is wider: verdict, confidence, action. */
.failure {
  display: block; padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  color: inherit; text-decoration: none;
  transition: background var(--t-fast);
}
.failure:last-child { border-bottom: none; }
.failure:hover { background: var(--surface-hover); text-decoration: none; }
.failure__head { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.failure__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.failure__meta { display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-1); flex-wrap: wrap; }
.failure__why { margin-top: var(--space-2); color: var(--text-muted); font-size: var(--fs-small); max-width: var(--maxw-text); }
.failure__action { color: var(--text-muted); font-size: var(--fs-small); }

/* ─────────────────────── 2.3 Metric card ─────────────────────── */

.metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4); }
@media (max-width: 720px) { .metrics { grid-template-columns: 1fr; } }

.metric {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: var(--space-4);
}
.metric__label { font-size: var(--fs-small); color: var(--text-muted); }
.metric__value { font-size: var(--fs-h1); line-height: var(--lh-tight); margin-top: var(--space-1); font-variant-numeric: tabular-nums; }
.metric__was { font-size: var(--fs-small); color: var(--text-muted); margin-top: var(--space-1); }
.metric__delta { font-size: var(--fs-small); margin-top: var(--space-1); }
/* A delta is NOT a run status, so green/red here come from the utility palette,
   not from --passed/--failed. Otherwise an improvement in noise would look like
   "the test passed" and the status-color rule would be violated. */
.metric__delta--good { color: var(--info); }
.metric__delta--bad  { color: var(--text); }

/* ─────────────────────── 2.4 Buttons ─────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: 36px; padding: 8px 16px;
  border-radius: var(--radius); border: 1px solid transparent;
  font-family: inherit; font-size: 14px; font-weight: 500;
  cursor: pointer; text-decoration: none;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.btn:hover { text-decoration: none; }
.btn[disabled], .btn[aria-disabled='true'] { opacity: .5; cursor: not-allowed; }

.btn--primary   { background: var(--passed); color: var(--text-inverse); }
.btn--primary:hover { background: color-mix(in srgb, var(--passed) 88%, white); }
.btn--secondary { background: var(--surface); color: var(--text); border-color: var(--border-strong); }
.btn--secondary:hover { background: var(--surface-hover); }
.btn--ghost     { background: transparent; color: var(--text-muted); }
.btn--ghost:hover { color: var(--text); }
.btn--danger    { background: transparent; color: var(--failed); border-color: color-mix(in srgb, var(--failed) 40%, transparent); }
.btn--danger:hover { border-color: var(--failed); }

.btn-row { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: center; }

/* ─────────────────────── 2.6 Empty states ─────────────────────── */
/* The third state is the most important: "nothing happened" should look like
   success, not emptiness (§2.6). */

.empty { padding: var(--space-6) var(--space-5); text-align: center; }
.empty__title { font-size: var(--fs-h3); }
.empty__text { color: var(--text-muted); margin-top: var(--space-2); max-width: var(--maxw-text); margin-inline: auto; }
.empty__action { margin-top: var(--space-4); display: flex; justify-content: center; gap: var(--space-3); }

/* ─────────────────────── noise chart (screen 2) ─────────────────────── */

.chart { width: 100%; height: auto; display: block; }
.chart__axis { stroke: var(--border); stroke-width: 1; }
.chart__grid { stroke: var(--border); stroke-width: 1; stroke-dasharray: 2 4; opacity: .6; }
.chart__label { fill: var(--text-muted); font-size: 11px; font-family: var(--font-ui); }
/* The target line is a commitment, so it is always drawn (§02, screen 2).
   This is not a run status: the color is the utility --info, not --passed/--failed. */
.chart__target { stroke: var(--info); stroke-width: 1; stroke-dasharray: 4 4; }
.chart__line { fill: none; stroke: var(--text); stroke-width: 2; }
.chart__point { fill: var(--text); }
.chart__gap { stroke: var(--border-strong); stroke-width: 1; stroke-dasharray: 3 3; }

/* ─────────────────────── screenshot and test history (screen 4) ─────────────────────── */

/* The screenshot is the only artifact shown as an image: the others
   (trace, log, video) are downloaded as files. A width limit is mandatory:
   the screenshot is captured at full page resolution and without it would
   stretch the layout to its width. We do NOT limit the height — unlike the
   internal triage page, where a ceiling is needed so the verdict buttons do not
   slide off screen. Here the screenshot is the evidence: shrinking it would
   make it unreadable, and the full size opens on click. */
.shot {
  display: block; max-width: 100%; height: auto;
  border: 1px solid var(--border); border-radius: var(--radius);
  margin-bottom: var(--space-3); background: var(--bg);
}

/* Test history across runs. The ✓/✗ marks are the test's status in the run, so
   --passed/--failed are legitimate here (the same exception as `.dot` and `.badge`). */
.history { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); }
.history__sep { color: var(--text-muted); }
.history__run { color: var(--text); font-family: var(--font-mono); font-size: var(--fs-small); white-space: nowrap; }
.history__mark { font-weight: 600; }
.history__mark--passed { color: var(--passed); }
.history__mark--failed { color: var(--failed); }
.history__verdict { color: var(--text-muted); font-size: var(--fs-micro); margin-left: var(--space-1); letter-spacing: .02em; }

/* ─────────────────────── forms and odds and ends ─────────────────────── */

.field { display: flex; flex-direction: column; gap: var(--space-1); }
.field__label { font-size: var(--fs-small); color: var(--text-muted); }
.input {
  height: 36px; padding: 0 var(--space-3);
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  font-family: inherit; font-size: var(--fs-small);
}
textarea.input { height: auto; padding: var(--space-2) var(--space-3); font-family: var(--font-mono); }

.settings-grid { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: var(--space-4) var(--space-5); align-items: start; }
@media (max-width: 720px) { .settings-grid { grid-template-columns: 1fr; } }
.settings-grid__label { color: var(--text-muted); font-size: var(--fs-small); padding-top: var(--space-2); }

.check { display: inline-flex; align-items: center; gap: var(--space-2); margin-right: var(--space-4); }

.kv { display: flex; gap: var(--space-4); align-items: baseline; flex-wrap: wrap; }
.kv__k { color: var(--text-muted); font-size: var(--fs-small); }

.code-block {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--space-3); overflow-x: auto;
  font-family: var(--font-mono); font-size: var(--fs-small); line-height: var(--lh-mono);
  white-space: pre-wrap; word-break: break-word; margin: 0;
}

.alert {
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  padding: var(--space-3) var(--space-4); margin-bottom: var(--space-4);
  background: var(--surface); font-size: var(--fs-small);
}
.alert--error { border-color: color-mix(in srgb, var(--failed) 40%, transparent); }
.alert__title { font-weight: 600; }
.alert__detail { color: var(--text-muted); margin-top: var(--space-1); font-family: var(--font-mono); font-size: var(--fs-micro); }

.banner-verdict {
  display: flex; align-items: center; gap: var(--space-4);
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  padding: var(--space-4); margin-bottom: var(--space-5); background: var(--surface);
}
.banner-verdict__label { font-family: var(--font-mono); font-size: var(--fs-h3); letter-spacing: .04em; }
.banner-verdict--ready      .banner-verdict__label { color: var(--passed); }
.banner-verdict--not_ready  .banner-verdict__label { color: var(--failed); }
.banner-verdict--undecidable .banner-verdict__label { color: var(--unknown); }

.loading { color: var(--text-muted); padding: var(--space-6) 0; text-align: center; }
