/* ===========================================================================
   DMARC Monitor — stylesheet

   Everything is driven by custom properties defined on :root (light) and
   overridden under html[data-mode="dark"] plus a prefers-color-scheme block for
   html[data-mode="auto"]. Components only ever reference var(--...), so dark
   mode costs no PHP and no duplicated component rules.

   Status colours have THREE tokens each, and the split matters:
     --st-X       saturated, for borders and glyphs on the card background
     --st-X-bg    tinted surface
     --st-X-ink   text on that tinted surface, contrast-checked to 4.5:1
   Using the saturated token for small text on the tint would fail contrast in
   both modes, which is why the ink tokens exist.

   Status is NEVER carried by colour alone — see .chip, which combines glyph,
   colour, border style and screen-reader text.
   =========================================================================== */

:root {
  --bg:            #f4f6f8;
  --surface:       #ffffff;
  --surface-2:     #f8fafc;
  --border:        #d8dee6;
  --border-strong: #b9c3ce;
  --ink:           #1b2530;
  --ink-2:         #4b5867;
  --ink-3:         #616d7a;   /* >= 4.5:1 on every light surface (WCAG AA) */
  --accent:        #1f5f8b;
  --accent-ink:    #ffffff;
  --accent-soft:   #e6f0f7;
  --focus:         #1f5f8b;
  --shadow:        0 1px 2px rgba(16, 24, 32, .06), 0 2px 8px rgba(16, 24, 32, .05);
  --radius:        .55rem;

  /* Status */
  --st-pass:    #14713f;  --st-pass-bg:    #e3f5ea;  --st-pass-ink:    #0b4527;
  --st-warn:    #9a5b00;  --st-warn-bg:    #fdf0d8;  --st-warn-ink:    #653c00;
  --st-fail:    #b3261e;  --st-fail-bg:    #fbe2e0;  --st-fail-ink:    #741913;
  --st-absent:  #566371;  --st-absent-bg:  #eef1f4;  --st-absent-ink:  #333d47;
  --st-error:   #4a4bb0;  --st-error-bg:   #e8e8f9;  --st-error-ink:   #2b2c78;
  --st-skipped: #8a939b;  --st-skipped-bg: transparent; --st-skipped-ink: #616d7a;
  --badge-ink:  #ffffff;   /* on --st-warn #9a5b00 = 5.43:1 */

  /* Severity */
  --sev-critical: #8e1b16;
  --sev-high:     #b3261e;
  --sev-medium:   #9a5b00;
  --sev-low:      #4a4bb0;
  --sev-info:     #566371;

  /* Grades */
  --grade-a: #14713f;
  --grade-b: #4e7a1e;
  --grade-c: #9a5b00;
  --grade-d: #b45309;
  --grade-f: #b3261e;

  /* Charts. Separate from the status palette on purpose: a chart band is a
     large filled area while a chip is a small glyph, so the same saturation
     reads far heavier here, and the four bands must stay distinguishable
     from each other rather than each from white. */
  --chart-pass:   #2e8f5b;
  --chart-fail:   #d98324;
  --chart-quar:   #b3261e;
  --chart-reject: #7a1a15;
  --chart-line:   #1f5f8b;
  --chart-grid:   #dfe5ea;
}

html[data-mode="dark"] {
  --bg:            #12171d;
  --surface:       #1a2028;
  --surface-2:     #212932;
  --border:        #2f3a45;
  --border-strong: #43505d;
  --ink:           #e6ebf1;
  --ink-2:         #b3bfcb;
  --ink-3:         #8b98a6;
  --accent:        #6cb2e0;
  --accent-ink:    #0d1319;
  --accent-soft:   #16303f;
  --focus:         #6cb2e0;
  --shadow:        0 1px 2px rgba(0, 0, 0, .4), 0 2px 10px rgba(0, 0, 0, .3);

  --st-pass:    #63d194;  --st-pass-bg:    #10301e;  --st-pass-ink:    #aeecc6;
  --st-warn:    #e3ab45;  --st-warn-bg:    #38290c;  --st-warn-ink:    #f7dda6;
  --st-fail:    #f58279;  --st-fail-bg:    #3a1613;  --st-fail-ink:    #ffc7c1;
  --st-absent:  #9aa5b1;  --st-absent-bg:  #222831;  --st-absent-ink:  #c5cdd6;
  --st-error:   #9298ec;  --st-error-bg:   #1b1d40;  --st-error-ink:   #c8ccf9;
  --st-skipped: #78828c;  --st-skipped-bg: transparent; --st-skipped-ink: #aab3bd;
  --badge-ink:  #12171d;   /* on --st-warn #e3ab45 = 8.73:1; #fff would be 2.06:1 */

  --sev-critical: #ff9a91;
  --sev-high:     #f58279;
  --sev-medium:   #e3ab45;
  --sev-low:      #9298ec;
  --sev-info:     #9aa5b1;

  --grade-a: #63d194;
  --grade-b: #a9d04e;
  --grade-c: #e3ab45;
  --grade-d: #f0913c;
  --grade-f: #f58279;

  --chart-pass:   #4fbb80;
  --chart-fail:   #e0a04a;
  --chart-quar:   #e2685e;
  --chart-reject: #a83b33;
  --chart-line:   #6cb2e0;
  --chart-grid:   #2f3a45;
}

