ereniko commited on
Commit
1b958fd
·
verified ·
1 Parent(s): c8146b1

Upload 5 files

Browse files
Files changed (4) hide show
  1. index.html +37 -12
  2. models.json +36 -0
  3. script.js +241 -57
  4. style.css +412 -49
index.html CHANGED
@@ -26,9 +26,13 @@
26
  </p>
27
  </header>
28
 
29
- <section class="tier-strip" id="tier-strip" aria-label="Benchmark tiers">
30
  <!-- populated by script.js -->
31
- </section>
 
 
 
 
32
 
33
  <div class="controls">
34
  <div class="filter-wrap">
@@ -79,23 +83,30 @@
79
  </div>
80
  </div>
81
 
82
- <div class="table-scroll">
 
 
 
83
  <table class="leaderboard" id="leaderboard-table">
84
  <thead id="leaderboard-head">
85
- <!-- populated by script.js: rank/model/params + one column per metric for the active benchmark -->
86
  </thead>
87
  <tbody id="leaderboard-body">
88
  <!-- populated by script.js -->
89
  </tbody>
90
  </table>
91
- <div class="empty-state" id="empty-state" hidden>
92
- <svg width="34" height="34" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.5" y2="16.5"/></svg>
93
- <p>No models match your search or filters on this benchmark yet.</p>
94
- </div>
95
- <div class="unavailable-state" id="unavailable-state" hidden>
96
- <svg width="34" height="34" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M12 9v4M12 17h.01M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z"/></svg>
97
- <p id="unavailable-text">This benchmark is unavailable.</p>
98
- </div>
 
 
 
 
99
  </div>
100
 
101
  <section class="detail-panel" id="detail-panel" aria-live="polite">
@@ -108,6 +119,7 @@
108
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
109
  </button>
110
  </div>
 
111
  <div class="cat-grid" id="detail-cats"></div>
112
  </section>
113
 
@@ -151,6 +163,8 @@
151
  "name": "org/ModelName",
152
  "org": "org",
153
  "params_b": 1.5,
 
 
154
  "url": "https://huggingface.co/org/ModelName",
155
  "eval_source": "https://…",
156
  "runs": {
@@ -167,6 +181,17 @@
167
  </div>
168
  </section>
169
 
 
 
 
 
 
 
 
 
 
 
 
170
  <footer class="page-footer">
171
  <span>Data from <a href="models.json">models.json</a> · loaded client-side, no build step.</span>
172
  <span>
 
26
  </p>
27
  </header>
28
 
29
+ <nav class="bench-tabs" id="bench-tabs" aria-label="Benchmark tier">
30
  <!-- populated by script.js -->
31
+ </nav>
32
+
33
+ <div class="bench-summary" id="bench-summary">
34
+ <!-- populated by script.js: active benchmark's own description + stats -->
35
+ </div>
36
 
37
  <div class="controls">
38
  <div class="filter-wrap">
 
83
  </div>
84
  </div>
85
 
86
+ <p class="results-count" id="results-count"></p>
87
+
88
+ <!-- Desktop/tablet: real table. Populated by script.js -->
89
+ <div class="table-scroll" id="table-scroll">
90
  <table class="leaderboard" id="leaderboard-table">
91
  <thead id="leaderboard-head">
92
+ <!-- populated by script.js -->
93
  </thead>
94
  <tbody id="leaderboard-body">
95
  <!-- populated by script.js -->
96
  </tbody>
97
  </table>
98
+ </div>
99
+
100
+ <!-- Mobile: stacked model cards, same data as the table. Populated by script.js -->
101
+ <div class="model-cards" id="model-cards"></div>
102
+
103
+ <div class="empty-state" id="empty-state" hidden>
104
+ <svg width="34" height="34" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.5" y2="16.5"/></svg>
105
+ <p>No models match your search or filters on this benchmark yet.</p>
106
+ </div>
107
+ <div class="unavailable-state" id="unavailable-state" hidden>
108
+ <svg width="34" height="34" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M12 9v4M12 17h.01M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z"/></svg>
109
+ <p id="unavailable-text">This benchmark is unavailable.</p>
110
  </div>
111
 
112
  <section class="detail-panel" id="detail-panel" aria-live="polite">
 
119
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
120
  </button>
121
  </div>
122
+ <div class="detail-meta" id="detail-meta"></div>
123
  <div class="cat-grid" id="detail-cats"></div>
124
  </section>
125
 
 
163
  "name": "org/ModelName",
164
  "org": "org",
165
  "params_b": 1.5,
166
+ "license": "apache-2.0",
167
+ "architecture": "Transformer decoder, dense",
168
  "url": "https://huggingface.co/org/ModelName",
169
  "eval_source": "https://…",
170
  "runs": {
 
181
  </div>
182
  </section>
183
 
184
+ <!-- Decorative — the same 4 tiers as the tabs above, shown as cards for context. Not interactive for switching; the tabs above do that. -->
185
+ <section class="tier-showcase" aria-label="About the benchmark tiers">
186
+ <div class="tier-showcase-heading">
187
+ <h2>The benchmark suite</h2>
188
+ <p>Four tiers, increasing in difficulty. <a href="https://huggingface.co/bench-labs" target="_blank" rel="noopener">bench-labs</a> on the Hub has the full datasets.</p>
189
+ </div>
190
+ <div class="tier-strip" id="tier-strip" aria-hidden="true">
191
+ <!-- populated by script.js, decorative only -->
192
+ </div>
193
+ </section>
194
+
195
  <footer class="page-footer">
196
  <span>Data from <a href="models.json">models.json</a> · loaded client-side, no build step.</span>
197
  <span>
models.json CHANGED
@@ -54,6 +54,8 @@
54
  "name": "Qwen/Qwen2.5-0.5B",
55
  "org": "Qwen",
56
  "params_b": 0.5,
 
 
57
  "url": "https://huggingface.co/Qwen/Qwen2.5-0.5B",
58
  "eval_source": "https://huggingface.co/spaces/bench-labs/blog?post=bMid-qwen0-5.html",
59
  "runs": {
@@ -103,6 +105,8 @@
103
  "name": "Qwen/Qwen2.5-1.5B-Instruct",
104
  "org": "Qwen",
105
  "params_b": 1.5,
 
 
106
  "url": "https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct",
107
  "eval_source": "https://huggingface.co/spaces/bench-labs/blog?post=evaluatingllm.html",
108
  "runs": {
@@ -119,6 +123,38 @@
119
  "bench-mid-6-2026": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." },
120
  "bench-AGI": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." }
121
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  }
123
  ]
124
  }
 
54
  "name": "Qwen/Qwen2.5-0.5B",
55
  "org": "Qwen",
56
  "params_b": 0.5,
57
+ "license": "apache-2.0",
58
+ "architecture": "Transformer decoder, dense",
59
  "url": "https://huggingface.co/Qwen/Qwen2.5-0.5B",
60
  "eval_source": "https://huggingface.co/spaces/bench-labs/blog?post=bMid-qwen0-5.html",
61
  "runs": {
 
105
  "name": "Qwen/Qwen2.5-1.5B-Instruct",
106
  "org": "Qwen",
107
  "params_b": 1.5,
108
+ "license": "apache-2.0",
109
+ "architecture": "Transformer decoder, dense, instruction-tuned",
110
  "url": "https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct",
111
  "eval_source": "https://huggingface.co/spaces/bench-labs/blog?post=evaluatingllm.html",
112
  "runs": {
 
123
  "bench-mid-6-2026": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." },
124
  "bench-AGI": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." }
125
  }
126
+ },
127
+ {
128
+ "id": "qwen2.5-0.5b-instruct",
129
+ "name": "Qwen/Qwen2.5-0.5B-Instruct",
130
+ "org": "Qwen",
131
+ "params_b": 0.5,
132
+ "license": "apache-2.0",
133
+ "architecture": "Transformer decoder, dense, instruction-tuned",
134
+ "url": "https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct",
135
+ "eval_source": null,
136
+ "runs": {
137
+ "bench-effortless-6-2026": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." },
138
+ "bench-easy-6-2026": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." },
139
+ "bench-mid-6-2026": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." },
140
+ "bench-AGI": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." }
141
+ }
142
+ },
143
+ {
144
+ "id": "smollm2-360m",
145
+ "name": "HuggingFaceTB/SmolLM2-360M",
146
+ "org": "HuggingFaceTB",
147
+ "params_b": 0.36,
148
+ "license": "apache-2.0",
149
+ "architecture": "Transformer decoder, dense",
150
+ "url": "https://huggingface.co/HuggingFaceTB/SmolLM2-360M",
151
+ "eval_source": null,
152
+ "runs": {
153
+ "bench-effortless-6-2026": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." },
154
+ "bench-easy-6-2026": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." },
155
+ "bench-mid-6-2026": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." },
156
+ "bench-AGI": { "score": null, "n": null, "notes": "Not yet evaluated on this tier." }
157
+ }
158
  }
159
  ]
