@crvouga/atlas 0.8.0 → 0.10.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 (60) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/core/src/lint.js +6 -2
  3. package/dist/core/src/spec/types.d.ts +4 -1
  4. package/dist/playwright-reporter/src/evidence.d.ts +122 -0
  5. package/dist/playwright-reporter/src/evidence.js +327 -0
  6. package/dist/playwright-reporter/src/index.d.ts +114 -0
  7. package/dist/playwright-reporter/src/index.js +312 -0
  8. package/dist/reports/src/compose.js +7 -14
  9. package/dist/reports/src/recorded-specs.d.ts +33 -0
  10. package/dist/reports/src/recorded-specs.js +42 -0
  11. package/dist/reports/src/report-index.d.ts +6 -0
  12. package/dist/reports/src/report-index.js +14 -2
  13. package/dist/reports/src/test-catalog.d.ts +386 -0
  14. package/dist/reports/src/test-catalog.js +655 -0
  15. package/dist/schema/src/api.d.ts +585 -0
  16. package/dist/schema/src/api.js +105 -0
  17. package/dist/schema/src/spec.d.ts +2 -1
  18. package/dist/schema/src/spec.js +5 -2
  19. package/dist/server/src/app.js +82 -4
  20. package/dist/server/src/llms.js +14 -0
  21. package/dist/server/src/openapi.d.ts +1 -1
  22. package/dist/server/src/openapi.js +60 -3
  23. package/docs/agents.md +1 -0
  24. package/docs/integrating.md +1 -0
  25. package/docs/reference/core.md +7 -2
  26. package/docs/reference/http-api.md +134 -2
  27. package/docs/reference/playwright-reporter.md +332 -0
  28. package/docs/reference/reports.md +632 -0
  29. package/docs/reference/schema.md +58 -1
  30. package/docs/rich-evidence.md +198 -0
  31. package/docs/server.md +41 -0
  32. package/docs/statecharts.md +2 -1
  33. package/llms-full.txt +380 -3
  34. package/llms.txt +2 -0
  35. package/package.json +6 -1
  36. package/packages/schema/schemas/report-run.schema.json +251 -0
  37. package/packages/schema/schemas/report-runs.schema.json +177 -0
  38. package/packages/schema/schemas/state-node.schema.json +7 -0
  39. package/packages/schema/schemas/test-catalog.schema.json +1177 -0
  40. package/packages/schema/schemas/test-history.schema.json +696 -0
  41. package/packages/server/openapi.json +8676 -5351
  42. package/packages/visualizer/src/app/AppShell.tsx +7 -3
  43. package/packages/visualizer/src/app/router.tsx +26 -3
  44. package/packages/visualizer/src/components/Header.tsx +2 -2
  45. package/packages/visualizer/src/evidence/evidence-context.tsx +10 -1
  46. package/packages/visualizer/src/explorer/Explorer.tsx +433 -0
  47. package/packages/visualizer/src/explorer/ExplorerIndex.tsx +120 -0
  48. package/packages/visualizer/src/explorer/RunsView.tsx +164 -0
  49. package/packages/visualizer/src/explorer/TestDetail.tsx +214 -0
  50. package/packages/visualizer/src/explorer/catalog.tsx +274 -0
  51. package/packages/visualizer/src/explorer/explorer.module.css +1238 -0
  52. package/packages/visualizer/src/explorer/groups.test.ts +87 -0
  53. package/packages/visualizer/src/explorer/groups.ts +126 -0
  54. package/packages/visualizer/src/explorer/navigate.ts +36 -0
  55. package/packages/visualizer/src/explorer/parts.tsx +59 -0
  56. package/packages/visualizer/src/explorer/search.ts +97 -0
  57. package/packages/visualizer/src/find/Finder.tsx +2 -0
  58. package/packages/visualizer/src/find/corpus.ts +13 -6
  59. package/packages/visualizer/src/find/rank.ts +2 -0
  60. package/packages/visualizer/src/evidence/project-home.tsx +0 -45