@media (prefers-color-scheme: dark) {
  html[data-mode="auto"] {
    --bg:            #12171d;
    --surface:       #1a2028;
    --surface-2:     #212932;
    --border:        #2f3a45;
    --border-strong: #43505d;
    --ink:           #e6ebf1;
    --ink-2:         #b3bfcb;
    --ink-3:         #8b98a6;
    --accent:        #6cb2e0;
    --accent-ink:    #0d1319;
    --accent-soft:   #16303f;
    --focus:         #6cb2e0;
    --shadow:        0 1px 2px rgba(0, 0, 0, .4), 0 2px 10px rgba(0, 0, 0, .3);

    --st-pass:    #63d194;  --st-pass-bg:    #10301e;  --st-pass-ink:    #aeecc6;
    --st-warn:    #e3ab45;  --st-warn-bg:    #38290c;  --st-warn-ink:    #f7dda6;
    --st-fail:    #f58279;  --st-fail-bg:    #3a1613;  --st-fail-ink:    #ffc7c1;
    --st-absent:  #9aa5b1;  --st-absent-bg:  #222831;  --st-absent-ink:  #c5cdd6;
    --st-error:   #9298ec;  --st-error-bg:   #1b1d40;  --st-error-ink:   #c8ccf9;
    --st-skipped: #78828c;  --st-skipped-bg: transparent; --st-skipped-ink: #aab3bd;
  --badge-ink:  #12171d;   /* on --st-warn #e3ab45 = 8.73:1; #fff would be 2.06:1 */

    --sev-critical: #ff9a91;
    --sev-high:     #f58279;
    --sev-medium:   #e3ab45;
    --sev-low:      #9298ec;
    --sev-info:     #9aa5b1;

    --grade-a: #63d194;
    --grade-b: #a9d04e;
    --grade-c: #e3ab45;
    --grade-d: #f0913c;
    --grade-f: #f58279;

    --chart-pass:   #4fbb80;
    --chart-fail:   #e0a04a;
    --chart-quar:   #e2685e;
    --chart-reject: #a83b33;
    --chart-line:   #6cb2e0;
    --chart-grid:   #2f3a45;
  }
}

/* --- Base ---------------------------------------------------------------- */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* WCAG 1.4.1. A link in running text was told apart from the text around it
   by hue alone -- 2.27:1 against the body colour in light and 1.93:1 in
   dark, where 3:1 is the floor below which colour cannot be the only cue.
   "Underline on hover" does not rescue it: hover does not exist for a
   keyboard or a touchscreen. Prose links are underlined; the places where a
   link is obviously a control -- buttons, nav, table headers, the brand --
   opt out below, because there the shape already carries it. */
a { color: var(--accent); text-decoration: underline; text-underline-offset: .15em; }
a:hover { text-decoration-thickness: 2px; }
a.btn, .topbar a, .brand, thead th a, .tabs a, .lang-switch a, .pill a,
a.tag, .chip a, .crumbs a { text-decoration: none; }
a.btn:hover, .topbar a:hover, .tabs a:hover, .crumbs a:hover { text-decoration: underline; }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 3px;
}

h1, h2, h3 { line-height: 1.25; margin: 0 0 .6rem; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.15rem; }
h3 { font-size: 1rem; }

code, pre, .mono {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", monospace;
  font-size: .875em;
}

/* Screen-reader-only text. Every status chip carries one of these, so the
   meaning survives when colour and glyph do not reach the user. */
.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;
}

/* --- Layout -------------------------------------------------------------- */

