/* SecureMailScope — "signal / ink" design system
   Instrument-console aesthetic. Severity and risk are carried by ink density and
   geometry first, and never by colour alone: every coloured element also has a
   distinct label, dot size or border, so the page still reads correctly in
   monochrome or with any colour vision.

   Critical and high may carry a restrained accent, defined by --sev-crit and
   --sev-high. Medium, low and info stay monochrome. This is a deliberate
   departure from the original strictly-monochrome rule, and it was made because
   with information notes demoted to a collapsed group, colour was the only
   remaining thing separating "a problem" from "a note". To go back, set both
   tokens to the value of --text-2 and nothing else needs to change. */

:root {
  /* Severity accents. Set these two to var(--text-2) to return to monochrome. */
  --sev-crit: oklch(0.5260 0.1897 26.77);   /* oklch(0.5758 0.2088 29.48) measured 4.23:1 on --surface-2, the hero card */
  --sev-high: oklch(0.5534 0.1739 38.40);

  --bg: oklch(0.9734 0.0000 0.00);
  --surface: oklch(1.0000 0.0000 0.00);
  --surface-2: oklch(0.9557 0.0000 0.00);
  --surface-3: oklch(0.9319 0.0000 0.00);
  --border: oklch(0.9228 0.0040 286.32);
  --border-strong: oklch(0.8683 0.0068 286.26);
  --border-sub: rgba(24, 24, 27, 0.06);
  --text: oklch(0.2020 0.0000 0.00);
  --text-2: oklch(0.3627 0.0000 0.00);
  --muted: oklch(0.5586 0.0000 0.00);
  --faint: oklch(0.7212 0.0000 0.00);
  --accent: oklch(0.2020 0.0000 0.00);
  --accent-fg: oklch(0.9764 0.0000 0.00);
  --accent-soft: rgba(22, 22, 26, 0.1);
  --accent-soft-2: rgba(22, 22, 26, 0.035);
  --glow: rgba(22, 22, 26, 0.05);
  --ring: rgba(22, 22, 26, 0.3);
  --shadow-sm: 0 1px 2px rgba(22, 22, 26, 0.05);
  --shadow-md: 0 10px 30px -14px rgba(22, 22, 26, 0.18);
  --shadow-lg: 0 24px 60px -24px rgba(22, 22, 26, 0.28);
  --radius-lg: 16px;
  --radius: 12px;
  --radius-sm: 8px;
  /* shadcn's derived radius scale: one base, everything else a multiple of it, so
     changing --radius moves the whole scale rather than six unrelated values. */
  --radius-pill: 999px;
  --radius-md: 10px;
  --radius-xl: 18px;
  --r-pill: 999px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Code", "JetBrains Mono", Menlo, Consolas, monospace;
}

[data-theme="dark"] {
  --sev-crit: oklch(0.6256 0.1933 23.03);
  --sev-high: oklch(0.6908 0.1909 45.02);

  --bg: oklch(0.1354 0.0000 0.00);
  --surface: oklch(0.1749 0.0000 0.00);
  --surface-2: oklch(0.2025 0.0000 0.00);
  --surface-3: oklch(0.2376 0.0000 0.00);
  --border: oklch(0.2587 0.0112 285.59);
  --border-strong: oklch(0.3516 0.0138 285.67);
  --border-sub: rgba(250, 250, 250, 0.05);
  --text: oklch(0.9677 0.0000 0.00);
  --text-2: oklch(0.8868 0.0000 0.00);
  --muted: oklch(0.6988 0.0000 0.00);
  --faint: oklch(0.5028 0.0000 0.00);
  --accent: oklch(0.9677 0.0000 0.00);
  --accent-fg: oklch(0.1749 0.0000 0.00);
  --accent-soft: rgba(244, 244, 246, 0.09);
  --accent-soft-2: rgba(244, 244, 246, 0.03);
  --glow: rgba(244, 244, 246, 0.04);
  --ring: rgba(244, 244, 246, 0.3);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45);
  --shadow-md: 0 10px 32px -14px rgba(0, 0, 0, 0.7);
  --shadow-lg: 0 26px 64px -26px rgba(0, 0, 0, 0.85);
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.55;
  color: var(--text);
  background:
    radial-gradient(1000px 460px at 88% -160px, var(--accent-soft), transparent 62%),
    radial-gradient(760px 380px at -12% 18%, var(--accent-soft-2), transparent 58%),
    var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background var(--ease), color var(--ease);
}

h1, h2, h3, h4 { margin: 0; font-weight: 720; letter-spacing: -0.018em; }

::selection { background: var(--accent); color: var(--accent-fg); }

a { color: var(--text); text-decoration: none; }
a:focus-visible, button:focus-visible, input:focus-visible, summary:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
  border-radius: 6px;
}

.num, .mono { font-family: var(--mono); }
.num { font-variant-numeric: tabular-nums; }
.mono { font-size: 12.5px; }

/* A single unbreakable token: a cipher suite, a JA3 digest, a host:port.
 *
 * `word-break: break-all` was splitting these anywhere, so
 * TLS_AES_128_GCM_SHA256 rendered as TLS_AES_128_GCM_SHA2 / 56 - which does not
 * read as a broken word, it reads as a different cipher. Tokens now never split.
 * Where one does not fit it is truncated in the middle by `.tok` in app.js, with
 * the full value on `title`, because both ends of a suite name carry meaning.
 */
.tok {
  font-family: var(--mono);
  overflow-wrap: normal;
  word-break: keep-all;
  white-space: nowrap;
}

svg.i { width: 16px; height: 16px; flex: none; vertical-align: middle; }
svg.i.w14 { width: 14px; height: 14px; }
svg.i.big { width: 34px; height: 34px; }

/* ---------------------------------------------------------------- topbar */
.stick {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  backdrop-filter: saturate(1.6) blur(14px);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
  border-bottom: 1px solid var(--border);
}

.stick::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-strong), transparent);
  opacity: 0.6;
}

.topbar {
  max-width: 1140px;
  margin: 0 auto;
  padding: 10px 24px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.brand { display: flex; align-items: center; gap: 11px; font-weight: 750; font-size: 15px; letter-spacing: -0.01em; }

.brand .mark {
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border-radius: 9px;
  background: linear-gradient(135deg, var(--text), color-mix(in srgb, var(--text) 55%, var(--faint)));
  color: var(--accent-fg);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), var(--shadow-sm);
}
.brand .mark .i { width: 17px; height: 17px; }

.brand small { color: var(--faint); font-weight: 550; font-size: 12px; letter-spacing: 0.01em; }

.actions { margin-left: auto; display: flex; align-items: center; gap: 8px; }

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 34px; height: 34px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text-2);
  cursor: pointer;
  transition: background var(--ease), border-color var(--ease), color var(--ease), transform 140ms var(--ease), box-shadow var(--ease);
}
.icon-btn:hover { background: var(--surface-2); border-color: var(--border-strong); color: var(--text); box-shadow: var(--shadow-sm); }
.icon-btn:active { transform: translateY(1px) scale(0.96); }

.pill-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 15px;
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-2);
  font-weight: 650;
  font-size: 13px;
  cursor: pointer;
  transition: background var(--ease), border-color var(--ease), color var(--ease), transform 140ms var(--ease), box-shadow var(--ease);
}
.pill-btn:hover { background: var(--surface-2); border-color: var(--border-strong); color: var(--text); box-shadow: var(--shadow-sm); }
.pill-btn:active { transform: translateY(1px) scale(0.98); }
.pill-btn.strong { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); box-shadow: inset 0 1px 0 rgba(255,255,255,.14), var(--shadow-sm); }
.pill-btn.strong:hover { background: var(--accent); filter: brightness(1.12); color: var(--accent-fg); }
.pill-btn.ghost { background: transparent; color: var(--muted); }
.pill-btn .i { width: 15px; height: 15px; }

/* ----------------------------------------------------------------- shell */
.shell { max-width: 1140px; margin: 0 auto; padding: 0 24px 64px; }
.view { padding-top: 26px; }

section.sec { margin-top: 46px; scroll-margin-top: 92px; }
.sec-head { display: flex; align-items: center; gap: 11px; margin-bottom: 15px; }
.sec-head .ico {
  display: grid; place-items: center;
  width: 32px; height: 32px;
  border-radius: 9px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-2);
  box-shadow: var(--shadow-sm);
}
.sec-head h2 { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.14em; color: var(--muted); font-weight: 700; }
.sec-head .meta { margin-left: auto; font-size: 12px; color: var(--faint); font-family: var(--mono); }

/* ---------------------------------------------------------- resusable bg */
.bg-grid {
  background-image:
    linear-gradient(var(--border-sub) 1px, transparent 1px),
    linear-gradient(90deg, var(--border-sub) 1px, transparent 1px);
  background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(120% 120% at 50% -10%, #000 30%, transparent 78%);
  mask-image: radial-gradient(120% 120% at 50% -10%, #000 30%, transparent 78%);
}

/* ----------------------------------------------------------------- cards */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.card-pad { padding: 20px 22px; }

.hairline-top {
  border-top: 3px solid transparent;
  border-image: linear-gradient(90deg, var(--accent), transparent 55%) 1;
}

/* ------------------------------------------------------------------ hero */
.hero {
  position: relative;
  overflow: hidden;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--surface) 88%, var(--surface-3)), var(--surface) 62%),
    var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  box-shadow: var(--shadow-md);
  padding: 28px 30px 24px;
}
.hero::before {
  content: "";
  position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-strong), transparent);
}
.hero::after {  /* soft halo behind the score */
  content: "";
  position: absolute;
  width: 260px; height: 260px;
  left: 14px; top: -120px;
  background: radial-gradient(circle, var(--accent-soft), transparent 68%);
  pointer-events: none;
}

.hero .row { position: relative; display: flex; gap: 30px; align-items: center; flex-wrap: wrap; z-index: 1; }

.score-box { display: flex; align-items: center; gap: 20px; }

/* score ring */

.evbrow { font-size: 11px; text-transform: uppercase; letter-spacing: 0.16em; color: var(--faint); font-weight: 700; }

.score-num {
  font-size: 56px;
  font-weight: 780;
  letter-spacing: -0.045em;
  line-height: 0.95;
  font-variant-numeric: tabular-nums;
  background: linear-gradient(180deg, var(--text), color-mix(in srgb, var(--text) 58%, var(--faint)));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  margin: 7px 0 10px;
}
.score-sub { font-size: 11.5px; color: var(--muted); margin-top: 8px; }

.grade-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 30px; min-height: 30px;
  padding: 0 11px;
  border-radius: 10px;
  background: var(--accent); color: var(--accent-fg);
  font-weight: 800; font-size: 14px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14), var(--shadow-sm);
  letter-spacing: 0.02em;
}
.grade-badge.lite {
  background: transparent; color: var(--text);
  border: 1.5px solid var(--text);
  box-shadow: none;
}

