/* One stylesheet (02c §28.3).
 *
 * Light by default, dark on request, high-contrast and dense in both. No
 * external fonts and no CDN: a dependency-free front end still runs unchanged
 * in three years, which is the decisive consideration for a single maintainer
 * (NFR-M-02).
 *
 * §28.1 forbids the portal from showing log data. It does not ask the portal to
 * look unfinished, and an earlier version of this sheet confused the two. What
 * the portal *does* hold — the shift, the queue's shape, scores, skill, spend,
 * rule health — is real data and is drawn properly here.
 *
 * Three ideas carry the design:
 *
 *   1. **Typeface carries role.** Prose, labels and controls are set in the
 *      system UI face; every identifier, address, timestamp, score and fragment
 *      of SPL is set in mono. That is the same distinction the platform draws
 *      between what the portal says and what the evidence says.
 *
 *   2. **Colour means risk.** The severity ramp and the accent are the only
 *      saturated things on screen. Nothing is coloured for decoration, so a red
 *      edge always means the same thing wherever it appears.
 *
 *   3. **The shared clock.** §27.2 says the exercise is choosing between open
 *      cases "with severity and ageing in tension". The queue therefore puts
 *      every case on one shared time axis instead of printing four remaining-
 *      minute figures and asking the learner to compare them in their head. */

/* ---------------------------------------------------------------- tokens -- */

/* **Light is the default** (§28.3, amended). The tools a learner will actually
   sit at — Elastic Security's alerts view, Splunk ES Mission Control — both
   ship light, and a training portal that matches the register of the real
   console is the whole point of the exercise. Dark remains a first-class
   choice, not an afterthought: every token below is redefined for it, and
   nothing else in this sheet knows which theme is in force. */
:root {
  color-scheme: light;

  --bg: #f6f8fb;
  --bg-2: #eef2f7;

  /* Cards are a gradient, not a flat fill, and they carry a hairline of light
     along the top edge. That is what makes a panel read as sitting above the
     page rather than being a differently-coloured region of it. */
  --card-top: #ffffff;
  --card-bottom: #fbfcfe;
  --card-line: #dbe2ec;
  --card-line-lit: #c3ceda;
  --edge-light: rgba(255, 255, 255, .9);
  --well: #f2f5f9;

  --line: #e4e9f0;
  --line-2: #d3dae4;
  --line-3: #b4bfcd;

  --ink: #101828;
  --ink-2: #4a5768;
  --ink-3: #7b8798;

  --accent: #1f6feb;
  --accent-2: #1a5fd0;
  --accent-ink: #ffffff;
  --accent-wash: rgba(31, 111, 235, .1);
  --accent-glow: rgba(31, 111, 235, .28);

  /* Severity is ordinal, not categorical: it runs critical → info and always
     ships with its own word and a four-segment level meter, so nothing is asked
     to carry identity by hue alone. */
  --critical: #d92d3c;
  --high: #d4711d;
  --medium: #a8820c;
  --low: #1f6feb;
  --info: #6b7789;

  --good: #10814f;
  --warn: #a8820c;
  --bad: #d92d3c;

  --ui: ui-sans-serif, system-ui, -apple-system, "Segoe UI Variable Text",
        "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", "SFMono-Regular", Menlo, Consolas,
          "DejaVu Sans Mono", monospace;

  --r: 10px;
  --r-sm: 6px;
  --rail: 3px;
  --measure: 68ch;

  --shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 8px 24px -12px rgba(16, 24, 40, .18);

  /* Surfaces that are not one of the ink or line steps: the chrome's
     translucent fill, the raised look of a control, and the two row states.
     Stated per theme rather than as an overlay, because "slightly lifted" is
     not the same operation on white as it is on black — a white wash that
     lifts a dark panel is invisible on a light one. */
  --chrome: linear-gradient(180deg, rgba(255, 255, 255, .93), rgba(250, 251, 253, .9));
  --chrome-inset: rgba(16, 24, 40, .03);
  --overlay: rgba(16, 24, 40, .05);
  --overlay-soft: rgba(16, 24, 40, .022);
  --btn-top: #ffffff;
  --btn-bottom: #f8fafc;
  --btn-top-hover: #f5f8fc;
  --btn-bottom-hover: #eef3f9;
  --row-hover-top: #f8fafd;
  --row-hover-bottom: #f3f6fa;
  --breach-top: #fdf3f4;
  --breach-bottom: #fbebed;
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #080b11;
  --bg-2: #0c1119;

  --card-top: #161d29;
  --card-bottom: #111721;
  --card-line: #232c3b;
  --card-line-lit: #2e3949;
  --edge-light: rgba(255, 255, 255, .045);
  --well: #070a0f;

  --line: #1d2530;
  --line-2: #2a3442;
  --line-3: #3a4757;

  --ink: #eaeff7;
  --ink-2: #97a5ba;
  --ink-3: #64718a;

  --accent: #4c8dff;
  --accent-2: #7fb0ff;
  --accent-ink: #04101f;
  --accent-wash: rgba(76, 141, 255, .13);
  --accent-glow: rgba(76, 141, 255, .35);

  /* Stepped for a dark surface rather than reused from the light set: the same
     hex on black is a different colour to the eye, and the mid-tones are the
     ones that break. */
  --critical: #ff5c6c;
  --high: #ff9245;
  --medium: #f0c04b;
  --low: #4c8dff;
  --info: #7d8ca3;

  --good: #3ecf8e;
  --warn: #f0c04b;
  --bad: #ff5c6c;

  --shadow: 0 1px 2px rgba(0, 0, 0, .5), 0 10px 30px -12px rgba(0, 0, 0, .7);

  --chrome: linear-gradient(180deg, rgba(22, 29, 41, .92), rgba(12, 17, 25, .92));
  --chrome-inset: rgba(255, 255, 255, .03);
  --overlay: rgba(255, 255, 255, .06);
  --overlay-soft: rgba(255, 255, 255, .022);
  --btn-top: #1e2634;
  --btn-bottom: #171e29;
  --btn-top-hover: #253040;
  --btn-bottom-hover: #1c2531;
  --row-hover-top: #1a2230;
  --row-hover-bottom: #141b25;
  --breach-top: #241a22;
  --breach-bottom: #1c151b;
}

* { box-sizing: border-box; }

/* ----------------------------------------------------------------- base -- */

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

body {
  margin: 0;
  color: var(--ink);
  font-family: var(--ui);
  font-size: 14px;
  line-height: 1.55;
  font-variant-numeric: tabular-nums;
  background: var(--bg);
  min-height: 100vh;
}

/* Dark gets two very wide, very faint washes. They give the page a light
   source, which is what stops a dark interface reading as a void. At this
   opacity they are never seen as gradients, only felt as depth. On white there
   is nothing to model, so the light default stays flat. */
:root[data-theme="dark"] body {
  background:
    radial-gradient(120rem 60rem at 12% -20%, rgba(76, 141, 255, .07), transparent 60%),
    radial-gradient(90rem 50rem at 100% 0%, rgba(255, 92, 108, .04), transparent 55%),
    var(--bg);
  background-attachment: fixed;
}

code, pre, kbd, samp, .mono,
td.ref, .kpi-value, .stat-value, .badge, .chip, .lane-label, .ruler, .score {
  font-family: var(--mono);
}

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

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
::selection { background: color-mix(in srgb, var(--accent) 28%, transparent); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 20;
  padding: .5rem .9rem; background: var(--accent); color: var(--accent-ink);
  font-weight: 600; border-radius: 0 0 var(--r-sm) 0;
}
.skip:focus { left: 0; top: 0; }

/* --------------------------------------------------------------- chrome -- */

.bar {
  display: flex; gap: 1.25rem; align-items: center;
  padding: 0 1.5rem; height: 56px;
  background: var(--chrome);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--card-line);
  box-shadow: 0 1px 0 var(--chrome-inset) inset;
  position: sticky; top: 0; z-index: 10;
}

/* The shift, drawn on the chrome itself: a hairline along the top edge that
   fills as the planned minutes are worked. It is on every page because the
   shift governs every page, and it costs no space at all. */
.bar::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px; background: var(--line);
}
.bar::after {
  content: ""; position: absolute; left: 0; top: 0;
  width: var(--shift-pct, 0); height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
}
.bar.paused::after { background: var(--warn); }
.bar.off::before, .bar.off::after { display: none; }

.brand {
  display: flex; align-items: center; gap: .6rem;
  color: var(--ink); font-weight: 700; font-size: 13px; letter-spacing: .18em;
}
.brand:hover { color: var(--ink); text-decoration: none; }
.brand svg { display: block; }

.bar nav { display: flex; gap: .15rem; flex: 1; flex-wrap: wrap; }
.bar nav a {
  position: relative; padding: .4rem .7rem; border-radius: var(--r-sm);
  color: var(--ink-2); font-size: 13px; font-weight: 500;
  transition: color .15s ease, background-color .15s ease;
}
.bar nav a:hover { color: var(--ink); background: var(--overlay); text-decoration: none; }
.bar nav a.on { color: var(--ink); background: var(--overlay); }
.bar nav a.on::after {
  content: ""; position: absolute; left: .7rem; right: .7rem; bottom: -11px;
  height: 2px; background: var(--accent); border-radius: 2px 2px 0 0;
  box-shadow: 0 0 10px var(--accent-glow);
}

.shift-chip {
  display: inline-flex; align-items: center; gap: .55rem;
  padding: .35rem .75rem .35rem .6rem;
  border: 1px solid var(--card-line); border-radius: 999px;
  background: linear-gradient(180deg, var(--card-top), var(--card-bottom));
  font-family: var(--mono); font-size: 11.5px; color: var(--ink-2);
  white-space: nowrap;
}
.shift-chip:hover { border-color: var(--card-line-lit); color: var(--ink); text-decoration: none; }

/* Which analyst is signed in. Quiet by design — it is orientation, not a
   control, and it sits beside `sign out` because that is where a reader looks
   to answer "whose session is this". */
