Minette Kaunismäki commited on
Commit
d5590eb
·
1 Parent(s): 5fc63f1

style fixes

Browse files
Files changed (3) hide show
  1. app.py +953 -316
  2. pruna-mascot.png +0 -0
  3. ui.py +175 -96
app.py CHANGED
@@ -1,7 +1,15 @@
 
1
  import json
2
  from collections import defaultdict
3
  from pathlib import Path
4
 
 
 
 
 
 
 
 
5
  import gradio as gr
6
  import pandas as pd
7
 
@@ -13,92 +21,373 @@ from ui import (
13
  render_home,
14
  )
15
 
 
16
  custom_css = """
17
- .logo {
18
- width: 300px;
19
- height: auto;
20
- max-width: 100%;
21
- margin: 0 auto;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  object-fit: contain;
23
- padding-bottom: 0;
24
- }
25
- .text {
26
- font-size: 16px !important;
27
- }
28
- .tabs button,
29
- .tab-nav button,
30
- .subtabs button {
31
- font-size: 20px;
32
- color: #581c87 !important;
33
- }
34
- .tabs button.selected,
35
- .tabs button[aria-selected="true"],
36
- .tab-nav button.selected,
37
- .tab-nav button[aria-selected="true"],
38
- .subtabs button.selected,
39
- .subtabs button[aria-selected="true"] {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  color: #ffffff !important;
41
- background: #7c3aed !important;
42
- border-color: #6d28d9 !important;
43
- }
44
- .dark .tabs button,
45
- .dark .tab-nav button,
46
- .dark .subtabs button {
47
- color: #e9d5ff !important;
48
- }
49
- .dark .tabs button.selected,
50
- .dark .tabs button[aria-selected="true"],
51
- .dark .tab-nav button.selected,
52
- .dark .tab-nav button[aria-selected="true"],
53
- .dark .subtabs button.selected,
54
- .dark .subtabs button[aria-selected="true"] {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  color: #ffffff !important;
56
- background: #6d28d9 !important;
 
 
 
 
 
 
 
 
57
  }
 
 
 
 
 
 
 
 
 
 
 
58
  .benchmark-catalogue-row {
59
  width: 100%;
60
- gap: 16px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
62
- .benchmark-card {
63
- width: 100%;
64
- max-width: none;
65
- min-height: 220px;
66
- border: 1px solid rgba(124, 58, 237, 0.45);
67
- border-left: 4px solid #7c3aed;
68
- border-radius: 12px;
69
- background: rgba(139, 92, 246, 0.14);
70
- padding: 16px 18px;
71
- box-shadow: 0 4px 12px rgba(76, 29, 149, 0.12);
72
- }
73
- .benchmark-card:hover {
74
- border-color: #5b21b6;
75
- box-shadow: 0 6px 18px rgba(76, 29, 149, 0.22);
76
- }
77
- .community-footer {
78
- margin-top: 24px;
79
- padding: 18px 20px;
80
- border: 1px solid #c4b5fd;
81
- border-radius: 12px;
82
- background: rgba(139, 92, 246, 0.16);
83
  }
84
- .community-footer h3 {
85
- margin: 0 0 10px;
86
- color: #581c87;
87
- font-size: 1.05rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
  .community-footer-links {
90
  display: flex;
91
  flex-wrap: wrap;
92
- gap: 10px 14px;
93
  align-items: center;
94
  }
95
- .dark .community-footer {
96
- border-color: #6d28d9;
97
- background: rgba(76, 29, 149, 0.35);
 
 
98
  }
99
- .dark .community-footer h3 {
100
- color: #f5f3ff;
101
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  .home-callouts {
103
  display: grid;
104
  grid-template-columns: repeat(3, minmax(0, 1fr));
@@ -107,143 +396,177 @@ custom_css = """
107
  }
108
  .home-callouts > div {
109
  padding: 14px 16px;
110
- border: 1px solid #a78bfa;
111
- border-radius: 10px;
112
- background: #f5f3ff;
113
  }
114
  .home-callouts span {
115
- color: #5b21b6;
116
- font-size: 11px;
117
- font-weight: 700;
118
- letter-spacing: 0.05em;
119
  }
120
  .home-callouts strong {
121
  display: block;
122
  margin-top: 6px;
123
- color: #1e1b4b;
124
- font-size: 18px;
125
  word-break: break-word;
126
  }
127
  .home-callouts em {
128
  display: block;
129
  margin-top: 4px;
130
- color: #4c1d95;
131
  font-style: normal;
132
- font-size: 13px;
133
- }
134
- .home-benchmark-card {
135
- height: 100%;
136
- padding: 18px 18px 16px;
137
- border: 1px solid #a78bfa;
138
- border-left: 4px solid #7c3aed;
139
- border-radius: 12px;
140
- background: #f5f3ff;
141
- box-shadow: 0 4px 12px rgba(76, 29, 149, 0.12);
142
  }
143
- .home-benchmark-title {
144
- color: #1e1b4b;
145
- font-size: 1.35rem;
146
- font-weight: 700;
147
- }
148
- .home-benchmark-blurb {
149
- margin: 8px 0 14px;
150
- color: #312e81;
151
- font-size: 0.95rem;
152
- line-height: 1.45;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  }
154
  .home-top-label {
155
- color: #5b21b6;
156
- font-size: 11px;
157
- font-weight: 700;
158
- letter-spacing: 0.05em;
159
- text-transform: uppercase;
160
  }
161
  .home-top-list {
162
  list-style: none;
163
  margin: 8px 0 0;
164
  padding: 0;
165
  }
166
- .home-top-list li {
 
167
  display: grid;
168
- grid-template-columns: 28px 1fr auto;
169
  gap: 10px;
170
  align-items: center;
171
  padding: 8px 0;
172
- border-bottom: 1px solid #ddd6fe;
173
- color: #1e1b4b;
174
  }
175
- .home-rank {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  width: 28px;
177
  height: 28px;
178
  border-radius: 999px;
179
- background: #ede9fe;
180
- color: #5b21b6;
181
  font-weight: 700;
182
  font-size: 13px;
183
  display: inline-flex;
184
  align-items: center;
185
  justify-content: center;
 
186
  }
187
- .home-model {
 
188
  font-weight: 600;
189
  word-break: break-word;
190
- color: #1e1b4b;
191
  }
192
- .home-score {
 
193
  font-variant-numeric: tabular-nums;
194
- color: #4c1d95;
195
  font-weight: 600;
196
  }
197
- .home-empty {
198
- color: #4c1d95;
199
- }
200
- .dark .home-callouts > div,
201
- .dark .home-benchmark-card {
202
- border-color: #7c3aed;
203
- background: #1e1b4b;
204
- }
205
- .dark .home-callouts span,
206
- .dark .home-top-label,
207
- .dark .home-rank {
208
- color: #c4b5fd;
209
- }
210
- .dark .home-rank {
211
- background: #312e81;
212
- }
213
- .dark .home-callouts strong,
214
- .dark .home-benchmark-title,
215
- .dark .home-model,
216
- .dark .home-top-list li {
217
- color: #faf5ff;
218
- }
219
- .dark .home-callouts em,
220
- .dark .home-benchmark-blurb,
221
- .dark .home-score,
222
- .dark .home-empty {
223
- color: #ddd6fe;
224
- }
225
- .dark .home-top-list li {
226
- border-bottom-color: #4c1d95;
227
  }
 
228
  @media (max-width: 700px) {
229
- .home-callouts {
230
- grid-template-columns: 1fr;
 
 
231
  }
 
232
  }
233
- .pareto-plot {
234
- width: 100%;
235
- }
236
- .pareto-plot .plotly {
237
- width: 100% !important;
238
- }
239
  .pareto-plot .js-plotly-plot,