.meta-chips { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 18px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-2);
  font-size: 12px;
  box-shadow: var(--shadow-sm);
}
.chip b { color: var(--text); font-weight: 680; }
.chip .i { width: 13px; height: 13px; color: var(--muted); }

.hero .actions2 { display: flex; gap: 9px; margin-top: 24px; flex-wrap: wrap; }
.risk-banner { display: grid; grid-template-columns: minmax(240px, 1.7fr) repeat(3, minmax(100px, .7fr)); gap: 1px; margin-top: 14px; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--border); box-shadow: var(--shadow-sm); }
.risk-main, .risk-stat { background: var(--surface); padding: 14px 16px; }
.risk-main { display: flex; flex-direction: column; gap: 2px; }
.risk-label, .risk-stat span { color: var(--faint); font-size: 10px; text-transform: uppercase; letter-spacing: .1em; font-weight: 700; }
.risk-main strong { font-size: 18px; letter-spacing: -.02em; }
.risk-method { color: var(--muted); font-size: 11px; margin-top: 3px; }
.risk-stat { display: flex; flex-direction: column; justify-content: center; gap: 4px; }
.risk-stat b { font-size: 17px; font-variant-numeric: tabular-nums; }
.risk-stat b small { color: var(--faint); font-size: 10px; font-weight: 600; margin-left: 2px; }
.scope-banner {
  margin-top: 14px; padding: 13px 16px; font-size: 12.5px; line-height: 1.55; color: var(--muted);
  border: 1px dashed var(--border-strong); border-radius: var(--radius-lg); background: var(--surface-2);
}
.scope-banner strong { color: var(--text); font-weight: 700; }

/* ------------------------------------------------------------ home hero */
.home-hero {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 24px;
  background: linear-gradient(180deg, var(--surface) 0%, var(--surface-2) 130%);
  box-shadow: var(--shadow-md);
  padding: 48px 50px 42px;
}
.home-hero .bg-grid {
  position: absolute; inset: 0; z-index: 0;
  -webkit-mask-image: radial-gradient(90% 110% at 85% -20%, #000 25%, transparent 75%);
  mask-image: radial-gradient(90% 110% at 85% -20%, #000 25%, transparent 75%);
}
.home-hero .scan {
  position: absolute; inset: -40% -20% auto -20%; z-index: 0; height: 180%;
  background: conic-gradient(from 200deg at 30% 0%, transparent 0deg, var(--accent-soft) 14deg, transparent 34deg);
  opacity: 0.5;
  animation: scan 9s var(--ease) infinite;
}
@keyframes scan { 50% { transform: translateX(12%); } }
.home-hero > *:not(.bg-grid):not(.scan):not(.mark-big) { position: relative; z-index: 1; }

.home-hero .mark-big {
  display: grid; place-items: center;
  width: 48px; height: 48px;
  border-radius: 13px;
  background: linear-gradient(135deg, var(--text), color-mix(in srgb, var(--text) 55%, var(--faint)));
  color: var(--accent-fg);
  margin-bottom: 20px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.18), var(--shadow-md);
}
.home-hero .mark-big .i { width: 24px; height: 24px; }
.home-hero h1 { font-size: clamp(28px, 4.8vw, 40px); letter-spacing: -0.03em; line-height: 1.12; }
.home-hero p { color: var(--muted); max-width: 640px; margin: 12px 0 0; font-size: 14.5px; line-height: 1.6; }
.home-hero .hero-pills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 22px; }
.home-hero .hero-pills .chip { background: var(--surface); }
.home-hero .hero-actions { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-top: 24px; }
.home-hero .hero-note { color: var(--faint); font-size: 11.5px; margin-left: 3px; }

.demo-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.demo-card {
  display: flex; flex-direction: column; min-height: 190px;
  padding: 18px 19px 16px; border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: linear-gradient(180deg, var(--surface), var(--surface-2));
  box-shadow: var(--shadow-sm); transition: border-color var(--ease), transform 180ms var(--ease), box-shadow var(--ease);
}
.demo-card:hover { border-color: var(--border-strong); transform: translateY(-3px); box-shadow: var(--shadow-md); }
.demo-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.demo-mark { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 10px; background: var(--surface); border: 1px solid var(--border); color: var(--text-2); }
.demo-mark .i { width: 16px; height: 16px; }
.demo-card h3 { margin-top: 18px; font-size: 15px; }
.demo-card p { color: var(--muted); font-size: 12.5px; line-height: 1.55; margin-top: 5px; }
.demo-link { display: inline-flex; align-items: center; gap: 5px; width: fit-content; margin-top: auto; padding: 9px 0 2px; border: 0; background: transparent; color: var(--text); font: inherit; font-size: 12px; font-weight: 700; cursor: pointer; }
.demo-link:hover { color: var(--muted); }
.demo-link .i { transition: transform 160ms var(--ease); }
.demo-link:hover .i { transform: translateX(3px); }
.demo-link:disabled { opacity: .55; cursor: wait; }

/* -------------------------------------------------------------- dropzone */
.dropzone {
  position: relative;
  overflow: hidden;
  border: 1.5px dashed var(--border-strong);
  border-radius: 20px;
  padding: 44px 24px;
  text-align: center;
  background:
    radial-gradient(360px 200px at 50% -40px, var(--accent-soft-2), transparent 70%),
    var(--surface);
  cursor: pointer;
  transition: border-color var(--ease), background var(--ease), box-shadow var(--ease), transform 160ms var(--ease);
}
.dropzone::before {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 20%, var(--accent-soft) 50%, transparent 80%);
  transform: translateX(-100%);
  transition: none;
}
.dropzone:hover::before, .dropzone.drag::before { transform: translateX(100%); transition: transform 900ms var(--ease); }
.dropzone:hover, .dropzone.drag {
  border-color: var(--text);
  background: var(--surface-2);
  box-shadow: var(--shadow-md);
}
.dropzone:active { transform: translateY(1px) scale(0.995); }

.dropzone .dz-icon {
  display: inline-grid; place-items: center;
  width: 58px; height: 58px;
  border-radius: 16px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  margin-bottom: 4px;
}
.dropzone .dz-icon .i { width: 26px; height: 26px; }
.dropzone:not(.busy):hover .dz-icon { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); transform: translateY(-1px); }
.dropzone .dz-icon { transition: background var(--ease), color var(--ease), transform 160ms var(--ease); }

.dropzone .dz-title { font-weight: 700; margin-top: 12px; font-size: 15px; }
.dropzone .dz-sub { color: var(--muted); font-size: 12.5px; margin-top: 3px; }
.dropzone .dz-hint { position: absolute; right: 14px; bottom: 12px; font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--faint); font-weight: 650; }

.dropzone .dz-state {
  position: absolute; inset: 0; z-index: 2;
  display: none;
  place-items: center;
  flex-direction: column; gap: 10px;
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: blur(6px);
  border-radius: 20px;
  color: var(--text-2); font-weight: 650; font-size: 13.5px;
}
.dropzone.busy .dz-state { display: grid; }
.spinner {
  width: 24px; height: 24px; border-radius: 50%;
  border: 2px solid var(--border-strong);
  border-top-color: var(--text);
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.err-banner {
  display: flex; gap: 10px; align-items: flex-start;
  margin-top: 14px;
  padding: 12px 16px;
  border-radius: var(--radius);
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text-2); font-size: 13px;
  border-left: 3px solid var(--text);
}
.err-banner .i { color: var(--text); flex: none; margin-top: 1px; }

/* -------------------------------------------------------------- grids */
.feat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; }
.feat {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: 18px 20px;
  position: relative;
  overflow: hidden;
  transition: border-color var(--ease), transform 180ms var(--ease), box-shadow var(--ease);
}
.feat::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: linear-gradient(180deg, transparent, var(--text), transparent);
  opacity: 0; transition: opacity var(--ease);
}
.feat:hover { border-color: var(--border-strong); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.feat:hover::before { opacity: 1; }
.feat .feat-ic {
  display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: 11px;
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text);
}
.feat .feat-ic .i { width: 18px; height: 18px; }
.feat b { display: block; margin-top: 13px; font-size: 13.5px; letter-spacing: -0.01em; }
.feat span { display: block; color: var(--muted); font-size: 12.5px; margin-top: 3px; line-height: 1.55; }

.server-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
.server-card {
  display: flex; flex-direction: column; gap: 13px;
  padding: 18px 19px 16px;
  position: relative;
  overflow: hidden;
  transition: border-color var(--ease), transform 180ms var(--ease), box-shadow var(--ease);
}
.server-card:hover { border-color: var(--border-strong); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.server-card .s-top { display: flex; align-items: flex-start; gap: 10px; }
.server-card .addr { font-family: var(--mono); font-weight: 680; font-size: 13.5px; overflow-wrap: normal; word-break: keep-all; letter-spacing: -0.01em; }
.server-card .sub { color: var(--faint); font-size: 11.5px; margin-top: 2px; }
.server-card .s-score { margin-left: auto; text-align: right; flex: none; }
.server-card .s-score b { font-size: 22px; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; line-height: 1; }
.server-card .s-score span { display: block; font-size: 10.5px; color: var(--faint); margin-top: 2px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700; }

.pbar { height: 5px; border-radius: var(--r-pill); background: var(--surface-3); overflow: hidden; }
.pbar i {
  display: block; height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--text), color-mix(in srgb, var(--text) 62%, var(--faint)));
  transition: width 1s var(--ease);
}

.server-card .s-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto; }
.server-card .s-finds { margin-top: 2px; border-top: 1px dashed var(--border); padding-top: 10px; display: flex; flex-direction: column; gap: 4px; }
.server-card .s-finds .sf { display: flex; gap: 8px; align-items: baseline; font-size: 12px; color: var(--muted); }
.server-card .s-finds .sf b { color: var(--text); font-weight: 650; font-size: 12px; }
.server-card .s-finds .sf .n { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--faint); }

