ruby_llm-agent-evaluations 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +25 -0
  3. data/LICENSE +21 -0
  4. data/README.md +332 -0
  5. data/app/models/ruby_llm/evaluations/application_record.rb +32 -0
  6. data/app/models/ruby_llm/evaluations/case_result.rb +39 -0
  7. data/app/models/ruby_llm/evaluations/metric_result.rb +22 -0
  8. data/app/models/ruby_llm/evaluations/run.rb +55 -0
  9. data/config/routes.rb +5 -0
  10. data/db/migrate/20261011000000_create_agent_evaluation_history.rb +145 -0
  11. data/db/migrate/20261011000100_rename_case_criteria_to_minimum_scores.rb +7 -0
  12. data/docs/images/dashboard-case.png +0 -0
  13. data/docs/images/dashboard-history.png +0 -0
  14. data/docs/images/dashboard-mobile.png +0 -0
  15. data/docs/images/dashboard-regression.png +0 -0
  16. data/docs/images/dashboard-without-judge.png +0 -0
  17. data/docs/images/html-report.png +0 -0
  18. data/examples/api_replay_eval.rb +41 -0
  19. data/examples/context_bloat_eval.rb +77 -0
  20. data/examples/fixtures/large_return_policy.json +8006 -0
  21. data/examples/fixtures/order-42.json +8 -0
  22. data/examples/ruby_llm_eval.rb +26 -0
  23. data/examples/semantic_actions_eval.rb +43 -0
  24. data/examples/support_eval.rb +52 -0
  25. data/exe/ruby_llm-agent-evaluations +5 -0
  26. data/lib/ruby_llm/evaluations/action_group.rb +21 -0
  27. data/lib/ruby_llm/evaluations/actions.rb +30 -0
  28. data/lib/ruby_llm/evaluations/adapters.rb +40 -0
  29. data/lib/ruby_llm/evaluations/api_replay.rb +426 -0
  30. data/lib/ruby_llm/evaluations/cli.rb +209 -0
  31. data/lib/ruby_llm/evaluations/context.rb +19 -0
  32. data/lib/ruby_llm/evaluations/dashboard/dashboard.css +939 -0
  33. data/lib/ruby_llm/evaluations/dashboard/error.erb +1 -0
  34. data/lib/ruby_llm/evaluations/dashboard/index.erb +46 -0
  35. data/lib/ruby_llm/evaluations/dashboard/layout.erb +18 -0
  36. data/lib/ruby_llm/evaluations/dashboard/run.erb +54 -0
  37. data/lib/ruby_llm/evaluations/dashboard.rb +270 -0
  38. data/lib/ruby_llm/evaluations/data.rb +55 -0
  39. data/lib/ruby_llm/evaluations/engine.rb +18 -0
  40. data/lib/ruby_llm/evaluations/evaluators.rb +65 -0
  41. data/lib/ruby_llm/evaluations/judge_metric.rb +42 -0
  42. data/lib/ruby_llm/evaluations/report.rb +248 -0
  43. data/lib/ruby_llm/evaluations/response.rb +50 -0
  44. data/lib/ruby_llm/evaluations/runner.rb +139 -0
  45. data/lib/ruby_llm/evaluations/suite.rb +171 -0
  46. data/lib/ruby_llm/evaluations/version.rb +7 -0
  47. data/lib/ruby_llm/evaluations.rb +48 -0
  48. metadata +156 -0