160
  }
script.js CHANGED
@@ -25,11 +25,16 @@
25
  document.addEventListener("DOMContentLoaded", init);
26
 
27
  async function init() {
28
- els.tierStrip = document.getElementById("tier-strip");
 
 
29
  els.sortSelect = document.getElementById("sort-select");
30
  els.searchInput = document.getElementById("model-search");
 
 
31
  els.thead = document.getElementById("leaderboard-head");
32
  els.tbody = document.getElementById("leaderboard-body");
 
33
  els.emptyState = document.getElementById("empty-state");
34
  els.unavailableState = document.getElementById("unavailable-state");
35
  els.unavailableText = document.getElementById("unavailable-text");
@@ -37,6 +42,7 @@
37
  els.detailPanel = document.getElementById("detail-panel");
38
  els.detailTitle = document.getElementById("detail-title");
39
  els.detailSubtitle = document.getElementById("detail-subtitle");
 
40
  els.detailCats = document.getElementById("detail-cats");
41
  els.detailClose = document.getElementById("detail-close");
42
  els.submitToggle = document.getElementById("submit-toggle");
@@ -66,18 +72,21 @@
66
  state.activeBenchmark = (firstAvailable || state.data.benchmarks[0])?.id || null;
67
 
68
  initParamsBounds();
69
- buildTierStrip();
 
70
  bindControls();
71
  bindParamsFilter();
72
  render();
73
  }
74
 
75
  function renderLoadError(err) {
76
- els.tbody.innerHTML =
77
- '<tr><td colspan="6" style="padding:32px;text-align:center;color:var(--muted);">' +
78
  "Couldn't load <code>models.json</code> (" + escapeHtml(String(err.message || err)) +
79
- "). Make sure it sits next to index.html." +
80
- "</td></tr>";
 
 
 
81
  }
82
 
83
  // -------------------- SUBMIT PANEL --------------------
@@ -91,21 +100,68 @@
91
  });
92
  }
93
 
94
- // -------------------- TIER STRIP --------------------
95
 
96
- function buildTierStrip() {
97
  const frag = document.createDocumentFragment();
98
  state.data.benchmarks
99
  .slice()
100
  .sort((a, b) => a.tier - b.tier)
101
  .forEach((bench) => {
102
- const card = document.createElement("button");
103
- card.type = "button";
104
- card.className =
105
- "tier-card" +
106
  (bench.id === state.activeBenchmark ? " active" : "") +
107
  (bench.unavailable ? " is-unavailable" : "");
108
- card.dataset.benchmarkId = bench.id;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
  const rowsLabel = bench.rows != null ? bench.rows + " rows" : "open-ended";
111
  const badge = bench.unavailable
@@ -121,13 +177,6 @@
121
  "<span>" + escapeHtml(bench.metric) + "</span>" +
122
  "</div>";
123
 
124
- card.addEventListener("click", () => {
125
- state.activeBenchmark = bench.id;
126
- closeDetail();
127
- buildTierStrip();
128
- render();
129
- });
130
-
131
  frag.appendChild(card);
132
  });
133
 
@@ -164,18 +213,10 @@
164
  const LOG_MIN = -1; // 10^-1 = 0.1B
165
  const LOG_MAX = Math.log10(PARAMS_ABSOLUTE_MAX); // 10^3 = 1000B
166
 
167
- function paramsToSlider(b) {
168
- const clamped = Math.max(0.1, Math.min(PARAMS_ABSOLUTE_MAX, b));
169
- return (Math.log10(clamped) - LOG_MIN) / (LOG_MAX - LOG_MIN);
170
- }
171
-
172
  function sliderToParams(t) {
173
  return Math.pow(10, LOG_MIN + t * (LOG_MAX - LOG_MIN));
174
  }
175
 
176
- // Derive slider bounds from the actual dataset, but always offer the full
177
- // 0.1B–1000B range so filtering isn't capped to whatever's in models.json
178
- // today.
179
  function initParamsBounds() {
180
  state.paramsFilter = { min: 0, max: PARAMS_ABSOLUTE_MAX };
181
 
@@ -210,12 +251,9 @@
210
  const onSlide = () => {
211
  let loPos = parseFloat(els.rangeMin.value);
212
  let hiPos = parseFloat(els.rangeMax.value);
213
- // keep the two thumbs from crossing
214
  if (loPos > hiPos) {
215
  [loPos, hiPos] = [hiPos, loPos];
216
  }
217
- // slider position 0 is a true "no lower bound" (0B); anything above
218
- // maps through the log curve so small models stay draggable.
219
  const lo = loPos <= 0 ? 0 : sliderToParams(loPos / 1000);
220
  const hi = hiPos >= 1000 ? PARAMS_ABSOLUTE_MAX : sliderToParams(hiPos / 1000);
221
  state.paramsFilter = { min: lo, max: hi };
@@ -247,9 +285,6 @@
247
  }
248
 
249
  function updateRangeVisuals() {
250
- // thumbs are already in slider-position units (0-1000); just read them
251
- // back for the fill bar rather than re-deriving from log space, so the
252
- // fill always matches exactly where the thumbs are.
253
  const loPct = (parseFloat(els.rangeMin.value) / 1000) * 100;
254
  const hiPct = (parseFloat(els.rangeMax.value) / 1000) * 100;
255
 
@@ -316,6 +351,13 @@
316
  return (v * 100).toFixed(1) + "%";
317
  }
318
 
 
 
 
 
 
 
 
319
  function escapeHtml(s) {
320
  return String(s)
321
  .replace(/&/g, "&amp;")
@@ -324,22 +366,29 @@
324
  .replace(/"/g, "&quot;");
325
  }
326
 
327
- // -------------------- RENDER TABLE --------------------
 
 
 
328
 
329
  function render() {
330
  const bench = getActiveBenchmark();
331
  if (!bench) return;
332
 
333
  if (bench.unavailable) {
334
- els.table.hidden = true;
 
335
  els.emptyState.hidden = true;
336
  els.unavailableState.hidden = false;
 
337
  els.unavailableText.textContent =
338
  bench.unavailable_reason || (bench.id + " is currently unavailable.");
339
  closeDetail();
340
  return;
341
  }
342
 
 
 
343
  const metricCols = getMetricColumns(bench);
344
  buildHead(metricCols);
345
 
@@ -349,6 +398,8 @@
349
  return { model: m, run, value };
350
  });
351
 
 
 
352
  if (state.search) {
353
  rows = rows.filter(
354
  (r) =>
@@ -361,30 +412,45 @@
361
  const { min, max } = state.paramsFilter;
362
  rows = rows.filter((r) => {
363
  const p = r.model.params_b;
364
- if (p == null) return false; // unknown size excluded once a filter is set
365
- if (max >= PARAMS_ABSOLUTE_MAX) return p >= min; // top thumb at the ceiling = open-ended "+"
366
  return p >= min && p <= max;
367
  });
368
  }
369
 
370
  rows = sortRows(rows, state.sort);
371
 
 
 
 
 
 
 
372
  els.tbody.innerHTML = "";
 
 
373
  if (rows.length === 0) {
374
  els.emptyState.hidden = false;
375
  els.unavailableState.hidden = true;
376
- els.table.hidden = true;
 
377
  return;
378
  }
379
  els.emptyState.hidden = true;
380
  els.unavailableState.hidden = true;
381
- els.table.hidden = false;
 
 
 
382
 
383
- const frag = document.createDocumentFragment();
 
384
  rows.forEach((r, idx) => {
385
- frag.appendChild(buildRow(r, idx + 1, bench, metricCols));
 
386
  });
387
- els.tbody.appendChild(frag);
 
388
 
389
  updateSortIndicators();
390
  }
@@ -394,7 +460,7 @@
394
 
395
  const thRank = document.createElement("th");
396
  thRank.dataset.key = "rank";
397
- thRank.style.width = "46px";
398
  thRank.textContent = "#";
399
  tr.appendChild(thRank);
400
 
@@ -420,10 +486,21 @@
420
  tr.appendChild(th);
421
  });