/* -------------------------------------------------------------- tables */
.table-scroll {
  overflow-x: auto;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
/* 760px was set when the sessions table carried five columns, one of them a
 * duplicate of the first. With four real columns the widest sensible minimum is
 * 560px - below that the columns compress rather than the table scrolling, which
 * is what the horizontal scrollbar in a 552px column was for. The wrapper keeps
 * `overflow-x: auto` for the genuinely narrow case. */
table.tbl { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 0; }
.tbl th {
  text-align: left; padding: 12px 16px;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--faint); font-weight: 700;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  white-space: nowrap;
}
.tbl td { padding: 12px 16px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.tbl tr:last-child td { border-bottom: 0; }
.tbl tbody tr { transition: background 120ms ease; }
.tbl tbody tr.click { cursor: pointer; }
.tbl tbody tr.click:hover { background: var(--accent-soft-2); }
.tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
/* The score, the grade and the risk level read as one figure. Left to wrap, row
   2 showed "60 D -" above "MEDIUM" while row 1 fit on one line, so the same
   column looked like two different columns. The wrapper still scrolls if a
   viewport is genuinely too narrow for one line. */
.tbl .score-cell { white-space: nowrap; }
.tbl .score-cell b { font-size: 14.5px; font-variant-numeric: tabular-nums; }
.tbl .score-cell span { color: var(--faint); font-size: 10.5px; margin-left: 4px; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 700; }

.sess-main .chev { color: var(--faint); transition: transform 180ms var(--ease); }
.sess-main.open .chev { transform: rotate(90deg); color: var(--text); }
tr.sess-detail td { background: var(--surface-2); padding: 16px 16px 18px; border-top: 1px dashed var(--border); }
.sess-detail[hidden] { display: none; }

.tl-detail { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; }
.tl-cell { display: flex; flex-direction: column; gap: 2px; }
.tl-cell .k { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--faint); font-weight: 700; }
.tl-cell .v { font-family: var(--mono); font-size: 12px; color: var(--text-2); font-weight: 600; overflow-wrap: normal; word-break: keep-all; }

/* stats strip above session table */
.stat-strip { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.stat-strip .pill {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px; border-radius: var(--r-pill);
  border: 1px solid var(--border); background: var(--surface);
  font-size: 12px; color: var(--muted); box-shadow: var(--shadow-sm);
}
.stat-strip .pill b { color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; }
.stat-strip .pill .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--faint); }
.stat-strip .pill.tls .dot { background: var(--text); }
.stat-strip .pill.warn { border-color: var(--border-strong); color: var(--text); }
.coverage-strip {
  display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  margin-top: 14px; padding: 10px 13px; border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm); color: var(--muted); font-size: 11.5px;
}
.coverage-strip span { display: inline-flex; align-items: center; gap: 7px; }
.coverage-strip .i { width: 14px; height: 14px; }

/* ------------------------------------------------------------ metric band */
.metric-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
.metric {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: 16px 18px 15px;
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: border-color var(--ease), transform 180ms var(--ease), box-shadow var(--ease);
}
.metric:hover { border-color: var(--border-strong); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.metric .m-ic {
  display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 9px;
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-2); margin-bottom: 12px;
}
.metric .m-ic .i { width: 15px; height: 15px; }
.metric .m-val { font-size: 26px; font-weight: 760; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; line-height: 1; }
.metric .m-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.11em; color: var(--faint); font-weight: 700; margin-top: 5px; }
.metric .m-sub { font-size: 11.5px; color: var(--muted); margin-top: 3px; }

.sev-share { display: flex; height: 6px; border-radius: var(--r-pill); overflow: hidden; gap: 2px; margin-top: 12px; background: var(--surface-3); }
.sev-share i { display: block; height: 100%; border-radius: inherit; transition: width 800ms var(--ease); }
.sev-share i.c { background: repeating-linear-gradient(45deg, var(--text) 0 4px, color-mix(in srgb, var(--text) 55%, transparent) 4px 8px); }
.sev-share i.h { background: var(--text); }
.sev-share i.m { background: var(--muted); }
.sev-share i.l { background: var(--faint); }
.sev-share i.i { background: var(--border-strong); }
.sev-legend { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 8px; }
.sev-legend .lg { display: inline-flex; align-items: center; gap: 5px; font-size: 10.5px; color: var(--muted); }
.sev-legend .sw { width: 8px; height: 8px; border-radius: 3px; }
.sev-legend .sw.c { background: repeating-linear-gradient(45deg, var(--text) 0 3px, transparent 3px 6px); }
.sev-legend .sw.h { background: var(--text); }
.sev-legend .sw.m { background: var(--muted); }
.sev-legend .sw.l { background: var(--faint); }
.sev-legend .sw.i { background: var(--border-strong); }

/* ------------------------------------------------------------ subnav */
.subnav {
  position: sticky;
  top: 53px;
  z-index: 30;
  display: flex;
  gap: 6px;
  overflow-x: auto;
  margin-bottom: 34px;
  margin-top: 26px;
  padding: 6px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: var(--shadow-sm);
  scrollbar-width: none;
}
.subnav::-webkit-scrollbar { display: none; }
.subnav button {
  border: 0; background: transparent;
  padding: 7px 15px;
  border-radius: var(--r-pill);
  font-size: 12.5px; font-weight: 650;
  color: var(--muted);
  cursor: pointer;
  white-space: nowrap;
  display: inline-flex; align-items: center; gap: 7px;
  transition: background var(--ease), color var(--ease);
}
.subnav button:hover { color: var(--text); }
.subnav button.active { background: var(--accent); color: var(--accent-fg); box-shadow: var(--shadow-sm); }
.subnav .pill { font-family: var(--mono); font-size: 10px; padding: 1px 7px; border-radius: var(--r-pill); background: var(--accent-soft); color: var(--text-2); }
/* The count pill inside the ACTIVE tab. Both properties were var(--accent-fg), so
 * the text was painted in the same colour as its own background - a black pill on a
 * black tab in dark mode, and the count silently unreadable. The active button is
 * --accent with --accent-fg text, so the pill is a --accent-fg chip carrying
 * --accent text. Visible in a screenshot, invisible to every test. */
.subnav button.active .pill { background: var(--accent-fg); color: var(--accent); opacity: 0.92; }

/* -------------------------------------------------------------- badges */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--mono); font-size: 10.5px;
  padding: 2px 8px; border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text-2);
  white-space: nowrap; font-weight: 600;
}
.badge.lite { border-color: var(--border); background: transparent; color: var(--muted); }

.mode-tag {
  display: inline-flex;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  padding: 2px 9px; border-radius: var(--r-pill);
  border: 1px solid var(--border-strong);
  color: var(--text-2); background: var(--surface-2);
}

/* monochrome severity scale — ink density communicates risk */
.sev {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10.5px; font-weight: 750; letter-spacing: 0.04em; text-transform: uppercase;
  padding: 3px 11px; border-radius: var(--r-pill);
  border: 1px solid var(--border); background: var(--surface); color: var(--text-2);
}
.sev .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--faint); }
.sev-c { background: var(--accent); border-color: var(--accent); color: var(--accent-fg);
  background-image: repeating-linear-gradient(45deg, transparent 0 5px, color-mix(in srgb, var(--accent-fg) 9%, transparent) 5px 10px); }
.sev-c .dot { background: var(--accent-fg); opacity: 0.9; }
.sev-h { background: var(--surface); border-color: var(--text); color: var(--text); }
.sev-h .dot { background: var(--text); }
.sev-m { background: var(--surface); border-color: var(--border-strong); color: var(--text-2); }
.sev-m .dot { background: var(--muted); }
.sev-l { background: var(--surface); border-color: var(--border); color: var(--muted); }
.sev-l .dot { background: var(--faint); }
.sev-i { background: transparent; border-style: dashed; color: var(--muted); }
.sev-i .dot { background: var(--faint); }

/* ------------------------------------------------------------ findings */
.find-tools { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 15px; align-items: center; }
.seg {
  display: inline-flex; padding: 3px;
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface); box-shadow: var(--shadow-sm);
  gap: 2px;
}
.seg button {
  border: 0; background: transparent;
  color: var(--muted);
  padding: 5px 13px;
  font-size: 12px; font-weight: 650;
  cursor: pointer;
  border-radius: var(--r-pill);
  transition: background var(--ease), color var(--ease);
}
.seg button.on { background: var(--accent); color: var(--accent-fg); }
.seg button:not(.on):hover { color: var(--text); background: var(--surface-2); }

.searchbox {
  display: flex; align-items: center; gap: 8px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface);
  flex: 1 1 200px;
  min-height: 34px;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--ease), box-shadow var(--ease);
}
.searchbox .i { color: var(--faint); width: 15px; height: 15px; }
.searchbox input { flex: 1; min-width: 0; border: 0; background: transparent; color: var(--text); font: inherit; font-size: 13px; outline: 0; }
.searchbox input::placeholder { color: var(--faint); }
.searchbox:focus-within { border-color: var(--text); box-shadow: 0 0 0 3px var(--accent-soft-2); }

.find-list { display: flex; flex-direction: column; gap: 10px; }

.find-row {
  display: grid;
  grid-template-columns: 6px 1fr;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: border-color var(--ease), transform 180ms var(--ease), box-shadow var(--ease);
}
.find-row:hover { border-color: var(--border-strong); transform: translateX(2px); box-shadow: var(--shadow-md); }
.find-row .gutter { background: var(--border); opacity: 0.75; }

.find-row .f-body { padding: 15px 18px 14px; }
.find-row .f-head { display: flex; align-items: flex-start; gap: 11px; flex-wrap: wrap; }
.find-row .f-title { font-weight: 690; font-size: 13.5px; letter-spacing: -0.01em; }
.find-row .f-id { font-family: var(--mono); font-size: 10.5px; color: var(--muted); margin-top: 2px; }
.find-row .f-count {
  margin-left: auto; flex: none;
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--mono); font-size: 11px; font-weight: 700;
  color: var(--text); padding: 3px 10px; border-radius: var(--r-pill);
  border: 1px solid var(--border); background: var(--surface-2);
}
.find-row .f-desc { color: var(--text-2); font-size: 13px; margin-top: 8px; max-width: 900px; }
.find-row .f-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; color: var(--faint); font-size: 12px; }
.find-row .f-meta .sv { display: inline-flex; align-items: center; gap: 6px; }
details.rec { margin-top: 11px; }
details.rec summary {
  cursor: pointer; user-select: none;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 680; color: var(--muted);
  padding: 5px 11px; border: 1px solid var(--border); border-radius: var(--r-pill);
  transition: color var(--ease), border-color var(--ease), background var(--ease);
}
details.rec summary:hover { color: var(--text); border-color: var(--border-strong); background: var(--surface-2); }
details.rec[open] summary { margin-bottom: 9px; background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
.rec-body {
  padding: 12px 14px; color: var(--text-2); font-size: 13px;
  border-left: 2px solid var(--text); background: var(--surface-2);
  border-radius: 0 var(--radius) var(--radius) 0;
  margin-top: 2px;
}

.empty { padding: 34px; text-align: center; color: var(--muted); display: flex; flex-direction: column; align-items: center; gap: 8px; }
.empty .i { width: 26px; height: 26px; opacity: 0.6; }

/* ------------------------------------------------------------ compliance */
.comp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 13px; }
.comp {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: 18px 19px;
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: border-color var(--ease), transform 180ms var(--ease), box-shadow var(--ease);
}
.comp:hover { border-color: var(--border-strong); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.comp .c-head { display: flex; align-items: flex-start; gap: 12px; }
.comp .std { font-weight: 680; font-size: 13px; letter-spacing: -0.01em; flex: 1; }
.comp .stamp {
  flex: none;
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 10px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 4px 10px; border-radius: 8px;
}
.comp .stamp .i { width: 13px; height: 13px; }
.comp .stamp.pass { background: var(--accent); color: var(--accent-fg); box-shadow: inset 0 1px 0 rgba(255,255,255,.14); }
.comp .stamp.fail { background: transparent; color: var(--text); border: 1.5px solid var(--text); }
.comp .stamp.partial { background: transparent; color: var(--muted); border: 1.5px dashed var(--muted); }
.comp .stamp.not_assessed { background: var(--surface-2); color: var(--muted); border: 1px solid var(--border); }
.comp .c-sub { font-size: 11.5px; color: var(--muted); margin-top: 7px; }
.comp .fails { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 11px; border-top: 1px dashed var(--border); padding-top: 11px; }
.comp .fails .lbl { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--faint); font-weight: 700; margin-right: 2px; align-self: center; }