.topbar {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding: .6rem 1.1rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.brand {
  font-weight: 700; font-size: 1.05rem; color: var(--ink);
  display: inline-flex; align-items: center; gap: .45rem;
}
.brand:hover { text-decoration: none; }

.topbar nav {
  display: flex; align-items: center; gap: .25rem; flex-wrap: wrap;
  margin-left: auto;
}
.topbar nav a {
  padding: .35rem .6rem; border-radius: var(--radius); color: var(--ink-2);
}
.topbar nav a:hover { background: var(--surface-2); text-decoration: none; color: var(--ink); }
.topbar nav a[aria-current="page"] { background: var(--accent-soft); color: var(--accent); font-weight: 600; }

.who { display: inline-flex; align-items: center; gap: .4rem; color: var(--ink-2); padding-left: .5rem; }

.lang-switch { display: inline-flex; gap: .15rem; align-items: center; margin-left: .4rem; }
.lang-switch a, .lang-current, .lang-btn {
  font-size: .75rem; font-weight: 700; letter-spacing: .03em;
  padding: .2rem .35rem; border-radius: 4px;
}
.lang-form { display: inline-flex; }
.lang-btn {
  background: none; border: 0; cursor: pointer; font-family: inherit;
  color: var(--accent); line-height: inherit;
  /* WCAG 2.2 AA 2.5.8 sets the floor at 24 CSS pixels and this sat exactly on
     it, which fails the moment a font renders a pixel small. 32 is the size
     the rest of the small controls use. */
  min-width: 2rem; min-height: 2rem;
  display: inline-flex; align-items: center; justify-content: center;
}
.lang-btn:hover { text-decoration: underline; }
.lang-current { background: var(--accent-soft); color: var(--accent); }

.mode-toggle {
  background: none; border: 1px solid var(--border); color: var(--ink-2);
  border-radius: var(--radius); cursor: pointer; padding: .25rem .45rem; font-size: .95rem;
}
.mode-toggle:hover { background: var(--surface-2); }

.container { max-width: 1220px; margin: 0 auto; padding: 1.25rem 1.1rem 3rem; }
.narrow { max-width: 640px; }

.site-footer {
  text-align: center; color: var(--ink-3); padding: 1.5rem 1rem 2.5rem; font-size: .85rem;
}

/* --- Cards, panels ------------------------------------------------------- */

.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 1rem 1.1rem; margin-bottom: 1rem;
}
.card > :last-child { margin-bottom: 0; }

.muted { color: var(--ink-3); }
.small { font-size: .85rem; }

/* --- Flash messages ------------------------------------------------------ */

.flash {
  border: 1px solid var(--border); border-left: 4px solid var(--accent);
  background: var(--surface); border-radius: var(--radius);
  padding: .65rem .85rem; margin-bottom: .8rem;
}
.flash.success { border-left-color: var(--st-pass); background: var(--st-pass-bg); color: var(--st-pass-ink); }
.flash.error   { border-left-color: var(--st-fail); background: var(--st-fail-bg); color: var(--st-fail-ink); }
.flash.warn    { border-left-color: var(--st-warn); background: var(--st-warn-bg); color: var(--st-warn-ink); }

/* --- Forms --------------------------------------------------------------- */

label { display: block; font-weight: 600; font-size: .875rem; margin-bottom: .25rem; color: var(--ink-2); }

input[type="text"], input[type="email"], input[type="number"], input[type="search"],
input[type="password"], select, textarea {
  width: 100%; padding: .45rem .55rem;
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--surface); color: var(--ink); font: inherit;
}
input:disabled, select:disabled { background: var(--surface-2); color: var(--ink-3); }

.field { margin-bottom: .85rem; }
.hint  { font-size: .8rem; color: var(--ink-3); margin-top: .2rem; font-weight: 400; }

