/* agentfit.css — Engineer Brutalist design system.
 *
 * Single stylesheet. Every rule reads tokens; no hex literals
 * outside :root. Single typeface (IBM Plex Mono). System palette.
 * Hairline rules. ASCII score-bars.
 *
 * Spec: docs/brand/design-system.md
 * Voice + anti-patterns: docs/brand/brand-book.md
 *
 * Phase 34a (v1.3.0) — foundation only. No templates link to this
 * yet; the migration runs in phase 34b/c/d. The CSS lands first so
 * downstream phases never need to invent rules.
 */


/* ============================================================
 * 0. fonts — IBM Plex Mono, self-hosted, SIL OFL.
 *    Subsets: latin / latin-ext / cyrillic. (Plex Mono does not
 *    ship Greek glyphs; Vietnamese omitted.) The browser only
 *    downloads the subset whose unicode-range covers a rendered
 *    glyph — English pages pull ~45 KB total across 3 weights.
 *
 *    Box-drawing characters used by the score-bar (█ U+2588,
 *    ░ U+2591) live in Unicode block U+2580–U+259F which fontsource
 *    does not split into a named subset and which IS NOT covered
 *    by any unicode-range below. By design — these glyphs fall
 *    back to the system monospace stack (`ui-monospace`, `SF Mono`,
 *    `Cascadia Mono`, `Consolas`, `Liberation Mono`), all of which
 *    ship U+2580–U+259F at the same advance width as Plex Mono.
 *    The visible bar stays aligned across operating systems.
 *    Reviewer #4 cycle-2 finding: documented, not regressed.
 * ============================================================ */

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/PlexMono-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/PlexMono-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/PlexMono-400-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/static/fonts/PlexMono-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/static/fonts/PlexMono-500-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/static/fonts/PlexMono-500-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/static/fonts/PlexMono-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/static/fonts/PlexMono-700-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/static/fonts/PlexMono-700-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}


/* ============================================================
 * 1. tokens
 * ============================================================ */

:root {
  /* colour */
  --paper:  #FFFFFF;
  --ink:    #000000;
  --link:   #0000EE;
  --pass:   #16A34A;
  --fail:   #DC2626;
  --rule:   #000000;
  --mute:   #595959;
  /* admin accent — same as ink today; reserved for /admin scope */
  --accent-admin: #000000;

  /* type */
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono",
               "Cascadia Mono", "Consolas",
               "Liberation Mono", monospace;
  --fw-regular: 400;
  --fw-medium:  500;
  --fw-bold:    700;

  --fs-caption: 0.75rem;   /* 12px */
  --fs-body:    0.9375rem; /* 15px */
  --fs-lead:    1.0625rem; /* 17px */
  --fs-h3:      1.25rem;   /* 20px */
  --fs-h2:      1.5rem;    /* 24px */
  --fs-h1:      2rem;      /* 32px */
  --fs-display: 3.5rem;    /* 56px — score number */

  --lh-tight: 1;
  --lh-body:  1.5;
  --lh-loose: 1.7;

  /* spacing — character grid only */
  --sp-x:  1ch;
  --sp-y:  1lh;
  --sp-2y: 2lh;
  --sp-3y: 3lh;

  /* borders — px only on hairlines */
  --border-hair:  1px solid var(--rule);
  --border-rule:  2px solid var(--rule);
  --border-thick: 4px solid var(--rule);
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #000000;
    --ink:   #FFFFFF;
    --rule:  #FFFFFF;
    --mute:  #A6A6A6;
    /* #0000EE fails AA on black; bump to AA-compliant blue. */
    --link:  #6E8BFF;
  }
}


/* ============================================================
 * 2. base
 * ============================================================ */

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

html, body { font-family: var(--font-mono); }

body {
  max-width: 80ch;
  margin: 0 auto;
  padding: var(--sp-2y) var(--sp-x);
  background: var(--paper);
  color: var(--ink);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-regular);
}

.wide { max-width: 120ch; }

p { margin: var(--sp-y) 0; }