/* ------------------------------------------------------------------- ml */
.ml-band {
  display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 15px; align-items: center;
}
.ml-meter-head { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 13px; margin-bottom: 15px; }
.ml-tile { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); padding: 15px 17px; box-shadow: var(--shadow-sm); }
.ml-tile .k { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--faint); font-weight: 700; }
.ml-tile .v { font-size: 24px; font-weight: 760; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; margin-top: 4px; }
.ml-tile .pct { font-size: 11px; color: var(--muted); margin-top: 3px; }

.ml-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 13px; }
.ml-card { display: flex; flex-direction: column; gap: 12px; padding: 16px 18px; transition: border-color var(--ease), transform 180ms var(--ease), box-shadow var(--ease); }
.ml-card:hover { border-color: var(--border-strong); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.ml-card .m-head { display: flex; gap: 10px; align-items: flex-start; }
.ml-card .sess { font-family: var(--mono); font-size: 12.5px; font-weight: 650; overflow-wrap: normal; word-break: keep-all; }
.ml-card .flag { margin-left: auto; flex: none; font-size: 10px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; padding: 3px 9px; border-radius: var(--r-pill); background: var(--accent); color: var(--accent-fg); }
.ml-card .flag.soft { background: var(--surface-2); color: var(--text-2); border: 1px solid var(--border-strong); }

.meter { display: flex; flex-direction: column; gap: 3px; }
.meter .m-row { display: flex; justify-content: space-between; font-size: 11px; color: var(--muted); }
.meter .m-row b { color: var(--text); font-variant-numeric: tabular-nums; }
.meter .track { height: 6px; border-radius: var(--r-pill); background: var(--surface-3); overflow: hidden; }
.meter .track i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--faint), var(--text)); }

.ml-card .devs { display: flex; flex-wrap: wrap; gap: 5px; border-top: 1px dashed var(--border); padding-top: 11px; }

/* ------------------------------------------------------------ trends/mon */
.trend-stats { display: flex; gap: 10px; flex-wrap: wrap; align-items: stretch; }
.trend-stat {
  flex: 1 1 130px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 15px;
  background: linear-gradient(180deg, var(--surface), var(--surface-2));
  box-shadow: var(--shadow-sm);
  position: relative; overflow: hidden;
}
.trend-stat span { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--faint); font-weight: 700; }
.trend-stat b { display: block; margin-top: 3px; font-size: 22px; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.trend-stats .badge { align-self: center; }

.trend-charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 13px; margin-top: 15px; }
.trend-panel { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface-2); padding: 16px 18px; box-shadow: var(--shadow-sm); }
.trend-panel-title { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--faint); font-weight: 700; margin-bottom: 10px; display: flex; align-items: center; gap: 7px; }
.trend-panel-title .i { width: 14px; height: 14px; }
.trend-svg svg { width: 100%; height: auto; display: block; }
.trend-svg line.grid { stroke: var(--border-strong); stroke-width: 1; stroke-dasharray: 2 4; }
.trend-svg path.trend-line { fill: none; stroke: var(--text); stroke-width: 2; vector-effect: non-scaling-stroke; }
.trend-svg path.trend-area { stroke: none; }
.trend-svg circle.dot { fill: var(--surface); stroke: var(--text); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.trend-svg circle.dot.worst { fill: var(--accent); stroke: var(--accent); }
.trend-svg circle.dot.best { fill: var(--surface-3); stroke: var(--faint); }
.trend-svg rect.bar { fill: var(--border-strong); rx: 3; }
.trend-svg rect.bar-set { fill: var(--text); }
.trend-svg text.axis { fill: var(--faint); font-size: 9px; font-family: var(--mono); }
.delta { font-variant-numeric: tabular-nums; font-weight: 680; }
.delta.up { color: var(--text); }
.delta.down { color: var(--muted); }
.delta.flat { color: var(--faint); }

.grade-dot { display: inline-grid; place-items: center; min-width: 22px; height: 22px; padding: 0 5px; border-radius: 7px; font-size: 10px; font-weight: 800; background: var(--accent); color: var(--accent-fg); }
.grade-dot.ghost { background: transparent; color: var(--text); border: 1px solid var(--text); }

/* ------------------------------------------------------------- skeleton */
.skel { position: relative; overflow: hidden; background: var(--surface-2); border-radius: var(--radius-sm); }
.skel::after {
  content: ""; position: absolute; inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--surface) 70%, transparent), transparent);
  animation: shimmer 1.3s infinite;
}
@keyframes shimmer { 100% { transform: translateX(100%); } }

.panel-skel { display: flex; flex-direction: column; gap: 9px; padding: 8px 0; }

/* ---------------------------------------------------------------- footer */
.foot {
  max-width: 1140px; margin: 48px auto 0;
  padding: 24px;
  border-top: 1px solid var(--border);
  color: var(--faint); font-size: 12px;
  display: flex; gap: 14px; flex-wrap: wrap; align-items: center;
}
.foot .ml { margin-left: auto; }

/* ---------------------------------------------------------- transitions */
.view { animation: viewIn 320ms var(--ease); }
@keyframes viewIn { from { opacity: 0; transform: translateY(8px); } }

@keyframes toastIn { from { opacity: 0; transform: translate(-50%, 10px); } }
.toast {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  background: var(--accent); color: var(--accent-fg);
  padding: 10px 18px; border-radius: var(--r-pill);
  font-size: 13px; font-weight: 650;
  box-shadow: var(--shadow-lg);
  animation: toastIn 220ms var(--ease);
  z-index: 60;
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
  .view { animation: none; }
}


body { background: radial-gradient(900px 480px at 88% -8%, var(--accent-soft), transparent 65%), radial-gradient(700px 420px at -10% 20%, rgba(73, 137, 255, 0.08), transparent 62%), var(--bg); }
body::before { content: ""; position: fixed; inset: 0; pointer-events: none; opacity: .22; background-image: linear-gradient(var(--border-sub) 1px, transparent 1px), linear-gradient(90deg, var(--border-sub) 1px, transparent 1px); background-size: 42px 42px; mask-image: linear-gradient(to bottom, #000, transparent 72%); z-index: -1; }
.app-frame { min-height: 100vh; }
.app-main { flex: 1; min-width: 0; }
.foot-status b { display: inline; }
.live-dot, .context-dot { width: 7px; height: 7px; margin-top: 3px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.topbar { max-width: 1320px; height: 66px; padding: 12px 30px; background: color-mix(in srgb, var(--bg) 80%, transparent); border-bottom-color: var(--border); }
.topbar-context { display: flex; align-items: center; gap: 9px; margin-left: 4px; color: var(--faint); font: 10px var(--mono); letter-spacing: .1em; }
.topbar-context .context-dot { display: inline-block; margin: 0; width: 5px; height: 5px; box-shadow: none; }
.topbar-date { color: var(--faint); font: 10px var(--mono); letter-spacing: .08em; }
.mobile-brand { display: none; }
.shell { max-width: 1320px; padding: 0 30px 70px; }
.view { padding-top: 32px; }
.home-hero { border-color: color-mix(in srgb, var(--accent) 20%, var(--border)); background: radial-gradient(500px 260px at 90% 10%, var(--accent-soft), transparent 68%), linear-gradient(135deg, color-mix(in srgb, var(--surface) 92%, var(--accent-soft)), var(--surface-2)); box-shadow: var(--shadow-lg); }
.home-hero::after { content: ""; position: absolute; width: 360px; height: 360px; right: -100px; top: -150px; border-radius: 50%; background: radial-gradient(circle, var(--accent-soft), transparent 68%); pointer-events: none; }
.home-hero h1 { max-width: 700px; background: linear-gradient(100deg, var(--text) 15%, var(--accent) 130%); -webkit-background-clip: text; background-clip: text; color: transparent; }
.home-hero p { color: var(--text-2); max-width: 700px; }
.dropzone { border-color: color-mix(in srgb, var(--accent) 34%, var(--border)); background: radial-gradient(460px 220px at 50% -50px, var(--accent-soft), transparent 72%), var(--surface); }
.dropzone:hover, .dropzone.drag { border-color: var(--accent); background: var(--surface-2); box-shadow: 0 0 0 4px var(--accent-soft-2), var(--shadow-md); }
.dropzone .dz-icon { color: var(--accent); background: var(--accent-soft); border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }
.demo-card { background: radial-gradient(260px 140px at 100% 0, var(--accent-soft), transparent 70%), var(--surface); }
.demo-card:hover { border-color: color-mix(in srgb, var(--accent) 44%, var(--border)); }
.demo-link { color: var(--accent); }
.hero { border-color: color-mix(in srgb, var(--accent) 18%, var(--border)); background: radial-gradient(500px 240px at 8% 0, var(--accent-soft), transparent 68%), linear-gradient(180deg, var(--surface), var(--surface-2)); box-shadow: var(--shadow-lg); }
.risk-banner { border-color: color-mix(in srgb, var(--accent) 25%, var(--border)); }
.risk-main strong { color: var(--accent); }
.subnav { top: 66px; background: color-mix(in srgb, var(--bg) 78%, transparent); border-color: color-mix(in srgb, var(--accent) 18%, var(--border)); }
.subnav button.active { background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 72%, var(--text))); color: var(--accent-fg); }
.pill-btn.strong { background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 72%, var(--text))); color: var(--accent-fg); border-color: transparent; }
.pill-btn.strong:hover { filter: brightness(1.08); background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 72%, var(--text))); }
.metric:hover, .server-card:hover, .find-row:hover, .comp:hover, .ml-card:hover, .demo-card:hover { border-color: color-mix(in srgb, var(--accent) 38%, var(--border)); }
.score-num { background: linear-gradient(180deg, var(--text), var(--accent)); -webkit-background-clip: text; background-clip: text; color: transparent; }
@media (max-width: 980px) { .topbar { padding-left: 20px; padding-right: 20px; } .shell { padding-left: 20px; padding-right: 20px; } .demo-grid { gap: 10px; } }
@media (max-width: 760px) {
  .topbar { height: 60px; padding: 10px 14px; gap: 10px; }
  .topbar-date { display: none; }
  /* The brand's second line is the first thing to go: the nav links are the
     navigation, and at 60px tall they need the room more. */
  .brand-text small { display: none; }
  .shell { padding: 0 14px 50px; }
  .subnav { top: 60px; }
}