.btn {
  display: inline-flex; align-items: center; gap: .4rem; justify-content: center;
  padding: .45rem .9rem; border-radius: var(--radius); cursor: pointer;
  border: 1px solid var(--accent); background: var(--accent); color: var(--accent-ink);
  font: inherit; font-weight: 600;
}
.btn:hover { filter: brightness(1.07); text-decoration: none; }
.btn:disabled { opacity: .55; cursor: not-allowed; filter: none; }
.btn.ghost { background: var(--surface); color: var(--ink); border-color: var(--border-strong); }
.btn.ghost:hover { background: var(--surface-2); }
.btn.danger { background: var(--st-fail); border-color: var(--st-fail); color: #fff; }
.btn.small { padding: .25rem .55rem; font-size: .82rem; }
.btn.big { padding: .7rem 1.3rem; font-size: 1.05rem; }

form.inline { display: inline; }
/* A checkbox that sits in a row with its siblings rather than on its own
   line: a list of ten record types reads as a set, not as ten questions. */
label.inline {
  display: inline-flex; align-items: center; gap: .3rem;
  margin: 0 .9rem .3rem 0; white-space: nowrap;
}

/* --- Tables -------------------------------------------------------------- */

/* Wide tables scroll inside their own container; the page body never scrolls
   horizontally. The row header stays put so a domain name is always visible. */
/* FOCUSABLE, because it scrolls. A region that scrolls horizontally and cannot
   take focus is unreachable from the keyboard: there is nothing to put focus
   on, so the columns past the right edge cannot be reached at all (WCAG
   2.1.1). tabindex="0" is added in the markup; this gives the focus a visible
   ring, since a scroll container has no other affordance. */
.table-wrap { overflow-x: auto; border-radius: var(--radius); }
.table-wrap:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

table.grid { border-collapse: collapse; width: 100%; background: var(--surface); }
table.grid th, table.grid td {
  padding: .5rem .6rem; text-align: left; border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
table.grid thead th {
  font-size: .78rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-3); background: var(--surface-2); white-space: nowrap;
  position: sticky; top: 0; z-index: 1;
}
table.grid tbody tr:hover { background: var(--surface-2); }
table.grid th[scope="row"] { font-weight: 600; }
table.grid td.mech { text-align: center; width: 2.6rem; padding-left: .2rem; padding-right: .2rem; }
table.grid td.num { text-align: right; font-variant-numeric: tabular-nums; }

thead th a { color: inherit; display: inline-flex; align-items: center; gap: .25rem; }
thead th[aria-sort] a::after { content: ""; }
thead th[aria-sort="ascending"] a::after  { content: "\2191"; }
thead th[aria-sort="descending"] a::after { content: "\2193"; }

/* --- Status chips -------------------------------------------------------- */

/* Five channels per chip: glyph, colour, border style, .sr-only sentence and a
   title attribute. Colour is never the only signal. */
.chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.6rem; height: 1.6rem; border-radius: .45rem;
  font-weight: 800; font-size: .85rem; line-height: 1;
  border: 2px solid transparent;
}
.chip--pass { background: var(--st-pass-bg); color: var(--st-pass-ink); border-color: var(--st-pass); }
.chip--warn {
  background: var(--st-warn-bg); color: var(--st-warn-ink); border-color: var(--st-warn);
  background-image: repeating-linear-gradient(45deg, transparent 0 3px, rgba(0,0,0,.07) 3px 6px);
}
.chip--fail {
  background: var(--st-fail-bg); color: var(--st-fail-ink);
  border-color: var(--st-fail); border-width: 3px;
}
.chip--absent {
  background: var(--st-absent-bg); color: var(--st-absent-ink);
  border-color: var(--st-absent); border-style: dashed;
}
.chip--error {
  background: var(--st-error-bg); color: var(--st-error-ink);
  border-color: var(--st-error); border-style: dotted;
}
/* opacity: .5 composited this to 1.87:1 in light and 2.38:1 in dark, with a
   transparent border -- so "not monitored" read as a rendering fault rather
   than a state. Full-strength ink and a real boundary instead. */
.chip--skipped {
  background: none; color: var(--st-skipped-ink); border-color: var(--st-absent);
  border-style: dotted;
}
.chip.lg { width: 2.2rem; height: 2.2rem; font-size: 1.05rem; }

@media (prefers-contrast: more) {
  .chip { border-width: 3px; }
}

/* --- Severity pills ------------------------------------------------------ */

.sev {
  display: inline-block; padding: .1rem .45rem; border-radius: 999px;
  font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  border: 1px solid currentColor;
}
.sev--critical { color: var(--sev-critical); }
.sev--high     { color: var(--sev-high); }
.sev--medium   { color: var(--sev-medium); }
.sev--low      { color: var(--sev-low); }
.sev--info     { color: var(--sev-info); }

/* --- Outcome tags -------------------------------------------------------- */

/* Text pills for ingestion outcomes. Unlike .chip, which is a glyph in a fixed
   square, these carry their meaning in words: "already ingested" and "domain
   not monitored" are not states an operator can be expected to read off a
   symbol, and both are the ordinary answer rather than an error. */
.tag {
  display: inline-block; padding: .1rem .5rem; border-radius: 999px;
  font-size: .78rem; font-weight: 700; border: 1px solid currentColor;
}
.tag--ok    { color: var(--st-pass); }
.tag--warn  { color: var(--st-warn); }
.tag--bad   { color: var(--st-fail); }
.tag--muted { color: var(--ink-3); }

/* --- Grade badge --------------------------------------------------------- */

/* The LETTER is the primary signal and the numeric score always sits beside
   it, so the badge still reads correctly without colour. */