h1 { font-size: var(--fs-h1); font-weight: var(--fw-bold);
     line-height: var(--lh-tight); margin: var(--sp-2y) 0 var(--sp-y); }
h2 { font-size: var(--fs-h2); font-weight: var(--fw-bold);
     line-height: var(--lh-tight); margin: var(--sp-2y) 0 var(--sp-y); }
h3 { font-size: var(--fs-h3); font-weight: var(--fw-bold);
     line-height: var(--lh-tight); margin: var(--sp-y) 0; }
.lead    { font-size: var(--fs-lead); color: var(--ink); }
.caption { font-size: var(--fs-caption); color: var(--mute);
           text-transform: uppercase; letter-spacing: .04em; }


/* ============================================================
 * 3. links — visible underlines, no purple, invert on hover.
 * ============================================================ */

a            { color: var(--link); text-decoration: underline;
               text-underline-offset: 2px; }
a:visited    { color: var(--link); }
a:hover      { background: var(--link); color: var(--paper); }

:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }


/* ============================================================
 * 4. rule + layout helpers
 * ============================================================ */

.rule    { border: 0; border-top: var(--border-hair);
           margin: var(--sp-2y) 0; }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(40ch, 1fr));
  gap: var(--sp-y) var(--sp-x);
}


/* ============================================================
 * 5. components
 * ============================================================ */

/* score-bar — brand signature. ASCII characters in DOM; copy-paste
 * preserves them. .fill / .empty are spans so colour can apply. */
.scorebar          { font-variant-numeric: tabular-nums; }
.scorebar .row     { display: grid;
                     grid-template-columns: 4ch 22ch 14ch 4ch;
                     gap: 0 var(--sp-x);
                     align-items: baseline; }
.scorebar .id      { font-weight: var(--fw-bold); }
.scorebar .name    { color: var(--ink); }
.scorebar .bar     { white-space: pre; letter-spacing: 0; }
.scorebar .fill,
.scorebar .empty   { font-weight: var(--fw-medium); }
.scorebar .fill    { color: var(--pass); }
.scorebar .empty   { color: var(--mute); }
.scorebar .num     { text-align: right; font-weight: var(--fw-bold); }
.scorebar .row[data-band="fail"] .fill { color: var(--fail); }


/* score-display — the big 0-100 number. */
.scoredisplay     { font-size: var(--fs-display);
                    font-weight: var(--fw-bold);
                    line-height: var(--lh-tight);
                    font-variant-numeric: tabular-nums; }
.scoredisplay .of { font-size: var(--fs-h2); color: var(--mute);
                    font-weight: var(--fw-regular); }


/* kpi — single-stat block. */
.kpi             { padding: 0; }
.kpi .label      { font-size: var(--fs-caption);
                   text-transform: uppercase; letter-spacing: .04em;
                   color: var(--mute); }
.kpi .value      { font-size: var(--fs-display);
                   font-weight: var(--fw-bold);
                   line-height: var(--lh-tight);
                   font-variant-numeric: tabular-nums; }


/* table — borderless except hairlines. */
table          { width: 100%; border-collapse: collapse; }
thead          { border-top: var(--border-hair); }
th, td         { padding: 0 var(--sp-x);
                 border-bottom: var(--border-hair);
                 text-align: left; vertical-align: baseline;
                 line-height: var(--lh-loose); }
th             { font-weight: var(--fw-bold); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }


/* prompt — terminal-style shell line. The `$` ships in the text. */
.prompt {
  background: var(--paper);
  border-left: var(--border-rule);
  padding: 0 var(--sp-x);
  margin: var(--sp-y) 0;
  white-space: pre-wrap;
  word-break: break-all;
}


/* bracket-tag — inline status. Brackets are CHARACTERS, not boxes.
 *
 * Two semantics, do not conflate:
 *   - `tag-pass` / `tag-fail`: SCORE bands (≥90 / <50). 50-89 is
 *     the neutral band and uses NO class — `.tag` alone inherits
 *     `--ink` (the brand-book "neutral = ink, not grey" rule).
 *   - `tag-mute`: prose-context labels that are NOT scores —
 *     empty-state copy ("no audits in this window"), in-progress
 *     status badges ("pending", "running"). Grey on purpose. */