422
 
 
 
 
 
 
 
 
 
 
 
 
 
423
  els.thead.innerHTML = "";
424
  els.thead.appendChild(tr);
425
 
426
- // (re)bind header click-to-sort now that the head was rebuilt
427
  els.thead.querySelectorAll("th[data-key]").forEach((th) => {
428
  th.addEventListener("click", () => {
429
  const key = th.dataset.key;
@@ -434,7 +511,7 @@
434
  } else if (key === "name") {
435
  state.sort = "name-asc";
436
  } else {
437
- return; // secondary metric columns are informational, not sortable
438
  }
439
  els.sortSelect.value = state.sort;
440
  render();
@@ -490,45 +567,52 @@
490
  });
491
  }
492
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  function buildRow(r, rank, bench, metricCols) {
494
  const tr = document.createElement("tr");
495
  const { model, run, value } = r;
496
 
497
- // rank
498
  const rankTd = document.createElement("td");
499
  rankTd.className = "rank-cell" + (rank <= 3 ? " top-" + rank : "");
500
  rankTd.textContent = value == null ? "–" : String(rank);
501
  tr.appendChild(rankTd);
502
 
503
- // model
504
  const modelTd = document.createElement("td");
505
  modelTd.innerHTML =
506
  '<div class="model-cell">' +
507
  '<span class="model-name"><a href="' + escapeHtml(model.url) + '" target="_blank" rel="noopener">' +
508
  escapeHtml(model.name) + "</a></span>" +
509
  '<span class="model-org">' + escapeHtml(model.org || "") + "</span>" +
 
510
  "</div>";
511
  tr.appendChild(modelTd);
512
 
513
- // params
514
  const paramsTd = document.createElement("td");
515
  paramsTd.className = "params-cell";
516
- paramsTd.textContent = model.params_b != null ? model.params_b + "B" : "—";
517
  tr.appendChild(paramsTd);
518
 
519
- // n (sample count)
520
  const nTd = document.createElement("td");
521
  nTd.className = "n-cell";
522
  nTd.textContent = run && run.n != null ? String(run.n) : "—";
523
  tr.appendChild(nTd);
524
 
525
- // one cell per metric column
526
  metricCols.forEach((key, i) => {
527
  const td = document.createElement("td");
528
  const v = getMetricValue(run, key);
529
 
530
  if (i === 0) {
531
- // primary "score" column: bar + colored number
532
  td.className = "score-cell";
533
  if (v == null) {
534
  td.innerHTML = '<span class="score-na">not evaluated</span>';
@@ -548,22 +632,122 @@
548
  tr.appendChild(td);
549
  });
550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
551
  if (run && run.categories) {
552
  tr.style.cursor = "pointer";
553
  tr.title = "Click for per-category breakdown";
554
- tr.addEventListener("click", () => openDetail(model, run, bench));
 
 
 
555
  }
556
 
557
  return tr;
558
  }
559
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
  // -------------------- DETAIL PANEL --------------------
561
 
562
  function openDetail(model, run, bench) {
563
  els.detailTitle.textContent = model.name + " on " + bench.id;
564
- els.detailSubtitle.textContent =
565
- "Per-category breakdown" + (run.n ? " · n=" + run.n : "") +
566
- (run.stderr != null ? " · stderr " + run.stderr : "");
 
 
 
 
 
 
 
 
 
 
 
 
567
 
568
  const cats = run.categories || {};
569
  const frag = document.createDocumentFragment();
 
25
  document.addEventListener("DOMContentLoaded", init);
26
 
27
  async function init() {
28
+ els.benchTabs = document.getElementById("bench-tabs");
29
+ els.benchSummary = document.getElementById("bench-summary");
30
+ els.tierStrip = document.getElementById("tier-strip"); // decorative, bottom of page
31
  els.sortSelect = document.getElementById("sort-select");
32
  els.searchInput = document.getElementById("model-search");
33
+ els.resultsCount = document.getElementById("results-count");
34
+ els.tableScroll = document.getElementById("table-scroll");
35
  els.thead = document.getElementById("leaderboard-head");
36
  els.tbody = document.getElementById("leaderboard-body");
37
+ els.modelCards = document.getElementById("model-cards");
38
  els.emptyState = document.getElementById("empty-state");
39
  els.unavailableState = document.getElementById("unavailable-state");
40
  els.unavailableText = document.getElementById("unavailable-text");
 
42
  els.detailPanel = document.getElementById("detail-panel");
43
  els.detailTitle = document.getElementById("detail-title");
44
  els.detailSubtitle = document.getElementById("detail-subtitle");
45
+ els.detailMeta = document.getElementById("detail-meta");
46
  els.detailCats = document.getElementById("detail-cats");
47
  els.detailClose = document.getElementById("detail-close");
48
  els.submitToggle = document.getElementById("submit-toggle");
 
72
  state.activeBenchmark = (firstAvailable || state.data.benchmarks[0])?.id || null;
73
 
74
  initParamsBounds();
75
+ buildBenchTabs();
76
+ buildTierShowcase();
77
  bindControls();
78
  bindParamsFilter();
79
  render();
80
  }
81
 
82
  function renderLoadError(err) {
83
+ const msg =
 
84
  "Couldn't load <code>models.json</code> (" + escapeHtml(String(err.message || err)) +
85
+ "). Make sure it sits next to index.html.";
86
+ if (els.tbody) {
87
+ els.tbody.innerHTML =
88
+ '<tr><td colspan="10" style="padding:32px;text-align:center;color:var(--muted);">' + msg + "</td></tr>";
89
+ }
90
  }
91
 
92
  // -------------------- SUBMIT PANEL --------------------
 
100
  });
101
  }
102
 
103
+ // -------------------- BENCHMARK TABS (the actual switcher) --------------------
104
 