@media (max-width: 720px) {
  .topbar { padding: 10px 14px; }
  .shell { padding: 0 14px 48px; }
  .view { padding-top: 18px; }
  .hero { padding: 20px 18px; border-radius: 18px; }
  .home-hero { padding: 34px 22px 30px; border-radius: 20px; }
  .risk-banner { grid-template-columns: 1fr 1fr; }
  .risk-main { grid-column: 1 / -1; }
  .score-num { font-size: 44px; }
  .ring-wrap, .ring-svg { width: 104px; height: 104px; }
  .card-pad { padding: 16px 15px; }
  .foot { padding: 18px 14px; }
  .topbar .brand small { display: none; }
  .subnav { top: 49px; border-radius: 14px; }
  .demo-grid { grid-template-columns: 1fr; }
  .demo-card { min-height: 0; }
  .home-hero .hero-actions { align-items: stretch; }
  .home-hero .hero-note { width: 100%; margin: 2px 0 0; }
  .metric { padding: 14px 15px; }
}

:root {
  --bg: oklch(0.1500 0.0000 0.00);
  --surface: oklch(0.1831 0.0000 0.00);
  --surface-2: oklch(0.2103 0.0000 0.00);
  --surface-3: oklch(0.2620 0.0000 0.00);
  --border: rgba(245, 245, 240, 0.11);
  --border-strong: rgba(245, 245, 240, 0.22);
  --border-sub: rgba(245, 245, 240, 0.045);
  --text: oklch(0.9570 0.0000 0.00);
  --text-2: oklch(0.8342 0.0000 0.00);
  --muted: oklch(0.6584 0.0000 0.00);
  --faint: oklch(0.6054 0.0000 0.00);
  --accent: oklch(0.9324 0.0000 0.00);
  --accent-fg: oklch(0.1785 0.0000 0.00);
  --accent-soft: rgba(245, 245, 240, 0.07);
  --accent-soft-2: rgba(245, 245, 240, 0.028);
  --glow: transparent;
  --ring: rgba(245, 245, 240, 0.34);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.26);
  --shadow-md: 0 18px 42px -26px rgba(0, 0, 0, 0.78);
  --shadow-lg: 0 32px 80px -38px rgba(0, 0, 0, 0.92);
}
[data-theme="light"] {
  --bg: oklch(0.9548 0.0000 0.00);
  --surface: oklch(0.9873 0.0000 0.00);
  --surface-2: oklch(0.9540 0.0000 0.00);
  --surface-3: oklch(0.9083 0.0000 0.00);
  --border: rgba(25, 25, 24, 0.14);
  --border-strong: rgba(25, 25, 24, 0.27);
  --border-sub: rgba(25, 25, 24, 0.055);
  --text: oklch(0.2217 0.0000 0.00);
  --text-2: oklch(0.3743 0.0000 0.00);
  /* Both of these are the colour of small text, not only of hairlines and dots:
     section headings, the "/ 100" beside the score, the provenance line. At
     oklch(0.5436 0.0076 106.65) and oklch(0.6779 0.0087 106.63) they measured 4.36:1 and 2.54:1 on --surface. These
     measure 6.5:1 and 4.9:1. The four-step grey hierarchy survives - compressed,
     but every step is still a step and every step is readable. */
  --muted: oklch(0.4735 0.0000 0.00);
  --faint: oklch(0.5230 0.0000 0.00);
  --accent: oklch(0.2637 0.0000 0.00);
  --accent-fg: oklch(0.9748 0.0000 0.00);
  --accent-soft: rgba(25, 25, 24, 0.07);
  --accent-soft-2: rgba(25, 25, 24, 0.03);
  --glow: transparent;
  --ring: rgba(25, 25, 24, 0.28);
  --shadow-sm: 0 1px 2px rgba(35, 35, 30, 0.08);
  --shadow-md: 0 18px 42px -28px rgba(35, 35, 30, 0.3);
  --shadow-lg: 0 32px 80px -40px rgba(35, 35, 30, 0.34);
}
[data-theme="dark"] {
  --bg: oklch(0.1500 0.0000 0.00);
  --surface: oklch(0.1831 0.0000 0.00);
  --surface-2: oklch(0.2103 0.0000 0.00);
  --surface-3: oklch(0.2620 0.0000 0.00);
  --border: rgba(245, 245, 240, 0.11);
  --border-strong: rgba(245, 245, 240, 0.22);
  --text: oklch(0.9570 0.0000 0.00);
  --text-2: oklch(0.8342 0.0000 0.00);
  --muted: oklch(0.6584 0.0000 0.00);
  --faint: oklch(0.6054 0.0000 0.00);
  --accent: oklch(0.9324 0.0000 0.00);
  --accent-fg: oklch(0.1785 0.0000 0.00);
}
body { background: radial-gradient(900px 480px at 88% -8%, rgba(255,255,255,.045), transparent 65%), radial-gradient(700px 420px at -10% 20%, rgba(255,255,255,.025), transparent 62%), var(--bg); }
body::before { opacity: .12; background-size: 48px 48px; }
.foot-status b, .demo-link, .risk-main strong { color: var(--text); }
.live-dot, .context-dot { background: var(--text); box-shadow: none; }
.topbar { background: color-mix(in srgb, var(--bg) 88%, transparent); }
.home-hero { border-color: var(--border-strong); background: linear-gradient(135deg, var(--surface), var(--surface-2)); box-shadow: var(--shadow-lg); }
.home-hero::after { background: radial-gradient(circle, var(--surface-3), transparent 68%); opacity: .6; }
.home-hero h1 { color: var(--text); background: none; -webkit-background-clip: initial; background-clip: initial; font-family: Georgia, "Times New Roman", serif; font-weight: 400; letter-spacing: -.045em; }
.home-hero p { color: var(--text-2); }
.home-hero .scan { opacity: .08; }
.dropzone { border-color: var(--border-strong); background: linear-gradient(180deg, var(--surface), var(--surface-2)); }
.dropzone:hover, .dropzone.drag { border-color: var(--text); background: var(--surface-2); box-shadow: var(--shadow-md); }
.dropzone .dz-icon { color: var(--text); background: var(--surface-3); border-color: var(--border-strong); }
.demo-card { background: linear-gradient(180deg, var(--surface), var(--surface-2)); }
.demo-card:hover { border-color: var(--border-strong); }
.hero { border-color: var(--border-strong); background: linear-gradient(180deg, var(--surface), var(--surface-2)); box-shadow: var(--shadow-lg); }
.score-num { color: var(--text); background: none; -webkit-background-clip: initial; background-clip: initial; }
.grade-badge, .pill-btn.strong, .subnav button.active { color: var(--accent-fg); background: var(--accent); border-color: var(--accent); box-shadow: none; }
.pill-btn.strong:hover, .subnav button.active:hover { background: var(--text); border-color: var(--text); }
.subnav { background: color-mix(in srgb, var(--bg) 88%, transparent); border-color: var(--border); }
.metric:hover, .server-card:hover, .find-row:hover, .comp:hover, .ml-card:hover, .demo-card:hover { border-color: var(--border-strong); }
.risk-banner { border-color: var(--border-strong); }
@media (max-width: 760px) { .topbar-date { display: none; } }

.home-hero .scan, .home-hero::after, .dropzone::before, .skel::after { display: none; }
.home-hero .scan, .skel::after, .view, .ring-fg, .pbar i { animation: none; transition: none; }
.view { animation: none; }
.pill-btn, .icon-btn, .dropzone, .card, .metric, .server-card, .find-row, .comp, .ml-card, .demo-card, .feat, .subnav, .topnav a { transition: none; }
.pill-btn:hover, .icon-btn:hover, .dropzone:hover, .dropzone.drag, .metric:hover, .server-card:hover, .find-row:hover, .comp:hover, .ml-card:hover, .demo-card:hover, .feat:hover { transform: none; box-shadow: none; }
.pill-btn:hover { background: var(--surface); }
.pill-btn.strong:hover, .subnav button.active:hover { background: var(--accent); }
.dropzone:hover, .dropzone.drag { border-color: var(--text); }
.metric:hover, .server-card:hover, .find-row:hover, .comp:hover, .ml-card:hover, .demo-card:hover, .feat:hover { border-color: var(--border); }
.feat:hover::before { opacity: 0; }
.find-row:hover { background: var(--surface); }

/* The cell that holds a token. It may scroll rather than force the token to split,
   so a long suite name stays readable at 390px instead of being cut in half. */
.tok-cell { max-width: 320px; overflow-x: auto; overflow-y: hidden; }
.tok-cell::-webkit-scrollbar { height: 4px; }

/* ------------------------------------------------------------ report hero */

.verdict {
  margin: 7px 0 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-2);
  max-width: 62ch;
}

.sev-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 12px; }
.sev-pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; color: var(--text);
  border: 1px solid var(--border); border-radius: var(--r-pill);
  padding: 3px 10px 3px 8px; background: var(--surface-2);
}
.sev-pill .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--faint); }
/* The only two places colour is allowed to carry severity. The label text beside
 * each pill is what actually conveys it; the colour is reinforcement. */
.sev-pill.sev-c { border-color: var(--sev-crit); }
.sev-pill.sev-c .dot { background: var(--sev-crit); }
.sev-pill.sev-h { border-color: var(--sev-high); }
.sev-pill.sev-h .dot { background: var(--sev-high); }
.sev-clear {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13px; font-weight: 640; color: var(--text);
}
.sev-note { font-size: 12px; color: var(--faint); }

.actions2 .icon-only { padding: 8px 10px; }
.actions2 .icon-only svg { width: 15px; height: 15px; }

