@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,69 +1,505 @@
1
- /* ── Reset & Variables ── */
1
+ /* ═══════════════════════════════════════════════════════════════════
2
+ E2E · TELEMETRY CONSOLE · base
3
+ Industrial lab-monitor aesthetic: warm ink, phosphor signals,
4
+ hairline grids, small-caps coordinates.
5
+ ═══════════════════════════════════════════════════════════════════ */
6
+
2
7
  *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
8
+
9
+ /* Smooth theme switch — cross-fade colors and surfaces */
10
+ html{transition:background-color .25s ease}
11
+ :root,html[data-theme="dark"],html[data-theme="light"]{
12
+ transition:--bg .25s,--surface .25s,--text .25s;
13
+ }
14
+
15
+ :root,
16
+ html[data-theme="dark"]{
17
+ /* ink — warm near-black paper */
18
+ --bg:#0b0c09;
19
+ --bg-2:#121310;
20
+ --surface:#181a13;
21
+ --surface2:#1f2018;
22
+ --surface3:#272821;
23
+
24
+ /* hairlines — bumped for visible separators on warm ink */
25
+ --border:#33342a;
26
+ --border-hi:#4a4b3a;
27
+
28
+ /* body text — AA-tuned three-step hierarchy on warm ink */
29
+ --text:#f3eddc; /* primary · 16:1 */
30
+ --text2:#b8b099; /* secondary · 8.1:1 */
31
+ --text3:#8d8772; /* tertiary · 5.1:1 — was 2.4:1 */
32
+
33
+ /* signals — phosphor + alarm vocabulary (dark theme) */
34
+ --phosphor:#a8f57a; /* PASS · phosphor — 13.5:1 */
35
+ --phosphor-dim:rgba(168,245,122,.13);
36
+ --phosphor-glow:rgba(168,245,122,.45);
37
+
38
+ --crimson:#ff6b6b; /* FAIL · alarm — 5.5:1 */
39
+ --crimson-dim:rgba(255,107,107,.14);
40
+
41
+ --amber:#ffc266; /* WARN / FLAKY · CRT amber — 11:1 */
42
+ --amber-dim:rgba(255,194,102,.15);
43
+
44
+ --radio:#ff5fa8; /* RUNNING / LIVE · hot magenta — 5.7:1 */
45
+ --radio-dim:rgba(255,95,168,.15);
46
+ --radio-glow:rgba(255,95,168,.36);
47
+
48
+ --beacon:#8edcfc; /* INFO / SELECT · cold cyan — 10:1 */
49
+ --beacon-dim:rgba(142,220,252,.14);
50
+
51
+ /* atmospheric overlays */
52
+ --grain-opacity:.42;
53
+ --grain-blend:overlay;
54
+ --halo-1:rgba(168,245,122,.045);
55
+ --halo-2:rgba(255,95,168,.035);
56
+ }
57
+
58
+ html[data-theme="light"]{
59
+ /* paper — warm cream */
60
+ --bg:#f5f2e8;
61
+ --bg-2:#ece8d8;
62
+ --surface:#ffffff;
63
+ --surface2:#f8f5ea;
64
+ --surface3:#ece8d8;
65
+
66
+ /* hairlines on paper */
67
+ --border:#c8c1a8;
68
+ --border-hi:#a59b7c;
69
+
70
+ /* ink on paper — AA-tuned */
71
+ --text:#15160f; /* primary · 17:1 */
72
+ --text2:#4a4534; /* secondary · 10.4:1 */
73
+ --text3:#6a634b; /* tertiary · 5.6:1 — was 3.6:1 */
74
+
75
+ /* signals — darker for AA contrast on cream */
76
+ --phosphor:#347d18; /* 4.9:1 on bg */
77
+ --phosphor-dim:rgba(52,125,24,.10);
78
+ --phosphor-glow:rgba(52,125,24,.40);
79
+
80
+ --crimson:#b41f1f;
81
+ --crimson-dim:rgba(180,31,31,.10);
82
+
83
+ --amber:#9c5900;
84
+ --amber-dim:rgba(156,89,0,.12);
85
+
86
+ --radio:#b41760;
87
+ --radio-dim:rgba(180,23,96,.12);
88
+ --radio-glow:rgba(180,23,96,.28);
89
+
90
+ --beacon:#155f8e;
91
+ --beacon-dim:rgba(21,95,142,.12);
92
+
93
+ /* dim atmospheric overlays — paper doesn't need scanlines */
94
+ --grain-opacity:.18;
95
+ --grain-blend:multiply;
96
+ --halo-1:rgba(52,125,24,.025);
97
+ --halo-2:rgba(180,23,96,.018);
98
+ }
99
+
3
100
  :root{
4
- --bg:#090a10;--surface:#11131b;--surface2:#181b26;--surface3:#1f2333;
5
- --border:#232738;--border-hi:#2d3248;
6
- --text:#dfe1e8;--text2:#7c8198;--text3:#464b62;
7
- --accent:#3b82f6;--accent-dim:rgba(59,130,246,.12);
8
- --green:#10b981;--green-dim:rgba(16,185,129,.10);
9
- --red:#ef4444;--red-dim:rgba(239,68,68,.10);
10
- --amber:#f59e0b;--amber-dim:rgba(245,158,11,.10);
11
- --purple:#8b5cf6;--purple-dim:rgba(139,92,246,.12);
12
- --mono:'JetBrains Mono','SF Mono','Fira Code',monospace;
13
- --sans:'Outfit','Inter',-apple-system,sans-serif;
14
- --r:6px;
101
+ /* UI accent — interactive/active/selected/focus/primary states.
102
+ Kept SEPARATE from --phosphor so green stays a pure PASS signal and
103
+ doesn't double as "this is the active tab / selected row / primary". */
104
+ --ui-accent:var(--beacon);
105
+ --ui-accent-dim:var(--beacon-dim);
106
+
107
+ /* backwards-compatible aliases (existing JS/CSS references) */
108
+ --accent:var(--beacon);
109
+ --accent-dim:var(--beacon-dim);
110
+ --green:var(--phosphor);
111
+ --green-dim:var(--phosphor-dim);
112
+ --red:var(--crimson);
113
+ --red-dim:var(--crimson-dim);
114
+ --purple:var(--radio);
115
+ --purple-dim:var(--radio-dim);
116
+
117
+ /* fonts */
118
+ --mono:'JetBrains Mono','SF Mono','IBM Plex Mono',ui-monospace,monospace;
119
+ --sans:'Archivo','IBM Plex Sans',ui-sans-serif,system-ui,sans-serif;
120
+ --display:'Instrument Serif','Times New Roman',serif;
121
+
122
+ /* radius scale — razor-thin, industrial */
123
+ --r:2px;
124
+ --r-2:4px;
125
+
126
+ /* thin elevation — hairlines, not shadows */
127
+ --hair:0 0 0 1px var(--border);
128
+ --hair-hi:0 0 0 1px var(--border-hi);
129
+
130
+ /* focus ring — visible, themed, never an outline:none orphan */
131
+ --focus-ring:0 0 0 2px var(--bg),0 0 0 4px var(--beacon);
132
+
133
+ /* grain / scan overlays */
134
+ --grain:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.1' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.95 0 0 0 0 0.92 0 0 0 0 0.82 0 0 0 0.045 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
135
+ }
136
+
137
+ /* ─── Global focus-visible — keyboard accessibility ─────────────── */
138
+ :focus{outline:none}
139
+ :focus-visible{
140
+ outline:none;
141
+ box-shadow:var(--focus-ring);
142
+ border-radius:var(--r);
143
+ }
144
+ button:focus-visible,
145
+ .btn:focus-visible,
146
+ .filter-btn:focus-visible,
147
+ .tab-btn:focus-visible,
148
+ a:focus-visible{
149
+ box-shadow:var(--focus-ring);
15
150
  }