@@ -0,0 +1,1238 @@
1
+ /* The test explorer: list on the left, the open test beside it. White, hairlines, one blue; outcome colors only for outcomes. */
2
+
3
+ .explorer {
4
+ display: grid;
5
+ grid-template-columns: minmax(0, 1fr);
6
+ height: 100%;
7
+ min-height: 0;
8
+ background: var(--bg);
9
+ }
10
+
11
+ .explorer[data-split] {
12
+ grid-template-columns: minmax(0, 1fr) minmax(24rem, 40rem);
13
+ }
14
+
15
+ .main,
16
+ .side {
17
+ min-height: 0;
18
+ overflow: auto;
19
+ }
20
+
21
+ .main {
22
+ padding: 28px 40px 80px;
23
+ }
24
+
25
+ .main > * {
26
+ max-width: 72rem;
27
+ }
28
+
29
+ .side {
30
+ border-left: 1px solid var(--line);
31
+ padding: 16px 24px 80px;
32
+ }
33
+
34
+ .head {
35
+ display: flex;
36
+ flex-wrap: wrap;
37
+ align-items: flex-end;
38
+ justify-content: space-between;
39
+ gap: 8px 24px;
40
+ margin-bottom: 18px;
41
+ border-bottom: 1px solid var(--line);
42
+ }
43
+
44
+ .title {
45
+ margin: 0 0 12px;
46
+ font-size: 1.375rem;
47
+ font-weight: 650;
48
+ letter-spacing: -0.01em;
49
+ line-height: 1.25;
50
+ }
51
+
52
+ .tabs {
53
+ display: flex;
54
+ gap: 20px;
55
+ }
56
+
57
+ .tabs a {
58
+ padding: 0 0 10px;
59
+ border-bottom: 2px solid transparent;
60
+ color: var(--ink-3);
61
+ font-size: 0.9375rem;
62
+ text-decoration: none;
63
+ }
64
+
65
+ .tabs a[aria-selected='true'] {
66
+ border-bottom-color: var(--place);
67
+ color: var(--ink);
68
+ font-weight: 600;
69
+ }
70
+
71
+ .tabs a span {
72
+ color: var(--ink-3);
73
+ font-size: 0.8125rem;
74
+ font-weight: 400;
75
+ font-variant-numeric: tabular-nums;
76
+ }
77
+
78
+ .label {
79
+ margin: 0 0 6px;
80
+ color: var(--ink-3);
81
+ font-size: 0.75rem;
82
+ font-weight: 600;
83
+ }
84
+
85
+ .quiet {
86
+ margin: 12px 0;
87
+ color: var(--ink-3);
88
+ font-size: 0.875rem;
89
+ }
90
+
91
+ .notice {
92
+ margin: 12px 0;
93
+ padding: 10px 12px;
94
+ border-radius: 8px;
95
+ background: var(--bg-2);
96
+ color: var(--ink-2);
97
+ font-size: 0.875rem;
98
+ }
99
+
100
+ .link {
101
+ padding: 0;
102
+ border: 0;
103
+ background: none;
104
+ color: var(--place);
105
+ font-size: 0.8125rem;
106
+ font-weight: 500;
107
+ cursor: pointer;
108
+ }
109
+
110
+ .link:hover {
111
+ text-decoration: underline;
112
+ }
113
+
114
+ .kinds {
115
+ display: flex;
116
+ flex-wrap: wrap;
117
+ align-items: baseline;
118
+ gap: 4px 16px;
119
+ margin-bottom: 18px;
120
+ }
121
+
122
+ .kinds .label {
123
+ margin: 0;
124
+ }
125
+
126
+ .kinds ul {
127
+ display: flex;
128
+ flex-wrap: wrap;
129
+ gap: 4px 16px;
130
+ margin: 0;
131
+ padding: 0;
132
+ list-style: none;
133
+ }
134
+
135
+ .kinds a {
136
+ color: var(--place);
137
+ font-size: 0.875rem;
138
+ text-decoration: none;
139
+ }
140
+
141
+ .kinds a span {
142
+ color: var(--ink-3);
143
+ }
144
+
145
+ /* Insight strip */
146
+
147
+ .insights {
148
+ display: grid;
149
+ grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
150
+ gap: 10px;
151
+ margin-bottom: 18px;
152
+ }
153
+
154
+ .tile {
155
+ display: flex;
156
+ flex-direction: column;
157
+ gap: 4px;
158
+ min-width: 0;
159
+ padding: 12px 14px;
160
+ border: 1px solid var(--line-2);
161
+ border-radius: 12px;
162
+ background: var(--bg);
163
+ color: var(--ink);
164
+ font: inherit;
165
+ text-align: left;
166
+ text-decoration: none;
167
+ }
168
+
169
+ .tile[data-wide] {
170
+ grid-column: span 2;
171
+ }
172
+
173
+ button.tile,
174
+ a.tile {
175
+ cursor: pointer;
176
+ }
177
+
178
+ button.tile:hover,
179
+ a.tile:hover {
180
+ border-color: var(--faint);
181
+ }
182
+
183
+ .tile[aria-pressed='true'] {
184
+ border-color: var(--place);
185
+ background: var(--place-soft);
186
+ }
187
+
188
+ .tileLabel {
189
+ color: var(--ink-3);
190
+ font-size: 0.75rem;
191
+ font-weight: 600;
192
+ }
193
+
194
+ .tileValue {
195
+ font-size: 1.5rem;
196
+ font-weight: 650;
197
+ line-height: 1.2;
198
+ }
199
+
200
+ .tileValue[data-warn] {
201
+ color: var(--flaky-ink);
202
+ }
203
+
204
+ .tileValue[data-none] {
205
+ color: var(--faint);
206
+ }
207
+
208
+ .tileNote {
209
+ color: var(--ink-3);
210
+ font-size: 0.75rem;
211
+ line-height: 1.35;
212
+ }
213
+
214
+ .tileCounts {
215
+ display: flex;
216
+ flex-wrap: wrap;
217
+ gap: 2px 10px;
218
+ margin-top: 2px;
219
+ }
220
+
221
+ .tileCounts button,
222
+ .envList button {
223
+ padding: 0;
224
+ border: 0;
225
+ border-radius: 4px;
226
+ background: none;
227
+ color: var(--ink-3);
228
+ font-size: 0.8125rem;
229
+ font-variant-numeric: tabular-nums;
230
+ cursor: pointer;
231
+ }
232
+
233
+ .tileCounts button:hover,
234
+ .envList button:hover {
235
+ color: var(--ink);
236
+ text-decoration: underline;
237
+ }
238
+
239
+ .tileCounts button[data-status='failed'] {
240
+ color: var(--failed);
241
+ font-weight: 600;
242
+ }
243
+
244
+ .tileCounts button[data-status='failed']:disabled {
245
+ color: var(--ink-3);
246
+ font-weight: 400;
247
+ cursor: default;
248
+ text-decoration: none;
249
+ }
250
+
251
+ .tileCounts button[data-status='running'] {
252
+ color: var(--place);
253
+ }
254
+
255
+ .tileCounts button[aria-pressed='true'],
256
+ .envList button[aria-pressed='true'] {
257
+ background: var(--place-soft);
258
+ box-shadow: 0 0 0 3px var(--place-soft);
259
+ color: var(--place);
260
+ }
261
+
262
+ .envList {
263
+ display: grid;
264
+ gap: 4px;
265
+ margin: 2px 0 0;
266
+ padding: 0;
267
+ list-style: none;
268
+ }
269
+
270
+ .envList button {
271
+ display: flex;
272
+ flex-wrap: wrap;
273
+ align-items: baseline;
274
+ gap: 0 8px;
275
+ width: 100%;
276
+ text-align: left;
277
+ }
278
+
279
+ .envList button > span + span::before {
280
+ margin-right: 8px;
281
+ color: var(--faint);
282
+ content: '·';
283
+ }
284
+
285
+ .envName {
286
+ color: var(--ink);
287
+ font-weight: 600;
288
+ }
289
+
290
+ .envList [data-status='failed'] {
291
+ color: var(--failed);
292
+ font-weight: 600;
293
+ }
294
+
295
+ .more {
296
+ grid-column: 1 / -1;
297
+ font-size: 0.8125rem;
298
+ }
299
+
300
+ .more summary {
301
+ color: var(--ink-3);
302
+ font-weight: 500;
303
+ cursor: pointer;
304
+ }
305
+
306
+ .moreLists {
307
+ display: grid;
308
+ grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
309
+ gap: 12px 24px;
310
+ margin-top: 10px;
311
+ }
312
+
313
+ .moreLists ol {
314
+ margin: 0;
315
+ padding: 0;
316
+ list-style: none;
317
+ }
318
+
319
+ .moreLists a {
320
+ display: flex;
321
+ align-items: center;
322
+ gap: 8px;
323
+ padding: 3px 0;
324
+ color: var(--ink);
325
+ text-decoration: none;
326
+ }
327
+
328
+ .moreLists a:hover .insightName {
329
+ color: var(--place);
330
+ }
331
+
332
+ .insightName {
333
+ flex: 1;
334
+ min-width: 0;
335
+ overflow: hidden;
336
+ text-overflow: ellipsis;
337
+ white-space: nowrap;
338
+ }
339
+
340
+ .insightValue {
341
+ flex: none;
342
+ color: var(--ink-3);
343
+ font-variant-numeric: tabular-nums;
344
+ }
345
+
346
+ /* Toolbar */
347
+
348
+ .toolbar {
349
+ display: grid;
350
+ gap: 10px;
351
+ margin-bottom: 8px;
352
+ }
353
+
354
+ .searchRow,
355
+ .filterRow {
356
+ display: flex;
357
+ flex-wrap: wrap;
358
+ align-items: center;
359
+ gap: 8px 12px;
360
+ }
361
+
362
+ .searchBox {
363
+ flex: 1 1 18rem;
364
+ min-width: 0;
365
+ height: 2.25rem;
366
+ padding: 0 12px;
367
+ border: 1px solid var(--line-2);
368
+ border-radius: var(--pill);
369
+ background: var(--bg);
370
+ color: var(--ink);
371
+ font: inherit;
372
+ font-size: 0.9rem;
373
+ }
374
+
375
+ .searchBox:focus {
376
+ outline: 2px solid var(--place-soft);
377
+ border-color: var(--place);
378
+ }
379
+
380
+ .select {
381
+ display: inline-flex;
382
+ align-items: center;
383
+ gap: 6px;
384
+ color: var(--ink-3);
385
+ font-size: 0.8125rem;
386
+ }
387
+
388
+ .select select {
389
+ height: 2.125rem;
390
+ max-width: 16rem;
391
+ padding: 0 8px;
392
+ border: 1px solid var(--line-2);
393
+ border-radius: var(--pill);
394
+ background: var(--bg);
395
+ color: var(--ink);
396
+ font: inherit;
397
+ font-size: 0.8125rem;
398
+ }
399
+
400
+ .segments,
401
+ .chips {
402
+ display: flex;
403
+ flex-wrap: wrap;
404
+ gap: 4px;
405
+ }
406
+
407
+ .segments button,
408
+ .chips button {
409
+ padding: 4px 10px;
410
+ border: 1px solid transparent;
411
+ border-radius: var(--pill);
412
+ background: none;
413
+ color: var(--ink-3);
414
+ font-size: 0.8125rem;
415
+ font-weight: 500;
416
+ white-space: nowrap;
417
+ cursor: pointer;
418
+ }
419
+
420
+ .chips button {
421
+ border-color: var(--line-2);
422
+ }
423
+
424
+ .segments button:hover,
425
+ .chips button:hover {
426
+ background: var(--bg-2);
427
+ }
428
+
429
+ .segments button[aria-pressed='true'],
430
+ .chips button[aria-pressed='true'] {
431
+ border-color: var(--place);
432
+ background: var(--place-soft);
433
+ color: var(--place);
434
+ font-weight: 600;
435
+ }
436
+
437
+ .segments button span,
438
+ .chips button span {
439
+ font-weight: 400;
440
+ font-variant-numeric: tabular-nums;
441
+ opacity: 0.8;
442
+ }
443
+
444
+ .segments button[data-status='failed'] span {
445
+ color: var(--failed);
446
+ font-weight: 600;
447
+ opacity: 1;
448
+ }
449
+
450
+ .showing {
451
+ display: flex;
452
+ flex-wrap: wrap;
453
+ align-items: center;
454
+ gap: 6px 12px;
455
+ margin: 0;
456
+ color: var(--ink-3);
457
+ font-size: 0.8125rem;
458
+ }
459
+
460
+ .activeChip {
461
+ padding: 2px 10px;
462
+ border: 1px solid var(--place);
463
+ border-radius: var(--pill);
464
+ background: var(--place-soft);
465
+ color: var(--place);
466
+ font-size: 0.75rem;
467
+ font-weight: 600;
468
+ cursor: pointer;
469
+ }
470
+
471
+ /* The grouped list */
472
+
473
+ .list {
474
+ margin-top: 8px;
475
+ }
476
+
477
+ .listHead {
478
+ display: flex;
479
+ align-items: center;
480
+ gap: 12px;
481
+ padding: 6px 14px;
482
+ color: var(--ink-3);
483
+ font-size: 0.75rem;
484
+ font-weight: 600;
485
+ }
486
+
487
+ .listHead > span:first-child {
488
+ flex: 1;
489
+ }
490
+
491
+ .listTools {
492
+ display: flex;
493
+ gap: 12px;
494
+ }
495
+
496
+ .listTools .link {
497
+ font-size: 0.75rem;
498
+ }
499
+
500
+ .columns {
501
+ display: grid;
502
+ flex: none;
503
+ grid-template-columns: 4.5rem 3.25rem 3rem 4.25rem;
504
+ gap: 8px;
505
+ color: var(--ink-3);
506
+ font-size: 0.8125rem;
507
+ text-align: right;
508
+ white-space: nowrap;
509
+ font-variant-numeric: tabular-nums;
510
+ }
511
+
512
+ .columns[data-one] {
513
+ grid-template-columns: 5rem;
514
+ }
515
+
516
+ .listHead .columns {
517
+ font-size: 0.75rem;
518
+ }
519
+
520
+ .columns [data-low] {
521
+ color: var(--ink);
522
+ font-weight: 600;
523
+ }
524
+
525
+ .domainHeading {
526
+ margin: 18px 0 6px;
527
+ color: var(--ink-3);
528
+ font-size: 0.75rem;
529
+ font-weight: 600;
530
+ text-transform: none;
531
+ }
532
+
533
+ .groupWrap + .groupWrap .group {
534
+ margin-top: 6px;
535
+ }
536
+
537
+ .group {
538
+ border: 1px solid var(--line-2);
539
+ border-radius: 12px;
540
+ overflow: hidden;
541
+ }
542
+
543
+ .group + .group {
544
+ margin-top: 6px;
545
+ }
546
+
547
+ .groupHead {
548
+ display: flex;
549
+ align-items: center;
550
+ gap: 10px;
551
+ width: 100%;
552
+ padding: 9px 14px;
553
+ border: 0;
554
+ background: var(--bg);
555
+ color: var(--ink);
556
+ font: inherit;
557
+ text-align: left;
558
+ cursor: pointer;
559
+ }
560
+
561
+ .groupHead[data-static] {
562
+ cursor: default;
563
+ background: var(--bg-2);
564
+ }
565
+
566
+ button.groupHead:hover {
567
+ background: var(--bg-2);
568
+ }
569
+
570
+ .group[data-open] > .groupHead {
571
+ border-bottom: 1px solid var(--line);
572
+ }
573
+
574
+ .groupName {
575
+ display: flex;
576
+ flex: 1;
577
+ flex-wrap: wrap;
578
+ align-items: baseline;
579
+ gap: 0 10px;
580
+ min-width: 0;
581
+ font-size: 0.9rem;
582
+ font-weight: 600;
583
+ }
584
+
585
+ .groupName code {
586
+ overflow: hidden;
587
+ color: var(--ink-3);
588
+ font-family: var(--mono);
589
+ font-size: 0.75rem;
590
+ font-weight: 400;
591
+ text-overflow: ellipsis;
592
+ white-space: nowrap;
593
+ }
594
+
595
+ .groupMeter {
596
+ flex: none;
597
+ width: 5rem;
598
+ }
599
+
600
+ .groupTally {
601
+ display: flex;
602
+ flex: none;
603
+ gap: 10px;
604
+ color: var(--ink-3);
605
+ font-size: 0.75rem;
606
+ white-space: nowrap;
607
+ font-variant-numeric: tabular-nums;
608
+ }
609
+
610
+ .groupTally strong {
611
+ color: var(--failed);
612
+ font-weight: 600;
613
+ }
614
+
615
+ .chevron {
616
+ flex: none;
617
+ width: 7px;
618
+ height: 7px;
619
+ margin: 0 3px 2px 1px;
620
+ border-right: 1.5px solid var(--faint);
621
+ border-bottom: 1.5px solid var(--faint);
622
+ transform: rotate(-45deg);
623
+ transition: transform var(--fade) var(--ease);
624
+ }
625
+
626
+ .group[data-open] .chevron,
627
+ .chevron[data-open] {
628
+ transform: rotate(45deg);
629
+ }
630
+
631
+ .rows {
632
+ margin: 0;
633
+ padding: 0;
634
+ list-style: none;
635
+ }
636
+
637
+ .row + .row {
638
+ border-top: 1px solid var(--line);
639
+ }
640
+
641
+ .rowLink {
642
+ display: flex;
643
+ align-items: center;
644
+ gap: 10px;
645
+ padding: 8px 14px;
646
+ color: var(--ink);
647
+ text-decoration: none;
648
+ }
649
+
650
+ .rowLink:hover {
651
+ background: var(--bg-2);
652
+ }
653
+
654
+ .rowLink[aria-current='true'] {
655
+ background: var(--place-soft);
656
+ }
657
+
658
+ .rowLink > svg {
659
+ align-self: flex-start;
660
+ margin-top: 2px;
661
+ }
662
+
663
+ .rowMain {
664
+ display: flex;
665
+ flex: 1;
666
+ flex-direction: column;
667
+ gap: 3px;
668
+ min-width: 0;
669
+ }
670
+
671
+ .rowTitle {
672
+ font-size: 0.9rem;
673
+ font-weight: 500;
674
+ line-height: 1.3;
675
+ }
676
+
677
+ .row[data-status='not-run'] .rowTitle {
678
+ color: var(--ink-2);
679
+ }
680
+
681
+ .rowMeta {
682
+ display: flex;
683
+ flex-wrap: wrap;
684
+ align-items: center;
685
+ gap: 4px 10px;
686
+ color: var(--ink-3);
687
+ font-size: 0.75rem;
688
+ }
689
+
690
+ .rowError {
691
+ overflow: hidden;
692
+ color: var(--failed-ink);
693
+ font-family: var(--mono);
694
+ font-size: 0.75rem;
695
+ text-overflow: ellipsis;
696
+ white-space: nowrap;
697
+ }
698
+
699
+ .moreRow {
700
+ padding: 8px 14px;
701
+ border-top: 1px solid var(--line);
702
+ }
703
+
704
+ .envChips {
705
+ display: inline-flex;
706
+ flex-wrap: wrap;
707
+ gap: 4px 10px;
708
+ }
709
+
710
+ .envChips > span {
711
+ display: inline-flex;
712
+ align-items: center;
713
+ gap: 4px;
714
+ color: var(--ink-3);
715
+ }
716
+
717
+ .envChips > span[data-status='failed'] {
718
+ color: var(--failed-ink);
719
+ font-weight: 600;
720
+ }
721
+
722
+ .envChips > span[data-status='passed'] {
723
+ color: var(--passed-ink);
724
+ }
725
+
726
+ .badges {
727
+ display: inline-flex;
728
+ flex-wrap: wrap;
729
+ gap: 4px;
730
+ }
731
+
732
+ .badges > span {
733
+ padding: 0 6px;
734
+ border: 1px solid var(--line-2);
735
+ border-radius: var(--pill);
736
+ color: var(--ink-3);
737
+ font-size: 0.6875rem;
738
+ line-height: 1.5;
739
+ }
740
+
741
+ .badges > span[data-badge='flaky'] {
742
+ border-color: var(--flaky);
743
+ color: var(--flaky-ink);
744
+ }
745
+
746
+ .badges > span[data-badge='live'] {
747
+ border-color: var(--place);
748
+ color: var(--place);
749
+ }
750
+
751
+ /* Test detail */
752
+
753
+ .detail {
754
+ display: grid;
755
+ gap: 18px;
756
+ }
757
+
758
+ .detailTop {
759
+ display: flex;
760
+ justify-content: flex-end;
761
+ margin-bottom: -18px;
762
+ }
763
+
764
+ .close {
765
+ display: inline-flex;
766
+ align-items: center;
767
+ justify-content: center;
768
+ width: 2rem;
769
+ height: 2rem;
770
+ border-radius: var(--pill);
771
+ color: var(--ink-3);
772
+ font-size: 1.25rem;
773
+ text-decoration: none;
774
+ }
775
+
776
+ .close:hover {
777
+ background: var(--bg-2);
778
+ color: var(--ink);
779
+ }
780
+
781
+ .detailEmpty {
782
+ display: grid;
783
+ gap: 8px;
784
+ justify-items: start;
785
+ }
786
+
787
+ .detailHead {
788
+ display: grid;
789
+ gap: 6px;
790
+ }
791
+
792
+ .detailSpec {
793
+ display: flex;
794
+ flex-wrap: wrap;
795
+ gap: 0 8px;
796
+ margin: 0;
797
+ font-size: 0.8125rem;
798
+ }
799
+
800
+ .detailSpec a {
801
+ color: var(--place);
802
+ text-decoration: none;
803
+ }
804
+
805
+ .detailSpec a + a::before {
806
+ margin-right: 8px;
807
+ color: var(--faint);
808
+ content: '›';
809
+ }
810
+
811
+ .detailTitle {
812
+ margin: 0;
813
+ font-size: 1.125rem;
814
+ font-weight: 650;
815
+ line-height: 1.3;
816
+ }
817
+
818
+ .detailStatus {
819
+ display: flex;
820
+ flex-wrap: wrap;
821
+ align-items: center;
822
+ gap: 4px 10px;
823
+ margin: 0;
824
+ font-size: 0.875rem;
825
+ }
826
+
827
+ .detailStatus strong[data-status='failed'] {
828
+ color: var(--failed);
829
+ }
830
+
831
+ .detailStatus strong[data-status='passed'] {
832
+ color: var(--passed-ink);
833
+ }
834
+
835
+ .flaky {
836
+ color: var(--flaky-ink);
837
+ font-size: 0.8125rem;
838
+ }
839
+
840
+ .mono {
841
+ overflow-wrap: anywhere;
842
+ color: var(--ink-3);
843
+ font-family: var(--mono);
844
+ font-size: 0.75rem;
845
+ }
846
+
847
+ .detailBlock {
848
+ display: grid;
849
+ gap: 8px;
850
+ padding-top: 14px;
851
+ border-top: 1px solid var(--line);
852
+ }
853
+
854
+ .detailBlock > * {
855
+ margin: 0;
856
+ }
857
+
858
+ .tableScroll {
859
+ overflow-x: auto;
860
+ }
861
+
862
+ .table {
863
+ width: 100%;
864
+ border-collapse: collapse;
865
+ font-size: 0.8125rem;
866
+ }
867
+
868
+ .table th,
869
+ .table td {
870
+ padding: 6px 8px;
871
+ border-bottom: 1px solid var(--line);
872
+ text-align: left;
873
+ vertical-align: top;
874
+ white-space: nowrap;
875
+ }
876
+
877
+ .table th {
878
+ color: var(--ink-3);
879
+ font-size: 0.75rem;
880
+ font-weight: 600;
881
+ }
882
+
883
+ .table a {
884
+ color: var(--place);
885
+ text-decoration: none;
886
+ }
887
+
888
+ .table a:hover {
889
+ text-decoration: underline;
890
+ }
891
+
892
+ .table code {
893
+ font-size: 0.75rem;
894
+ }
895
+
896
+ .num {
897
+ text-align: right !important;
898
+ font-variant-numeric: tabular-nums;
899
+ }
900
+
901
+ .ellipsis {
902
+ max-width: 12rem;
903
+ overflow: hidden;
904
+ text-overflow: ellipsis;
905
+ }
906
+
907
+ .detailCell {
908
+ max-width: 18rem;
909
+ overflow: hidden;
910
+ color: var(--ink-3);
911
+ text-overflow: ellipsis;
912
+ }
913
+
914
+ .table tr[data-status='failed'] .detailCell {
915
+ color: var(--failed-ink);
916
+ }
917
+
918
+ .cellStatus {
919
+ display: inline-flex;
920
+ align-items: center;
921
+ gap: 5px;
922
+ }
923
+
924
+ .param {
925
+ color: var(--ink-3);
926
+ }
927
+
928
+ .stats {
929
+ display: grid;
930
+ grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
931
+ gap: 10px 14px;
932
+ }
933
+
934
+ .stats div {
935
+ min-width: 0;
936
+ }
937
+
938
+ .stats dt {
939
+ color: var(--ink-3);
940
+ font-size: 0.75rem;
941
+ }
942
+
943
+ .stats dd {
944
+ margin: 0;
945
+ font-size: 0.9375rem;
946
+ font-weight: 600;
947
+ font-variant-numeric: tabular-nums;
948
+ }
949
+
950
+ .stats dd span {
951
+ color: var(--ink-3);
952
+ font-size: 0.75rem;
953
+ font-weight: 400;
954
+ }
955
+
956
+ .trend {
957
+ display: grid;
958
+ gap: 8px;
959
+ }
960
+
961
+ .spark {
962
+ margin: 0;
963
+ }
964
+
965
+ .spark figcaption {
966
+ margin-bottom: 4px;
967
+ color: var(--ink-3);
968
+ font-size: 0.75rem;
969
+ }
970
+
971
+ .spark svg {
972
+ display: block;
973
+ width: 100%;
974
+ height: 56px;
975
+ overflow: visible;
976
+ }
977
+
978
+ .sparkBase {
979
+ stroke: var(--line-2);
980
+ stroke-width: 1;
981
+ vector-effect: non-scaling-stroke;
982
+ }
983
+
984
+ .sparkLine {
985
+ fill: none;
986
+ stroke: var(--ink-3);
987
+ stroke-width: 2;
988
+ stroke-linejoin: round;
989
+ stroke-linecap: round;
990
+ vector-effect: non-scaling-stroke;
991
+ }
992
+
993
+ .spark circle {
994
+ fill: var(--ink-3);
995
+ stroke: var(--bg);
996
+ stroke-width: 1;
997
+ }
998
+
999
+ .spark circle[data-status='failed'] {
1000
+ fill: var(--failed);
1001
+ }
1002
+
1003
+ .sparkHit {
1004
+ fill: transparent;
1005
+ }
1006
+
1007
+ .sparkHit:hover {
1008
+ fill: var(--place-soft);
1009
+ fill-opacity: 0.5;
1010
+ }
1011
+
1012
+ .strip {
1013
+ display: flex;
1014
+ flex-wrap: wrap;
1015
+ gap: 2px;
1016
+ }
1017
+
1018
+ .strip span {
1019
+ width: 8px;
1020
+ height: 14px;
1021
+ border-radius: 2px;
1022
+ background: var(--not-reached);
1023
+ }
1024
+
1025
+ .strip span[data-status='passed'] {
1026
+ background: var(--passed);
1027
+ }
1028
+
1029
+ .strip span[data-status='failed'] {
1030
+ background: var(--failed);
1031
+ }
1032
+
1033
+ .strip span[data-status='running'] {
1034
+ background: var(--place);
1035
+ }
1036
+
1037
+ .tags {
1038
+ display: flex;
1039
+ flex-wrap: wrap;
1040
+ gap: 4px 8px;
1041
+ font-size: 0.8125rem;
1042
+ }
1043
+
1044
+ .tags > * {
1045
+ padding: 1px 8px;
1046
+ border: 1px solid var(--line-2);
1047
+ border-radius: var(--pill);
1048
+ color: var(--ink-2);
1049
+ text-decoration: none;
1050
+ }
1051
+
1052
+ .tags a {
1053
+ color: var(--place);
1054
+ }
1055
+
1056
+ /* Runs */
1057
+
1058
+ .runs {
1059
+ display: grid;
1060
+ gap: 10px;
1061
+ }
1062
+
1063
+ .runs > * {
1064
+ margin: 0;
1065
+ }
1066
+
1067
+ .runMeter {
1068
+ display: inline-block;
1069
+ width: 4rem;
1070
+ margin-right: 8px;
1071
+ vertical-align: middle;
1072
+ }
1073
+
1074
+ .runCounts {
1075
+ display: inline-flex;
1076
+ gap: 8px;
1077
+ color: var(--ink-3);
1078
+ font-variant-numeric: tabular-nums;
1079
+ }
1080
+
1081
+ .runCounts strong {
1082
+ color: var(--failed);
1083
+ }
1084
+
1085
+ .runCounts [data-status='running'] {
1086
+ color: var(--place);
1087
+ }
1088
+
1089
+ .runTitle {
1090
+ font-size: 1.125rem;
1091
+ font-weight: 650;
1092
+ }
1093
+
1094
+ .runMeta {
1095
+ display: flex;
1096
+ flex-wrap: wrap;
1097
+ gap: 0 10px;
1098
+ color: var(--ink-3);
1099
+ font-size: 0.8125rem;
1100
+ }
1101
+
1102
+ .runMeta > * + *::before {
1103
+ margin-right: 10px;
1104
+ color: var(--faint);
1105
+ content: '·';
1106
+ }
1107
+
1108
+ .runSummary {
1109
+ display: flex;
1110
+ align-items: center;
1111
+ gap: 12px;
1112
+ font-size: 0.875rem;
1113
+ }
1114
+
1115
+ .back {
1116
+ display: inline-flex;
1117
+ gap: 6px;
1118
+ color: var(--place);
1119
+ font-size: 0.875rem;
1120
+ font-weight: 500;
1121
+ text-decoration: none;
1122
+ }
1123
+
1124
+ .actionsLine {
1125
+ display: flex;
1126
+ flex-wrap: wrap;
1127
+ align-items: center;
1128
+ gap: 14px;
1129
+ font-size: 0.875rem;
1130
+ }
1131
+
1132
+ .actionsLine a {
1133
+ color: var(--place);
1134
+ }
1135
+
1136
+ .actionsLine a.primary {
1137
+ padding: 6px 14px;
1138
+ border-radius: var(--pill);
1139
+ background: var(--place);
1140
+ color: #fff;
1141
+ font-weight: 600;
1142
+ text-decoration: none;
1143
+ }
1144
+
1145
+ /* Index */
1146
+
1147
+ .indexHeading {
1148
+ margin: 14px 10px 4px;
1149
+ color: var(--ink-3);
1150
+ font-size: 0.75rem;
1151
+ font-weight: 600;
1152
+ }
1153
+
1154
+ .indexDomainHead {
1155
+ display: flex;
1156
+ align-items: center;
1157
+ }
1158
+
1159
+ .indexDomainHead > a {
1160
+ flex: 1;
1161
+ min-width: 0;
1162
+ }
1163
+
1164
+ .indexToggle {
1165
+ display: inline-flex;
1166
+ flex: none;
1167
+ align-items: center;
1168
+ justify-content: center;
1169
+ width: 20px;
1170
+ height: 28px;
1171
+ padding: 0;
1172
+ border: 0;
1173
+ background: none;
1174
+ cursor: pointer;
1175
+ }
1176
+
1177
+ .indexSpecs {
1178
+ padding-left: 14px !important;
1179
+ }
1180
+
1181
+ /* Too narrow for two columns: the open test above the list, one scroll. */
1182
+ @media (max-width: 1100px) {
1183
+ .explorer[data-split] {
1184
+ display: flex;
1185
+ flex-direction: column;
1186
+ overflow: auto;
1187
+ }
1188
+
1189
+ .explorer[data-split] .side {
1190
+ order: -1;
1191
+ flex: none;
1192
+ overflow: visible;
1193
+ border-left: 0;
1194
+ border-bottom: 1px solid var(--line);
1195
+ }
1196
+
1197
+ .explorer[data-split] .main {
1198
+ flex: none;
1199
+ overflow: visible;
1200
+ }
1201
+ }
1202
+
1203
+ @media (max-width: 760px) {
1204
+ .explorer,
1205
+ .explorer[data-split] {
1206
+ height: auto;
1207
+ overflow: visible;
1208
+ }
1209
+
1210
+ .main,
1211
+ .side {
1212
+ overflow: visible;
1213
+ }
1214
+
1215
+ .main {
1216
+ padding: 20px 16px 48px;
1217
+ }
1218
+
1219
+ .side {
1220
+ padding: 16px;
1221
+ }
1222
+
1223
+ .tile[data-wide] {
1224
+ grid-column: auto;
1225
+ }
1226
+
1227
+ .columns {
1228
+ grid-template-columns: 4rem 3rem;
1229
+ }
1230
+
1231
+ .columns > span:nth-child(n + 3) {
1232
+ display: none;
1233
+ }
1234
+
1235
+ .groupMeter {
1236
+ display: none;
1237
+ }
1238
+ }