.how-scored { margin-top: 16px; border-top: 1px solid var(--border-sub); padding-top: 10px; }
.how-scored > summary {
  cursor: pointer; font-size: 12.5px; font-weight: 620; color: var(--text-2);
  list-style: none; display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 0; border-radius: 4px;
}
.how-scored > summary::-webkit-details-marker { display: none; }
.how-scored > summary::before { content: "\25B8"; font-size: 10px; color: var(--faint); }
.how-scored[open] > summary::before { content: "\25BE"; }
.how-scored > summary:hover { color: var(--text); }
.hs-body { padding: 10px 0 2px; }
.hs-body dl {
  margin: 0; display: grid; grid-template-columns: max-content 1fr;
  gap: 5px 16px; font-size: 12.5px;
}
.hs-body dt { color: var(--faint); font-weight: 600; }
.hs-body dd { margin: 0; color: var(--text); font-weight: 600; }
.hs-note { display: block; font-weight: 450; color: var(--faint); font-size: 11.5px; }
.hs-drivers { margin-top: 12px; font-size: 12.5px; color: var(--text-2); }
.hs-drivers b { display: block; color: var(--faint); font-weight: 620; margin-bottom: 4px; font-size: 12px; }
.hs-drivers ul { margin: 0; padding-left: 18px; }
.hs-drivers li { margin: 2px 0; }

.sec-foot-line {
  display: flex; align-items: center; gap: 7px;
  font-size: 12px; color: var(--faint); margin: -4px 0 12px;
}
.sec-foot-line svg { width: 14px; height: 14px; flex: none; }

/* ------------------------------------------------- findings: action vs notes */

.find-clean {
  display: flex; align-items: center; gap: 9px;
  padding: 16px 18px; border: 1px solid var(--border); border-radius: var(--r);
  background: var(--surface-2); color: var(--text); font-size: 13.5px; font-weight: 620;
}
.find-clean svg { width: 16px; height: 16px; color: var(--muted); flex: none; }

/* Info notes are collapsed by default. The summary reads as a footnote, not as a
   control that hides something important. */
.find-notes { margin-top: 10px; border-top: 1px solid var(--border-sub); padding-top: 10px; }
.find-notes > summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 600; color: var(--muted); padding: 4px 0;
  border-radius: 4px;
}
.find-notes > summary::-webkit-details-marker { display: none; }
.find-notes > summary::before { content: "\25B8"; font-size: 10px; color: var(--faint); }
.find-notes[open] > summary::before { content: "\25BE"; }
.find-notes > summary:hover { color: var(--text); }
.find-notes .find-row { opacity: 0.92; }

.find-notes-open { margin-top: 14px; }
.find-notes-open .fn-head {
  font-size: 12px; font-weight: 640; color: var(--faint);
  letter-spacing: 0.02em; text-transform: uppercase; margin-bottom: 8px;
}

.find-row .f-count { cursor: help; }
.find-row .rec-body p { margin: 0 0 8px; }

/* ------------------------------------------- servers: one compact row each */

.server-grid { display: flex; flex-direction: column; gap: 8px; }
.server-row {
  display: grid; grid-template-columns: minmax(180px, 1.4fr) minmax(120px, 1fr) minmax(140px, 1.2fr) max-content;
  gap: 14px; align-items: center; padding: 13px 16px;
}
.sr-addr { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.sr-addr .mono { font-size: 13px; font-weight: 640; overflow-wrap: normal; word-break: keep-all; }
.sr-proto { font-size: 11.5px; color: var(--faint); }
.sr-tls { font-size: 12.5px; color: var(--text-2); }
.sr-sev { display: flex; flex-wrap: wrap; gap: 6px; }
.sr-sev .sev { font-size: 11px; }
.sr-none { font-size: 12px; color: var(--faint); }
.sr-grade { text-align: right; font-size: 12.5px; color: var(--muted); white-space: nowrap; }
.sr-grade b { font-family: var(--mono); font-size: 15px; color: var(--text); margin-right: 4px; }

@media (max-width: 720px) {
  .server-row { grid-template-columns: 1fr auto; row-gap: 8px; }
  .sr-tls, .sr-sev { grid-column: 1 / -1; }
  .sr-grade { text-align: left; }
}

/* ------------------------------------------------- compliance: one list */

.comp-list { display: flex; flex-direction: column; }
.comp-row {
  display: grid; grid-template-columns: 18px minmax(150px, 1.1fr) max-content minmax(0, 2fr) auto;
  gap: 12px; align-items: center; padding: 11px 4px;
  border-bottom: 1px solid var(--border-sub);
}
.comp-row:last-child { border-bottom: 0; }
.cr-mark { display: inline-flex; color: var(--faint); }
.cr-mark svg { width: 15px; height: 15px; }
.comp-fail .cr-mark { color: var(--sev-crit); }
.comp-pass .cr-mark { color: var(--muted); }
.comp-partial .cr-mark, .comp-not_assessed .cr-mark { color: var(--faint); }
.cr-name { font-size: 13.5px; font-weight: 620; color: var(--text); }
.cr-label { font-size: 11px; font-weight: 700; letter-spacing: 0.04em; color: var(--muted); }
.comp-fail .cr-label { color: var(--sev-crit); }
.cr-reason { font-size: 12.5px; color: var(--muted); min-width: 0; }
.cr-fails { display: flex; gap: 5px; flex-wrap: wrap; justify-content: flex-end; }
.cr-fails .badge { font-size: 10.5px; }

.comp-na { margin-top: 12px; border-top: 1px solid var(--border-sub); padding-top: 10px; }
.comp-na > summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 600; color: var(--muted); padding: 4px 0; border-radius: 4px;
}
.comp-na > summary::-webkit-details-marker { display: none; }
.comp-na > summary::before { content: "\25B8"; font-size: 10px; color: var(--faint); }
.comp-na[open] > summary::before { content: "\25BE"; }
.comp-na > summary:hover { color: var(--text); }
.comp-foot { margin: 14px 0 0; font-size: 12px; color: var(--faint); }

/* The five-column row needs about 620px of its own. The viewport media query that
 * used to switch it to three columns measured the WINDOW, but the constraint is
 * the content column, which is 592px at this width - so on an 800px window the
 * wide layout stayed in force, the name column was squeezed to its 150px floor
 * and "RFC 8314 (implicit TLS)" broke across two lines as "RFC 8314 (implicit" /
 * "TLS)". A container query asks the element how much room it actually has.
 *
 * The viewport query is kept as the fallback for browsers without container
 * query support; both do the same thing. */
.comp-list { container-type: inline-size; }

@container (max-width: 700px) {
  /* `auto` for the name, not 1fr: with a 1fr name column the status label sat at
   * the far end of that column, so "N/A" read as a value belonging to nothing.
   * The slack now falls between the label and the failing-control chips, which is
   * where there is genuinely nothing to say. */
  .comp-row { grid-template-columns: 18px auto max-content minmax(0, 1fr) auto; row-gap: 4px; }
  .cr-reason { grid-column: 2 / -1; }
  .cr-fails { grid-column: 2 / -1; justify-content: flex-start; }
}

@media (max-width: 720px) {
  .comp-row { grid-template-columns: 18px minmax(0, 1fr) max-content auto; row-gap: 4px; }
  .cr-reason { grid-column: 2 / -1; }
  .cr-fails { grid-column: 2 / -1; justify-content: flex-start; }
}

/* ------------------------------------------------ sessions: four columns */

.sess-id { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.sess-id .arrow { color: var(--faint); font-size: 12px; }
.sess-sub { display: flex; align-items: center; gap: 8px; margin-top: 3px; }
.sess-sub .mono { font-size: 11px; color: var(--faint); }
.proto-tag {
  font-size: 10px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--muted); border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px;
}
/* A critical or high finding is visible on the row without expanding it. */
.sess-flag { width: 7px; height: 7px; border-radius: 50%; background: var(--sev-crit); flex: none; }
.chev-cell { width: 26px; color: var(--faint); }
.chev-cell svg { width: 16px; height: 16px; transition: transform 0.15s ease; }
tr.sess-main:hover .chev-cell svg, tr.sess-main.open .chev-cell svg { transform: translateX(2px); }

.ml-off {
  display: flex; align-items: center; gap: 9px; margin: 0;
  padding: 13px 16px; border: 1px solid var(--border); border-radius: var(--r);
  background: var(--surface-2); color: var(--muted); font-size: 13px;
}
.ml-off svg { width: 15px; height: 15px; flex: none; }

.sev-na { font-size: 13px; font-weight: 600; color: var(--faint); }

/* =====================================================================
   The gauge. This is the one element that has to read in the first second,
   so it is the one element allowed colour. The previous ring was a grey
   gradient arc: on a dark background it looked like a spinner that had
   stopped, and it encoded nothing.
   ===================================================================== */

.ring-wrap {
  position: relative; width: 146px; height: 146px; flex: none;
  display: grid; place-items: center;
}
.ring-svg { width: 146px; height: 146px; transform: rotate(-90deg); }
.ring-ticks { color: var(--text); }

.ring-track { stroke: var(--surface-3); }
.ring-fg { stroke: var(--ring-c); transition: stroke 0.3s ease; }

.ring-good { --ring-c: oklch(0.5786 0.1256 154.44); }
.ring-warn { --ring-c: oklch(0.5855 0.1248 72.89); }
.ring-bad  { --ring-c: oklch(0.5510 0.1719 24.78); }
[data-theme="dark"] .ring-good { --ring-c: oklch(0.7930 0.1803 154.00); }
[data-theme="dark"] .ring-warn { --ring-c: oklch(0.8446 0.1525 80.60); }
[data-theme="dark"] .ring-bad  { --ring-c: oklch(0.7116 0.1812 22.84); }

.ring-centre {
  position: absolute; inset: 0; display: grid; place-content: center;
  text-align: center; line-height: 1;
}
.ring-grade {
  font-size: 43px; font-weight: 300; letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums; color: var(--ring-c);
}
.ring-band {
  margin-top: 5px; font-size: 10px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-2);
}

.ring-none .ring-empty {
  font-size: 12px; font-weight: 650; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--faint); text-align: center; line-height: 1.5;
}

/* The numeric score sits beside the dial rather than inside it: a 40px letter in
   the middle and a 44px number next to it would fight, and the letter is the
   faster read. */
.score-block { min-width: 0; }
.score-num {
  font-size: 44px; font-weight: 300; letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums; color: var(--text); line-height: 1.05;
  margin-top: 2px;
}
.score-sub { margin-top: 5px; font-size: 12px; color: var(--faint); }

/* =====================================================================
   Rhythm. The page had three stacked bands of air between the hero, the
   subnav and the first section - 26px, then 34px, then 46px - which read as
   separate screens rather than one document. A dashboard earns its density
   from the data, not from padding.
   ===================================================================== */

.subnav { margin-top: 18px !important; margin-bottom: 22px !important; }
.sec { margin-top: 30px; }
.sec-head { margin-bottom: 12px; }

.hero { padding-top: 22px !important; padding-bottom: 20px !important; }
.hero .score-box { align-items: center; }

