{adapter.name}
-{adapter.body}
-{adapter.snippet}
- diff --git a/tests/test_publication_claims.py b/tests/test_publication_claims.py index 43e1340..ee82ad2 100644 --- a/tests/test_publication_claims.py +++ b/tests/test_publication_claims.py @@ -49,13 +49,15 @@ def test_public_claim_surfaces_use_the_frozen_lane_and_current_gate() -> None: def test_employer_facing_site_links_current_evidence_and_metadata() -> None: - hero = Path("web/src/components/Hero.tsx").read_text() + results = Path("web/src/components/ResultsExplorer.tsx").read_text() footer = Path("web/src/components/Footer.tsx").read_text() index = Path("web/index.html").read_text() - assert "0 beat the scripted bar" in hero - assert "sota-v2-phase-one-2026-07-19" in hero - assert "Built by Ned Cutler" in footer + assert "Above scripted bar" in results + assert "modelsAboveBar" in results + assert "Holm-adjusted family test" in results + assert "sota-v2-phase-one-2026-07-19" in footer + assert "Ned Cutler" in footer assert "REPRODUCING_SOTA_V2_RELEASE.md" in footer assert 'href="%BASE_URL%favicon.svg"' in index assert 'rel="canonical" href="https://nedcut.github.io/gm-bench/"' in index diff --git a/web/bun.lock b/web/bun.lock index eac3a05..42a519d 100644 --- a/web/bun.lock +++ b/web/bun.lock @@ -5,10 +5,14 @@ "": { "name": "web", "dependencies": { + "d3-array": "^3.2.4", + "d3-scale": "^4.0.2", "react": "^19.2.7", "react-dom": "^19.2.7", }, "devDependencies": { + "@types/d3-array": "^3.2.2", + "@types/d3-scale": "^4.0.9", "@types/node": "^26.1.1", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", @@ -102,6 +106,12 @@ "@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="], + "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], + + "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], + + "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], + "@types/node": ["@types/node@26.1.1", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw=="], "@types/react": ["@types/react@19.2.17", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw=="], @@ -152,12 +162,28 @@ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], + + "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], + + "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="], + + "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], + + "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], + + "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], + + "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], diff --git a/web/index.html b/web/index.html index 5eae457..11e609e 100644 --- a/web/index.html +++ b/web/index.html @@ -4,31 +4,31 @@ - + - + - + -
Bring your own model
-- Every adapter speaks the same observation/action schema, so results are comparable - across providers — from frontier APIs to a laptop-hosted 4B model. -
-{adapter.body}
-{adapter.snippet}
- Absolute score
++ Select a model anywhere on the page to trace its score, cost, and rejected + actions through the same published record. +
++ Amber means more actions were rejected. Exact values remain visible in + every cell. +
+- A pre-registered front-office benchmark for LLM agents - By Ned Cutler -
- - Phase-one result - {data.models.length} models tested. 0 beat the scripted bar. - View evidence → - -- GM-Bench puts agents in charge of a franchise in a fictional hockey-style league — - contracts, trades, drafts, cap pressure — for seeded, replayable multi-season episodes. - Eight scripted heuristics set the bar and a hidden-information oracle sets the ceiling.{" "} - The board opens only when the pre-registered evidence is complete. -
- -- {fingerprint && ( - <> - frozen contract {fingerprint} ·{" "} - > - )} - {data.preset.seeds.length} seeds × {data.preset.seasons} seasons × 3 repeats - {cap && ( - <> - {" "} - · {cap.toLocaleString("en-US")}-token output ceiling · reasoning off - > - )} - {registryFrozen ? " · routes pinned" : " · routes pending smoke verification"} -
-The decision loop
+Protocol
- No browser automation, no memorized rosters — every player is fictional. Agents - face the same long-horizon trade-offs a real front office does, expressed as a - minimal JSON protocol any process can speak. + No browser automation, no memorized rosters — every player is fictional. Agents speak a + minimal JSON protocol any process can run. Under the published scaffold, reading that JSON/API contract is + part of what the benchmark measures.
{phase.num}
+{phase.num}
{phase.body}
{point.body}
-{point.body}
Integrity
-- The score-affecting contract and statistical plan are frozen and fingerprinted before - official results. Route selection remains visibly pending until every registered smoke - clears the gate below. -
-
- Simulator, scoring, presets, and action schemas hash to{" "}
- {contract?.contract_fingerprint ?? "—"}. Any change to a score-affecting
- source changes the fingerprint and invalidates comparability.
-
- One common {cap.toLocaleString("en-US")}-token output ceiling, reasoning off, JSON - mode on; exact provider routes are {registryFrozen ? "pinned" : "pending smoke verification"}. - The v1 table ranked output budgets, not models; v2 holds compute constant. -
- ) : ( -The common compute policy is still pending and no fixed-ceiling claim is published.
- )} -- The statistical plan froze before any data: Holm-corrected paired contrasts, per-model - p-values reported as descriptive only, and models with overlapping uncertainty - published as one tier. -
-- Paid runs are serial, checkpointed, and spend-capped; raw artifacts are hash-linked; - valid poor results are never re-run. When v1 failed this standard, it was withdrawn — - not patched. -
-| Tier | } -Model | -Score | -Lift vs panel [95% CI] | -Cost/episode | -Status | - {showTelemetry && ( - <> -Fallback | -Failed queries | -Input/dec | -Output/dec | -Latency | - > - )} -
|---|---|---|---|---|---|---|---|---|---|---|
| {tierStarts ? Tier {tier} : ·} | - )} -- - {model.model} - {PROVIDER_LABELS[model.provider] ?? model.provider} - - | -{fmt(model.mean_score, 1)} | -{liftCell(model)} | -{cost(model)} | -{statusTag(model)} | - {showTelemetry && ( - <> -{pct(model.fallback_rate)} | -- {model.failed_queries === undefined ? "—" : model.failed_queries} - | -- {model.input_tokens_per_decision === null ? "—" : fmt(model.input_tokens_per_decision, 0)} - | -- {model.output_tokens_per_decision === null ? "—" : fmt(model.output_tokens_per_decision, 0)} - | -- {latency === null ? "—" : `${fmt(latency, 1)}s`} - | - > - )} -
| Agent | -- | Mean score | -σ | -- |
|---|---|---|---|---|
| - - - {row.agent} - - | -- {row.kind === "bar" && the red line} - {row.kind === "ceiling" && hidden-information ceiling} - {row.kind === "baseline" && scripted} - | -{fmt(row.mean_score, 1)} | -{row.score_stddev === null ? "—" : fmt(row.score_stddev, 1)} | -
-
-
-
- |
-
- The previous version of this table was withdrawn when a contract defect was found to - penalize some models and not others. The v2 board therefore publishes nothing until every - gate below is machine-verified: {publication.reason}. -
-- Scores cannot influence the protocol — the contract, compute policy, model registry, and - statistical analysis plan freeze before official runs, and a valid poor result is - never re-run. -
-
- Every score published under the previous sota-v1 contract has been withdrawn.
- The scaffold prompt documented {`{"type":"scout","prospect_id":N}`} as a valid
- action, but the simulator only ever read player_id and silently rejected the
- documented form — with no protocol penalty, so the rejections never appeared in any summary.
-
- The defect did not fall evenly. It cost some candidates over a thousand silently-rejected
- lookups and others none at all, while the scripted baselines were untouched. The v1 table was
- therefore not a valid ranking of the models in it, and no caveat makes it one. The raw
- artifacts remain in results/leaderboard/archive-v1/ as evidence of the defect.
-
| Model | - {mechanics.map(([key, label]) => ( -- {label} - | - ))} -
|---|---|
| {model.model} | - {mechanics.map(([key]) => { - const outcome = model.mechanic_breakdown?.[key] ?? { accepted: 0, rejected: 0 }; - return ( -- {outcome.accepted} / {outcome.rejected} - | - ); - })} -
The board
-- Models manage the same franchises over the same {data.preset.seeds.length} seeds for{" "} - {data.preset.seasons} seasons ({data.preset.decision_points_per_episode} decisions per - franchise), paired per-seed against the scripted panel. The frozen analysis plan - publishes overlapping-uncertainty tiers — never an ordinal #1. -
-- Coding-harness rows run the same episodes through a CLI agent's own tool loop, context, - and retries. That harness is part of what gets measured, so these rows live in their own - observational table and never mix with the API lane. -
-
@@ -47,17 +56,27 @@ export default function Quickstart() {
- Quickstart
- From clone to scoreboard in two commands.
+ Run
+ Calibrate on baselines, then plug in an agent.
- Start with the scripted baselines to calibrate, then plug in your own agent with
- --agent-cmd. JSON Schemas for the observation and action protocol ship in{" "}
+ Use --agent-cmd for any subprocess. Observation and action schemas ship in{" "}
schemas/.
-
-
+
+
+
+
+ Compatible with Codex CLI, Claude Code, Ollama, OpenAI-compatible
+ endpoints, opencode, or any stdin/stdout process:
+
+ {ADAPTERS.map((adapter) => (
+
+ {adapter.snippet}
+
+ ))}
+
diff --git a/web/src/components/Results.tsx b/web/src/components/Results.tsx
deleted file mode 100644
index f8be4f2..0000000
--- a/web/src/components/Results.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-import type { Snapshot } from "../types";
-import { agentColor, fmt, pct } from "../lib";
-import { LiftChart, SeasonTraceChart } from "./Charts";
-
-function StandingsTable({ snapshot }: { snapshot: Snapshot }) {
- const { standings, config } = snapshot;
- const maxScore = Math.max(...standings.map((row) => row.mean_score));
- return (
-
-
- Agent standings
-
- seeds {config.seeds.join(" ")} · {config.seasons} seasons
-
-
-
-
-
-
- Agent
- Mean score
-
- σ
- Wins/ep
- Titles
- Illegal
-
-
-
- {standings.map((row) => (
-
-
-
-
- {row.agent}
-
- {row.agent === config.candidate ? "candidate" : "baseline"}
-
-
-
- {fmt(row.mean_score, 1)}
-
-
-
-
-
- {fmt(row.score_stddev, 1)}
- {fmt(row.mean_wins, 1)}
- {row.titles}
- {row.illegal_actions}
-
- ))}
-
-
-
-
- );
-}
-
-function Verdict({ snapshot }: { snapshot: Snapshot }) {
- const { normalized, paired } = snapshot;
- return (
-
-
- Paired evaluation verdict
- value vs panel · descriptive
-
-
- +{fmt(paired.paired_lift_mean, 1)}
- paired lift
-
-
-
- Candidate mean score
- {fmt(normalized.candidate_mean_score, 1)}
-
-
- Baseline panel mean
- {fmt(normalized.baseline_panel_mean_score, 1)}
-
-
- Bootstrap 95% CI on lift
-
- [{fmt(paired.paired_lift_ci95[0], 1)}, {fmt(paired.paired_lift_ci95[1], 1)}]
-
-
-
- Seed win rate vs panel
- {pct(paired.candidate_seed_win_rate)}
-
- {paired.best_baseline && (
-
- vs best baseline ({paired.best_baseline.agent})
-
- +{fmt(paired.best_baseline.paired_lift_mean, 1)} · {pct(paired.best_baseline.seed_win_rate)} seeds
-
-
- )}
-
- Illegal actions (candidate)
- {normalized.candidate_illegal_actions}
-
-
-
- intervals are descriptive — the frozen analysis plan reserves significance language for the Holm-corrected family
-
-
- );
-}
-
-export default function Results({ snapshot }: { snapshot: Snapshot }) {
- return (
-
-
-
- Reference run
- How a result reads, demonstrated on scripted agents.
-
- Every agent plays the exact same league generations. Per-seed differencing cancels league
- luck, and a deterministic bootstrap puts an interval on the lift. This reference run pits
- the scripted value agent against the panel — the same report every model row
- gets.
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/web/src/components/ResultsExplorer.tsx b/web/src/components/ResultsExplorer.tsx
new file mode 100644
index 0000000..594ff94
--- /dev/null
+++ b/web/src/components/ResultsExplorer.tsx
@@ -0,0 +1,682 @@
+import { useMemo, useState, type CSSProperties } from "react";
+import { max } from "d3-array";
+import { scaleLinear } from "d3-scale";
+import type { BenchmarkView, ResultModel } from "../benchmarkData";
+import { issueLabels, shortModelName } from "../benchmarkData";
+import type { Leaderboard as LeaderboardData } from "../types";
+import { fmt } from "../lib";
+
+type ChartView = "lift" | "cost";
+type SortKey = "score" | "lift" | "cost";
+
+function ObservationDisclosure({ model }: { model: ResultModel }) {
+ const issues = model.sota_v2_issues ?? [];
+ const labels = issueLabels(model);
+ return (
+
+
+ {issues.length} observation{issues.length === 1 ? "" : "s"}
+
+
+
+ {labels.map((label, index) => (
+ {label}
+ ))}
+
+
+ {issues.map((issue) => (
+ - {issue}
+ ))}
+
+
+
+ );
+}
+
+function ForestPlot({
+ models,
+ selected,
+ onSelect,
+}: {
+ models: ResultModel[];
+ selected: string;
+ onSelect: (id: string) => void;
+}) {
+ const width = 1280;
+ const left = 270;
+ const right = 42;
+ const rowHeight = 48;
+ const top = 46;
+ const bottom = 58;
+ const height = top + models.length * rowHeight + bottom;
+ const ciValues = models.flatMap((model) => model.ci95);
+ const minLift = Math.min(-20, Math.floor((Math.min(...ciValues) - 8) / 20) * 20);
+ const x = scaleLinear().domain([minLift, 20]).range([left, width - right]);
+ const ticks = x.ticks(8);
+
+ return (
+
+
+
+ );
+}
+
+function CostScatter({
+ models,
+ scriptedBar,
+ oracle,
+ selected,
+ onSelect,
+}: {
+ models: ResultModel[];
+ scriptedBar: number;
+ oracle: number;
+ selected: string;
+ onSelect: (id: string) => void;
+}) {
+ const width = 1280;
+ const height = 480;
+ const left = 88;
+ const right = 42;
+ const top = 34;
+ const bottom = 64;
+ const maxCost = max(models, (model) => model.cost_per_episode_usd) ?? 0.5;
+ const x = scaleLinear()
+ .domain([0, Math.max(0.5, maxCost * 1.08)])
+ .nice()
+ .range([left, width - right]);
+ const y = scaleLinear()
+ .domain([0, Math.max(450, oracle * 1.04)])
+ .nice()
+ .range([height - bottom, top]);
+ const xTicks = x.ticks(6);
+ const yTicks = y.ticks(6);
+ const labels = [...models]
+ .map((model) => ({
+ id: model.id,
+ x: x(model.cost_per_episode_usd),
+ pointY: y(model.mean_score),
+ labelY: y(model.mean_score) - 10,
+ }))
+ .sort((a, b) => a.labelY - b.labelY);
+ labels.forEach((label, index) => {
+ if (index > 0) {
+ label.labelY = Math.max(label.labelY, labels[index - 1].labelY + 18);
+ }
+ });
+ const labelById = new Map(labels.map((label) => [label.id, label]));
+
+ return (
+
+
+
+ );
+}
+
+function ResultsTable({
+ models,
+ selected,
+ onSelect,
+}: {
+ models: ResultModel[];
+ selected: string;
+ onSelect: (id: string) => void;
+}) {
+ const [sort, setSort] = useState("score");
+ const sorted = useMemo(() => {
+ const next = [...models];
+ if (sort === "score") next.sort((a, b) => b.mean_score - a.mean_score);
+ if (sort === "lift") next.sort((a, b) => b.paired_lift - a.paired_lift);
+ if (sort === "cost") next.sort((a, b) => a.cost_per_episode_usd - b.cost_per_episode_usd);
+ return next;
+ }, [models, sort]);
+
+ return (
+
+
+
+
+ Model
+
+
+
+
+
+
+ 95% CI
+
+
+
+ Protocol observations
+
+
+
+ {sorted.map((model) => (
+
+
+
+
+ {fmt(model.mean_score, 1)}
+ {fmt(model.paired_lift, 1)}
+
+ [{fmt(model.ci95[0], 1)}, {fmt(model.ci95[1], 1)}]
+
+ ${fmt(model.cost_per_episode_usd, 2)}
+
+
+
+
+ ))}
+
+
+
+ );
+}
+
+export default function ResultsExplorer({
+ data,
+ benchmark,
+ selectedModelId,
+ onSelectModel,
+}: {
+ data: LeaderboardData;
+ benchmark: BenchmarkView;
+ selectedModelId: string;
+ onSelectModel: (id: string) => void;
+}) {
+ const [view, setView] = useState("lift");
+ const [modelMenuOpen, setModelMenuOpen] = useState(false);
+ const [selectedIds, setSelectedIds] = useState(
+ () => new Set(benchmark.models.map((model) => model.id)),
+ );
+
+ const filtered = useMemo(() => {
+ return benchmark.models.filter((model) => selectedIds.has(model.id));
+ }, [benchmark.models, selectedIds]);
+
+ const selectedModel =
+ benchmark.models.find((model) => model.id === selectedModelId) ??
+ benchmark.models[0];
+ const bestModel = benchmark.models[0];
+ const panelMean = bestModel?.baseline_panel_mean_score;
+
+ const toggleModel = (id: string) => {
+ setSelectedIds((current) => {
+ const next = new Set(current);
+ if (next.has(id)) next.delete(id);
+ else next.add(id);
+ if (id === selectedModelId && !next.has(id)) {
+ const fallback = benchmark.models.find((model) => next.has(model.id));
+ if (fallback) onSelectModel(fallback.id);
+ }
+ return next;
+ });
+ };
+
+ return (
+
+
+
+
+ Phase one results
+ Performance against the baseline panel.
+
+ Paired seed-level differences for eight published model-plus-scaffold
+ systems.
+
+
+ Descriptive intervals; the predeclared Holm-adjusted family test does
+ not reject at 0.05.
+
+
+
+
+ - Best observed mean
+ - {bestModel ? fmt(bestModel.mean_score, 1) : "—"}
+ {bestModel ? shortModelName(bestModel.model) : "No result"}
+
+
+ - Baseline panel mean
+ - {panelMean === null || panelMean === undefined ? "—" : fmt(panelMean, 1)}
+ paired reference
+
+
+ - Above scripted bar
+ -
+ {benchmark.modelsAboveBar}/{benchmark.modelCount}
+
+ pick-trader · {fmt(benchmark.scriptedBar, 1)}
+
+
+
+
+
+
+
+ - Seeds
+ - {data.preset.seeds.length}
+
+
+ - Seasons
+ - {data.preset.seasons}
+
+
+ - Repeats
+ - {benchmark.repeats}
+
+
+ - Updated
+ - {data.updated}
+
+
+ Read the protocol
+
+
+
+
+
+
+
+ API lane · {filtered.length} visible
+
+
+ {modelMenuOpen && (
+
+
+
+
+
+ {benchmark.models.map((model) => (
+
+ ))}
+
+ )}
+
+
+
+
+
+
+
+ {view === "lift" ? "Primary comparison" : "Secondary lens"}
+
+
+ {view === "lift"
+ ? "Every paired difference is below the panel reference."
+ : "Score vs cost per episode"}
+
+
+ {view === "lift"
+ ? "Whiskers show 95% intervals. All eight rows overlap in one descriptive tier."
+ : "Price varies widely, but no observed mean reaches the pick-trader bar."}
+
+
+ {filtered.length} models
+
+ {filtered.length === 0 ? (
+
+ No models match the current filters.
+
+
+ ) : (
+
+ {view === "lift" ? (
+
+ ) : (
+
+ )}
+
+ )}
+ {selectedModel && selectedIds.has(selectedModel.id) && (
+
+ Selected
+ {shortModelName(selectedModel.model)}
+ score {fmt(selectedModel.mean_score, 1)}
+ paired lift {fmt(selectedModel.paired_lift, 1)}
+
+ 95% CI [{fmt(selectedModel.ci95[0], 1)},{" "}
+ {fmt(selectedModel.ci95[1], 1)}]
+
+ ${fmt(selectedModel.cost_per_episode_usd, 2)} / episode
+ Inspect mechanics ↓
+
+ )}
+
+
+
+
+
+ );
+}
diff --git a/web/src/index.css b/web/src/index.css
index f951aef..c744b5d 100644
--- a/web/src/index.css
+++ b/web/src/index.css
@@ -1,25 +1,93 @@
-/* GM-Bench — "the officials' report from the rink".
- Light ice surface, deep ink, rink-line hairlines. Red is reserved for one
- meaning everywhere on the page: the bar to beat (the red line). Blue marks
- measured candidates. Display type is condensed and uppercase like a
- scoreboard; running text is a serif, like the report that gets filed. */
+/* GM-Bench — sports wire / box score.
+ Cold paper, ink, rink-line hairlines. Red means one thing: the bar to beat.
+ Blue marks measured candidates. Scores use condensed numerals; copy is
+ sentence-case grotesque, not campaign headlines. */
:root {
- --ice: #f4f7f9;
- --ice-2: #ecf1f5;
+ --paper: #eef2f5;
+ --paper-2: #e4eaef;
--card: #ffffff;
- --ink: #0c1d2e;
- --steel: #51697e;
- --faint: #5a7185;
+ --ink: #0a1620;
+ --steel: #3d5163;
+ --faint: #5c7386;
--red: #c8102e;
--red-soft: rgba(200, 16, 46, 0.07);
- --blue: #155b9a;
- --blue-soft: rgba(21, 91, 154, 0.08);
- --line: #d9e4eb;
- --line-strong: #b9cbd7;
- --font-display: "Barlow Condensed", "Arial Narrow", sans-serif;
- --font-body: "source serif 4", Georgia, serif;
+ --blue: #1a5f8f;
+ --blue-soft: rgba(26, 95, 143, 0.08);
+ --line: #d3dde6;
+ --line-strong: #c5d3de;
+ /* chart marks — themeable so the SVG ladder tracks the table palette */
+ --mark-axis: #0a1620;
+ --mark-ref: #7e93a6;
+ --mark-faint: #8aa0b2;
+ --mark-grid: #c5d3de;
+ --hero-grad-top: #f5f8fa;
+ --hero-lines: rgba(197, 211, 222, 0.35);
+ --nav-bg: rgba(238, 242, 245, 0.94);
+ /* the code card is a terminal in both registers — pinned dark */
+ --code-bg: #0a1620;
+ --code-fg: #dce8f2;
+ --code-dim: #8fa8bd;
+ --code-line: rgba(220, 232, 242, 0.12);
+ --font-score: "Barlow Condensed", "Arial Narrow", sans-serif;
+ --font-body: "IBM Plex Sans", "Helvetica Neue", sans-serif;
--font-mono: "IBM Plex Mono", ui-monospace, monospace;
+ color-scheme: light;
+}
+
+/* Dark register: same cold-wire system after dusk. Red still means one thing;
+ blue still marks candidates — both nudged brighter to hold contrast on ink. */
+:root[data-theme="dark"] {
+ --paper: #0d141b;
+ --paper-2: #131d26;
+ --card: #111a22;
+ --ink: #e8eef3;
+ --steel: #a9bccb;
+ --faint: #7f95a8;
+ --red: #ff4d5e;
+ --red-soft: rgba(255, 77, 94, 0.1);
+ --blue: #5ea8e0;
+ --blue-soft: rgba(94, 168, 224, 0.12);
+ --line: #1c2731;
+ --line-strong: #253340;
+ --mark-axis: #c9d6e0;
+ --mark-ref: #7f95a8;
+ --mark-faint: #5f7488;
+ --mark-grid: #253340;
+ --hero-grad-top: #101922;
+ --hero-lines: rgba(37, 51, 64, 0.55);
+ --nav-bg: rgba(13, 20, 27, 0.92);
+ --code-bg: #080f16;
+ --code-fg: #dce8f2;
+ --code-dim: #8fa8bd;
+ --code-line: rgba(220, 232, 242, 0.1);
+ color-scheme: dark;
+}
+
+body,
+.nav,
+.panel,
+.gate,
+.footnotes,
+.phase-wire,
+.code-card,
+table,
+tbody tr {
+ transition: background-color 0.25s ease, border-color 0.25s ease, color 0.25s ease;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ body,
+ .nav,
+ .panel,
+ .gate,
+ .footnotes,
+ .phase-wire,
+ .code-card,
+ table,
+ tbody tr {
+ transition: none;
+ }
}
* {
@@ -34,17 +102,17 @@ html {
}
body {
- background: var(--ice);
+ background: var(--paper);
color: var(--ink);
font-family: var(--font-body);
- font-size: 16.5px;
- line-height: 1.65;
+ font-size: 15.5px;
+ line-height: 1.55;
-webkit-font-smoothing: antialiased;
overflow-x: clip;
}
::selection {
- background: rgba(21, 91, 154, 0.18);
+ background: rgba(26, 95, 143, 0.18);
}
a {
@@ -73,22 +141,9 @@ code {
}
.shell {
- max-width: 1120px;
+ max-width: 1080px;
margin: 0 auto;
- padding: 0 24px;
-}
-
-/* ---------- display type ---------- */
-
-.display,
-h1,
-h2,
-.section-head h2 {
- font-family: var(--font-display);
- font-weight: 700;
- text-transform: uppercase;
- letter-spacing: 0.01em;
- line-height: 0.98;
+ padding: 0 22px;
}
/* ---------- nav ---------- */
@@ -97,8 +152,8 @@ h2,
position: sticky;
top: 0;
z-index: 40;
- background: rgba(244, 247, 249, 0.92);
- backdrop-filter: blur(10px);
+ background: var(--nav-bg);
+ backdrop-filter: blur(8px);
border-bottom: 1px solid var(--line-strong);
}
@@ -106,43 +161,38 @@ h2,
display: flex;
align-items: center;
justify-content: space-between;
- height: 60px;
+ height: 52px;
}
.brand {
display: flex;
align-items: center;
- gap: 10px;
- font-family: var(--font-display);
- font-weight: 700;
- font-size: 21px;
- text-transform: uppercase;
- letter-spacing: 0.04em;
+ gap: 9px;
+ font-family: var(--font-body);
+ font-weight: 600;
+ font-size: 16px;
+ letter-spacing: -0.01em;
}
.brand-tag {
font-family: var(--font-mono);
font-size: 10px;
font-weight: 500;
- color: var(--blue);
- border: 1px solid var(--blue);
- border-radius: 3px;
- padding: 1px 7px;
+ color: var(--steel);
+ border: 1px solid var(--line-strong);
+ border-radius: 2px;
+ padding: 1px 6px;
margin-left: 2px;
- letter-spacing: 0.1em;
+ letter-spacing: 0.06em;
text-transform: uppercase;
- transform: translateY(-1px);
}
.nav-links {
display: flex;
align-items: center;
- gap: 26px;
- font-family: var(--font-display);
+ gap: 22px;
+ font-size: 13.5px;
font-weight: 500;
- font-size: 16px;
- text-transform: uppercase;
- letter-spacing: 0.05em;
color: var(--steel);
}
@@ -151,18 +201,13 @@ h2,
}
.nav-cta {
- font-family: var(--font-display);
- font-weight: 600;
- color: var(--ice);
- background: var(--ink);
- padding: 7px 16px 8px;
- border-radius: 4px;
- transition: background 0.15s ease;
+ color: var(--ink);
+ border-bottom: 1px solid var(--line-strong);
+ padding-bottom: 1px;
}
.nav-cta:hover {
- background: var(--blue);
- color: var(--ice);
+ border-color: var(--ink);
}
@media (max-width: 800px) {
@@ -173,18 +218,18 @@ h2,
@media (max-width: 480px) {
.shell {
- padding-inline: 16px;
+ padding-inline: 14px;
}
.brand {
gap: 7px;
- font-size: 18px;
+ font-size: 15px;
white-space: nowrap;
}
.brand svg {
- width: 24px;
- height: 24px;
+ width: 22px;
+ height: 22px;
}
.brand-tag {
@@ -196,8 +241,7 @@ h2,
}
.nav-cta {
- padding: 7px 10px 8px;
- font-size: 14px;
+ font-size: 13px;
white-space: nowrap;
}
}
@@ -205,181 +249,310 @@ h2,
/* ---------- hero ---------- */
.hero {
- padding: 62px 0 40px;
+ padding: 48px 0 0;
+ border-bottom: 1px solid var(--line-strong);
+ background:
+ linear-gradient(180deg, var(--hero-grad-top) 0%, var(--paper) 72%),
+ repeating-linear-gradient(
+ 90deg,
+ transparent,
+ transparent 47px,
+ var(--hero-lines) 47px,
+ var(--hero-lines) 48px
+ );
}
-.hero-eyebrow {
- display: inline-flex;
- align-items: center;
- gap: 10px;
- font-family: var(--font-mono);
- font-size: 12px;
- letter-spacing: 0.12em;
- text-transform: uppercase;
- color: var(--steel);
- margin-bottom: 16px;
+.hero-top {
+ padding-bottom: 28px;
}
-.hero-eyebrow::before {
- content: "";
- width: 34px;
- height: 3px;
- background: var(--red);
+.hero-brand {
+ font-family: var(--font-score);
+ font-weight: 700;
+ font-size: clamp(42px, 7vw, 68px);
+ letter-spacing: 0.02em;
+ line-height: 0.95;
+ text-transform: uppercase;
+ margin-bottom: 18px;
}
-.hero-eyebrow a {
- color: var(--ink);
- border-bottom: 1px solid var(--line-strong);
+.hero-brand span {
+ color: var(--red);
}
-.hero-eyebrow a:hover {
- color: var(--blue);
- border-color: var(--blue);
+.hero h1 {
+ font-family: var(--font-body);
+ font-weight: 600;
+ font-size: clamp(20px, 2.6vw, 25px);
+ letter-spacing: -0.02em;
+ line-height: 1.25;
+ max-width: 40ch;
+ margin-bottom: 10px;
+ text-transform: none;
}
-.hero h1 {
- font-size: clamp(52px, 7.6vw, 94px);
- max-width: 17ch;
- margin-bottom: 26px;
+.hero-sub {
+ font-size: 15px;
+ color: var(--steel);
+ max-width: 46ch;
+ margin-bottom: 18px;
}
-.hero-result {
- display: flex;
- align-items: baseline;
- width: fit-content;
- gap: 10px 14px;
- margin-bottom: 24px;
- padding: 8px 12px 9px;
+.hero-caveat {
+ max-width: 50ch;
border-left: 3px solid var(--red);
- background: var(--card);
- box-shadow: inset 0 0 0 1px var(--line);
- font-family: var(--font-mono);
+ padding-left: 10px;
+ color: var(--steel);
+ font-size: 12px;
+ line-height: 1.45;
}
-.hero-result span,
-.hero-result i {
+.ranking-callout {
+ margin: 0 0 18px;
+ padding: 12px 14px;
+ border: 1px solid var(--line-strong);
+ border-left: 4px solid var(--red);
+ background: var(--card);
color: var(--steel);
- font-size: 10.5px;
- font-style: normal;
- letter-spacing: 0.08em;
- text-transform: uppercase;
+ font-size: 13px;
+ line-height: 1.45;
}
-.hero-result strong {
- font-family: var(--font-display);
- font-size: 18px;
- letter-spacing: 0.02em;
- text-transform: uppercase;
+.ranking-callout strong { color: var(--ink); }
+
+/* ---------- gap-chart hero ---------- */
+
+.hero-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
+ gap: 40px;
+ align-items: center;
+ padding-top: 6px;
+ padding-bottom: 40px;
}
-.hero-result:hover strong,
-.hero-result:hover i {
- color: var(--blue);
+@media (max-width: 860px) {
+ .hero-grid {
+ grid-template-columns: 1fr;
+ gap: 26px;
+ align-items: stretch;
+ }
}
-.hero h1 .bar-word {
- color: var(--red);
+.hero-verdict {
+ font-family: "Newsreader", Georgia, serif;
+ font-weight: 600;
+ font-size: clamp(30px, 4.4vw, 44px);
+ line-height: 1.08;
+ letter-spacing: -0.01em;
+ text-transform: none;
+ max-width: 16ch;
+ margin-bottom: 16px;
}
-.hero-sub {
- font-size: 19px;
- color: var(--steel);
- max-width: 58ch;
- margin-bottom: 30px;
+.hero-verdict em {
+ font-style: normal;
+ color: var(--red);
}
-.hero-sub strong {
- color: var(--ink);
- font-weight: 600;
+.gapchart {
+ border: 1px solid var(--line-strong);
+ border-radius: 4px;
+ background: var(--card);
+ padding: 18px 20px 16px;
}
-.hero-actions {
+.gapchart-head {
display: flex;
- flex-wrap: wrap;
- gap: 12px;
- margin-bottom: 18px;
+ justify-content: space-between;
+ align-items: baseline;
+ gap: 10px;
+ margin-bottom: 16px;
+ font-family: var(--font-mono);
+ font-size: 10.5px;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ color: var(--faint);
+ font-weight: 500;
}
-.btn-primary,
-.btn-ghost {
- display: inline-flex;
+.gapchart-scale {
+ white-space: nowrap;
+}
+
+.gaprow {
+ display: grid;
+ grid-template-columns: minmax(90px, 128px) minmax(0, 1fr) 52px;
+ gap: 12px;
align-items: center;
- gap: 9px;
- font-family: var(--font-display);
- font-weight: 600;
- font-size: 18px;
- text-transform: uppercase;
- letter-spacing: 0.05em;
- border-radius: 4px;
- padding: 10px 22px 11px;
+ height: 30px;
}
-.btn-text {
- align-self: center;
- padding: 8px 4px;
- color: var(--steel);
- border-bottom: 1px solid var(--line-strong);
- font-family: var(--font-display);
- font-size: 17px;
+.gap-label {
+ font-size: 13px;
font-weight: 600;
- letter-spacing: 0.05em;
- line-height: 1;
- text-transform: uppercase;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
-.btn-text:hover {
- color: var(--blue);
- border-color: var(--blue);
+.gap-bar .gap-label {
+ color: var(--red);
}
-@media (max-width: 620px) {
- .hero {
- padding-top: 44px;
- }
+.gap-ceiling .gap-label {
+ color: var(--ink);
+}
- .hero-result {
- align-items: flex-start;
- flex-direction: column;
- gap: 2px;
- width: 100%;
- }
+.gap-rest .gap-label {
+ color: var(--faint);
+ font-weight: 400;
+}
- .hero-eyebrow {
- align-items: flex-start;
- flex-wrap: wrap;
+.gap-track {
+ position: relative;
+ height: 15px;
+ background: var(--paper-2);
+ border-radius: 3px;
+}
+
+.gap-fill {
+ position: absolute;
+ inset: 0 auto 0 0;
+ border-radius: 3px;
+ background: var(--blue);
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ .gap-fill {
+ animation: gap-grow 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
}
+}
- .hero-result strong {
- font-size: 17px;
+@keyframes gap-grow {
+ from {
+ transform: scaleX(0);
+ transform-origin: left;
}
}
-.btn-primary {
- color: var(--ice);
+.gap-ceiling .gap-fill {
background: var(--ink);
- transition: background 0.15s ease;
}
-.btn-primary:hover {
- background: var(--blue);
+.gap-bar .gap-fill {
+ background: var(--red);
+}
+
+.gap-rest .gap-fill {
+ background: var(--mark-grid);
+}
+
+/* the shared vertical line every model bar stops short of */
+.gap-redline {
+ position: absolute;
+ top: -8px;
+ bottom: -8px;
+ width: 2px;
+ background: var(--red);
+ transform: translateX(-1px);
+ z-index: 2;
+ pointer-events: none;
+}
+
+.gapchart-legend {
+ margin-top: 14px;
+ padding-top: 12px;
+ border-top: 1px solid var(--line);
+ font-family: var(--font-mono);
+ font-size: 10.5px;
+ line-height: 1.5;
+ color: var(--faint);
+}
+
+.gapchart-legend i {
+ display: inline-block;
+ width: 2px;
+ height: 10px;
+ background: var(--red);
+ vertical-align: -1px;
+ margin-right: 6px;
+}
+
+.gap-value {
+ font-family: var(--font-mono);
+ font-size: 12px;
+ font-variant-numeric: tabular-nums;
+ text-align: right;
+ color: var(--steel);
}
-.btn-ghost {
+.gap-ceiling .gap-value,
+.gap-bar .gap-value {
color: var(--ink);
+ font-weight: 500;
+}
+
+@media (max-width: 480px) {
+ .gaprow {
+ grid-template-columns: minmax(78px, 100px) minmax(0, 1fr) 44px;
+ gap: 8px;
+ }
+}
+
+/* ---------- theme toggle ---------- */
+
+.theme-toggle {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: auto;
+ min-width: 44px;
+ height: 30px;
+ padding-inline: 8px;
border: 1px solid var(--line-strong);
- transition: border-color 0.15s ease, background 0.15s ease;
+ border-radius: 3px;
+ color: var(--steel);
+ font-size: 10px;
+ font-weight: 600;
+ transition: color 0.15s ease, border-color 0.15s ease;
}
-.btn-ghost:hover {
- border-color: var(--blue);
- background: var(--blue-soft);
+.theme-toggle:hover {
+ color: var(--ink);
+ border-color: var(--ink);
+}
+
+.hero-actions {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 16px;
+ margin-bottom: 14px;
+}
+
+.btn-primary {
+ display: inline-flex;
+ align-items: center;
+ font-family: var(--font-body);
+ font-weight: 600;
+ font-size: 14px;
+ color: var(--paper);
+ background: var(--ink);
+ border-radius: 3px;
+ padding: 9px 16px;
+ transition: background 0.15s ease;
+}
+
+.btn-primary:hover {
+ background: var(--blue);
}
.hero-facts {
font-family: var(--font-mono);
- font-size: 12px;
+ font-size: 11.5px;
color: var(--faint);
- letter-spacing: 0.02em;
+ letter-spacing: 0.01em;
}
.hero-facts b {
@@ -387,12 +560,12 @@ h2,
font-weight: 500;
}
-/* ---------- score ladder (signature) ---------- */
+/* ---------- score ladder ---------- */
.ladder-panel {
- margin: 44px 0 0;
+ margin: 0;
border-top: 3px solid var(--red);
- border-bottom: 1px solid var(--line-strong);
+ border-bottom: none;
background: var(--card);
}
@@ -402,22 +575,27 @@ h2,
justify-content: space-between;
align-items: baseline;
gap: 8px;
- padding: 16px 22px 0;
+ padding: 14px 18px 0;
}
.ladder-head h2 {
- font-size: 24px;
+ font-family: var(--font-body);
+ font-weight: 600;
+ font-size: 15px;
+ letter-spacing: -0.01em;
+ text-transform: none;
+ line-height: 1.2;
}
.ladder-head span {
font-family: var(--font-mono);
- font-size: 11.5px;
+ font-size: 11px;
color: var(--faint);
}
.ladder-wrap {
position: relative;
- padding: 4px 10px 8px;
+ padding: 2px 8px 6px;
}
.ladder-svg {
@@ -444,10 +622,11 @@ h2,
}
}
-/* On narrow screens the scaled-down SVG can't fit every label; keep only the
- semantically load-bearing ones (bar, ceiling, floor) — the full numbers
- remain in the baselines table. */
@media (max-width: 620px) {
+ .hero {
+ padding-top: 36px;
+ }
+
.ladder-svg .lbl:not(.lbl-key) {
display: none;
}
@@ -457,12 +636,12 @@ h2,
position: absolute;
pointer-events: none;
background: var(--ink);
- color: var(--ice);
+ color: var(--paper);
font-family: var(--font-mono);
- font-size: 11.5px;
+ font-size: 11px;
line-height: 1.5;
- padding: 7px 10px;
- border-radius: 4px;
+ padding: 6px 9px;
+ border-radius: 3px;
transform: translate(-50%, calc(-100% - 10px));
white-space: nowrap;
z-index: 30;
@@ -476,7 +655,7 @@ h2,
/* ---------- sections ---------- */
.section {
- padding: 76px 0;
+ padding: 52px 0;
}
.section + .section {
@@ -484,41 +663,36 @@ h2,
}
.section-alt {
- background: var(--ice-2);
+ background: var(--paper-2);
}
.kicker {
- display: flex;
- align-items: center;
- gap: 12px;
font-family: var(--font-mono);
- font-size: 12px;
- letter-spacing: 0.14em;
+ font-size: 11px;
+ letter-spacing: 0.1em;
text-transform: uppercase;
- color: var(--steel);
- margin-bottom: 14px;
-}
-
-.kicker::before {
- content: "";
- width: 22px;
- height: 1px;
- background: var(--line-strong);
+ color: var(--faint);
+ margin-bottom: 8px;
}
.section-head {
- max-width: 720px;
- margin-bottom: 40px;
+ max-width: 640px;
+ margin-bottom: 28px;
}
.section-head h2 {
- font-size: clamp(34px, 4.6vw, 52px);
- margin-bottom: 14px;
+ font-family: var(--font-body);
+ font-weight: 600;
+ font-size: clamp(22px, 3vw, 28px);
+ letter-spacing: -0.02em;
+ line-height: 1.2;
+ text-transform: none;
+ margin-bottom: 10px;
}
.section-head p {
color: var(--steel);
- font-size: 17px;
+ font-size: 15px;
}
.section-head p code {
@@ -530,14 +704,15 @@ h2,
.panel {
background: var(--card);
border: 1px solid var(--line-strong);
- border-radius: 6px;
- padding: 22px 24px;
+ border-radius: 2px;
+ padding: 16px 18px;
}
.panel + .panel,
.panel + .lane-note,
-.lane-note + .panel {
- margin-top: 20px;
+.lane-note + .panel,
+.panel + .footnotes {
+ margin-top: 14px;
}
.panel-title {
@@ -546,15 +721,15 @@ h2,
justify-content: space-between;
flex-wrap: wrap;
gap: 6px 12px;
- margin-bottom: 16px;
+ margin-bottom: 12px;
}
.panel-title h3 {
- font-family: var(--font-display);
+ font-family: var(--font-body);
font-weight: 600;
- text-transform: uppercase;
- letter-spacing: 0.03em;
- font-size: 20px;
+ font-size: 14.5px;
+ letter-spacing: -0.01em;
+ text-transform: none;
}
.panel-title span {
@@ -573,25 +748,24 @@ h2,
.telemetry-toggle {
color: var(--blue);
- border-bottom: 1px solid var(--blue);
+ border-bottom: 1px solid transparent;
font-family: var(--font-mono);
font-size: 11px;
line-height: 1.5;
}
.telemetry-toggle:hover {
- color: var(--ink);
- border-color: var(--ink);
+ border-color: var(--blue);
}
.panel > p {
- font-size: 15.5px;
+ font-size: 14.5px;
color: var(--steel);
max-width: 70ch;
}
.panel > p + p {
- margin-top: 10px;
+ margin-top: 8px;
}
.panel > p code {
@@ -610,19 +784,19 @@ h2,
table {
width: 100%;
border-collapse: collapse;
- font-size: 14px;
+ font-size: 13.5px;
}
thead th {
font-family: var(--font-mono);
font-size: 10px;
font-weight: 500;
- letter-spacing: 0.09em;
+ letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--faint);
text-align: left;
- padding: 8px 12px;
- border-bottom: 1px solid var(--ink);
+ padding: 6px 10px;
+ border-bottom: 2px solid var(--ink);
white-space: nowrap;
}
@@ -633,11 +807,19 @@ tbody td.num {
}
tbody td {
- padding: 10px 12px;
+ padding: 8px 10px;
border-bottom: 1px solid var(--line);
white-space: nowrap;
}
+tbody tr {
+ transition: background 0.12s ease;
+}
+
+tbody tr:hover {
+ background: rgba(26, 95, 143, 0.04);
+}
+
tbody tr:last-child td {
border-bottom: none;
}
@@ -665,24 +847,24 @@ tbody tr.tier-start td {
.agent-cell {
display: flex;
align-items: center;
- gap: 10px;
+ gap: 8px;
font-weight: 600;
}
.agent-chip {
- width: 10px;
- height: 10px;
- border-radius: 2px;
+ width: 8px;
+ height: 8px;
+ border-radius: 1px;
flex-shrink: 0;
}
.tag {
font-family: var(--font-mono);
font-size: 9.5px;
- letter-spacing: 0.07em;
+ letter-spacing: 0.05em;
text-transform: uppercase;
- border-radius: 3px;
- padding: 2px 7px;
+ border-radius: 2px;
+ padding: 1px 6px;
font-weight: 500;
}
@@ -702,7 +884,7 @@ tbody tr.tier-start td {
}
.tag-official {
- color: var(--ice);
+ color: var(--paper);
background: var(--blue);
}
@@ -714,15 +896,15 @@ tbody tr.tier-start td {
.tier-chip {
display: inline-block;
- font-family: var(--font-display);
- font-weight: 600;
+ font-family: var(--font-score);
+ font-weight: 700;
font-size: 14px;
- letter-spacing: 0.06em;
+ letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--ink);
border: 1px solid var(--ink);
- border-radius: 3px;
- padding: 1px 9px 2px;
+ border-radius: 2px;
+ padding: 0 7px 1px;
}
.status-stack {
@@ -733,9 +915,10 @@ tbody tr.tier-start td {
}
.score-strong {
- font-family: var(--font-display);
+ font-family: var(--font-score);
font-weight: 700;
- font-size: 17px;
+ font-size: 18px;
+ letter-spacing: 0.01em;
}
.mono-dim {
@@ -746,9 +929,9 @@ tbody tr.tier-start td {
.bar-track {
position: relative;
- height: 8px;
- background: var(--ice-2);
- min-width: 90px;
+ height: 6px;
+ background: var(--paper-2);
+ min-width: 80px;
}
.bar-fill {
@@ -759,19 +942,19 @@ tbody tr.tier-start td {
.legend {
display: flex;
flex-wrap: wrap;
- gap: 6px 18px;
- margin-top: 14px;
+ gap: 4px 16px;
+ margin-top: 12px;
font-family: var(--font-mono);
- font-size: 11.5px;
+ font-size: 11px;
color: var(--steel);
}
.legend i {
display: inline-block;
- width: 10px;
- height: 10px;
- border-radius: 2px;
- margin-right: 7px;
+ width: 8px;
+ height: 8px;
+ border-radius: 1px;
+ margin-right: 6px;
vertical-align: -1px;
}
@@ -781,11 +964,11 @@ tbody tr.tier-start td {
position: relative;
background: var(--card);
border: 1px solid var(--line-strong);
- border-radius: 6px;
- padding: 26px 28px;
+ border-radius: 2px;
+ padding: 18px 20px;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
- gap: 24px;
+ gap: 18px;
align-items: start;
}
@@ -796,46 +979,45 @@ tbody tr.tier-start td {
}
.gate h3 {
- font-family: var(--font-display);
- font-weight: 700;
- text-transform: uppercase;
- font-size: 27px;
- margin-bottom: 10px;
+ font-family: var(--font-body);
+ font-weight: 600;
+ font-size: 16px;
+ letter-spacing: -0.01em;
+ text-transform: none;
+ margin-bottom: 8px;
}
.gate p {
- font-size: 15.5px;
+ font-size: 14.5px;
color: var(--steel);
max-width: 62ch;
}
.gate p + p {
- margin-top: 10px;
+ margin-top: 8px;
}
.stamp {
- font-family: var(--font-display);
- font-weight: 700;
- font-size: 20px;
- letter-spacing: 0.12em;
+ font-family: var(--font-mono);
+ font-weight: 600;
+ font-size: 11px;
+ letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--steel);
- border: 2px solid var(--steel);
- border-radius: 4px;
- padding: 8px 18px;
- transform: rotate(3deg);
+ border: 1px solid var(--steel);
+ border-radius: 2px;
+ padding: 6px 12px;
white-space: nowrap;
align-self: center;
- opacity: 0.85;
}
.gate-checks {
- margin-top: 18px;
+ margin-top: 14px;
display: flex;
flex-wrap: wrap;
- gap: 8px 22px;
+ gap: 6px 18px;
font-family: var(--font-mono);
- font-size: 12px;
+ font-size: 11.5px;
color: var(--steel);
}
@@ -849,103 +1031,123 @@ tbody tr.tier-start td {
color: var(--faint);
}
-/* ---------- integrity facts ---------- */
+/* ---------- integrity footnotes ---------- */
-.fact-grid {
+.footnotes {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0;
border: 1px solid var(--line-strong);
- border-radius: 6px;
+ border-radius: 2px;
background: var(--card);
overflow: hidden;
}
@media (max-width: 900px) {
- .fact-grid {
+ .footnotes {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 540px) {
- .fact-grid {
+ .footnotes {
grid-template-columns: 1fr;
}
}
-.fact {
- padding: 22px 24px;
+.footnote {
+ padding: 14px 16px;
border-right: 1px solid var(--line);
border-bottom: 1px solid var(--line);
}
-.fact h4 {
- font-family: var(--font-display);
- font-weight: 600;
+.footnote h4 {
+ font-family: var(--font-mono);
+ font-weight: 500;
+ font-size: 10.5px;
+ letter-spacing: 0.08em;
text-transform: uppercase;
- letter-spacing: 0.04em;
- font-size: 18px;
- margin-bottom: 6px;
+ color: var(--faint);
+ margin-bottom: 5px;
}
-.fact p {
- font-size: 14px;
+.footnote p {
+ font-size: 13px;
color: var(--steel);
+ line-height: 1.45;
}
-.fact code {
- font-size: 12px;
+.footnote code {
+ font-size: 11.5px;
color: var(--blue);
}
-/* ---------- decision loop ---------- */
+/* ---------- protocol (phases + IO) ---------- */
-.loop-grid {
+.phase-wire {
display: grid;
grid-template-columns: repeat(3, 1fr);
- gap: 20px;
+ gap: 0;
+ border: 1px solid var(--line-strong);
+ border-radius: 2px;
+ background: var(--card);
+ overflow: hidden;
+ margin-bottom: 18px;
}
@media (max-width: 900px) {
- .loop-grid {
+ .phase-wire {
grid-template-columns: 1fr;
}
}
-.loop-card {
- background: var(--card);
- border: 1px solid var(--line-strong);
- border-radius: 6px;
- padding: 24px;
+.phase-row {
+ padding: 18px 20px;
+ border-right: 1px solid var(--line);
+}
+
+.phase-row:last-child {
+ border-right: none;
+}
+
+@media (max-width: 900px) {
+ .phase-row {
+ border-right: none;
+ border-bottom: 1px solid var(--line);
+ }
+
+ .phase-row:last-child {
+ border-bottom: none;
+ }
}
-.loop-num {
+.phase-num {
font-family: var(--font-mono);
font-size: 11px;
- letter-spacing: 0.1em;
+ letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--blue);
- margin-bottom: 12px;
+ margin-bottom: 8px;
}
-.loop-card h3 {
- font-family: var(--font-display);
+.phase-row h3 {
+ font-family: var(--font-body);
font-weight: 600;
- text-transform: uppercase;
- font-size: 22px;
- margin-bottom: 8px;
+ font-size: 15px;
+ letter-spacing: -0.01em;
+ text-transform: none;
+ margin-bottom: 6px;
}
-.loop-card p {
- font-size: 14.5px;
+.phase-row p {
+ font-size: 13.5px;
color: var(--steel);
}
.protocol-grid {
display: grid;
grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
- gap: 20px;
- margin-top: 20px;
+ gap: 18px;
align-items: start;
}
@@ -956,9 +1158,9 @@ tbody tr.tier-start td {
}
.proto-point {
- display: flex;
- gap: 14px;
- padding: 16px 4px;
+ display: grid;
+ gap: 2px;
+ padding: 12px 0;
border-bottom: 1px solid var(--line);
}
@@ -966,33 +1168,16 @@ tbody tr.tier-start td {
border-bottom: none;
}
-.proto-icon {
- flex-shrink: 0;
- width: 36px;
- height: 36px;
- display: grid;
- place-items: center;
- border-radius: 4px;
- border: 1px solid var(--line-strong);
- color: var(--blue);
- background: var(--card);
-}
-
-.proto-icon svg {
- width: 18px;
- height: 18px;
-}
-
.proto-point h4 {
- font-family: var(--font-display);
+ font-family: var(--font-body);
font-weight: 600;
- text-transform: uppercase;
- font-size: 17px;
- margin-bottom: 3px;
+ font-size: 14px;
+ letter-spacing: -0.01em;
+ text-transform: none;
}
.proto-point p {
- font-size: 14px;
+ font-size: 13.5px;
color: var(--steel);
}
@@ -1000,9 +1185,9 @@ tbody tr.tier-start td {
.code-card {
border: 1px solid var(--line-strong);
- border-radius: 6px;
- background: var(--ink);
- color: #dce8f2;
+ border-radius: 2px;
+ background: var(--code-bg);
+ color: var(--code-fg);
overflow: hidden;
}
@@ -1010,20 +1195,20 @@ tbody tr.tier-start td {
display: flex;
align-items: center;
justify-content: space-between;
- padding: 9px 16px;
- border-bottom: 1px solid rgba(220, 232, 242, 0.15);
+ padding: 8px 14px;
+ border-bottom: 1px solid var(--code-line);
font-family: var(--font-mono);
font-size: 11px;
- color: #8fa8bd;
+ color: var(--code-dim);
}
.code-card pre {
margin: 0;
- padding: 16px 18px;
+ padding: 14px 16px;
overflow-x: auto;
font-family: var(--font-mono);
- font-size: 12.5px;
- line-height: 1.7;
+ font-size: 12px;
+ line-height: 1.65;
}
.code-card code {
@@ -1034,9 +1219,9 @@ tbody tr.tier-start td {
font-family: var(--font-mono);
font-size: 11px;
color: #8fa8bd;
- border: 1px solid rgba(220, 232, 242, 0.25);
- border-radius: 4px;
- padding: 2px 10px;
+ border: 1px solid rgba(220, 232, 242, 0.22);
+ border-radius: 2px;
+ padding: 2px 9px;
transition: color 0.15s ease, border-color 0.15s ease;
}
@@ -1045,54 +1230,35 @@ tbody tr.tier-start td {
border-color: #fff;
}
-/* ---------- adapters ---------- */
-
-.adapter-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 16px;
-}
-
-@media (max-width: 900px) {
- .adapter-grid {
- grid-template-columns: repeat(2, 1fr);
- }
-}
-
-@media (max-width: 600px) {
- .adapter-grid {
- grid-template-columns: 1fr;
- }
-}
+/* ---------- adapters (inline in Run) ---------- */
-.adapter-card {
- background: var(--card);
- border: 1px solid var(--line-strong);
- border-radius: 6px;
- padding: 20px 22px;
+.adapter-line {
+ margin-top: 18px;
+ padding-top: 16px;
+ border-top: 1px solid var(--line);
+ font-size: 13.5px;
+ color: var(--steel);
}
-.adapter-card h4 {
- font-family: var(--font-display);
+.adapter-line strong {
+ color: var(--ink);
font-weight: 600;
- text-transform: uppercase;
- font-size: 18px;
- margin-bottom: 5px;
}
-.adapter-card p {
- font-size: 13.5px;
- color: var(--steel);
- margin-bottom: 10px;
+.adapter-chips {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ margin-top: 10px;
}
-.adapter-card code {
+.adapter-chips code {
font-size: 11.5px;
color: var(--blue);
border: 1px solid var(--line-strong);
- border-radius: 4px;
- padding: 2px 8px;
- display: inline-block;
+ border-radius: 2px;
+ padding: 3px 8px;
+ background: var(--card);
}
/* ---------- transaction feed ---------- */
@@ -1100,17 +1266,17 @@ tbody tr.tier-start td {
.txn-list {
display: flex;
flex-direction: column;
- max-height: 360px;
+ max-height: 320px;
overflow-y: auto;
}
.txn-row {
display: flex;
align-items: baseline;
- gap: 14px;
- padding: 10px 4px;
+ gap: 12px;
+ padding: 8px 2px;
border-bottom: 1px solid var(--line);
- font-size: 13.5px;
+ font-size: 13px;
}
.txn-row:last-child {
@@ -1120,12 +1286,12 @@ tbody tr.tier-start td {
.txn-phase {
font-family: var(--font-mono);
font-size: 10px;
- letter-spacing: 0.07em;
+ letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--blue);
border: 1px solid var(--line-strong);
- border-radius: 3px;
- padding: 1px 7px;
+ border-radius: 2px;
+ padding: 1px 6px;
white-space: nowrap;
}
@@ -1151,168 +1317,1736 @@ tbody tr.tier-start td {
/* ---------- grids ---------- */
-.results-grid {
+.quickstart-grid {
display: grid;
- grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
- gap: 20px;
+ grid-template-columns: 1fr 1fr;
+ gap: 14px;
}
@media (max-width: 900px) {
- .results-grid {
+ .quickstart-grid {
grid-template-columns: 1fr;
}
}
-.charts-grid {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 20px;
- margin-top: 20px;
+.lane-note {
+ font-size: 14px;
+ color: var(--steel);
+ max-width: 76ch;
+ padding: 2px 0;
}
-@media (max-width: 900px) {
- .charts-grid {
- grid-template-columns: 1fr;
- }
-}
+/* ---------- footer ---------- */
-.chart-svg {
- width: 100%;
- height: auto;
- display: block;
+.footer {
+ border-top: 2px solid var(--ink);
+ padding: 28px 0 40px;
+ color: var(--steel);
+ font-size: 13px;
}
-.chart-holder {
- position: relative;
+.footer-inner {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ gap: 14px;
+ align-items: center;
}
-.quickstart-grid {
+.footer-brand {
display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 20px;
+ gap: 4px;
}
-@media (max-width: 900px) {
- .quickstart-grid {
- grid-template-columns: 1fr;
+.footer-brand > div {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.footer .byline {
+ width: fit-content;
+ margin-left: 30px;
+ color: var(--ink);
+}
+
+.footer a {
+ color: var(--steel);
+ border-bottom: 1px solid var(--line-strong);
+}
+
+.footer a:hover {
+ color: var(--ink);
+ border-color: var(--ink);
+}
+
+.footer-links {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 18px;
+}
+
+.footer .mono {
+ font-family: var(--font-mono);
+ font-size: 11px;
+ color: var(--faint);
+}
+
+@media (prefers-reduced-motion: reduce) {
+ html {
+ scroll-behavior: auto;
+ }
+ *,
+ *::before,
+ *::after {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
}
}
-/* ---------- verdict ---------- */
+/* ================================================================
+ Results-first redesign
+ The published JSON record owns every value in charts and tables.
+ Red is reserved for the scripted reference line.
+ ================================================================ */
-.verdict-big {
- font-family: var(--font-display);
- font-size: 46px;
- font-weight: 700;
- line-height: 1;
- color: var(--blue);
+:root {
+ --amber: #b56f12;
+ --candidate: #287a7d;
+ --candidate-dark: #1d555c;
+ --candidate-soft: rgba(40, 122, 125, 0.11);
+ --selection: #6657b8;
+ --selection-soft: rgba(102, 87, 184, 0.12);
+ --chart-blue: var(--candidate);
+ --chart-blue-dark: var(--candidate-dark);
+ --chart-blue-soft: var(--candidate-soft);
+ --panel-reference: #586670;
+ --adverse-1: #faf3e6;
+ --adverse-2: #f0dcab;
+ --adverse-3: #e0b465;
+ --adverse-4: #bd8620;
+ --adverse-5: #81520b;
+ --adverse-text-1: #38280f;
+ --adverse-text-2: #38280f;
+ --adverse-text-3: #2c1d08;
+ --adverse-text-4: #211504;
+ --adverse-text-5: #fffaf0;
+ --surface-warm: #f5f8f8;
+}
+
+:root[data-theme="dark"] {
+ --amber: #e2a543;
+ --candidate: #62bdba;
+ --candidate-dark: #8dd5d1;
+ --candidate-soft: rgba(98, 189, 186, 0.14);
+ --selection: #a99cf2;
+ --selection-soft: rgba(169, 156, 242, 0.15);
+ --panel-reference: #9aabb7;
+ --adverse-1: #2d281f;
+ --adverse-2: #56431f;
+ --adverse-3: #866020;
+ --adverse-4: #b9852b;
+ --adverse-5: #dda94b;
+ --adverse-text-1: #fff2d8;
+ --adverse-text-2: #fff2d8;
+ --adverse-text-3: #fff8eb;
+ --adverse-text-4: #181106;
+ --adverse-text-5: #181106;
+ --surface-warm: #0f1820;
+}
+
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
+
+.nav .shell {
+ max-width: 1480px;
+}
+
+.nav-inner {
+ height: 56px;
+}
+
+.nav-links a {
+ position: relative;
+ padding-block: 18px;
+}
+
+.nav-links a.is-active::after {
+ content: "";
+ position: absolute;
+ inset: auto 0 0;
+ height: 2px;
+ background: var(--red);
+}
+
+.results-shell {
+ width: min(100%, 1480px);
+ margin: 0 auto;
+ padding-inline: 22px;
+}
+
+.results-section {
+ scroll-margin-top: 56px;
+ padding: 14px 0 42px;
+ background: var(--paper);
+ border-bottom: 1px solid var(--line-strong);
+}
+
+.result-summary {
+ min-height: 66px;
+ display: grid;
+ grid-template-columns: minmax(330px, 1fr) auto auto;
+ align-items: center;
+ gap: 28px;
+ padding: 12px 16px;
+ background: var(--card);
+ border: 1px solid var(--line-strong);
+ border-radius: 5px;
}
-.verdict-big small {
+.result-summary > p {
font-size: 17px;
font-weight: 600;
- color: var(--steel);
- margin-left: 6px;
- text-transform: uppercase;
- letter-spacing: 0.04em;
+ letter-spacing: -0.015em;
+}
+
+.result-summary > p strong {
+ color: var(--red);
+ font-size: 21px;
+ margin-right: 1px;
}
-.verdict-row {
+.result-summary dl {
display: flex;
- justify-content: space-between;
- gap: 12px;
- font-size: 14px;
- padding: 9px 0;
- border-bottom: 1px solid var(--line);
+ align-items: center;
+ gap: 24px;
}
-.verdict-row:last-child {
- border-bottom: none;
+.result-summary dl div {
+ display: grid;
+ grid-template-columns: auto auto;
+ gap: 6px;
+ align-items: baseline;
+}
+
+.result-summary dt {
+ color: var(--faint);
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.055em;
}
-.verdict-row span {
+.result-summary dd {
+ font-family: var(--font-mono);
color: var(--steel);
+ font-size: 12px;
}
-.verdict-row strong {
- font-variant-numeric: tabular-nums;
- font-weight: 600;
+.result-summary > a {
+ color: var(--steel);
+ font-size: 12px;
+ text-decoration: underline;
+ text-underline-offset: 3px;
+ white-space: nowrap;
+}
+
+.result-summary > a:hover {
+ color: var(--ink);
}
-/* ---------- lane note ---------- */
+.result-toolbar {
+ position: relative;
+ display: grid;
+ grid-template-columns: auto auto minmax(190px, 1fr) auto;
+ gap: 14px;
+ align-items: center;
+ padding: 18px 0 14px;
+}
-.lane-note {
- font-size: 15px;
+.segmented {
+ display: inline-flex;
+ align-items: stretch;
+ border: 1px solid var(--line-strong);
+ border-radius: 4px;
+ overflow: hidden;
+ background: var(--card);
+ width: max-content;
+}
+
+.segmented button {
+ min-height: 38px;
+ padding: 8px 16px;
+ border-right: 1px solid var(--line-strong);
color: var(--steel);
- max-width: 76ch;
- padding: 4px 2px;
+ font-size: 13px;
+ font-weight: 500;
+ white-space: nowrap;
}
-/* ---------- footer ---------- */
+.segmented button:last-child {
+ border-right: 0;
+}
-.footer {
- border-top: 3px solid var(--ink);
- padding: 40px 0 56px;
+.segmented button:hover:not(:disabled) {
+ color: var(--ink);
+ background: var(--paper);
+}
+
+.segmented button.is-active {
+ color: var(--card);
+ background: var(--ink);
+}
+
+.segmented button:disabled {
+ color: var(--faint);
+ opacity: 0.55;
+ cursor: not-allowed;
+}
+
+.model-filter {
+ justify-self: end;
+ width: min(100%, 330px);
+}
+
+.model-filter input {
+ width: 100%;
+ height: 40px;
+ padding: 8px 13px;
+ color: var(--ink);
+ background: var(--card);
+ border: 1px solid var(--line-strong);
+ border-radius: 4px;
+ font: inherit;
+ font-size: 13px;
+}
+
+.model-filter input::placeholder {
+ color: var(--faint);
+}
+
+.model-filter input:focus {
+ outline: 2px solid var(--blue);
+ outline-offset: 1px;
+}
+
+.model-picker {
+ position: relative;
+}
+
+.picker-button {
+ min-width: 150px;
+ height: 40px;
+ padding: 8px 12px;
+ text-align: left;
color: var(--steel);
- font-size: 13.5px;
+ background: var(--card);
+ border: 1px solid var(--line-strong);
+ border-radius: 4px;
+ font-size: 13px;
}
-.footer-inner {
+.picker-menu {
+ position: absolute;
+ z-index: 20;
+ top: calc(100% + 6px);
+ right: 0;
+ width: 260px;
+ padding: 10px;
+ background: var(--card);
+ border: 1px solid var(--line-strong);
+ border-radius: 4px;
+ box-shadow: 0 10px 30px rgba(10, 22, 32, 0.14);
+}
+
+.picker-menu-actions {
display: flex;
- flex-wrap: wrap;
justify-content: space-between;
- gap: 18px;
- align-items: center;
+ padding: 2px 4px 8px;
+ margin-bottom: 4px;
+ border-bottom: 1px solid var(--line);
}
-.footer-brand {
- display: grid;
- gap: 5px;
+.picker-menu-actions button {
+ color: var(--blue);
+ font-size: 11px;
+ font-weight: 600;
}
-.footer-brand > div {
+.picker-menu label {
display: flex;
align-items: center;
- gap: 10px;
+ gap: 8px;
+ padding: 6px 4px;
+ color: var(--steel);
+ font-size: 12px;
+ cursor: pointer;
}
-.footer .byline {
- width: fit-content;
- margin-left: 32px;
- color: var(--ink);
+.picker-menu input {
+ accent-color: var(--blue);
}
-.footer a {
- color: var(--steel);
- border-bottom: 1px solid var(--line-strong);
+.chart-panel {
+ background: var(--card);
+ border: 1px solid var(--line-strong);
+ border-radius: 5px;
+ overflow: hidden;
}
-.footer a:hover {
- color: var(--ink);
- border-color: var(--ink);
+.chart-panel-head {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 20px;
+ padding: 16px 18px 12px;
+ border-bottom: 1px solid var(--line);
}
-.footer-links {
- display: flex;
- flex-wrap: wrap;
- gap: 22px;
+.chart-panel-head h1 {
+ font-size: 18px;
+ line-height: 1.25;
+ font-weight: 600;
+ letter-spacing: -0.015em;
}
-.footer .mono {
- font-family: var(--font-mono);
- font-size: 11.5px;
+.chart-panel-head p {
+ margin-top: 3px;
color: var(--faint);
+ font-size: 12px;
}
-@media (prefers-reduced-motion: reduce) {
- html {
- scroll-behavior: auto;
- }
- *,
- *::before,
- *::after {
- animation-duration: 0.01ms !important;
- animation-iteration-count: 1 !important;
- transition-duration: 0.01ms !important;
+.chart-panel-head > span {
+ color: var(--faint);
+ font-family: var(--font-mono);
+ font-size: 11px;
+ white-space: nowrap;
+}
+
+.chart-scroll {
+ width: 100%;
+ overflow-x: auto;
+}
+
+.result-chart {
+ display: block;
+ width: 100%;
+ min-width: 980px;
+ height: auto;
+ background: var(--card);
+}
+
+.chart-grid {
+ stroke: var(--line);
+ stroke-width: 1;
+ stroke-dasharray: 3 4;
+}
+
+.chart-row-rule {
+ stroke: var(--line);
+ stroke-width: 1;
+}
+
+.chart-reference {
+ stroke: var(--red);
+ stroke-width: 2.25;
+}
+
+.chart-oracle {
+ stroke: var(--ink);
+ stroke-width: 1.5;
+ stroke-dasharray: 5 5;
+}
+
+.chart-tick,
+.chart-axis-label,
+.chart-axis-note,
+.chart-column-head,
+.chart-value,
+.chart-ci,
+.chart-model-label,
+.chart-tier-dot,
+.chart-tier-label,
+.scatter-label,
+.ranking-model {
+ fill: var(--steel);
+}
+
+.chart-tick {
+ font-family: var(--font-mono);
+ font-size: 11px;
+}
+
+.chart-tick-bar,
+.chart-reference-label {
+ fill: var(--red);
+}
+
+.chart-reference-label,
+.chart-oracle-label {
+ font-family: var(--font-mono);
+ font-size: 10.5px;
+ font-weight: 600;
+}
+
+.chart-oracle-label {
+ fill: var(--ink);
+}
+
+.chart-axis-label,
+.chart-axis-note {
+ font-size: 11px;
+}
+
+.chart-axis-note {
+ font-style: italic;
+}
+
+.chart-column-head {
+ font-size: 11px;
+ font-weight: 600;
+}
+
+.chart-model-label,
+.ranking-model {
+ fill: var(--ink);
+ font-size: 12px;
+ font-weight: 500;
+}
+
+.chart-tier-label,
+.chart-tier-dot {
+ fill: var(--chart-blue);
+ font-family: var(--font-mono);
+ font-size: 10px;
+ font-weight: 600;
+ letter-spacing: 0.05em;
+}
+
+.chart-value {
+ fill: var(--ink);
+ font-family: var(--font-mono);
+ font-size: 11px;
+ font-variant-numeric: tabular-nums;
+}
+
+.chart-ci {
+ font-family: var(--font-mono);
+ font-size: 9.5px;
+ font-variant-numeric: tabular-nums;
+}
+
+.interval-line,
+.interval-cap {
+ stroke: var(--chart-blue);
+ stroke-width: 1.7;
+}
+
+.candidate-dot {
+ fill: var(--chart-blue-dark);
+ stroke: var(--card);
+ stroke-width: 1.5;
+}
+
+.forest-row:focus,
+.scatter-point:focus,
+.ranking-row:focus {
+ outline: none;
+}
+
+.forest-row:focus .candidate-dot,
+.scatter-point:focus .candidate-dot,
+.ranking-row:focus .candidate-dot {
+ stroke: var(--blue);
+ stroke-width: 4;
+}
+
+.scatter-label {
+ fill: var(--ink);
+ font-size: 10.5px;
+ font-weight: 500;
+}
+
+.empty-results {
+ display: grid;
+ place-items: center;
+ min-height: 360px;
+ gap: 12px;
+ color: var(--faint);
+}
+
+.empty-results button {
+ color: var(--blue);
+ text-decoration: underline;
+}
+
+.results-table-wrap {
+ position: relative;
+ margin-top: 14px;
+ overflow: auto;
+ background: var(--card);
+ border: 1px solid var(--line-strong);
+ border-radius: 5px;
+}
+
+.results-table-wrap:focus-visible {
+ outline: 2px solid var(--blue);
+ outline-offset: 2px;
+}
+
+.results-table {
+ width: 100%;
+ min-width: 1050px;
+ border-collapse: collapse;
+ font-size: 12px;
+}
+
+.results-table th {
+ padding: 10px 12px;
+ color: var(--steel);
+ background: var(--surface-warm);
+ border-bottom: 1px solid var(--line-strong);
+ font-size: 10.5px;
+ font-weight: 600;
+ text-align: left;
+ text-transform: none;
+ letter-spacing: 0.015em;
+ white-space: nowrap;
+}
+
+.results-table th button {
+ color: inherit;
+ font-size: inherit;
+ font-weight: inherit;
+}
+
+.results-table th button[aria-pressed="true"] {
+ color: var(--ink);
+}
+
+.results-table td {
+ position: relative;
+ padding: 10px 12px;
+ border-bottom: 1px solid var(--line);
+ color: var(--steel);
+ vertical-align: top;
+}
+
+.results-table tbody tr:last-child td {
+ border-bottom: 0;
+}
+
+.results-table tbody tr:hover td {
+ background: var(--chart-blue-soft);
+}
+
+.results-table .model-name {
+ color: var(--ink);
+ font-weight: 500;
+ white-space: nowrap;
+}
+
+.results-table .numeric {
+ font-family: var(--font-mono);
+ font-variant-numeric: tabular-nums;
+ white-space: nowrap;
+}
+
+.results-table .strong {
+ color: var(--ink);
+ font-weight: 600;
+}
+
+.results-table .ci-cell {
+ color: var(--faint);
+}
+
+.tier-label {
+ color: var(--chart-blue);
+ font-size: 10px;
+ font-weight: 600;
+ white-space: nowrap;
+}
+
+.observations {
+ position: relative;
+ min-width: 126px;
+}
+
+.observations summary {
+ color: var(--ink);
+ cursor: pointer;
+ white-space: nowrap;
+}
+
+.observations summary::marker {
+ color: var(--faint);
+}
+
+.observation-popover {
+ position: absolute;
+ z-index: 15;
+ top: calc(100% + 7px);
+ right: 0;
+ width: min(420px, 72vw);
+ padding: 12px;
+ background: var(--card);
+ border: 1px solid var(--line-strong);
+ border-radius: 4px;
+ box-shadow: 0 10px 30px rgba(10, 22, 32, 0.15);
+}
+
+.observation-labels {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 5px;
+ padding-bottom: 8px;
+}
+
+.observation-labels span {
+ padding: 2px 6px;
+ color: var(--steel);
+ background: var(--paper);
+ border: 1px solid var(--line);
+ border-radius: 3px;
+ font-size: 10px;
+}
+
+.observation-popover ul {
+ display: grid;
+ gap: 5px;
+ padding-left: 16px;
+ color: var(--steel);
+ font-size: 11px;
+ line-height: 1.35;
+}
+
+.result-caveat {
+ margin-top: 12px;
+ padding-left: 11px;
+ color: var(--faint);
+ border-left: 2px solid var(--line-strong);
+ font-size: 11px;
+ line-height: 1.5;
+}
+
+/* ---------- analysis ---------- */
+
+.analysis-section {
+ scroll-margin-top: 56px;
+ padding: 52px 0;
+ background: var(--card);
+ border-bottom: 1px solid var(--line-strong);
+}
+
+.analysis-heading {
+ display: grid;
+ grid-template-columns: 1fr minmax(260px, 520px);
+ align-items: end;
+ gap: 36px;
+ margin-bottom: 22px;
+}
+
+.analysis-heading .kicker {
+ margin-bottom: 5px;
+}
+
+.analysis-heading h2 {
+ font-family: var(--font-body);
+ font-size: clamp(26px, 3vw, 38px);
+ line-height: 1.05;
+ letter-spacing: -0.035em;
+ text-transform: none;
+}
+
+.analysis-heading > p {
+ color: var(--steel);
+ font-size: 13px;
+ line-height: 1.5;
+}
+
+.analysis-evidence {
+ display: grid;
+ grid-template-columns: minmax(0, 1.2fr) minmax(380px, 0.8fr);
+ border: 1px solid var(--line-strong);
+ border-radius: 5px;
+ overflow: hidden;
+}
+
+.analysis-ranking-panel {
+ min-width: 0;
+ padding: 16px 16px 8px;
+ border-right: 1px solid var(--line-strong);
+}
+
+.analysis-panel-title {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ gap: 12px;
+ margin-bottom: 4px;
+}
+
+.analysis-panel-title h3,
+.model-inspector h3,
+.heatmap-title h3 {
+ font-size: 17px;
+ line-height: 1.25;
+ letter-spacing: -0.015em;
+}
+
+.analysis-panel-title span {
+ color: var(--faint);
+ font-size: 11px;
+}
+
+.analysis-ranking {
+ display: block;
+ width: 100%;
+ min-width: 650px;
+ height: auto;
+}
+
+.ranking-row rect {
+ fill: transparent;
+ cursor: pointer;
+}
+
+.ranking-row:hover rect,
+.ranking-row.is-selected rect {
+ fill: var(--chart-blue-soft);
+}
+
+.rank-line {
+ stroke: var(--chart-blue);
+ stroke-width: 1.5;
+}
+
+.model-inspector {
+ min-width: 0;
+ padding: 20px;
+}
+
+.model-inspector > p {
+ color: var(--faint);
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+}
+
+.model-inspector > h3 {
+ margin: 2px 0 14px;
+ font-size: 24px;
+}
+
+.model-inspector dl {
+ border-block: 1px solid var(--line);
+ padding-block: 8px;
+}
+
+.model-inspector dl div {
+ display: flex;
+ justify-content: space-between;
+ gap: 20px;
+ padding: 5px 0;
+}
+
+.model-inspector dt {
+ color: var(--steel);
+ font-size: 12px;
+}
+
+.model-inspector dd {
+ color: var(--ink);
+ font-family: var(--font-mono);
+ font-size: 12px;
+ font-weight: 500;
+}
+
+.model-inspector h4 {
+ margin: 14px 0 8px;
+ font-size: 12px;
+ font-weight: 600;
+}
+
+.mechanic-legend {
+ display: flex;
+ justify-content: flex-end;
+ gap: 12px;
+ margin-bottom: 8px;
+ color: var(--faint);
+ font-size: 9.5px;
+}
+
+.mechanic-legend span {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.mechanic-legend i {
+ width: 8px;
+ height: 8px;
+}
+
+.accepted-key,
+.accepted-segment {
+ background: var(--chart-blue);
+}
+
+.rejected-key,
+.rejected-segment {
+ background: var(--amber);
+}
+
+.mechanic-bar-row {
+ display: grid;
+ grid-template-columns: 108px minmax(80px, 1fr) 92px;
+ gap: 8px;
+ align-items: center;
+ min-height: 28px;
+ font-size: 10.5px;
+}
+
+.mechanic-bar-row > span:first-child {
+ color: var(--steel);
+}
+
+.mechanic-track {
+ height: 14px;
+ background: var(--paper-2);
+}
+
+.mechanic-total {
+ display: flex;
+ height: 100%;
+}
+
+.mechanic-total i {
+ display: block;
+ height: 100%;
+}
+
+.mechanic-count {
+ color: var(--faint);
+ font-family: var(--font-mono);
+ font-size: 9.5px;
+ text-align: right;
+ white-space: nowrap;
+}
+
+.heatmap-section {
+ margin-top: 18px;
+ padding: 18px;
+ border: 1px solid var(--line-strong);
+ border-radius: 5px;
+}
+
+.heatmap-title {
+ display: flex;
+ justify-content: space-between;
+ align-items: end;
+ gap: 24px;
+ margin-bottom: 14px;
+}
+
+.heatmap-title p {
+ margin-top: 3px;
+ color: var(--faint);
+ font-size: 11px;
+}
+
+.heatmap-wrap {
+ overflow-x: auto;
+}
+
+.heatmap-grid {
+ display: grid;
+ grid-template-columns: minmax(180px, 1.25fr) repeat(5, minmax(112px, 1fr));
+ min-width: 830px;
+}
+
+.heatmap-head span {
+ padding: 8px 10px;
+ color: var(--steel);
+ font-size: 11px;
+ font-weight: 600;
+ text-align: center;
+}
+
+.heatmap-row > button {
+ min-height: 42px;
+ padding: 7px 10px;
+ border: 1px solid var(--card);
+ color: var(--ink);
+ font-family: var(--font-mono);
+ font-size: 11px;
+ font-variant-numeric: tabular-nums;
+}
+
+.heatmap-row > button:first-child {
+ color: var(--ink);
+ background: var(--surface-warm) !important;
+ font-family: var(--font-body);
+ font-weight: 500;
+ text-align: left;
+}
+
+.heatmap-row > button:not(:first-child) {
+ color: #07131c;
+ font-weight: 600;
+}
+
+.heatmap-row > button:hover,
+.heatmap-row > button:focus-visible {
+ outline: 2px solid var(--ink);
+ outline-offset: -2px;
+}
+
+.heatmap-legend {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ gap: 7px;
+ margin-top: 10px;
+ color: var(--faint);
+ font-family: var(--font-mono);
+ font-size: 9px;
+}
+
+.heatmap-legend i {
+ width: 18px;
+ height: 8px;
+ background: var(--chart-blue);
+ opacity: 0.72;
+}
+
+.section {
+ scroll-margin-top: 56px;
+}
+
+.section .shell,
+.footer .shell {
+ max-width: 1180px;
+}
+
+@media (max-width: 1080px) {
+ .result-summary {
+ grid-template-columns: 1fr auto;
+ }
+
+ .result-summary dl {
+ grid-column: 1 / -1;
+ grid-row: 2;
+ justify-content: flex-start;
+ }
+
+ .result-summary > a {
+ grid-column: 2;
+ grid-row: 1;
+ }
+
+ .result-toolbar {
+ grid-template-columns: auto 1fr auto;
+ }
+
+ .lane-switch {
+ display: none;
+ }
+
+ .analysis-evidence {
+ grid-template-columns: 1fr;
+ }
+
+ .analysis-ranking-panel {
+ border-right: 0;
+ border-bottom: 1px solid var(--line-strong);
+ }
+}
+
+@media (max-width: 760px) {
+ .nav-links {
+ gap: 14px;
+ }
+
+ .nav-links a {
+ display: none;
+ }
+
+ .nav-links a[href="#results"],
+ .nav-links a[href="#analysis"] {
+ display: block;
+ padding-block: 18px;
+ }
+
+ .results-shell {
+ padding-inline: 14px;
+ }
+
+ .results-section {
+ padding-top: 10px;
+ }
+
+ .result-summary {
+ display: block;
+ padding: 12px;
+ }
+
+ .result-summary > p {
+ font-size: 15px;
+ }
+
+ .result-summary dl {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 5px 14px;
+ margin-top: 10px;
+ }
+
+ .result-summary > a {
+ display: inline-block;
+ margin-top: 9px;
+ }
+
+ .result-toolbar {
+ grid-template-columns: 1fr auto;
+ gap: 10px;
+ }
+
+ .segmented button {
+ padding-inline: 12px;
+ }
+
+ .model-filter {
+ grid-column: 1 / -1;
+ grid-row: 2;
+ justify-self: stretch;
+ width: 100%;
+ }
+
+ .model-picker {
+ grid-column: 2;
+ grid-row: 1;
+ }
+
+ .chart-panel-head {
+ display: block;
+ }
+
+ .chart-panel-head > span {
+ display: block;
+ margin-top: 7px;
+ }
+
+ .analysis-section {
+ padding-block: 38px;
+ }
+
+ .analysis-heading {
+ grid-template-columns: 1fr;
+ gap: 10px;
+ }
+
+ .analysis-evidence {
+ display: block;
+ }
+
+ .model-inspector {
+ padding: 16px;
+ }
+
+ .heatmap-title {
+ display: block;
+ }
+
+ .heatmap-title .segmented {
+ margin-top: 12px;
+ }
+}
+
+@media (max-width: 480px) {
+ .nav-links {
+ gap: 10px;
+ font-size: 12.5px;
+ }
+
+ .result-toolbar {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .model-filter {
+ order: 3;
+ flex-basis: 100%;
+ }
+
+ .picker-button {
+ min-width: 130px;
+ }
+
+ .picker-menu {
+ right: -2px;
+ width: min(260px, 88vw);
+ }
+
+ .analysis-heading h2 {
+ font-size: 28px;
+ }
+
+ .mechanic-bar-row {
+ grid-template-columns: 96px minmax(68px, 1fr);
+ }
+
+ .mechanic-count {
+ grid-column: 2;
+ margin-top: -6px;
+ }
+}
+
+/* ================================================================
+ Results storytelling and interaction polish
+ ================================================================ */
+
+.result-overview {
+ display: grid;
+ grid-template-columns: minmax(320px, 0.9fr) minmax(560px, 1.1fr);
+ gap: 42px;
+ align-items: end;
+ padding: 28px 4px 22px;
+}
+
+.result-overview-copy h1 {
+ max-width: 720px;
+ margin-top: 4px;
+ font-family: var(--font-body);
+ font-size: clamp(27px, 3vw, 40px);
+ line-height: 1.04;
+ letter-spacing: -0.04em;
+ text-transform: none;
+}
+
+.result-overview-copy > p:not(.kicker) {
+ margin-top: 8px;
+ color: var(--steel);
+ font-size: 14px;
+}
+
+.result-overview-copy small {
+ display: block;
+ max-width: 680px;
+ margin-top: 7px;
+ color: var(--faint);
+ font-size: 11px;
+ line-height: 1.45;
+}
+
+.result-readouts {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ border: 1px solid var(--line-strong);
+ border-radius: 6px;
+ overflow: hidden;
+ background: var(--card);
+ box-shadow: 0 8px 24px rgba(18, 35, 45, 0.04);
+}
+
+.result-readouts > div {
+ min-width: 0;
+ padding: 15px 16px 14px;
+ border-right: 1px solid var(--line);
+}
+
+.result-readouts > div:last-child {
+ border-right: 0;
+}
+
+.result-readouts dt {
+ color: var(--faint);
+ font-size: 10px;
+ font-weight: 600;
+ letter-spacing: 0.045em;
+ text-transform: uppercase;
+}
+
+.result-readouts dd {
+ margin-top: 4px;
+ color: var(--ink);
+ font-family: var(--font-mono);
+ font-size: clamp(22px, 2.3vw, 31px);
+ font-weight: 600;
+ line-height: 1;
+ letter-spacing: -0.04em;
+}
+
+.result-readouts span {
+ display: block;
+ margin-top: 7px;
+ overflow: hidden;
+ color: var(--steel);
+ font-size: 11px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.result-metadata {
+ display: grid;
+ grid-template-columns: 1fr auto;
+ align-items: center;
+ gap: 22px;
+ min-height: 42px;
+ padding: 8px 12px;
+ color: var(--faint);
+ background: var(--surface-warm);
+ border-block: 1px solid var(--line);
+}
+
+.result-metadata dl {
+ display: flex;
+ gap: 22px;
+}
+
+.result-metadata dl > div {
+ display: flex;
+ gap: 6px;
+ align-items: baseline;
+}
+
+.result-metadata dt {
+ font-size: 9.5px;
+ letter-spacing: 0.05em;
+ text-transform: uppercase;
+}
+
+.result-metadata dd {
+ font-family: var(--font-mono);
+ font-size: 10.5px;
+}
+
+.result-metadata a {
+ color: var(--steel);
+ font-size: 11px;
+ font-weight: 600;
+ text-decoration: underline;
+ text-underline-offset: 3px;
+}
+
+.result-toolbar {
+ grid-template-columns: auto 1fr auto;
+}
+
+.toolbar-context {
+ color: var(--faint);
+ font-family: var(--font-mono);
+ font-size: 10.5px;
+}
+
+.chart-story-label {
+ display: block;
+ margin-bottom: 4px;
+ color: var(--candidate);
+ font-size: 9.5px;
+ font-weight: 700;
+ letter-spacing: 0.075em;
+ text-transform: uppercase;
+}
+
+.chart-panel-head h2 {
+ font-size: 20px;
+ line-height: 1.2;
+ font-weight: 650;
+ letter-spacing: -0.022em;
+}
+
+.chart-stage {
+ animation: chart-stage-in 280ms ease-out both;
+}
+
+.chart-panel-reference {
+ stroke: var(--panel-reference);
+ stroke-width: 1.6;
+ stroke-dasharray: 4 4;
+}
+
+.chart-panel-reference-label {
+ fill: var(--panel-reference);
+ font-family: var(--font-mono);
+ font-size: 10.5px;
+ font-weight: 600;
+}
+
+.chart-row-hit {
+ fill: transparent;
+ transition: fill 150ms ease;
+}
+
+.forest-row,
+.scatter-point,
+.ranking-row {
+ cursor: pointer;
+}
+
+.forest-row:hover .chart-row-hit,
+.forest-row:focus-visible .chart-row-hit {
+ fill: var(--candidate-soft);
+}
+
+.forest-row.is-selected .chart-row-hit {
+ fill: var(--selection-soft);
+}
+
+.forest-row.is-selected .interval-line,
+.forest-row.is-selected .interval-cap,
+.ranking-row.is-selected .rank-line {
+ stroke: var(--selection);
+ stroke-width: 2.2;
+}
+
+.forest-row.is-selected .candidate-dot,
+.scatter-point.is-selected .candidate-dot,
+.ranking-row.is-selected .candidate-dot {
+ fill: var(--selection);
+ stroke: var(--card);
+ stroke-width: 2;
+}
+
+.scatter-point .scatter-label {
+ transition:
+ fill 150ms ease,
+ font-weight 150ms ease;
+}
+
+.scatter-leader {
+ stroke: var(--line-strong);
+ stroke-width: 1;
+ stroke-dasharray: 2 3;
+}
+
+.scatter-point.is-selected .scatter-leader {
+ stroke: var(--selection);
+}
+
+.scatter-point.is-selected .scatter-label {
+ fill: var(--selection);
+ font-weight: 700;
+}
+
+.chart-mark-line,
+.rank-line {
+ transform-box: fill-box;
+ transform-origin: center;
+ animation: chart-line-in 420ms cubic-bezier(0.22, 1, 0.36, 1) both;
+ animation-delay: calc(var(--row-index, 0) * 36ms);
+}
+
+.chart-mark-cap,
+.chart-mark-dot {
+ animation: chart-dot-in 320ms ease-out both;
+ animation-delay: calc(80ms + var(--row-index, 0) * 36ms);
+}
+
+.chart-selection {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 7px 14px;
+ min-height: 43px;
+ padding: 9px 16px;
+ color: var(--steel);
+ background: color-mix(in srgb, var(--selection-soft) 58%, var(--card));
+ border-top: 1px solid var(--line);
+ font-family: var(--font-mono);
+ font-size: 10.5px;
+}
+
+.chart-selection strong {
+ color: var(--ink);
+ font-family: var(--font-body);
+ font-size: 12px;
+}
+
+.selection-status {
+ padding: 2px 6px;
+ color: var(--selection);
+ border: 1px solid color-mix(in srgb, var(--selection) 45%, transparent);
+ border-radius: 999px;
+ font-family: var(--font-body);
+ font-size: 9px;
+ font-weight: 700;
+ letter-spacing: 0.05em;
+ text-transform: uppercase;
+}
+
+.chart-selection a {
+ margin-left: auto;
+ color: var(--selection);
+ font-family: var(--font-body);
+ font-weight: 650;
+}
+
+.results-table .model-name button {
+ color: inherit;
+ font: inherit;
+ text-align: left;
+}
+
+.results-table .model-name button:hover,
+.results-table .model-name button:focus-visible {
+ color: var(--selection);
+ text-decoration: underline;
+ text-underline-offset: 3px;
+}
+
+.results-table tbody tr.is-selected td {
+ background: var(--selection-soft);
+}
+
+.analysis-heading .kicker,
+.heatmap-title .chart-story-label {
+ color: var(--candidate);
+}
+
+.ranking-row rect,
+.rank-line,
+.candidate-dot,
+.mechanic-total,
+.mechanic-total i {
+ transition:
+ fill 160ms ease,
+ stroke 160ms ease,
+ width 260ms ease,
+ background-color 220ms ease;
+}
+
+.ranking-row.is-selected rect {
+ fill: var(--selection-soft);
+}
+
+.model-inspector dd em {
+ margin-left: 4px;
+ color: var(--amber);
+ font-family: var(--font-body);
+ font-size: 9px;
+ font-style: normal;
+ font-weight: 700;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+}
+
+.accepted-key,
+.accepted-segment {
+ background: var(--candidate);
+}
+
+.heatmap-insight {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: baseline;
+ gap: 7px 12px;
+ margin: -2px 0 13px;
+ padding: 9px 11px;
+ color: var(--steel);
+ background: var(--surface-warm);
+ border-left: 3px solid var(--amber);
+ font-size: 11px;
+}
+
+.heatmap-insight strong {
+ color: var(--ink);
+}
+
+.heatmap-row > button:not(:first-child) {
+ transition:
+ background-color 220ms ease,
+ color 220ms ease,
+ box-shadow 150ms ease;
+}
+
+.heatmap-row.is-selected > button:first-child {
+ color: var(--selection);
+ box-shadow: inset 3px 0 0 var(--selection);
+}
+
+.heatmap-row.is-selected > button:not(:first-child) {
+ box-shadow:
+ inset 0 2px 0 color-mix(in srgb, var(--selection) 62%, transparent),
+ inset 0 -2px 0 color-mix(in srgb, var(--selection) 62%, transparent);
+}
+
+.heatmap-row > button.adverse-1,
+.heatmap-ramp .adverse-1 {
+ color: var(--adverse-text-1);
+ background: var(--adverse-1);
+}
+
+.heatmap-row > button.adverse-2,
+.heatmap-ramp .adverse-2 {
+ color: var(--adverse-text-2);
+ background: var(--adverse-2);
+}
+
+.heatmap-row > button.adverse-3,
+.heatmap-ramp .adverse-3 {
+ color: var(--adverse-text-3);
+ background: var(--adverse-3);
+}
+
+.heatmap-row > button.adverse-4,
+.heatmap-ramp .adverse-4 {
+ color: var(--adverse-text-4);
+ background: var(--adverse-4);
+}
+
+.heatmap-row > button.adverse-5,
+.heatmap-ramp .adverse-5 {
+ color: var(--adverse-text-5);
+ background: var(--adverse-5);
+}
+
+.heatmap-legend {
+ gap: 9px;
+ font-family: var(--font-body);
+ font-size: 9.5px;
+}
+
+.heatmap-ramp {
+ display: inline-grid;
+ grid-template-columns: repeat(5, 18px);
+ gap: 2px;
+}
+
+.heatmap-ramp i {
+ display: block;
+ width: 18px;
+ height: 9px;
+ opacity: 1;
+}
+
+@keyframes chart-stage-in {
+ from {
+ opacity: 0;
+ transform: translateY(5px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes chart-line-in {
+ from {
+ opacity: 0;
+ transform: scaleX(0);
+ }
+ to {
+ opacity: 1;
+ transform: scaleX(1);
+ }
+}
+
+@keyframes chart-dot-in {
+ from {
+ opacity: 0;
+ transform: scale(0.72);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1);
+ }
+}
+
+@media (max-width: 1080px) {
+ .result-overview {
+ grid-template-columns: 1fr;
+ gap: 20px;
+ }
+
+ .result-metadata {
+ grid-template-columns: 1fr auto;
+ }
+
+ .result-metadata p {
+ display: none;
+ }
+}
+
+@media (max-width: 760px) {
+ .result-overview {
+ padding-top: 20px;
+ }
+
+ .result-readouts {
+ grid-template-columns: 1fr;
+ }
+
+ .result-readouts > div {
+ display: grid;
+ grid-template-columns: 1fr auto;
+ align-items: baseline;
+ gap: 2px 14px;
+ padding: 11px 13px;
+ border-right: 0;
+ border-bottom: 1px solid var(--line);
+ }
+
+ .result-readouts > div:last-child {
+ border-bottom: 0;
+ }
+
+ .result-readouts dd {
+ grid-row: 1 / 3;
+ grid-column: 2;
+ font-size: 23px;
+ }
+
+ .result-readouts span {
+ margin-top: 1px;
+ }
+
+ .result-metadata {
+ display: block;
+ padding: 9px 12px;
+ }
+
+ .result-metadata dl {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 5px 14px;
+ }
+
+ .result-metadata a {
+ display: inline-block;
+ margin-top: 8px;
+ }
+
+ .result-toolbar {
+ grid-template-columns: 1fr auto;
+ }
+
+ .toolbar-context {
+ display: none;
+ }
+
+ .chart-selection a {
+ flex-basis: 100%;
+ margin-left: 0;
+ }
+}
+
+@media (max-width: 480px) {
+ .result-overview-copy h1 {
+ font-size: 29px;
+ }
+
+ .result-overview-copy > p:not(.kicker) {
+ font-size: 13px;
}
}
diff --git a/web/src/lib.ts b/web/src/lib.ts
index cfa273f..017043d 100644
--- a/web/src/lib.ts
+++ b/web/src/lib.ts
@@ -5,18 +5,21 @@
// never rides on color alone — every mark sits next to its label.
export const COLOR = {
red: "#C8102E",
- blue: "#155B9A",
+ blue: "#1A5F8F",
steel: "#7E93A6",
- ink: "#0C1D2E",
+ ink: "#0A1620",
faint: "#8AA0B2",
- grid: "#D9E4EB",
+ grid: "#C5D3DE",
} as const;
+// Returns CSS variables (not raw hex) so panel bars and chips recolor with the
+// active theme. COLOR above stays the canonical reference for the SVG-free spots
+// and documents what each variable resolves to in the light register.
export function agentColor(agent: string): string {
- if (agent === "pick-trader") return COLOR.red;
- if (agent === "oracle") return COLOR.ink;
- if (agent === "value" || agent === "candidate") return COLOR.blue;
- return COLOR.steel;
+ if (agent === "pick-trader") return "var(--red)";
+ if (agent === "oracle") return "var(--mark-axis)";
+ if (agent === "value" || agent === "candidate") return "var(--blue)";
+ return "var(--mark-ref)";
}
export function fmt(value: number, digits = 1): string {
diff --git a/web/src/theme.ts b/web/src/theme.ts
new file mode 100644
index 0000000..45cc7b0
--- /dev/null
+++ b/web/src/theme.ts
@@ -0,0 +1,30 @@
+import { useEffect, useState } from "react";
+
+export type Theme = "light" | "dark";
+
+const STORAGE_KEY = "gm-bench-theme";
+
+function initialTheme(): Theme {
+ if (typeof window === "undefined") return "light";
+ const stored = window.localStorage.getItem(STORAGE_KEY);
+ if (stored === "light" || stored === "dark") return stored;
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
+}
+
+/* Single source of truth for the palette: the hook only sets data-theme on
+ ; every color lives in CSS variables that key off that attribute, so
+ the tables and the SVG ladder recolor from the same cascade. */
+export function useTheme(): [Theme, () => void] {
+ const [theme, setTheme] = useState(initialTheme);
+
+ useEffect(() => {
+ const root = document.documentElement;
+ root.setAttribute("data-theme", theme);
+ window.localStorage.setItem(STORAGE_KEY, theme);
+ const meta = document.querySelector('meta[name="theme-color"]');
+ meta?.setAttribute("content", theme === "dark" ? "#0d141b" : "#eef2f5");
+ }, [theme]);
+
+ const toggle = () => setTheme((current) => (current === "dark" ? "light" : "dark"));
+ return [theme, toggle];
+}