105
+ function buildBenchTabs() {
106
  const frag = document.createDocumentFragment();
107
  state.data.benchmarks
108
  .slice()
109
  .sort((a, b) => a.tier - b.tier)
110
  .forEach((bench) => {
111
+ const tab = document.createElement("button");
112
+ tab.type = "button";
113
+ tab.className =
114
+ "bench-tab" +
115
  (bench.id === state.activeBenchmark ? " active" : "") +
116
  (bench.unavailable ? " is-unavailable" : "");
117
+ tab.dataset.benchmarkId = bench.id;
118
+
119
+ const badge = bench.unavailable
120
+ ? '<span class="tab-badge-unavailable">Unavailable</span>'
121
+ : "";
122
+
123
+ tab.innerHTML =
124
+ '<span class="tab-tier-num">T' + bench.tier + "</span>" +
125
+ "<span>" + escapeHtml(bench.label) + "</span>" +
126
+ badge;
127
+
128
+ tab.addEventListener("click", () => {
129
+ state.activeBenchmark = bench.id;
130
+ closeDetail();
131
+ buildBenchTabs();
132
+ render();
133
+ });
134
+
135
+ frag.appendChild(tab);
136
+ });
137
+
138
+ els.benchTabs.innerHTML = "";
139
+ els.benchTabs.appendChild(frag);
140
+ }
141
+
142
+ function renderBenchSummary(bench) {
143
+ const rowsLabel = bench.rows != null ? bench.rows + " rows" : "open-ended";
144
+ els.benchSummary.innerHTML =
145
+ '<div class="bench-summary-desc"><strong>' + escapeHtml(bench.id) + "</strong> — " +
146
+ escapeHtml(bench.description) + "</div>" +
147
+ '<div class="bench-summary-stats">' +
148
+ "<span>" + rowsLabel + "</span>" +
149
+ "<span>" + escapeHtml(bench.metric) + "</span>" +
150
+ '<span><a href="' + escapeHtml(bench.dataset_url) + '" target="_blank" rel="noopener">dataset ↗</a></span>' +
151
+ "</div>";
152
+ }
153
+
154
+ // -------------------- DECORATIVE TIER SHOWCASE (bottom of page) --------------------
155
+
156
+ function buildTierShowcase() {
157
+ if (!els.tierStrip) return;
158
+ const frag = document.createDocumentFragment();
159
+ state.data.benchmarks
160
+ .slice()
161
+ .sort((a, b) => a.tier - b.tier)
162
+ .forEach((bench) => {
163
+ const card = document.createElement("div");
164
+ card.className = "tier-card";
165
 
166
  const rowsLabel = bench.rows != null ? bench.rows + " rows" : "open-ended";
167
  const badge = bench.unavailable
 
177
  "<span>" + escapeHtml(bench.metric) + "</span>" +
178
  "</div>";
179
 
 
 
 
 
 
 
 
180
  frag.appendChild(card);
181
  });
182
 
 
213
  const LOG_MIN = -1; // 10^-1 = 0.1B
214
  const LOG_MAX = Math.log10(PARAMS_ABSOLUTE_MAX); // 10^3 = 1000B
215
 
 
 
 
 
 
216
  function sliderToParams(t) {
217
  return Math.pow(10, LOG_MIN + t * (LOG_MAX - LOG_MIN));
218
  }
219
 
 
 
 
220
  function initParamsBounds() {
221
  state.paramsFilter = { min: 0, max: PARAMS_ABSOLUTE_MAX };
222
 
 
251
  const onSlide = () => {
252
  let loPos = parseFloat(els.rangeMin.value);
253
  let hiPos = parseFloat(els.rangeMax.value);
 
254
  if (loPos > hiPos) {
255
  [loPos, hiPos] = [hiPos, loPos];
256
  }
 
 
257
  const lo = loPos <= 0 ? 0 : sliderToParams(loPos / 1000);
258
  const hi = hiPos >= 1000 ? PARAMS_ABSOLUTE_MAX : sliderToParams(hiPos / 1000);
259
  state.paramsFilter = { min: lo, max: hi };
 
285
  }
286
 
287
  function updateRangeVisuals() {
 
 
 
288
  const loPct = (parseFloat(els.rangeMin.value) / 1000) * 100;
289
  const hiPct = (parseFloat(els.rangeMax.value) / 1000) * 100;
290
 
 
351
  return (v * 100).toFixed(1) + "%";
352
  }
353
 
354
+ function fmtParams(b) {
355
+ if (b == null) return "—";
356
+ if (b < 1) return (b * 1000).toFixed(0) + "M";
357
+ if (b >= 1000) return (b / 1000).toFixed(1).replace(/\.0$/, "") + "T";
358
+ return (Number.isInteger(b) ? b.toFixed(0) : b.toFixed(1)) + "B";
359
+ }
360
+
361
  function escapeHtml(s) {
362
  return String(s)
363
  .replace(/&/g, "&amp;")
 
366
  .replace(/"/g, "&quot;");
367
  }
368
 
369
+ const EVAL_LINK_SVG =
370
+ '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M9 7h8v8"/></svg>';
371
+
372
+ // -------------------- RENDER --------------------
373
 
374
  function render() {
375
  const bench = getActiveBenchmark();
376
  if (!bench) return;
377
 
378
  if (bench.unavailable) {
379
+ els.tableScroll.hidden = true;
380
+ els.modelCards.hidden = true;
381
  els.emptyState.hidden = true;
382
  els.unavailableState.hidden = false;
383
+ els.resultsCount.hidden = true;
384
  els.unavailableText.textContent =
385
  bench.unavailable_reason || (bench.id + " is currently unavailable.");
386
  closeDetail();
387
  return;
388
  }
389
 
390
+ renderBenchSummary(bench);
391
+
392
  const metricCols = getMetricColumns(bench);
393
  buildHead(metricCols);
394
 
 
398
  return { model: m, run, value };
399
  });
400
 
401
+ const totalCount = rows.length;
402
+
403
  if (state.search) {
404
  rows = rows.filter(
405
  (r) =>
 
412
  const { min, max } = state.paramsFilter;
413
  rows = rows.filter((r) => {
414
  const p = r.model.params_b;
415
+ if (p == null) return false;
416
+ if (max >= PARAMS_ABSOLUTE_MAX) return p >= min;
417
  return p >= min && p <= max;
418
  });
419
  }
420
 
421
  rows = sortRows(rows, state.sort);
422
 
423
+ els.resultsCount.hidden = false;
424
+ els.resultsCount.textContent =
425
+ rows.length === totalCount
426
+ ? "Showing all " + totalCount + " model" + (totalCount === 1 ? "" : "s")
427
+ : "Showing " + rows.length + " of " + totalCount + " models";
428
+
429
  els.tbody.innerHTML = "";
430
+ els.modelCards.innerHTML = "";
431
+
432
  if (rows.length === 0) {
433
  els.emptyState.hidden = false;
434
  els.unavailableState.hidden = true;
435
+ els.tableScroll.hidden = true;
436
+ els.modelCards.hidden = true;
437
  return;
438
  }
439
  els.emptyState.hidden = true;
440
  els.unavailableState.hidden = true;
441
+ els.tableScroll.hidden = false;
442
+ // .model-cards visibility itself is controlled by the mobile media query
443
+ // (display: none above 700px); just make sure it's not force-hidden here.
444
+ els.modelCards.hidden = false;
445
 
446
+ const tableFrag = document.createDocumentFragment();
447
+ const cardsFrag = document.createDocumentFragment();
448
  rows.forEach((r, idx) => {
449
+ tableFrag.appendChild(buildRow(r, idx + 1, bench, metricCols));
450
+ cardsFrag.appendChild(buildCard(r, idx + 1, bench, metricCols));
451
  });
452
+ els.tbody.appendChild(tableFrag);
453
+ els.modelCards.appendChild(cardsFrag);
454
 
455
  updateSortIndicators();
456
  }
 
460
 
461
  const thRank = document.createElement("th");
462
  thRank.dataset.key = "rank";
463
+ thRank.style.width = "40px";
464
  thRank.textContent = "#";
465
  tr.appendChild(thRank);
466
 
 
486
  tr.appendChild(th);
487
  });
488
 