151
+ input:focus-visible,
152
+ select:focus-visible,
153
+ textarea:focus-visible{
154
+ outline:none;
155
+ border-color:var(--beacon);
156
+ box-shadow:0 0 0 3px var(--beacon-dim);
157
+ }
158
+
16
159
  html{font-size:13px}
17
- body{font-family:var(--mono);background:var(--bg);color:var(--text);min-height:100vh;display:flex}
18
- a{color:var(--accent);text-decoration:none}
19
- ::selection{background:var(--accent);color:#fff}
20
-
21
- /* ── Sidebar ── */
22
- .sidebar{width:232px;background:var(--surface);border-right:1px solid var(--border);display:flex;flex-direction:column;position:fixed;top:0;left:0;bottom:0;z-index:50;overflow-y:auto}
23
- .sidebar-logo{padding:20px 16px 16px;border-bottom:1px solid var(--border)}
24
- .sidebar-logo h1{font-family:var(--sans);font-size:15px;font-weight:700;letter-spacing:-.02em}
25
- .sidebar-logo h1 span{color:var(--accent)}
26
- .sidebar-logo .ver{font-size:10px;color:var(--text3);margin-top:2px}
27
-
28
- .sidebar-section{padding:12px 16px 8px}
29
- .sidebar-section-label{font-size:9px;font-weight:600;color:var(--text3);letter-spacing:.12em;text-transform:uppercase;margin-bottom:8px}
30
- .sidebar select{width:100%;padding:8px 10px;border-radius:var(--r);border:1px solid var(--border);background:var(--surface2);color:var(--text);font-family:var(--mono);font-size:12px;appearance:auto;cursor:pointer}
31
- .sidebar select:focus{outline:none;border-color:var(--accent)}
32
-
33
- .nav-item{display:flex;align-items:center;gap:10px;padding:8px 16px;font-size:12px;color:var(--text2);cursor:pointer;border-left:2px solid transparent;transition:all .15s}
160
+
161
+ body{
162
+ font-family:var(--mono);
163
+ background:var(--bg);
164
+ color:var(--text);
165
+ min-height:100vh;
166
+ display:flex;
167
+ -webkit-font-smoothing:antialiased;
168
+ font-feature-settings:"ss01","ss02","cv11","tnum","zero";
169
+ position:relative;
170
+ letter-spacing:.002em;
171
+ }
172
+
173
+ /* atmospheric grain quiet paper tooth */
174
+ body::before{
175
+ content:'';
176
+ position:fixed;inset:0;pointer-events:none;z-index:1000;
177
+ background-image:var(--grain);
178
+ opacity:var(--grain-opacity,.5);
179
+ mix-blend-mode:var(--grain-blend,overlay);
180
+ }
181
+ /* scan halo — extremely subtle lens breathing */
182
+ body::after{
183
+ content:'';
184
+ position:fixed;inset:0;pointer-events:none;z-index:999;
185
+ background:radial-gradient(ellipse at 50% -10%,var(--halo-1,rgba(158,242,106,.04)),transparent 60%),
186
+ radial-gradient(ellipse at 120% 110%,var(--halo-2,rgba(255,45,141,.035)),transparent 55%);
187
+ }
188
+
189
+ a{color:var(--beacon);text-decoration:none;border-bottom:1px dashed transparent;transition:border-color .15s}
190
+ a:hover{border-bottom-color:var(--beacon)}
191
+ ::selection{background:var(--phosphor);color:#101009}
192
+
193
+ /* scrollbars — thin, utilitarian */
194
+ *::-webkit-scrollbar{width:8px;height:8px}
195
+ *::-webkit-scrollbar-track{background:transparent}
196
+ *::-webkit-scrollbar-thumb{background:var(--surface3);border-radius:0}
197
+ *::-webkit-scrollbar-thumb:hover{background:var(--border-hi)}
198
+
199
+ /* ═══════════════════ SIDEBAR — Control Column ═══════════════════ */
200
+
201
+ .sidebar{
202
+ width:236px;
203
+ background:
204
+ linear-gradient(180deg,var(--bg-2) 0,var(--bg) 100%);
205
+ border-right:1px solid var(--border);
206
+ display:flex;flex-direction:column;
207
+ position:fixed;top:0;left:0;bottom:0;z-index:50;
208
+ overflow-y:auto;
209
+ box-shadow:inset -1px 0 0 rgba(158,242,106,.03);
210
+ }
211
+
212
+ .sidebar-logo{
213
+ padding:22px 16px 18px;
214
+ border-bottom:1px solid var(--border);
215
+ position:relative;
216
+ }
217
+ /* phosphor spine running down the logo edge */
218
+ .sidebar-logo::after{
219
+ content:'';position:absolute;left:0;top:14px;bottom:14px;width:2px;
220
+ background:linear-gradient(180deg,var(--phosphor),transparent);
221
+ box-shadow:0 0 6px var(--phosphor-glow);
222
+ }
223
+ .sidebar-logo h1{
224
+ font-family:var(--display);
225
+ font-size:26px;font-weight:400;letter-spacing:-.01em;
226
+ line-height:.95;color:var(--text);
227
+ }
228
+ .sidebar-logo h1 span{
229
+ color:var(--phosphor);
230
+ font-style:italic;
231
+ text-shadow:0 0 12px var(--phosphor-glow);
232
+ }
233
+ .sidebar-logo .ver{
234
+ font-family:var(--mono);
235
+ font-size:9px;color:var(--text3);
236
+ margin-top:6px;letter-spacing:.14em;text-transform:uppercase;
237
+ display:flex;align-items:center;gap:6px;
238
+ }
239
+ .sidebar-logo .ver::before{
240
+ content:'';width:4px;height:4px;background:var(--phosphor);
241
+ border-radius:50%;box-shadow:0 0 6px var(--phosphor-glow);
242
+ animation:pulse-dot 2.2s ease-in-out infinite;
243
+ }
244
+ @keyframes pulse-dot{
245
+ 0%,100%{opacity:1;transform:scale(1)}
246
+ 50%{opacity:.45;transform:scale(.82)}
247
+ }
248
+
249
+ .sidebar-section{padding:14px 16px 6px}
250
+ .sidebar-section-label{
251
+ font-size:10px;font-weight:700;color:var(--text3);
252
+ letter-spacing:.14em;text-transform:uppercase;
253
+ margin-bottom:8px;
254
+ display:flex;align-items:center;gap:6px;
255
+ }
256
+ .sidebar-section-label::after{
257
+ content:'';flex:1;height:1px;background:var(--border);
258
+ }
259
+
260
+ .sidebar select{
261
+ width:100%;padding:8px 10px;
262
+ border-radius:var(--r);
263
+ border:1px solid var(--border);
264
+ background:var(--surface);
265
+ color:var(--text);
266
+ font-family:var(--mono);font-size:11px;
267
+ appearance:auto;cursor:pointer;
268
+ transition:border-color .15s,background .15s;
269
+ }
270
+ .sidebar select:hover{background:var(--surface2);border-color:var(--border-hi)}
271
+ .sidebar select:focus{outline:none;border-color:var(--ui-accent);box-shadow:0 0 0 1px var(--ui-accent-dim)}
272
+
273
+ .nav-item{
274
+ display:flex;align-items:center;gap:10px;
275
+ padding:9px 16px;
276
+ font-size:11px;
277
+ font-family:var(--mono);
278
+ color:var(--text2);
279
+ cursor:pointer;
280
+ border-left:2px solid transparent;
281
+ transition:color .15s,background .15s,border-color .15s;
282
+ text-transform:uppercase;letter-spacing:.12em;
283
+ position:relative;
284
+ }
34
285
  .nav-item:hover{color:var(--text);background:var(--surface2)}
35
- .nav-item.active{color:var(--accent);border-left-color:var(--accent);background:var(--accent-dim)}
36
- .nav-item .icon{width:16px;text-align:center;font-style:normal}
37
- .nav-item .badge{margin-left:auto;background:var(--surface3);color:var(--text2);font-size:10px;padding:1px 6px;border-radius:10px}
38
-
39
- .pool-status{margin-top:auto;padding:16px;border-top:1px solid var(--border)}
40
- .pool-dot{width:7px;height:7px;border-radius:50%;display:inline-block;margin-right:6px}
41
- .pool-dot.on{background:var(--green);box-shadow:0 0 8px var(--green)}
42
- .pool-dot.off{background:var(--red);box-shadow:0 0 8px var(--red)}
43
- .pool-info{font-size:11px;color:var(--text2);line-height:1.7}
44
- .pool-info strong{color:var(--text)}
45
- .ws-dot{width:6px;height:6px;border-radius:50%;display:inline-block;margin-right:4px}
46
- .pool-list{margin-top:6px;display:flex;flex-direction:column;gap:3px}
47
- .pool-item{display:flex;align-items:center;gap:5px;font-size:10px;color:var(--text2);font-family:var(--mono);padding:2px 0}
48
- .pool-item .pool-dot{width:6px;height:6px;margin-right:0}
286
+ .nav-item.active{
287
+ color:var(--ui-accent);
288
+ border-left-color:var(--ui-accent);
289
+ background:linear-gradient(90deg,var(--ui-accent-dim),transparent 70%);
290
+ }
291
+ .nav-item.active::after{
292
+ content:'◂';position:absolute;right:14px;color:var(--ui-accent);font-size:10px;
293
+ }
294
+ .nav-item .icon{
295
+ width:14px;text-align:center;font-style:normal;
296
+ font-size:12px;opacity:.85;
297
+ }
298
+ .nav-item .badge{
299
+ margin-left:auto;
300
+ background:transparent;
301
+ border:1px solid var(--border);
302
+ color:var(--text2);
303
+ font-size:9px;font-weight:600;
304
+ padding:1px 6px;border-radius:999px;
305
+ letter-spacing:.06em;
306
+ font-variant-numeric:tabular-nums;
307
+ }
308
+ .nav-item.active .badge{border-color:var(--ui-accent);color:var(--ui-accent)}
309
+
310
+ /* pool status — a tiny instrument panel */
311
+ .pool-status{
312
+ margin-top:auto;padding:14px 16px 18px;
313
+ border-top:1px solid var(--border);
314
+ background:
315
+ repeating-linear-gradient(180deg,transparent 0 3px,rgba(158,242,106,.015) 3px 4px),
316
+ var(--bg-2);
317
+ font-size:10px;
318
+ }
319
+ .pool-status::before{
320
+ content:'POOL·STATUS';
321
+ display:block;
322
+ font-size:9.5px;font-weight:700;
323
+ color:var(--text3);letter-spacing:.14em;
324
+ margin-bottom:8px;
325
+ }
326
+ .pool-dot{
327
+ width:7px;height:7px;border-radius:50%;
328
+ display:inline-block;margin-right:8px;
329
+ position:relative;flex-shrink:0;
330
+ }
331
+ .pool-dot.on{
332
+ background:var(--phosphor);
333
+ box-shadow:0 0 10px var(--phosphor-glow),0 0 2px var(--phosphor);
334
+ animation:pulse-dot 2s ease-in-out infinite;
335
+ }
336
+ .pool-dot.off{
337
+ background:var(--crimson);
338
+ box-shadow:0 0 10px rgba(255,77,77,.55),0 0 2px var(--crimson);
339
+ }
340
+ .pool-info{
341
+ font-size:10px;color:var(--text2);line-height:1.8;
342
+ display:flex;align-items:center;
343
+ letter-spacing:.04em;
344
+ }
345
+ .pool-info strong{color:var(--text);font-weight:500;font-variant-numeric:tabular-nums}
346
+ .ws-dot{width:6px;height:6px;border-radius:50%;display:inline-block;margin-right:6px}
347
+ .pool-list{margin-top:8px;display:flex;flex-direction:column;gap:4px;padding-left:2px}
348
+ .pool-item{
349
+ display:flex;align-items:center;gap:6px;
350
+ font-size:9px;color:var(--text2);font-family:var(--mono);
351
+ padding:2px 0;letter-spacing:.02em;
352
+ }
353
+ .pool-item .pool-dot{width:5px;height:5px;margin-right:0}
49
354
  .pool-item strong{color:var(--text);font-weight:500}
50
- .pool-item .pool-sessions{margin-left:auto;color:var(--text3);font-size:9px}
355
+ .pool-item .pool-sessions{
356
+ margin-left:auto;color:var(--text3);font-size:9px;
357
+ font-variant-numeric:tabular-nums;
358
+ }
359
+
360
+ /* ═══════════════════ MAIN AREA ═══════════════════ */
51
361
 
52
- /* ── Main ── */
53
- .main{margin-left:232px;flex:1;min-height:100vh;display:flex;flex-direction:column}
54
- .main-header{padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;background:var(--surface);position:sticky;top:0;z-index:40}
55
- .main-header .title{font-family:var(--sans);font-size:16px;font-weight:600}
362
+ .main{
363
+ margin-left:236px;flex:1;min-height:100vh;
364
+ display:flex;flex-direction:column;
365
+ position:relative;
366
+ }
367
+
368
+ .main-header{
369
+ padding:16px 24px;
370
+ border-bottom:1px solid var(--border);
371
+ display:flex;align-items:center;gap:12px;
372
+ background:var(--surface);
373
+ position:sticky;top:0;z-index:40;
374
+ }
375
+ .main-header .title{font-family:var(--display);font-size:22px;font-weight:400}
56
376
  .main-header .actions{margin-left:auto;display:flex;gap:8px}
57
- .view{display:none;padding:24px}
377
+
378
+ .view{display:none;padding:28px 28px 40px;position:relative}
58
379
  .view.active{display:block}
59
- #view-live.active{display:flex;flex-direction:column;flex:1;min-height:calc(100vh - 0px);padding:16px}
60
380
 
61
- /* ── Responsive ── */
381
+ /* each view header — editorial style */
382
+ .view > div:first-child[style*="justify-content:space-between"]{
383
+ position:relative;padding-bottom:14px;margin-bottom:22px!important;
384
+ border-bottom:1px solid var(--border);
385
+ }
386
+ .view > div:first-child[style*="justify-content:space-between"]::before{
387
+ content:'';position:absolute;left:0;right:0;bottom:-1px;height:1px;
388
+ background:linear-gradient(90deg,var(--ui-accent),transparent 35%);
389
+ opacity:.5;
390
+ }
391
+ .view > div:first-child[style*="font-weight:600"],
392
+ .view > div:first-child > div:first-child[style*="font-weight:600"]{
393
+ font-family:var(--display)!important;
394
+ font-size:34px!important;
395
+ font-weight:400!important;
396
+ letter-spacing:-.015em;
397
+ color:var(--text);
398
+ }
399
+
400
+ #view-live.active{display:flex;flex-direction:column;flex:1;min-height:calc(100vh - 0px);padding:20px}
401
+
402
+ /* ═══════════════════ Responsive ═══════════════════ */
62
403
  @media(max-width:768px){
63
- .sidebar{width:60px}.sidebar-logo h1,.sidebar-section-label,.nav-item span:not(.icon):not(.badge),.pool-info,.sidebar select,.sidebar-logo .ver{display:none}
64
- .nav-item{justify-content:center;padding:12px}.nav-item .icon{width:auto}
404
+ .sidebar{width:60px}
405
+ .sidebar-logo h1,.sidebar-section-label,.nav-item span:not(.icon):not(.badge),.pool-info,.sidebar select,.sidebar-logo .ver,.pool-status::before{display:none}
406
+ .nav-item{justify-content:center;padding:12px}
407
+ .nav-item.active::after{display:none}
408
+ .nav-item .icon{width:auto}
65
409
  .main{margin-left:60px}
66
410
  .suite-grid,.gallery,.module-grid{grid-template-columns:1fr}
67
411
  .lr-test-grid{grid-template-columns:1fr}
68
412
  .toast-container{right:12px;bottom:12px}
413
+ .sidebar::before{display:none}
414
+ }
415
+
416
+ /* ═══════════════════ Grouped Sidebar Nav ═══════════════════ */
417
+ .sidebar-nav{display:flex;flex-direction:column;padding-top:4px}
418
+ .nav-group{padding:0 0 4px}
419
+ .nav-group + .nav-group{margin-top:10px}
420
+ .nav-group-label{
421
+ font-size:10px;font-weight:700;color:var(--text3);
422
+ letter-spacing:.16em;text-transform:uppercase;
423
+ padding:8px 16px 6px;
424
+ display:flex;align-items:center;gap:8px;
425
+ position:relative;
426
+ }
427
+ .nav-group-label::before{
428
+ content:'';display:inline-block;width:6px;height:1px;background:var(--border-hi);
429
+ }
430
+ .nav-group-label::after{
431
+ content:'';flex:1;height:1px;background:linear-gradient(90deg,var(--border) 0%,transparent 60%);
432
+ }
433
+ /* Tighter nav rows inside groups */
434
+ .nav-group .nav-item{
435
+ padding:7px 16px 7px 22px;font-size:10.5px;
436
+ letter-spacing:.10em;
437
+ }
438
+ .nav-group .nav-item .icon{font-size:11px;width:13px;opacity:.7}
439
+ .nav-group .nav-item.active .icon{opacity:1}
440
+ .nav-group .nav-item.active::after{font-size:9px;right:12px}
441
+
442
+ /* ═══════════════════ Telemetry Strip ═══════════════════ */
443
+ .topbar-telemetry{
444
+ display:flex;align-items:center;gap:10px;
445
+ justify-self:center;
446
+ padding:0 6px;
447
+ position:relative;
448
+ }
449
+ .tele-pill{
450
+ display:inline-flex;align-items:center;gap:8px;
451
+ padding:5px 10px;
452
+ background:var(--surface);
453
+ border:1px solid var(--border);
454
+ border-radius:var(--r);
455
+ font-family:var(--mono);font-size:10px;
456
+ color:var(--text2);
457
+ letter-spacing:.06em;
458
+ white-space:nowrap;
459
+ transition:border-color .15s,background .15s;
460
+ }
461
+ .tele-pill:hover{border-color:var(--border-hi);background:var(--surface2)}
462
+ .tele-pill-label{
463
+ font-size:8.5px;font-weight:700;
464
+ text-transform:uppercase;letter-spacing:.16em;
465
+ color:var(--text3);
466
+ }
467
+ .tele-pill-value{
468
+ color:var(--text);font-weight:500;
469
+ }
470
+ .tele-pill-num{
471
+ font-variant-numeric:tabular-nums;color:var(--text);
472
+ }
473
+ .tele-pill-dot{
474
+ width:7px;height:7px;border-radius:50%;
475
+ background:var(--text3);flex-shrink:0;
476
+ box-shadow:0 0 0 1px var(--border);
477
+ }
478
+ .tele-pill-dot.on{
479
+ background:var(--phosphor);
480
+ box-shadow:0 0 6px var(--phosphor-glow),0 0 0 1px var(--phosphor);
481
+ }
482
+ .tele-pill-dot.off{
483
+ background:var(--crimson);
484
+ box-shadow:0 0 6px rgba(255,77,77,.4),0 0 0 1px var(--crimson);
485
+ }
486
+ .tele-pill.has-running{border-color:var(--radio);color:var(--text)}
487
+ .tele-pill.has-running .tele-pill-value{color:var(--radio);text-shadow:0 0 8px var(--radio-glow)}
488
+ .tele-pill.has-running .tele-pill-label{color:var(--radio)}
489
+
490
+ @media(max-width:1100px){
491
+ .topbar-telemetry{display:none}
492
+ }
493
+
494
+ /* ═══════════════════ View-header tightening ═══════════════════ */
495
+ /* Editorial display heading sized as an instrument readout title —
496
+ confident but not magazine-cover huge. */
497
+ .view > div:first-child[style*="font-weight:600"],
498
+ .view > div:first-child > div:first-child[style*="font-weight:600"]{
499
+ font-size:26px!important;
500
+ letter-spacing:-.012em;
501
+ line-height:1.05;
502
+ }
503
+ .view > div:first-child[style*="justify-content:space-between"]{
504
+ padding-bottom:12px;margin-bottom:20px!important;
69
505
  }