.who {
  font-family: var(--mono); font-size: 11.5px; color: var(--ink-3);
  white-space: nowrap; margin-right: .35rem;
}
.shift-chip .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ink-3); flex: none; }
.shift-chip.live .dot {
  background: var(--good);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--good) 16%, transparent), 0 0 10px color-mix(in srgb, var(--good) 60%, transparent);
}
.shift-chip.paused .dot { background: var(--warn); box-shadow: 0 0 0 3px color-mix(in srgb, var(--warn) 16%, transparent); }
.shift-chip strong { color: var(--ink); font-weight: 600; }

.bar form { margin: 0; }

/* The theme switch. A real form posting to a real route, so it works with
   JavaScript off; `soe.js` upgrades it to an instant flip with no round trip.
   The preference is a cookie the server reads before it renders, which is what
   stops the page painting dark and then jumping to light. */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0;
  border: 1px solid var(--card-line); border-radius: var(--r-sm);
  background: linear-gradient(180deg, var(--card-top), var(--card-bottom));
  color: var(--ink-2); box-shadow: none;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--card-line-lit); }
.theme-toggle svg { display: block; }
/* One icon per theme: the control shows what it will switch *to*, which is the
   convention every OS uses and the one users guess right. Light is the default,
   so the moon shows first. */
.theme-toggle .to-light { display: none; }
.theme-toggle .to-dark { display: block; }
:root[data-theme="dark"] .theme-toggle .to-light { display: block; }
:root[data-theme="dark"] .theme-toggle .to-dark { display: none; }

/* Glow is a property of the dark theme, not of the components. On white a
   coloured halo reads as a printing fault; on black it reads as a light
   source, which is the only reason it is here at all. */
:root[data-theme="dark"] .brand svg { filter: drop-shadow(0 0 6px var(--accent-glow)); }
:root[data-theme="dark"] .bar::after { box-shadow: 0 0 12px var(--accent-glow); }
:root[data-theme="dark"] .bar.paused::after { box-shadow: 0 0 12px color-mix(in srgb, var(--warn) 35%, transparent); }
:root[data-theme="dark"] .bar nav a.on::after { box-shadow: 0 0 10px var(--accent-glow); }
:root[data-theme="dark"] .lane-bar { box-shadow: 0 0 14px -2px var(--sev, var(--accent)); }
:root[data-theme="dark"] button.primary { box-shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 0 20px -6px var(--accent-glow); }

/* --------------------------------------------------------------- layout -- */

main { max-width: 1240px; margin: 0 auto; padding: 2rem 1.5rem 5rem; }
section { margin-bottom: 2rem; }

h1 { font-size: 22px; line-height: 1.25; font-weight: 650; letter-spacing: -.01em; margin: 0 0 .35rem; }
h1 .ref { font-family: var(--mono); font-weight: 600; letter-spacing: 0; }

/* The head of a record, set the way the head of a record is set: a kicker that
   names what kind of thing this is, then the identifier at a size that admits
   it is the title. A case reference is the one string on the page a learner
   reads aloud to somebody else. */
.record { margin-bottom: 1.5rem; }
.record-kicker {
  display: block; font-family: var(--mono);
  font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--accent); margin-bottom: .4rem;
}
.record h1 {
  font-family: var(--mono); font-size: 32px; font-weight: 600;
  letter-spacing: -.025em; line-height: 1.1;
}
.record-line { display: flex; align-items: center; gap: .85rem; flex-wrap: wrap; }

/* The eyebrow. A tracked label with a hairline running to the edge — the way a
   form separates one part of a record from the next. Structural, not
   decorative: each marks a genuinely separate part of the record, and there is
   no numbering because these are parts, not steps. */
h2 {
  display: flex; align-items: center; gap: .85rem;
  font-size: 11px; font-weight: 650; text-transform: uppercase;
  letter-spacing: .14em; color: var(--ink-2); margin: 2rem 0 .85rem;
}
h2::after { content: ""; flex: 1; height: 1px; background: linear-gradient(90deg, var(--line-2), transparent); }
h3 { font-size: 13.5px; font-weight: 620; margin: 1.1rem 0 .3rem; color: var(--ink); }

p { margin: .45rem 0; }
main p { max-width: var(--measure); }

/* A card. Gradient body, hairline border, a line of light along the top edge,
   and a soft shadow beneath — the four things that together make a surface. */
.card {
  position: relative;
  background: linear-gradient(180deg, var(--card-top), var(--card-bottom));
  border: 1px solid var(--card-line);
  border-radius: var(--r);
  box-shadow: var(--shadow);
  padding: 1.15rem 1.3rem;
}
.card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--edge-light) 20%, var(--edge-light) 80%, transparent);
  border-radius: var(--r) var(--r) 0 0;
}
.card > :first-child { margin-top: 0; }
.card > :last-child { margin-bottom: 0; }
.card h2:first-child { margin-top: 0; }
.card-title {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: .14em;
  color: var(--ink-2); margin: 0 0 .9rem;
}

/* The dashboard grid. Twelve columns so a panel can be a third, a half or two
   thirds without inventing a new class each time. */
.grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 1.1rem; }
.col-3 { grid-column: span 3; }
.col-4 { grid-column: span 4; }
.col-5 { grid-column: span 5; }
.col-6 { grid-column: span 6; }
.col-7 { grid-column: span 7; }
.col-8 { grid-column: span 8; }
.col-9 { grid-column: span 9; }
.col-12 { grid-column: span 12; }

.meta, .hint, .quiet { color: var(--ink-2); font-size: 12.5px; }
.quiet { color: var(--ink-3); }
.hint { display: block; font-weight: 400; color: var(--ink-3); }
.meta .sep { color: var(--line-3); margin: 0 .2rem; }
.paused { color: var(--warn); font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: .1em; }

/* ----------------------------------------------------------------- kpis -- */

/* The hero. One number at a size that admits it is the answer, with the ring
   beside it carrying the same figure as a shape. Everything else on the shift
   card is subordinate to it. */
.kpi { display: flex; align-items: center; gap: 1.4rem; }
.kpi-figure { flex: none; }
.kpi-body { min-width: 0; }
.kpi-value {
  font-size: 40px; font-weight: 600; line-height: 1; letter-spacing: -.03em;
  color: var(--ink); display: block;
}
.kpi-value small { font-size: 15px; color: var(--ink-3); font-weight: 400; letter-spacing: 0; }
.kpi-label {
  display: block; font-size: 10.5px; text-transform: uppercase;
  letter-spacing: .14em; color: var(--ink-3); margin-bottom: .35rem;
}
.kpi-note { display: block; font-size: 12.5px; color: var(--ink-2); margin-top: .4rem; }

.stats { display: grid; gap: .9rem; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); }
.stat-label { display: block; font-size: 10.5px; text-transform: uppercase; letter-spacing: .12em; color: var(--ink-3); }
.stat-value { display: block; font-size: 24px; line-height: 1.2; color: var(--ink); margin-top: .2rem; font-weight: 600; letter-spacing: -.02em; }
.stat-value small { font-size: 12px; color: var(--ink-3); font-weight: 400; }
.stat-note { display: block; font-size: 11.5px; color: var(--ink-3); }
.stat.bad .stat-value { color: var(--bad); }
.stat.good .stat-value { color: var(--good); }
.stat.warn .stat-value { color: var(--warn); }

/* A depleting rail. One shape for every quantity on this site that is a
   fraction of something fixed, so it only has to be learned once. */
.meter {
  --pct: 0%; --meter-colour: var(--accent);
  position: relative; height: 5px; border-radius: 3px;
  background: var(--well); border: 1px solid var(--line); overflow: hidden;
}
.meter::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: var(--pct);
  background: linear-gradient(90deg, color-mix(in srgb, var(--meter-colour) 60%, transparent), var(--meter-colour));
}
.meter.warn { --meter-colour: var(--warn); }
.meter.bad { --meter-colour: var(--bad); }
.meter.good { --meter-colour: var(--good); }
.meter + .meter-label, .stat .meter { margin-top: .5rem; }
.meter-label { display: block; font-size: 11px; color: var(--ink-3); margin-bottom: .3rem; }
.meter-label.warn { color: var(--warn); }
.meter-label.bad { color: var(--bad); }

/* --------------------------------------------------- the SOC panel row -- */

/* Elastic Security and Splunk ES Mission Control converge on the same layout
   above a triage queue: a strip of current state, then a row of breakdown
   panels — the mix by severity, the mix by status, and what the open work has
   in common — and only then the queue itself. It is worth copying because it
   answers the three questions an analyst asks before picking a case, in the
   order they ask them, and none of it is log data. */

.strip {
  display: flex; flex-wrap: wrap; align-items: stretch; gap: 0;
  border: 1px solid var(--card-line); border-radius: var(--r);
  background: linear-gradient(180deg, var(--card-top), var(--card-bottom));
  box-shadow: var(--shadow); overflow: hidden;
}
.strip-cell { padding: .7rem 1.05rem; flex: 1 1 9rem; min-width: 0; border-right: 1px solid var(--card-line); }
.strip-cell:last-child { border-right: 0; }
.strip-cell.actions-cell { flex: 0 0 auto; display: flex; align-items: center; gap: .55rem; }
.strip-label { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .14em; color: var(--ink-3); }
.strip-value { display: block; font-size: 15px; font-weight: 600; color: var(--ink); margin-top: .15rem; letter-spacing: -.01em; }
.strip-value.ref { font-family: var(--mono); }
.strip-cell .meter { margin-top: .45rem; }

/* A legend that is also a table, which is how Elastic renders the severity
   ring: swatch, name, count. Colour never carries a value on its own. */