/* A wash of colour behind the dial, drawn from the grade band, so the eye lands
   on the number before it reads anything else. */
.score-box { position: relative; }
.hero.band-good .score-box::before { background: radial-gradient(circle, color-mix(in srgb, oklch(0.6217 0.1373 153.99) 18%, transparent) 0%, transparent 68%); }
.hero.band-warn .score-box::before { background: radial-gradient(circle, color-mix(in srgb, oklch(0.6822 0.1465 71.47) 20%, transparent) 0%, transparent 68%); }
.hero.band-bad  .score-box::before { background: radial-gradient(circle, color-mix(in srgb, oklch(0.5966 0.1818 24.51) 20%, transparent) 0%, transparent 68%); }
.hero.band-none .score-box::before,
.hero .score-box::before {
  content: ""; position: absolute; left: -34px; top: -30px;
  width: 210px; height: 210px; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--ring-c) 17%, transparent) 0%, transparent 68%);
  pointer-events: none; z-index: 0;
}
.score-box > * { position: relative; z-index: 1; }

/* Severity pills: a little more presence. They are the second thing a reader
   looks at and they were the same weight as a footer link. */
.sev-pill { font-size: 12.5px; padding: 4px 11px 4px 9px; gap: 7px; }
.sev-pill .dot { width: 8px; height: 8px; }
.sev-clear { font-size: 14px; }
.sev-note { font-size: 12.5px; }

.verdict { font-size: 14.5px; line-height: 1.5; margin-top: 9px; }
.actions2 { margin-top: 16px !important; }
.how-scored { margin-top: 14px; }


/* =====================================================================
   Hero composition. It used to be one flex row holding two very different
   weights - the dial on the left, everything else squeezed into a 260px
   column - so the filename, the verdict and the buttons wrapped into a narrow
   ribbon while the dial sat alone in white space. Three rows of unequal
   content is the fix: the number, the verdict beside it, then a bar that
   carries the facts and the actions on one line.
   ===================================================================== */

.hero-top {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 22px;
}

.score-line { display: flex; align-items: baseline; gap: 8px; }
.score-of {
  font-size: 15px; font-weight: 500; color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* The capture name and the severity counts belong together, on the right of
   the number: they are what the number is about. */
.hero-side {
  grid-column: 1 / -1;
  margin-top: 16px;
  padding-top: 15px;
  border-top: 1px solid var(--border);
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.fname {
  font-weight: 640; font-size: 14.5px; letter-spacing: -0.005em;
  min-width: 0; overflow-wrap: anywhere;
}

.hero-bar {
  margin-top: 14px; padding-top: 13px;
  border-top: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
.hero-bar-note {
  font-size: 11.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; letter-spacing: 0.005em;
}
.hero-bar .actions2 { margin-top: 0 !important; }

/* Below ~560px the dial, the number and the actions each want the full width.
   Letting them fight for one row is what produced the two-column ribbon. */
@media (max-width: 560px) {
  .hero-top { grid-template-columns: 1fr; gap: 14px; justify-items: start; }
  .hero-side { margin-top: 12px; padding-top: 12px; }
  .hero-bar { align-items: flex-start; flex-direction: column; gap: 10px; }
}


/* The hero card had ~55px of dead space under "How this was scored" because the
   details block inherits the row gap. */
.hero .how-scored { margin-bottom: 0; }
.hero > :last-child { margin-bottom: 0; }

/* The provenance line is reference material, not a headline: it must never be
   the thing that wraps. */
.hero-bar-note { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }


/* =====================================================================
   Findings. This is the part of the page that carries the product's actual
   answer, and it was rendering as an undifferentiated stack of grey cards:
   a severity-ranked list with nothing in the rendering that encoded the
   ranking. A reader had to read every label to learn which one mattered.

   The gutter on the left edge is the ranking, drawn. Colour is used here and
   nowhere else in the list, which is what makes it legible at a glance - a
   wall of five coloured cards would be noise, five coloured edges are not.
   ===================================================================== */

:root {
  /* Darkened from oklch(0.6251 0.1254 78.76) and oklch(0.5782 0.0539 236.96): both were used as the text colour on the
     10.5px/750 severity tag, and measured 3.51:1 and 4.13:1 against --surface.
     Small text needs 4.5:1. These measure 5.2:1 and 5.4:1. Checked by
     `every severity token used as text meets contrast`, not by eye. */
  --sev-med: oklch(0.5306 0.1086 76.59);
  --sev-low: oklch(0.5141 0.0524 237.52);
  --find-c: var(--sev-crit);
  --find-h: var(--sev-high);
  --find-m: var(--sev-med);
  --find-l: var(--sev-low);
  --find-i: var(--faint);
}
[data-theme="dark"] {
  --sev-med: oklch(0.7507 0.1295 79.85);
  --sev-low: oklch(0.7118 0.0605 238.55);
}

.find-row .gutter--c { background: var(--find-c); }
.find-row .gutter--h { background: var(--find-h); }
.find-row .gutter--m { background: var(--find-m); }
.find-row .gutter--l { background: var(--find-l); }
.find-row .gutter--i { background: var(--find-i); }

/* The tag in the finding head. Critical and high keep the restrained border
   treatment; medium and low gain a tinted dot so five cards at a glance still
   separate into three ranks instead of one. */
.find-row .sev { border-color: color-mix(in srgb, var(--find-x, var(--border)) 55%, var(--border)); }
/* `background` is set on all five, not left to the base `.sev-c` rule: that one
   paints a filled chip in --accent, so a critical tag would have been red text on
   a near-white block - about 3.3:1 at 10.5px - while the other four were outlined
   chips. One shape for all five, and the colour lives in the text and the dot. */
.find-row .sev.sev-c { background: var(--surface); color: var(--find-c); border-color: color-mix(in srgb, var(--find-c) 60%, transparent); }
.find-row .sev.sev-c .dot { background: var(--find-c); }
.find-row .sev.sev-h { color: var(--find-h); border-color: color-mix(in srgb, var(--find-h) 60%, transparent); }
.find-row .sev.sev-h .dot { background: var(--find-h); }
.find-row .sev.sev-m { color: var(--find-m); }
.find-row .sev.sev-m .dot { background: var(--find-m); }
.find-row .sev.sev-l { color: var(--find-l); }
.find-row .sev.sev-l .dot { background: var(--find-l); }

/* The title is the finding. It was 13.5px at 690 weight - the same weight as
   the rule id and very close to the body copy, so nothing led. */
.find-row .f-title { font-weight: 700; font-size: 14.5px; letter-spacing: -0.012em; line-height: 1.35; }
.find-row .f-id { margin-top: 3px; }
.find-row .f-desc { margin-top: 7px; line-height: 1.55; }
.find-row .f-body { padding: 13px 17px 12px; }
.find-row .f-head { gap: 12px; }
.find-row .rec { margin-top: 9px; }

/* A ranked list should read as ranked even with the labels stripped. */
.find-row { --find-x: var(--find-i); }
.find-row:has(.gutter--c) { --find-x: var(--find-c); }
.find-row:has(.gutter--h) { --find-x: var(--find-h); }
.find-row:has(.gutter--m) { --find-x: var(--find-m); }
.find-row:has(.gutter--l) { --find-x: var(--find-l); }


/* One control bar on the section heading's line.
 *
 * Whether the bar fits beside the heading depends on the width of the content
 * column, not the viewport - the rail is a fixed 214px - so a media query on
 * the viewport guesses wrong on every window but one. Flex wrapping decides it
 * from the space actually available, and the heading is told never to break so
 * that "Prioritized findings" cannot end up on two lines to make room.
 */
.sec-head { flex-wrap: wrap; row-gap: 10px; }
.sec-head > h2 { white-space: nowrap; }
.sec-head .find-tools {
  margin-left: auto; display: flex; align-items: center; gap: 10px;
  margin-bottom: 0; min-width: 0; flex: 0 1 auto;
}
.sec-head .seg { flex-wrap: nowrap; }
/* The search box is the only part that should shrink, and only down to a point
   where it still reads as a field rather than a smudge. */
.sec-head .searchbox { width: 190px; min-width: 120px; flex: 0 1 190px; }
@media (max-width: 520px) {
  .sec-head .searchbox { flex: 1 1 100%; width: auto; }
}


.find-row .f-meta-line {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-top: 3px;
}
.find-row .f-meta-line .f-id { margin-top: 0; }
.find-row .f-meta-line .f-count { margin-left: 0; }
/* A hairline between the two facts, so the eye reads them as one metadata
   line rather than as two unrelated labels that happen to be adjacent. */
.find-row .f-meta-line .f-count::before {
  content: ""; width: 1px; height: 9px; background: var(--border-strong);
  display: inline-block; margin-right: 9px; vertical-align: -1px;
}

/* =====================================================================
   The no-JavaScript page.

   It is a product surface, not an apology. Everything the dashboard draws
   is built by app.js, so with scripting off there was nothing on screen and
   no way to learn what the tool measures - which is also exactly what a
   text-mode fetcher, a link preview or a reader-mode extension receives.

   It is styled with the same tokens as the SPA rather than inline styles, so
   it reads as the same product in both themes rather than as a separate,
   plainer document that happens to share a name.
   ===================================================================== */

.nj {
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  padding: 40px 24px 72px;
}
.nj-in { max-width: 780px; margin: 0 auto; }

.nj-brand { display: flex; align-items: center; gap: 12px; margin-bottom: 34px; }
.nj-mark {
  display: grid; place-items: center;
  width: 38px; height: 38px; flex: none;
  border-radius: 11px;
  background: var(--accent);
  color: var(--accent-fg);
}
.nj-mark svg { width: 20px; height: 20px; }
.nj-brand strong { display: block; font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
.nj-brand small { display: block; font-size: 12px; color: var(--muted); margin-top: 1px; }

.nj h1 {
  margin: 0 0 14px;
  font-size: clamp(30px, 5.2vw, 44px);
  font-weight: 400; line-height: 1.08; letter-spacing: -0.028em;
}
.nj-lede { margin: 0 0 28px; max-width: 62ch; font-size: 15.5px; line-height: 1.6; color: var(--text-2); }

.nj-form { display: flex; flex-wrap: wrap; gap: 10px; align-items: stretch; margin-bottom: 14px; }
.nj-drop {
  flex: 1 1 320px; min-width: 0;
  display: flex; flex-direction: column; justify-content: center; gap: 4px;
  padding: 15px 17px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  cursor: pointer;
}
.nj-drop:hover { border-color: var(--accent); }
.nj-drop input { font-size: 12.5px; color: var(--muted); }
.nj-drop span { font-size: 13.5px; color: var(--text-2); }
.nj-drop strong { color: var(--text); font-weight: 650; }
.nj-drop code { font-family: var(--mono); font-size: 12.5px; color: var(--muted); }

.nj-form button {
  flex: 0 0 auto; align-self: stretch;
  padding: 0 22px;
  border: 0; border-radius: var(--radius-lg);
  background: var(--accent); color: var(--accent-fg);
  font: inherit; font-size: 14px; font-weight: 650; cursor: pointer;
}
.nj-form button:hover { opacity: 0.92; }

.nj-note { margin: 0 0 12px; font-size: 13px; color: var(--muted); }
.nj-demos { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 40px; }
.nj-demo {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 14px;
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--surface); color: var(--text-2);
  font-size: 13px; font-weight: 550; text-decoration: none;
}
.nj-demo:hover { border-color: var(--border-strong); color: var(--text); }

.nj h2 {
  margin: 0 0 16px; padding-top: 26px;
  border-top: 1px solid var(--border-sub);
  font-size: 11.5px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted);
}
.nj-facts {
  display: grid; grid-template-columns: 148px minmax(0, 1fr);
  gap: 9px 20px; margin: 0 0 34px;
  font-size: 13.5px; line-height: 1.55;
}
.nj-facts dt { font-family: var(--mono); font-size: 12.5px; color: var(--text); }
.nj-facts dd { margin: 0; color: var(--text-2); }

.nj-foot {
  margin: 0; padding-top: 20px; border-top: 1px solid var(--border-sub);
  font-size: 12.5px; color: var(--muted); line-height: 1.6;
}

@media (max-width: 560px) {
  .nj { padding: 28px 16px 56px; }
  .nj-facts { grid-template-columns: 1fr; gap: 3px; }
  .nj-facts dd { margin-bottom: 11px; }
}

/* =====================================================================
   Which server a finding was seen on, and filtering by area.

   The server was only inside the expanded panel, so the one fact that tells
   a reader where to go was a click away - and a reader working a queue of
   findings is exactly the reader who needs it on the row.

   The area filter sits beside the severity filter rather than inside it:
   severity answers "how bad", area answers "which part of the system", and
   they are independent questions. Grouping is read off the rule id prefix
   (MAIL / TLS / CERT), so a new rule inherits the right facet.
   ===================================================================== */

.find-row .f-where {
  display: inline-flex; align-items: center; gap: 5px;
  color: var(--muted); font-size: 11.5px;
  min-width: 0;
}
.find-row .f-where .mono {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 22ch;
}
.find-row .f-where svg { color: var(--faint); flex: none; }

.sec-head .seg-facet {
  border-left: 1px solid var(--border); padding-left: 9px; margin-left: 1px;
}
.sec-head .seg-facet .facet-n {
  font-size: 9.5px; font-weight: 700; opacity: 0.55;
  font-variant-numeric: tabular-nums; margin-left: 2px;
}
.sec-head .seg-facet button.on .facet-n { opacity: 0.75; }

@media (max-width: 900px) {
  .sec-head .seg-facet { border-left: 0; padding-left: 0; margin-left: 0; }
  .sec-head .seg-facet button:not(.on) .facet-n { display: none; }
}

/* =====================================================================
   Worked examples on the landing page.

   An upload form cannot answer "what does this produce?". These four cards
   can, and every number in them was measured: lab/examples.py runs the shipped
   pipeline over the lab captures and a test fails if the file drifts from what
   the tool now produces. The grade is the thing that reads at a glance, so it
   is the one element carrying the band colour - the same single definition of
   the band the report's gauge uses.
   ===================================================================== */

.strip-link { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.strip { min-width: 0; }

.strip-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(268px, 1fr));
}

.strip-card {
  position: relative;
  display: flex; gap: 13px; align-items: flex-start;
  padding: 14px 15px;
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface);
  min-width: 0;
  overflow: hidden;
}
/* The band reaches the reader before the number does. Two stops of the grade
   colour, not a fill: the strip is four cards side by side and four filled
   blocks would be a traffic light rather than evidence. */
