TrangBui commited on
Commit
8f03abe
·
verified ·
1 Parent(s): 6efe2fe

Publish RoleRouteBench trajectory explorer

Browse files

Add the static trajectory viewer, JEV reference results, public/private isolation design, and router-submission links. The Space runs entirely in the browser and executes no model.

Files changed (7) hide show
  1. README.md +11 -5
  2. app.js +89 -0
  3. benchmark.json +0 -0
  4. index.html +154 -17
  5. robots.txt +4 -0
  6. sitemap.xml +9 -0
  7. styles.css +123 -0
README.md CHANGED
@@ -1,12 +1,18 @@
1
  ---
2
  title: RoleRouteBench Explorer
3
- emoji: 🐨
4
- colorFrom: pink
5
- colorTo: pink
6
  sdk: static
 
7
  pinned: false
8
  license: apache-2.0
9
- short_description: Explore live multi-agent routing trajectories and results.
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
1
  ---
2
  title: RoleRouteBench Explorer
3
+ emoji: 🧭
4
+ colorFrom: blue
5
+ colorTo: indigo
6
  sdk: static
7
+ app_file: index.html
8
  pinned: false
9
  license: apache-2.0
10
+ datasets:
11
+ - TrangBui/RoleRouteBench
12
  ---
13
 