.legend { list-style: none; margin: 0; padding: 0; display: grid; gap: .1rem; }
.legend li {
  display: grid; grid-template-columns: 10px 1fr auto; align-items: center;
  gap: .6rem; padding: .3rem 0; border-bottom: 1px solid var(--line); font-size: 12.5px;
}
.legend li:last-child { border-bottom: 0; }
.legend .swatch { width: 9px; height: 9px; border-radius: 2px; background: var(--sev, var(--ink-3)); }
.legend .name { color: var(--ink-2); }
.legend .count { font-family: var(--mono); color: var(--ink); font-weight: 600; }

/* A ranked list with the proportion drawn as a rule under each row — Elastic's
   "Top alerts by" panel. Denser than a bar chart and it keeps the value
   readable, which is the whole reason that panel is a list and not a chart. */
.topn { list-style: none; margin: 0; padding: 0; }
.topn li { padding: .45rem 0 .5rem; border-bottom: 1px solid var(--line); }
.topn li:last-child { border-bottom: 0; }
.topn .row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.topn .key { font-family: var(--mono); font-size: 12px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topn .val { font-family: var(--mono); font-size: 11.5px; color: var(--ink-2); flex: none; }
.topn .track { height: 2px; margin-top: .4rem; background: var(--line); border-radius: 2px; }
.topn .track span { display: block; height: 100%; width: var(--pct, 0); background: var(--sev, var(--accent)); border-radius: 2px; }

/* ----------------------------------------------------------- severities -- */

/* Severity carries three encodings at once: the word, a four-segment level
   meter, and colour. The first two survive a colour-blind reader and a
   greyscale print, which is why the meter is here and not merely decorative. */
.sev {
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--mono); font-size: 11.5px; color: var(--sev, var(--ink-2));
  white-space: nowrap;
}
/* Four 3px segments on a 2px pitch. Fill widths are in pixels, not per cent,
   so a filled segment is always wholly filled. */
.sev .level {
  --fill: 0; flex: none; width: 18px; height: 9px;
  background:
    linear-gradient(currentColor, currentColor) left / var(--fill) 100% no-repeat,
    linear-gradient(var(--line-2), var(--line-2));
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 3px, transparent 3px 5px);
          mask: repeating-linear-gradient(90deg, #000 0 3px, transparent 3px 5px);
}
.sev-critical { --sev: var(--critical); }
.sev-high     { --sev: var(--high); }
.sev-medium   { --sev: var(--medium); }
.sev-low      { --sev: var(--low); }
.sev-info     { --sev: var(--info); }
.sev-critical .level { --fill: 18px; }
.sev-high     .level { --fill: 14px; }
.sev-medium   .level { --fill: 9px; }
.sev-low      .level { --fill: 4px; }
.sev-info     .level { --fill: 0; }

.badge {
  display: inline-block; padding: .12rem .5rem;
  border: 1px solid var(--line-2); border-radius: 999px;
  background: var(--overlay-soft); color: var(--ink-2);
  font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; white-space: nowrap;
}
.badge.on { border-color: color-mix(in srgb, var(--accent) 45%, transparent); color: var(--accent-2); background: var(--accent-wash); }
.badge.bad { border-color: color-mix(in srgb, var(--bad) 45%, transparent); color: var(--bad); background: color-mix(in srgb, var(--bad) 12%, transparent); }
.badge.good { border-color: color-mix(in srgb, var(--good) 45%, transparent); color: var(--good); background: color-mix(in srgb, var(--good) 12%, transparent); }
.badge.warn { border-color: color-mix(in srgb, var(--warn) 45%, transparent); color: var(--warn); background: color-mix(in srgb, var(--warn) 12%, transparent); }

.chip {
  display: inline-block; padding: .12rem .45rem; margin: 0 .25rem .25rem 0;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--well); color: var(--ink-2); font-size: 11px;
}

/* A legend row for the donut. Colour is never the only channel: each swatch is
   followed by its own name and count. */
.legend { list-style: none; margin: .9rem 0 0; padding: 0; display: grid; gap: .45rem; }
.legend li { display: flex; align-items: center; gap: .6rem; font-size: 12.5px; }
.legend .swatch { width: 9px; height: 9px; border-radius: 2px; background: var(--sev, var(--ink-3)); flex: none; }
.legend .name { color: var(--ink-2); flex: 1; }
.legend .count { font-family: var(--mono); color: var(--ink); }

/* --------------------------------------------------------------- tables -- */

table { width: 100%; border-collapse: collapse; margin: .6rem 0; font-size: 13px; }
th, td { text-align: left; padding: .55rem .7rem; vertical-align: top; }
/* Not sticky: a sticky header inside a `.scroll` box sticks to that box rather
   than the viewport and lands on top of the first row, and no table here is
   long enough to need one — the queue is capped at four. */
thead th {
  color: var(--ink-3); font-weight: 600; font-size: 10.5px;
  text-transform: uppercase; letter-spacing: .12em;
  border-bottom: 1px solid var(--line-2); white-space: nowrap;
}
tbody td { border-bottom: 1px solid var(--line); }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: var(--overlay-soft); }

.scroll { overflow-x: auto; border-radius: var(--r); }
.scroll > table { margin: 0; }

td.ref { font-size: 12.5px; }
td.num, th.num { text-align: right; }
tr.uncited td { color: var(--warn); }
tr.diagnostic td { color: var(--ink-3); }
tr.breached td { background: color-mix(in srgb, var(--bad) 7%, transparent); }

/* The queue, as a stack of cards. Each row is its own record with its own
   severity edge, because prioritisation practice is a comparison between whole
   records rather than a scan down one column. */
table.slips { border-collapse: separate; border-spacing: 0 8px; }
table.slips thead th { border-bottom: 0; padding-bottom: .1rem; }
table.slips tbody td {
  background: linear-gradient(180deg, var(--card-top), var(--card-bottom));
  border-top: 1px solid var(--card-line);
  border-bottom: 1px solid var(--card-line);
  padding: .8rem .75rem; vertical-align: middle;
  transition: border-color .15s ease;
}
table.slips tbody td:first-child {
  border-left: var(--rail) solid var(--sev, var(--line-3));
  border-radius: var(--r) 0 0 var(--r); padding-left: .95rem;
}
table.slips tbody td:last-child { border-right: 1px solid var(--card-line); border-radius: 0 var(--r) var(--r) 0; }
table.slips tbody tr { box-shadow: var(--shadow); }
table.slips tbody tr:hover td { border-color: var(--card-line-lit); background: linear-gradient(180deg, var(--row-hover-top), var(--row-hover-bottom)); }
table.slips tbody tr:hover td:first-child { border-left-color: var(--sev, var(--line-3)); }
table.slips td a { font-weight: 600; display: block; }
table.slips td .badge { margin-top: .35rem; }
table.slips tr.breached td { background: linear-gradient(180deg, var(--breach-top), var(--breach-bottom)); }

.entity-list { display: flex; flex-wrap: wrap; gap: 0 .15rem; }

/* ------------------------------------------------------------ the clock -- */

/* **The one idea on the queue.** Severity is the left edge; time is the length.
   When a MEDIUM's bar is visibly shorter than a CRITICAL's, the tension the
   view exists to teach is on screen as a shape. The horizon is shared and
   stated on the ruler, because a bar chart whose rows use different scales is
   a lie. */
.lane, th.lane-head { width: 30%; min-width: 13rem; padding-left: 1.5rem; padding-right: 1rem; }
th.lane-head { vertical-align: bottom; padding-bottom: .1rem; }

.ruler {
  position: relative; height: 1.05rem;
  font-size: 10px; letter-spacing: .04em; color: var(--ink-3);
  font-weight: 400; text-transform: none;
}
.ruler i { position: absolute; top: 0; left: var(--at); font-style: normal; white-space: nowrap; transform: translateX(-50%); }
.ruler i:first-child { transform: none; }
.ruler i:last-child { transform: translateX(-100%); }

.lane-track {
  --tick: 25%;
  position: relative; height: 20px; border-radius: 3px;
  background-image: repeating-linear-gradient(90deg, var(--line-2) 0 1px, transparent 1px var(--tick));
}
/* Now. Every bar starts here, so it is drawn once and heavier than the ticks. */
.lane-track::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; background: var(--line-3); }
.lane-bar {
  position: absolute; left: 0; top: 5px; height: 10px;
  width: var(--pct, 0); min-width: 3px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--sev, var(--accent)) 55%, transparent), var(--sev, var(--accent)));
  border-radius: 0 5px 5px 0;
}
/* A breach has no remaining time to draw, so it is drawn as an overrun across
   the whole horizon — hatched, because a solid bar would read as "plenty of
   time left" to anyone scanning length alone. */
tr.breached .lane-bar {
  width: 100%; border-radius: 3px; box-shadow: none;
  background: repeating-linear-gradient(135deg, color-mix(in srgb, var(--bad) 60%, transparent) 0 3px, transparent 3px 7px);
}
.lane-label { display: block; margin-top: .3rem; font-size: 11px; color: var(--ink-2); }
.lane-label.warn { color: var(--warn); }
.lane-label.bad { color: var(--bad); }

/* ------------------------------------------------------------- the case -- */

.case-head { border-left: var(--rail) solid var(--sev, var(--line-3)); }
.case-head h1 { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; }
.case-head .sla { margin-top: .9rem; max-width: 26rem; }

/* Entities and the window are re-read constantly while the report is written,
   so on a wide screen they stay beside the work instead of scrolling away. */
.case-layout { display: block; }
@media (min-width: 1080px) {
  .case-layout { display: grid; grid-template-columns: 15.5rem 1fr; gap: 2rem; align-items: start; }
  .case-facts { position: sticky; top: 5rem; }
}
.case-facts dl.entities { grid-template-columns: 1fr; gap: .1rem; }
.case-facts dt { margin-top: .7rem; }
.case-facts dt:first-child { margin-top: 0; }
.case-main { min-width: 0; }

/* ----------------------------------------------------- definition lists -- */

dl.entities, dl.ops, .truth dl, .trace dl {
  display: grid; grid-template-columns: minmax(7rem, 11rem) 1fr; gap: .4rem .9rem; margin: .6rem 0;
}
dt { color: var(--ink-3); font-size: 10.5px; text-transform: uppercase; letter-spacing: .12em; padding-top: .2rem; }
dd { margin: 0; min-width: 0; }