.tag         { font-weight: var(--fw-medium); white-space: nowrap; }
.tag-pass    { color: var(--pass); }
.tag-fail    { color: var(--fail); }
.tag-mute    { color: var(--mute); }


/* callout — quoted block, 2px left rule. No background. */
.callout {
  margin: var(--sp-y) 0;
  padding: 0 var(--sp-x);
  border-left: var(--border-rule);
  color: var(--ink);
}


/* search-form — inverted-ink button + bordered input. Used by
 * /browse/search, /browse landing search, and the homepage
 * audit-submission form. Promoted in Phase 34c from inline
 * style= snippets that lived in templates after 34b.
 *
 * input  : hairline border, paper background, ink text.
 * button : inverted — ink background, paper text.
 * gap    : 1ch character-grid. */
.search-form {
  display: flex;
  gap: var(--sp-x);
  margin: var(--sp-y) 0;
}
.search-form input,
.search-form button {
  font: inherit;
  line-height: var(--lh-loose);
  padding: 0 var(--sp-x);
}
.search-form input {
  flex: 1;
  border: var(--border-hair);
  background: var(--paper);
  color: var(--ink);
}
.search-form button {
  background: var(--ink);
  color: var(--paper);
  border: 0;
  cursor: pointer;
  font-weight: var(--fw-medium);
}
.search-form button:disabled { opacity: .5; cursor: progress; }


/* delta — for diff tables (Phase 27e / share_report).
 * Positive deltas read pass-green, negative deltas fail-red,
 * zero is muted. Kept distinct from .tag-* so the score-tag
 * vocabulary stays untouched. */
.delta-pos  { color: var(--pass); font-weight: var(--fw-bold); }
.delta-neg  { color: var(--fail); font-weight: var(--fw-bold); }
.delta-zero { color: var(--mute); }


/* ============================================================
 * 7. admin scope (Phase 34d)
 *
 * The authenticated /admin zone wears the same brand but needs
 * primitives the public surface didn't: nav header, form
 * controls (input/select/textarea/label), button variants,
 * grouped row-action toolbars.
 *
 * Scoped under `body.admin` so a public template that
 * accidentally inherits a button or input declaration doesn't
 * get hit. The `--accent-admin` token is reserved here for any
 * future zone-distinction tweak; today it equals --ink.
 * ============================================================ */

body.admin {
  max-width: 100%;
  padding: 0;
  /* Legacy token aliases for inline style= attributes in 8 of
   * the 10 untouched admin templates (run_detail, dashboard_detail,
   * site_detail, users_list). Pre-34d these used --danger / --ok /
   * --warn; without these aliases they'd resolve to `unset`
   * (border-color → currentColor, color → inherit) — making the
   * Delete-Site button invisible and the error banners colourless.
   * Cycle-2 review B1. Future cleanup: hoist the inline styles
   * into named utility classes (.danger-box, .ok-toast) and drop
   * these aliases. */
  --danger: var(--fail);
  --ok:     var(--pass);
  --warn:   var(--mute);
}

.admin-nav {
  border-bottom: var(--border-hair);
  padding: var(--sp-y) var(--sp-x);
  display: flex;
  align-items: baseline;
  gap: calc(var(--sp-x) * 2);
}
.admin-nav h1 {
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  margin: 0;
}
.admin-nav h1 a { color: var(--accent-admin); text-decoration: none; }
.admin-nav h1 a:hover { background: none; color: var(--link); }
.admin-nav nav {
  display: flex;
  gap: calc(var(--sp-x) * 2);
  flex: 1;
}
.admin-nav nav a {
  color: var(--mute);
  text-decoration: none;
  font-weight: var(--fw-medium);
}
.admin-nav nav a.active,
.admin-nav nav a:hover { color: var(--ink); background: none; }
.admin-nav .me { color: var(--mute); font-size: var(--fs-caption); }
.admin-nav .me .role { color: var(--mute); }