.strip-card::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--strip-c, var(--border));
}
.strip-card.band-good { --strip-c: oklch(0.5786 0.1256 154.44); }
.strip-card.band-warn { --strip-c: oklch(0.5855 0.1248 72.89); }
.strip-card.band-bad  { --strip-c: oklch(0.5510 0.1719 24.78); }
.strip-card.band-none { --strip-c: var(--border-strong); }
[data-theme="dark"] .strip-card.band-good { --strip-c: oklch(0.7930 0.1803 154.00); }
[data-theme="dark"] .strip-card.band-warn { --strip-c: oklch(0.8446 0.1525 80.60); }
[data-theme="dark"] .strip-card.band-bad  { --strip-c: oklch(0.7116 0.1812 22.84); }

.strip-grade {
  flex: none;
  font-size: 26px; font-weight: 300; letter-spacing: -0.03em; line-height: 1;
  color: var(--strip-c, var(--text));
  min-width: 1.3em; text-align: center;
}

.strip-body { min-width: 0; flex: 1; }
.strip-head {
  font-size: 13.5px; font-weight: 620; line-height: 1.35;
  color: var(--text); letter-spacing: -0.005em;
}
.strip-nums {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: 5px;
}
.strip-score {
  font-size: 17px; font-weight: 400; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; color: var(--text);
}
.strip-of { font-size: 11.5px; color: var(--muted); margin-left: 1px; }
.strip-cov { font-size: 11.5px; color: var(--muted); }
.strip-sevs { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 8px; }
.strip-sev {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.strip-sev .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted); flex: none; }
.strip-sev.ssev-c .dot { background: var(--sev-crit); }
.strip-sev.ssev-h .dot { background: var(--sev-high); }
.strip-sev.ssev-m .dot { background: var(--sev-med); }
.strip-sev.ssev-l .dot { background: var(--sev-low); }
.strip-sev.ssev-i .dot { background: var(--faint); }
/* No background, border or padding on these, ever: the chip is a label and a dot.
   If it starts picking up a chip shape, a modifier name has collided with one
   belonging to a different element. */
.strip-sev { background: transparent; border: 0; padding: 0; }

/* The capture name, so every number on the strip is traceable to a named artefact
   rather than floating free. Small and mono for the same reason rule ids are. */
.strip-capture { margin-top: 3px; font-size: 10.5px; color: var(--faint); }

/* =====================================================================
   Horizontal navigation, and the header it lives in.

   Three links in a 214px rail was a quarter of an 800px window spent on
   navigation, and the column it left behind was too narrow for the sessions
   table. The links move into the header; the content gets the width back.

   The nav is a segmented control rather than a list of links: the active page is
   filled, the others are quiet, and the state is carried by background and colour
   rather than by a heavier font or an underline that moves on hover. That is the
   shadcn pattern - `bg-accent text-accent-foreground` on the selected item - and
   it is what makes the header read as one control instead of three buttons.
   ===================================================================== */

.topbar {
  display: flex; align-items: center; gap: 18px;
  height: 66px; padding: 0 26px;
}
.brand { display: flex; align-items: center; gap: 10px; flex: none; text-decoration: none; }
.brand-text { display: flex; flex-direction: column; line-height: 1.2; }
.brand-text b { font-size: 14.5px; font-weight: 700; letter-spacing: -0.015em; color: var(--text); }
.brand-text small { font-size: 11px; color: var(--muted); margin-top: 1px; }

.topnav {
  display: flex; align-items: center; gap: 2px;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.topnav::-webkit-scrollbar { display: none; }

.topnav a {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 13px;
  border-radius: var(--radius-pill);
  color: var(--muted);
  font-size: 13px; font-weight: 560; white-space: nowrap;
  text-decoration: none;
  /* One transition, on the two properties that actually change. A link that
     animates everything looks busy; one that animates its own background and
     text colour reads as a state change. */
  transition: background 150ms var(--ease), color 150ms var(--ease);
}
.topnav a svg { width: 15px; height: 15px; opacity: 0.75; transition: opacity 150ms var(--ease); }
.topnav a:hover { background: var(--surface-3); color: var(--text); }
.topnav a:hover svg { opacity: 1; }
.topnav a:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }

/* Active page. Filled, so the current location is unambiguous at a glance without
   relying on position in the bar. Set by render() from the route. */
.topnav a.on {
  background: var(--accent); color: var(--accent-fg);
  font-weight: 640;
}
.topnav a.on svg { opacity: 1; }

.topbar .actions { margin-left: auto; display: flex; align-items: center; gap: 10px; flex: none; }

@media (max-width: 620px) {
  .topbar { gap: 10px; }
  .brand-text b { font-size: 13.5px; }
  /* Labels go before the nav does: three icons still identify the destinations,
     three truncated words do not. */
  .topnav a span { display: none; }
  .topnav a { padding: 6px 10px; }
}

@media (prefers-reduced-motion: reduce) {
  .topnav a, .topnav a svg { transition: none; }
}

/* =====================================================================
   Motion.

   One easing curve, one duration pair, applied only to things that respond to
   input. shadcn's rule is the right one and it is worth stating: motion belongs
   on state change, not on arrival. Nothing here animates a number or a severity
   colour - a score that counts up is decoration on a number the reader has to
   trust, and a severity that fades in is a severity that can be missed.

   Two durations, both short. 150ms reads as instant but shows the change;
   anything longer makes a tool feel slow to get out of the way.
   ===================================================================== */

:root {
  --dur-fast: 150ms;
  --dur: 220ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

/* Interactive surfaces. Border and background only - a shadow that animates on
   hover reads as the card lifting, which is decoration in an instrument. */
.card,
.server-card,
.find-row,
.strip-card,
.ml-card,
.demo-card,
.compl-card,
.dropzone,
.stat-strip > * {
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

/* Controls. */
.pill-btn,
.icon-btn,
.seg button,
.topnav a,
.searchbox,
.swatch,
.badge,
.chip {
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              opacity var(--dur-fast) var(--ease-out);
}

/* The subnav tabs move between views, so the indicator moving is the cue. */
.subnav button {
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

/* Rows that expand. Height is not animatable to an unknown value, so the detail
   fades as it opens - short enough that it is not noticed as an animation. */
.sess-detail[hidden] { display: none; }
.sess-detail td > * { animation: detail-in var(--dur) var(--ease-out) both; }
@keyframes detail-in {
  from { opacity: 0; transform: translateY(-3px); }
  to { opacity: 1; transform: none; }
}

/* A visible focus ring, not just an outline the browser guesses at. Keyboard
   users get the same affordance as a hover. */
:where(a, button, input, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Hover affordances that did not exist before, kept quiet on purpose: no lift,
   no glow, no scale. A row that grows under the cursor makes the thing under the
   cursor change. */
.find-row:hover,
.server-card:hover,
.strip-card:hover {
  border-color: var(--border-strong);
  background: var(--surface-2);
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: 1ms; --dur: 1ms; }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}