489
+ const thStderr = document.createElement("th");
490
+ thStderr.textContent = "stderr";
491
+ tr.appendChild(thStderr);
492
+
493
+ const thNotes = document.createElement("th");
494
+ thNotes.textContent = "Notes";
495
+ tr.appendChild(thNotes);
496
+
497
+ const thEval = document.createElement("th");
498
+ thEval.textContent = "Eval";
499
+ tr.appendChild(thEval);
500
+
501
  els.thead.innerHTML = "";
502
  els.thead.appendChild(tr);
503
 
 
504
  els.thead.querySelectorAll("th[data-key]").forEach((th) => {
505
  th.addEventListener("click", () => {
506
  const key = th.dataset.key;
 
511
  } else if (key === "name") {
512
  state.sort = "name-asc";
513
  } else {
514
+ return;
515
  }
516
  els.sortSelect.value = state.sort;
517
  render();
 
567
  });
568
  }
569
 
570
+ function modelTagsHtml(model) {
571
+ const tags = [];
572
+ if (model.architecture) tags.push(model.architecture);
573
+ if (model.license) tags.push(model.license);
574
+ if (!tags.length) return "";
575
+ return (
576
+ '<div class="model-tags">' +
577
+ tags.map((t) => '<span class="model-tag">' + escapeHtml(t) + "</span>").join("") +
578
+ "</div>"
579
+ );
580
+ }
581
+
582
  function buildRow(r, rank, bench, metricCols) {
583
  const tr = document.createElement("tr");
584
  const { model, run, value } = r;
585
 
 
586
  const rankTd = document.createElement("td");
587
  rankTd.className = "rank-cell" + (rank <= 3 ? " top-" + rank : "");
588
  rankTd.textContent = value == null ? "–" : String(rank);
589
  tr.appendChild(rankTd);
590
 
 
591
  const modelTd = document.createElement("td");
592
  modelTd.innerHTML =
593
  '<div class="model-cell">' +
594
  '<span class="model-name"><a href="' + escapeHtml(model.url) + '" target="_blank" rel="noopener">' +
595
  escapeHtml(model.name) + "</a></span>" +
596
  '<span class="model-org">' + escapeHtml(model.org || "") + "</span>" +
597
+ modelTagsHtml(model) +
598
  "</div>";
599
  tr.appendChild(modelTd);
600
 
 
601
  const paramsTd = document.createElement("td");
602
  paramsTd.className = "params-cell";
603
+ paramsTd.textContent = fmtParams(model.params_b);
604
  tr.appendChild(paramsTd);
605
 
 
606
  const nTd = document.createElement("td");
607
  nTd.className = "n-cell";
608
  nTd.textContent = run && run.n != null ? String(run.n) : "—";
609
  tr.appendChild(nTd);
610
 
 
611
  metricCols.forEach((key, i) => {
612
  const td = document.createElement("td");
613
  const v = getMetricValue(run, key);
614
 
615
  if (i === 0) {
 
616
  td.className = "score-cell";
617
  if (v == null) {
618
  td.innerHTML = '<span class="score-na">not evaluated</span>';
 
632
  tr.appendChild(td);
633
  });
634
 
635
+ const stderrTd = document.createElement("td");
636
+ stderrTd.className = "stderr-cell";
637
+ stderrTd.textContent = run && typeof run.stderr === "number" ? "±" + run.stderr.toFixed(4) : "—";
638
+ tr.appendChild(stderrTd);
639
+
640
+ const notesTd = document.createElement("td");
641
+ notesTd.className = "notes-cell";
642
+ notesTd.innerHTML = run && run.notes ? escapeHtml(run.notes) : '<span class="notes-na">—</span>';
643
+ tr.appendChild(notesTd);
644
+
645
+ const evalTd = document.createElement("td");
646
+ evalTd.innerHTML = model.eval_source
647
+ ? '<a class="eval-link tooltip" href="' + escapeHtml(model.eval_source) + '" target="_blank" rel="noopener" data-tooltip="View eval write-up">' + EVAL_LINK_SVG + "</a>"
648
+ : '<span class="notes-na">—</span>';
649
+ tr.appendChild(evalTd);
650
+
651
  if (run && run.categories) {
652
  tr.style.cursor = "pointer";
653
  tr.title = "Click for per-category breakdown";
654
+ tr.addEventListener("click", (e) => {
655
+ if (e.target.closest("a")) return; // let links behave normally
656
+ openDetail(model, run, bench);
657
+ });
658
  }
659
 
660
  return tr;
661
  }
662
 
663
+ function buildCard(r, rank, bench, metricCols) {
664
+ const { model, run, value } = r;
665
+ const card = document.createElement("div");
666
+ card.className = "model-card";
667
+
668
+ const rankCls = rank <= 3 ? " top-" + rank : "";
669
+ const scoreHtml =
670
+ value == null
671
+ ? '<span class="score-na">not evaluated</span>'
672
+ : '<span class="score-num ' + scoreClass(value) + '">' + fmtScore(value) + "</span>" +
673
+ '<div class="score-bar-track"><div class="score-bar-fill" style="width:' +
674
+ Math.max(0, Math.min(100, value * 100)).toFixed(1) + '%"></div></div>';
675
+
676
+ card.innerHTML =
677
+ '<div class="model-card-top">' +
678
+ '<span class="model-card-rank' + rankCls + '">' + (value == null ? "–" : rank) + "</span>" +
679
+ '<div class="model-card-name">' +
680
+ '<span class="model-name"><a href="' + escapeHtml(model.url) + '" target="_blank" rel="noopener">' + escapeHtml(model.name) + "</a></span>" +
681
+ '<span class="model-org">' + escapeHtml(model.org || "") + " · " + fmtParams(model.params_b) + "</span>" +
682
+ "</div>" +
683
+ '<div class="model-card-score">' + scoreHtml + "</div>" +
684
+ "</div>" +
685
+ modelTagsHtml(model).replace("model-tags", "model-tags model-card-tags") +
686
+ buildCardMetrics(run, metricCols) +
687
+ (run && run.notes ? '<div class="model-card-notes">' + escapeHtml(run.notes) + "</div>" : "") +
688
+ '<div class="model-card-footer">' +
689
+ (model.eval_source
690
+ ? '<a href="' + escapeHtml(model.eval_source) + '" target="_blank" rel="noopener">Eval write-up ' + EVAL_LINK_SVG + "</a>"
691
+ : "<span></span>") +
692
+ (run && run.categories ? '<button type="button" class="model-card-details-btn">Category breakdown</button>' : "") +
693
+ "</div>";
694
+
695
+ if (run && run.categories) {
696
+ const btn = card.querySelector(".model-card-details-btn");
697
+ if (btn) btn.addEventListener("click", () => openDetail(model, run, bench));
698
+ }
699
+
700
+ return card;
701
+ }
702
+
703
+ function buildCardMetrics(run, metricCols) {
704
+ const parts = [];
705
+ if (run && run.n != null) {
706
+ parts.push({ label: "n", value: String(run.n) });
707
+ }
708
+ metricCols.slice(1).forEach((key) => {
709
+ const v = getMetricValue(run, key);
710
+ if (v != null) parts.push({ label: METRIC_LABELS[key] || key, value: fmtScore(v) });
711
+ });
712
+ if (run && typeof run.stderr === "number") {
713
+ parts.push({ label: "stderr", value: "±" + run.stderr.toFixed(4) });
714
+ }
715
+ if (!parts.length) return "";
716
+ return (
717
+ '<div class="model-card-metrics">' +
718
+ parts
719
+ .map(
720
+ (p) =>
721
+ '<div class="model-card-metric"><span class="model-card-metric-label">' +
722
+ escapeHtml(p.label) +
723
+ '</span><span class="model-card-metric-value">' +
724
+ escapeHtml(p.value) +
725
+ "</span></div>"
726
+ )
727
+ .join("") +
728
+ "</div>"
729
+ );
730
+ }
731
+
732
  // -------------------- DETAIL PANEL --------------------
733
 
734
  function openDetail(model, run, bench) {
735
  els.detailTitle.textContent = model.name + " on " + bench.id;
736
+ els.detailSubtitle.textContent = "Per-category breakdown";
737
+
738
+ const metaParts = [];
739
+ metaParts.push(fmtParams(model.params_b) + " params");
740
+ if (model.architecture) metaParts.push(model.architecture);
741
+ if (model.license) metaParts.push(model.license);
742
+ if (run.n != null) metaParts.push("n=" + run.n);
743
+ if (run.stderr != null) metaParts.push("stderr ±" + run.stderr.toFixed(4));
744
+
745
+ els.detailMeta.innerHTML =
746
+ metaParts.map((m) => "<span>" + escapeHtml(m) + "</span>").join("") +
747
+ (model.eval_source
748
+ ? '<span><a href="' + escapeHtml(model.eval_source) + '" target="_blank" rel="noopener">eval write-up ↗</a></span>'
749
+ : "") +
750
+ (model.url ? '<span><a href="' + escapeHtml(model.url) + '" target="_blank" rel="noopener">model card ↗</a></span>' : "");
751
 
752
  const cats = run.categories || {};
753
  const frag = document.createDocumentFragment();
style.css CHANGED
@@ -175,39 +175,152 @@ a:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-
175
  font-size: 1.05rem;
176
  }
177
 
178
- /* -------------------- TIER STRIP -------------------- */
179
 
180
- .tier-strip {
181
- display: grid;
182
- grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
183
- gap: 14px;
184
- margin: 32px 0 30px;
185
  }
186
 
187
- .tier-card {
188
- padding: 18px 20px;
189
- border-radius: var(--radius);
 
 
 
190
  background: var(--surface);
191
  border: 1px solid var(--border);
192
  backdrop-filter: blur(20px) saturate(1.2);
193
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
194
  box-shadow: var(--shadow-soft);
195
- transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
 
 
196
  cursor: pointer;
 
 
197
  }
198
 
199
- .tier-card:hover {
200
- transform: translateY(-3px);
201
- box-shadow: var(--shadow-hover);
202
- border-color: rgba(93, 165, 112, 0.4);
203
- }
204
 
205
- .tier-card.active {
 
206
  border-color: var(--accent);
207
- background: var(--surface-2);
208
  box-shadow: var(--shadow-hover);
209
  }
210
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  .tier-card .tier-num {
212
  display: inline-block;
213
  font-size: 0.7rem;
@@ -218,7 +331,7 @@ a:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-
218
  margin-bottom: 6px;
219
  }
220
 
221
- .tier-card h3 { font-size: 1.15rem; margin-bottom: 6px; }
222
  .tier-card p { color: var(--muted); font-size: 0.85rem; line-height: 1.5; }
223
 
224
  .tier-meta {
@@ -227,6 +340,7 @@ a:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-
227
  margin-top: 10px;
228
  font-size: 0.72rem;
229
  color: var(--muted);
 
230
  }
231
 
232
  .tier-meta span {
@@ -236,6 +350,22 @@ a:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-
236
  border: 1px solid var(--border-soft);
237
  }
238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  /* -------------------- SUBMIT PANEL -------------------- */
240
 
241
  .submit-panel {
@@ -702,11 +832,14 @@ table.leaderboard td {
702
  .model-cell {
703
  display: flex;
704
  flex-direction: column;
705
- gap: 2px;
706
- min-width: 200px;
707
  }
708
 
709
  .model-name {
 
 
 
710
  font-weight: 600;
711
  color: var(--heading);
712
  font-size: 0.95rem;
@@ -720,6 +853,41 @@ table.leaderboard td {
720
  color: var(--muted);
721
  }
722
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
723
  .params-cell {
724
  font-variant-numeric: tabular-nums;
725
  color: var(--muted);
@@ -756,6 +924,13 @@ table.leaderboard td {
756
  white-space: nowrap;
757
  }
758
 
 
 
 
 
 
 
 
759
  .score-pill {
760
  display: inline-flex;
761
  align-items: center;
@@ -816,29 +991,6 @@ table.leaderboard td {
816
  .unavailable-state svg { margin-bottom: 14px; color: #d99a3e; }
817
  .unavailable-state p { max-width: 420px; margin: 0 auto; line-height: 1.6; }
818
 
819
- .tier-card.is-unavailable {
820
- opacity: 0.72;
821
- cursor: pointer;
822
- }
823
-
824
- .tier-card.is-unavailable:hover { opacity: 0.9; }
825
-
826
- .tier-badge-unavailable {
827
- display: inline-flex;
828
- align-items: center;
829
- gap: 4px;
830
- margin-left: 8px;
831
- padding: 2px 8px;
832
- border-radius: 999px;
833
- background: rgba(217, 154, 62, 0.16);
834
- color: #b5791f;
835
- font-size: 0.62rem;
836
- font-weight: 700;
837
- text-transform: uppercase;
838
- letter-spacing: 0.06em;
839
- vertical-align: middle;
840
- }
841
-
842
  /* -------------------- DETAIL PANEL -------------------- */
843
 
844
  .detail-panel {
@@ -884,6 +1036,24 @@ table.leaderboard td {
884
 
885
  .detail-close:hover { background: #fff; color: var(--accent); border-color: var(--accent); }
886
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
887
  .cat-grid {
888
  display: grid;
889
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
@@ -934,6 +1104,145 @@ table.leaderboard td {
934
  border-radius: 999px;
935
  }
936
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
937
  /* -------------------- FOOTER -------------------- */
938
 
939
  .page-footer {
@@ -952,12 +1261,66 @@ table.leaderboard td {
952
 
953
  /* -------------------- RESPONSIVE -------------------- */
954
 
955
- @media (max-width: 640px) {
956
- .container { padding: 40px 16px 32px; }
957
- .controls { flex-direction: column; align-items: stretch; }
958
- .filter-wrap { align-self: flex-start; }
959
- .filter-popup { left: 0; right: auto; width: min(260px, calc(100vw - 64px)); }
960
- table.leaderboard { min-width: 560px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
961
  }
962
 
963
  /* -------------------- SCROLLBARS / SELECTION -------------------- */
 
175
  font-size: 1.05rem;
176
  }
177
 
178
+ /* -------------------- BENCHMARK TABS (the actual switcher) -------------------- */
179
 
180
+ .bench-tabs {
181
+ display: flex;
182
+ flex-wrap: wrap;
183
+ gap: 8px;
184
+ margin: 28px 0 16px;
185
  }
186
 
187
+ .bench-tab {
188
+ display: inline-flex;
189
+ align-items: center;
190
+ gap: 8px;
191
+ padding: 10px 16px;
192
+ border-radius: 999px;
193
  background: var(--surface);
194
  border: 1px solid var(--border);
195
  backdrop-filter: blur(20px) saturate(1.2);
196
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
197
  box-shadow: var(--shadow-soft);
198
+ color: var(--heading);
199
+ font-size: 0.85rem;
200
+ font-weight: 600;
201
  cursor: pointer;
202
+ transition: background var(--transition), border-color var(--transition), box-shadow var(--transition), color var(--transition);
203
+ font-family: inherit;
204
  }
205
 
206
+ .bench-tab:hover { border-color: rgba(93, 165, 112, 0.4); box-shadow: var(--shadow-hover); }
 
 
 
 
207
 
208
+ .bench-tab.active {
209
+ background: var(--accent);
210
  border-color: var(--accent);
211
+ color: #fff;
212
  box-shadow: var(--shadow-hover);
213
  }
214
 
215
+ .bench-tab .tab-tier-num {
216
+ font-size: 0.68rem;
217
+ opacity: 0.7;
218
+ font-weight: 700;
219
+ }
220
+
221
+ .bench-tab.is-unavailable {
222
+ opacity: 0.65;
223
+ }
224
+
225
+ .bench-tab .tab-badge-unavailable {
226
+ display: inline-flex;
227
+ align-items: center;
228
+ padding: 1px 7px;
229
+ border-radius: 999px;
230
+ background: rgba(217, 154, 62, 0.2);
231
+ color: #b5791f;
232
+ font-size: 0.6rem;
233
+ font-weight: 700;
234
+ text-transform: uppercase;
235
+ letter-spacing: 0.05em;
236
+ }
237
+
238
+ .bench-tab.active .tab-badge-unavailable {
239
+ background: rgba(255,255,255,0.28);
240
+ color: #fff;
241
+ }
242
+
243
+ /* -------------------- BENCH SUMMARY (active tier's own blurb) -------------------- */
244
+
245
+ .bench-summary {
246
+ display: flex;
247
+ flex-wrap: wrap;
248
+ align-items: baseline;
249
+ justify-content: space-between;
250
+ gap: 10px;
251
+ margin-bottom: 22px;
252
+ color: var(--muted);
253
+ font-size: 0.88rem;
254
+ line-height: 1.6;
255
+ }
256
+
257
+ .bench-summary-desc { max-width: 620px; }
258
+ .bench-summary-desc strong { color: var(--heading); }
259
+
260
+ .bench-summary-stats {
261
+ display: flex;
262
+ gap: 8px;
263
+ flex-wrap: wrap;
264
+ }
265
+
266
+ .bench-summary-stats span {
267
+ padding: 3px 10px;
268
+ background: rgba(255,255,255,0.55);
269
+ border: 1px solid var(--border-soft);
270
+ border-radius: 999px;
271
+ font-size: 0.75rem;
272
+ white-space: nowrap;
273
+ }
274
+
275
+ .bench-summary-stats a { color: var(--accent); font-weight: 600; }
276
+
277
+ /* -------------------- RESULTS COUNT -------------------- */
278
+
279
+ .results-count {
280
+ color: var(--muted);
281
+ font-size: 0.8rem;
282
+ margin-bottom: 10px;
283
+ }
284
+
285
+ /* -------------------- DECORATIVE TIER SHOWCASE (bottom of page) -------------------- */
286
+
287
+ .tier-showcase {
288
+ margin-top: 46px;
289
+ }
290
+
291
+ .tier-showcase-heading {
292
+ margin-bottom: 18px;
293
+ }
294
+
295
+ .tier-showcase-heading h2 {
296
+ font-size: 1.3rem;
297
+ margin-bottom: 4px;
298
+ }
299
+
300
+ .tier-showcase-heading p {
301
+ color: var(--muted);
302
+ font-size: 0.88rem;
303
+ }
304
+
305
+ .tier-showcase-heading a { color: var(--accent); }
306
+
307
+ .tier-strip {
308
+ display: grid;
309
+ grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
310
+ gap: 14px;
311
+ }
312
+
313
+ .tier-card {
314
+ padding: 18px 20px;
315
+ border-radius: var(--radius);
316
+ background: var(--surface);
317
+ border: 1px solid var(--border);
318
+ backdrop-filter: blur(16px) saturate(1.1);
319
+ -webkit-backdrop-filter: blur(16px) saturate(1.1);
320
+ box-shadow: var(--shadow-soft);
321
+ opacity: 0.92;
322
+ }
323
+
324
  .tier-card .tier-num {
325
  display: inline-block;
326
  font-size: 0.7rem;
 
331
  margin-bottom: 6px;
332
  }
333
 
334
+ .tier-card h3 { font-size: 1.1rem; margin-bottom: 6px; }
335
  .tier-card p { color: var(--muted); font-size: 0.85rem; line-height: 1.5; }
336
 
337
  .tier-meta {
 
340
  margin-top: 10px;
341
  font-size: 0.72rem;
342
  color: var(--muted);
343
+ flex-wrap: wrap;
344
  }
345
 
346
  .tier-meta span {
 
350
  border: 1px solid var(--border-soft);
351
  }
352
 
353
+ .tier-badge-unavailable {
354
+ display: inline-flex;
355
+ align-items: center;
356
+ gap: 4px;
357
+ margin-left: 8px;
358
+ padding: 2px 8px;
359
+ border-radius: 999px;
360
+ background: rgba(217, 154, 62, 0.16);
361
+ color: #b5791f;
362
+ font-size: 0.62rem;
363
+ font-weight: 700;
364
+ text-transform: uppercase;
365
+ letter-spacing: 0.06em;
366
+ vertical-align: middle;
367
+ }
368
+
369
  /* -------------------- SUBMIT PANEL -------------------- */
370
 
371
  .submit-panel {
 
832
  .model-cell {
833
  display: flex;
834
  flex-direction: column;
835
+ gap: 3px;
836
+ min-width: 220px;
837
  }
838
 
839
  .model-name {
840
+ display: flex;
841
+ align-items: center;
842
+ gap: 6px;
843
  font-weight: 600;
844
  color: var(--heading);
845
  font-size: 0.95rem;
 
853
  color: var(--muted);
854
  }
855
 
856
+ .model-tags {
857
+ display: flex;
858
+ gap: 6px;
859
+ flex-wrap: wrap;
860
+ margin-top: 3px;
861
+ }
862
+
863
+ .model-tag {
864
+ padding: 1px 7px;
865
+ border-radius: 999px;
866
+ background: rgba(120,160,200,0.12);
867
+ border: 1px solid var(--border-soft);
868
+ color: var(--muted);
869
+ font-size: 0.66rem;
870
+ white-space: nowrap;
871
+ }
872
+
873
+ .eval-link {
874
+ display: inline-flex;
875
+ align-items: center;
876
+ color: var(--muted);
877
+ transition: color var(--transition);
878
+ flex-shrink: 0;
879
+ }
880
+ .eval-link:hover { color: var(--accent); opacity: 1; }
881
+
882
+ .notes-cell {
883
+ max-width: 240px;
884
+ color: var(--muted);
885
+ font-size: 0.8rem;
886
+ line-height: 1.4;
887
+ }
888
+
889
+ .notes-cell .notes-na { font-style: italic; opacity: 0.7; }
890
+
891
  .params-cell {
892
  font-variant-numeric: tabular-nums;
893
  color: var(--muted);
 
924
  white-space: nowrap;
925
  }
926
 
927
+ .stderr-cell {
928
+ font-variant-numeric: tabular-nums;
929
+ color: var(--muted);
930
+ font-size: 0.78rem;
931
+ white-space: nowrap;
932
+ }
933
+
934
  .score-pill {
935
  display: inline-flex;
936
  align-items: center;
 
991
  .unavailable-state svg { margin-bottom: 14px; color: #d99a3e; }
992
  .unavailable-state p { max-width: 420px; margin: 0 auto; line-height: 1.6; }
993
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
994
  /* -------------------- DETAIL PANEL -------------------- */
995
 
996
  .detail-panel {
 
1036
 
1037
  .detail-close:hover { background: #fff; color: var(--accent); border-color: var(--accent); }
1038
 
1039
+ .detail-meta {
1040
+ display: flex;
1041
+ flex-wrap: wrap;
1042
+ gap: 8px;
1043
+ margin-bottom: 18px;
1044
+ }
1045
+
1046
+ .detail-meta span {
1047
+ padding: 4px 11px;
1048
+ background: rgba(255,255,255,0.55);
1049
+ border: 1px solid var(--border-soft);
1050
+ border-radius: 999px;
1051
+ font-size: 0.76rem;
1052
+ color: var(--text);
1053
+ }
1054
+
1055
+ .detail-meta a { color: var(--accent); font-weight: 600; }
1056
+
1057
  .cat-grid {
1058
  display: grid;
1059
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
 
1104
  border-radius: 999px;
1105
  }
1106
 
1107
+ /* -------------------- MOBILE MODEL CARDS (replaces table under 700px) -------------------- */
1108
+
1109
+ .model-cards {
1110
+ display: none;
1111
+ flex-direction: column;
1112
+ gap: 12px;
1113
+ }
1114
+
1115
+ .model-card {
1116
+ padding: 16px 18px;
1117
+ border-radius: var(--radius);
1118
+ background: var(--surface);
1119
+ border: 1px solid var(--border);
1120
+ backdrop-filter: blur(20px) saturate(1.2);
1121
+ -webkit-backdrop-filter: blur(20px) saturate(1.2);
1122
+ box-shadow: var(--shadow-soft);
1123
+ }
1124
+
1125
+ .model-card-top {
1126
+ display: flex;
1127
+ align-items: flex-start;
1128
+ justify-content: space-between;
1129
+ gap: 10px;
1130
+ margin-bottom: 10px;
1131
+ }
1132
+
1133
+ .model-card-rank {
1134
+ display: inline-flex;
1135
+ align-items: center;
1136
+ justify-content: center;
1137
+ width: 26px;
1138
+ height: 26px;
1139
+ border-radius: 50%;
1140
+ background: rgba(120,160,200,0.14);
1141
+ color: var(--muted);
1142
+ font-weight: 700;
1143
+ font-size: 0.78rem;
1144
+ flex-shrink: 0;
1145
+ font-variant-numeric: tabular-nums;
1146
+ }
1147
+
1148
+ .model-card-rank.top-1 { background: rgba(217,164,65,0.18); color: #b5791f; }
1149
+ .model-card-rank.top-2 { background: rgba(154,165,177,0.2); color: #6b7683; }
1150
+ .model-card-rank.top-3 { background: rgba(192,133,82,0.18); color: #a35f2f; }
1151
+
1152
+ .model-card-name {
1153
+ display: flex;
1154
+ flex-direction: column;
1155
+ gap: 2px;
1156
+ min-width: 0;
1157
+ }
1158
+
1159
+ .model-card-name .model-name { font-size: 0.98rem; }
1160
+ .model-card-name .model-org { font-size: 0.78rem; }
1161
+
1162
+ .model-card-score {
1163
+ text-align: right;
1164
+ flex-shrink: 0;
1165
+ }
1166
+
1167
+ .model-card-score .score-num {
1168
+ display: block;
1169
+ font-size: 1.15rem;
1170
+ font-weight: 700;
1171
+ }
1172
+
1173
+ .model-card-score .score-bar-track { width: 64px; margin-top: 4px; }
1174
+
1175
+ .model-card-tags {
1176
+ display: flex;
1177
+ gap: 6px;
1178
+ flex-wrap: wrap;
1179
+ margin: 8px 0 10px;
1180
+ }
1181
+
1182
+ .model-card-metrics {
1183
+ display: grid;
1184
+ grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
1185
+ gap: 8px;
1186
+ margin-top: 10px;
1187
+ padding-top: 10px;
1188
+ border-top: 1px solid var(--border-soft);
1189
+ }
1190
+
1191
+ .model-card-metric {
1192
+ display: flex;
1193
+ flex-direction: column;
1194
+ gap: 2px;
1195
+ }
1196
+
1197
+ .model-card-metric-label {
1198
+ font-size: 0.62rem;
1199
+ text-transform: uppercase;
1200
+ letter-spacing: 0.05em;
1201
+ color: var(--muted);
1202
+ }
1203
+
1204
+ .model-card-metric-value {
1205
+ font-size: 0.85rem;
1206
+ font-weight: 600;
1207
+ color: var(--heading);
1208
+ font-variant-numeric: tabular-nums;
1209
+ }
1210
+
1211
+ .model-card-notes {
1212
+ margin-top: 10px;
1213
+ color: var(--muted);
1214
+ font-size: 0.8rem;
1215
+ line-height: 1.5;
1216
+ }
1217
+
1218
+ .model-card-footer {
1219
+ display: flex;
1220
+ align-items: center;
1221
+ justify-content: space-between;
1222
+ gap: 10px;
1223
+ margin-top: 12px;
1224
+ }
1225
+
1226
+ .model-card-footer a {
1227
+ font-size: 0.78rem;
1228
+ font-weight: 600;
1229
+ display: inline-flex;
1230
+ align-items: center;
1231
+ gap: 4px;
1232
+ }
1233
+
1234
+ .model-card-details-btn {
1235
+ padding: 6px 12px;
1236
+ border-radius: 999px;
1237
+ border: 1px solid var(--border-soft);
1238
+ background: rgba(255,255,255,0.55);
1239
+ color: var(--accent);
1240
+ font-size: 0.76rem;
1241
+ font-weight: 600;
1242
+ cursor: pointer;
1243
+ font-family: inherit;
1244
+ }
1245
+
1246
  /* -------------------- FOOTER -------------------- */
1247
 
1248
  .page-footer {
 
1261
 
1262
  /* -------------------- RESPONSIVE -------------------- */
1263
 
1264
+ /* Tablet: table stays, but tighten paddings and let it scroll */
1265
+ @media (max-width: 900px) {
1266
+ .container { padding: 56px 20px 36px; }
1267
+ table.leaderboard { min-width: 720px; }
1268
+ }
1269
+
1270
+ /* Phone: swap the table for stacked cards; simplify controls; single-column
1271
+ grids; popups sized and positioned to stay on-screen. */
1272
+ @media (max-width: 700px) {
1273
+ .container { padding: 44px 16px 32px; }
1274
+
1275
+ .hero h1 { font-size: clamp(1.9rem, 9vw, 2.6rem); }
1276
+ .subtitle { font-size: 0.95rem; }
1277
+
1278
+ .bench-tabs {
1279
+ flex-wrap: nowrap;
1280
+ overflow-x: auto;
1281
+ -webkit-overflow-scrolling: touch;
1282
+ padding-bottom: 4px;
1283
+ margin-left: -16px;
1284
+ margin-right: -16px;
1285
+ padding-left: 16px;
1286
+ padding-right: 16px;
1287
+ }
1288
+ .bench-tab { flex-shrink: 0; }
1289
+
1290
+ .bench-summary { flex-direction: column; align-items: flex-start; }
1291
+
1292
+ .controls { flex-direction: row; flex-wrap: wrap; align-items: stretch; }
1293
+ .search-pill { order: 1; width: 100%; min-width: 0; }
1294
+ .filter-wrap { order: 2; }
1295
+ .sort-select-wrap { order: 3; flex: 1; }
1296
+ .pill-select { width: 100%; }
1297
+
1298
+ .filter-popup {
1299
+ left: 50%;
1300
+ right: auto;
1301
+ transform: translateX(-50%);
1302
+ width: min(280px, calc(100vw - 32px));
1303
+ }
1304
+
1305
+ /* table -> cards */
1306
+ .table-scroll { display: none; }
1307
+ .model-cards { display: flex; }
1308
+
1309
+ .detail-panel { padding: 20px; }
1310
+ .cat-grid { grid-template-columns: 1fr; }
1311
+
1312
+ .tier-strip { grid-template-columns: 1fr; }
1313
+
1314
+ .submit-body { padding: 4px 18px 22px; }
1315
+ .submit-body pre { font-size: 0.76rem; }
1316
+ .submit-body pre code { font-size: 0.76rem; white-space: pre-wrap; word-break: break-word; }
1317
+
1318
+ .page-footer { flex-direction: column; align-items: flex-start; gap: 6px; }
1319
+ }
1320
+
1321
+ @media (max-width: 380px) {
1322
+ .bench-summary-stats span { font-size: 0.7rem; }
1323
+ .model-card-metrics { grid-template-columns: repeat(2, 1fr); }
1324
  }
1325
 
1326
  /* -------------------- SCROLLBARS / SELECTION -------------------- */