@matware/e2e-runner 1.3.1 → 1.5.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 (47) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/README.md +110 -21
  4. package/agents/test-creator.md +4 -2
  5. package/agents/test-improver.md +5 -3
  6. package/bin/cli.js +80 -17
  7. package/package.json +3 -2
  8. package/skills/e2e-testing/SKILL.md +3 -2
  9. package/skills/e2e-testing/references/action-types.md +22 -4
  10. package/skills/e2e-testing/references/test-json-format.md +23 -0
  11. package/src/actions.js +170 -14
  12. package/src/config.js +6 -0
  13. package/src/dashboard.js +135 -4
  14. package/src/db.js +11 -0
  15. package/src/mcp-tools.js +8 -2
  16. package/src/module-analysis.js +247 -0
  17. package/src/module-resolver.js +35 -2
  18. package/src/narrate.js +14 -1
  19. package/src/pool-manager.js +46 -1
  20. package/src/pool.js +177 -20
  21. package/src/runner.js +77 -10
  22. package/src/visual-diff.js +69 -0
  23. package/src/websocket.js +14 -3
  24. package/src/wizard.js +184 -0
  25. package/templates/build-dashboard.js +3 -0
  26. package/templates/dashboard/js/api.js +60 -3
  27. package/templates/dashboard/js/init.js +46 -0
  28. package/templates/dashboard/js/keyboard.js +8 -7
  29. package/templates/dashboard/js/quicksearch.js +277 -0
  30. package/templates/dashboard/js/state.js +61 -7
  31. package/templates/dashboard/js/toast.js +1 -1
  32. package/templates/dashboard/js/view-live.js +235 -42
  33. package/templates/dashboard/js/view-runs.js +379 -37
  34. package/templates/dashboard/js/view-tests.js +157 -16
  35. package/templates/dashboard/js/view-tools.js +234 -0
  36. package/templates/dashboard/js/view-watch.js +2 -2
  37. package/templates/dashboard/js/websocket.js +33 -3
  38. package/templates/dashboard/styles/base.css +489 -53
  39. package/templates/dashboard/styles/components.css +719 -84
  40. package/templates/dashboard/styles/view-live.css +459 -78
  41. package/templates/dashboard/styles/view-runs.css +779 -177
  42. package/templates/dashboard/styles/view-tests.css +440 -77
  43. package/templates/dashboard/styles/view-tools.css +206 -0
  44. package/templates/dashboard/styles/view-watch.css +198 -41
  45. package/templates/dashboard/template.html +354 -56
  46. package/templates/dashboard.html +5173 -711
  47. package/templates/docker-compose-lightpanda.yml +7 -0
@@ -1,117 +1,752 @@
1
+ /* ═══════════════════════════════════════════════════════════════════
2
+ COMPONENTS — buttons, cards, tables, badges, toasts, modals
3
+ ═══════════════════════════════════════════════════════════════════ */
4
+
1
5
  /* ── Buttons ── */
2
- .btn{display:inline-flex;align-items:center;gap:6px;padding:7px 14px;border-radius:var(--r);font-family:var(--mono);font-size:11px;font-weight:500;cursor:pointer;border:1px solid var(--border);background:var(--surface2);color:var(--text);transition:all .15s;white-space:nowrap}
3
- .btn:hover{background:var(--surface3);border-color:var(--border-hi)}
4
- .btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}
5
- .btn.primary:hover{background:#2563eb}
6
- .btn.danger{background:var(--red-dim);border-color:rgba(239,68,68,.3);color:var(--red)}
7
- .btn:disabled{opacity:.4;cursor:not-allowed}
8
- .btn.sm{padding:4px 10px;font-size:10px}
6
+ .btn{
7
+ display:inline-flex;align-items:center;gap:6px;
8
+ padding:8px 14px;
9
+ border-radius:var(--r);
10
+ font-family:var(--mono);
11
+ font-size:10px;font-weight:600;
12
+ letter-spacing:.14em;text-transform:uppercase;
13
+ cursor:pointer;
14
+ border:1px solid var(--border);
15
+ background:var(--surface);
16
+ color:var(--text2);
17
+ transition:all .15s ease;
18
+ white-space:nowrap;
19
+ position:relative;
20
+ }
21
+ .btn:hover{background:var(--surface2);border-color:var(--border-hi);color:var(--text)}
22
+ .btn:active{transform:translateY(1px)}
23
+ .btn.primary{
24
+ background:var(--ui-accent);
25
+ border-color:var(--ui-accent);
26
+ color:#06121a;
27
+ text-shadow:none;
28
+ box-shadow:0 0 16px var(--ui-accent-dim);
29
+ }
30
+ .btn.primary:hover{
31
+ filter:brightness(1.08);
32
+ box-shadow:0 0 22px var(--ui-accent-dim);
33
+ }
34
+ .btn.danger{background:var(--crimson-dim);border-color:rgba(255,77,77,.4);color:var(--crimson)}
35
+ .btn.danger:hover{background:rgba(255,77,77,.18);color:var(--crimson)}
36
+ .btn:disabled{opacity:.35;cursor:not-allowed;filter:grayscale(.5)}
37
+ .btn.sm{padding:5px 10px;font-size:9px;letter-spacing:.12em}
9
38
 
10
39
  /* ── Cards ── */
11
- .card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);padding:16px;margin-bottom:16px}
12
- .card-label{font-size:9px;font-weight:600;color:var(--text3);letter-spacing:.1em;text-transform:uppercase;margin-bottom:10px}
40
+ .card{
41
+ background:var(--surface);
42
+ border:1px solid var(--border);
43
+ border-radius:var(--r);
44
+ padding:18px;
45
+ margin-bottom:16px;
46
+ position:relative;
47
+ }
48
+ .card::before{
49
+ content:'';position:absolute;top:0;left:16px;width:22px;height:1px;
50
+ background:var(--phosphor);opacity:.5;
51
+ }
52
+ .card-label{
53
+ font-size:10px;font-weight:700;color:var(--text3);
54
+ letter-spacing:.14em;text-transform:uppercase;
55
+ margin-bottom:12px;
56
+ display:flex;align-items:center;gap:8px;
57
+ }
58
+ .card-label::after{content:'';flex:1;height:1px;background:var(--border)}
13
59
 