.grade {
  display: inline-flex; align-items: baseline; gap: .3rem;
  padding: .2rem .5rem; border-radius: var(--radius);
  border: 2px solid currentColor; font-weight: 800;
}
.grade__letter { font-size: 1rem; letter-spacing: .02em; }
/* opacity: .85 pushed A/B/C/D under 4.5:1 in light (3.79-4.44:1). The
   smaller size already de-emphasises it; the opacity only cost contrast. */
.grade__score  { font-size: .78rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.grade--a { color: var(--grade-a); }
.grade--b { color: var(--grade-b); }
.grade--c { color: var(--grade-c); }
.grade--d { color: var(--grade-d); }
.grade--f { color: var(--grade-f); }
.grade--none { color: var(--ink-3); }

/* --- Records and findings ------------------------------------------------ */

pre.record {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .6rem .7rem; margin: .35rem 0;
  overflow-wrap: anywhere; white-space: pre-wrap;   /* long SPF/DKIM records */
}

.finding { border-left: 4px solid var(--sev-info); padding: .5rem .75rem; margin-bottom: .6rem; }
.finding--critical { border-left-color: var(--sev-critical); }
.finding--high     { border-left-color: var(--sev-high); }
.finding--medium   { border-left-color: var(--sev-medium); }
.finding--low      { border-left-color: var(--sev-low); }
.finding--info     { border-left-color: var(--sev-info); }
.finding h3 { margin: .2rem 0 .3rem; font-size: .95rem; }
.finding p  { margin: .25rem 0; color: var(--ink-2); }

dl.facts { display: grid; grid-template-columns: auto 1fr; gap: .25rem .8rem; margin: .5rem 0; }
dl.facts dt { color: var(--ink-3); font-size: .85rem; }
dl.facts dd { margin: 0; font-variant-numeric: tabular-nums; }

/* --- Small helpers ------------------------------------------------------- */

.pill {
  display: inline-block; padding: .05rem .4rem; border-radius: 999px;
  border: 1px solid var(--border-strong); color: var(--ink-3);
  font-size: .72rem; font-weight: 600;
}
.row { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.spread { display: flex; gap: .8rem; align-items: center; justify-content: space-between; flex-wrap: wrap; }
.stack > * + * { margin-top: .6rem; }

/* --- Narrow screens ------------------------------------------------------ */

/* The domain list is thirteen columns wide and scrolls sideways inside
   .table-wrap on a narrow screen. That is fine -- a data table is exempt
   from reflow -- EXCEPT that scrolling to the chips used to carry the
   domain name off the left edge, so you could no longer tell whose row you
   were reading. Pin the row header instead.

   (This replaces a rule that collapsed the mechanism cells into a 4x2 grid
   inside `td.mech-group`. No page has ever emitted that class -- mech_matrix()
   writes eight separate `td.mech` cells -- so the rule matched nothing from
   the day it was written. Doing it properly needs the row restructured, not
   a stylesheet edit, and eight cells cannot become one without the row
   disagreeing with its own header.) */
@media (max-width: 760px) {
  .topbar { padding: .5rem .7rem; }
  .container { padding: 1rem .7rem 2.5rem; }
  table.grid.domains th[scope="row"] {
    position: sticky; left: 0; z-index: 1;
    background: var(--surface);
    box-shadow: 1px 0 0 var(--border);
  }
}

/* --- Charts -------------------------------------------------------------- */

/* Every chart is server-rendered inline SVG (includes/svg_chart.php). Colours
   come from the custom properties above, so dark mode and print need no
   special-casing here, and the same numbers always appear in a .sr-only table
   beside the picture. */

.chart-figure { margin: 0; }
.chart { width: 100%; height: auto; display: block; }
.chart__grid { stroke: var(--chart-grid); stroke-width: 1; }
.chart__axis { fill: var(--ink-3); font-size: 10px; }
.chart__line { fill: none; stroke: var(--chart-line); stroke-width: 2; stroke-linejoin: round; }
.chart__dot  { fill: var(--chart-line); }

/* Rating history. The grade bands sit behind the line at low opacity: they are
   a reading aid, and a saturated background would win the contrast fight
   against the data drawn on top of it. */
.chart__band { opacity: .12; }
.chart__band--a { fill: var(--grade-a); }
.chart__band--b { fill: var(--grade-b); }
.chart__band--c { fill: var(--grade-c); }
.chart__band--d { fill: var(--grade-d); }
.chart__band--f { fill: var(--grade-f); }
.chart__bandlabel { fill: var(--ink-3); font-size: 9px; font-weight: 600; }
.chart__marker { stroke-width: 2; stroke: var(--st-absent); }
.chart__marker--critical,
.chart__marker--high   { stroke: var(--st-fail); }
.chart__marker--medium { stroke: var(--st-warn); }

/* Grade distribution: one SVG bar with a segment per grade. Widths are SVG
   presentation attributes, not styles, so no nonce and no style attribute --
   which the CSP would refuse anyway. */
.gradedist { display: block; width: 100%; height: auto; }
.chart-legend__swatch--grade-a { background: var(--grade-a); }
.chart-legend__swatch--grade-b { background: var(--grade-b); }
.chart-legend__swatch--grade-c { background: var(--grade-c); }
.chart-legend__swatch--grade-d { background: var(--grade-d); }
.chart-legend__swatch--grade-f { background: var(--grade-f); }

.delta { font-variant-numeric: tabular-nums; font-weight: 600; }
.delta--up   { color: var(--st-pass); }
.delta--down { color: var(--st-fail); }
.delta--flat { color: var(--ink-3); font-weight: 500; }

.range-switch { display: inline-flex; gap: .25rem; }
.range-switch a { padding: .1rem .5rem; border-radius: .3rem; font-size: .85rem; }
.range-switch a[aria-current="page"] { background: var(--surface-2); font-weight: 600; }

.chart-legend {
  list-style: none; display: flex; flex-wrap: wrap; gap: .2rem 1rem;
  margin: .5rem 0 0; padding: 0; font-size: .8rem; color: var(--ink-2);
}
.chart-legend li { display: inline-flex; align-items: center; gap: .35rem; }
.chart-legend__swatch {
  width: .8rem; height: .8rem; border-radius: .2rem; display: inline-block;
  border: 1px solid rgba(0, 0, 0, .15);
}
.chart-legend__swatch--pass   { background: var(--chart-pass); }

/* THE SAME TEXTURES AS THE BANDS. Adjacent segments sit at 1.39:1 from each
   other, so a reader with deuteranopia cannot map a band to its meaning from
   colour -- and a patterned chart with a plain legend would be worse than
   neither: four distinguishable bands and no way to name them.

   Gradients rather than the SVG patterns themselves, because a swatch is a
   <span> and referencing an SVG pattern from CSS needs an inline SVG per
   swatch. The angles match the definitions in svg_chart.php. */
.chart-legend__swatch--fail {
  background-image: repeating-linear-gradient(45deg,
    rgba(0,0,0,.42) 0 2px, transparent 2px 6px);
}
.chart-legend__swatch--quar {
  background-image: radial-gradient(rgba(0,0,0,.42) 1.25px, transparent 1.3px);
  background-size: 5px 5px;
}
.chart-legend__swatch--reject {
  background-image: repeating-linear-gradient(-45deg,
    rgba(0,0,0,.42) 0 2px, transparent 2px 6px);
}
.chart-legend__swatch--fail   { background: var(--chart-fail); }
.chart-legend__swatch--quar   { background: var(--chart-quar); }
.chart-legend__swatch--reject { background: var(--chart-reject); }
.chart-legend__swatch--line   {
  background: none; border: 0; height: 0;
  border-top: 2px solid var(--chart-line); border-radius: 0;
}

/* The bar is the scanning aid; the number beside it is the value. 97% and 99%
   are visually identical as bars and are entirely different answers. */
.meter { display: inline-flex; align-items: center; gap: .4rem; }
.meter__value { font-variant-numeric: tabular-nums; font-size: .85rem; }

.spark { display: block; }
.spark polyline { fill: none; stroke: var(--chart-line); stroke-width: 1.5; }

.trend { font-size: .8rem; font-weight: 600; white-space: nowrap; }
.trend--up   { color: var(--st-pass); }
.trend--down { color: var(--st-fail); }
.trend--flat { color: var(--ink-3); font-weight: 500; }

/* KPI strip: the four numbers that answer "should I look closer?" */
.kpis { display: flex; flex-wrap: wrap; gap: .8rem; }
.kpi {
  flex: 1 1 9rem; padding: .6rem .75rem; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--surface-2);
}
.kpi__label { font-size: .78rem; color: var(--ink-3); text-transform: uppercase; letter-spacing: .04em; }
.kpi__value { font-size: 1.4rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.kpi__note  { font-size: .78rem; color: var(--ink-2); }

/* A KPI that is a link to the list filtered to it. The tone is a left rail
   rather than a coloured number: a number in red on a card is hard to read at
   a glance and impossible for a reader who cannot see the colour, and the
   label already says which state it counts. */
a.kpi {
  display: block; text-decoration: none; color: inherit;
  border-left: 3px solid transparent;
}
a.kpi:hover, a.kpi:focus-visible { border-color: var(--accent); background: var(--surface-2); }

/* A control that is working. Styled from aria-disabled rather than :disabled,
   because disabling a focused button removes it from the tab order and drops
   the user's focus to the body -- see the busy handler in ui.js. */
[aria-disabled="true"] { opacity: .65; cursor: progress; }

/* A validation message beside its field. Not colour alone: the message is
   words, and the control is marked with aria-invalid for anyone who cannot see
   the rule beside it. */
.field-error {
  margin: .3rem 0 0; font-size: .85rem; color: var(--st-fail-ink);
  border-left: 3px solid var(--st-fail); padding-left: .5rem;
}
[aria-invalid="true"] { border-color: var(--st-fail); }
.btn.is-busy { pointer-events: none; }
a.kpi .kpi__label { display: block; }
a.kpi .kpi__value { display: block; }
.kpi--bad  { border-left-color: var(--st-fail); }
.kpi--warn { border-left-color: var(--st-warn); }
.kpi--ok   { border-left-color: var(--st-pass); }

@media print {
  .topbar, .site-footer, .btn, .no-print { display: none !important; }
  body { background: #fff; }
  .card { box-shadow: none; border-color: #ccc; break-inside: avoid; }
  /* A printed page has no hover and no tooltips, so the hidden data table
     becomes the record of what the chart showed. */
  .chart-figure + .sr-only,
  table.grid.sr-only {
    position: static; width: auto; height: auto; clip: auto;
    margin: .5rem 0; overflow: visible; white-space: normal;
  }
}

/* --- Passkey ceremony status --------------------------------------------- */

.pk-status { min-height: 1.4em; margin: .5rem 0 0; color: var(--ink-2); font-size: .9rem; }
.pk-status--error { color: var(--st-fail-ink); background: var(--st-fail-bg);
  border-left: 3px solid var(--st-fail); padding: .4rem .6rem; border-radius: 4px; }

#pkCodesList { font-size: 1rem; letter-spacing: .06em; line-height: 1.8; text-align: center; }

/* Count badge in the navigation, for changes waiting to be reviewed. It is
   shown only when non-zero, so it never reads "0" and never becomes furniture
   people stop seeing. */
.nav-badge {
  display: inline-block; min-width: 1.25rem; padding: 0 .35rem;
  /* #fff on --st-warn is 5.43:1 in light but 2.06:1 in dark, and this is
     the count of unreviewed changes -- the one number on the page that is
     meant to be noticed. Each theme gets ink that works on its own ground. */
  border-radius: 999px; background: var(--st-warn); color: var(--badge-ink);
  font-size: .72rem; font-weight: 700; text-align: center; line-height: 1.25rem;
}

/* --- Tools ---------------------------------------------------------------
   The technician tools are laid out with these small utilities instead of
   inline style attributes, which the Content-Security-Policy (style-src with
   a nonce, no 'unsafe-inline') would block. */
.row--bottom  { align-items: flex-end; }
.grow         { flex: 1; }
.field-wide   { flex: 1; min-width: 220px; }
.full         { width: 100%; }
.err-text     { color: var(--st-fail-ink); }
.pre-wrap     { white-space: pre-wrap; }
.nowrap       { white-space: nowrap; }
.mt           { margin-top: .6rem; }
.mt-sm        { margin-top: .35rem; }
.tracked      { letter-spacing: .15em; }
.cap-tag      { display: inline-block; margin: 0 .2rem .2rem 0; }
.tool-drop    { border: 2px dashed var(--border-strong); border-radius: var(--radius);
                padding: 1.4rem; text-align: center; color: var(--ink-3); }
.tool-drop.is-drag { border-color: var(--accent); background: var(--accent-soft); }
.qr-preview   { max-width: 240px; height: auto; border: 1px solid var(--border);
                border-radius: 6px; }

/* --- Email header analyser ----------------------------------------------- */
.hl-email   { color: var(--accent); }
.hl-ip      { color: var(--st-error-ink); }
.hl-pass    { color: var(--st-pass-ink); font-weight: 600; }
.hl-fail    { color: var(--st-fail-ink); font-weight: 600; }
.hl-neutral { color: var(--st-warn-ink); font-weight: 600; }
.hdr-name   { font-weight: 600; cursor: help; border-bottom: 1px dotted var(--border-strong); }
.hdr-row    { border-top: 1px solid var(--border); padding: .5rem 0; }
.hdr-row:first-child { border-top: 0; }
.hdr-val    { display: block; margin-top: .2rem; word-break: break-word; }
.hdr-name--plain { border-bottom: 0; cursor: default; }

/* --- Certificate tool ---------------------------------------------------- */
.inline-form { display: inline; margin-left: .5rem; }
.linkbtn { background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
           color: var(--accent); text-decoration: underline; }
.linkbtn.danger { color: var(--st-fail-ink); }

/* --- MIB browser --------------------------------------------------------- */
.mib-tree { list-style: none; margin: 0; padding-left: 1rem; }
.mib-tree--root { padding-left: 0; }
.mib-tree li { margin: .15rem 0; }
.mib-tree summary { cursor: pointer; }
.mib-leaf { padding-left: 1.1rem; }
.mib-oid { color: var(--ink-3); margin-right: .4rem; }
.mib-name--def { font-weight: 600; color: var(--accent); }
.mib-detail { margin: .3rem 0 .5rem 1.1rem; padding-left: .6rem; border-left: 2px solid var(--border); }

/* --- Website screenshot -------------------------------------------------- */
.shot-img { max-width: 100%; height: auto; border: 1px solid var(--border);
            border-radius: 6px; display: block; margin-top: .4rem; }

/* --- Accessibility & form polish ---------------------------------------- */
/* Grouped checkbox/radio sets use fieldset/legend; make them look like the
   plain field labels around them. */
fieldset.field { border: 0; padding: 0; margin: 0 0 .85rem; min-width: 0; }
fieldset.field > legend { padding: 0; font-weight: 600; margin-bottom: .2rem; }
/* Required-field marker. */
.req { color: var(--st-fail); margin-left: .15rem; }
/* A submit button in its working state. */
button[disabled] { opacity: .6; cursor: progress; }

/* --- Nav utility cluster (account/help/lang/theme) ----------------------- */
.topbar nav .nav-utility {
  display: inline-flex; align-items: center; gap: .25rem; flex-wrap: wrap;
  margin-left: auto; padding-left: .6rem; border-left: 1px solid var(--border);
}
/* Header-analyser description line under each recognised header. */
.hdr-desc { margin: .15rem 0 0; }

/* --- Skip link ------------------------------------------------------------
   Hidden until focused, so a keyboard user can jump the whole navigation
   instead of tabbing through a dozen links on every page. */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--surface); color: var(--ink);
  padding: .6rem 1rem; border: 2px solid var(--focus); border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus { left: 0; }
#main:focus { outline: none; }

/* --- Compact navigation ---------------------------------------------------
   The menu button exists only below the breakpoint; above it the nav is a
   normal row and is never hidden, so JavaScript is not required to navigate. */
.nav-toggle { display: none; }

@media (max-width: 860px) {
  .nav-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    margin-left: auto; min-width: 2.5rem; min-height: 2.5rem;
    background: none; border: 1px solid var(--border); border-radius: var(--radius);
    color: var(--ink); font-size: 1.2rem; cursor: pointer;
  }
  .nav-toggle:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

  .topbar { flex-wrap: wrap; }
  .topbar nav {
    display: none;
    flex-basis: 100%; margin-left: 0; flex-direction: column; align-items: stretch;
    gap: .1rem; padding-top: .5rem;
  }
  .topbar nav.is-open { display: flex; }
  .topbar nav a { padding: .55rem .6rem; }        /* comfortable touch targets */
  .topbar nav .nav-utility {
    margin-left: 0; padding-left: 0; padding-top: .5rem;
    border-left: 0; border-top: 1px solid var(--border);
    flex-wrap: wrap;
  }
}

/* --- Guided setup --------------------------------------------------------- */
.setup-progress {
  display: block; height: .5rem; margin-top: .6rem; width: 100%;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 999px; overflow: hidden;
}
/* The width itself comes from the page's nonce'd style block: it is data. */
.setup-progress__fill { display: block; height: 100%; background: var(--st-pass); }

.setup-steps { list-style: none; margin: 0; padding: 0; counter-reset: setup; }
.setup-steps > li { margin: 0; }
.setup-step__num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.6rem; height: 1.6rem; margin-right: .45rem;
  border-radius: 999px; background: var(--surface-2); border: 1px solid var(--border);
  font-size: .85rem; font-weight: 700; color: var(--ink-2);
}
.setup-step--done  .setup-step__num { background: var(--st-pass-bg); border-color: var(--st-pass); color: var(--st-pass-ink); }
.setup-step--now   .setup-step__num { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.setup-step--done > .card { opacity: .75; }
.setup-step--now  > .card { border-left: 3px solid var(--accent); }

/* The offer on the domain list. */
.setup-offer { border-left: 3px solid var(--accent); }
