alexshah commited on
Commit
92fb9a5
·
0 Parent(s):

Initial commit

Browse files
Files changed (7) hide show
  1. .gitattributes +35 -0
  2. .gitignore +3 -0
  3. README.md +16 -0
  4. app.js +428 -0
  5. index.html +220 -0
  6. results.csv +30 -0
  7. style.css +339 -0
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ .DS_Store
2
+ /BLOG_POST_*.md
3
+ /assets/dataset-treemap.png
README.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: "ArmBench-ASR: Armenian Speech Recognition in the Real World"
3
+ emoji: 🎙️
4
+ colorFrom: blue
5
+ colorTo: indigo
6
+ sdk: static
7
+ pinned: false
8
+ ---
9
+
10
+ # ArmBench-ASR: Armenian Speech Recognition in the Real World
11
+
12
+ An interactive Armenian automatic speech recognition leaderboard.
13
+
14
+ Current benchmark release: **v0.1**.
15
+
16
+ The static leaderboard reads `results.csv` directly in the browser and supports single-dataset and all-datasets views, numeric sorting, availability filtering, external model links, and optional grouped score heatmaps.
app.js ADDED
@@ -0,0 +1,428 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const DATASET_LABELS = {
2
+ combined: "Combined",
3
+ mcv26: "Common Voice 26",
4
+ fleurs: "FLEURS",
5
+ poems: "Poems",
6
+ movies: "Movies",
7
+ infocom_may_26: "Infocom",
8
+ };
9
+
10
+ const METRICS = ["WER", "CER", "WER-norm", "CER-norm"];
11
+
12
+ const state = {
13
+ records: [],
14
+ datasets: [],
15
+ columns: new Map(),
16
+ view: "matrix",
17
+ sortKey: "combined|WER",
18
+ sortDirection: "asc",
19
+ colorScores: false,
20
+ availability: new Set(["Open", "Closed"]),
21
+ availabilityMenuOpen: false,
22
+ };
23
+
24
+ function setTheme(theme, persist = true) {
25
+ document.documentElement.dataset.theme = theme;
26
+ const toggle = document.querySelector("#theme-toggle");
27
+ if (toggle) {
28
+ const nextTheme = theme === "dark" ? "light" : "dark";
29
+ toggle.setAttribute("aria-label", `Switch to ${nextTheme} mode`);
30
+ toggle.title = `Switch to ${nextTheme} mode`;
31
+ }
32
+ if (persist) {
33
+ try { localStorage.setItem("arm-asr-theme", theme); } catch (_) {}
34
+ }
35
+ }
36
+
37
+ function parseCsv(text) {
38
+ const rows = [];
39
+ let row = [];
40
+ let field = "";
41
+ let quoted = false;
42
+
43
+ for (let index = 0; index < text.length; index += 1) {
44
+ const char = text[index];
45
+ if (quoted) {
46
+ if (char === '"' && text[index + 1] === '"') {
47
+ field += '"';
48
+ index += 1;
49
+ } else if (char === '"') {
50
+ quoted = false;
51
+ } else {
52
+ field += char;
53
+ }
54
+ } else if (char === '"') {
55
+ quoted = true;
56
+ } else if (char === ",") {
57
+ row.push(field);
58
+ field = "";
59
+ } else if (char === "\n") {
60
+ row.push(field.replace(/\r$/, ""));
61
+ if (row.some((value) => value !== "")) rows.push(row);
62
+ row = [];
63
+ field = "";
64
+ } else {
65
+ field += char;
66
+ }
67
+ }
68
+
69
+ if (field || row.length) {
70
+ row.push(field.replace(/\r$/, ""));
71
+ rows.push(row);
72
+ }
73
+ return rows;
74
+ }
75
+
76
+ function ingest(rows) {
77
+ const [sections, datasets, metrics] = rows.slice(0, 3);
78
+ const modelIndex = sections.indexOf("model");
79
+ const urlIndex = sections.indexOf("model_url");
80
+ const availabilityIndex = sections.indexOf("availability");
81
+ const standardIndex = sections.indexOf("standard");
82
+ let currentDataset = "";
83
+
84
+ for (let index = standardIndex; index < sections.length; index += 1) {
85
+ if (datasets[index]) currentDataset = datasets[index];
86
+ if (currentDataset && METRICS.includes(metrics[index])) {
87
+ state.columns.set(`${currentDataset}|${metrics[index]}`, index);
88
+ if (!state.datasets.includes(currentDataset)) state.datasets.push(currentDataset);
89
+ }
90
+ }
91
+
92
+ state.records = rows.slice(3).map((row) => {
93
+ const values = {};
94
+ for (const [key, index] of state.columns) {
95
+ values[key] = row[index] === "" || row[index] === undefined ? null : Number(row[index]);
96
+ }
97
+ return {
98
+ model: row[modelIndex],
99
+ url: row[urlIndex],
100
+ availability: row[availabilityIndex],
101
+ values,
102
+ };
103
+ });
104
+ }
105
+
106
+ function currentDataset() {
107
+ return document.querySelector('input[name="dataset"]:checked')?.value || state.datasets[0];
108
+ }
109
+
110
+ function currentMatrixMetric() {
111
+ return document.querySelector('input[name="matrix-metric"]:checked')?.value || "WER";
112
+ }
113
+
114
+ function rankRecords(records, dataset, metric = "WER") {
115
+ const rankKey = `${dataset}|${metric}`;
116
+ const ranked = [...records].sort((left, right) => {
117
+ const a = left.values[rankKey];
118
+ const b = right.values[rankKey];
119
+ if (a === null) return 1;
120
+ if (b === null) return -1;
121
+ return a - b || left.model.localeCompare(right.model);
122
+ });
123
+ return new Map(ranked.map((record, index) => [record.model, index + 1]));
124
+ }
125
+
126
+ function makeCell(tag, text, className = "") {
127
+ const cell = document.createElement(tag);
128
+ cell.textContent = text;
129
+ if (className) cell.className = className;
130
+ return cell;
131
+ }
132
+
133
+ function matrixRanges(columns) {
134
+ const familyValues = { wer: [], cer: [] };
135
+ columns.forEach((column) => {
136
+ const metric = column.key.split("|")[1];
137
+ const family = metric.startsWith("CER") ? "cer" : "wer";
138
+ state.records.forEach((record) => {
139
+ const value = record.values[column.key];
140
+ if (value !== null) familyValues[family].push(value);
141
+ });
142
+ });
143
+
144
+ const familyRanges = Object.fromEntries(Object.entries(familyValues).map(([family, values]) => [
145
+ family,
146
+ values.length ? { min: Math.min(...values), max: Math.max(...values) } : null,
147
+ ]));
148
+
149
+ return new Map(columns.map((column) => {
150
+ const metric = column.key.split("|")[1];
151
+ const family = metric.startsWith("CER") ? "cer" : "wer";
152
+ return [column.key, familyRanges[family]];
153
+ }));
154
+ }
155
+
156
+ function heatClass(value, range) {
157
+ if (value === null || !range || range.max === range.min) return "";
158
+ const ratio = (value - range.min) / (range.max - range.min);
159
+ return ` heat-score-${Math.min(5, Math.floor(ratio * 5) + 1)}`;
160
+ }
161
+
162
+ function render() {
163
+ const dataset = currentDataset();
164
+ const matrixMetric = currentMatrixMetric();
165
+ const isMatrix = state.view === "matrix";
166
+ const columns = isMatrix
167
+ ? state.datasets.map((item) => ({ label: DATASET_LABELS[item] || item, key: `${item}|${matrixMetric}` }))
168
+ : METRICS.map((metric) => ({ label: metric, key: `${dataset}|${metric}` }));
169
+ const table = document.querySelector("#leaderboard-table");
170
+ const head = table.querySelector("thead");
171
+ const body = table.querySelector("tbody");
172
+ const rankDataset = isMatrix ? "combined" : dataset;
173
+ const rankMetric = isMatrix ? matrixMetric : "WER";
174
+ const ranks = rankRecords(state.records, rankDataset, rankMetric);
175
+ const ranges = state.colorScores ? matrixRanges(columns) : new Map();
176
+
177
+ let records = state.records.filter((record) => state.availability.has(record.availability));
178
+
179
+ if (columns.some((column) => column.key === state.sortKey)) {
180
+ const direction = state.sortDirection === "asc" ? 1 : -1;
181
+ records = [...records].sort((left, right) => {
182
+ const a = left.values[state.sortKey];
183
+ const b = right.values[state.sortKey];
184
+ if (a === null) return 1;
185
+ if (b === null) return -1;
186
+ return (a - b) * direction || left.model.localeCompare(right.model);
187
+ });
188
+ }
189
+
190
+ const headerRow = document.createElement("tr");
191
+ const rankHeader = makeCell("th", "Rank");
192
+ rankHeader.title = `Ranked by ${rankMetric} for ${DATASET_LABELS[rankDataset] || rankDataset}`;
193
+ const availabilityHeader = document.createElement("th");
194
+ const availabilityControl = document.createElement("span");
195
+ availabilityControl.className = "availability-control";
196
+ const availabilityLabel = document.createElement("button");
197
+ availabilityLabel.type = "button";
198
+ availabilityLabel.className = "availability-label";
199
+ availabilityLabel.setAttribute("aria-expanded", String(state.availabilityMenuOpen));
200
+ availabilityLabel.setAttribute("aria-label", "Filter models by availability");
201
+ const availabilitySummary = state.availability.size === 2
202
+ ? "All"
203
+ : [...state.availability][0];
204
+ availabilityLabel.innerHTML = `Availability <span>${availabilitySummary}</span><b aria-hidden="true">⌄</b>`;
205
+ availabilityLabel.addEventListener("click", (event) => {
206
+ event.stopPropagation();
207
+ state.availabilityMenuOpen = !state.availabilityMenuOpen;
208
+ render();
209
+ });
210
+ const availabilityFilters = document.createElement("span");
211
+ availabilityFilters.className = "availability-filters";
212
+ availabilityFilters.hidden = !state.availabilityMenuOpen;
213
+ availabilityFilters.addEventListener("click", (event) => event.stopPropagation());
214
+ ["Open", "Closed"].forEach((value) => {
215
+ const button = document.createElement("button");
216
+ button.type = "button";
217
+ button.className = `availability-filter ${value.toLowerCase()}`;
218
+ button.classList.toggle("is-active", state.availability.has(value));
219
+ button.setAttribute("aria-pressed", String(state.availability.has(value)));
220
+ button.setAttribute("aria-label", `Toggle ${value.toLowerCase()} models`);
221
+ button.textContent = value;
222
+ button.addEventListener("click", () => {
223
+ if (state.availability.has(value) && state.availability.size > 1) state.availability.delete(value);
224
+ else state.availability.add(value);
225
+ render();
226
+ });
227
+ availabilityFilters.append(button);
228
+ });
229
+ availabilityControl.append(availabilityLabel, availabilityFilters);
230
+ availabilityHeader.append(availabilityControl);
231
+ headerRow.append(rankHeader, makeCell("th", "Model"), availabilityHeader);
232
+ columns.forEach((column) => {
233
+ const header = document.createElement("th");
234
+ if (isMatrix && column.key.startsWith("combined|")) header.classList.add("combined-score");
235
+ const button = document.createElement("button");
236
+ button.type = "button";
237
+ button.className = "sort-button";
238
+ if (state.sortKey === column.key) button.classList.add(`is-${state.sortDirection}`);
239
+ button.textContent = column.label;
240
+ button.setAttribute("aria-label", `Sort by ${column.label}`);
241
+ button.addEventListener("click", () => {
242
+ if (state.sortKey === column.key) {
243
+ state.sortDirection = state.sortDirection === "asc" ? "desc" : "asc";
244
+ } else {
245
+ state.sortKey = column.key;
246
+ state.sortDirection = "asc";
247
+ }
248
+ render();
249
+ });
250
+ header.append(button);
251
+ headerRow.append(header);
252
+ });
253
+ head.replaceChildren(headerRow);
254
+
255
+ const rows = records.map((record) => {
256
+ const row = document.createElement("tr");
257
+ const modelCell = document.createElement("td");
258
+ const modelWrap = document.createElement("div");
259
+ modelWrap.className = "model-cell";
260
+ const model = document.createElement("span");
261
+ model.className = "model-name";
262
+ model.textContent = record.model;
263
+ modelWrap.append(model);
264
+ if (record.url) {
265
+ const link = document.createElement("a");
266
+ link.className = "model-link";
267
+ link.href = record.url;
268
+ link.target = "_blank";
269
+ link.rel = "noreferrer";
270
+ link.title = `Open ${record.model}`;
271
+ link.setAttribute("aria-label", `Open ${record.model} model page`);
272
+ link.innerHTML = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14 5h5v5m0-5-8 8M19 14v4a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h4"/></svg>';
273
+ modelWrap.append(link);
274
+ }
275
+ modelCell.append(modelWrap);
276
+
277
+ const rank = ranks.get(record.model);
278
+ const rankCell = makeCell("td", rank ? `#${rank}` : "—", `rank${rank <= 3 ? " rank-top" : ""}`);
279
+
280
+ const availabilityCell = document.createElement("td");
281
+ const badge = document.createElement("span");
282
+ badge.className = `availability-badge ${record.availability.toLowerCase()}`;
283
+ badge.textContent = record.availability;
284
+ availabilityCell.append(badge);
285
+ row.append(rankCell, modelCell, availabilityCell);
286
+
287
+ columns.forEach((column) => {
288
+ const value = record.values[column.key];
289
+ const heat = state.colorScores ? `heat-cell${heatClass(value, ranges.get(column.key))}` : "";
290
+ const cell = makeCell("td", value === null ? "—" : value.toFixed(2), heat);
291
+ if (isMatrix && column.key.startsWith("combined|")) cell.classList.add("combined-score");
292
+ row.append(cell);
293
+ });
294
+ return row;
295
+ });
296
+ body.replaceChildren(...rows);
297
+
298
+ document.querySelector("#table-title").textContent = isMatrix
299
+ ? `${matrixMetric} across all datasets`
300
+ : `${DATASET_LABELS[dataset] || dataset} leaderboard`;
301
+ const colorNote = state.colorScores
302
+ ? " Colors are scaled separately within the WER and CER metric families: green is better, red is worse."
303
+ : "";
304
+ document.querySelector("#table-description").textContent = (isMatrix
305
+ ? `Rank is based on Overall ${matrixMetric}. Scores are percentages; lower is better.`
306
+ : "Rank is based on WER. Scores are percentages; lower is better.") + colorNote;
307
+ document.querySelector("#result-count").textContent = `${records.length} ${records.length === 1 ? "model" : "models"}`;
308
+ document.querySelector("#empty-state").hidden = records.length !== 0;
309
+ table.hidden = records.length === 0;
310
+ }
311
+
312
+ function setView(view) {
313
+ state.view = view;
314
+ const isMatrix = view === "matrix";
315
+ document.querySelector("#leaderboards").classList.toggle("matrix-view", isMatrix);
316
+ document.querySelector(".matrix-metric-field").hidden = !isMatrix;
317
+ document.querySelectorAll(".view-button").forEach((button) => {
318
+ const active = button.dataset.view === view;
319
+ button.classList.toggle("is-active", active);
320
+ button.setAttribute("aria-pressed", String(active));
321
+ });
322
+ state.sortKey = isMatrix
323
+ ? `combined|${currentMatrixMetric()}`
324
+ : `${currentDataset()}|WER`;
325
+ state.sortDirection = "asc";
326
+ render();
327
+ }
328
+
329
+ function activateTab(name, updateHash = true) {
330
+ const validName = ["leaderboards", "datasets", "about"].includes(name) ? name : "leaderboards";
331
+ document.querySelectorAll(".tab").forEach((tab) => {
332
+ const active = tab.dataset.tab === validName;
333
+ tab.classList.toggle("is-active", active);
334
+ tab.setAttribute("aria-selected", String(active));
335
+ });
336
+ document.querySelectorAll(".panel").forEach((panel) => {
337
+ const active = panel.id === validName;
338
+ panel.classList.toggle("is-active", active);
339
+ panel.hidden = !active;
340
+ });
341
+ if (updateHash) history.replaceState(null, "", `#${validName}`);
342
+ }
343
+
344
+ function buildControls() {
345
+ const datasetOptions = document.querySelector("#dataset-options");
346
+ state.datasets.forEach((dataset, index) => {
347
+ const label = document.createElement("label");
348
+ label.className = "choice-pill";
349
+ if (dataset === "combined") label.classList.add("combined-choice");
350
+ const input = document.createElement("input");
351
+ input.type = "radio";
352
+ input.name = "dataset";
353
+ input.value = dataset;
354
+ input.checked = index === 0;
355
+ input.addEventListener("change", () => {
356
+ state.sortKey = `${dataset}|WER`;
357
+ state.sortDirection = "asc";
358
+ render();
359
+ });
360
+ label.append(input, document.createTextNode(DATASET_LABELS[dataset] || dataset));
361
+ datasetOptions.append(label);
362
+ });
363
+
364
+ const matrixOptions = document.querySelector("#matrix-metric-options");
365
+ METRICS.forEach((metric, index) => {
366
+ const matrixLabel = document.createElement("label");
367
+ matrixLabel.className = "choice-pill";
368
+ const matrixInput = document.createElement("input");
369
+ matrixInput.type = "radio";
370
+ matrixInput.name = "matrix-metric";
371
+ matrixInput.value = metric;
372
+ matrixInput.checked = index === 0;
373
+ matrixInput.addEventListener("change", () => {
374
+ state.sortKey = `combined|${metric}`;
375
+ state.sortDirection = "asc";
376
+ render();
377
+ });
378
+ matrixLabel.append(matrixInput, document.createTextNode(metric));
379
+ matrixOptions.append(matrixLabel);
380
+ });
381
+
382
+ document.querySelector("#color-toggle").addEventListener("click", (event) => {
383
+ state.colorScores = !state.colorScores;
384
+ event.currentTarget.classList.toggle("is-active", state.colorScores);
385
+ event.currentTarget.setAttribute("aria-pressed", String(state.colorScores));
386
+ render();
387
+ });
388
+ document.querySelectorAll(".view-button").forEach((button) => button.addEventListener("click", () => setView(button.dataset.view)));
389
+ document.querySelectorAll(".tab").forEach((tab) => tab.addEventListener("click", () => activateTab(tab.dataset.tab)));
390
+ document.querySelector("#theme-toggle").addEventListener("click", () => {
391
+ setTheme(document.documentElement.dataset.theme === "dark" ? "light" : "dark");
392
+ });
393
+ document.addEventListener("click", () => {
394
+ if (!state.availabilityMenuOpen) return;
395
+ state.availabilityMenuOpen = false;
396
+ render();
397
+ });
398
+ document.addEventListener("keydown", (event) => {
399
+ if (event.key !== "Escape" || !state.availabilityMenuOpen) return;
400
+ state.availabilityMenuOpen = false;
401
+ render();
402
+ });
403
+ setTheme(document.documentElement.dataset.theme, false);
404
+ }
405
+
406
+ async function start() {
407
+ try {
408
+ const response = await fetch("results.csv");
409
+ if (!response.ok) throw new Error(`Could not load results.csv (${response.status})`);
410
+ ingest(parseCsv(await response.text()));
411
+ buildControls();
412
+ activateTab(location.hash.slice(1), false);
413
+ render();
414
+ } catch (error) {
415
+ document.querySelector("#table-title").textContent = "Leaderboard unavailable";
416
+ document.querySelector("#leaderboard-table").hidden = true;
417
+ const empty = document.querySelector("#empty-state");
418
+ empty.hidden = false;
419
+ empty.querySelector("h3").textContent = "Could not load results";
420
+ empty.querySelector("p").textContent = error.message;
421
+ }
422
+ }
423
+
424
+ if (typeof module !== "undefined") {
425
+ module.exports = { heatClass, ingest, matrixRanges, parseCsv, rankRecords, setTheme, state };
426
+ }
427
+
428
+ if (typeof document !== "undefined") start();
index.html ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
7
+ name="description"
8
+ content="A comparative leaderboard for Armenian automatic speech recognition models."
9
+ />
10
+ <title>ArmBench-ASR: Armenian Speech Recognition in the Real World</title>
11
+ <script>
12
+ (() => {
13
+ let saved = null;
14
+ try { saved = localStorage.getItem("arm-asr-theme"); } catch (_) {}
15
+ const theme = saved || (matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
16
+ document.documentElement.dataset.theme = theme;
17
+ })();
18
+ </script>
19
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
20
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
21
+ <link
22
+ href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&amp;family=Manrope:wght@600;700;800&amp;display=swap"
23
+ rel="stylesheet"
24
+ />
25
+ <link rel="stylesheet" href="style.css" />
26
+ <script src="app.js" defer></script>
27
+ </head>
28
+ <body>
29
+ <main class="shell">
30
+ <header class="hero">
31
+ <div class="hero-tools">
32
+ <button class="theme-toggle" id="theme-toggle" type="button" aria-label="Switch color theme">
33
+ <svg class="sun-icon" viewBox="0 0 24 24" aria-hidden="true">
34
+ <circle cx="12" cy="12" r="3.5"></circle>
35
+ <path d="M12 2v2m0 16v2M4.9 4.9l1.4 1.4m11.4 11.4 1.4 1.4M2 12h2m16 0h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"></path>
36
+ </svg>
37
+ <svg class="moon-icon" viewBox="0 0 24 24" aria-hidden="true">
38
+ <path d="M20.2 15.1A8.5 8.5 0 0 1 8.9 3.8a8.5 8.5 0 1 0 11.3 11.3Z"></path>
39
+ </svg>
40
+ </button>
41
+ </div>
42
+ <div class="hero-copy">
43
+ <h1><span class="heading-flag" role="img" aria-label="Armenian flag">🇦🇲</span> ArmBench-ASR: Armenian Speech Recognition in the Real World</h1>
44
+ <p class="lede">
45
+ <span class="version-badge">v0.1</span>
46
+ A clear, comparable view of Armenian ASR performance across public and
47
+ private evaluation sets.
48
+ </p>
49
+ </div>
50
+ <div class="hero-art" aria-hidden="true">
51
+ <span></span><span></span><span></span><span></span><span></span>
52
+ <span></span><span></span><span></span><span></span>
53
+ </div>
54
+ </header>
55
+
56
+ <nav class="tabs" role="tablist" aria-label="Benchmark sections">
57
+ <button class="tab is-active" role="tab" aria-selected="true" data-tab="leaderboards">
58
+ Leaderboards
59
+ </button>
60
+ <button class="tab" role="tab" aria-selected="false" data-tab="datasets">Datasets</button>
61
+ <button class="tab" role="tab" aria-selected="false" data-tab="about">About</button>
62
+ </nav>
63
+
64
+ <section class="panel is-active matrix-view" id="leaderboards" role="tabpanel">
65
+ <div class="view-switch" role="group" aria-label="Leaderboard view">
66
+ <button class="view-button" type="button" data-view="single" aria-pressed="false">Single dataset</button>
67
+ <button class="view-button is-active" type="button" data-view="matrix" aria-pressed="true">All datasets</button>
68
+ </div>
69
+
70
+ <div class="filter-card">
71
+ <fieldset class="field dataset-field">
72
+ <legend>Dataset</legend>
73
+ <div class="choice-options" id="dataset-options"></div>
74
+ </fieldset>
75
+
76
+ <fieldset class="field matrix-metric-field">
77
+ <legend>Metric across all datasets</legend>
78
+ <div class="choice-options" id="matrix-metric-options"></div>
79
+ </fieldset>
80
+ </div>
81
+
82
+ <div class="table-heading">
83
+ <div>
84
+ <h2 id="table-title">Overall leaderboard</h2>
85
+ <p id="table-description">Rank is based on WER. Scores are percentages; lower is better.</p>
86
+ </div>
87
+ <div class="table-tools">
88
+ <button class="color-toggle" id="color-toggle" type="button" aria-pressed="false">
89
+ <span class="color-swatch good"></span><span class="color-swatch mid"></span><span class="color-swatch bad"></span>
90
+ Colors
91
+ </button>
92
+ <span class="result-count" id="result-count" aria-live="polite"></span>
93
+ </div>
94
+ </div>
95
+
96
+ <div class="table-card">
97
+ <div class="table-scroll">
98
+ <table id="leaderboard-table">
99
+ <thead></thead>
100
+ <tbody></tbody>
101
+ </table>
102
+ </div>
103
+ <div class="empty-state" id="empty-state" hidden>
104
+ <h3>No matching models</h3>
105
+ <p>Select Open or Closed in the Availability column to show models.</p>
106
+ </div>
107
+ </div>
108
+ </section>
109
+
110
+ <section class="panel" id="datasets" role="tabpanel" hidden>
111
+ <div class="section-intro">
112
+ <h2>Five datasets, one Armenian benchmark</h2>
113
+ <p>10,113 clips and 20.7 hours of speech spanning read, literary, cinematic, and conversational Armenian. Every model is evaluated on the same fixed test material.</p>
114
+ </div>
115
+ <div class="dataset-grid">
116
+ <article class="dataset-card accent">
117
+ <div class="dataset-card-top"><span>01</span><span class="dataset-tag">Aggregate</span></div>
118
+ <h3>Combined</h3>
119
+ <p>A pooled view across all five sources, balancing large public test sets with smaller domain-focused evaluation data.</p>
120
+ <dl class="dataset-meta"><div><dt>Samples</dt><dd>10,113</dd></div><div><dt>Audio</dt><dd>20.7 h</dd></div><div><dt>Sources</dt><dd>5 datasets</dd></div></dl>
121
+ </article>
122
+ <article class="dataset-card">
123
+ <div class="dataset-card-top"><span>02</span><span class="dataset-tag public">Public</span></div>
124
+ <h3><a class="dataset-source" href="https://mozilladatacollective.com/datasets/cmqinsp2y00xsnr07ra8gxfoi" target="_blank" rel="noreferrer">Common Voice 26 <span>↗</span></a></h3>
125
+ <p>Mozilla Common Voice Scripted Speech 26.0 for Armenian, using the full <code>hy-AM</code> test split released in June 2026.</p>
126
+ <dl class="dataset-meta"><div><dt>Samples</dt><dd>6,892</dd></div><div><dt>Audio</dt><dd>10.8 h</dd></div><div><dt>Style</dt><dd>Read speech</dd></div></dl>
127
+ </article>
128
+ <article class="dataset-card">
129
+ <div class="dataset-card-top"><span>03</span><span class="dataset-tag public">Public</span></div>
130
+ <h3><a class="dataset-source" href="https://huggingface.co/datasets/google/fleurs" target="_blank" rel="noreferrer">FLEURS <span>↗</span></a></h3>
131
+ <p>Google FLEURS Armenian (<code>hy_am</code>) test split. Raw transcriptions retain punctuation and capitalization for strict scoring, with some <a href="https://huggingface.co/datasets/Metric-AI/fleurs-corrections" target="_blank" rel="noreferrer">manual corrections</a> applied.</p>
132
+ <dl class="dataset-meta"><div><dt>Samples</dt><dd>932</dd></div><div><dt>Audio</dt><dd>3.0 h</dd></div><div><dt>Style</dt><dd>Read speech</dd></div></dl>
133
+ </article>
134
+ <article class="dataset-card">
135
+ <div class="dataset-card-top"><span>04</span><span class="dataset-tag private">Private</span></div>
136
+ <h3>Poems</h3>
137
+ <p>Read Armenian poetry with background music, literary vocabulary, expressive phrasing, and text structures underrepresented in general ASR sets.</p>
138
+ <dl class="dataset-meta"><div><dt>Samples</dt><dd>969</dd></div><div><dt>Audio</dt><dd>3.3 h</dd></div><div><dt>Style</dt><dd>Literary</dd></div></dl>
139
+ </article>
140
+ <article class="dataset-card">
141
+ <div class="dataset-card-top"><span>05</span><span class="dataset-tag private">Private</span></div>
142
+ <h3>Movies</h3>
143
+ <p>Armenian movie dialogue with conversational delivery, produced-media acoustics, and occasional background noise.</p>
144
+ <dl class="dataset-meta"><div><dt>Samples</dt><dd>820</dd></div><div><dt>Audio</dt><dd>1.7 h</dd></div><div><dt>Style</dt><dd>Dialogue</dd></div></dl>
145
+ </article>
146
+ <article class="dataset-card">
147
+ <div class="dataset-card-top"><span>06</span><span class="dataset-tag private">Private</span></div>
148
+ <h3>Infocom</h3>
149
+ <p>A compact Armenian news dataset recited by a speaker, designed to evaluate clear narrated speech beyond standard public test sets.</p>
150
+ <dl class="dataset-meta"><div><dt>Samples</dt><dd>500</dd></div><div><dt>Audio</dt><dd>1.9 h</dd></div><div><dt>Style</dt><dd>Narrated news</dd></div></dl>
151
+ </article>
152
+ </div>
153
+ </section>
154
+
155
+ <section class="panel" id="about" role="tabpanel" hidden>
156
+ <div class="about-grid">
157
+ <div class="section-intro">
158
+ <h2>Reading the benchmark</h2>
159
+ <p>
160
+ Armenian ASR Benchmark compares automatic speech recognition systems on a varied
161
+ Armenian evaluation suite. Every score is an error rate, so lower values are better.
162
+ </p>
163
+ <p>
164
+ The benchmark aims to bring clarity to the Armenian ASR landscape, make model comparisons easier, and help model creators identify strengths, gaps, and opportunities for meaningful improvement.
165
+ </p>
166
+ </div>
167
+ <div class="definition-list">
168
+ <article><strong>WER</strong><span>Word error rate after strict, punctuation-preserving preprocessing.</span></article>
169
+ <article><strong>CER</strong><span>Character error rate after strict, punctuation-preserving preprocessing.</span></article>
170
+ <article><strong>WER-norm</strong><span>Word error rate after text normalization.</span></article>
171
+ <article><strong>CER-norm</strong><span>Character error rate after text normalization.</span></article>
172
+ </div>
173
+ </div>
174
+ <div class="note">
175
+ <strong>Availability</strong>
176
+ <p><b>Open</b> means model weights are publicly available. <b>Closed</b> means access is provided through a hosted product or API.</p>
177
+ </div>
178
+ <div class="note">
179
+ <strong>API settings</strong>
180
+ <p>Hosted systems use fixed model identifiers and transcription-only prompts. Evaluated Gemini runs use temperature 0, a 1,000-token output cap, and audio limited to 40 seconds. Thinking is disabled or set to the lowest applicable level: budget 0 for Gemini 2.5 Flash, budget 128 for Gemini 2.5 Pro, and <b>MINIMAL</b> for Gemini 3.1 Flash Lite, 3.5 Flash Lite, and 3.6 Flash.</p>
181
+ </div>
182
+
183
+ <section class="method-section">
184
+ <div class="section-intro compact">
185
+ <h2>Cleaning without hiding mistakes</h2>
186
+ <p>Original references and predictions remain auditable. The benchmark derives strict and normalized text from both sides with the same deterministic pipeline, so normalization never changes only one side of a comparison.</p>
187
+ </div>
188
+ <div class="pipeline-grid">
189
+ <article class="pipeline-card">
190
+ <span>01</span><h3>Source fidelity</h3>
191
+ <p>Predictions are kept verbatim. FLEURS uses raw transcriptions when available, preserving case and punctuation for strict evaluation.</p>
192
+ </article>
193
+ <article class="pipeline-card">
194
+ <span>02</span><h3>Strict preprocessing</h3>
195
+ <p>Unicode NFKC, Armenian punctuation, quotes, apostrophes, hyphens, grouped numbers, spacing, trailing segment punctuation, capitalization, and whitespace are made consistent.</p>
196
+ </article>
197
+ <article class="pipeline-card">
198
+ <span>03</span><h3>Normalized scoring</h3>
199
+ <p>Text is lowercased; standalone Armenian “Եվ” and hyphenated suffixes are canonicalized; dashes become spaces; Armenian, English, Russian letters and digits are retained. Other punctuation is removed, except separators in recognized <code>HH:MM</code> clock times, which are preserved in Armenian form (<code>12։00</code>).</p>
200
+ </article>
201
+ </div>
202
+ <p class="method-footnote">Both views are published: <b>WER / CER</b> reflect the stricter cleaned transcription, while <b>WER-norm / CER-norm</b> reduce formatting and orthographic noise.</p>
203
+ </section>
204
+
205
+ <section class="lab-card">
206
+ <div>
207
+ <h2>Metric AI Lab</h2>
208
+ <p>Armenian ASR Benchmark is a Metric AI Lab project. The applied AI research lab builds production systems across custom language and vision-language models, multilingual voice agents, Physical AI, retrieval, and analytics—while publishing frontier research and open benchmarks.</p>
209
+ </div>
210
+ <a href="https://metricailab.com" target="_blank" rel="noreferrer">Visit Metric AI Lab <span>↗</span></a>
211
+ </section>
212
+ </section>
213
+
214
+ <footer>
215
+ <span>Armenian ASR Benchmark · v0.1</span>
216
+ <span>A Metric AI Lab project · Built for transparent Armenian speech recognition evaluation.</span>
217
+ </footer>
218
+ </main>
219
+ </body>
220
+ </html>
results.csv ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ model,model_url,availability,standard,,,,,,,,,,,,,,,,,,,,,,,
2
+ ,,,combined,,,,mcv26,,,,fleurs,,,,poems,,,,movies,,,,infocom_may_26,,,
3
+ ,,,WER,CER,WER-norm,CER-norm,WER,CER,WER-norm,CER-norm,WER,CER,WER-norm,CER-norm,WER,CER,WER-norm,CER-norm,WER,CER,WER-norm,CER-norm,WER,CER,WER-norm,CER-norm
4
+ google/gemini-2.5-pro,https://ai.google.dev/gemini-api/docs/models/gemini-2.5-pro,Closed,14.307,4.0955,6.4197,2.4423,9.6864,2.5433,6.3459,1.9419,8.5084,2.0004,2.9433,1.1523,24.7593,5.3359,3.9983,1.2723,38.9844,16.3223,18.8966,10.1838,11.91,3.9989,4.5688,2.7964
5
+ hispeech/model-23012026,https://www.hispeech.ai/api.html,Closed,16.8129,4.2261,7.4986,2.2817,11.0856,2.4903,7.3486,1.761,13.7435,3.3926,5.87,1.8887,22.7285,5.4921,4.6175,1.5223,41.6997,16.3958,19.4237,9.6334,14.7849,3.3687,4.7462,1.5464
6
+ google/gemini-2.5-flash,https://ai.google.dev/gemini-api/docs/models/gemini-2.5-flash,Closed,17.5469,4.6513,8.6718,2.8069,12.319,2.98,8.5497,2.3472,10.598,2.4786,3.9687,1.4569,28.1633,6.2153,5.6564,1.5213,46.0284,18.7923,27.1194,12.545,14.0014,3.7409,4.7969,2.2266
7
+ talk2edit,https://talk2edit.com,Closed,17.8337,4.2155,8.0151,2.3704,12.3693,2.6625,8.5198,2.0073,10.5202,2.3319,4.1683,1.3561,25.0855,5.5935,5.7719,1.5641,46.0725,17.6354,20.9259,10.8242,15.7326,3.1442,4.0999,1.3002
8
+ elevenlabs/scribe_v2,https://elevenlabs.io/docs/overview/capabilities/speech-to-text,Closed,17.9525,4.3362,8.7695,2.5805,12.0917,2.4134,7.5713,1.7013,10.0811,2.3679,4.135,1.4697,26.0273,5.8995,8.0753,2.0474,49.9515,19.3585,28.5865,13.1939,14.1467,3.574,4.6702,2.0372
9
+ hispeech/model-01052025,https://www.hispeech.ai/api.html,Closed,17.9822,4.48,8.6709,2.6206,10.2156,2.205,6.8155,1.6571,15.5719,3.7499,8.1204,2.4814,22.9179,5.5556,4.8484,1.6561,49.8545,19.2636,26.7504,12.4295,18.2915,4.0996,7.1605,2.0652
10
+ google/gemini-3.6-flash,https://ai.google.dev/gemini-api/docs/models/gemini-3.6-flash,Closed,19.6098,5.2995,10.1194,3.5158,16.1478,4.0149,10.1325,3.0682,11.7095,2.8982,5.2104,1.9015,25.8694,6.329,8.0753,2.5018,46.8218,18.8627,27.4971,13.34,13.3127,4.1459,5.6207,2.9026
11
+ wavam/default,https://wav.am,Closed,20.1028,4.9044,9.3242,2.7368,12.6209,2.9858,9.3149,2.3614,13.4156,3.3471,6.3855,2.1722,30.7834,7.3266,7.5716,2.3587,53.5044,18.3362,22.9377,9.5349,16.3139,3.7337,5.0124,1.6387
12
+ google/gemini-3.1-flash-lite,https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-lite,Closed,20.4652,6.2546,12.4615,4.6047,16.4105,4.615,12.9892,4.0185,11.0926,2.7537,5.1217,1.8097,26.4008,7.0928,9.702,3.5157,55.0295,26.8234,36.2734,20.9757,13.3253,3.9878,5.2215,2.6358
13
+ tbb-asr,https://asr.tbb.rip,Closed,20.5739,5.5345,10.7268,3.4857,8.1509,1.7125,5.5219,1.29,17.0223,5.0072,8.9241,3.7525,31.2727,7.51,11.5909,3.0966,61.8708,26.5403,37.2925,18.55,24.2876,5.9792,10.2085,3.5103
14
+ wavam/streaming,https://wav.am,Closed,21.1144,5.1478,10.3147,2.9628,13.4723,3.1688,10.1979,2.5488,15.3662,3.6728,8.3865,2.4912,31.3832,7.2507,8.3692,2.2788,54.2537,19.2146,22.7357,10.2246,17.4828,4.0445,6.3051,1.9367
15
+ openai/gpt-transcribe,https://developers.openai.com/api/docs/models/gpt-transcribe,Closed,22.5595,5.9631,14.1197,4.2576,17.2917,4.1186,13.8105,3.5182,15.9275,3.9751,8.7966,2.8454,30.131,7.241,13.6531,3.5603,52.1114,23.0863,34.6042,17.7397,17.6913,4.126,7.0401,2.3361
16
+ nvidia/stt_hy_fastconformer_hybrid_large_pc,https://huggingface.co/nvidia/stt_hy_fastconformer_hybrid_large_pc,Open,24.9471,7.2708,14.9855,5.1482,7.6985,1.5642,5.229,1.1576,16.3721,4.9419,8.7246,3.7623,31.32,7.5453,11.6854,3.1524,60.9451,26.3582,37.5911,18.7198,24.5024,5.9968,10.4049,3.5285
17
+ google/gemini-3.5-flash-lite,https://ai.google.dev/gemini-api/docs/models/gemini-3.5-flash-lite,Closed,26.2101,8.3246,17.6418,6.5826,23.6786,7.7033,19.5952,6.944,14.8049,4.1232,8.7357,3.1433,33.7402,9.2069,15.521,5.1867,56.1668,25.1706,38.9265,20.1264,17.249,5.3594,8.4152,3.8216
18
+ chillarmo/whisper-large-v3-turbo-armenian,https://huggingface.co/chillarmo/whisper-large-v3-turbo-armenian,Open,33.1251,13.6194,23.3776,11.3725,12.9432,2.5861,9.6292,2.0609,25.0361,9.393,16.0302,7.8195,55.1113,26.9981,35.6858,22.704,82.0947,39.4393,59.5362,30.5854,49.2639,29.0766,37.3994,26.762
19
+ arampacha/whisper-large-hy-2,https://huggingface.co/arampacha/whisper-large-hy-2,Open,33.283,8.1694,22.433,5.6564,23.1886,4.7625,19.6082,4.1286,17.856,3.7587,10.9916,2.6153,44.4363,11.0406,25.5326,6.4506,77.669,32.3799,55.9431,23.5714,39.8496,8.9892,17.1662,4.6599
20
+ facebook/omniASR-LLM-3B,https://huggingface.co/facebook/omniASR-LLM-3B,Open,39.2308,10.9837,16.8896,6.6404,27.3266,4.8987,9.4384,2.298,26.9201,5.4025,6.5351,2.2249,56.5558,16.7054,26.3796,9.3765,89.4516,57.1848,63.3258,48.3842,36.3303,7.5905,8.7384,2.9628
21
+ facebook/omniASR-LLM-1B,https://huggingface.co/facebook/omniASR-LLM-1B,Open,39.6051,10.7221,16.9431,6.32,28.0104,5.1484,10.168,2.5503,27.4203,5.4759,7.1393,2.3076,55.7526,15.2889,25.341,7.82,89.8539,54.4434,59.6566,44.753,36.9179,7.6296,9.898,3.0229
22
+ facebook/omniASR-CTC-3B,https://huggingface.co/facebook/omniASR-CTC-3B,Open,41.1224,11.8272,21.4443,7.727,30.4883,5.3088,13.5823,2.688,28.9152,5.5969,9.2789,2.4137,58.2351,14.6111,30.2455,7.018,86.9501,68.524,77.1309,64.3544,37.2275,7.6903,10.8612,3.0929
23
+ cast/whisper-large-v3-mwa-hy,https://huggingface.co/Center-of-Advanced-Software-Technologies/whisper-large-v3-mwa-hy,Open,41.6865,10.1111,22.5511,6.1765,29.5828,5.3063,12.1997,2.6544,31.9996,7.411,13.2531,4.358,52.8174,14.2677,30.2603,8.748,75.227,31.1618,50.4261,21.9763,56.3404,14.1713,38.8252,9.9003
24
+ facebook/omniASR-CTC-1B,https://huggingface.co/facebook/omniASR-CTC-1B,Open,41.9099,10.4939,21.4817,6.3275,33.8327,6.0835,17.5728,3.4618,31.1659,6.0664,12.3275,2.9041,54.0054,12.1948,22.3615,4.3528,80.0577,48.8093,63.3694,42.6041,39.3062,8.1153,13.6683,3.5268
25
+ facebook/omniASR-LLM-300M,https://huggingface.co/facebook/omniASR-LLM-300M,Open,42.4713,11.4939,21.025,7.0071,30.7231,5.6727,13.4008,3.0543,29.7377,6.1456,10.0327,3.0011,59.951,16.1485,32.1653,8.7,92.9765,57.3088,65.5308,46.5174,39.1293,8.1457,13.5986,3.61
26
+ facebook/mms-1b-all,https://huggingface.co/facebook/mms-1b-all,Open,48.6009,10.7795,30.4742,6.5337,43.0794,7.7882,29.2,5.2074,34.606,6.3033,16.5623,3.1892,59.6641,14.0066,30.9222,6.2569,83.5855,37.9021,69.7761,29.0887,44.8537,8.4724,21.9061,3.9048
27
+ google/gemma-4-e4b-it,https://huggingface.co/google/gemma-4-e4b-it,Open,50.6746,18.9239,41.7823,16.2226,48.4173,17.8457,43.1284,16.1956,37.3402,12.8714,30.2644,11.3516,58.3259,20.7961,42.1031,15.6847,79.7761,42.2581,66.2479,35.4199,44.3925,15.2009,32.3554,12.8153
28
+ facebook/omniASR-CTC-300M,https://huggingface.co/facebook/omniASR-CTC-300M,Open,51.743,12.7912,34.645,8.7434,44.9164,8.3903,30.996,5.8332,40.4468,7.9296,23.696,4.8357,63.633,15.2827,37.8934,7.7029,86.8801,51.8881,75.4837,46.1984,47.9497,9.7258,25.9046,5.2149
29
+ google/gemma-4-e2b-it,https://huggingface.co/google/gemma-4-e2b-it,Open,53.5029,20.7604,44.578,17.6968,50.4164,18.8588,45.5343,17.4727,42.9199,18.2358,34.4715,13.5592,59.9042,22.157,44.7634,17.1837,80.2081,40.8992,67.8116,35.16,49.2134,18.0144,35.9103,14.9587
30
+ openai/whisper-large-v3,https://huggingface.co/openai/whisper-large-v3,Open,65.131,20.8108,58.645,19.0484,61.7163,17.1442,59.0287,16.5047,51.9618,14.6363,45.4687,13.1643,71.0738,28.6474,58.7732,25.5887,105.8362,52.0858,95.3176,48.8992,55.3737,16.2242,45.8019,13.6535
style.css ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --ink: #19212d;
3
+ --muted: #697587;
4
+ --line: #e7e8eb;
5
+ --surface: #ffffff;
6
+ --soft: #f7f7f6;
7
+ --accent: #356fbe;
8
+ --accent-dark: #24508e;
9
+ --accent-soft: #edf4ff;
10
+ --blue-soft: #edf3ff;
11
+ --green: #21855b;
12
+ --shadow: 0 18px 50px rgba(33, 39, 49, 0.08);
13
+ color-scheme: light;
14
+ }
15
+
16
+ html[data-theme="dark"] {
17
+ --ink: #eef1f6;
18
+ --muted: #9da8b8;
19
+ --line: #303744;
20
+ --surface: #171c24;
21
+ --soft: #202630;
22
+ --accent: #78aaf0;
23
+ --accent-dark: #a8caff;
24
+ --accent-soft: #1d2d43;
25
+ --blue-soft: #202a3b;
26
+ --green: #62c997;
27
+ --shadow: 0 20px 55px rgba(0, 0, 0, 0.34);
28
+ color-scheme: dark;
29
+ }
30
+
31
+ * { box-sizing: border-box; }
32
+
33
+ html { scroll-behavior: smooth; }
34
+
35
+ body {
36
+ margin: 0;
37
+ color: var(--ink);
38
+ background:
39
+ radial-gradient(circle at 8% 0%, rgba(53, 111, 190, 0.09), transparent 25rem),
40
+ #fbfbfa;
41
+ font-family: "DM Sans", system-ui, sans-serif;
42
+ -webkit-font-smoothing: antialiased;
43
+ }
44
+
45
+ button, input, select { font: inherit; }
46
+ button, select, label { -webkit-tap-highlight-color: transparent; }
47
+
48
+ .shell { width: min(1460px, calc(100% - 40px)); margin: 0 auto; padding: 34px 0 24px; }
49
+
50
+ .hero {
51
+ position: relative;
52
+ min-height: 190px;
53
+ overflow: hidden;
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: space-between;
57
+ padding: 30px 52px;
58
+ border: 1px solid rgba(53, 111, 190, 0.16);
59
+ border-radius: 28px;
60
+ background: linear-gradient(118deg, #fff 18%, #f7faff 62%, #edf4ff 100%);
61
+ box-shadow: var(--shadow);
62
+ }
63
+
64
+ .hero::before {
65
+ content: "";
66
+ position: absolute;
67
+ width: 240px;
68
+ height: 240px;
69
+ right: 12%;
70
+ top: -58%;
71
+ border: 1px solid rgba(53, 111, 190, 0.15);
72
+ border-radius: 50%;
73
+ }
74
+
75
+ .hero-tools { position: absolute; z-index: 3; top: 20px; right: 22px; display: flex; align-items: center; gap: 9px; }
76
+ .theme-toggle { display: grid; place-items: center; width: 38px; height: 38px; padding: 0; border: 1px solid rgba(25, 33, 45, 0.12); border-radius: 11px; color: #4e5b6e; background: rgba(255, 255, 255, 0.72); backdrop-filter: blur(8px); cursor: pointer; transition: 150ms ease; }
77
+ .theme-toggle:hover { border-color: rgba(53, 111, 190, 0.4); color: var(--accent-dark); transform: translateY(-1px); }
78
+ .theme-toggle svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
79
+ .moon-icon { display: none; }
80
+ html[data-theme="dark"] .sun-icon { display: none; }
81
+ html[data-theme="dark"] .moon-icon { display: block; }
82
+
83
+ .hero-copy { position: relative; z-index: 1; max-width: 980px; }
84
+ .eyebrow { display: flex; align-items: center; gap: 9px; margin: 0; color: var(--accent-dark); font-size: 12px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; }
85
+ .eyebrow-mark { width: 18px; height: 3px; border-radius: 2px; background: var(--accent); }
86
+ h1, h2, h3 { font-family: "Manrope", system-ui, sans-serif; }
87
+ h1 { margin: 8px 0 10px; font-size: clamp(38px, 5vw, 60px); line-height: 0.98; letter-spacing: -0.055em; }
88
+ .heading-flag { display: inline-block; margin-right: 0.08em; font-size: 0.9em; line-height: 1; letter-spacing: 0; transform: translateY(-0.02em); }
89
+ .lede { max-width: 710px; margin: 0; color: var(--muted); font-size: clamp(16px, 2vw, 19px); line-height: 1.6; }
90
+ .version-badge { display: inline-flex; align-items: center; margin-right: 7px; padding: 2px 7px; border: 1px solid rgba(53, 111, 190, 0.25); border-radius: 999px; color: var(--accent-dark); background: var(--accent-soft); font-size: 0.68em; font-weight: 800; letter-spacing: 0.04em; vertical-align: 0.12em; }
91
+
92
+ .hero-art { z-index: 1; display: flex; align-items: center; gap: 7px; height: 92px; padding: 0 34px; }
93
+ .hero-art span { display: block; width: 8px; border-radius: 10px; background: linear-gradient(180deg, var(--accent), #79a9eb); opacity: 0.82; }
94
+ .hero-art span:nth-child(1), .hero-art span:nth-child(9) { height: 20%; }
95
+ .hero-art span:nth-child(2), .hero-art span:nth-child(8) { height: 42%; }
96
+ .hero-art span:nth-child(3), .hero-art span:nth-child(7) { height: 68%; }
97
+ .hero-art span:nth-child(4), .hero-art span:nth-child(6) { height: 92%; }
98
+ .hero-art span:nth-child(5) { height: 60%; }
99
+
100
+ .tabs { display: flex; gap: 6px; margin: 20px 0; padding: 6px; width: fit-content; border: 1px solid var(--line); border-radius: 14px; background: rgba(255,255,255,0.86); }
101
+ .tab { padding: 10px 18px; border: 0; border-radius: 9px; color: var(--muted); background: transparent; cursor: pointer; font-weight: 600; transition: 150ms ease; }
102
+ .tab:hover { color: var(--ink); background: var(--soft); }
103
+ .tab.is-active { color: #fff; background: var(--ink); box-shadow: 0 5px 15px rgba(25, 33, 45, 0.18); }
104
+
105
+ .panel { animation: reveal 240ms ease; }
106
+ @keyframes reveal { from { opacity: 0; transform: translateY(5px); } }
107
+
108
+ .view-switch { display: inline-flex; gap: 4px; margin-bottom: 14px; padding: 4px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); }
109
+ .view-button { padding: 9px 14px; border: 0; border-radius: 8px; color: var(--muted); background: transparent; cursor: pointer; font-size: 13px; font-weight: 700; }
110
+ .view-button:hover { color: var(--ink); background: var(--soft); }
111
+ .view-button.is-active { color: #fff; background: #315f9d; box-shadow: 0 4px 12px rgba(36, 80, 142, 0.24); }
112
+
113
+ .filter-card {
114
+ display: grid;
115
+ gap: 20px;
116
+ padding: 20px;
117
+ border: 1px solid var(--line);
118
+ border-radius: 18px;
119
+ background: rgba(255,255,255,0.92);
120
+ }
121
+ .filter-card { grid-template-columns: 1fr; }
122
+ .dataset-field { grid-column: 1 / -1; }
123
+ .matrix-view .dataset-field { display: none; }
124
+ .matrix-metric-field { grid-column: 1 / -1; width: auto; }
125
+ .field { min-width: 0; }
126
+ .field > label, fieldset legend { display: block; margin-bottom: 8px; color: #4c5665; font-size: 12px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
127
+ fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
128
+ .choice-pill input { position: absolute; opacity: 0; pointer-events: none; }
129
+ .choice-options { display: flex; flex-wrap: wrap; gap: 8px; }
130
+ .choice-pill { position: relative; display: inline-flex; align-items: center; min-height: 40px; padding: 0 14px; border: 1px solid #dadde2; border-radius: 10px; color: #586475; background: #fff; cursor: pointer; font-size: 13px; font-weight: 700; transition: 150ms ease; }
131
+ .choice-pill:hover { border-color: #b8c3d2; color: var(--ink); }
132
+ .choice-pill:has(input:checked) { border-color: #4f83c9; color: #fff; background: #315f9d; box-shadow: 0 4px 12px rgba(36, 80, 142, 0.22); }
133
+ .choice-pill.combined-choice:has(input:checked) { border-color: #142d4f; background: #0d2a4f; box-shadow: 0 4px 15px rgba(7, 25, 49, 0.42); }
134
+ .color-toggle { display: flex; align-items: center; justify-content: center; gap: 7px; height: 30px; padding: 0 10px; border: 1px solid #dadde2; border-radius: 8px; color: #586475; background: transparent; cursor: pointer; font-size: 12px; font-weight: 700; }
135
+ .color-toggle:hover { border-color: #b8c3d2; color: var(--ink); }
136
+ .color-toggle.is-active { border-color: rgba(53, 111, 190, 0.4); color: var(--accent-dark); background: var(--accent-soft); }
137
+ .color-swatch { width: 6px; height: 13px; border-radius: 3px; opacity: 0.85; }
138
+ .color-swatch.good { background: #22c55e; }
139
+ .color-swatch.mid { margin-left: -4px; background: #eab308; }
140
+ .color-swatch.bad { margin-left: -4px; background: #ef4444; }
141
+ #matrix-metric-options .choice-pill { justify-content: center; width: 94px; padding-inline: 10px; }
142
+
143
+ .table-heading { display: flex; justify-content: space-between; align-items: end; margin: 28px 2px 12px; }
144
+ .table-heading h2 { margin: 0 0 3px; font-size: 21px; letter-spacing: -0.025em; }
145
+ .table-heading p { margin: 0; color: var(--muted); font-size: 13px; }
146
+ .table-tools { display: flex; align-items: center; gap: 8px; }
147
+ .result-count { padding: 6px 10px; border-radius: 999px; color: var(--muted); background: #eeefef; font-size: 12px; font-weight: 700; }
148
+
149
+ .table-card { overflow: hidden; min-height: 180px; border: 1px solid var(--line); border-radius: 18px; background: var(--surface); box-shadow: 0 10px 32px rgba(35, 40, 48, 0.05); }
150
+ .table-scroll { overflow-x: auto; }
151
+ table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 14px; }
152
+ th, td { padding: 10px 16px; border-bottom: 1px solid #eceef0; text-align: right; white-space: nowrap; }
153
+ th { position: sticky; top: 0; z-index: 2; color: #697483; background: #f7f7f6; font-size: 11px; letter-spacing: 0.055em; text-transform: uppercase; }
154
+ th:first-child, td:first-child { position: sticky; left: 0; z-index: 2; width: 64px; min-width: 64px; text-align: center; background: #fff; }
155
+ th:first-child { z-index: 4; background: #f7f7f6; }
156
+ th:nth-child(2), td:nth-child(2) { position: sticky; left: 64px; z-index: 1; width: 100%; min-width: 480px; overflow: hidden; text-align: left; background: #fff; }
157
+ th:nth-child(2) { z-index: 3; background: #f7f7f6; }
158
+ th:nth-child(3), td:nth-child(3) { width: 156px; min-width: 156px; max-width: 156px; text-align: left; }
159
+ th:nth-child(n+4), td:nth-child(n+4) { width: 110px; min-width: 110px; }
160
+ .combined-score { border-right: 2px solid #c8ced7; border-left: 3px solid #aeb7c3; }
161
+ tbody tr:last-child td { border-bottom: 0; }
162
+ tbody tr:hover td { background: #fbfbfa; }
163
+ tbody tr:hover td:first-child { background: #fbfbfa; }
164
+ tbody tr:hover td:nth-child(2) { background: #fbfbfa; }
165
+ .model-cell { display: flex; align-items: center; min-width: 0; }
166
+ .model-name { min-width: 0; overflow: hidden; color: #26374e; font-weight: 700; text-overflow: ellipsis; }
167
+ .model-link { display: inline-grid; flex: 0 0 24px; place-items: center; width: 24px; height: 24px; margin-left: 6px; border-radius: 6px; color: #7d8999; text-decoration: none; }
168
+ .model-link:hover { color: var(--accent-dark); background: var(--accent-soft); }
169
+ .model-link svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
170
+ .rank { color: #7a8492; font: 700 12px "Manrope", sans-serif; }
171
+ .rank.rank-top { color: var(--accent-dark); }
172
+ .availability-badge { display: inline-flex; align-items: center; gap: 7px; padding: 5px 9px; border-radius: 999px; font-size: 12px; font-weight: 700; }
173
+ .availability-badge.open { color: #167149; background: #eaf7f0; }
174
+ .availability-badge.closed { color: #677180; background: #f0f1f3; }
175
+ .availability-control { position: relative; display: inline-block; }
176
+ .availability-label { display: inline-flex; align-items: center; gap: 6px; padding: 5px 7px; border: 0; border-radius: 7px; color: inherit; background: transparent; cursor: pointer; font: inherit; letter-spacing: inherit; text-transform: inherit; }
177
+ .availability-label:hover, .availability-label[aria-expanded="true"] { color: var(--ink); background: #eceef1; }
178
+ .availability-label span { padding: 2px 5px; border-radius: 5px; color: var(--accent-dark); background: var(--accent-soft); font-size: 9px; }
179
+ .availability-label b { color: #9aa3af; font-size: 12px; line-height: 1; transition: transform 150ms ease; }
180
+ .availability-label[aria-expanded="true"] b { transform: rotate(180deg); }
181
+ .availability-filters { position: absolute; z-index: 8; top: calc(100% + 7px); left: 0; display: flex; gap: 5px; padding: 7px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface); box-shadow: 0 10px 28px rgba(25, 33, 45, 0.16); }
182
+ .availability-filters[hidden] { display: none; }
183
+ .availability-filter { min-width: 52px; height: 23px; padding: 0 7px; border: 1px solid #d8dce2; border-radius: 6px; color: #8993a1; background: transparent; cursor: pointer; font-size: 9px; font-weight: 800; letter-spacing: 0.035em; text-transform: uppercase; }
184
+ .availability-filter:hover { color: var(--ink); border-color: #b8c0cb; }
185
+ .availability-filter.open.is-active { border-color: rgba(33, 133, 91, 0.3); color: #167149; background: #eaf7f0; }
186
+ .availability-filter.closed.is-active { border-color: #cfd4db; color: #596575; background: #e9ebee; }
187
+ .sort-button { display: inline-flex; align-items: center; gap: 5px; padding: 0; border: 0; color: inherit; background: none; cursor: pointer; font: inherit; letter-spacing: inherit; text-transform: inherit; }
188
+ .sort-button::after { content: "↕"; color: #a3a9b2; font-size: 12px; }
189
+ .sort-button.is-asc::after { content: "↑"; color: var(--accent); }
190
+ .sort-button.is-desc::after { content: "↓"; color: var(--accent); }
191
+ .heat-cell.heat-score-1 { background: rgba(16, 185, 129, 0.38); }
192
+ .heat-cell.heat-score-2 { background: rgba(132, 204, 22, 0.34); }
193
+ .heat-cell.heat-score-3 { background: rgba(250, 204, 21, 0.38); }
194
+ .heat-cell.heat-score-4 { background: rgba(249, 115, 22, 0.34); }
195
+ .heat-cell.heat-score-5 { background: rgba(244, 63, 94, 0.36); }
196
+ .empty-state { padding: 48px 20px; text-align: center; }
197
+ .empty-state h3 { margin: 0 0 5px; }
198
+ .empty-state p { margin: 0; color: var(--muted); }
199
+
200
+ .section-intro { max-width: 760px; padding: 34px 4px 22px; }
201
+ .section-intro h2 { margin: 9px 0; font-size: clamp(28px, 4vw, 42px); letter-spacing: -0.04em; }
202
+ .section-intro > p:last-child { margin: 0; color: var(--muted); font-size: 16px; line-height: 1.7; }
203
+ .dataset-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
204
+ .dataset-card { display: flex; flex-direction: column; min-height: 310px; padding: 24px; border: 1px solid var(--line); border-radius: 18px; background: #fff; box-shadow: 0 9px 28px rgba(35, 40, 48, 0.04); }
205
+ .dataset-card.accent { background: linear-gradient(135deg, #f5f9ff, #edf4ff); }
206
+ .dataset-card-top { display: flex; align-items: center; justify-content: space-between; }
207
+ .dataset-card-top > span:first-child { color: var(--accent); font: 700 12px "Manrope", sans-serif; }
208
+ .dataset-tag { padding: 5px 8px; border-radius: 999px; color: #697483; background: #eeeff1; font-size: 10px; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase; }
209
+ .dataset-tag.public { color: #167149; background: #eaf7f0; }
210
+ .dataset-tag.private { color: #7556a5; background: #f2ecfb; }
211
+ .dataset-card h3 { margin: 24px 0 7px; font-size: 19px; }
212
+ .dataset-source { color: var(--ink); text-decoration: none; }
213
+ .dataset-source span { color: var(--accent); font-size: 14px; }
214
+ .dataset-source:hover { color: var(--accent-dark); }
215
+ .dataset-card p { margin: 0; color: var(--muted); line-height: 1.55; }
216
+ .dataset-card code { padding: 1px 4px; border-radius: 4px; color: var(--ink); background: var(--soft); font-size: 0.86em; }
217
+ .dataset-meta { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: auto 0 0; padding-top: 22px; }
218
+ .dataset-meta div { padding-top: 10px; border-top: 1px solid var(--line); }
219
+ .dataset-meta dt { color: #949daa; font-size: 9px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; }
220
+ .dataset-meta dd { margin: 3px 0 0; color: var(--ink); font-size: 12px; font-weight: 700; }
221
+
222
+ .about-grid { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 50px; align-items: start; }
223
+ .definition-list { margin-top: 38px; border: 1px solid var(--line); border-radius: 18px; background: #fff; }
224
+ .definition-list article { display: grid; grid-template-columns: 120px 1fr; gap: 18px; padding: 20px; border-bottom: 1px solid var(--line); }
225
+ .definition-list article:last-child { border-bottom: 0; }
226
+ .definition-list strong { color: var(--accent-dark); }
227
+ .definition-list span { color: var(--muted); }
228
+ .note { display: grid; grid-template-columns: 150px 1fr; gap: 20px; margin-top: 18px; padding: 22px; border-radius: 16px; background: var(--blue-soft); }
229
+ .note p { margin: 0; color: #57677e; }
230
+ .method-section { margin-top: 44px; }
231
+ .section-intro.compact { padding-top: 0; }
232
+ .pipeline-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
233
+ .pipeline-card { min-height: 220px; padding: 24px; border: 1px solid var(--line); border-radius: 18px; background: var(--surface); }
234
+ .pipeline-card > span { color: var(--accent); font: 700 11px "Manrope", sans-serif; }
235
+ .pipeline-card h3 { margin: 28px 0 8px; font-size: 18px; }
236
+ .pipeline-card p { margin: 0; color: var(--muted); line-height: 1.6; }
237
+ .method-footnote { margin: 14px 0 0; padding: 18px 20px; border-left: 3px solid var(--accent); border-radius: 0 12px 12px 0; color: var(--muted); background: var(--soft); line-height: 1.6; }
238
+ .method-footnote b { color: var(--ink); }
239
+ .lab-card { display: grid; grid-template-columns: 1fr auto; gap: 40px; align-items: end; margin-top: 44px; padding: 34px; overflow: hidden; border: 1px solid rgba(53, 111, 190, 0.19); border-radius: 22px; background: linear-gradient(125deg, #f5f9ff, #edf4ff); }
240
+ .lab-card h2 { margin: 8px 0 10px; font-size: 30px; letter-spacing: -0.035em; }
241
+ .lab-card p:last-child { max-width: 800px; margin: 0; color: var(--muted); line-height: 1.65; }
242
+ .lab-card a { display: inline-flex; align-items: center; gap: 8px; padding: 12px 16px; border-radius: 11px; color: #fff; background: var(--ink); text-decoration: none; white-space: nowrap; font-weight: 700; }
243
+ .lab-card a:hover { background: var(--accent-dark); }
244
+
245
+ footer { display: flex; justify-content: space-between; gap: 20px; margin-top: 48px; padding: 20px 4px 0; border-top: 1px solid var(--line); color: #8a93a0; font-size: 12px; }
246
+ footer span:first-child { color: #596474; font-weight: 700; }
247
+
248
+ html[data-theme="dark"] body {
249
+ background:
250
+ radial-gradient(circle at 8% 0%, rgba(120, 170, 240, 0.1), transparent 25rem),
251
+ #11151b;
252
+ }
253
+ html[data-theme="dark"] .hero {
254
+ border-color: rgba(120, 170, 240, 0.18);
255
+ background: linear-gradient(118deg, #1c222c 18%, #1d2430 62%, #19283d 100%);
256
+ }
257
+ html[data-theme="dark"] .hero::before { border-color: rgba(120, 170, 240, 0.18); }
258
+ html[data-theme="dark"] .theme-toggle { border-color: #3b4350; color: #cbd3df; background: rgba(23, 28, 36, 0.74); }
259
+ html[data-theme="dark"] .tabs,
260
+ html[data-theme="dark"] .filter-card { background: rgba(23, 28, 36, 0.92); }
261
+ html[data-theme="dark"] .tab.is-active { color: #171c24; background: #eef1f6; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.28); }
262
+ html[data-theme="dark"] .field > label,
263
+ html[data-theme="dark"] fieldset legend { color: #aab4c2; }
264
+ html[data-theme="dark"] .choice-pill,
265
+ html[data-theme="dark"] .color-toggle { border-color: #465064; color: #d9e1ed; background: #202630; }
266
+ html[data-theme="dark"] .choice-pill:hover { border-color: #65738a; color: #fff; background: #27303d; }
267
+ html[data-theme="dark"] .choice-pill:has(input:checked) { border-color: #4f83c9; color: #fff; background: #315f9d; box-shadow: 0 4px 14px rgba(8, 28, 56, 0.38); }
268
+ html[data-theme="dark"] .choice-pill.combined-choice:has(input:checked) { border-color: #2b527f; background: #091f3b; box-shadow: 0 4px 16px rgba(0, 8, 20, 0.64); }
269
+ html[data-theme="dark"] .color-toggle.is-active { border-color: rgba(120, 170, 240, 0.42); color: #a8caff; background: #1d2d43; }
270
+ html[data-theme="dark"] .table-card,
271
+ html[data-theme="dark"] .dataset-card,
272
+ html[data-theme="dark"] .definition-list { background: var(--surface); }
273
+ html[data-theme="dark"] .dataset-card.accent { background: linear-gradient(135deg, #1d2939, #1b304b); }
274
+ html[data-theme="dark"] .dataset-tag { color: #b5bfcb; background: #292f38; }
275
+ html[data-theme="dark"] .dataset-tag.public { color: #7ed6aa; background: #17362b; }
276
+ html[data-theme="dark"] .dataset-tag.private { color: #c5a9ee; background: #302641; }
277
+ html[data-theme="dark"] .lab-card { background: linear-gradient(125deg, #1d2939, #1b304b); }
278
+ html[data-theme="dark"] .lab-card a { color: #171c24; background: #eef1f6; }
279
+ html[data-theme="dark"] .lab-card a:hover { color: #fff; background: var(--accent); }
280
+ html[data-theme="dark"] th { color: #a4afbd; background: #202630; }
281
+ html[data-theme="dark"] th:first-child,
282
+ html[data-theme="dark"] th:nth-child(2) { background: #202630; }
283
+ html[data-theme="dark"] td:first-child,
284
+ html[data-theme="dark"] td:nth-child(2) { background: var(--surface); }
285
+ html[data-theme="dark"] th,
286
+ html[data-theme="dark"] td { border-bottom-color: #2a313c; }
287
+ html[data-theme="dark"] .combined-score { border-right-color: #4b5667; border-left-color: #657185; }
288
+ html[data-theme="dark"] tbody tr:hover td,
289
+ html[data-theme="dark"] tbody tr:hover td:first-child,
290
+ html[data-theme="dark"] tbody tr:hover td:nth-child(2) { background: #1c222b; }
291
+ html[data-theme="dark"] .heat-cell.heat-score-1 { background: rgba(16, 185, 129, 0.42); }
292
+ html[data-theme="dark"] .heat-cell.heat-score-2 { background: rgba(132, 204, 22, 0.38); }
293
+ html[data-theme="dark"] .heat-cell.heat-score-3 { background: rgba(250, 204, 21, 0.38); }
294
+ html[data-theme="dark"] .heat-cell.heat-score-4 { background: rgba(249, 115, 22, 0.38); }
295
+ html[data-theme="dark"] .heat-cell.heat-score-5 { background: rgba(244, 63, 94, 0.42); }
296
+ html[data-theme="dark"] .model-name { color: #dce5f2; }
297
+ html[data-theme="dark"] .model-link { color: #91a0b3; }
298
+ html[data-theme="dark"] .availability-badge.open { color: #7ed6aa; background: #17362b; }
299
+ html[data-theme="dark"] .availability-badge.closed { color: #abb5c3; background: #292f38; }
300
+ html[data-theme="dark"] .availability-filter { border-color: #414a58; color: #8995a6; }
301
+ html[data-theme="dark"] .availability-filter.open.is-active { border-color: #285c48; color: #7ed6aa; background: #17362b; }
302
+ html[data-theme="dark"] .availability-filter.closed.is-active { border-color: #454d59; color: #c0c8d3; background: #292f38; }
303
+ html[data-theme="dark"] .availability-label:hover,
304
+ html[data-theme="dark"] .availability-label[aria-expanded="true"] { background: #303744; }
305
+ html[data-theme="dark"] .result-count { color: #aeb8c6; background: #252c35; }
306
+ html[data-theme="dark"] .note { background: var(--blue-soft); }
307
+ html[data-theme="dark"] .note p { color: #aab7ca; }
308
+ html[data-theme="dark"] footer span:first-child { color: #b1bbc8; }
309
+
310
+ @media (max-width: 900px) {
311
+ .hero { min-height: 180px; padding: 28px 36px; }
312
+ .hero-art { display: none; }
313
+ .filter-card { grid-template-columns: 1fr; }
314
+ .dataset-grid { grid-template-columns: repeat(2, 1fr); }
315
+ .pipeline-grid { grid-template-columns: 1fr; }
316
+ .pipeline-card { min-height: 0; }
317
+ .about-grid { grid-template-columns: 1fr; gap: 0; }
318
+ .definition-list { margin-top: 0; }
319
+ }
320
+
321
+ @media (max-width: 620px) {
322
+ .shell { width: min(100% - 24px, 1460px); padding-top: 12px; }
323
+ .hero { min-height: 168px; padding: 24px; border-radius: 20px; }
324
+ .hero-tools { top: 14px; right: 14px; }
325
+ .theme-toggle { width: 35px; height: 35px; }
326
+ .tabs { width: 100%; }
327
+ .tab { flex: 1; padding-inline: 9px; }
328
+ .filter-card { grid-template-columns: 1fr; padding: 16px; }
329
+ .choice-pill { flex: 1 1 auto; justify-content: center; }
330
+ th:nth-child(2), td:nth-child(2) { width: 260px; min-width: 260px; max-width: 260px; }
331
+ .table-heading { align-items: center; gap: 12px; }
332
+ .table-tools { flex-direction: column-reverse; align-items: end; gap: 5px; }
333
+ .dataset-grid { grid-template-columns: 1fr; }
334
+ .lab-card { grid-template-columns: 1fr; gap: 24px; padding: 24px; }
335
+ .lab-card a { width: fit-content; }
336
+ .definition-list article { grid-template-columns: 1fr; gap: 5px; }
337
+ .note { grid-template-columns: 1fr; gap: 7px; }
338
+ footer { flex-direction: column; }
339
+ }