14
60
  /* ── Stats Row ── */
15
61
  .stats{display:flex;gap:24px;margin-bottom:20px}
16
62
  .stat-block{text-align:center;min-width:80px}
17
- .stat-val{font-size:26px;font-weight:700}
18
- .stat-lbl{font-size:9px;color:var(--text3);text-transform:uppercase;letter-spacing:.1em;margin-top:2px}
19
- .stat-val.green{color:var(--green)}
20
- .stat-val.red{color:var(--red)}
21
- .stat-val.accent{color:var(--accent)}
22
- .stat-val.purple{color:var(--purple)}
63
+ .stat-val{font-family:var(--display);font-size:34px;font-weight:400;line-height:1;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
64
+ .stat-lbl{font-size:10px;color:var(--text3);text-transform:uppercase;letter-spacing:.14em;margin-top:6px;font-weight:700}
65
+ .stat-val.green{color:var(--phosphor);text-shadow:0 0 14px var(--phosphor-glow)}
66
+ .stat-val.red{color:var(--crimson)}
67
+ .stat-val.accent{color:var(--beacon)}
68
+ .stat-val.purple{color:var(--radio);text-shadow:0 0 14px var(--radio-glow)}
23
69
 
24
70
  /* ── Tables ── */
25
71
  .tbl-wrap{overflow-x:auto}
26
- table{width:100%;border-collapse:collapse;font-size:12px}
27
- th{text-align:left;font-size:9px;font-weight:600;color:var(--text3);letter-spacing:.1em;text-transform:uppercase;padding:8px 12px;border-bottom:1px solid var(--border)}
28
- td{padding:8px 12px;border-bottom:1px solid var(--border)}
29
- tbody tr{cursor:pointer;transition:background .1s}
72
+ table{width:100%;border-collapse:collapse;font-size:11px;font-family:var(--mono)}
73
+ th{
74
+ text-align:left;
75
+ font-size:9.5px;font-weight:700;
76
+ color:var(--text3);
77
+ letter-spacing:.14em;text-transform:uppercase;
78
+ padding:10px 14px;
79
+ border-bottom:1px solid var(--border);
80
+ background:var(--bg-2);
81
+ position:relative;
82
+ }
83
+ td{
84
+ padding:10px 14px;
85
+ border-bottom:1px solid var(--border);
86
+ font-variant-numeric:tabular-nums;
87
+ }
88
+ tbody tr{cursor:pointer;transition:background .12s}
30
89
  tbody tr:hover td{background:var(--surface2)}
31
- tbody tr.selected td{background:var(--accent-dim)}
90
+ tbody tr:hover td:first-child{box-shadow:inset 3px 0 0 var(--border-hi)}
91
+ tbody tr.selected td{
92
+ background:var(--ui-accent-dim);
93
+ color:var(--text);
94
+ box-shadow:inset 3px 0 0 var(--ui-accent);
95
+ }
32
96
 
33
97
  /* ── Badges ── */
34
- .badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:10px;font-weight:600}
35
- .badge.pass{background:var(--green-dim);color:var(--green)}
36
- .badge.fail{background:var(--red-dim);color:var(--red)}
37
- .badge.flaky{background:var(--amber-dim);color:var(--amber)}
38
- .badge.run{background:var(--purple-dim);color:var(--purple)}
98
+ .badge{
99
+ display:inline-flex;align-items:center;
100
+ padding:3px 9px;border-radius:999px;
101
+ font-size:9px;font-weight:700;
102
+ letter-spacing:.1em;text-transform:uppercase;
103
+ font-family:var(--mono);
104
+ border:1px solid transparent;
105
+ }
106
+ .badge.pass,.badge.passed{background:var(--phosphor-dim);color:var(--phosphor);border-color:rgba(158,242,106,.3)}
107
+ .badge.fail,.badge.failed{background:var(--crimson-dim);color:var(--crimson);border-color:rgba(255,77,77,.35)}
108
+ .badge.flaky{background:var(--amber-dim);color:var(--amber);border-color:rgba(255,179,71,.3)}
109
+ .badge.run,.badge.running{background:var(--purple-dim);color:var(--purple);border-color:rgba(167,139,250,.35);animation:badgePulse 1.6s ease-in-out infinite}
110
+ .badge.idle{background:transparent;color:var(--text3);border-color:var(--border)}
111
+ @keyframes badgePulse{
112
+ 0%,100%{box-shadow:0 0 0 0 rgba(167,139,250,.3)}
113
+ 50%{box-shadow:0 0 0 5px rgba(167,139,250,0)}
114
+ }
115
+
116
+ /* ── Top bar ── */
117
+ .topbar{
118
+ display:grid;align-items:center;
119
+ grid-template-columns:1fr auto 1fr;
120
+ gap:14px;
121
+ padding:9px 22px;
122
+ margin:-22px -22px 18px;
123
+ background:var(--bg-2);
124
+ border-bottom:1px solid var(--border);
125
+ position:sticky;top:0;z-index:20;
126
+ backdrop-filter:blur(8px);
127
+ }
128
+ .topbar-breadcrumb{justify-self:start;min-width:0}
129
+ .topbar-actions{justify-self:end;display:flex;gap:10px;align-items:center}
130
+ .topbar-breadcrumb{
131
+ display:flex;align-items:center;gap:8px;
132
+ font-family:var(--mono);font-size:11px;
133
+ color:var(--text3);letter-spacing:.06em;
134
+ }
135
+ .topbar-section{
136
+ color:var(--text);font-weight:600;
137
+ text-transform:uppercase;letter-spacing:.16em;
138
+ font-size:11px;
139
+ }
140
+ .topbar-sep{color:var(--text3);opacity:.6}
141
+ .topbar-subsection{color:var(--text2);text-transform:uppercase;letter-spacing:.12em;font-size:10px}
142
+ .topbar-actions{display:flex;align-items:center;gap:10px}
143
+ .topbar-live{
144
+ display:inline-flex;align-items:center;gap:7px;
145
+ padding:5px 12px;border-radius:999px;
146
+ cursor:pointer;user-select:none;
147
+ border:1px solid var(--border);
148
+ background:transparent;
149
+ font-family:var(--mono);font-size:10px;font-weight:700;
150
+ letter-spacing:.16em;text-transform:uppercase;
151
+ transition:all .18s;
152
+ }
153
+ .topbar-live:hover{border-color:var(--border-hi);background:var(--surface)}
154
+ .topbar-live-dot{
155
+ width:7px;height:7px;border-radius:50%;
156
+ background:var(--text3);
157
+ }
158
+ .topbar-live-label{color:var(--text2)}
159
+ .topbar-live-count{
160
+ min-width:20px;text-align:center;
161
+ font-variant-numeric:tabular-nums;
162
+ }
163
+ .topbar-live.idle{opacity:.55}
164
+ .topbar-live.running{
165
+ border-color:var(--purple);background:var(--purple-dim);
166
+ }
167
+ .topbar-live.running .topbar-live-dot{
168
+ background:var(--purple);box-shadow:0 0 10px var(--purple);
169
+ animation:livePulse 1.2s ease-in-out infinite;
170
+ }
171
+ .topbar-live.running .topbar-live-label,
172
+ .topbar-live.running .topbar-live-count{color:var(--purple)}
173
+ .topbar-live.failed{border-color:var(--crimson);background:var(--crimson-dim)}
174
+ .topbar-live.failed .topbar-live-dot{background:var(--crimson)}
175
+ .topbar-live.failed .topbar-live-label,
176
+ .topbar-live.failed .topbar-live-count{color:var(--crimson)}
177
+ .topbar-live.passed{border-color:rgba(158,242,106,.3);background:var(--phosphor-dim)}
178
+ .topbar-live.passed .topbar-live-dot{background:var(--phosphor)}
179
+ .topbar-live.passed .topbar-live-label,
180
+ .topbar-live.passed .topbar-live-count{color:var(--phosphor)}
181
+ @keyframes livePulse{
182
+ 0%,100%{transform:scale(1);opacity:1}
183
+ 50%{transform:scale(1.4);opacity:.7}
184
+ }
185
+
186
+ /* ── Network sub-tab table (Investigate › Network) ── */
187
+ .net-row{
188
+ display:grid;
189
+ grid-template-columns:60px 70px 60px 1fr 80px;
190
+ gap:12px;align-items:center;
191
+ padding:8px 14px;
192
+ border-bottom:1px solid var(--border);
193
+ font-family:var(--mono);font-size:11px;
194
+ }
195
+ .net-row:last-child{border-bottom:none}
196
+ .net-row.clickable{cursor:pointer;transition:background .12s}
197
+ .net-row.clickable:hover{background:var(--surface2)}
198
+ .net-row.net-head{
199
+ background:var(--bg-2);font-size:9px;font-weight:700;
200
+ color:var(--text3);text-transform:uppercase;letter-spacing:.18em;
201
+ padding:10px 14px;
202
+ }
203
+ .net-col-run{color:var(--text3)}
204
+ .net-col-method{font-weight:700;text-transform:uppercase;font-size:10px}
205
+ .net-col-method.m-get{color:var(--phosphor)}
206
+ .net-col-method.m-post{color:var(--amber)}
207
+ .net-col-method.m-put,.net-col-method.m-patch{color:var(--radio)}
208
+ .net-col-method.m-delete{color:var(--crimson)}
209
+ .net-col-status{font-weight:700;font-variant-numeric:tabular-nums}
210
+ .net-col-status.st-s2xx{color:var(--phosphor)}
211
+ .net-col-status.st-s3xx{color:var(--beacon)}
212
+ .net-col-status.st-s4xx{color:var(--amber)}
213
+ .net-col-status.st-s5xx{color:var(--crimson)}
214
+ .net-col-url{color:var(--text2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
215
+ .net-col-dur{color:var(--text3);text-align:right;font-variant-numeric:tabular-nums}
39
216
 
40
217
  /* ── Empty ── */
41
- .empty{text-align:center;padding:48px 24px;color:var(--text3)}
42
- .empty-icon{font-size:36px;margin-bottom:8px;opacity:.5}
218
+ .empty{
219
+ text-align:center;padding:64px 24px;color:var(--text2);
220
+ font-family:var(--mono);font-size:12px;
221
+ border:1px dashed var(--border-hi);
222
+ border-radius:var(--r);
223
+ background:
224
+ repeating-linear-gradient(135deg,transparent 0 18px,rgba(168,245,122,.025) 18px 19px),
225
+ var(--surface);
226
+ }
227
+ .empty-icon{
228
+ font-size:44px;margin-bottom:14px;opacity:.6;
229
+ color:var(--phosphor);
230
+ display:block;
231
+ text-shadow:0 0 18px var(--phosphor-glow);
232
+ }
233
+ .empty p{letter-spacing:.06em;line-height:1.6}
234
+ .empty code{color:var(--phosphor);background:var(--bg-2);padding:1px 6px;border-radius:2px;border:1px solid var(--border)}
43
235
 
44
- /* ── Modal ── */
45
- .modal{position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:200;display:none;align-items:center;justify-content:center;padding:24px;cursor:pointer}
236
+ /* ── Modal (image lightbox) ── */
237
+ .modal{
238
+ position:fixed;inset:0;
239
+ background:rgba(10,11,8,.92);
240
+ backdrop-filter:blur(6px);
241
+ z-index:200;display:none;
242
+ align-items:center;justify-content:center;padding:32px;cursor:pointer;
243
+ }
46
244
  .modal.open{display:flex}
47
- .modal img{max-width:100%;max-height:90vh;border-radius:var(--r);cursor:default}
48
-
49
- /* ── Toast Notifications ── */
50
- .toast-container{position:fixed;bottom:24px;right:24px;z-index:300;display:flex;flex-direction:column-reverse;gap:8px;pointer-events:none}
51
- .toast{padding:10px 16px;border-radius:var(--r);font-family:var(--mono);font-size:11px;font-weight:500;color:#fff;pointer-events:auto;animation:toastIn .3s ease;min-width:200px;max-width:380px;box-shadow:0 8px 24px rgba(0,0,0,.4);display:flex;align-items:center;gap:8px}
52
- .toast.success{background:var(--green);border:1px solid rgba(255,255,255,.15)}
53
- .toast.error{background:var(--red);border:1px solid rgba(255,255,255,.15)}
54
- .toast.info{background:var(--accent);border:1px solid rgba(255,255,255,.15)}
55
- .toast.fade-out{animation:toastOut .3s ease forwards}
56
- @keyframes toastIn{from{opacity:0;transform:translateX(24px)}to{opacity:1;transform:translateX(0)}}
57
- @keyframes toastOut{from{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(24px)}}
245
+ .modal img{
246
+ max-width:100%;max-height:90vh;
247
+ border:1px solid var(--border);border-radius:var(--r);
248
+ cursor:default;
249
+ box-shadow:0 0 0 1px rgba(158,242,106,.12),0 40px 80px rgba(0,0,0,.6);
250
+ }
251
+
252
+ /* ── Toasts ── */
253
+ .toast-container{
254
+ position:fixed;bottom:24px;right:24px;z-index:300;
255
+ display:flex;flex-direction:column-reverse;gap:8px;pointer-events:none;
256
+ }
257
+ .toast{
258
+ padding:10px 14px 10px 16px;
259
+ border-radius:var(--r);
260
+ font-family:var(--mono);
261
+ font-size:11px;font-weight:500;
262
+ color:#0b0c09;
263
+ pointer-events:auto;
264
+ animation:toastIn .28s cubic-bezier(.2,.9,.3,1.2);
265
+ min-width:240px;max-width:380px;
266
+ box-shadow:0 0 0 1px rgba(0,0,0,.4),0 12px 30px rgba(0,0,0,.45);
267
+ display:flex;align-items:center;gap:10px;
268
+ position:relative;overflow:hidden;
269
+ letter-spacing:.03em;
270
+ }
271
+ .toast::before{
272
+ content:'';position:absolute;left:0;top:0;bottom:0;width:3px;
273
+ background:currentColor;opacity:.7;
274
+ }
275
+ .toast.success{background:var(--phosphor);color:#0b0c09}
276
+ .toast.error{background:var(--crimson);color:#fff}
277
+ .toast.info{background:var(--beacon);color:#0b0c09}
278
+ .toast.fade-out{animation:toastOut .25s ease forwards}
279
+ @keyframes toastIn{
280
+ from{opacity:0;transform:translateX(28px) scale(.96)}
281
+ to{opacity:1;transform:translateX(0) scale(1)}
282
+ }
283
+ @keyframes toastOut{
284
+ from{opacity:1;transform:translateX(0)}
285
+ to{opacity:0;transform:translateX(28px)}
286
+ }
58
287
  .toast.clickable{cursor:pointer}
59
- .toast.clickable:hover{filter:brightness(1.1)}
288
+ .toast.clickable:hover{filter:brightness(1.08)}
60
289
 
61
290
  /* ── Copy Button ── */
62
- .copy-btn{display:inline-flex;align-items:center;gap:3px;padding:2px 8px;border-radius:4px;font-size:9px;font-family:var(--mono);font-weight:500;color:var(--text3);background:transparent;border:1px solid transparent;cursor:pointer;transition:all .15s;user-select:none;white-space:nowrap;flex-shrink:0}
63
- .copy-btn:hover{color:var(--accent);border-color:var(--accent);background:var(--accent-dim)}
64
- .copy-btn.copied{color:var(--green);border-color:var(--green);background:var(--green-dim)}
65
-
66
- /* ── Screenshot Hash Badge ── */
67
- .ss-hash{display:inline-flex;align-items:center;gap:4px;padding:2px 7px;border-radius:10px;font-family:var(--mono);font-size:9px;font-weight:500;background:var(--surface3);border:1px solid var(--border);color:var(--text2);cursor:pointer;transition:all .15s;user-select:none;white-space:nowrap;vertical-align:middle}
68
- .ss-hash:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-dim)}
69
- .ss-hash.copied{border-color:var(--green);color:var(--green);background:var(--green-dim)}
291
+ .copy-btn{
292
+ display:inline-flex;align-items:center;gap:3px;
293
+ padding:2px 8px;border-radius:2px;
294
+ font-size:9px;font-family:var(--mono);font-weight:600;
295
+ letter-spacing:.1em;text-transform:uppercase;
296
+ color:var(--text3);background:transparent;
297
+ border:1px solid transparent;
298
+ cursor:pointer;transition:all .15s;user-select:none;white-space:nowrap;flex-shrink:0;
299
+ }
300
+ .copy-btn:hover{color:var(--beacon);border-color:var(--beacon);background:var(--beacon-dim)}
301
+ .copy-btn.copied{color:var(--phosphor);border-color:var(--phosphor);background:var(--phosphor-dim)}
302
+
303
+ /* ── Screenshot hash badge ── */
304
+ .ss-hash{
305
+ display:inline-flex;align-items:center;gap:4px;
306
+ padding:2px 8px;border-radius:999px;
307
+ font-family:var(--mono);font-size:9px;font-weight:500;
308
+ letter-spacing:.04em;
309
+ background:var(--surface3);
310
+ border:1px solid var(--border);
311
+ color:var(--text2);cursor:pointer;
312
+ transition:all .15s;user-select:none;white-space:nowrap;vertical-align:middle;
313
+ }
314
+ .ss-hash:hover{border-color:var(--beacon);color:var(--beacon);background:var(--beacon-dim)}
315
+ .ss-hash.copied{border-color:var(--phosphor);color:var(--phosphor);background:var(--phosphor-dim)}
70
316
  .ss-hash .ss-icon{font-size:10px;line-height:1}
71
317
 
72
- /* ── Trigger Source Badges ── */
73
- .trigger-badge{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;font-size:10px;font-weight:600;font-family:var(--mono);white-space:nowrap}
74
- .trigger-badge.src-dashboard{background:rgba(127,140,162,.10);color:var(--text2)}
75
- .trigger-badge.src-mcp{background:var(--purple-dim);color:var(--purple)}
76
- .trigger-badge.src-cli{background:var(--accent-dim);color:var(--accent)}
77
- .trigger-badge.src-unknown{background:rgba(70,75,98,.15);color:var(--text3)}
78
- .trigger-badge .trig-icon{font-size:11px;line-height:1}
79
-
80
- /* ── Driver Badges ── */
81
- .driver-badge{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;font-size:10px;font-weight:600;font-family:var(--mono);white-space:nowrap}
82
- .driver-badge.drv-browserless{background:var(--accent-dim)}
83
- .driver-badge.drv-cdp{background:var(--purple-dim)}
84
- .driver-badge.drv-steel{background:var(--amber-dim)}
85
- .driver-badge .drv-icon{font-size:11px;line-height:1}
318
+ /* ── Trigger & Driver Badges ── */
319
+ .trigger-badge,.driver-badge{
320
+ display:inline-flex;align-items:center;gap:4px;
321
+ padding:2px 8px;border-radius:999px;
322
+ font-size:9px;font-weight:700;font-family:var(--mono);
323
+ letter-spacing:.1em;text-transform:uppercase;
324
+ white-space:nowrap;
325
+ border:1px solid transparent;
326
+ }
327
+ .trigger-badge.src-dashboard{background:rgba(150,144,119,.1);color:var(--text2);border-color:var(--border)}
328
+ .trigger-badge.src-mcp{background:var(--radio-dim);color:var(--radio);border-color:rgba(255,45,141,.35)}
329
+ .trigger-badge.src-cli{background:var(--beacon-dim);color:var(--beacon);border-color:rgba(125,211,252,.35)}
330
+ .trigger-badge.src-unknown{background:rgba(91,87,68,.15);color:var(--text3)}
331
+ .trigger-badge .trig-icon{font-size:10px;line-height:1}
332
+
333
+ .driver-badge.drv-browserless{background:var(--beacon-dim);color:var(--beacon);border-color:rgba(125,211,252,.3)}
334
+ .driver-badge.drv-cdp{background:var(--radio-dim);color:var(--radio);border-color:rgba(255,45,141,.3)}
335
+ .driver-badge.drv-steel{background:var(--amber-dim);color:var(--amber);border-color:rgba(255,179,71,.3)}
336
+ .driver-badge .drv-icon{font-size:10px;line-height:1}
86
337
 
87
338
  /* ── Filter Bar ── */
88
- .filter-bar{display:flex;align-items:center;gap:8px;margin-bottom:16px;flex-wrap:wrap}
89
- .filter-btn{padding:5px 12px;border-radius:var(--r);border:1px solid var(--border);background:var(--surface2);color:var(--text2);font-family:var(--mono);font-size:11px;cursor:pointer;transition:all .15s}
90
- .filter-btn:hover{background:var(--surface3);border-color:var(--border-hi)}
91
- .filter-btn.active{background:var(--accent-dim);border-color:var(--accent);color:var(--accent)}
92
- .filter-bar input{padding:5px 10px;border-radius:var(--r);border:1px solid var(--border);background:var(--surface2);color:var(--text);font-family:var(--mono);font-size:11px;max-width:200px}
93
- .filter-bar input:focus{outline:none;border-color:var(--accent)}
94
- .filter-bar input::placeholder{color:var(--text3)}
339
+ .filter-bar{
340
+ display:flex;align-items:center;gap:6px;
341
+ margin-bottom:16px;flex-wrap:wrap;
342
+ padding:8px 10px;
343
+ background:var(--bg-2);
344
+ border:1px solid var(--border);
345
+ border-radius:var(--r);
346
+ }
347
+ .filter-btn{
348
+ padding:5px 12px;border-radius:var(--r);
349
+ border:1px solid var(--border);
350
+ background:transparent;
351
+ color:var(--text2);font-family:var(--mono);
352
+ font-size:10px;font-weight:600;
353
+ letter-spacing:.1em;text-transform:uppercase;
354
+ cursor:pointer;transition:all .15s;
355
+ }
356
+ .filter-btn:hover{background:var(--surface2);border-color:var(--border-hi);color:var(--text)}
357
+ .filter-btn.active{
358
+ background:var(--ui-accent-dim);
359
+ border-color:var(--ui-accent);
360
+ color:var(--ui-accent);
361
+ }
362
+ .filter-bar input{
363
+ padding:6px 12px;border-radius:var(--r);
364
+ border:1px solid var(--border);
365
+ background:var(--surface);
366
+ color:var(--text);
367
+ font-family:var(--mono);font-size:11px;
368
+ max-width:220px;
369
+ margin-left:auto;
370
+ }
371
+ .filter-bar input:focus{outline:none;border-color:var(--ui-accent);box-shadow:0 0 0 1px var(--ui-accent-dim)}
372
+ .filter-bar input::placeholder{color:var(--text3);letter-spacing:.04em}
95
373
 
96
374
  /* ── Inner Tabs ── */
97
- .tab-bar{display:flex;gap:0;border-bottom:1px solid var(--border);margin-bottom:20px}
98
- .tab-btn{padding:8px 16px;font-family:var(--mono);font-size:11px;font-weight:500;color:var(--text3);cursor:pointer;border:none;background:transparent;border-bottom:2px solid transparent;transition:all .15s}
99
- .tab-btn:hover{color:var(--text2);background:var(--surface2)}
100
- .tab-btn.active{color:var(--accent);border-bottom-color:var(--accent)}
375
+ .tab-bar{
376
+ display:flex;gap:0;
377
+ border-bottom:1px solid var(--border);
378
+ margin-bottom:22px;
379
+ position:relative;
380
+ }
381
+ .tab-btn{
382
+ padding:10px 18px;
383
+ font-family:var(--mono);
384
+ font-size:10px;font-weight:700;
385
+ letter-spacing:.18em;text-transform:uppercase;
386
+ color:var(--text2);cursor:pointer;
387
+ border:none;background:transparent;
388
+ border-bottom:2px solid transparent;
389
+ transition:color .15s,border-color .15s,background .15s;
390
+ position:relative;
391
+ }
392
+ .tab-btn:hover{color:var(--text);background:var(--surface2)}
393
+ .tab-btn.active{
394
+ color:var(--ui-accent);
395
+ border-bottom-color:var(--ui-accent);
396
+ }
397
+ .tab-btn.active::before{
398
+ content:'▸';position:absolute;left:6px;top:50%;transform:translateY(-50%);
399
+ font-size:9px;color:var(--ui-accent);
400
+ }
101
401
  .tab-pane{display:none}
102
- .tab-pane.active{display:block}
402
+ .tab-pane.active{display:block;animation:paneIn .25s ease}
403
+ @keyframes paneIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}
103
404
 
104
405
  /* ── Keyboard Shortcuts Modal ── */
105
- .kb-modal{position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:250;display:none;align-items:center;justify-content:center;padding:24px}
406
+ .kb-modal{
407
+ position:fixed;inset:0;
408
+ background:rgba(10,11,8,.9);
409
+ backdrop-filter:blur(6px);
410
+ z-index:250;display:none;
411
+ align-items:center;justify-content:center;padding:24px;
412
+ }
106
413
  .kb-modal.open{display:flex}
107
- .kb-modal-content{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:24px;max-width:420px;width:100%;max-height:80vh;overflow-y:auto}
108
- .kb-modal-content h2{font-family:var(--sans);font-size:16px;font-weight:700;margin-bottom:16px;color:var(--text)}
109
- .kb-row{display:flex;align-items:center;justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--border)}
414
+ .kb-modal-content{
415
+ background:var(--surface);
416
+ border:1px solid var(--border);
417
+ border-radius:var(--r);
418
+ padding:28px 28px 22px;
419
+ max-width:460px;width:100%;max-height:80vh;overflow-y:auto;
420
+ position:relative;
421
+ box-shadow:0 0 0 1px rgba(158,242,106,.12),0 40px 80px rgba(0,0,0,.6);
422
+ }
423
+ .kb-modal-content::before{
424
+ content:'KBD · HELP';
425
+ position:absolute;top:-8px;left:20px;
426
+ background:var(--surface);padding:0 8px;
427
+ font-family:var(--mono);font-size:9px;
428
+ letter-spacing:.28em;color:var(--phosphor);font-weight:700;
429
+ }
430
+ .kb-modal-content h2{
431
+ font-family:var(--display);
432
+ font-size:28px;font-weight:400;
433
+ margin-bottom:22px;color:var(--text);letter-spacing:-.01em;
434
+ }
435
+ .kb-row{
436
+ display:flex;align-items:center;justify-content:space-between;
437
+ padding:8px 0;
438
+ border-bottom:1px dashed var(--border);
439
+ }
110
440
  .kb-row:last-child{border-bottom:none}
111
- .kb-key{display:inline-flex;align-items:center;justify-content:center;min-width:24px;padding:2px 8px;border-radius:4px;background:var(--surface3);border:1px solid var(--border);font-family:var(--mono);font-size:11px;font-weight:600;color:var(--accent)}
112
- .kb-desc{font-size:12px;color:var(--text2)}
441
+ .kb-key{
442
+ display:inline-flex;align-items:center;justify-content:center;
443
+ min-width:28px;padding:3px 9px;
444
+ border-radius:var(--r);
445
+ background:var(--bg);
446
+ border:1px solid var(--border-hi);
447
+ font-family:var(--mono);font-size:10px;font-weight:700;
448
+ color:var(--phosphor);
449
+ box-shadow:inset 0 -2px 0 rgba(0,0,0,.3);
450
+ letter-spacing:.08em;
451
+ }
452
+ .kb-desc{font-size:11px;color:var(--text2);letter-spacing:.04em}
113
453
 
114
454
  /* ── Serial / Pool Badges ── */
115
- .serial-badge{display:inline-flex;align-items:center;gap:3px;padding:1px 6px;border-radius:8px;font-size:9px;font-weight:600;background:var(--amber-dim);color:var(--amber);vertical-align:middle;margin-left:4px}
116
- .pool-badge{display:inline-flex;align-items:center;gap:3px;padding:1px 6px;border-radius:8px;font-size:9px;font-weight:600;background:rgba(99,102,241,.15);color:#818cf8;vertical-align:middle;margin-left:4px;font-family:var(--mono);letter-spacing:-.3px}
117
- .pool-badge::before{content:'\1F517';font-size:8px}
455
+ .serial-badge{
456
+ display:inline-flex;align-items:center;gap:3px;
457
+ padding:1px 7px;border-radius:999px;
458
+ font-size:9.5px;font-weight:700;
459
+ letter-spacing:.12em;text-transform:uppercase;
460
+ background:var(--amber-dim);color:var(--amber);
461
+ border:1px solid rgba(255,179,71,.3);
462
+ vertical-align:middle;margin-left:4px;
463
+ }
464
+ .pool-badge{
465
+ display:inline-flex;align-items:center;gap:3px;
466
+ padding:1px 7px;border-radius:999px;
467
+ font-size:9.5px;font-weight:700;
468
+ letter-spacing:.06em;
469
+ background:rgba(125,211,252,.12);color:var(--beacon);
470
+ border:1px solid rgba(125,211,252,.3);
471
+ vertical-align:middle;margin-left:4px;
472
+ font-family:var(--mono);
473
+ }
474
+ .pool-badge::before{content:'◈';font-size:7px;margin-right:1px}
475
+
476
+ /* ── Theme toggle ─────────────────────────────────────────────── */
477
+ .theme-toggle{
478
+ margin:10px 12px 14px;
479
+ display:flex;align-items:center;gap:8px;
480
+ padding:7px 10px;
481
+ background:var(--surface2);
482
+ border:1px solid var(--border);
483
+ border-radius:var(--r-2);
484
+ color:var(--text2);
485
+ font-family:var(--mono);
486
+ font-size:10px;letter-spacing:.06em;text-transform:uppercase;
487
+ cursor:pointer;
488
+ transition:background .15s,color .15s,border-color .15s;
489
+ }
490
+ .theme-toggle:hover{background:var(--surface3);color:var(--text);border-color:var(--border-hi)}
491
+ .theme-toggle-icon{font-size:13px;line-height:1;display:none}
492
+ html[data-theme="dark"] .theme-toggle-icon[data-theme-icon="dark"]{display:inline;color:var(--amber)}
493
+ html[data-theme="light"] .theme-toggle-icon[data-theme-icon="light"]{display:inline;color:var(--beacon)}
494
+ .theme-toggle-label{flex:1;text-align:left}
495
+
496
+ /* ── Screenshot Replay Player ─────────────────────────────────── */
497
+ .replay-modal{
498
+ position:fixed;inset:0;z-index:1100;
499
+ display:none;flex-direction:column;
500
+ background:rgba(0,0,0,.92);
501
+ backdrop-filter:blur(4px);
502
+ }
503
+ .replay-modal.open{display:flex}
504
+ .replay-stage{
505
+ flex:1;min-height:0;
506
+ display:flex;align-items:center;justify-content:center;
507
+ padding:24px;position:relative;
508
+ }
509
+ .replay-stage img{
510
+ max-width:100%;max-height:100%;
511
+ object-fit:contain;
512
+ box-shadow:0 8px 40px rgba(0,0,0,.6);
513
+ border:1px solid rgba(255,255,255,.08);
514
+ border-radius:4px;
515
+ }
516
+ .replay-stage img:not([src]),
517
+ .replay-stage img[src=""]{display:none}
518
+ .replay-empty{
519
+ display:none;color:var(--text3);font-family:var(--mono);font-size:11px;
520
+ letter-spacing:.08em;text-transform:uppercase;
521
+ padding:60px;border:1px dashed rgba(255,255,255,.18);border-radius:4px;
522
+ }
523
+ .replay-modal.empty .replay-empty{display:block}
524
+ .replay-modal.empty .replay-stage img{display:none}
525
+ .replay-info{
526
+ background:rgba(0,0,0,.7);
527
+ border-top:1px solid rgba(255,255,255,.08);
528
+ padding:14px 20px 18px;
529
+ font-family:var(--mono);
530
+ }
531
+ .replay-step-line{
532
+ display:flex;align-items:baseline;gap:12px;
533
+ color:var(--text);font-size:12px;
534
+ margin-bottom:10px;
535
+ }
536
+ .replay-step-num{
537
+ font-weight:600;color:var(--text2);
538
+ letter-spacing:.06em;font-variant-numeric:tabular-nums;
539
+ min-width:60px;
540
+ }
541
+ .replay-step-type{
542
+ padding:2px 8px;background:rgba(255,255,255,.08);
543
+ border-radius:3px;font-size:10px;letter-spacing:.06em;
544
+ text-transform:uppercase;color:var(--beacon);
545
+ }
546
+ .replay-step-narr{flex:1;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
547
+ .replay-progress{
548
+ height:3px;background:rgba(255,255,255,.08);
549
+ border-radius:2px;overflow:hidden;margin-bottom:12px;
550
+ }
551
+ .replay-progress-fill{
552
+ height:100%;background:var(--beacon);
553
+ width:0%;transition:width .15s linear;
554
+ }
555
+ .replay-controls{
556
+ display:flex;align-items:center;gap:8px;
557
+ }
558
+ .replay-btn{
559
+ background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);
560
+ color:var(--text);
561
+ padding:7px 12px;border-radius:3px;cursor:pointer;
562
+ font-family:var(--mono);font-size:11px;
563
+ transition:background .15s,border-color .15s;
564
+ }
565
+ .replay-btn:hover{background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.24)}
566
+ .replay-btn.replay-play{min-width:48px;font-size:13px}
567
+ .replay-speed-group{
568
+ display:flex;align-items:center;gap:4px;margin-left:8px;
569
+ padding-left:12px;border-left:1px solid rgba(255,255,255,.1);
570
+ }
571
+ .replay-label{
572
+ font-size:10px;letter-spacing:.08em;text-transform:uppercase;
573
+ color:var(--text3);margin-right:4px;
574
+ }
575
+ .replay-speed-btn{
576
+ background:transparent;border:1px solid rgba(255,255,255,.12);
577
+ color:var(--text2);
578
+ padding:5px 9px;border-radius:3px;cursor:pointer;
579
+ font-family:var(--mono);font-size:10px;
580
+ transition:background .15s,color .15s,border-color .15s;
581
+ }
582
+ .replay-speed-btn:hover{color:var(--text);border-color:rgba(255,255,255,.24)}
583
+ .replay-speed-btn.active{
584
+ background:var(--beacon);color:var(--bg);border-color:var(--beacon);
585
+ font-weight:600;
586
+ }
587
+ .replay-spacer{flex:1}
588
+ .replay-close{
589
+ background:transparent;border:none;color:var(--text2);
590
+ font-size:24px;cursor:pointer;padding:0 8px;line-height:1;
591
+ }
592
+ .replay-close:hover{color:var(--text)}
593
+ /* Storyline header play button */
594
+ .rd-replay-btn{
595
+ background:rgba(255,255,255,.05);border:1px solid var(--border);
596
+ color:var(--text);
597
+ padding:4px 10px;border-radius:3px;cursor:pointer;
598
+ font-family:var(--mono);font-size:10px;letter-spacing:.06em;
599
+ text-transform:uppercase;
600
+ margin-left:8px;
601
+ transition:background .15s,color .15s,border-color .15s;
602
+ }
603
+ .rd-replay-btn:hover{background:var(--beacon);color:var(--bg);border-color:var(--beacon)}
604
+
605
+ /* ─── Quick Search trigger in topbar ───────────────────────────── */
606
+ .topbar-search-trigger{
607
+ display:inline-flex;align-items:center;gap:10px;
608
+ padding:5px 10px 5px 12px;
609
+ background:var(--surface);
610
+ border:1px solid var(--border);
611
+ border-radius:var(--r);
612
+ color:var(--text2);
613
+ font-family:var(--mono);font-size:10px;
614
+ cursor:pointer;letter-spacing:.06em;
615
+ min-width:200px;
616
+ transition:border-color .15s,background .15s,color .15s;
617
+ }
618
+ .topbar-search-trigger:hover{
619
+ background:var(--surface2);border-color:var(--border-hi);color:var(--text);
620
+ }
621
+ .topbar-search-icon{font-size:11px;opacity:.75}
622
+ .topbar-search-label{flex:1;text-align:left;color:var(--text3);letter-spacing:.04em}
623
+ .topbar-search-kbd{
624
+ font-size:9px;font-weight:700;
625
+ padding:2px 6px;border-radius:2px;
626
+ background:var(--bg-2);border:1px solid var(--border);
627
+ color:var(--text3);letter-spacing:.04em;
628
+ }
629
+ @media(max-width:1100px){
630
+ .topbar-search-label,.topbar-search-kbd{display:none}
631
+ .topbar-search-trigger{min-width:0;padding:5px 10px}
632
+ }
633
+
634
+ /* ─── Quick Search modal ───────────────────────────────────────── */
635
+ .qs-modal{
636
+ position:fixed;inset:0;z-index:1200;
637
+ display:none;align-items:flex-start;justify-content:center;
638
+ padding-top:11vh;
639
+ background:rgba(0,0,0,.55);
640
+ backdrop-filter:blur(3px);
641
+ animation:qs-fade .12s ease-out;
642
+ }
643
+ .qs-modal.open{display:flex}
644
+ @keyframes qs-fade{from{opacity:0}to{opacity:1}}
645
+ .qs-panel{
646
+ width:min(720px,90vw);
647
+ background:var(--surface);
648
+ border:1px solid var(--border-hi);
649
+ border-radius:var(--r-2);
650
+ box-shadow:0 24px 60px rgba(0,0,0,.45),0 0 0 1px rgba(158,242,106,.05);
651
+ overflow:hidden;
652
+ display:flex;flex-direction:column;
653
+ max-height:70vh;
654
+ position:relative;
655
+ }
656
+ .qs-panel::before{
657
+ content:'QUICK·SEARCH';
658
+ position:absolute;top:-8px;left:18px;
659
+ background:var(--bg);padding:0 8px;
660
+ font-family:var(--mono);font-size:8px;font-weight:700;
661
+ letter-spacing:.32em;color:var(--phosphor);
662
+ }
663
+ .qs-input-row{
664
+ display:flex;align-items:center;gap:12px;
665
+ padding:18px 18px 14px;
666
+ border-bottom:1px solid var(--border);
667
+ }
668
+ .qs-input-icon{font-size:14px;color:var(--text3)}
669
+ .qs-input-row input{
670
+ flex:1;
671
+ background:transparent;border:none;outline:none;
672
+ font-family:var(--mono);font-size:14px;
673
+ color:var(--text);
674
+ padding:2px 0;
675
+ letter-spacing:.01em;
676
+ }
677
+ .qs-input-row input::placeholder{color:var(--text3);font-style:italic}
678
+ .qs-input-hint{
679
+ font-family:var(--mono);font-size:9px;
680
+ color:var(--text3);letter-spacing:.06em;
681
+ white-space:nowrap;
682
+ }
683
+ .qs-results{
684
+ flex:1;overflow-y:auto;
685
+ padding:6px 0;
686
+ }
687
+ .qs-group-label{
688
+ font-family:var(--mono);font-size:8.5px;font-weight:700;
689
+ color:var(--text3);letter-spacing:.16em;text-transform:uppercase;
690
+ padding:10px 18px 6px;
691
+ display:flex;align-items:center;gap:8px;
692
+ }
693
+ .qs-group-label::after{
694
+ content:'';flex:1;height:1px;background:var(--border);
695
+ }
696
+ .qs-item{
697
+ display:flex;align-items:center;gap:12px;
698
+ padding:9px 18px;
699
+ cursor:pointer;
700
+ border-left:2px solid transparent;
701
+ transition:background .1s,border-color .1s;
702
+ }
703
+ .qs-item:hover,.qs-item.active{
704
+ background:var(--surface2);
705
+ border-left-color:var(--ui-accent);
706
+ }
707
+ .qs-item-kind{
708
+ font-family:var(--mono);font-size:9px;font-weight:700;
709
+ text-transform:uppercase;letter-spacing:.12em;
710
+ padding:2px 7px;border-radius:2px;
711
+ background:var(--surface3);color:var(--text2);
712
+ min-width:60px;text-align:center;
713
+ }
714
+ .qs-item-kind.suite{background:var(--beacon-dim);color:var(--beacon)}
715
+ .qs-item-kind.module{background:var(--phosphor-dim);color:var(--phosphor)}
716
+ .qs-item-kind.test{background:var(--radio-dim);color:var(--radio)}
717
+ .qs-item-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
718
+ .qs-item-name{
719
+ font-family:var(--mono);font-size:12px;
720
+ color:var(--text);
721
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
722
+ }
723
+ .qs-item-name mark{
724
+ background:transparent;color:var(--ui-accent);font-weight:600;
725
+ }
726
+ .qs-item-sub{
727
+ font-family:var(--mono);font-size:10px;
728
+ color:var(--text3);
729
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
730
+ letter-spacing:.02em;
731
+ }
732
+ .qs-item-meta{
733
+ font-family:var(--mono);font-size:9px;
734
+ color:var(--text3);letter-spacing:.04em;
735
+ white-space:nowrap;
736
+ }
737
+ .qs-empty{
738
+ padding:32px;text-align:center;
739
+ font-family:var(--mono);font-size:11px;
740
+ color:var(--text3);letter-spacing:.04em;
741
+ }
742
+ .qs-modal:not(.has-results) .qs-empty{display:block}
743
+ .qs-modal.has-results .qs-empty{display:none}
744
+
745
+ /* ─── Quick search flash highlight on jump ──────────────────────── */
746
+ .qs-flash{
747
+ animation:qs-flash 1.4s ease-out;
748
+ }
749
+ @keyframes qs-flash{
750
+ 0%{box-shadow:0 0 0 2px var(--ui-accent),0 0 24px var(--ui-accent-dim)}
751
+ 100%{box-shadow:0 0 0 0 transparent,0 0 0 transparent}
752
+ }