14
+ # RoleRouteBench Explorer
15
+
16
+ Static trajectory explorer and reference-results dashboard for
17
+ [RoleRouteBench](https://huggingface.co/datasets/TrangBui/RoleRouteBench).
18
+ It runs entirely in the browser and does not execute a router or model.
app.js ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const state = { data: null, packet: null };
2
+ const byId = (id) => document.getElementById(id);
3
+ const esc = (value) => String(value ?? "").replace(/[&<>'"]/g, (char) => ({"&":"&amp;","<":"&lt;",">":"&gt;","'":"&#39;",'"':"&quot;"}[char]));
4
+ const percent = (part, total) => total ? `${Math.round(part * 100 / total)}%` : "—";
5
+
6
+ async function loadData() {
7
+ const response = await fetch("benchmark.json");
8
+ if (!response.ok) throw new Error(`data request failed (${response.status})`);
9
+ return response.json();
10
+ }
11
+
12
+ function renderResults(runs) {
13
+ byId("results-body").innerHTML = runs.map((run) => `
14
+ <tr>
15
+ <td><strong>${esc(run.domain_label)}</strong></td>
16
+ <td>${run.packet_count}</td>
17
+ <td>${run.trajectory_passed}/${run.packet_count} <span class="badge">${percent(run.trajectory_passed, run.packet_count)}</span></td>
18
+ <td>${run.independent_end_task_passed}/${run.packet_count} <span class="badge">${percent(run.independent_end_task_passed, run.packet_count)}</span></td>
19
+ <td>${run.primary_routing_decisions}</td>
20
+ <td>${run.suppressed_by_budget}</td>
21
+ </tr>`).join("");
22
+ }
23
+
24
+ function unique(values) { return [...new Set(values.filter(Boolean))].sort(); }
25
+ function fillSelect(select, values, label) {
26
+ select.innerHTML = `<option value="">${label}</option>` + values.map((value) => `<option value="${esc(value)}">${esc(value)}</option>`).join("");
27
+ }
28
+
29
+ function availablePackets() {
30
+ const domain = byId("domain-filter").value;
31
+ return state.data.packets.filter((packet) => !domain || packet.domain === domain);
32
+ }
33
+
34
+ function updatePacketOptions(keepSelection = true) {
35
+ const select = byId("packet-filter");
36
+ const previous = keepSelection ? select.value : "";
37
+ const packets = availablePackets();
38
+ select.innerHTML = packets.map((packet) => `<option value="${esc(packet.packet_id)}">${esc(packet.packet_id)}</option>`).join("");
39
+ if (packets.some((packet) => packet.packet_id === previous)) select.value = previous;
40
+ renderPacket();
41
+ }
42
+
43
+ function renderPacket() {
44
+ const id = byId("packet-filter").value;
45
+ state.packet = state.data.packets.find((packet) => packet.packet_id === id) || availablePackets()[0];
46
+ if (!state.packet) return;
47
+ byId("packet-filter").value = state.packet.packet_id;
48
+ const p = state.packet;
49
+ byId("packet-summary").innerHTML = `
50
+ <div class="packet-summary-head">
51
+ <div><h3>${esc(p.packet_id)}</h3><div class="badges"><span class="badge">${esc(p.domain_label)}</span><span class="badge">${esc(p.executor_model)}</span><span class="badge">${p.primary_routing_decisions} primary decisions</span></div></div>
52
+ <div class="badges"><span class="status ${p.trajectory_passed ? "success" : "failed"}">trajectory ${p.trajectory_passed ? "pass" : "fail"}</span><span class="status ${p.independent_end_task_passed ? "success" : "failed"}">trusted ${p.independent_end_task_passed ? "pass" : "fail"}</span></div>
53
+ </div><p>${esc(p.task)}</p>`;
54
+ renderSteps();
55
+ }
56
+
57
+ function renderSteps() {
58
+ const role = byId("role-filter").value;
59
+ const status = byId("status-filter").value;
60
+ const rows = state.packet.steps.filter((step) => (!role || step.role === role) && (!status || step.event_status === status));
61
+ byId("trajectory").innerHTML = rows.length ? rows.map((step) => `
62
+ <article class="trajectory-step">
63
+ <div class="step-number">#${String(step.index).padStart(2,"0")}</div>
64
+ <div class="step-role"><strong>${esc(step.role)}</strong><small>budget before: ${esc(step.budget_before)} · confidence: ${step.confidence == null ? "—" : Number(step.confidence).toFixed(2)}</small><span class="event-pill">${esc(step.event_status)} · ${esc(step.semantic_delta)}</span></div>
65
+ <div class="state-change"><small>state before → after</small><code>${esc(step.state_before || "not executed")}</code><code>→ ${esc(step.state_after || "not executed")}</code></div>
66
+ <div class="choice-list">top choices<br>${step.top_choices.map((choice) => `${esc(choice.role)} ${(choice.probability * 100).toFixed(0)}%`).join(" · ") || "not recorded"}</div>
67
+ </article>`).join("") : `<p class="error">No step matches the active role and status filters.</p>`;
68
+ }
69
+
70
+ async function init() {
71
+ try {
72
+ state.data = await loadData();
73
+ renderResults(state.data.runs);
74
+ const domains = state.data.runs.map((run) => run.domain);
75
+ byId("domain-filter").innerHTML += domains.map((domain) => `<option value="${esc(domain)}">${esc(state.data.runs.find((run) => run.domain === domain).domain_label)}</option>`).join("");
76
+ fillSelect(byId("role-filter"), unique(state.data.packets.flatMap((packet) => packet.steps.map((step) => step.role))), "All roles");
77
+ fillSelect(byId("status-filter"), unique(state.data.packets.flatMap((packet) => packet.steps.map((step) => step.event_status))), "All statuses");
78
+ updatePacketOptions(false);
79
+ byId("domain-filter").addEventListener("change", () => updatePacketOptions(false));
80
+ byId("packet-filter").addEventListener("change", renderPacket);
81
+ byId("role-filter").addEventListener("change", renderSteps);
82
+ byId("status-filter").addEventListener("change", renderSteps);
83
+ } catch (error) {
84
+ byId("results-body").innerHTML = `<tr><td colspan="6" class="error">Could not load explorer data: ${esc(error.message)}</td></tr>`;
85
+ byId("trajectory").innerHTML = `<p class="error">Explorer data is unavailable.</p>`;
86
+ }
87
+ }
88
+
89
+ document.addEventListener("DOMContentLoaded", init);
benchmark.json ADDED
The diff for this file is too large to render. See raw diff
 
index.html CHANGED
@@ -1,19 +1,156 @@
1
  <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
  <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta name="description" content="Explore RoleRouteBench live multi-agent routing trajectories, JEV reference results, and the public/private isolation protocol.">
7
+ <meta name="theme-color" content="#08111f">
8
+ <title>RoleRouteBench — Dynamic role routing, made inspectable</title>
9
+ <link rel="stylesheet" href="styles.css">
10
+ <script type="application/ld+json">
11
+ {
12
+ "@context": "https://schema.org",
13
+ "@type": "Dataset",
14
+ "name": "RoleRouteBench",
15
+ "alternateName": "RoutingBench V4-beta",
16
+ "description": "A reproducible multi-domain benchmark for dynamic role routing in multi-agent systems, with 82 live trajectories across four domains.",
17
+ "identifier": "https://doi.org/10.57967/hf/11430",
18
+ "url": "https://huggingface.co/datasets/TrangBui/RoleRouteBench",
19
+ "version": "4.0.0-beta.2",
20
+ "creator": {"@type": "Person", "name": "Trang Bui"},
21
+ "license": "https://huggingface.co/datasets/TrangBui/RoleRouteBench/blob/main/LICENSE_DATA",
22
+ "sameAs": [
23
+ "https://doi.org/10.57967/hf/11430",
24
+ "https://huggingface.co/datasets/TrangBui/RoleRouteBench",
25
+ "https://github.com/BuiThiThanhTrang/RACO_MAS"
26
+ ],
27
+ "keywords": ["multi-agent systems", "dynamic routing", "agent orchestration", "tool use", "benchmark", "live trajectories"]
28
+ }
29
+ </script>
30
+ </head>
31
+ <body>
32
+ <a class="skip-link" href="#main">Skip to content</a>
33
+ <header class="site-header">
34
+ <a class="brand" href="#top" aria-label="RoleRouteBench home">
35
+ <span class="brand-mark">RR</span>
36
+ <span>RoleRouteBench</span>
37
+ </a>
38
+ <nav aria-label="Primary navigation">
39
+ <a href="#results">Results</a>
40
+ <a href="#explorer">Explorer</a>
41
+ <a href="#isolation">Isolation</a>
42
+ <a href="#submit">Submit</a>
43
+ </nav>
44
+ <a class="header-link" href="https://huggingface.co/datasets/TrangBui/RoleRouteBench">Dataset ↗</a>
45
+ </header>
46
+
47
+ <main id="main">
48
+ <section class="hero" id="top">
49
+ <div class="hero-copy">
50
+ <p class="eyebrow">Frozen environment · live consequences · multi-step tasks</p>
51
+ <h1>Dynamic role routing,<br><span>made inspectable.</span></h1>
52
+ <p class="hero-lede">RoleRouteBench evaluates whether a decision model can coordinate specialized executors across evolving task states—not merely whether the final answer happens to be correct.</p>
53
+ <div class="hero-actions">
54
+ <a class="button primary" href="#explorer">Explore trajectories</a>
55
+ <a class="button secondary" href="https://doi.org/10.57967/hf/11430">DOI 10.57967/hf/11430 ↗</a>
56
+ </div>
57
+ </div>
58
+ <div class="route-card" aria-label="Illustrative routing trajectory">
59
+ <div class="route-card-head"><span>packet / live state</span><span class="live-dot">LIVE</span></div>
60
+ <div class="route-step"><span class="step-index">01</span><div><strong>Inspect evidence</strong><small>state changed</small></div><span class="status success">success</span></div>
61
+ <div class="route-line"></div>
62
+ <div class="route-step"><span class="step-index">02</span><div><strong>Author candidate</strong><small>artifact created</small></div><span class="status success">success</span></div>
63
+ <div class="route-line warning"></div>
64
+ <div class="route-step"><span class="step-index">03</span><div><strong>Execute candidate</strong><small>failure preserved</small></div><span class="status failed">failed</span></div>
65
+ <div class="route-line"></div>
66
+ <div class="route-step"><span class="step-index">04</span><div><strong>Diagnose & repair</strong><small>new routed action</small></div><span class="status success">success</span></div>
67
+ </div>
68
+ </section>
69
+
70
+ <section class="stats" aria-label="Benchmark summary">
71
+ <div><strong>82</strong><span>live trajectories</span></div>
72
+ <div><strong>4</strong><span>task domains</span></div>
73
+ <div><strong>568</strong><span>primary decisions</span></div>
74
+ <div><strong>33</strong><span>specialized roles</span></div>
75
+ </section>
76
+
77
+ <section class="section why">
78
+ <div class="section-kicker">Why RoleRouteBench?</div>
79
+ <div class="why-grid">
80
+ <h2>Final task success cannot tell you whether a router coordinated well.</h2>
81
+ <div class="why-copy">
82
+ <p>Outcome quality also depends on the frozen executor. RoleRouteBench therefore retains every routing decision, failed action, state transition, budget event, and independent evaluator result.</p>
83
+ <p>Competing routers see the same public state, role pool, adapters, executors, budgets, and evaluator. The environment stays fixed; only the routing policy changes.</p>
84
+ </div>
85
+ </div>
86
+ </section>
87
+
88
+ <section class="section" id="results">
89
+ <div class="section-heading">
90
+ <div><div class="section-kicker">Reference system</div><h2>JEV 1.13 results</h2></div>
91
+ <p>Reference signals for environment validation—not an oracle and not a composite leaderboard score.</p>
92
+ </div>
93
+ <div class="table-wrap">
94
+ <table>
95
+ <thead><tr><th>Domain</th><th>Packets</th><th>Trajectory pass</th><th>Trusted task pass</th><th>Primary decisions</th><th>Budget-suppressed</th></tr></thead>
96
+ <tbody id="results-body"><tr><td colspan="6">Loading reference results…</td></tr></tbody>
97
+ </table>
98
+ </div>
99
+ </section>
100
+
101
+ <section class="section explorer-section" id="explorer">
102
+ <div class="section-heading">
103
+ <div><div class="section-kicker">Trajectory explorer</div><h2>Follow each routed consequence</h2></div>
104
+ <p>Filter public compact traces. Raw prompts and executor outputs are not included.</p>
105
+ </div>
106
+ <div class="filters" aria-label="Trajectory filters">
107
+ <label>Domain<select id="domain-filter"><option value="">All domains</option></select></label>
108
+ <label>Packet<select id="packet-filter"></select></label>
109
+ <label>Role<select id="role-filter"><option value="">All roles</option></select></label>
110
+ <label>Event status<select id="status-filter"><option value="">All statuses</option></select></label>
111
+ </div>
112
+ <div class="packet-summary" id="packet-summary" aria-live="polite"></div>
113
+ <div class="trajectory" id="trajectory" aria-live="polite"></div>
114
+ </section>
115
+
116
+ <section class="section isolation-section" id="isolation">
117
+ <div class="section-heading">
118
+ <div><div class="section-kicker">Evaluation boundary</div><h2>Public/private isolation by construction</h2></div>
119
+ <p>“Private” means evaluator-only under the benchmark protocol; the artifacts remain downloadable for transparent reproduction.</p>
120
+ </div>
121
+ <div class="isolation-grid">
122
+ <div class="boundary public-boundary">
123
+ <span class="boundary-label">ROUTER + EXECUTOR VISIBLE</span>
124
+ <h3>Public state</h3>
125
+ <ul><li>Task and public artifacts</li><li>Full role pool plus STOP</li><li>Prior observable consequences</li><li>Remaining call budget</li></ul>
126
+ </div>
127
+ <div class="boundary-flow" aria-hidden="true"><span>route</span><b>→</b><span>execute</span><b>→</b><span>observe</span></div>
128
+ <div class="boundary private-boundary">
129
+ <span class="boundary-label">EVALUATOR ONLY</span>
130
+ <h3>Reference state</h3>
131
+ <ul><li>Gold patches and proofs</li><li>Answer workbooks and oracles</li><li>Trusted evaluator results</li><li>Track A labels</li></ul>
132
+ </div>
133
+ </div>
134
+ <p class="boundary-note">The evaluator runs only after termination. It does not feed private artifacts back into the trajectory.</p>
135
+ </section>
136
+
137
+ <section class="section submit-section" id="submit">
138
+ <div>
139
+ <div class="section-kicker">Community evaluation</div>
140
+ <h2>Bring your own router.</h2>
141
+ <p>JEV is the reference system. Submit reproducible results from another decision model under the frozen environment—without sending us your model.</p>
142
+ </div>
143
+ <div class="submit-actions">
144
+ <a class="button primary" href="https://github.com/BuiThiThanhTrang/RACO_MAS/issues/new?template=router-result.yml">Submit router results ↗</a>
145
+ <a class="button secondary" href="https://github.com/BuiThiThanhTrang/RACO_MAS/blob/main/puppeteer/CONTRIBUTING_ROUTER_RESULTS.md">Read the protocol ↗</a>
146
+ </div>
147
+ </section>
148
+ </main>
149
+
150
+ <footer>
151
+ <div><strong>RoleRouteBench</strong><span>Version 4.0.0-beta.2 · DOI 10.57967/hf/11430</span></div>
152
+ <div class="footer-links"><a href="https://huggingface.co/datasets/TrangBui/RoleRouteBench">Dataset</a><a href="https://github.com/BuiThiThanhTrang/RACO_MAS">Code</a><a href="https://doi.org/10.57967/hf/11430">DOI</a></div>
153
+ </footer>
154
+ <script src="app.js" defer></script>
155
+ </body>
156
  </html>
robots.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ User-agent: *
2
+ Allow: /
3
+
4
+ Sitemap: https://buithithanhtrang.github.io/RACO_MAS/sitemap.xml
sitemap.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
+ <url>
4
+ <loc>https://buithithanhtrang.github.io/RACO_MAS/</loc>
5
+ <lastmod>2026-11-04</lastmod>
6
+ <changefreq>monthly</changefreq>
7
+ <priority>1.0</priority>
8
+ </url>
9
+ </urlset>
styles.css ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --bg: #07101d;
3
+ --panel: #0d1929;
4
+ --panel-2: #112238;
5
+ --text: #edf5ff;
6
+ --muted: #9cb0c9;
7
+ --line: #233b58;
8
+ --cyan: #53dddb;
9
+ --blue: #71a7ff;
10
+ --green: #59d391;
11
+ --red: #ff7f7f;
12
+ --amber: #f1c76d;
13
+ --max: 1180px;
14
+ }
15
+ * { box-sizing: border-box; }
16
+ html { scroll-behavior: smooth; }
17
+ body { margin: 0; color: var(--text); background: var(--bg); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; line-height: 1.55; }
18
+ a { color: inherit; }
19
+ .skip-link { position: absolute; left: -9999px; top: 1rem; z-index: 20; background: white; color: black; padding: .7rem 1rem; }
20
+ .skip-link:focus { left: 1rem; }
21
+ .site-header { position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: 2rem; padding: 1rem max(1.25rem, calc((100vw - var(--max))/2)); border-bottom: 1px solid rgba(113,167,255,.18); background: rgba(7,16,29,.9); backdrop-filter: blur(16px); }
22
+ .brand { display: flex; align-items: center; gap: .75rem; text-decoration: none; font-weight: 740; letter-spacing: -.02em; }
23
+ .brand-mark { display: grid; place-items: center; width: 2.1rem; height: 2.1rem; border-radius: .65rem; color: #07101d; background: linear-gradient(135deg,var(--cyan),var(--blue)); font-size: .72rem; letter-spacing: .04em; }
24
+ nav { display: flex; gap: 1.4rem; margin-left: auto; }
25
+ nav a, .header-link { color: var(--muted); text-decoration: none; font-size: .9rem; }
26
+ nav a:hover, .header-link:hover { color: var(--text); }
27
+ .header-link { padding-left: 1.5rem; border-left: 1px solid var(--line); }
28
+ .hero { max-width: var(--max); margin: 0 auto; padding: 7rem 1.25rem 5rem; display: grid; grid-template-columns: 1.12fr .88fr; gap: 4rem; align-items: center; }
29
+ .hero::before { content: ""; position: absolute; inset: 4rem 0 auto; height: 34rem; pointer-events: none; background: radial-gradient(circle at 22% 40%, rgba(42,125,187,.24), transparent 34%), radial-gradient(circle at 82% 18%, rgba(83,221,219,.13), transparent 30%); }
30
+ .hero-copy, .route-card { position: relative; }
31
+ .eyebrow, .section-kicker { color: var(--cyan); text-transform: uppercase; letter-spacing: .14em; font-size: .72rem; font-weight: 760; }
32
+ h1 { margin: 1rem 0 1.4rem; max-width: 13ch; font-size: clamp(3rem, 6vw, 5.8rem); line-height: .97; letter-spacing: -.065em; }
33
+ h1 span { color: transparent; background: linear-gradient(90deg,var(--cyan),var(--blue)); background-clip: text; -webkit-background-clip: text; }
34
+ .hero-lede { max-width: 63ch; color: #b7c8da; font-size: 1.1rem; }
35
+ .hero-actions, .submit-actions { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: 2rem; }
36
+ .button { display: inline-flex; justify-content: center; align-items: center; min-height: 2.8rem; padding: .72rem 1.05rem; border-radius: .65rem; text-decoration: none; font-weight: 700; font-size: .9rem; }
37
+ .button.primary { color: #06101b; background: var(--cyan); }
38
+ .button.primary:hover { background: #78ece9; }
39
+ .button.secondary { color: var(--text); border: 1px solid var(--line); background: rgba(16,31,51,.58); }
40
+ .button.secondary:hover { border-color: var(--blue); }
41
+ .route-card { padding: 1.2rem; border: 1px solid var(--line); border-radius: 1rem; background: linear-gradient(160deg,rgba(17,34,56,.98),rgba(8,20,34,.95)); box-shadow: 0 28px 80px rgba(0,0,0,.36); }
42
+ .route-card-head { display: flex; justify-content: space-between; padding-bottom: 1rem; border-bottom: 1px solid var(--line); color: var(--muted); font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: .72rem; }
43
+ .live-dot { color: var(--green); }
44
+ .route-step { display: grid; grid-template-columns: 2.2rem 1fr auto; align-items: center; gap: .85rem; padding: .9rem .3rem; }
45
+ .step-index { display: grid; place-items: center; width: 2rem; height: 2rem; border: 1px solid var(--line); border-radius: 50%; color: var(--muted); font: .72rem ui-monospace, monospace; }
46
+ .route-step div { display: flex; flex-direction: column; }
47
+ .route-step small { color: var(--muted); }
48
+ .status { border-radius: 999px; padding: .25rem .5rem; font: .67rem ui-monospace, monospace; }
49
+ .status.success { color: var(--green); background: rgba(89,211,145,.1); }
50
+ .status.failed { color: var(--red); background: rgba(255,127,127,.1); }
51
+ .route-line { width: 1px; height: .75rem; margin: -.4rem 0 -.4rem 1.28rem; background: var(--green); }
52
+ .route-line.warning { background: var(--red); }
53
+ .stats { max-width: var(--max); margin: 0 auto; padding: 0 1.25rem 5rem; display: grid; grid-template-columns: repeat(4,1fr); }
54
+ .stats div { padding: 1.4rem 1.6rem; border-block: 1px solid var(--line); border-right: 1px solid var(--line); }
55
+ .stats div:first-child { border-left: 1px solid var(--line); }
56
+ .stats strong { display: block; font-size: 2rem; letter-spacing: -.04em; }
57
+ .stats span { color: var(--muted); font-size: .84rem; }
58
+ .section { max-width: var(--max); margin: 0 auto; padding: 5.5rem 1.25rem; border-top: 1px solid var(--line); }
59
+ .why-grid { display: grid; grid-template-columns: 1.08fr .92fr; gap: 5rem; margin-top: 1rem; }
60
+ h2 { margin: .65rem 0 1rem; font-size: clamp(2rem,4vw,3.3rem); line-height: 1.08; letter-spacing: -.045em; }
61
+ .why-copy, .section-heading > p, .boundary-note { color: var(--muted); }
62
+ .section-heading { display: flex; align-items: end; justify-content: space-between; gap: 3rem; margin-bottom: 2rem; }
63
+ .section-heading > p { max-width: 48ch; }
64
+ .table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: .8rem; }
65
+ table { width: 100%; border-collapse: collapse; min-width: 760px; background: rgba(13,25,41,.72); }
66
+ th, td { padding: 1rem 1.1rem; border-bottom: 1px solid var(--line); text-align: left; }
67
+ th { color: var(--muted); font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; }
68
+ tbody tr:last-child td { border-bottom: 0; }
69
+ .filters { display: grid; grid-template-columns: 1.15fr 1.55fr 1.15fr 1fr; gap: .8rem; }
70
+ label { color: var(--muted); font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; }
71
+ select { width: 100%; margin-top: .45rem; padding: .72rem .8rem; border: 1px solid var(--line); border-radius: .55rem; color: var(--text); background: var(--panel); font: inherit; text-transform: none; letter-spacing: 0; }
72
+ .packet-summary { margin: 1.3rem 0; padding: 1.2rem; border: 1px solid var(--line); border-radius: .75rem; background: var(--panel); }
73
+ .packet-summary-head { display: flex; justify-content: space-between; gap: 1rem; }
74
+ .packet-summary h3 { margin: 0 0 .5rem; font: 700 1rem ui-monospace, monospace; }
75
+ .packet-summary p { margin: .7rem 0 0; color: var(--muted); }
76
+ .badges { display: flex; flex-wrap: wrap; gap: .4rem; }
77
+ .badge { padding: .25rem .5rem; border: 1px solid var(--line); border-radius: 999px; color: var(--muted); font-size: .7rem; }
78
+ .trajectory { display: grid; gap: .7rem; }
79
+ .trajectory-step { display: grid; grid-template-columns: 3rem minmax(11rem,1.1fr) minmax(12rem,.9fr) minmax(13rem,1.2fr); gap: 1rem; align-items: center; padding: .9rem 1rem; border: 1px solid var(--line); border-radius: .7rem; background: rgba(13,25,41,.72); }
80
+ .trajectory-step.hidden { display: none; }
81
+ .step-number { color: var(--muted); font: .75rem ui-monospace, monospace; }
82
+ .step-role strong { display: block; }
83
+ .step-role small, .state-change small { color: var(--muted); }
84
+ .state-change code { display: block; overflow: hidden; text-overflow: ellipsis; color: var(--blue); font-size: .72rem; }
85
+ .choice-list { color: var(--muted); font-size: .76rem; }
86
+ .event-pill { display: inline-block; width: fit-content; margin-top: .35rem; padding: .18rem .45rem; border-radius: 999px; background: rgba(113,167,255,.1); color: var(--blue); font-size: .68rem; }
87
+ .isolation-grid { display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem; align-items: stretch; }
88
+ .boundary { padding: 1.6rem; border: 1px solid var(--line); border-radius: .8rem; background: var(--panel); }
89
+ .public-boundary { border-top: 3px solid var(--cyan); }
90
+ .private-boundary { border-top: 3px solid var(--amber); }
91
+ .boundary h3 { margin: .65rem 0; font-size: 1.55rem; }
92
+ .boundary-label { color: var(--muted); font: .68rem ui-monospace, monospace; letter-spacing: .08em; }
93
+ .boundary ul { margin: .8rem 0 0; padding-left: 1.15rem; color: var(--muted); }
94
+ .boundary-flow { display: flex; align-items: center; gap: .45rem; color: var(--muted); font: .68rem ui-monospace, monospace; writing-mode: vertical-rl; }
95
+ .boundary-note { text-align: center; }
96
+ .submit-section { display: flex; justify-content: space-between; align-items: center; gap: 3rem; margin-bottom: 5rem; padding: 3rem; border: 1px solid var(--line); border-radius: 1rem; background: linear-gradient(120deg,rgba(19,55,75,.78),rgba(14,29,49,.85)); }
97
+ .submit-section p { max-width: 60ch; color: var(--muted); }
98
+ footer { max-width: var(--max); margin: 0 auto; padding: 2rem 1.25rem 3rem; border-top: 1px solid var(--line); display: flex; justify-content: space-between; color: var(--muted); }
99
+ footer div:first-child { display: flex; flex-direction: column; }
100
+ .footer-links { display: flex; gap: 1rem; }
101
+ .error { color: var(--red); }
102
+ @media (max-width: 900px) {
103
+ nav { display: none; }
104
+ .header-link { margin-left: auto; }
105
+ .hero, .why-grid { grid-template-columns: 1fr; }
106
+ .hero { padding-top: 4.5rem; }
107
+ .stats { grid-template-columns: repeat(2,1fr); }
108
+ .filters { grid-template-columns: 1fr 1fr; }
109
+ .trajectory-step { grid-template-columns: 2.5rem 1fr; }
110
+ .state-change, .choice-list { grid-column: 2; }
111
+ .isolation-grid { grid-template-columns: 1fr; }
112
+ .boundary-flow { writing-mode: initial; justify-content: center; padding: .5rem; }
113
+ .submit-section, .section-heading { align-items: flex-start; flex-direction: column; }
114
+ }
115
+ @media (max-width: 560px) {
116
+ .site-header { gap: .5rem; }
117
+ .header-link { display: none; }
118
+ h1 { font-size: 3.25rem; }
119
+ .stats, .filters { grid-template-columns: 1fr; }
120
+ .stats div { border-left: 1px solid var(--line); }
121
+ .packet-summary-head, footer { flex-direction: column; }
122
+ .submit-section { padding: 2rem 1.2rem; margin-inline: 1rem; }
123
+ }