body.admin main {
  max-width: 120ch;
  margin: 0 auto;
  padding: var(--sp-2y) var(--sp-x);
}

/* form controls — brutal hairline borders, paper bg, ink text. */
body.admin label {
  display: block;
  color: var(--mute);
  font-size: var(--fs-caption);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin-bottom: calc(var(--sp-y) / 4);
}
body.admin input[type=text],
body.admin input[type=email],
body.admin input[type=password],
body.admin input[type=url],
body.admin input[type=number],
body.admin select,
body.admin textarea {
  font: inherit;
  background: var(--paper);
  color: var(--ink);
  border: var(--border-hair);
  padding: 0 var(--sp-x);
  line-height: var(--lh-loose);
  width: 100%;
  max-width: 60ch;
}
body.admin textarea { line-height: var(--lh-body); padding: var(--sp-y) var(--sp-x); }
body.admin input[type=checkbox] { accent-color: var(--ink); }

/* button variants. .btn (default = inverted ink) primary;
 * .btn-secondary outlined; .btn-danger red. All share padding +
 * font + line-height + medium weight. */
body.admin button,
body.admin .btn {
  font: inherit;
  background: var(--ink);
  color: var(--paper);
  border: 0;
  padding: 0 var(--sp-x);
  line-height: var(--lh-loose);
  cursor: pointer;
  font-weight: var(--fw-medium);
  text-decoration: none;
  display: inline-block;
}
body.admin button:disabled,
body.admin .btn:disabled { opacity: .5; cursor: progress; }
body.admin .btn-secondary,
body.admin button.secondary {
  background: var(--paper);
  color: var(--ink);
  border: var(--border-hair);
}
body.admin .btn-danger,
body.admin button.danger { background: var(--fail); color: var(--paper); }

body.admin form.inline {
  display: flex;
  gap: var(--sp-x);
  flex-wrap: wrap;
  align-items: flex-end;
}

/* row-actions toolbar — buttons + forms side-by-side on a row. */
body.admin .row-actions {
  display: flex;
  gap: var(--sp-x);
  flex-wrap: wrap;
  align-items: center;
}

body.admin .empty {
  color: var(--mute);
  font-style: italic;
  padding: var(--sp-y) 0;
}
body.admin .err { color: var(--fail); font-size: var(--fs-caption); margin: var(--sp-y) 0; }
body.admin .muted { color: var(--mute); }

/* Admin .card was a rounded box in the pre-34d aesthetic. Brand
 * rejects cards — keep the class as an alias for a hairline-
 * separated section so admin templates don't need wholesale
 * rewrites. */
body.admin .card {
  border-top: var(--border-hair);
  padding: var(--sp-y) 0;
  margin: var(--sp-y) 0;
}

/* Admin compatibility — bridge the pre-34d class vocabulary that
 * lives in ~11 admin templates without rewriting all of them.
 *
 * `.score` was the old class for tabular numbers; we keep it as
 * an alias for the same typographic treatment, with .tag-pass /
 * .tag-fail composing on top.
 *
 * `.status.done` etc. mirrors the post-34c semantic mapping
 * (done = pass, error = fail, others = mute). New admin templates
 * should prefer `class="tag tag-pass"` directly; legacy
 * `class="status done"` continues to render correctly. */
body.admin .score {
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-bold);
}
body.admin .status {
  font-weight: var(--fw-medium);
  white-space: nowrap;
}
body.admin .status.done,
body.admin .status.pass,
body.admin .status.present     { color: var(--pass); }
body.admin .status.error,
body.admin .status.fail,
body.admin .status.absent      { color: var(--fail); }
body.admin .status.running,
body.admin .status.pending,
body.admin .status.warn,
body.admin .status.partial     { color: var(--mute); }


/* cursor-blink — used on the wordmark in homepage hero + favicon. */
.cursor {
  display: inline-block;
  animation: cursor-blink 1.06s steps(1) infinite;
}
@keyframes cursor-blink {
  0%, 50%   { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .cursor { animation: none; }
}


/* ============================================================
 * 6. accessibility helpers
 * ============================================================ */

.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;
}