@@ -0,0 +1,939 @@
1
+ :root {
2
+ color-scheme: light;
3
+ --ink: #172b42;
4
+ --muted: #56687c;
5
+ --teal: #087780;
6
+ --line: #dce5ec;
7
+ --surface: #fff;
8
+ --canvas: #f4f7fa;
9
+ --danger: #a72c3b;
10
+ --success: #11634f;
11
+ --radius: 14px;
12
+ font-family:
13
+ Inter,
14
+ -apple-system,
15
+ BlinkMacSystemFont,
16
+ "Segoe UI",
17
+ sans-serif;
18
+ font-size: 15px;
19
+ line-height: 1.55;
20
+ color: var(--ink);
21
+ background: var(--canvas);
22
+ }
23
+ * {
24
+ box-sizing: border-box;
25
+ }
26
+ body {
27
+ margin: 0;
28
+ }
29
+ a {
30
+ color: var(--teal);
31
+ text-decoration: none;
32
+ }
33
+ a:hover {
34
+ text-decoration: underline;
35
+ }
36
+ button,
37
+ input,
38
+ select {
39
+ font: inherit;
40
+ }
41
+ button,
42
+ a,
43
+ select,
44
+ summary {
45
+ -webkit-tap-highlight-color: transparent;
46
+ }
47
+ a:focus-visible,
48
+ button:focus-visible,
49
+ select:focus-visible,
50
+ summary:focus-visible {
51
+ outline: 3px solid #087780;
52
+ outline-offset: 4px;
53
+ }
54
+ h1,
55
+ h2,
56
+ h3,
57
+ h4,
58
+ p {
59
+ margin-top: 0;
60
+ }
61
+ h1 {
62
+ font-size: clamp(1.8rem, 3vw, 2.45rem);
63
+ letter-spacing: -0.045em;
64
+ line-height: 1.18;
65
+ margin-bottom: 12px;
66
+ font-weight: 730;
67
+ overflow-wrap: anywhere;
68
+ }
69
+ h2 {
70
+ font-size: 1.35rem;
71
+ letter-spacing: -0.025em;
72
+ line-height: 1.3;
73
+ margin-bottom: 8px;
74
+ }
75
+ h3 {
76
+ font-size: 1.08rem;
77
+ line-height: 1.4;
78
+ margin-bottom: 12px;
79
+ }
80
+ h4 {
81
+ font-size: 0.8rem;
82
+ letter-spacing: 0.03em;
83
+ margin-bottom: 9px;
84
+ }
85
+ pre {
86
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
87
+ font-size: 0.82rem;
88
+ line-height: 1.65;
89
+ white-space: pre-wrap;
90
+ overflow-wrap: anywhere;
91
+ margin: 0;
92
+ }
93
+ button {
94
+ cursor: pointer;
95
+ }
96
+ .site-header {
97
+ background: var(--surface);
98
+ border-bottom: 1px solid var(--line);
99
+ }
100
+ .header-inner {
101
+ max-width: 1264px;
102
+ margin: auto;
103
+ padding: 20px 32px;
104
+ display: flex;
105
+ justify-content: space-between;
106
+ align-items: center;
107
+ gap: 24px;
108
+ }
109
+ .brand {
110
+ color: var(--ink);
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 12px;
114
+ font-size: 1rem;
115
+ letter-spacing: -0.025em;
116
+ }
117
+ .brand:hover {
118
+ text-decoration: none;
119
+ }
120
+ .brand strong {
121
+ font-weight: 700;
122
+ }
123
+ .brand-mark {
124
+ display: grid;
125
+ place-items: center;
126
+ width: 35px;
127
+ height: 35px;
128
+ border-radius: 10px;
129
+ background: var(--ink);
130
+ color: #fff;
131
+ font-weight: 800;
132
+ font-size: 1.1rem;
133
+ }
134
+ .header-inner nav {
135
+ display: flex;
136
+ align-items: center;
137
+ gap: 27px;
138
+ font-size: 0.85rem;
139
+ font-weight: 600;
140
+ }
141
+ .header-inner nav > a {
142
+ color: var(--ink);
143
+ }
144
+ .local-badge {
145
+ color: var(--muted);
146
+ font-size: 0.75rem;
147
+ border: 1px solid var(--line);
148
+ padding: 4px 10px;
149
+ border-radius: 20px;
150
+ font-weight: 500;
151
+ }
152
+ main {
153
+ max-width: 1264px;
154
+ margin: auto;
155
+ padding: 43px 32px 56px;
156
+ outline: none;
157
+ min-height: calc(100vh - 162px);
158
+ }
159
+ .page-heading {
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: space-between;
163
+ gap: 24px;
164
+ margin-bottom: 28px;
165
+ }
166
+ .eyebrow {
167
+ text-transform: uppercase;
168
+ font-size: 0.68rem;
169
+ letter-spacing: 0.13em;
170
+ font-weight: 750;
171
+ color: var(--teal);
172
+ margin-bottom: 11px;
173
+ display: block;
174
+ }
175
+ .lead {
176
+ color: var(--muted);
177
+ font-size: 0.95rem;
178
+ margin: 0;
179
+ max-width: 750px;
180
+ }
181
+ .workspace-status {
182
+ display: flex;
183
+ gap: 8px;
184
+ align-items: center;
185
+ font-size: 0.8rem;
186
+ color: var(--muted);
187
+ white-space: nowrap;
188
+ }
189
+ .workspace-status > span {
190
+ height: 7px;
191
+ width: 7px;
192
+ background: var(--teal);
193
+ border-radius: 50%;
194
+ }
195
+ .panel {
196
+ background: var(--surface);
197
+ border: 1px solid var(--line);
198
+ border-radius: var(--radius);
199
+ box-shadow: 0 3px 12px #172b4203;
200
+ }
201
+ .filter-panel {
202
+ padding: 20px 24px;
203
+ margin-bottom: 24px;
204
+ }
205
+ .filter-form {
206
+ display: flex;
207
+ align-items: flex-end;
208
+ gap: 12px;
209
+ }
210
+ .field {
211
+ display: flex;
212
+ flex-direction: column;
213
+ gap: 7px;
214
+ flex: 1;
215
+ max-width: 340px;
216
+ min-width: 0;
217
+ }
218
+ .field label {
219
+ font-size: 0.75rem;
220
+ font-weight: 650;
221
+ }
222
+ .field select {
223
+ background: #fff;
224
+ border: 1px solid #bfccd8;
225
+ border-radius: 7px;
226
+ color: var(--ink);
227
+ height: 42px;
228
+ padding: 8px 30px 8px 12px;
229
+ max-width: 100%;
230
+ width: 100%;
231
+ }
232
+ .button {
233
+ min-height: 42px;
234
+ display: inline-flex;
235
+ align-items: center;
236
+ justify-content: center;
237
+ padding: 9px 17px;
238
+ border-radius: 7px;
239
+ border: 1px solid transparent;
240
+ font-weight: 650;
241
+ font-size: 0.82rem;
242
+ white-space: nowrap;
243
+ }
244
+ .button:hover {
245
+ text-decoration: none;
246
+ }
247
+ .primary {
248
+ background: var(--teal);
249
+ color: #fff;
250
+ border-color: var(--teal);
251
+ }
252
+ .primary:hover {
253
+ background: #05646d;
254
+ }
255
+ .quiet {
256
+ background: #f3f6f8;
257
+ border-color: var(--line);
258
+ color: var(--muted);
259
+ }
260
+ .filter-hint {
261
+ font-size: 0.73rem;
262
+ color: var(--muted);
263
+ margin: 12px 0 0;
264
+ }
265
+ .stats-grid {
266
+ display: grid;
267
+ grid-template-columns: repeat(4, minmax(0, 1fr));
268
+ gap: 16px;
269
+ margin-bottom: 25px;
270
+ }
271
+ .stat-card {
272
+ border: 1px solid var(--line);
273
+ background: #fff;
274
+ border-radius: var(--radius);
275
+ padding: 21px 23px;
276
+ display: flex;
277
+ flex-direction: column;
278
+ }
279
+ .stat-label {
280
+ font-size: 0.76rem;
281
+ color: var(--muted);
282
+ font-weight: 600;
283
+ letter-spacing: 0.01em;
284
+ }
285
+ .stat-card > strong {
286
+ font-size: 2rem;
287
+ line-height: 1.3;
288
+ letter-spacing: -0.045em;
289
+ margin: 9px 0;
290
+ }
291
+ .stat-caption {
292
+ font-size: 0.72rem;
293
+ color: var(--muted);
294
+ overflow-wrap: anywhere;
295
+ }
296
+ .section-heading {
297
+ display: flex;
298
+ justify-content: space-between;
299
+ align-items: center;
300
+ gap: 20px;
301
+ }
302
+ .section-heading .eyebrow {
303
+ margin-bottom: 7px;
304
+ }
305
+ .section-heading h2 {
306
+ margin: 0;
307
+ }
308
+ .chart-panel {
309
+ padding: 25px 27px 20px;
310
+ margin-bottom: 25px;
311
+ }
312
+ .section-description {
313
+ font-size: 0.82rem;
314
+ color: var(--muted);
315
+ margin: 12px 0 16px;
316
+ }
317
+ .tag {
318
+ background: #edf5f5;
319
+ border: 1px solid #d5e6e7;
320
+ color: #2b6166;
321
+ font-size: 0.72rem;
322
+ padding: 5px 10px;
323
+ border-radius: 6px;
324
+ white-space: nowrap;
325
+ }
326
+ .trend-chart {
327
+ display: block;
328
+ width: 100%;
329
+ height: auto;
330
+ min-height: 180px;
331
+ }
332
+ .grid-line {
333
+ stroke: #e1e8ee;
334
+ stroke-width: 1;
335
+ stroke-dasharray: 3 5;
336
+ }
337
+ .axis-label {
338
+ fill: #56687c;
339
+ font-size: 11px;
340
+ font-family: inherit;
341
+ }
342
+ .chart-point {
343
+ stroke: #fff;
344
+ stroke-width: 2;
345
+ transition: r 0.12s;
346
+ }
347
+ .trend-chart a:hover .chart-point,
348
+ .trend-chart a:focus .chart-point {
349
+ r: 8;
350
+ }
351
+ .chart-legend {
352
+ display: flex;
353
+ gap: 8px 23px;
354
+ flex-wrap: wrap;
355
+ list-style: none;
356
+ font-size: 0.72rem;
357
+ color: var(--muted);
358
+ padding: 7px 0 0;
359
+ margin: 0;
360
+ }
361
+ .chart-legend li {
362
+ display: flex;
363
+ align-items: center;
364
+ gap: 7px;
365
+ overflow-wrap: anywhere;
366
+ max-width: 100%;
367
+ }
368
+ .chart-legend svg {
369
+ flex-shrink: 0;
370
+ }
371
+ .history-panel {
372
+ overflow: hidden;
373
+ }
374
+ .history-panel > .section-heading {
375
+ padding: 25px 27px 22px;
376
+ }
377
+ .muted {
378
+ color: var(--muted);
379
+ }
380
+ .table-scroll {
381
+ position: relative;
382
+ overflow-x: auto;
383
+ }
384
+ table {
385
+ width: 100%;
386
+ border-collapse: collapse;
387
+ text-align: left;
388
+ font-size: 0.82rem;
389
+ }
390
+ th {
391
+ font-size: 0.67rem;
392
+ color: var(--muted);
393
+ letter-spacing: 0.05em;
394
+ text-transform: uppercase;
395
+ background: #f8fafc;
396
+ font-weight: 700;
397
+ white-space: nowrap;
398
+ }
399
+ th,
400
+ td {
401
+ padding: 16px 20px;
402
+ border-bottom: 1px solid #e4ebf0;
403
+ vertical-align: top;
404
+ }
405
+ tbody tr:last-child td {
406
+ border-bottom: 0;
407
+ }
408
+ .history-table {
409
+ min-width: 865px;
410
+ }
411
+ .history-table th:first-child,
412
+ .history-table td:first-child {
413
+ padding-left: 27px;
414
+ }
415
+ .history-table th:last-child,
416
+ .history-table td:last-child {
417
+ padding-right: 27px;
418
+ }
419
+ .history-table tbody tr:hover {
420
+ background: #fbfdfd;
421
+ }
422
+ .suite-link {
423
+ font-weight: 700;
424
+ color: var(--ink);
425
+ overflow-wrap: anywhere;
426
+ }
427
+ .table-secondary {
428
+ display: block;
429
+ font-size: 0.71rem;
430
+ color: var(--muted);
431
+ margin-top: 4px;
432
+ }
433
+ .mono {
434
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
435
+ letter-spacing: -0.02em;
436
+ }
437
+ .quality-score {
438
+ font-size: 1rem;
439
+ }
440
+ .badge {
441
+ display: inline-flex;
442
+ align-items: center;
443
+ font-size: 0.67rem;
444
+ font-weight: 700;
445
+ padding: 4px 9px;
446
+ border-radius: 20px;
447
+ line-height: 1.35;
448
+ white-space: nowrap;
449
+ }
450
+ .passed {
451
+ color: #11634f;
452
+ background: #e8f6ef;
453
+ border: 1px solid #c7e7d9;
454
+ }
455
+ .failed,
456
+ .error {
457
+ color: #9f2736;
458
+ background: #fdf0f1;
459
+ border: 1px solid #f0ced3;
460
+ }
461
+ .neutral {
462
+ color: #526479;
463
+ background: #f0f4f7;
464
+ border: 1px solid #dce5ec;
465
+ }
466
+ .danger-text {
467
+ color: var(--danger) !important;
468
+ }
469
+ .teal-text {
470
+ color: var(--success) !important;
471
+ }
472
+ .detail-link {
473
+ font-size: 0.76rem;
474
+ white-space: nowrap;
475
+ font-weight: 650;
476
+ }
477
+ .empty-state {
478
+ text-align: center;
479
+ padding: 68px 25px;
480
+ }
481
+ .empty-state h2 {
482
+ font-size: 1.6rem;
483
+ }
484
+ .empty-state p {
485
+ color: var(--muted);
486
+ max-width: 490px;
487
+ margin: 12px auto 23px;
488
+ }
489
+ .empty-icon {
490
+ height: 53px;
491
+ width: 53px;
492
+ border-radius: 14px;
493
+ background: #e7f3f4;
494
+ color: var(--teal);
495
+ font-size: 1.8rem;
496
+ display: grid;
497
+ place-items: center;
498
+ margin: 0 auto 20px;
499
+ }
500
+ .command {
501
+ display: inline-block;
502
+ background: #f1f5f8;
503
+ border: 1px solid var(--line);
504
+ border-radius: 7px;
505
+ padding: 12px 18px;
506
+ max-width: 100%;
507
+ text-align: left;
508
+ }
509
+ .site-footer {
510
+ max-width: 1264px;
511
+ margin: auto;
512
+ padding: 20px 32px 25px;
513
+ border-top: 1px solid var(--line);
514
+ display: flex;
515
+ justify-content: space-between;
516
+ gap: 15px;
517
+ color: var(--muted);
518
+ font-size: 0.7rem;
519
+ }
520
+ .back-link {
521
+ display: inline-block;
522
+ font-size: 0.8rem;
523
+ margin-bottom: 24px;
524
+ font-weight: 600;
525
+ }
526
+ .comparison-panel {
527
+ padding: 25px 27px;
528
+ margin-bottom: 32px;
529
+ }
530
+ .comparison-deltas {
531
+ display: flex;
532
+ gap: 60px;
533
+ margin: 19px 0 23px;
534
+ padding: 17px 0;
535
+ border-top: 1px solid var(--line);
536
+ border-bottom: 1px solid var(--line);
537
+ }
538
+ .comparison-deltas > div {
539
+ display: flex;
540
+ flex-direction: column;
541
+ gap: 5px;
542
+ }
543
+ .comparison-deltas span {
544
+ font-size: 0.75rem;
545
+ color: var(--muted);
546
+ }
547
+ .comparison-deltas strong {
548
+ font-size: 1.35rem;
549
+ letter-spacing: -0.03em;
550
+ }
551
+ .comparison-panel h3 {
552
+ margin: 24px 0 9px;
553
+ }
554
+ .comparison-panel h3 .badge {
555
+ margin-left: 6px;
556
+ }
557
+ .evidence-list {
558
+ list-style: none;
559
+ padding: 0;
560
+ margin: 0;
561
+ }
562
+ .evidence-list li {
563
+ padding: 14px 17px;
564
+ border-left: 3px solid #c8dadd;
565
+ background: #f8fafb;
566
+ margin-top: 8px;
567
+ border-radius: 0 7px 7px 0;
568
+ font-size: 0.82rem;
569
+ }
570
+ .evidence-list p {
571
+ margin: 6px 0;
572
+ }
573
+ .evidence-list .mono {
574
+ font-size: 0.73rem;
575
+ }
576
+ .case-section > .section-heading {
577
+ margin-bottom: 18px;
578
+ }
579
+ .case-card {
580
+ padding: 24px 27px;
581
+ margin-bottom: 20px;
582
+ }
583
+ .case-header {
584
+ display: flex;
585
+ justify-content: space-between;
586
+ align-items: center;
587
+ gap: 16px;
588
+ }
589
+ .case-header .eyebrow {
590
+ font-size: 0.64rem;
591
+ margin-bottom: 5px;
592
+ }
593
+ .case-header h3 {
594
+ font-size: 1.16rem;
595
+ overflow-wrap: anywhere;
596
+ margin: 0;
597
+ }
598
+ .case-telemetry {
599
+ display: flex;
600
+ flex-wrap: wrap;
601
+ gap: 8px 20px;
602
+ font-size: 0.73rem;
603
+ color: var(--muted);
604
+ padding: 13px 0 18px;
605
+ }
606
+ .payload-grid {
607
+ display: grid;
608
+ grid-template-columns: 1fr 1fr;
609
+ gap: 18px;
610
+ margin: 0 0 22px;
611
+ }
612
+ .payload-grid section {
613
+ min-width: 0;
614
+ }
615
+ .payload-grid h4 {
616
+ color: var(--muted);
617
+ text-transform: uppercase;
618
+ font-size: 0.67rem;
619
+ }
620
+ .output-payload {
621
+ grid-column: 1/-1;
622
+ }
623
+ .payload {
624
+ background: #f7f9fb;
625
+ border: 1px solid #e0e7ee;
626
+ border-radius: 8px;
627
+ padding: 15px 17px;
628
+ max-height: 360px;
629
+ overflow: auto;
630
+ color: #243950;
631
+ }
632
+ .output-payload .payload {
633
+ background: #f3f8f8;
634
+ border-color: #d6e5e5;
635
+ }
636
+ .error-alert {
637
+ background: #fdf1f2;
638
+ border: 1px solid #efcbd0;
639
+ border-radius: 8px;
640
+ padding: 13px 17px;
641
+ margin: 0 0 19px;
642
+ color: #9f2736;
643
+ font-size: 0.82rem;
644
+ }
645
+ .error-alert pre {
646
+ margin-top: 5px;
647
+ }
648
+ .evaluation-table {
649
+ border: 1px solid var(--line);
650
+ border-radius: 9px;
651
+ }
652
+ .evaluation-table table {
653
+ min-width: 570px;
654
+ }
655
+ .evaluation-table caption {
656
+ text-align: left;
657
+ padding: 12px 17px;
658
+ font-size: 0.78rem;
659
+ font-weight: 700;
660
+ border-bottom: 1px solid var(--line);
661
+ }
662
+ .evaluation-table td,
663
+ .evaluation-table th {
664
+ padding: 13px 17px;
665
+ }
666
+ .evaluation-reason {
667
+ min-width: 220px;
668
+ max-width: 600px;
669
+ overflow-wrap: anywhere;
670
+ }
671
+ .evaluation-reason p {
672
+ margin: 0;
673
+ white-space: pre-wrap;
674
+ }
675
+ .evaluation-reason pre {
676
+ font-size: 0.77rem;
677
+ }
678
+ .metadata-details {
679
+ margin-top: 17px;
680
+ font-size: 0.8rem;
681
+ }
682
+ .metadata-details summary {
683
+ cursor: pointer;
684
+ color: var(--teal);
685
+ font-weight: 600;
686
+ }
687
+ .metadata-details pre {
688
+ margin-top: 12px;
689
+ }
690
+ .run-metadata {
691
+ padding: 24px 27px;
692
+ margin-top: 28px;
693
+ }
694
+ .run-metadata h2 {
695
+ font-size: 1.06rem;
696
+ }
697
+ .run-metadata dl {
698
+ display: grid;
699
+ grid-template-columns: 155px 1fr;
700
+ gap: 8px 16px;
701
+ font-size: 0.78rem;
702
+ margin: 18px 0;
703
+ }
704
+ .run-metadata dt {
705
+ color: var(--muted);
706
+ }
707
+ .run-metadata dd {
708
+ margin: 0;
709
+ overflow-wrap: anywhere;
710
+ }
711
+ .small {
712
+ font-size: 0.72rem;
713
+ margin: 19px 0 0;
714
+ }
715
+ .skip-link {
716
+ position: absolute;
717
+ top: -90px;
718
+ left: 16px;
719
+ background: var(--ink);
720
+ color: #fff;
721
+ padding: 10px 18px;
722
+ border-radius: 5px;
723
+ z-index: 2;
724
+ }
725
+ .skip-link:focus {
726
+ top: 10px;
727
+ }
728
+ .sr-only {
729
+ position: absolute;
730
+ width: 1px;
731
+ height: 1px;
732
+ padding: 0;
733
+ margin: -1px;
734
+ overflow: hidden;
735
+ clip: rect(0, 0, 0, 0);
736
+ white-space: nowrap;
737
+ border: 0;
738
+ }
739
+ .error-page {
740
+ margin: 35px 0;
741
+ }
742
+ .error-page h1 {
743
+ font-size: 2.1rem;
744
+ }
745
+ @media (max-width: 1050px) {
746
+ .header-inner,
747
+ main,
748
+ .site-footer {
749
+ padding-left: 24px;
750
+ padding-right: 24px;
751
+ }
752
+ .stats-grid {
753
+ gap: 12px;
754
+ }
755
+ .stat-card {
756
+ padding: 18px;
757
+ }
758
+ .stat-card > strong {
759
+ font-size: 1.7rem;
760
+ }
761
+ .workspace-status {
762
+ display: none;
763
+ }
764
+ .page-heading h1 {
765
+ font-size: 2rem;
766
+ }
767
+ .chart-panel {
768
+ padding: 22px;
769
+ }
770
+ }
771
+ @media (max-width: 720px) {
772
+ .header-inner {
773
+ padding: 16px 18px;
774
+ }
775
+ .brand {
776
+ font-size: 0.88rem;
777
+ }
778
+ .brand-mark {
779
+ width: 31px;
780
+ height: 31px;
781
+ }
782
+ .local-badge {
783
+ display: none;
784
+ }
785
+ .header-inner nav {
786
+ font-size: 0.75rem;
787
+ }
788
+ .header-inner {
789
+ gap: 12px;
790
+ }
791
+ main {
792
+ padding: 29px 18px 36px;
793
+ }
794
+ .page-heading {
795
+ align-items: flex-start;
796
+ flex-direction: column;
797
+ gap: 18px;
798
+ }
799
+ .page-heading h1 {
800
+ font-size: 1.85rem;
801
+ }
802
+ .lead {
803
+ font-size: 0.85rem;
804
+ }
805
+ .stats-grid {
806
+ grid-template-columns: repeat(2, minmax(0, 1fr));
807
+ gap: 11px;
808
+ }
809
+ .stat-card {
810
+ padding: 16px;
811
+ }
812
+ .stat-card > strong {
813
+ font-size: 1.65rem;
814
+ }
815
+ .stat-caption {
816
+ font-size: 0.68rem;
817
+ }
818
+ .filter-panel {
819
+ padding: 17px;
820
+ }
821
+ .filter-form {
822
+ flex-wrap: wrap;
823
+ gap: 12px;
824
+ }
825
+ .field {
826
+ flex-basis: calc(50% - 6px);
827
+ max-width: none;
828
+ }
829
+ .filter-form .button {
830
+ flex: 1;
831
+ }
832
+ .filter-hint {
833
+ font-size: 0.67rem;
834
+ }
835
+ .chart-panel,
836
+ .comparison-panel,
837
+ .case-card,
838
+ .run-metadata {
839
+ padding: 20px 18px;
840
+ }
841
+ .trend-chart {
842
+ min-height: 0;
843
+ }
844
+ .section-heading {
845
+ gap: 12px;
846
+ }
847
+ .section-heading h2 {
848
+ font-size: 1.17rem;
849
+ }
850
+ .chart-legend {
851
+ font-size: 0.65rem;
852
+ gap: 6px 14px;
853
+ }
854
+ .chart-legend li {
855
+ flex-basis: 100%;
856
+ }
857
+ .section-description {
858
+ font-size: 0.77rem;
859
+ }
860
+ .history-panel > .section-heading {
861
+ padding: 21px 18px;
862
+ }
863
+ .comparison-panel .section-heading {
864
+ align-items: flex-start;
865
+ flex-direction: column;
866
+ }
867
+ .comparison-deltas {
868
+ gap: 35px;
869
+ }
870
+ .comparison-deltas span {
871
+ font-size: 0.69rem;
872
+ }
873
+ .comparison-deltas strong {
874
+ font-size: 1.15rem;
875
+ }
876
+ .payload-grid {
877
+ grid-template-columns: 1fr;
878
+ gap: 16px;
879
+ }
880
+ .output-payload {
881
+ grid-column: auto;
882
+ }
883
+ .case-header {
884
+ align-items: flex-start;
885
+ }
886
+ .case-header h3 {
887
+ font-size: 1.05rem;
888
+ }
889
+ .case-header .badge {
890
+ margin-top: 2px;
891
+ }
892
+ .case-telemetry {
893
+ gap: 5px 12px;
894
+ font-size: 0.67rem;
895
+ }
896
+ .payload {
897
+ padding: 12px 14px;
898
+ font-size: 0.75rem;
899
+ }
900
+ .run-metadata dl {
901
+ grid-template-columns: 1fr;
902
+ gap: 3px;
903
+ }
904
+ .run-metadata dd {
905
+ margin-bottom: 10px;
906
+ }
907
+ .site-footer {
908
+ padding: 18px;
909
+ flex-direction: column;
910
+ gap: 5px;
911
+ font-size: 0.65rem;
912
+ }
913
+ .empty-state {
914
+ padding: 45px 20px;
915
+ }
916
+ .empty-state h2 {
917
+ font-size: 1.35rem;
918
+ }
919
+ .command {
920
+ font-size: 0.68rem;
921
+ }
922
+ .comparison-deltas {
923
+ justify-content: space-between;
924
+ }
925
+ }
926
+ @media (prefers-reduced-motion: reduce) {
927
+ * {
928
+ transition: none !important;
929
+ scroll-behavior: auto !important;
930
+ }
931
+ }
932
+ .section-description a {
933
+ text-decoration: underline;
934
+ text-underline-offset: 0.15em;
935
+ }
936
+ .dimension-summary {
937
+ padding: 28px;
938
+ margin-bottom: 28px;
939
+ }