240
- .pareto-plot .plot-container {
241
- width: 100% !important;
242
- }
243
- /* Hide the Plotly toolbar so it doesn't cover points in the top-right. */
244
- .pareto-plot .modebar {
245
- display: none !important;
246
- }
247
  .leaderboard-summary {
248
  display: grid;
249
  grid-template-columns: repeat(4, minmax(0, 1fr));
@@ -252,13 +575,13 @@ custom_css = """
252
  }
253
  .leaderboard-summary > div {
254
  padding: 14px 16px;
255
- border: 1px solid #c4b5fd;
256
- border-radius: 10px;
257
- background: rgba(139, 92, 246, 0.14);
258
  }
259
  .leaderboard-summary span,
260
  .results-heading {
261
- color: #7e22ce;
262
  font-size: 11px;
263
  font-weight: 700;
264
  letter-spacing: 0.05em;
@@ -266,19 +589,90 @@ custom_css = """
266
  .leaderboard-summary strong {
267
  display: block;
268
  margin-top: 4px;
269
- color: #581c87;
270
  font-size: 22px;
271
  }
272
  .leaderboard-controls {
273
- align-items: end;
274
- margin-bottom: 8px;
275
- }
276
- .ranking-table-host {
277
- width: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  }
279
- .ranking-table {
280
- margin-top: 4px;
281
- width: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  }
283
  .results-heading {
284
  display: flex;
@@ -287,143 +681,173 @@ custom_css = """
287
  text-transform: uppercase;
288
  }
289
  .ranking-table-scroll {
290
- overflow-x: auto;
291
- border: 1px solid #c4b5fd;
292
- border-radius: 10px;
293
- background: rgba(139, 92, 246, 0.12);
294
- }
295
- .ranking-table table {
 
 
 
 
296
  width: 100%;
297
- min-width: 800px;
298
- border-collapse: collapse;
299
- color: #581c87;
300
- font-size: 14px;
301
- }
302
- .ranking-table th {
303
- padding: 11px 14px;
304
- border-bottom: 1px solid #c4b5fd;
305
- color: #7e22ce;
306
- font-size: 11px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  letter-spacing: 0.04em;
308
  text-align: left;
309
  text-transform: uppercase;
310
- }
311
- .ranking-table th.sortable-col {
312
- cursor: pointer;
313
- user-select: none;
314
  white-space: nowrap;
 
315
  }
316
- .ranking-table th.sortable-col:hover {
317
- color: #4c1d95;
318
- }
319
  .ranking-table th.sortable-col.sorted-asc::after,
320
  .ranking-table th.sortable-col.sorted-desc::after {
321
  margin-left: 0.35em;
322
  font-size: 0.85em;
323
  opacity: 0.85;
324
  }
325
- .ranking-table th.sortable-col.sorted-asc::after {
326
- content: "";
327
- }
328
- .ranking-table th.sortable-col.sorted-desc::after {
329
- content: "▼";
330
- }
331
- .ranking-table td {
332
- padding: 13px 14px;
333
- border-bottom: 1px solid #e9d5ff;
334
- }
335
- .ranking-table tbody tr:last-child td {
336
- border-bottom: 0;
337
- }
338
- .ranking-table tbody tr:hover {
339
- background: #6d28d9;
340
  }
341
  .ranking-table tbody tr:hover td,
342
  .ranking-table tbody tr:hover .rank,
343
  .ranking-table tbody tr:hover .metric-score,
 
344
  .ranking-table tbody tr:hover .model-cell strong,
345
- .ranking-table tbody tr:hover .model-cell span {
346
- color: #ffffff;
 
 
 
 
 
 
 
 
 
 
 
347
  }
348
- .ranking-table .rank {
349
- color: #7c3aed;
350
- font-weight: 700;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  }
352
  .ranking-table .model-cell strong,
353
- .ranking-table .model-cell span {
354
- display: block;
 
 
 
 
 
355
  }
356
  .ranking-table .model-cell span {
357
  margin-top: 3px;
358
- color: #9333ea;
359
  font-size: 12px;
360
  }
361
- .ranking-table .metric-score {
362
- color: #4c1d95;
 
 
 
 
 
 
 
363
  font-variant-numeric: tabular-nums;
364
- font-weight: 700;
 
 
365
  }
 
366
  .ranking-table .empty-state {
367
- color: #9333ea;
368
  padding: 32px;
369
  text-align: center;
370
  }
371
- @media (prefers-color-scheme: dark) {
372
- .leaderboard-summary > div,
373
- .ranking-table-scroll {
374
- border-color: rgba(221, 214, 254, 0.45);
375
- }
376
- .leaderboard-summary span,
377
- .results-heading,
378
- .ranking-table th,
379
- .ranking-table .model-cell span,
380
- .ranking-table .empty-state {
381
- color: #ddd6fe;
382
- }
383
- .leaderboard-summary strong,
384
- .ranking-table table,
385
- .ranking-table .rank,
386
- .ranking-table .metric-score {
387
- color: #f5f3ff;
388
- }
389
- .ranking-table td {
390
- border-bottom-color: rgba(221, 214, 254, 0.2);
391
- }
392
- }
393
- .dark .leaderboard-summary > div,
394
- .dark .ranking-table-scroll {
395
- border-color: rgba(221, 214, 254, 0.45);
396
- }
397
- .dark .leaderboard-summary span,
398
- .dark .results-heading,
399
- .dark .ranking-table th,
400
- .dark .ranking-table .model-cell span,
401
- .dark .ranking-table .empty-state {
402
- color: #ddd6fe;
403
- }
404
- .dark .leaderboard-summary strong,
405
- .dark .ranking-table table,
406
- .dark .ranking-table .rank,
407
- .dark .ranking-table .metric-score {
408
- color: #f5f3ff;
409
- }
410
- .compare-samples-help {
411
- color: #6b21a8;
412
- margin-bottom: 8px;
413
- }
414
  .compare-prompt-block {
415
  margin: 0 0 22px;
416
  padding: 14px 16px;
417
- border: 1px solid #c4b5fd;
418
- border-radius: 12px;
419
- background: rgba(139, 92, 246, 0.10);
420
  }
421
  .compare-prompt-meta {
422
  display: flex;
423
  justify-content: space-between;
424
  gap: 12px;
425
  margin-bottom: 8px;
426
- color: #7e22ce;
427
  font-size: 12px;
428
  font-weight: 700;
429
  letter-spacing: 0.04em;
@@ -431,20 +855,15 @@ custom_css = """
431
  }
432
  .compare-prompt-text {
433
  margin: 0 0 14px;
434
- color: #3b0764;
435
  font-size: 15px;
436
  line-height: 1.45;
437
  }
438
- .compare-row {
439
- display: grid;
440
- gap: 12px;
441
- }
442
- .compare-cell {
443
- min-width: 0;
444
- }
445
  .compare-model-label {
446
  margin-bottom: 6px;
447
- color: #5b21b6;
448
  font-size: 13px;
449
  font-weight: 700;
450
  word-break: break-word;
@@ -454,57 +873,269 @@ custom_css = """
454
  width: 100%;
455
  aspect-ratio: 1 / 1;
456
  object-fit: cover;
457
- border-radius: 10px;
458
- border: 1px solid #ddd6fe;
459
- background: #f5f3ff;
460
  }
461
  .compare-empty {
462
  padding: 18px;
463
- border: 1px dashed #c4b5fd;
464
- border-radius: 10px;
465
- color: #6b21a8;
466
  text-align: center;
467
  }
468
- .dark .compare-samples-help,
469
- .dark .compare-prompt-meta,
470
- .dark .compare-model-label,
471
- .dark .compare-empty {
472
- color: #e9d5ff;
473
  }
474
- .dark .compare-prompt-block {
475
- border-color: #6d28d9;
476
- background: rgba(76, 29, 149, 0.35);
 
 
 
 
 
 
 
 
 
 
477
  }
478
- .dark .compare-prompt-text {
479
- color: #f5f3ff;
 
 
 
 
480
  }
481
- .dark .compare-cell img {
482
- border-color: #6d28d9;
483
- background: #2e1065;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
  }
485
- .dark .ranking-table td {
486
- border-bottom-color: rgba(221, 214, 254, 0.2);
 
 
 
487
  }
488
- @media (max-width: 700px) {
489
- .leaderboard-summary {
490
- grid-template-columns: repeat(2, minmax(0, 1fr));
491
- }
 
 
 
 
 
 
 
 
 
492
  }
493
- h1, h2 {
494
- margin: 0;
495
- padding-top: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
  }
497
  """
498
 
499
- theme = gr.Theme.from_hub("Werli/Purple-Crimson-Gradio-Theme").set(
500
- body_background_fill="#c4b5fd",
501
- body_background_fill_dark="#120B1B",
502
- body_text_color="#3b0764",
503
- body_text_color_dark="#ffffff",
504
- block_background_fill="#ede9fe",
505
- block_background_fill_dark="#2e1065",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
  )
507
 
 
508
  space_root = Path(__file__).resolve().parent
509
  data_dir = space_root / "data"
510
 
@@ -842,6 +1473,9 @@ benchmarks = [
842
 
843
 
844
  custom_head = """
 
 
 
845
  <script>
846
  (() => {
847
  if (window.__inferbenchLeaderboardSortBound) return;
@@ -903,7 +1537,7 @@ with gr.Blocks(
903
  theme=theme, fill_width=True, css=custom_css, head=custom_head
904
  ) as demo:
905
  render_header()
906
- with gr.Tabs():
907
  with gr.TabItem("Home"):
908
  render_home(benchmarks)
909
  with gr.TabItem("Benchmarks") as benchmarks_tab:
@@ -918,4 +1552,7 @@ with gr.Blocks(
918
 
919
 
920
  if __name__ == "__main__":
921
- demo.launch(ssr_mode=False)
 
 
 
 
1
+ import asyncio
2
  import json
3
  from collections import defaultdict
4
  from pathlib import Path
5
 
6
+ # Gradio 5.19's safe_get_lock() returns None on Python 3.12+/3.14 when no
7
+ # event loop exists yet, which breaks /queue/join (pending_message_lock).
8
+ try:
9
+ asyncio.get_running_loop()
10
+ except RuntimeError:
11
+ asyncio.set_event_loop(asyncio.new_event_loop())
12
+
13
  import gradio as gr
14
  import pandas as pd
15
 
 
21
  render_home,
22
  )
23
 
24
+ # Visual tokens from https://www.pruna.ai/ and https://playground.pruna.ai/
25
  custom_css = """
26
+ :root {
27
+ --pruna-bg-primary: #120b1b;
28
+ --pruna-bg-card: #171021;
29
+ --pruna-bg-elevated: #1d1429;
30
+ --pruna-border: rgba(74, 57, 98, 0.75);
31
+ --pruna-text-primary: #fafafa;
32
+ --pruna-text-body: #d4d4d4;
33
+ --pruna-text-muted: #a3a3a3;
34
+ --pruna-accent: #9334e9;
35
+ --pruna-accent-bright: #8f35ff;
36
+ --pruna-lavender: #d8b4fe;
37
+ --pruna-green: #69a45c;
38
+ --pruna-link: #bf8bff;
39
+ --pruna-font: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;
40
+ }
41
+
42
+ html, body, .gradio-container, .main {
43
+ background: var(--pruna-bg-primary) !important;
44
+ color: var(--pruna-text-primary) !important;
45
+ font-family: var(--pruna-font) !important;
46
+ }
47
+
48
+ /* Subtle depth — not a marketing-site hero glow */
49
+ body, .gradio-container {
50
+ background-image:
51
+ radial-gradient(ellipse 60% 35% at 50% -5%, rgba(147, 52, 233, 0.18), transparent 55%) !important;
52
+ background-attachment: fixed !important;
53
+ }
54
+
55
+ .gradio-container {
56
+ max-width: 1200px !important;
57
+ margin: 0 auto !important;
58
+ padding-top: 0 !important;
59
+ }
60
+
61
+ /* —— App header (InferBench only) —— */
62
+ .app-header {
63
+ display: flex;
64
+ align-items: center;
65
+ justify-content: center;
66
+ gap: 14px;
67
+ margin: 8px 0 20px;
68
+ padding: 8px 4px 4px;
69
+ text-align: left;
70
+ }
71
+ .app-header-logo {
72
+ width: 40px;
73
+ height: 47px;
74
  object-fit: contain;
75
+ flex-shrink: 0;
76
+ }
77
+
78
+ /* —— Page tabs: centered underline nav (Gradio 5 uses tab-wrapper/container) —— */
79
+ .tabs {
80
+ gap: 0 !important;
81
+ }
82
+ .main-tabs > .tab-wrapper {
83
+ height: auto !important;
84
+ min-height: 0 !important;
85
+ padding: 0 !important;
86
+ margin: 0 0 22px !important;
87
+ justify-content: center !important;
88
+ }
89
+ .main-tabs .tab-container {
90
+ height: auto !important;
91
+ justify-content: center !important;
92
+ overflow: visible !important;
93
+ gap: 2px;
94
+ }
95
+ .main-tabs .tab-container::after {
96
+ background: rgba(255, 255, 255, 0.08) !important;
97
+ }
98
+ .main-tabs .tab-container > button {
99
+ font-family: var(--pruna-font) !important;
100
+ font-size: 0.95rem !important;
101
+ font-weight: 600 !important;
102
+ letter-spacing: -0.015em !important;
103
+ color: var(--pruna-text-muted) !important;
104
+ background: transparent !important;
105
+ border: none !important;
106
+ border-radius: 0 !important;
107
+ box-shadow: none !important;
108
+ padding: 12px 20px !important;
109
+ min-height: 44px !important;
110
+ height: auto !important;
111
+ }
112
+ .main-tabs .tab-container > button:hover:not(.selected) {
113
+ color: #e4e4e7 !important;
114
+ background: transparent !important;
115
+ }
116
+ .main-tabs .tab-container > button.selected,
117
+ .main-tabs .tab-container > button[aria-selected="true"] {
118
  color: #ffffff !important;
119
+ background: transparent !important;
120
+ }
121
+ .main-tabs .tab-container > button.selected::after,
122
+ .main-tabs .tab-container > button[aria-selected="true"]::after {
123
+ background: var(--pruna-accent-bright) !important;
124
+ height: 2px !important;
125
+ }
126
+
127
+ /* —— Benchmark view menu (Leaderboard / Graphs / Compare) —— */
128
+ .benchmark-back-btn,
129
+ .benchmark-back-btn.block,
130
+ .benchmark-back-btn .padded {
131
+ width: fit-content !important;
132
+ min-width: 0 !important;
133
+ margin: 0 0 4px !important;
134
+ padding: 0 !important;
135
+ border: none !important;
136
+ background: transparent !important;
137
+ box-shadow: none !important;
138
+ }
139
+ .benchmark-back-btn button,
140
+ .benchmark-back-btn button.secondary,
141
+ .benchmark-back-btn button.lg,
142
+ .benchmark-back-btn button.sm {
143
+ display: inline-flex !important;
144
+ align-items: center !important;
145
+ width: auto !important;
146
+ min-width: 0 !important;
147
+ min-height: 0 !important;
148
+ height: auto !important;
149
+ margin: 0 !important;
150
+ padding: 0 !important;
151
+ border: none !important;
152
+ border-radius: 0 !important;
153
+ background: transparent !important;
154
+ box-shadow: none !important;
155
+ color: var(--pruna-text-muted) !important;
156
+ font-family: var(--pruna-font) !important;
157
+ font-size: 0.9rem !important;
158
+ font-weight: 500 !important;
159
+ letter-spacing: -0.01em !important;
160
+ line-height: 1.4 !important;
161
+ }
162
+ .benchmark-back-btn button:hover {
163
+ color: var(--pruna-link) !important;
164
+ background: transparent !important;
165
+ border: none !important;
166
+ box-shadow: none !important;
167
+ }
168
+ .benchmark-view-menu,
169
+ .benchmark-view-menu.block,
170
+ .benchmark-view-menu .form {
171
+ border: none !important;
172
+ background: transparent !important;
173
+ box-shadow: none !important;
174
+ padding: 0 !important;
175
+ margin: 4px 0 20px !important;
176
+ }
177
+ .benchmark-view-menu .wrap {
178
+ display: grid !important;
179
+ grid-template-columns: repeat(3, minmax(0, 1fr));
180
+ gap: 4px !important;
181
+ width: 100%;
182
+ padding: 4px !important;
183
+ border: 1px solid rgba(255, 255, 255, 0.08) !important;
184
+ border-radius: 12px !important;
185
+ background: rgba(255, 255, 255, 0.03) !important;
186
+ }
187
+ .benchmark-view-menu label {
188
+ display: flex !important;
189
+ align-items: center !important;
190
+ justify-content: center !important;
191
+ margin: 0 !important;
192
+ padding: 10px 12px !important;
193
+ border: none !important;
194
+ border-radius: 8px !important;
195
+ background: transparent !important;
196
+ box-shadow: none !important;
197
+ color: var(--pruna-text-muted) !important;
198
+ font-family: var(--pruna-font) !important;
199
+ font-size: 0.9rem !important;
200
+ font-weight: 600 !important;
201
+ letter-spacing: -0.015em !important;
202
+ cursor: pointer;
203
+ }
204
+ .benchmark-view-menu label:hover {
205
+ color: #e4e4e7 !important;
206
+ background: rgba(255, 255, 255, 0.05) !important;
207
+ }
208
+ .benchmark-view-menu label.selected {
209
  color: #ffffff !important;
210
+ background: rgba(143, 53, 255, 0.22) !important;
211
+ }
212
+ .benchmark-view-menu input[type="radio"] {
213
+ position: absolute !important;
214
+ opacity: 0 !important;
215
+ width: 0 !important;
216
+ height: 0 !important;
217
+ margin: 0 !important;
218
+ pointer-events: none !important;
219
  }
220
+ .benchmark-view-menu label span {
221
+ margin: 0 !important;
222
+ color: inherit !important;
223
+ }
224
+ @media (max-width: 700px) {
225
+ .benchmark-view-menu .wrap {
226
+ grid-template-columns: 1fr;
227
+ }
228
+ }
229
+
230
+ /* Surfaces */
231
  .benchmark-catalogue-row {
232
  width: 100%;
233
+ gap: 16px !important;
234
+ align-items: stretch !important;
235
+ }
236
+ .benchmark-catalogue-row > div {
237
+ display: flex !important;
238
+ flex-direction: column !important;
239
+ height: 100% !important;
240
+ }
241
+ .benchmark-card-col {
242
+ display: flex !important;
243
+ flex-direction: column !important;
244
+ justify-content: space-between !important;
245
+ gap: 16px !important;
246
+ height: 100% !important;
247
+ min-height: 240px !important;
248
+ padding: 18px 20px !important;
249
+ border: 1px solid var(--pruna-border) !important;
250
+ border-radius: 16px !important;
251
+ background: color-mix(in oklab, var(--pruna-bg-elevated) 92%, black 8%) !important;
252
+ box-shadow: 0 24px 55px rgba(0, 0, 0, 0.42), inset 0 1px rgba(255, 255, 255, 0.04) !important;
253
+ }
254
+ .benchmark-card-col:hover {
255
+ border-color: color-mix(in srgb, var(--pruna-accent) 50%, transparent) !important;
256
+ }
257
+ .benchmark-card-body {
258
+ flex: 1 1 auto;
259
+ min-height: 0;
260
+ }
261
+ .benchmark-card-title {
262
+ color: var(--pruna-text-primary);
263
+ font-size: 1.25rem;
264
+ font-weight: 700;
265
+ line-height: 1.3;
266
+ margin: 0 0 8px;
267
  }
268
+ .benchmark-card-blurb {
269
+ margin: 0;
270
+ color: var(--pruna-text-body);
271
+ font-size: 0.95rem;
272
+ line-height: 1.45;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  }
274
+ .benchmark-card-col .benchmark-open-btn,
275
+ .benchmark-card-col button {
276
+ margin-top: auto !important;
277
+ width: 100% !important;
278
+ align-self: stretch !important;
279
+ flex-shrink: 0 !important;
280
+ }
281
+ .home-callouts > div,
282
+ .compare-prompt-block {
283
+ border: 1px solid var(--pruna-border) !important;
284
+ border-radius: 16px !important;
285
+ background: color-mix(in oklab, var(--pruna-bg-elevated) 92%, black 8%) !important;
286
+ box-shadow: 0 24px 55px rgba(0, 0, 0, 0.42), inset 0 1px rgba(255, 255, 255, 0.04) !important;
287
+ }
288
+
289
+ /* Page footer — flat community strip + quiet citation accordion */
290
+ .page-footer-host,
291
+ .page-footer-host .html-container,
292
+ .page-footer-host .prose,
293
+ .page-footer-host.block,
294
+ .page-footer-host .padded {
295
+ border: none !important;
296
+ background: transparent !important;
297
+ box-shadow: none !important;
298
+ padding: 0 !important;
299
+ margin: 0 !important;
300
+ }
301
+ .page-footer {
302
+ margin: 32px 0 16px;
303
+ padding: 20px 0 0;
304
+ border-top: 1px solid rgba(255, 255, 255, 0.08);
305
+ }
306
+ .page-footer h3 {
307
+ margin: 0 0 10px !important;
308
+ font-size: 1.05rem !important;
309
+ font-weight: 600 !important;
310
+ letter-spacing: -0.015em !important;
311
+ text-transform: none !important;
312
+ color: #ffffff !important;
313
  }
314
  .community-footer-links {
315
  display: flex;
316
  flex-wrap: wrap;
317
+ gap: 8px 16px;
318
  align-items: center;
319
  }
320
+ .community-footer-links a {
321
+ color: var(--pruna-text-muted) !important;
322
+ text-decoration: none !important;
323
+ font-size: 0.9rem !important;
324
+ font-weight: 500 !important;
325
  }
326
+ .community-footer-links a:hover {
327
+ color: var(--pruna-link) !important;
328
  }
329
+
330
+ /* Citation accordion — full-width control, not a section heading */
331
+ .citation-accordion {
332
+ margin: 0 0 28px !important;
333
+ }
334
+ .citation-accordion,
335
+ .citation-accordion.block {
336
+ border: 1px solid rgba(216, 180, 254, 0.15) !important;
337
+ border-radius: 10px !important;
338
+ background: rgba(255, 255, 255, 0.02) !important;
339
+ box-shadow: none !important;
340
+ overflow: hidden !important;
341
+ }
342
+ .citation-accordion > .label-wrap,
343
+ .citation-accordion .label-wrap {
344
+ border: none !important;
345
+ background: transparent !important;
346
+ box-shadow: none !important;
347
+ padding: 11px 14px !important;
348
+ font-size: 0.92rem !important;
349
+ font-weight: 500 !important;
350
+ color: #e4e4e7 !important;
351
+ letter-spacing: -0.01em !important;
352
+ }
353
+ .citation-accordion > .label-wrap:hover,
354
+ .citation-accordion .label-wrap:hover {
355
+ background: rgba(255, 255, 255, 0.04) !important;
356
+ }
357
+ .citation-accordion > .label-wrap span,
358
+ .citation-accordion .label-wrap span {
359
+ color: #e4e4e7 !important;
360
+ font-size: 0.92rem !important;
361
+ font-weight: 500 !important;
362
+ }
363
+ .citation-accordion .icon,
364
+ .citation-accordion .label-wrap .icon {
365
+ color: var(--pruna-text-muted) !important;
366
+ opacity: 0.9;
367
+ }
368
+ .citation-accordion .prose,
369
+ .citation-accordion .markdown,
370
+ .citation-accordion pre,
371
+ .citation-accordion code {
372
+ color: var(--pruna-text-muted) !important;
373
+ background: transparent !important;
374
+ border: none !important;
375
+ box-shadow: none !important;
376
+ }
377
+ .citation-accordion .wrap,
378
+ .citation-accordion > .wrap {
379
+ border-top: 1px solid rgba(255, 255, 255, 0.06) !important;
380
+ padding: 4px 14px 12px !important;
381
+ background: transparent !important;
382
+ }
383
+ .citation-accordion pre {
384
+ margin: 0 !important;
385
+ padding: 0 !important;
386
+ font-size: 0.8rem !important;
387
+ line-height: 1.55 !important;
388
+ overflow-x: auto;
389
+ }
390
+
391
  .home-callouts {
392
  display: grid;
393
  grid-template-columns: repeat(3, minmax(0, 1fr));
 
396
  }
397
  .home-callouts > div {
398
  padding: 14px 16px;
399
+ background: color-mix(in oklab, var(--pruna-bg-card) 82%, black 18%) !important;
400
+ box-shadow: none !important;
 
401
  }
402
  .home-callouts span {
403
+ display: block;
 
 
 
404
  }
405
  .home-callouts strong {
406
  display: block;
407
  margin-top: 6px;
 
 
408
  word-break: break-word;
409
  }
410
  .home-callouts em {
411
  display: block;
412
  margin-top: 4px;
 
413
  font-style: normal;
 
 
 
 
 
 
 
 
 
 
414
  }
415
+ .home-snapshots-host,
416
+ .home-snapshots-host .html-container,
417
+ .home-snapshots-host .prose,
418
+ .home-snapshots-host.block,
419
+ .home-snapshots-host .padded {
420
+ border: none !important;
421
+ background: transparent !important;
422
+ box-shadow: none !important;
423
+ padding: 0 !important;
424
+ margin: 0 !important;
425
+ }
426
+ .home-snapshots-table {
427
+ display: table !important;
428
+ width: 100% !important;
429
+ border-collapse: separate !important;
430
+ border-spacing: 40px 14px !important;
431
+ margin: 0 !important;
432
+ table-layout: fixed !important;
433
+ border: none !important;
434
+ background: transparent !important;
435
+ }
436
+ .home-snapshots-table tbody {
437
+ display: table-row-group !important;
438
+ }
439
+ .home-snapshots-table tr {
440
+ display: table-row !important;
441
+ }
442
+ .home-snapshots-table td.home-snap-cell {
443
+ display: table-cell !important;
444
+ vertical-align: top !important;
445
+ width: 50% !important;
446
+ padding: 0 !important;
447
+ border: 0 !important;
448
+ background: transparent !important;
449
+ }
450
+ .home-snap-title,
451
+ .prose .home-snap-title {
452
+ display: flex !important;
453
+ align-items: center !important;
454
+ gap: 8px !important;
455
+ margin: 0 !important;
456
+ min-height: 1.5rem;
457
+ font-size: 0.95rem !important;
458
+ font-weight: 600 !important;
459
+ letter-spacing: -0.01em;
460
+ line-height: 1.3 !important;
461
+ color: #e4e4e7 !important;
462
+ }
463
+ .home-snap-emoji {
464
+ display: inline-flex;
465
+ align-items: center;
466
+ justify-content: center;
467
+ width: 1.25rem;
468
+ height: 1.25rem;
469
+ flex-shrink: 0;
470
+ font-size: 1rem;
471
+ line-height: 1;
472
+ }
473
+ .home-snap-blurb,
474
+ .prose .home-snap-blurb,
475
+ .prose p.home-snap-blurb {
476
+ margin: 0 !important;
477
+ color: var(--pruna-text-muted) !important;
478
+ font-size: 0.875rem !important;
479
+ font-weight: 400 !important;
480
+ line-height: 1.45 !important;
481
+ }
482
+ .home-snap-top {
483
+ padding-top: 10px;
484
+ border-top: 1px solid rgba(255, 255, 255, 0.08);
485
+ width: 100%;
486
  }
487
  .home-top-label {
488
+ margin: 0;
 
 
 
 
489
  }
490
  .home-top-list {
491
  list-style: none;
492
  margin: 8px 0 0;
493
  padding: 0;
494
  }
495
+ .home-top-list li,
496
+ .prose .home-top-list li {
497
  display: grid;
498
+ grid-template-columns: 28px minmax(0, 1fr) auto;
499
  gap: 10px;
500
  align-items: center;
501
  padding: 8px 0;
502
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
503
+ color: var(--pruna-text-primary) !important;
504
  }
505
+ @media (max-width: 700px) {
506
+ .home-snapshots-table,
507
+ .home-snapshots-table tbody,
508
+ .home-snapshots-table tr,
509
+ .home-snapshots-table td {
510
+ display: block;
511
+ width: 100% !important;
512
+ }
513
+ .home-snapshots-table {
514
+ margin: 4px 0 8px;
515
+ border-spacing: 0;
516
+ }
517
+ .home-snapshots-table td.home-snap-cell {
518
+ margin-bottom: 8px;
519
+ }
520
+ .home-snap-top {
521
+ margin-bottom: 16px;
522
+ }
523
+ }
524
+ .home-rank,
525
+ .prose .home-rank {
526
  width: 28px;
527
  height: 28px;
528
  border-radius: 999px;
529
+ background: rgba(143, 53, 255, 0.22) !important;
530
+ color: var(--pruna-lavender) !important;
531
  font-weight: 700;
532
  font-size: 13px;
533
  display: inline-flex;
534
  align-items: center;
535
  justify-content: center;
536
+ box-shadow: 0 0 0 1px rgba(143, 53, 255, 0.45);
537
  }
538
+ .home-model,
539
+ .prose .home-model {
540
  font-weight: 600;
541
  word-break: break-word;
542
+ color: var(--pruna-text-primary) !important;
543
  }
544
+ .home-score,
545
+ .prose .home-score {
546
  font-variant-numeric: tabular-nums;
547
+ color: #ddd6fe !important;
548
  font-weight: 600;
549
  }
550
+ .home-empty,
551
+ .prose .home-empty {
552
+ color: var(--pruna-text-muted) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
553
  }
554
+
555
  @media (max-width: 700px) {
556
+ .home-callouts { grid-template-columns: 1fr; }
557
+ .app-header {
558
+ flex-direction: column;
559
+ text-align: center;
560
  }
561
+ .app-header-copy { text-align: center; }
562
  }
563
+
564
+ .pareto-plot { width: 100%; }
565
+ .pareto-plot .plotly,
 
 
 
566
  .pareto-plot .js-plotly-plot,
567
+ .pareto-plot .plot-container { width: 100% !important; }
568
+ .pareto-plot .modebar { display: none !important; }
569
+
 
 
 
 
570
  .leaderboard-summary {
571
  display: grid;
572
  grid-template-columns: repeat(4, minmax(0, 1fr));
 
575
  }
576
  .leaderboard-summary > div {
577
  padding: 14px 16px;
578
+ border: 1px solid color-mix(in oklab, var(--pruna-border) 60%, transparent);
579
+ border-radius: 12px;
580
+ background: color-mix(in oklab, var(--pruna-bg-card) 82%, black 18%);
581
  }
582
  .leaderboard-summary span,
583
  .results-heading {
584
+ color: var(--pruna-text-muted);
585
  font-size: 11px;
586
  font-weight: 700;
587
  letter-spacing: 0.05em;
 
589
  .leaderboard-summary strong {
590
  display: block;
591
  margin-top: 4px;
592
+ color: var(--pruna-text-primary);
593
  font-size: 22px;
594
  }
595
  .leaderboard-controls {
596
+ align-items: end !important;
597
+ gap: 10px !important;
598
+ margin-bottom: 12px;
599
+ }
600
+ .leaderboard-controls > .block,
601
+ .leaderboard-controls .form,
602
+ .leaderboard-controls .block {
603
+ border: none !important;
604
+ background: transparent !important;
605
+ box-shadow: none !important;
606
+ padding: 0 !important;
607
+ --block-border-width: 0 !important;
608
+ }
609
+ .leaderboard-controls label {
610
+ color: var(--pruna-text-muted) !important;
611
+ font-size: 0.8rem !important;
612
+ font-weight: 500 !important;
613
+ }
614
+ .leaderboard-search label,
615
+ .leaderboard-search .block-label,
616
+ .leaderboard-search .block-label span {
617
+ color: #ffffff !important;
618
+ font-size: 0.85rem !important;
619
+ font-weight: 700 !important;
620
+ letter-spacing: -0.01em !important;
621
+ }
622
+ .leaderboard-search input,
623
+ .leaderboard-controls input,
624
+ .leaderboard-controls textarea {
625
+ min-height: 40px !important;
626
+ height: 40px !important;
627
+ padding: 0 12px !important;
628
+ border: 1px solid rgba(255, 255, 255, 0.08) !important;
629
+ border-radius: 10px !important;
630
+ background: rgba(255, 255, 255, 0.03) !important;
631
+ box-shadow: none !important;
632
+ color: var(--pruna-text-primary) !important;
633
+ font-family: var(--pruna-font) !important;
634
+ font-size: 0.9rem !important;
635
+ line-height: 40px !important;
636
+ resize: none !important;
637
+ }
638
+ .leaderboard-search input {
639
+ font-weight: 600 !important;
640
+ }
641
+ .leaderboard-search input::placeholder,
642
+ .leaderboard-controls input::placeholder {
643
+ color: var(--pruna-text-muted) !important;
644
+ opacity: 0.85;
645
  }
646
+ .leaderboard-search input:focus,
647
+ .leaderboard-controls input:focus,
648
+ .leaderboard-controls textarea:focus {
649
+ border-color: rgba(143, 53, 255, 0.45) !important;
650
+ outline: none !important;
651
+ box-shadow: 0 0 0 3px rgba(143, 53, 255, 0.16) !important;
652
+ }
653
+ .leaderboard-controls .wrap,
654
+ .leaderboard-controls .wrap-inner,
655
+ .leaderboard-controls .secondary-wrap {
656
+ min-height: 40px !important;
657
+ border: 1px solid rgba(255, 255, 255, 0.08) !important;
658
+ border-radius: 10px !important;
659
+ background: rgba(255, 255, 255, 0.03) !important;
660
+ box-shadow: none !important;
661
+ }
662
+ .ranking-table-host,
663
+ .ranking-table-host .html-container,
664
+ .ranking-table-host .prose,
665
+ .ranking-table-host.block,
666
+ .ranking-table-host .padded,
667
+ .ranking-table-host.prose {
668
+ border: none !important;
669
+ outline: none !important;
670
+ background: transparent !important;
671
+ box-shadow: none !important;
672
+ padding: 0 !important;
673
+ margin: 0 !important;
674
+ width: 100% !important;
675
+ --block-border-width: 0 !important;
676
  }
677
  .results-heading {
678
  display: flex;
 
681
  text-transform: uppercase;
682
  }
683
  .ranking-table-scroll {
684
+ border: 1px solid rgba(255, 255, 255, 0.08);
685
+ border-radius: 12px;
686
+ background: rgba(255, 255, 255, 0.03);
687
+ box-shadow: none;
688
+ max-height: min(70vh, 720px);
689
+ overflow: auto;
690
+ -webkit-overflow-scrolling: touch;
691
+ }
692
+ .ranking-table,
693
+ .prose .ranking-table {
694
  width: 100%;
695
+ margin: 0 !important;
696
+ overflow: visible;
697
+ }
698
+ .ranking-table table,
699
+ .prose .ranking-table table {
700
+ display: table !important;
701
+ width: max-content !important;
702
+ min-width: 100% !important;
703
+ max-width: none !important;
704
+ margin: 0 !important;
705
+ border-collapse: separate !important;
706
+ border-spacing: 0 !important;
707
+ color: var(--pruna-text-body) !important;
708
+ font-size: 13px !important;
709
+ line-height: 1.35 !important;
710
+ background: transparent !important;
711
+ border: none !important;
712
+ outline: none !important;
713
+ }
714
+ .ranking-table thead { display: table-header-group !important; }
715
+ .ranking-table tbody { display: table-row-group !important; }
716
+ .ranking-table tr { display: table-row !important; }
717
+ .ranking-table th,
718
+ .ranking-table td,
719
+ .prose .ranking-table th,
720
+ .prose .ranking-table td {
721
+ display: table-cell !important;
722
+ vertical-align: middle !important;
723
+ padding: 11px 14px !important;
724
+ border: 0 !important;
725
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08) !important;
726
+ background: transparent !important;
727
+ box-shadow: none !important;
728
+ outline: none !important;
729
+ }
730
+ .ranking-table th,
731
+ .prose .ranking-table th {
732
+ position: sticky;
733
+ top: 0;
734
+ z-index: 3;
735
+ background: #17101f !important;
736
+ color: var(--pruna-text-muted) !important;
737
+ font-size: 11px !important;
738
+ font-weight: 600 !important;
739
  letter-spacing: 0.04em;
740
  text-align: left;
741
  text-transform: uppercase;
 
 
 
 
742
  white-space: nowrap;
743
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) !important;
744
  }
745
+ .ranking-table th.sortable-col { cursor: pointer; user-select: none; }
746
+ .ranking-table th.sortable-col:hover { color: var(--pruna-lavender) !important; }
 
747
  .ranking-table th.sortable-col.sorted-asc::after,
748
  .ranking-table th.sortable-col.sorted-desc::after {
749
  margin-left: 0.35em;
750
  font-size: 0.85em;
751
  opacity: 0.85;
752
  }
753
+ .ranking-table th.sortable-col.sorted-asc::after { content: "▲"; }
754
+ .ranking-table th.sortable-col.sorted-desc::after { content: ""; }
755
+ .ranking-table tbody tr:last-child td { border-bottom: 0 !important; }
756
+ .ranking-table tbody tr:hover td {
757
+ background: rgba(143, 53, 255, 0.16) !important;
 
 
 
 
 
 
 
 
 
 
758
  }
759
  .ranking-table tbody tr:hover td,
760
  .ranking-table tbody tr:hover .rank,
761
  .ranking-table tbody tr:hover .metric-score,
762
+ .ranking-table tbody tr:hover .text-cell,
763
  .ranking-table tbody tr:hover .model-cell strong,
764
+ .ranking-table tbody tr:hover .model-cell span { color: #ffffff !important; }
765
+ .ranking-table .rank,
766
+ .prose .ranking-table .rank {
767
+ position: sticky;
768
+ left: 0;
769
+ z-index: 1;
770
+ box-sizing: border-box;
771
+ width: 3.25rem;
772
+ min-width: 3.25rem;
773
+ color: var(--pruna-lavender) !important;
774
+ font-weight: 700 !important;
775
+ text-align: center;
776
+ background: #17101f !important;
777
  }
778
+ .ranking-table th.rank,
779
+ .prose .ranking-table th.rank {
780
+ top: 0;
781
+ left: 0;
782
+ z-index: 5;
783
+ text-align: center;
784
+ }
785
+ .ranking-table .model-cell,
786
+ .prose .ranking-table .model-cell {
787
+ position: sticky;
788
+ left: 3.25rem;
789
+ z-index: 1;
790
+ min-width: 180px;
791
+ max-width: 260px;
792
+ background: #17101f !important;
793
+ }
794
+ .ranking-table th.model-cell,
795
+ .prose .ranking-table th.model-cell {
796
+ top: 0;
797
+ left: 3.25rem;
798
+ z-index: 5;
799
+ }
800
+ .ranking-table tbody tr:hover .rank,
801
+ .ranking-table tbody tr:hover .model-cell {
802
+ background: #2a1844 !important;
803
  }
804
  .ranking-table .model-cell strong,
805
+ .ranking-table .model-cell span { display: block; }
806
+ .ranking-table .model-cell strong {
807
+ color: var(--pruna-text-primary) !important;
808
+ font-weight: 600 !important;
809
+ white-space: nowrap;
810
+ overflow: hidden;
811
+ text-overflow: ellipsis;
812
  }
813
  .ranking-table .model-cell span {
814
  margin-top: 3px;
815
+ color: var(--pruna-text-muted) !important;
816
  font-size: 12px;
817
  }
818
+ .ranking-table .text-cell,
819
+ .prose .ranking-table .text-cell {
820
+ color: var(--pruna-text-muted) !important;
821
+ font-weight: 500 !important;
822
+ white-space: nowrap;
823
+ }
824
+ .ranking-table .metric-score,
825
+ .prose .ranking-table .metric-score {
826
+ color: var(--pruna-text-primary) !important;
827
  font-variant-numeric: tabular-nums;
828
+ font-weight: 600 !important;
829
+ text-align: right;
830
+ white-space: nowrap;
831
  }
832
+ .ranking-table th.metric-score { text-align: right; }
833
  .ranking-table .empty-state {
834
+ color: var(--pruna-text-muted);
835
  padding: 32px;
836
  text-align: center;
837
  }
838
+
839
+ .compare-samples-help { color: var(--pruna-text-body); margin-bottom: 8px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
840
  .compare-prompt-block {
841
  margin: 0 0 22px;
842
  padding: 14px 16px;
843
+ background: color-mix(in oklab, var(--pruna-bg-card) 82%, black 18%) !important;
 
 
844
  }
845
  .compare-prompt-meta {
846
  display: flex;
847
  justify-content: space-between;
848
  gap: 12px;
849
  margin-bottom: 8px;
850
+ color: var(--pruna-text-muted);
851
  font-size: 12px;
852
  font-weight: 700;
853
  letter-spacing: 0.04em;
 
855
  }
856
  .compare-prompt-text {
857
  margin: 0 0 14px;
858
+ color: var(--pruna-text-body);
859
  font-size: 15px;
860
  line-height: 1.45;
861
  }
862
+ .compare-row { display: grid; gap: 12px; }
863
+ .compare-cell { min-width: 0; }
 
 
 
 
 
864
  .compare-model-label {
865
  margin-bottom: 6px;
866
+ color: var(--pruna-lavender);
867
  font-size: 13px;
868
  font-weight: 700;
869
  word-break: break-word;
 
873
  width: 100%;
874
  aspect-ratio: 1 / 1;
875
  object-fit: cover;
876
+ border-radius: 12px;
877
+ border: 1px solid rgba(255, 255, 255, 0.1);
878
+ background: var(--pruna-bg-elevated);
879
  }
880
  .compare-empty {
881
  padding: 18px;
882
+ border: 1px dashed color-mix(in oklab, var(--pruna-border) 60%, transparent);
883
+ border-radius: 12px;
884
+ color: var(--pruna-text-muted);
885
  text-align: center;
886
  }
887
+
888
+ @media (max-width: 700px) {
889
+ .leaderboard-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
 
 
890
  }
891
+
892
+ /*
893
+ Type scale (playground-like):
894
+ product title > page h1 > section h2/h3 > meta labels > body
895
+ Uppercase lavender is reserved for meta labels only — not section titles.
896
+ */
897
+ .app-header-copy h1 {
898
+ margin: 0;
899
+ font-size: clamp(1.9rem, 3vw, 2.4rem) !important;
900
+ font-weight: 700 !important;
901
+ letter-spacing: -0.035em;
902
+ line-height: 1.1;
903
+ color: #ffffff !important;
904
  }
905
+ .app-header-copy p {
906
+ margin: 6px 0 0;
907
+ color: var(--pruna-text-muted) !important;
908
+ font-size: 0.95rem !important;
909
+ line-height: 1.45;
910
+ font-weight: 400;
911
  }
912
+
913
+ .gradio-container h1,
914
+ .markdown h1, .md h1, .prose h1 {
915
+ margin: 0 0 0.65rem !important;
916
+ padding: 0 !important;
917
+ color: #ffffff !important;
918
+ font-family: var(--pruna-font) !important;
919
+ font-size: 1.5rem !important;
920
+ font-weight: 700 !important;
921
+ letter-spacing: -0.03em !important;
922
+ line-height: 1.2 !important;
923
+ text-transform: none !important;
924
+ }
925
+ .gradio-container h2,
926
+ .markdown h2, .md h2, .prose h2 {
927
+ margin: 1.75rem 0 0.75rem !important;
928
+ padding: 0 !important;
929
+ color: #ffffff !important;
930
+ font-family: var(--pruna-font) !important;
931
+ font-size: 1.25rem !important;
932
+ font-weight: 600 !important;
933
+ letter-spacing: -0.02em !important;
934
+ line-height: 1.3 !important;
935
+ text-transform: none !important;
936
+ }
937
+ .gradio-container h3,
938
+ .markdown h3, .md h3, .prose h3 {
939
+ margin: 1.35rem 0 0.5rem !important;
940
+ padding: 0 !important;
941
+ color: #f4f4f5 !important;
942
+ font-family: var(--pruna-font) !important;
943
+ font-size: 1.05rem !important;
944
+ font-weight: 600 !important;
945
+ letter-spacing: -0.015em !important;
946
+ line-height: 1.35 !important;
947
+ text-transform: none !important;
948
+ }
949
+ .gradio-container h4,
950
+ .markdown h4, .md h4, .prose h4 {
951
+ margin: 1rem 0 0.4rem !important;
952
+ padding: 0 !important;
953
+ color: var(--pruna-text-body) !important;
954
+ font-family: var(--pruna-font) !important;
955
+ font-size: 0.95rem !important;
956
+ font-weight: 600 !important;
957
+ letter-spacing: -0.01em !important;
958
+ line-height: 1.35 !important;
959
+ text-transform: none !important;
960
  }
961
+
962
+ /* Brand header wins over generic h1 rules */
963
+ .app-header .app-header-copy h1 {
964
+ font-size: clamp(1.9rem, 3vw, 2.4rem) !important;
965
+ margin: 0 !important;
966
  }
967
+
968
+ .markdown p, .md p, .prose p,
969
+ .gradio-container .markdown p {
970
+ margin: 0 0 0.8rem !important;
971
+ color: var(--pruna-text-body) !important;
972
+ font-size: 0.95rem !important;
973
+ font-weight: 400 !important;
974
+ line-height: 1.55 !important;
975
+ }
976
+ .markdown li, .md li, .prose li {
977
+ color: var(--pruna-text-body) !important;
978
+ font-size: 0.95rem;
979
+ line-height: 1.5;
980
  }
981
+ .markdown strong, .md strong, .prose strong {
982
+ color: #ffffff !important;
983
+ font-weight: 600 !important;
984
+ }
985
+
986
+ /* Card / list titles sit under section headings */
987
+ .home-snap-title,
988
+ .benchmark-card-title {
989
+ margin: 0 0 6px !important;
990
+ font-size: 0.95rem !important;
991
+ font-weight: 600 !important;
992
+ letter-spacing: -0.01em;
993
+ line-height: 1.3;
994
+ color: #e4e4e7 !important;
995
+ }
996
+ .home-snap-blurb,
997
+ .benchmark-card-blurb {
998
+ color: var(--pruna-text-muted) !important;
999
+ font-size: 0.875rem !important;
1000
+ font-weight: 400 !important;
1001
+ }
1002
+
1003
+ /* Meta labels only — not used for real headings */
1004
+ .home-callouts span,
1005
+ .home-top-label {
1006
+ color: var(--pruna-text-muted) !important;
1007
+ font-size: 11px !important;
1008
+ font-weight: 600 !important;
1009
+ letter-spacing: 0.06em !important;
1010
+ text-transform: uppercase !important;
1011
+ }
1012
+ .home-callouts strong {
1013
+ color: #ffffff !important;
1014
+ font-size: 1.15rem !important;
1015
+ font-weight: 600 !important;
1016
+ }
1017
+ .home-callouts em {
1018
+ color: var(--pruna-text-muted) !important;
1019
+ font-size: 0.85rem !important;
1020
+ }
1021
+
1022
+ label, .block-label span {
1023
+ color: var(--pruna-text-muted) !important;
1024
+ font-size: 0.8rem !important;
1025
+ font-weight: 500 !important;
1026
+ }
1027
+ a { color: var(--pruna-link); }
1028
+
1029
+ /* Gradio form chrome → playground */
1030
+ button.primary, .gr-button-primary,
1031
+ button.primary:hover, .primary-button {
1032
+ background: var(--pruna-accent) !important;
1033
+ border: 1px solid color-mix(in oklab, var(--pruna-accent) 72%, transparent) !important;
1034
+ color: #fff !important;
1035
+ border-radius: 8px !important;
1036
+ box-shadow: inset 0 1px #fff3 !important;
1037
+ font-weight: 600 !important;
1038
+ }
1039
+ .block, .gr-group, .form, .panel {
1040
+ border-color: var(--pruna-border) !important;
1041
+ background: transparent !important;
1042
+ }
1043
+ input, textarea, select, .wrap .secondary-wrap {
1044
+ background: var(--pruna-bg-card) !important;
1045
+ border-color: var(--pruna-border) !important;
1046
+ color: var(--pruna-text-primary) !important;
1047
+ border-radius: 8px !important;
1048
+ }
1049
+ footer, .footer { display: none !important; }
1050
+
1051
+ /* Search label lives in a Gradio BlockTitle span with its own font-weight */
1052
+ .leaderboard-search span[data-testid="block-info"],
1053
+ .leaderboard-search label > span {
1054
+ color: #ffffff !important;
1055
+ font-size: 0.95rem !important;
1056
+ font-weight: 700 !important;
1057
+ letter-spacing: -0.015em !important;
1058
+ }
1059
+ .leaderboard-search input {
1060
+ font-size: 0.95rem !important;
1061
+ font-weight: 600 !important;
1062
+ }
1063
+ .leaderboard-search input::placeholder {
1064
+ color: #d4d4d4 !important;
1065
+ font-size: 0.95rem !important;
1066
+ font-weight: 600 !important;
1067
+ opacity: 1 !important;
1068
  }
1069
  """
1070
 
1071
+ theme = gr.themes.Base(
1072
+ primary_hue=gr.themes.Color(
1073
+ c50="#faf5ff",
1074
+ c100="#f3e8ff",
1075
+ c200="#e9d5ff",
1076
+ c300="#d8b4fe",
1077
+ c400="#c084fc",
1078
+ c500="#9334e9",
1079
+ c600="#9334e9",
1080
+ c700="#7e22ce",
1081
+ c800="#6b21a8",
1082
+ c900="#3b0764",
1083
+ c950="#120b1b",
1084
+ ),
1085
+ secondary_hue="zinc",
1086
+ neutral_hue="zinc",
1087
+ font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"],
1088
+ font_mono=[gr.themes.GoogleFont("IBM Plex Mono"), "ui-monospace", "monospace"],
1089
+ ).set(
1090
+ body_background_fill="#120b1b",
1091
+ body_background_fill_dark="#120b1b",
1092
+ body_text_color="#fafafa",
1093
+ body_text_color_dark="#fafafa",
1094
+ body_text_color_subdued="#a3a3a3",
1095
+ body_text_color_subdued_dark="#a3a3a3",
1096
+ background_fill_primary="#120b1b",
1097
+ background_fill_primary_dark="#120b1b",
1098
+ background_fill_secondary="#171021",
1099
+ background_fill_secondary_dark="#171021",
1100
+ block_background_fill="#1d1429",
1101
+ block_background_fill_dark="#1d1429",
1102
+ block_border_color="#4a3962bf",
1103
+ block_border_color_dark="#4a3962bf",
1104
+ block_label_text_color="#a3a3a3",
1105
+ block_label_text_color_dark="#a3a3a3",
1106
+ block_title_text_color="#fafafa",
1107
+ block_title_text_color_dark="#fafafa",
1108
+ border_color_primary="#4a3962bf",
1109
+ border_color_primary_dark="#4a3962bf",
1110
+ button_primary_background_fill="#9334e9",
1111
+ button_primary_background_fill_dark="#9334e9",
1112
+ button_primary_background_fill_hover="#8f35ff",
1113
+ button_primary_background_fill_hover_dark="#8f35ff",
1114
+ button_primary_text_color="#ffffff",
1115
+ button_primary_text_color_dark="#ffffff",
1116
+ button_secondary_background_fill="#ffffff05",
1117
+ button_secondary_background_fill_dark="#ffffff05",
1118
+ button_secondary_background_fill_hover="rgba(147, 52, 233, 0.10)",
1119
+ button_secondary_background_fill_hover_dark="rgba(147, 52, 233, 0.10)",
1120
+ button_secondary_text_color="#fafafa",
1121
+ button_secondary_text_color_dark="#fafafa",
1122
+ button_secondary_border_color="#d8b4fe26",
1123
+ button_secondary_border_color_dark="#d8b4fe26",
1124
+ input_background_fill="#171021",
1125
+ input_background_fill_dark="#171021",
1126
+ input_border_color="#4a3962bf",
1127
+ input_border_color_dark="#4a3962bf",
1128
+ input_placeholder_color="#a3a3a3",
1129
+ input_placeholder_color_dark="#a3a3a3",
1130
+ link_text_color="#bf8bff",
1131
+ link_text_color_dark="#bf8bff",
1132
+ link_text_color_hover="#d2a8ff",
1133
+ link_text_color_hover_dark="#d2a8ff",
1134
+ shadow_drop="none",
1135
+ shadow_drop_lg="none",
1136
  )
1137
 
1138
+
1139
  space_root = Path(__file__).resolve().parent
1140
  data_dir = space_root / "data"
1141
 
 
1473
 
1474
 
1475
  custom_head = """
1476
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
1477
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
1478
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
1479
  <script>
1480
  (() => {
1481
  if (window.__inferbenchLeaderboardSortBound) return;
 
1537
  theme=theme, fill_width=True, css=custom_css, head=custom_head
1538
  ) as demo:
1539
  render_header()
1540
+ with gr.Tabs(elem_classes="main-tabs"):
1541
  with gr.TabItem("Home"):
1542
  render_home(benchmarks)
1543
  with gr.TabItem("Benchmarks") as benchmarks_tab:
 
1552
 
1553
 
1554
  if __name__ == "__main__":
1555
+ demo.launch(
1556
+ ssr_mode=False,
1557
+ allowed_paths=[str(space_root)],
1558
+ )
pruna-mascot.png ADDED
ui.py CHANGED
@@ -1,10 +1,20 @@
1
  from html import escape
 
 
2
  import random
3
 
4
  import gradio as gr
5
  import pandas as pd
6
  import plotly.graph_objects as go
7
 
 
 
 
 
 
 
 
 
8
 
9
  FILTER_COLUMNS = ["Platform", "Endpoint Owner", "Model", "Optimized"]
10
  MAX_COMPARE_MODELS = 4
@@ -163,14 +173,14 @@ ABOUT_DETAILS_CONTENT = """
163
  Built by [Pruna AI](https://www.pruna.ai/). Contributions and new evaluation runs welcome.
164
  """
165
 
166
- COMMUNITY_CONTENT = """
167
- <div class="community-footer">
168
  <h3>Join the Pruna AI community</h3>
169
  <div class="community-footer-links">
170
  <a rel="nofollow" href="https://x.com/PrunaAI" target="_blank">X / Twitter</a>
171
  <a rel="nofollow" href="https://github.com/PrunaAI/pruna" target="_blank">GitHub</a>
172
  <a rel="nofollow" href="https://www.linkedin.com/company/pruna-ai" target="_blank">LinkedIn</a>
173
- <a rel="nofollow" href="https://discord.com/invite/rskEr4BZJx" target="_blank">Discord</a>
174
  <a rel="nofollow" href="https://www.reddit.com/r/PrunaAI/" target="_blank">Reddit</a>
175
  <a rel="nofollow" href="https://www.pruna.ai/" target="_blank">pruna.ai</a>
176
  </div>
@@ -191,11 +201,14 @@ CITATION_CONTENT = """
191
 
192
  def render_header():
193
  gr.HTML(
194
- """
195
- <div style="text-align: center;">
 
 
196
  <h1>InferBench</h1>
197
- <h2>Compare text-to-image models on quality, speed, and price</h2>
198
- </div>
 
199
  """
200
  )
201
 
@@ -274,39 +287,52 @@ def render_home(benchmarks):
274
  ]
275
  gr.HTML(f'<div class="home-callouts">{"".join(callout_bits)}</div>')
276
 
277
- gr.Markdown("### Benchmark snapshots")
278
- with gr.Row(equal_height=True, elem_classes="benchmark-catalogue-row"):
279
- for benchmark in benchmarks:
280
- data = benchmark["data"]
281
- score_column = benchmark.get("overall_column")
282
- score_columns = benchmark.get("score_columns") or []
283
- if not score_column or score_column not in data.columns:
284
- score_column = score_columns[0] if score_columns else None
285
- top = _top_models(data, score_column, n=3) if score_column else []
286
- score_label = _display_label(score_column) if score_column else "Score"
287
- rows_html = "".join(
288
- f"<li><span class='home-rank'>{idx}</span>"
289
- f"<span class='home-model'>{escape(model)}</span>"
290
- f"<span class='home-score'>{_format_score(score)}</span></li>"
291
- for idx, (model, score) in enumerate(top, start=1)
292
- ) or "<li class='home-empty'>No scores yet.</li>"
293
-
294
- with gr.Column(scale=1, min_width=280):
295
- gr.HTML(
296
- f"""
297
- <div class="home-benchmark-card">
298
- <div class="home-benchmark-title">
299
- {escape(benchmark.get("emoji", "📊"))}
300
- {escape(benchmark["title"])}
301
- </div>
302
- <p class="home-benchmark-blurb">
303
- {escape(benchmark.get("card_description", ""))}
304
- </p>
305
- <div class="home-top-label">Top 3 by {escape(score_label)}</div>
306
- <ol class="home-top-list">{rows_html}</ol>
307
- </div>
308
- """
309
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
 
312
  def _format_leaderboard_cell(column, value):
@@ -353,6 +379,16 @@ def _leaderboard_sort_type(column):
353
  return "number"
354
 
355
 
 
 
 
 
 
 
 
 
 
 
356
  def _leaderboard_html(data, columns, score_columns, overall_column):
357
  leaderboard = _leaderboard_dataframe(
358
  data, columns, score_columns, overall_column
@@ -367,18 +403,19 @@ def _leaderboard_html(data, columns, score_columns, overall_column):
367
  header_cells = []
368
  for index, column in enumerate(leaderboard.columns):
369
  sort_type = _leaderboard_sort_type(column)
 
370
  header_cells.append(
371
- f'<th class="sortable-col" data-col="{index}" data-type="{sort_type}" '
372
- f'title="Sort by {escape(str(column))}">{escape(str(column))}</th>'
 
373
  )
374
  body_rows = []
375
  for _, row in leaderboard.iterrows():
376
  cells = []
377
  for column in leaderboard.columns:
378
- css = "rank" if column == "Rank" else "metric-score"
379
  sort_value = escape(_leaderboard_sort_value(column, row[column]), quote=True)
380
  if column == "Model":
381
- css = "model-cell"
382
  cells.append(
383
  f'<td class="{css}" data-sort-value="{sort_value}">'
384
  f"<strong>{_format_leaderboard_cell(column, row[column])}</strong></td>"
@@ -422,8 +459,10 @@ def render_leaderboard(
422
  with gr.Row(elem_classes="leaderboard-controls"):
423
  search = gr.Textbox(
424
  label="Search models",
425
- placeholder="Search by model or provider",
426
  scale=3,
 
 
427
  )
428
  filter_inputs.append(search)
429
  platform = None
@@ -459,6 +498,7 @@ def render_leaderboard(
459
 
460
  ranking = gr.HTML(
461
  _leaderboard_html(data, columns, score_columns, overall_column),
 
462
  elem_classes="ranking-table-host",
463
  )
464
 
@@ -636,20 +676,38 @@ def render_benchmark_detail(benchmark):
636
  {benchmark["intro"]}
637
  """
638
  )
639
- with gr.Tabs(elem_classes="subtabs", selected=0) as detail_tabs:
640
- with gr.TabItem("Leaderboard"):
641
- render_leaderboard(
642
- benchmark["data"],
643
- benchmark["columns"],
644
- note=benchmark.get("note"),
645
- score_columns=benchmark.get("score_columns"),
646
- overall_column=benchmark.get("overall_column"),
647
- )
648
- with gr.TabItem("Graphs"):
649
- render_benchmark_graphs(benchmark)
650
- with gr.TabItem("Compare samples"):
651
- render_compare_samples(benchmark)
652
- return detail_tabs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
653
 
654
 
655
  def render_compare_samples(benchmark):
@@ -830,25 +888,41 @@ def render_benchmarks(benchmarks):
830
  for row in card_rows:
831
  with gr.Row(equal_height=True, elem_classes="benchmark-catalogue-row"):
832
  for benchmark in row:
833
- with gr.Column(scale=1, min_width=280):
834
- with gr.Group(elem_classes="benchmark-card"):
835
- gr.Markdown(
836
- f"""
837
- ## {benchmark.get("emoji", "📊")} {benchmark["title"]}
838
-
839
- {benchmark["card_description"]}
840
- """
841
- )
842
- open_buttons.append(
843
- (
844
- benchmark["id"],
845
- gr.Button("View benchmark →", variant="primary"),
846
- )
 
 
 
 
 
 
 
 
 
 
 
 
847
  )
 
848
 
849
  for benchmark in benchmarks:
850
  with gr.Column(visible=False) as detail:
851
- back_button = gr.Button("← All benchmarks", size="sm")
 
 
 
852
  render_benchmark_detail(benchmark)
853
  detail_entries.append((benchmark["id"], detail, back_button))
854
 
@@ -938,8 +1012,8 @@ def _build_pareto_figure(
938
  hovertemplate=hover,
939
  marker={
940
  "size": 9,
941
- "color": "#c4b5fd",
942
- "opacity": 0.75,
943
  "line": {"width": 0},
944
  },
945
  )
@@ -953,11 +1027,11 @@ def _build_pareto_figure(
953
  name="On frontier",
954
  text=frontier["Model"],
955
  hovertemplate=hover,
956
- line={"color": "#7c3aed", "width": 2.5},
957
  marker={
958
  "size": 12,
959
- "color": "#db2777",
960
- "line": {"width": 1.5, "color": "#7c3aed"},
961
  },
962
  )
963
  )
@@ -977,30 +1051,30 @@ def _build_pareto_figure(
977
  "xanchor": "center",
978
  "x": 0.5,
979
  "bgcolor": "rgba(0,0,0,0)",
980
- "font": {"color": "#e9d5ff", "size": 12},
981
  },
982
- # Dark-theme plot: soft purple panel + light text (readable, not a white flash).
983
- plot_bgcolor="#1e1b4b",
984
- paper_bgcolor="#17153b",
985
- font={"color": "#e9d5ff", "size": 13},
986
  )
987
- axis_font = {"color": "#f3e8ff", "size": 13}
988
- tick_font = {"color": "#ddd6fe", "size": 12}
989
  fig.update_xaxes(
990
  showgrid=True,
991
- gridcolor="rgba(167, 139, 250, 0.28)",
992
  zeroline=False,
993
  title_font=axis_font,
994
  tickfont=tick_font,
995
- color="#e9d5ff",
996
  )
997
  fig.update_yaxes(
998
  showgrid=True,
999
- gridcolor="rgba(167, 139, 250, 0.28)",
1000
  zeroline=False,
1001
  title_font=axis_font,
1002
  tickfont=tick_font,
1003
- color="#e9d5ff",
1004
  )
1005
  return fig
1006
 
@@ -1079,10 +1153,11 @@ def render_benchmark_graphs(benchmark):
1079
  if price_figures or time_figures:
1080
  gr.Markdown(
1081
  "### Pareto frontiers\n\n"
1082
- "<span style='color:#4c1d95;font-size:0.95rem;'>"
1083
- "Pink = on the frontier (lower cost or time at the same or better score). "
1084
- "Light purple = below the frontier."
1085
- "</span>"
 
1086
  )
1087
  with gr.Row(equal_height=False):
1088
  with gr.Column(scale=1, min_width=320):
@@ -1118,6 +1193,10 @@ def render_about():
1118
 
1119
 
1120
  def render_footer():
1121
- gr.HTML(COMMUNITY_CONTENT)
1122
- with gr.Accordion("Citation", open=False):
 
 
 
 
1123
  gr.Markdown(CITATION_CONTENT)
 
1
  from html import escape
2
+ from pathlib import Path
3
+ import base64
4
  import random
5
 
6
  import gradio as gr
7
  import pandas as pd
8
  import plotly.graph_objects as go
9
 
10
+ _MASCOT_PATH = Path(__file__).resolve().parent / "pruna-mascot.png"
11
+ _MASCOT_DATA_URI = (
12
+ "data:image/png;base64,"
13
+ + base64.b64encode(_MASCOT_PATH.read_bytes()).decode("ascii")
14
+ if _MASCOT_PATH.exists()
15
+ else "https://playground.pruna.ai/logo.svg"
16
+ )
17
+
18
 
19
  FILTER_COLUMNS = ["Platform", "Endpoint Owner", "Model", "Optimized"]
20
  MAX_COMPARE_MODELS = 4
 
173
  Built by [Pruna AI](https://www.pruna.ai/). Contributions and new evaluation runs welcome.
174
  """
175
 
176
+ FOOTER_CONTENT = """
177
+ <div class="page-footer">
178
  <h3>Join the Pruna AI community</h3>
179
  <div class="community-footer-links">
180
  <a rel="nofollow" href="https://x.com/PrunaAI" target="_blank">X / Twitter</a>
181
  <a rel="nofollow" href="https://github.com/PrunaAI/pruna" target="_blank">GitHub</a>
182
  <a rel="nofollow" href="https://www.linkedin.com/company/pruna-ai" target="_blank">LinkedIn</a>
183
+ <a rel="nofollow" href="https://discord.gg/JFQmtFKCjd" target="_blank">Discord</a>
184
  <a rel="nofollow" href="https://www.reddit.com/r/PrunaAI/" target="_blank">Reddit</a>
185
  <a rel="nofollow" href="https://www.pruna.ai/" target="_blank">pruna.ai</a>
186
  </div>
 
201
 
202
  def render_header():
203
  gr.HTML(
204
+ f"""
205
+ <header class="app-header">
206
+ <img class="app-header-logo" src="{_MASCOT_DATA_URI}" alt="" />
207
+ <div class="app-header-copy">
208
  <h1>InferBench</h1>
209
+ <p>Compare text-to-image models on quality, speed, and price</p>
210
+ </div>
211
+ </header>
212
  """
213
  )
214
 
 
287
  ]
288
  gr.HTML(f'<div class="home-callouts">{"".join(callout_bits)}</div>')
289
 
290
+ gr.Markdown("## Benchmark snapshots")
291
+ title_cells = []
292
+ blurb_cells = []
293
+ top_cells = []
294
+ for benchmark in benchmarks:
295
+ data = benchmark["data"]
296
+ score_column = benchmark.get("overall_column")
297
+ score_columns = benchmark.get("score_columns") or []
298
+ if not score_column or score_column not in data.columns:
299
+ score_column = score_columns[0] if score_columns else None
300
+ top = _top_models(data, score_column, n=3) if score_column else []
301
+ score_label = _display_label(score_column) if score_column else "Score"
302
+ rows_html = "".join(
303
+ f"<li><span class='home-rank'>{idx}</span>"
304
+ f"<span class='home-model'>{escape(model)}</span>"
305
+ f"<span class='home-score'>{_format_score(score)}</span></li>"
306
+ for idx, (model, score) in enumerate(top, start=1)
307
+ ) or "<li class='home-empty'>No scores yet.</li>"
308
+ title_cells.append(
309
+ "<td class='home-snap-cell'>"
310
+ "<div class='home-snap-title'>"
311
+ f"<span class='home-snap-emoji' aria-hidden='true'>{escape(benchmark.get('emoji', '📊'))}</span>"
312
+ f"<span>{escape(benchmark['title'])}</span>"
313
+ "</div></td>"
314
+ )
315
+ blurb_cells.append(
316
+ "<td class='home-snap-cell'>"
317
+ f"<p class='home-snap-blurb'>{escape(benchmark.get('card_description', ''))}</p>"
318
+ "</td>"
319
+ )
320
+ top_cells.append(
321
+ "<td class='home-snap-cell'>"
322
+ "<div class='home-snap-top'>"
323
+ f"<div class='home-top-label'>Top 3 by {escape(score_label)}</div>"
324
+ f"<ol class='home-top-list'>{rows_html}</ol>"
325
+ "</div></td>"
326
+ )
327
+ gr.HTML(
328
+ "<table class='home-snapshots-table' role='presentation'>"
329
+ f"<tr>{''.join(title_cells)}</tr>"
330
+ f"<tr>{''.join(blurb_cells)}</tr>"
331
+ f"<tr>{''.join(top_cells)}</tr>"
332
+ "</table>",
333
+ padding=False,
334
+ elem_classes="home-snapshots-host",
335
+ )
336
 
337
 
338
  def _format_leaderboard_cell(column, value):
 
379
  return "number"
380
 
381
 
382
+ def _leaderboard_cell_class(column):
383
+ if column == "Rank":
384
+ return "rank"
385
+ if column == "Model":
386
+ return "model-cell"
387
+ if _leaderboard_sort_type(column) == "text":
388
+ return "text-cell"
389
+ return "metric-score"
390
+
391
+
392
  def _leaderboard_html(data, columns, score_columns, overall_column):
393
  leaderboard = _leaderboard_dataframe(
394
  data, columns, score_columns, overall_column
 
403
  header_cells = []
404
  for index, column in enumerate(leaderboard.columns):
405
  sort_type = _leaderboard_sort_type(column)
406
+ cell_class = _leaderboard_cell_class(column)
407
  header_cells.append(
408
+ f'<th class="sortable-col {cell_class}" data-col="{index}" '
409
+ f'data-type="{sort_type}" title="Sort by {escape(str(column))}">'
410
+ f"{escape(str(column))}</th>"
411
  )
412
  body_rows = []
413
  for _, row in leaderboard.iterrows():
414
  cells = []
415
  for column in leaderboard.columns:
416
+ css = _leaderboard_cell_class(column)
417
  sort_value = escape(_leaderboard_sort_value(column, row[column]), quote=True)
418
  if column == "Model":
 
419
  cells.append(
420
  f'<td class="{css}" data-sort-value="{sort_value}">'
421
  f"<strong>{_format_leaderboard_cell(column, row[column])}</strong></td>"
 
459
  with gr.Row(elem_classes="leaderboard-controls"):
460
  search = gr.Textbox(
461
  label="Search models",
462
+ placeholder="Type a model or provider name…",
463
  scale=3,
464
+ max_lines=1,
465
+ elem_classes="leaderboard-search",
466
  )
467
  filter_inputs.append(search)
468
  platform = None
 
498
 
499
  ranking = gr.HTML(
500
  _leaderboard_html(data, columns, score_columns, overall_column),
501
+ padding=False,
502
  elem_classes="ranking-table-host",
503
  )
504
 
 
676
  {benchmark["intro"]}
677
  """
678
  )
679
+ view_menu = gr.Radio(
680
+ choices=["Leaderboard", "Graphs", "Compare samples"],
681
+ value="Leaderboard",
682
+ show_label=False,
683
+ container=False,
684
+ elem_classes="benchmark-view-menu",
685
+ )
686
+ with gr.Column(visible=True) as leaderboard_view:
687
+ render_leaderboard(
688
+ benchmark["data"],
689
+ benchmark["columns"],
690
+ note=benchmark.get("note"),
691
+ score_columns=benchmark.get("score_columns"),
692
+ overall_column=benchmark.get("overall_column"),
693
+ )
694
+ with gr.Column(visible=False) as graphs_view:
695
+ render_benchmark_graphs(benchmark)
696
+ with gr.Column(visible=False) as compare_view:
697
+ render_compare_samples(benchmark)
698
+
699
+ def switch_view(choice):
700
+ return (
701
+ gr.update(visible=choice == "Leaderboard"),
702
+ gr.update(visible=choice == "Graphs"),
703
+ gr.update(visible=choice == "Compare samples"),
704
+ )
705
+
706
+ view_menu.change(
707
+ switch_view,
708
+ inputs=view_menu,
709
+ outputs=[leaderboard_view, graphs_view, compare_view],
710
+ )
711
 
712
 
713
  def render_compare_samples(benchmark):
 
888
  for row in card_rows:
889
  with gr.Row(equal_height=True, elem_classes="benchmark-catalogue-row"):
890
  for benchmark in row:
891
+ with gr.Column(
892
+ scale=1,
893
+ min_width=280,
894
+ elem_classes="benchmark-card-col",
895
+ ):
896
+ gr.HTML(
897
+ f"""
898
+ <div class="benchmark-card-body">
899
+ <div class="benchmark-card-title">
900
+ {escape(benchmark.get("emoji", "📊"))}
901
+ {escape(benchmark["title"])}
902
+ </div>
903
+ <p class="benchmark-card-blurb">
904
+ {escape(benchmark.get("card_description", ""))}
905
+ </p>
906
+ </div>
907
+ """
908
+ )
909
+ open_buttons.append(
910
+ (
911
+ benchmark["id"],
912
+ gr.Button(
913
+ "View benchmark →",
914
+ variant="primary",
915
+ elem_classes="benchmark-open-btn",
916
+ ),
917
  )
918
+ )
919
 
920
  for benchmark in benchmarks:
921
  with gr.Column(visible=False) as detail:
922
+ back_button = gr.Button(
923
+ "← All benchmarks",
924
+ elem_classes="benchmark-back-btn",
925
+ )
926
  render_benchmark_detail(benchmark)
927
  detail_entries.append((benchmark["id"], detail, back_button))
928
 
 
1012
  hovertemplate=hover,
1013
  marker={
1014
  "size": 9,
1015
+ "color": "#d8b4fe",
1016
+ "opacity": 0.8,
1017
  "line": {"width": 0},
1018
  },
1019
  )
 
1027
  name="On frontier",
1028
  text=frontier["Model"],
1029
  hovertemplate=hover,
1030
+ line={"color": "#69a45c", "width": 2.5},
1031
  marker={
1032
  "size": 12,
1033
+ "color": "#69a45c",
1034
+ "line": {"width": 1.5, "color": "#86c077"},
1035
  },
1036
  )
1037
  )
 
1051
  "xanchor": "center",
1052
  "x": 0.5,
1053
  "bgcolor": "rgba(0,0,0,0)",
1054
+ "font": {"color": "#d4d4d4", "size": 12},
1055
  },
1056
+ # Match Pruna playground surfaces (#120b1b / #1d1429).
1057
+ plot_bgcolor="#1d1429",
1058
+ paper_bgcolor="#171021",
1059
+ font={"color": "#d4d4d4", "size": 13},
1060
  )
1061
+ axis_font = {"color": "#fafafa", "size": 13}
1062
+ tick_font = {"color": "#a3a3a3", "size": 12}
1063
  fig.update_xaxes(
1064
  showgrid=True,
1065
+ gridcolor="rgba(74, 57, 98, 0.55)",
1066
  zeroline=False,
1067
  title_font=axis_font,
1068
  tickfont=tick_font,
1069
+ color="#d4d4d4",
1070
  )
1071
  fig.update_yaxes(
1072
  showgrid=True,
1073
+ gridcolor="rgba(74, 57, 98, 0.55)",
1074
  zeroline=False,
1075
  title_font=axis_font,
1076
  tickfont=tick_font,
1077
+ color="#d4d4d4",
1078
  )
1079
  return fig
1080
 
 
1153
  if price_figures or time_figures:
1154
  gr.Markdown(
1155
  "### Pareto frontiers\n\n"
1156
+ "<span style='color:#a3a3a3;font-size:0.95rem;'>"
1157
+ "Green = on the frontier (lower cost or time at the same or better score). "
1158
+ "Lavender = below the frontier."
1159
+ "</span><br/>"
1160
+ "<strong style='color:#ffffff;font-size:1rem;'>Hover a point to see which model it is.</strong>"
1161
  )
1162
  with gr.Row(equal_height=False):
1163
  with gr.Column(scale=1, min_width=320):
 
1193
 
1194
 
1195
  def render_footer():
1196
+ gr.HTML(FOOTER_CONTENT, padding=False, elem_classes="page-footer-host")
1197
+ with gr.Accordion(
1198
+ "Citation",
1199
+ open=False,
1200
+ elem_classes="citation-accordion",
1201
+ ):
1202
  gr.Markdown(CITATION_CONTENT)