/* **A grid cell does not shrink below its longest unbreakable word**, and an
   entity value is routinely one long unbreakable word: an alert on DET-0003
   carries `parent_image`, whose value is a path like
   `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` — 55 characters
   with no space in them. A browser will not break on a backslash, so the cell
   demanded its full width, pushed the 15.5rem facts column out from the inside,
   and the value ran off the panel. `anywhere` is the one value that also lets
   the *cell* shrink; `break-word` alone wraps the text and leaves the column
   wide. `min-width: 0` on the dd is the other half — without it the grid track
   still refuses to shrink. */
dl.entities dd, dl.ops dd, .trace dd {
  font-family: var(--mono); font-size: 12.5px; overflow-wrap: anywhere;
}
.prose-dl dd { font-family: var(--ui); font-size: 13px; max-width: var(--measure); }

/* ---------------------------------------------------------------- forms -- */

form { margin: .6rem 0; }
form.inline { display: flex; flex-wrap: wrap; gap: .6rem; align-items: flex-end; }

label { display: block; margin: 1rem 0 0; color: var(--ink-2); font-size: 10.5px; font-weight: 650; text-transform: uppercase; letter-spacing: .12em; }
label.check { display: flex; gap: .6rem; align-items: center; text-transform: none; letter-spacing: 0; font-size: 13px; font-weight: 400; color: var(--ink); }
label .hint { text-transform: none; letter-spacing: 0; font-weight: 400; margin-top: .2rem; }

input, select, textarea {
  width: 100%; margin-top: .35rem; padding: .55rem .7rem;
  background: var(--well); color: var(--ink);
  border: 1px solid var(--line-2); border-radius: var(--r-sm);
  font: inherit; font-size: 13px;
  transition: border-color .15s ease, box-shadow .15s ease, background-color .15s ease;
}
input, textarea { font-family: var(--mono); }
select { font-family: var(--ui); }
input::placeholder, textarea::placeholder { color: var(--ink-3); }
input:hover, select:hover, textarea:hover { border-color: var(--line-3); }
input:focus, select:focus, textarea:focus {
  border-color: var(--accent); background: color-mix(in srgb, var(--accent) 5%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 13%, transparent); outline: none;
}
input[type="checkbox"] { width: auto; margin-top: 0; accent-color: var(--accent); }
textarea { resize: vertical; line-height: 1.55; }

fieldset { border: 1px solid var(--line); border-radius: var(--r-sm); padding: .5rem .9rem 1rem; margin: 1.2rem 0 0; }
legend { padding: 0 .4rem; color: var(--ink-3); font-size: 10.5px; text-transform: uppercase; letter-spacing: .12em; }

.field-grid { display: grid; gap: 0 1.1rem; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }

button, .button {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .5rem .95rem;
  border: 1px solid var(--card-line-lit); border-radius: var(--r-sm);
  background: linear-gradient(180deg, var(--btn-top), var(--btn-bottom));
  color: var(--ink); font: inherit; font-size: 13px; font-weight: 550;
  cursor: pointer; text-decoration: none;
  box-shadow: var(--shadow);
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
button:hover, .button:hover { border-color: var(--line-3); background: linear-gradient(180deg, var(--btn-top-hover), var(--btn-bottom-hover)); color: var(--ink); text-decoration: none; }
button.primary {
  background: linear-gradient(180deg, var(--accent-2), var(--accent));
  color: var(--accent-ink); border-color: var(--accent); font-weight: 650;
  box-shadow: var(--shadow);
}
button.primary:hover { background: linear-gradient(180deg, #9cc3ff, var(--accent-2)); border-color: var(--accent-2); color: var(--accent-ink); }
button.danger { color: var(--bad); border-color: color-mix(in srgb, var(--bad) 35%, transparent); }
button.danger:hover { background: color-mix(in srgb, var(--bad) 12%, transparent); border-color: var(--bad); color: var(--bad); }
button.link { background: none; border: none; box-shadow: none; padding: .25rem .35rem; color: var(--ink-3); font-weight: 400; font-size: 12.5px; }
button.link:hover { background: none; color: var(--ink); }

.actions { display: flex; flex-wrap: wrap; gap: .65rem; align-items: center; margin-top: 1.1rem; }
.actions form { margin: 0; }

.ioc-row { display: flex; gap: .5rem; margin: .45rem 0 0; }
.ioc-row select { flex: 0 0 8.5rem; margin-top: 0; }
.ioc-row input { margin-top: 0; }

.timeline-add { display: grid; grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr)); gap: .55rem; align-items: end; }
.timeline-add input, .timeline-add select { margin-top: 0; }

/* A refused row's reason, next to the boxes it was refused from. The flash bar
   is at the top of the page and the builder is at the bottom, and the redirect
   lands on `#timeline` — so a message rendered only up there is a message the
   learner never sees. */
.entry-error {
  margin: 1rem 0 .6rem; padding: .6rem .8rem; font-size: 13px;
  background: color-mix(in srgb, var(--bad) 9%, transparent);
  border-left: var(--rail) solid var(--bad);
}

.submit-row { display: flex; gap: .8rem; align-items: center; flex-wrap: wrap; margin-top: 1.4rem; padding-top: 1.1rem; border-top: 1px solid var(--line); }
.autosave { color: var(--ink-3); font-size: 11.5px; font-family: var(--mono); margin-left: auto; }

/* ---------------------------------------------------------------- flash -- */

.flash { list-style: none; margin: 0; padding: 0; }
.flash li {
  padding: .75rem 1.5rem; background: color-mix(in srgb, var(--accent) 10%, transparent);
  border-bottom: 1px solid var(--card-line); border-left: var(--rail) solid var(--accent);
  white-space: pre-wrap; font-size: 13px;
}

/* A flash carrying more than one sentence. `pre-wrap` above is right for the
   one-line messages the portal usually flashes — it keeps a deliberate break
   where an author put one — but it also preserves the template's own
   indentation, so a paragraph written across several source lines rendered
   ragged and half-width. This is the multi-paragraph case: the withdrawn
   answer-key notice, which is the longest thing the portal ever flashes and the
   one a learner most needs to be able to read. */
.flash li.prose { white-space: normal; }
.flash li.prose p { margin: .35rem 0; max-width: var(--measure); }
.flash li.prose p:first-child { margin-top: 0; }
.flash li.prose p:last-child { margin-bottom: 0; }

/* ------------------------------------------------------------ playbooks -- */

/* Deliberately quieter than the alert table above it: this is a prompt, not a
   finding, and it must not read as the case's content. No checkboxes and no
   numbering — a numbered list is a procedure, which is what FR-P-04 and the
   whole of ADR-030 were about. */
.playbook { border-left: 2px solid var(--line-2); padding: .1rem 0 .1rem 1.05rem; margin: 1rem 0 1.4rem; }
.playbook h3 { margin-top: .2rem; }
.playbook > p { margin: .3rem 0 .65rem; color: var(--ink-2); max-width: var(--measure); }
ul.questions { list-style: none; margin: .45rem 0; padding: 0; max-width: var(--measure); }
ul.questions li { margin: 0 0 .65rem; padding-left: 1.1rem; text-indent: -1.1rem; }
ul.questions li::before { content: "— "; color: var(--ink-3); }
ul.known-fps { margin: .25rem 0 0; padding-left: 1.2rem; color: var(--ink-3); font-size: 12.5px; }

/* An outbound link in the header nav. Company Records is a Splunk dashboard,
   not a portal view, and the arrow says so before the click rather than after —
   a nav item that silently leaves the site is a small betrayal of the chrome. */
.bar nav a.external { display: inline-flex; align-items: center; gap: .3rem; }
.bar nav a.external svg { opacity: .55; }
.bar nav a.external:hover svg { opacity: 1; }

/* The one emphasised link on the Briefing: the door to the records. */
a.cta {
  font-weight: 600; border-bottom: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
}

/* -------------------------------------------------------- pre and notes -- */

pre {
  white-space: pre-wrap; word-break: break-word;
  background: var(--well); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: .8rem .95rem; margin: .45rem 0; font-size: 12.5px; line-height: 1.6; color: var(--ink-2);
}
code { font-size: .92em; color: var(--ink); }

article.note, article.bulletin {
  background: linear-gradient(180deg, var(--card-top), var(--card-bottom));
  border: 1px solid var(--card-line); border-left: var(--rail) solid var(--line-3);
  border-radius: 0 var(--r) var(--r) 0; box-shadow: var(--shadow);
  padding: 1rem 1.2rem; margin-bottom: .9rem;
}
article.note h2, article.bulletin h2 {
  font-size: 14.5px; text-transform: none; letter-spacing: 0; color: var(--ink);
  margin: 0 0 .25rem; font-weight: 620;
}
article.note h2::after, article.bulletin h2::after { display: none; }
article.bulletin { border-left-color: var(--accent); }
article.note p, article.bulletin p { max-width: var(--measure); }
.pin { color: var(--warn); font-family: var(--mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: .1em; }

details.handover { margin-top: 1rem; }
details.handover summary { cursor: pointer; color: var(--ink-2); font-size: 12.5px; }
details.handover summary:hover { color: var(--ink); }

/* --------------------------------------------------------------- charts -- */

.chart { width: 100%; height: auto; margin: .5rem 0; display: block; }
.chart .axis { stroke: var(--line-2); stroke-width: 1; }
.chart .grid-line { stroke: var(--line); stroke-width: 1; }
.chart .trend { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.chart .trend-fill { fill: url(#soe-trend-fill); stroke: none; }
.chart .latest { fill: var(--accent); stroke: var(--card-bottom); stroke-width: 2.5; }
.chart .tick { fill: var(--ink-3); font-family: var(--mono); font-size: 10px; }
.chart .latest-label { fill: var(--ink); font-weight: 600; }

.bars .bar-label { fill: var(--ink-2); font-family: var(--ui); font-size: 12px; }
.bars .bar-value { fill: var(--ink-3); font-family: var(--mono); font-size: 11px; }
.bars .bar-track { fill: var(--well); stroke: var(--line); }
.bars .bar-fill { fill: url(#soe-bar-fill); }

/* Wider than the other charts because the viewBox is 340×260 — the extra width
   is the margin the spoke labels are anchored into, not a bigger polygon. */
.radar { width: 100%; max-width: 340px; height: auto; margin: 0 auto; display: block; }
.radar .grid { fill: none; stroke: var(--line-2); stroke-width: 1; }
.radar .web { fill: none; stroke: var(--line); stroke-width: 1; }
.radar .shape { fill: var(--accent-wash); stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; }
.radar .vertex { fill: var(--accent); stroke: var(--card-bottom); stroke-width: 2; }
.radar .spoke { fill: var(--ink-2); font-family: var(--ui); font-size: 10.5px; }

/* The donut. Ordinal severity, so the ring runs critical → info clockwise and
   every arc is named in the legend beside it. */
.donut { width: 100%; max-width: 168px; height: auto; display: block; margin: 0 auto; }
.donut .arc { fill: none; stroke-width: 13; stroke-linecap: butt; }
.donut .arc-critical { stroke: var(--critical); }
.donut .arc-high { stroke: var(--high); }
.donut .arc-medium { stroke: var(--medium); }
.donut .arc-low { stroke: var(--low); }
.donut .arc-info { stroke: var(--info); }
.donut .arc-empty { stroke: var(--line); }
.donut .hole-value { fill: var(--ink); font-family: var(--mono); font-size: 26px; font-weight: 600; }
.donut .hole-label { fill: var(--ink-3); font-family: var(--ui); font-size: 9px; letter-spacing: .12em; text-transform: uppercase; }

.chart-row { display: flex; flex-wrap: wrap; gap: 1.75rem; align-items: center; }
.chart-row > * { flex: 1 1 14rem; min-width: 0; }

/* The ring and its legend are one object and must not wrap apart inside a
   third-of-the-row panel — a donut stacked above its own key is twice the
   height and none of the extra height is information. */
.mix { display: flex; align-items: center; gap: 1.1rem; }
.mix .donut { flex: 0 0 118px; max-width: 118px; margin: 0; }
.mix .legend { flex: 1 1 auto; min-width: 0; }

/* ------------------------------------------------------------- feedback -- */

.score-hero { display: flex; align-items: baseline; gap: .7rem; flex-wrap: wrap; }
.score-hero .score { font-size: 46px; font-weight: 600; line-height: 1; letter-spacing: -.03em; }
.score-hero .of { color: var(--ink-3); font-family: var(--mono); font-size: 16px; }

/* The review (§30.1). The LLM's entire learner-visible surface, and it is set
   apart deliberately: everything above it on the feedback page is reproducible
   and everything inside it is not. */
.review { border-top: 1px solid var(--line-2); margin-top: 2rem; padding-top: .5rem; }
.review .coaching { max-width: var(--measure); line-height: 1.7; font-size: 15px; }
.review .withheld {
  max-width: var(--measure); color: var(--warn);
  border-left: var(--rail) solid var(--warn); background: color-mix(in srgb, var(--warn) 9%, transparent);
  padding: .7rem 1rem; border-radius: 0 var(--r-sm) var(--r-sm) 0;
}

/* Gaps are a definition list rather than a table because the method line is
   prose and wants a measure, not a cell. */
dl.gaps { display: block; }
dl.gaps dt { color: var(--ink); font-size: 13px; font-weight: 620; text-transform: none; letter-spacing: 0; margin-top: 1.2rem; }
dl.gaps dd { margin: .3rem 0 0; padding-left: 1rem; border-left: 2px solid var(--line-2); }
dl.gaps dd p { margin: .3rem 0; max-width: var(--measure); }

/* A pivot the trace credited and one it did not are the same sentence, so the
   difference has to be carried by something other than the words. The rail on
   the missed ones is the same device the gaps use — a mark in the margin — and
   deliberately not a colour that reads as failure: these are the moves worth
   learning, not marks lost. */
ul.pivots { list-style: none; padding-left: 0; }
ul.pivots li { padding-left: .85rem; border-left: 2px solid var(--line-2); margin: .35rem 0; max-width: var(--measure); }
ul.pivots li.missed { border-left-color: var(--warn); color: var(--ink); }
/* Unmeasured is neither a pass nor a miss, and must not read as either: a case
   closed before pivot signatures existed could not be measured, and colouring it
   like a miss would be the page accusing the learner of not doing work nobody
   looked for. Muted and unmarked. */
ul.pivots li.unmeasured { border-left-style: dashed; color: var(--ink-2); }

/* ------------------------------------------------------ worked searches -- */
/* The one place in the portal that prints SPL, and it exists only after
   closure. Monospace at a readable size and never wrapped mid-token: a search
   the learner cannot select cleanly is one they retype, and retyping is how a
   field name becomes a typo they then blame on themselves. */

.worked { border-left: var(--rail) solid var(--accent); }
.worked > p.quiet { max-width: var(--measure); }

article.recipe { margin: 1.3rem 0 0; }
article.recipe h3 { font-size: 14px; font-weight: 620; margin: 0 0 .3rem; }
article.recipe p { max-width: var(--measure); margin: .4rem 0; }
article.recipe p.because { color: var(--ink-2); font-size: 13px; }
article.recipe.missed p.because strong { color: var(--warn); }

pre.spl {
  font-family: var(--mono); font-size: 12.5px; color: var(--ink);
  white-space: pre; overflow-x: auto; word-break: normal;
  border-left: var(--rail) solid var(--accent);
}

.recipe-group { margin-top: 1.6rem; }
.recipe-group h3.rule {
  font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3); font-weight: 600; margin: 0;
}

.truth { border-left: var(--rail) solid var(--good); }

/* ---------------------------------------------------------------- login -- */

form.login { max-width: 22rem; margin: 6rem auto; }
form.login h1 { margin-bottom: 1.1rem; font-size: 19px; }
form.login button { width: 100%; justify-content: center; margin-top: 1.5rem; }

/* --------------------------------------------------------------- footer -- */

footer { color: var(--ink-3); font-size: 11.5px; text-align: center; padding: 1.75rem; border-top: 1px solid var(--line); margin-top: 2.5rem; }

/* ----------------------------------------------------------- responsive -- */

@media (max-width: 1024px) {
  .col-3, .col-4, .col-5 { grid-column: span 6; }
  .col-7, .col-8, .col-9 { grid-column: span 12; }
}
@media (max-width: 720px) {
  .bar { height: auto; flex-wrap: wrap; padding: .7rem 1rem; gap: .6rem; }
  .bar nav { order: 3; width: 100%; }
  .bar nav a.on::after { bottom: -2px; }
  main { padding: 1.5rem 1rem 3.5rem; }
  .grid > * { grid-column: span 12 !important; }
  .record h1 { font-size: 26px; }
  .kpi { gap: 1rem; }
  .kpi-value { font-size: 32px; }
  dl.entities, dl.ops, .truth dl, .trace dl { grid-template-columns: 1fr; gap: .1rem; }
  dl.entities dt, dl.ops dt, .trace dt { margin-top: .6rem; }
}

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

/* ---------------------------------------------------------------- print -- */

/* Charts render in a printed report (§28.3), so the sheet has to survive being
   printed rather than merely tolerate it. */
@media print {
  :root {
    --bg: #fff; --card-top: #fff; --card-bottom: #fff; --well: #fff;
    --ink: #000; --ink-2: #333; --ink-3: #555;
    --line: #ccc; --line-2: #aaa; --line-3: #888;
    --card-line: #bbb; --edge-light: transparent;
    --accent: #0b4fa8; --accent-wash: #dbe8f8; --shadow: none;
  }
  body { background: #fff; }
  .bar, footer, .actions, form, .skip { display: none; }
  main { max-width: none; padding: 0; }
  .card, table.slips tbody td { break-inside: avoid; box-shadow: none; }
}

/* --------------------------------------------------------- diagnostics --- */
.diagnostics dl { display: grid; grid-template-columns: auto 1fr; gap: .2rem .9rem; font-size: 13px; }
.diagnostics dt { color: var(--ink-2); }
.diagnostics dd { margin: 0; font-variant-numeric: tabular-nums; }
.diagnostics p.warn { color: var(--warn); max-width: var(--measure); font-size: 13px; }

/* ----------------------------------------------------- reference path ---- */
/* A strong path and not the only one, which the wording carries and the styling
   must not contradict: no numbering, no ticks down the side, nothing that reads
   as a checklist the learner failed. */

.reference { border-left: var(--rail) solid var(--line-2); }
.reference h3 { font-size: 13.5px; font-weight: 620; margin: 1.1rem 0 .2rem; }
.reference > p.quiet, .reference p.quiet { max-width: var(--measure); }
ul.moves { list-style: none; padding-left: 0; }
ul.moves li { padding-left: .85rem; border-left: 2px solid var(--line-2); margin: .35rem 0; max-width: var(--measure); }

.pill {
  display: inline-block; font-family: var(--mono); font-size: 10.5px;
  text-transform: uppercase; letter-spacing: .08em;
  padding: .05rem .35rem; border-radius: 3px; margin-right: .4rem;
  border: 1px solid var(--line-2); color: var(--ink-2);
}
.pill-hit { border-color: color-mix(in srgb, var(--good) 45%, transparent); color: var(--good); }
.pill-miss { border-color: color-mix(in srgb, var(--warn) 45%, transparent); color: var(--warn); }
/* Neither a pass nor a miss, and it must not read as either — the same rule
   `ul.pivots li.unmeasured` follows, for the same reason. */
.pill-unmeasured { border-style: dashed; color: var(--ink-3); }

/* -------------------------------------------------------------- drill ---- */
/* One move, on a case whose answer the learner already has. Styled as an
   instruction rather than as an alert: no severity colour, no clock, nothing
   that borrows the visual language of the queue — a drill that looked like a
   case would reintroduce the pressure it exists to remove. */

.drill { border-left: var(--rail) solid var(--line-2); }
.drill-ask {
  font-size: 15px; font-weight: 560; max-width: var(--measure);
  margin: .7rem 0; color: var(--ink);
}
.drill-actions { display: flex; gap: .6rem; align-items: center; margin-top: .9rem; }
.drill-actions form { margin: 0; }


/* ------------------------------------------------------ feedback tabs ---- */
/* Twelve things a learner wants after a case, stacked, meant reaching the
   comparison that matters — their investigation beside a strong one — after
   scrolling past the answer key, the coaching and four worked searches.
   Grouped into four panels instead.

   Radio inputs and sibling selectors, no script. §28.3 asks for progressive
   enhancement; this satisfies it by having nothing to enhance — the tabs are
   native form controls, so they arrow-key between themselves, they are
   focusable, and they work identically with JavaScript off. */

.tabs > input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.tablist {
  display: flex;
  flex-wrap: wrap;
  gap: .1rem;
  margin: 1.2rem 0 0;
  border-bottom: 1px solid var(--line);
}

.tablist label {
  padding: .5rem .9rem;
  font-size: 13px;
  font-weight: 560;
  color: var(--ink-2);
  cursor: pointer;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 4px 4px 0 0;
  margin-bottom: -1px;
  white-space: nowrap;
}

.tablist label:hover { color: var(--ink); background: var(--bg-2); }

/* The focus ring has to survive the input being visually hidden, or the tabs
   are keyboard-operable and invisibly so. */
.tabs > input[type="radio"]:focus-visible + input + input + input ~ .tablist label,
.tabs > input[type="radio"]:focus-visible ~ .tablist label { outline: none; }
#tab-verdict:focus-visible  ~ .tablist label[for="tab-verdict"],
#tab-truth:focus-visible    ~ .tablist label[for="tab-truth"],
#tab-work:focus-visible     ~ .tablist label[for="tab-work"],
#tab-practise:focus-visible ~ .tablist label[for="tab-practise"] {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

#tab-verdict:checked  ~ .tablist label[for="tab-verdict"],
#tab-truth:checked    ~ .tablist label[for="tab-truth"],
#tab-work:checked     ~ .tablist label[for="tab-work"],
#tab-practise:checked ~ .tablist label[for="tab-practise"] {
  color: var(--ink);
  border-color: var(--line);
  border-bottom: 1px solid var(--bg);
  background: var(--bg);
}

.panels > .panel { display: none; }
#tab-verdict:checked  ~ .panels > #panel-verdict,
#tab-truth:checked    ~ .panels > #panel-truth,
#tab-work:checked     ~ .panels > #panel-work,
#tab-practise:checked ~ .panels > #panel-practise { display: block; }

/* The panel's own first heading is redundant beside the tab that opened it. */
.panels > .panel > section:first-child > h2:first-child { margin-top: .9rem; }

/* --------------------------------------------------- side-by-side -------- */
/* The learner's path and a strong one, read as two columns. Below the
   breakpoint they stack in order — a phone cannot show a comparison as a
   comparison, and pretending otherwise gives two unreadable columns instead of
   two readable sections. */

.side-by-side { display: grid; grid-template-columns: 1fr; gap: 1.2rem; }
.side-by-side > .column { min-width: 0; }

@media (min-width: 1100px) {
  .side-by-side { grid-template-columns: 1fr 1fr; }
}

/* A long replay must scroll inside its own column rather than widening the
   grid, which is what a `table` inside a grid track does by default. */
.side-by-side .column table { display: block; overflow-x: auto; max-width: 100%; }

/* ---------------------------------------------------- macro legend ------- */
/* `soe_windows` and `wineventlog` are the same index under two names, listed in
   two different tables on the briefing, and only the macro appears in a worked
   search. One line under the SPL removes the question. */

p.macro-legend {
  font-size: 11.5px;
  color: var(--ink-3);
  margin: .25rem 0 .6rem;
  max-width: var(--measure);
}
p.macro-legend code {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-2);
}

.verdict-head .pill { margin-left: .6rem; vertical-align: middle; }
p.drill-cta { margin-top: 1.4rem; font-size: 13.5px; }

/* Printing a case review should give the whole review, not the open tab. */
@media print {
  .tablist { display: none; }
  .panels > .panel { display: block !important; page-break-inside: auto; }
  .side-by-side { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------- capabilities ---- */
/* What the learner can do, beside the four domains that say how they are
   doing. A bar per capability rather than six columns of counts: the question
   is "where am I strong and where am I not", which is a shape question, and six
   numbers per row made the reader do the arithmetic themselves.
   
   Deliberately not a chart. Thirteen rows with a label, a proportion and a
   caveat is a table of facts; drawing it as a radar or a treemap would make an
   unmeasured cell look like a low one, which is the exact conflation the
   capability model exists to prevent. */

.cap-list { list-style: none; margin: 0; padding: 0; }

.cap-row {
  display: grid;
  grid-template-columns: minmax(9rem, 13rem) 1fr 3.2rem minmax(5.5rem, auto);
  align-items: center;
  gap: .8rem;
  padding: .3rem 0;
  font-size: 12.5px;
  border-bottom: 1px solid var(--line);
}
.cap-row:last-child { border-bottom: none; }

.cap-label { color: var(--ink); }

/* The track is the "not performed" ground; the segments sit on top of it, so a
   capability with nothing demonstrated reads as an empty bar rather than as a
   missing one. */
.cap-bar {
  display: flex;
  height: 6px;
  border-radius: 3px;
  overflow: hidden;
  background: var(--well);
  box-shadow: inset 0 0 0 1px var(--line);
}
.cap-seg { display: block; height: 100%; }
.cap-done { background: var(--good); }
/* Amber, not red: performed and came up short is not a failure to perform. */
.cap-part { background: var(--warn); }

.cap-count { text-align: right; font-variant-numeric: tabular-nums; color: var(--ink); }
.cap-of { color: var(--ink-3); }

/* Never coloured. An outage and an untested capability are statements about the
   platform's reach, and the moment either is styled like a miss the grid starts
   accusing the learner of the platform's gaps. */
.cap-note { color: var(--ink-3); font-size: 11.5px; }

.cap-row.is-untested .cap-label,
.cap-row.is-untested .cap-count { color: var(--ink-3); }
.cap-row.is-untested .cap-bar { opacity: .45; }

@media (max-width: 900px) {
  .cap-row { grid-template-columns: 1fr 3rem; row-gap: .15rem; }
  .cap-bar { grid-column: 1 / -1; }
  .cap-note { grid-column: 1 / -1; }
}

/* ---------------------------------------------------------- judgement ---- */
/* The two failures a learner cannot feel, in one card. Escalating everything
   feels responsible; being wrong and certain does not feel like being wrong. */

.judgement-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: .2rem 0 .5rem;
}
.judgement-head + .judgement-head { margin-top: 1.1rem; }
.judgement-label { font-size: 11.5px; color: var(--ink-2); }
.judgement-value { font-size: 19px; font-weight: 620; font-variant-numeric: tabular-nums; }
.judgement .matrix { font-size: 12px; width: 100%; }
.judgement p.quiet { margin-top: .55rem; }

/* A right-aligned note in a card title: a count, or a link, without competing
   with the title itself. */
.card-note {
  font-size: 10.5px; font-weight: 500; letter-spacing: .06em;
  text-transform: none; color: var(--ink-3);
}
.card-note a { color: var(--ink-3); }
.card-note a:hover { color: var(--accent); }

/* ------------------------------------------------------------- replay ---- */
/* The learner's own investigation, as a sequence of moments rather than a log.
   Seventy-two searches printed in full is a log, and a learner scrolls past a
   log — so the track carries the milestones and the rest sits behind a native
   `details`.
   
   Read as a timeline: a hairline rail down the left, offsets in mono so the
   gaps between them are visible at a glance, and the search text in mono
   because it is something the learner typed. Everything else is body face, so
   a lifecycle stamp never looks like a query. */

.track { list-style: none; margin: .2rem 0 0; padding: 0 0 0 .1rem; position: relative; }

.track-step {
  display: grid;
  grid-template-columns: 4.2rem 1fr;
  gap: .7rem;
  align-items: baseline;
  padding: .32rem 0 .32rem .9rem;
  border-left: 2px solid var(--line);
  position: relative;
}
/* The node. Small, and only filled where the step did something. */
.track-step::before {
  content: ""; position: absolute; left: -4px; top: .72rem;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--bg); border: 1.5px solid var(--line-3);
}
.track-step.is-useful::before { background: var(--good); border-color: var(--good); }

.track-at {
  font-family: var(--mono); font-size: 11.5px; color: var(--ink-3);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.track-body { min-width: 0; }
.track-what { font-size: 12.5px; color: var(--ink); }

.track-spl {
  display: block; font-family: var(--mono); font-size: 12px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* What the step earned, on its own line and never as a colour alone. */
.track-note { display: block; font-size: 11.5px; color: var(--ink-2); margin-top: .1rem; }
.track-step.is-useful .track-note { color: var(--good); }

/* The scaffolding steps are muted so the work between them carries the eye. */
.track-opened .track-what,
.track-acknowledged .track-what,
.track-submitted .track-what { color: var(--ink-3); }

/* ------------------------------------------------ the whole search list --- */

details.track-all { margin-top: .9rem; border-top: 1px solid var(--line); padding-top: .6rem; }
details.track-all > summary {
  cursor: pointer; font-size: 12px; color: var(--ink-2);
  list-style: none; display: inline-flex; align-items: center; gap: .35rem;
}
details.track-all > summary::-webkit-details-marker { display: none; }
details.track-all > summary::before { content: "▸"; color: var(--ink-3); font-size: 10px; }
details.track-all[open] > summary::before { content: "▾"; }
details.track-all > summary:hover { color: var(--ink); }
details.track-all > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

ol.track-list { list-style: none; margin: .6rem 0 0; padding: 0; max-height: 22rem; overflow-y: auto; }
ol.track-list li {
  display: grid; grid-template-columns: 4.2rem 1fr; gap: .7rem;
  padding: .16rem 0; font-size: 11.5px; align-items: baseline;
}
ol.track-list code {
  font-family: var(--mono); color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
ol.track-list li.is-useful code { color: var(--ink); }

@media (max-width: 700px) {
  .track-step, ol.track-list li { grid-template-columns: 1fr; gap: 0; }
  .track-at { display: block; }
}

/* A printed case review shows the whole investigation, not the summary of it. */
@media print {
  details.track-all { display: block; }
  details.track-all > summary { display: none; }
  ol.track-list { max-height: none; overflow: visible; }
  .track-spl, ol.track-list code { white-space: pre-wrap; overflow: visible; }
}

/* --------------------------------------------------------- the roster ---- */
/* The account lifecycle admin area. Deliberately thin: every table, card,
   pill and field style below this line already existed for the operator page,
   and an admin area with its own visual language would be an admin area
   somebody maintains separately. What is new is the small number of states the
   rest of the portal has no reason to express — a disabled account, and a
   credential that exists in one response and then does not. */

table.roster td.ref a { font-family: var(--mono); font-size: 12.5px; }

/* A disabled account is muted rather than coloured. It is not an alert and not
   an error: somebody made this decision on purpose, and the row should read as
   "out of service", not as "something went wrong". */
table.roster tr.disabled td { color: var(--ink-3); }
table.roster tr.disabled td strong { color: var(--warn); font-weight: 600; }

/* ----------------------------------------------------- the credential ---- */
/* Shown once, in the body of the response that produced it. The border is the
   accent rather than a warning colour: this is a normal, expected step in
   onboarding somebody, and dressing it as a hazard would train the
   administrator to click past it. */
.card.credential { border-color: color-mix(in srgb, var(--accent) 40%, var(--card-line)); }
.card.credential .secret {
  margin: .8rem 0 .4rem;
  padding: .7rem .85rem;
  background: var(--well);
  border: 1px dashed var(--line-2); border-radius: var(--r-sm);
}
/* Selectable at a glance and unambiguous character by character: this string is
   read off one screen and typed into another, sometimes over a phone. */
.card.credential .secret code {
  font-family: var(--mono); font-size: 16px; letter-spacing: .06em;
  color: var(--ink); user-select: all;
}

/* --------------------------------------------------------- the actions --- */
/* Three destructive-ish controls in a column, each with the sentence that says
   what it does *to the person*, not to the row. An administrator disabling an
   account at the end of a contract and one revoking a session after a lost
   laptop are doing different jobs, and the labels have to keep them apart. */
.admin-actions { display: grid; gap: 1rem; max-width: var(--measure); }
.admin-actions form {
  margin: 0; padding: .85rem 0 0; border-top: 1px solid var(--line);
}
.admin-actions form:first-child { border-top: 0; padding-top: 0; }
.admin-actions .hint { margin-top: .45rem; }
.admin-actions button[disabled] { opacity: .5; cursor: not-allowed; }

table.audit td { font-size: 12.5px; }
table.audit td:nth-child(2), table.audit td:nth-child(3) { font-family: var(--mono); font-size: 11.5px; }
table.sessions td { font-family: var(--mono); font-size: 12.5px; }

/* --------------------------------------------------------------- landing -- */

/* The public front door (`public-multiuser.md`, step 7).
 *
 * It uses the portal's tokens, severity ramp, mono face and card surfaces —
 * nothing here defines a colour or a typeface of its own, so a visitor who signs
 * in arrives somewhere they recognise. What it *does* add is composition: the
 * workspace is a dense duty log read at arm's length, and a front door is read
 * once, at a distance, by somebody deciding whether to care.
 *
 * Three moves carry it:
 *
 *   1. **Full-bleed bands, centred content.** `main.landing` drops the
 *      workspace's 1240px box so a band can own the viewport edge to edge; every
 *      band re-imposes it with `.wrap`. That is what stops the page reading as a
 *      column of documentation on a wide screen.
 *   2. **Asymmetry.** The hero is 1.05fr / 1fr, the "marked on method" section
 *      is 1fr / 1.1fr and reversed. Nothing is centred except the closer, which
 *      is centred because it is one instruction.
 *   3. **The data surfaces are real components.** The investigation panel and
 *      the scorecard are built from `--card-*`, the severity ramp and the mono
 *      face — the same parts the queue is built from, at the same weights. */

main.landing { max-width: none; padding: 0; }
main.landing .wrap { max-width: 1200px; margin: 0 auto; padding: 0 1.5rem; }
main.landing section { margin: 0; }
main.landing p { max-width: none; }

/* Section rhythm. Generous, and the same everywhere so the eye can predict it. */
.band { padding: clamp(3.25rem, 6.5vw, 5.5rem) 0; border-top: 1px solid var(--line); }
.band-alt { background: var(--bg-2); }

/* Headings are set as headings, not as the workspace's mono eyebrows. §28.3's
   uppercase micro-label is right above a table of figures and wrong as the only
   voice on a page somebody is reading for the first time. */
/* The workspace sets `h2` to `display: flex` with a trailing hairline `::after`
   — the duty-log section rule, right above a table and wrong as the voice of a
   page somebody is reading for the first time. Both are undone here, and the
   flex is what mattered: it also made `text-align` do nothing, so the closer's
   heading sat left of its own centred content. */
main.landing h2 {
  display: block;
  font-family: var(--ui); font-size: clamp(24px, 3.2vw, 34px); line-height: 1.15;
  letter-spacing: -.02em; font-weight: 660; color: var(--ink);
  text-transform: none; border: 0; padding: 0; margin: 0 0 .75rem;
}
main.landing h2::after { content: none; }
main.landing h3 {
  font-size: 15px; font-weight: 650; letter-spacing: -.006em;
  color: var(--ink); margin: 0 0 .4rem;
}
.band-head { max-width: 40rem; margin-bottom: clamp(2rem, 4vw, 3.25rem); }
.band-head p { font-size: 15.5px; color: var(--ink-2); margin: 0; }

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

.hero {
  padding: clamp(2.25rem, 5vw, 4.5rem) 0 clamp(2.5rem, 5vw, 4.5rem);
  /* A single, very soft accent wash anchored behind the panel. Not a gradient
     for decoration: it lifts the visualisation off the page and dies out long
     before it reaches the type. */
  background:
    radial-gradient(60rem 34rem at 78% 18%, var(--accent-wash), transparent 62%);
}
.hero-grid {
  display: grid; grid-template-columns: 1.12fr 1fr;
  gap: clamp(2rem, 4vw, 3.75rem); align-items: center;
}

.eyebrow {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); margin: 0 0 1.1rem;
}

/* The one place in the product where type is allowed to be large, and the only
   place it is allowed to be this large. `clamp` bottoms out at 30px so the
   two-line break never becomes four lines on a phone. */
.hero h1 {
  font-size: clamp(30px, 4.6vw, 52px); line-height: 1.05; letter-spacing: -.03em;
  font-weight: 700; margin: 0 0 1.35rem; color: var(--ink);
}
.standfirst {
  font-size: clamp(15.5px, 1.5vw, 18px); line-height: 1.62; color: var(--ink-2);
  max-width: 40ch; margin: 0 0 2rem;
}

.cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.25rem; margin: 0; }
.cta {
  display: inline-block; padding: .8rem 1.6rem; border-radius: 8px;
  background: var(--accent); color: var(--accent-ink); text-decoration: none;
  font-weight: 620; font-size: 15px; letter-spacing: -.006em;
  border: 1px solid var(--accent-2);
  box-shadow: 0 1px 2px rgba(16, 24, 40, .18), 0 8px 20px -10px var(--accent-glow);
  transition: transform .16s ease, box-shadow .16s ease, background .16s ease;
}
.cta:hover { background: var(--accent-2); transform: translateY(-1px);
             box-shadow: 0 2px 4px rgba(16, 24, 40, .2), 0 12px 26px -10px var(--accent-glow); }
.cta:active { transform: translateY(0); }
.cta:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.cta-lg { padding: .95rem 2.1rem; font-size: 16px; }
.cta-note { font-size: 13px; color: var(--ink-3); }

/* ------------------------------------------------ the investigation panel -- */

.scene { margin: 0; }
.panel {
  border: 1px solid var(--card-line); border-radius: 12px;
  background: linear-gradient(var(--card-top), var(--card-bottom));
  box-shadow: var(--shadow); overflow: hidden;
}
.scene figcaption, .scorecard figcaption {
  margin-top: .85rem; font-size: 12px; line-height: 1.5; color: var(--ink-3);
  max-width: 44ch;
}

.panel-head {
  display: grid; grid-template-columns: auto 1fr auto; gap: .85rem; align-items: center;
  padding: 1rem 1.15rem; border-bottom: 1px solid var(--card-line);
  background: var(--overlay-soft);
}
.panel-rule { margin: 0; font-size: 14px; font-weight: 620; color: var(--ink); line-height: 1.3; }
.panel-meta { margin: .2rem 0 0; font-size: 12px; color: var(--ink-3); }
.panel-clock { font-family: var(--mono); font-size: 12px; color: var(--ink-3); }

/* The severity meter the queue already uses: ordinal, four segments, never hue
   alone. Medium here, so two segments lit. */
.sev { display: inline-flex; gap: 2px; align-items: flex-end; height: 18px; }
.sev i { width: 3.5px; border-radius: 1px; background: var(--medium); }
.sev i:nth-child(1) { height: 7px; }
.sev i:nth-child(2) { height: 11px; }
.sev i:nth-child(3) { height: 15px; }
.sev i:nth-child(4) { height: 18px; }
.sev i.off { background: var(--line-2); }

.panel-row {
  display: grid; grid-template-columns: 5.5rem 1fr; gap: 1rem;
  padding: .95rem 1.15rem; border-bottom: 1px solid var(--line);
}
.row-label {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-3); padding-top: .2rem;
}

.evidence { list-style: none; margin: 0; padding: 0; display: grid; gap: .42rem; }
.evidence li {
  display: grid; grid-template-columns: 3.4rem 1fr auto auto; gap: .7rem;
  align-items: baseline; font-size: 13px;
}
.evidence b { font-family: var(--mono); font-weight: 600; color: var(--ink); }
.evidence span { color: var(--ink-2); }
.evidence em { font-family: var(--mono); font-style: normal; color: var(--ink-3); font-size: 12px; }
.evidence time { font-family: var(--mono); color: var(--ink-3); font-size: 12px; }
/* The one row that changes the answer gets the accent, once. */
.evidence li.hit b, .evidence li.hit span { color: var(--accent); }

.pivot { display: flex; flex-wrap: wrap; align-items: center; gap: .55rem; }
.pivot code {
  font-family: var(--mono); font-size: 12.5px; color: var(--ink);
  background: var(--well); border: 1px solid var(--line); border-radius: 5px;
  padding: .18rem .45rem;
}
.pivot .arrow { color: var(--ink-3); flex: none; }
.tag {
  font-family: var(--mono); font-size: 11.5px; color: var(--good);
  border: 1px solid currentColor; border-radius: 999px; padding: .12rem .55rem;
  opacity: .95;
}

/* A time axis, not a progress bar: ticks where events landed, and the one that
   resolved the case marked in the accent. */
.track { position: relative; height: 22px; }
.track::before {
  content: ""; position: absolute; left: 0; right: 0; top: 10px; height: 1px;
  background: var(--line-2);
}
.tick {
  position: absolute; top: 5px; width: 2px; height: 11px; border-radius: 1px;
  background: var(--ink-3); opacity: .75;
}
.tick-hit { background: var(--accent); opacity: 1; height: 15px; top: 3px; width: 2.5px; }

.panel-foot {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .7rem;
  padding: .95rem 1.15rem; background: var(--overlay-soft);
}
.verdict {
  font-size: 12.5px; font-weight: 650; color: var(--good);
  border: 1px solid currentColor; border-radius: 5px; padding: .16rem .5rem;
}
.foot-note { font-size: 12.5px; color: var(--ink-3); }

/* ------------------------------------------------------------------- rail -- */

/* Five moves as one continuous piece of work. The connecting line is the whole
   point — the previous four-cards-plus-a-stranded-fifth said the opposite. */
.rail {
  list-style: none; margin: 0; padding: 0; counter-reset: step;
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 0;
}
.rail li {
  counter-increment: step; position: relative;
  padding: 3rem 1.4rem 0 0; margin-right: 1.4rem;
}
.rail li:last-child { margin-right: 0; padding-right: 0; }
/* The rail itself, drawn once per item so it stops cleanly at the last. */
.rail li::before {
  content: ""; position: absolute; left: 0; right: 0; top: 11px; height: 1px;
  background: var(--line-2);
}
.rail li:last-child::before { right: auto; width: 24px; }
/* The node, with its number set beneath it in mono. */
.rail li::after {
  content: counter(step, decimal-leading-zero);
  position: absolute; left: 0; top: 0;
  font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  background: var(--bg); padding-right: .6rem; line-height: 22px;
}
.band-alt .rail li::after { background: var(--bg-2); }
.rail h3 { margin-bottom: .45rem; }
.rail p { font-size: 13.5px; line-height: 1.55; color: var(--ink-2); margin: 0; }

/* ------------------------------------------------------- marked on method -- */

.split {
  display: grid; grid-template-columns: 1fr 1.1fr;
  gap: clamp(2rem, 5vw, 4.5rem); align-items: center;
}
/* Held to a measure so the heading sets in two lines, breaking after
   "method,". Unconstrained it stranded "just the verdict"; at 15ch it took
   three. Measured against the rendered page, not guessed. */
.split-copy h2 { max-width: 20ch; }
.split-copy p { font-size: 15.5px; line-height: 1.62; color: var(--ink-2); max-width: 46ch; }
.split-copy p + p { margin-top: 1rem; }

.scorecard { margin: 0; }
.score-head {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 1rem 1.15rem; border-bottom: 1px solid var(--card-line);
  background: var(--overlay-soft);
  font-size: 13px; color: var(--ink-2);
}
.score-head b { font-family: var(--mono); font-size: 22px; font-weight: 650; color: var(--ink); }
.score-head b i { font-style: normal; font-size: 13px; color: var(--ink-3); }

.marks { list-style: none; margin: 0; padding: .9rem 1.15rem; display: grid; gap: .6rem; }
.marks li {
  display: grid; grid-template-columns: 9.5rem 1fr 3.2rem; gap: .8rem; align-items: center;
  font-size: 13px; color: var(--ink-2);
}
.marks em { font-family: var(--mono); font-style: normal; font-size: 12px;
            color: var(--ink-3); text-align: right; }
.meter { height: 5px; border-radius: 3px; background: var(--line); overflow: hidden; }
.meter i { display: block; height: 100%; border-radius: 3px; background: var(--good); }
.marks li.strong span { color: var(--ink); font-weight: 600; }
.marks li.strong .meter i { background: var(--accent); }
.marks li.miss .meter i { background: var(--bad); }
.marks li.miss em { color: var(--bad); }
.score-foot {
  margin: 0; padding: .2rem 1.15rem 1.1rem; font-size: 12px; line-height: 1.5;
  color: var(--ink-3);
}

/* -------------------------------------------------------------- refusals -- */

/* The statement is the largest thing on the page after the hero, and it is
   allowed to be, because it is the sentence people repeat about this product. */
.statement {
  font-size: clamp(28px, 4.6vw, 46px) !important; line-height: 1.08; letter-spacing: -.028em;
  font-weight: 700; margin: 0 0 clamp(2rem, 4vw, 3rem) !important;
}
.refusals {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.5rem, 3vw, 3rem);
  border-top: 1px solid var(--line); padding-top: 2rem;
}
.refusals p { font-size: 13.5px; line-height: 1.6; color: var(--ink-2); margin: 0; }

/* ---------------------------------------------------------------- honest -- */

.honest { max-width: 52rem; }
.honest .lead { font-size: clamp(16px, 1.7vw, 19px); line-height: 1.55; color: var(--ink);
                margin: 0 0 1.15rem; }
.honest p { font-size: 15.5px; line-height: 1.62; color: var(--ink-2); margin: 0; }
.honest em { color: var(--ink); font-style: italic; }

/* ---------------------------------------------------------------- closer -- */

.closer {
  padding: clamp(4rem, 9vw, 7.5rem) 0; text-align: center;
  border-top: 1px solid var(--line);
  background: radial-gradient(48rem 26rem at 50% 0%, var(--accent-wash), transparent 66%);
}
.closer h2 { font-size: clamp(26px, 3.6vw, 40px) !important; margin-bottom: .6rem !important; }
.closer p { font-size: 15px; color: var(--ink-2); margin: 0 0 1.8rem; }
.closer .cta-note { display: block; margin: 1.1rem 0 0; }

/* ---------------------------------------------------------------- footer -- */

footer.landing-foot { border-top: 1px solid var(--line); padding: 1.75rem 0; }
.foot-grid {
  display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center;
  gap: 1rem; font-size: 12.5px; color: var(--ink-3);
}
.foot-mark { display: inline-flex; align-items: center; gap: .55rem; color: var(--ink-2); }

/* ------------------------------------------------------------- responsive -- */

@media (max-width: 62rem) {
  .hero-grid, .split { grid-template-columns: 1fr; }
  .split-copy { order: 1; }
  .scorecard { order: 2; }
  .refusals { grid-template-columns: 1fr; gap: 1.75rem; }
  .refusals > div { border-top: 1px solid var(--line); padding-top: 1.25rem; }
  .refusals { border-top: 0; padding-top: 0; }

  /* The rail turns vertical rather than wrapping into an uneven grid — which is
     exactly the composition this replaced. */
  .rail { grid-template-columns: 1fr; gap: 0; }
  .rail li { padding: 0 0 1.6rem 2.2rem; margin: 0; }
  .rail li:last-child { padding-bottom: 0; }
  .rail li::before {
    left: 5px; right: auto; top: 6px; bottom: 0; width: 1px; height: auto;
  }
  .rail li:last-child::before { height: 0; }
  .rail li::after { top: 0; left: 0; background: none; padding: 0; line-height: 1.3; }
  .rail li::after { left: 0; }
}

@media (max-width: 40rem) {
  main.landing .wrap { padding: 0 1.15rem; }
  .hero { padding-top: 1.5rem; }
  .cta { width: 100%; text-align: center; }
  .cta-note { width: 100%; }
  .panel-row { grid-template-columns: 1fr; gap: .5rem; }
  .evidence li { grid-template-columns: 3rem 1fr auto; }
  .evidence time { display: none; }
  .marks li { grid-template-columns: 7.5rem 1fr 2.8rem; font-size: 12.5px; }
  .score-head b { font-size: 19px; }
}

/* ----------------------------------------------------------------- motion -- */

/* One entrance, once, and nothing that loops. A landing page that animates
   continuously reads as a game; the point of this movement is only to let the
   eye land on the headline before the panel arrives. */
@media (prefers-reduced-motion: no-preference) {
  .hero-copy > *, .scene { animation: rise .42s cubic-bezier(.22, .61, .36, 1) both; }
  .hero-copy > :nth-child(1) { animation-delay: .01s; }
  .hero-copy > :nth-child(2) { animation-delay: .05s; }
  .hero-copy > :nth-child(3) { animation-delay: .09s; }
  .hero-copy > :nth-child(4) { animation-delay: .13s; }
  .scene { animation-delay: .1s; }
}
@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
