4bnode 4.1.9 → 4.2.1

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.
@@ -3,49 +3,15 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>4bnode Dashboard</title>
6
+ <title>4bnode</title>
7
+ <meta name="theme-color" content="#0b0b0e" />
7
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
8
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
10
  <link
10
- href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap"
11
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;450;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"
11
12
  rel="stylesheet"
12
13
  />
13
14
  <style>
14
- @font-face {
15
- font-family: "Noto Sans";
16
- src: url("/_dev/assets/fonts/NotoSans-Light.woff2") format("woff2");
17
- font-weight: 300;
18
- font-style: normal;
19
- font-display: swap;
20
- }
21
- @font-face {
22
- font-family: "Noto Sans";
23
- src: url("/_dev/assets/fonts/NotoSans-Regular.woff2") format("woff2");
24
- font-weight: 400;
25
- font-style: normal;
26
- font-display: swap;
27
- }
28
- @font-face {
29
- font-family: "Noto Sans";
30
- src: url("/_dev/assets/fonts/NotoSans-Medium.woff2") format("woff2");
31
- font-weight: 500;
32
- font-style: normal;
33
- font-display: swap;
34
- }
35
- @font-face {
36
- font-family: "Noto Sans";
37
- src: url("/_dev/assets/fonts/NotoSans-SemiBold.woff2") format("woff2");
38
- font-weight: 600;
39
- font-style: normal;
40
- font-display: swap;
41
- }
42
- @font-face {
43
- font-family: "Noto Sans";
44
- src: url("/_dev/assets/fonts/NotoSans-Bold.woff2") format("woff2");
45
- font-weight: 700;
46
- font-style: normal;
47
- font-display: swap;
48
- }
49
15
 
50
16
  *,
51
17
  *::before,
@@ -56,32 +22,47 @@
56
22
  }
57
23
 
58
24
  :root {
59
- --bg: #141720;
60
- --bg-surface: #11141e;
61
- --bg-card: #1a1d2b;
62
- --bg-card-hover: #21253a;
63
- --bg-input: #13161f;
64
- --border: rgba(255, 255, 255, 0.08);
65
- --border-focus: rgba(0, 121, 255, 0.5);
66
- --text: #eceef4;
67
- --text-secondary: #8b8fa3;
68
- --text-muted: #626880;
69
- --accent: #0079ff;
70
- --accent-light: #3daefd;
71
- --accent-glow: rgba(0, 94, 255, 0.18);
72
- --success: #22c55e;
73
- --success-glow: rgba(34, 197, 94, 0.12);
74
- --warning: #f59e0b;
75
- --warning-glow: rgba(245, 158, 11, 0.12);
76
- --error: #ef4444;
77
- --error-glow: rgba(239, 68, 68, 0.12);
78
- --info: #3b82f6;
79
- --info-glow: rgba(59, 130, 246, 0.12);
80
- --radius: 8px;
81
- --radius-lg: 12px;
82
- --radius-xl: 16px;
83
- --sidebar-w: 220px;
84
- --transition: 150ms ease;
25
+ color-scheme: dark;
26
+ /* Surfaces — near-black neutrals, layered by small lightness steps */
27
+ --bg: #0b0b0e;
28
+ --bg-surface: #0e0e12;
29
+ --bg-card: #131318;
30
+ --bg-card-hover: #18181f;
31
+ --bg-input: #0f0f13;
32
+ --bg-elevated: #17171d;
33
+ --card: var(--bg-card);
34
+ --border: rgba(255, 255, 255, 0.07);
35
+ --border-strong: rgba(255, 255, 255, 0.12);
36
+ --border-focus: rgba(91, 140, 255, 0.55);
37
+ /* Ink */
38
+ --text: #ededf0;
39
+ --text-primary: var(--text);
40
+ --text-secondary: #a1a1ab;
41
+ --text-muted: #6c6c78;
42
+ /* One accent */
43
+ --accent: #5b8cff;
44
+ --accent-light: #8fb0ff;
45
+ --accent-glow: rgba(91, 140, 255, 0.14);
46
+ /* Status (reserved for state, never decoration) */
47
+ --success: #3ecf8e;
48
+ --success-glow: rgba(62, 207, 142, 0.12);
49
+ --warning: #f5a524;
50
+ --warning-glow: rgba(245, 165, 36, 0.12);
51
+ --error: #f2555a;
52
+ --error-glow: rgba(242, 85, 90, 0.12);
53
+ --danger: var(--error);
54
+ --info: #5b8cff;
55
+ --info-glow: rgba(91, 140, 255, 0.12);
56
+ --radius: 7px;
57
+ --radius-lg: 10px;
58
+ --radius-xl: 14px;
59
+ --sidebar-w: 236px;
60
+ --sidebar-w-collapsed: 56px;
61
+ --topbar-h: 52px;
62
+ --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
63
+ --mono: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, monospace;
64
+ --shadow-lg: 0 24px 64px -12px rgba(0, 0, 0, 0.6), 0 0 0 1px var(--border);
65
+ --transition: 140ms cubic-bezier(0.2, 0, 0, 1);
85
66
  }
86
67
 
87
68
  html,
@@ -89,16 +70,27 @@
89
70
  height: 100%;
90
71
  }
91
72
  body {
92
- font-family:
93
- "Noto Sans",
94
- -apple-system,
95
- BlinkMacSystemFont,
96
- sans-serif;
73
+ font-family: var(--font);
74
+ font-feature-settings: "cv11", "ss01", "ss03";
75
+ font-size: 13px;
97
76
  background: var(--bg);
98
77
  color: var(--text);
99
78
  overflow: hidden;
100
79
  -webkit-font-smoothing: antialiased;
101
80
  }
81
+ code, pre, kbd, .mono {
82
+ font-family: var(--mono);
83
+ }
84
+ ::selection {
85
+ background: rgba(91, 140, 255, 0.3);
86
+ }
87
+ :focus-visible {
88
+ outline: 2px solid var(--border-focus);
89
+ outline-offset: 1px;
90
+ }
91
+ button {
92
+ font-family: inherit;
93
+ }
102
94
 
103
95
  #root {
104
96
  display: flex;
@@ -107,17 +99,37 @@
107
99
 
108
100
  /* ── Scrollbar ── */
109
101
  ::-webkit-scrollbar {
110
- width: 6px;
102
+ width: 8px;
103
+ height: 8px;
111
104
  }
112
105
  ::-webkit-scrollbar-track {
113
106
  background: transparent;
114
107
  }
115
108
  ::-webkit-scrollbar-thumb {
116
- background: rgba(255, 255, 255, 0.08);
117
- border-radius: 3px;
109
+ background: rgba(255, 255, 255, 0.07);
110
+ border-radius: 8px;
111
+ border: 2px solid transparent;
112
+ background-clip: padding-box;
118
113
  }
119
114
  ::-webkit-scrollbar-thumb:hover {
120
115
  background: rgba(255, 255, 255, 0.14);
116
+ background-clip: padding-box;
117
+ }
118
+
119
+ kbd {
120
+ display: inline-flex;
121
+ align-items: center;
122
+ justify-content: center;
123
+ min-width: 18px;
124
+ height: 18px;
125
+ padding: 0 5px;
126
+ font-size: 10.5px;
127
+ font-weight: 500;
128
+ color: var(--text-muted);
129
+ background: rgba(255, 255, 255, 0.04);
130
+ border: 1px solid var(--border);
131
+ border-radius: 4px;
132
+ line-height: 1;
121
133
  }
122
134
 
123
135
  /* ── Sidebar ── */
@@ -128,75 +140,116 @@
128
140
  display: flex;
129
141
  flex-direction: column;
130
142
  flex-shrink: 0;
131
- padding: 0 0 16px;
132
- overflow-y: auto;
143
+ transition: width 180ms cubic-bezier(0.2, 0, 0, 1);
144
+ overflow: hidden;
145
+ z-index: 40;
133
146
  }
134
147
  .sidebar-brand {
135
- height: 61px;
148
+ height: var(--topbar-h);
136
149
  display: flex;
137
150
  align-items: center;
138
- padding: 0 20px;
139
- border-bottom: 1px solid var(--border);
140
- margin-bottom: 8px;
151
+ gap: 10px;
152
+ padding: 0 14px;
141
153
  flex-shrink: 0;
142
154
  }
143
- .sidebar-brand pre {
144
- font-family: monospace;
145
- font-size: 4px;
146
- line-height: 1.1;
147
- letter-spacing: 0.5px;
148
- background: linear-gradient(135deg, #3daefd, #0079ff, #005eff);
149
- -webkit-background-clip: text;
150
- -webkit-text-fill-color: transparent;
151
- margin: 0 0 0 -2px;
152
- white-space: pre;
153
- user-select: none;
155
+ .brand-mark {
156
+ width: 28px;
157
+ height: 28px;
158
+ flex-shrink: 0;
159
+ border-radius: 7px;
160
+ display: grid;
161
+ place-items: center;
162
+ font-size: 12px;
163
+ font-weight: 700;
164
+ letter-spacing: -0.5px;
165
+ color: #fff;
166
+ background: linear-gradient(140deg, #8fb0ff 0%, #5b8cff 45%, #3a5fd9 100%);
167
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.4);
168
+ }
169
+ .brand-text {
170
+ display: flex;
171
+ flex-direction: column;
172
+ min-width: 0;
173
+ line-height: 1.2;
174
+ }
175
+ .brand-name {
176
+ font-size: 13.5px;
177
+ font-weight: 600;
178
+ letter-spacing: -0.2px;
154
179
  }
155
- .sidebar-brand span {
180
+ .brand-app {
156
181
  font-size: 11px;
157
182
  color: var(--text-muted);
158
- font-weight: 400;
183
+ white-space: nowrap;
184
+ overflow: hidden;
185
+ text-overflow: ellipsis;
186
+ }
187
+ .sidebar-search {
188
+ display: flex;
189
+ align-items: center;
190
+ gap: 10px;
191
+ margin: 4px 10px 6px;
192
+ padding: 0 8px;
193
+ height: 32px;
194
+ border-radius: var(--radius);
195
+ border: 1px solid var(--border);
196
+ background: rgba(255, 255, 255, 0.02);
197
+ color: var(--text-muted);
198
+ font-size: 12.5px;
199
+ cursor: pointer;
200
+ transition: all var(--transition);
201
+ white-space: nowrap;
202
+ }
203
+ .sidebar-search:hover {
204
+ border-color: var(--border-strong);
205
+ color: var(--text-secondary);
206
+ }
207
+ .sidebar-search .sidebar-label {
208
+ flex: 1;
209
+ text-align: left;
210
+ }
211
+ .sidebar-nav {
212
+ flex: 1;
213
+ overflow-y: auto;
214
+ overflow-x: hidden;
215
+ padding: 2px 0 12px;
159
216
  }
160
217
  .sidebar-section {
161
- padding: 12px 12px 4px;
162
- font-size: 10px;
163
- font-weight: 600;
218
+ padding: 14px 18px 4px;
219
+ font-size: 11px;
220
+ font-weight: 500;
164
221
  color: var(--text-muted);
165
- text-transform: uppercase;
166
- letter-spacing: 1px;
222
+ white-space: nowrap;
223
+ height: 33px;
167
224
  }
168
225
  .sidebar-item {
169
226
  display: flex;
170
227
  align-items: center;
171
228
  gap: 10px;
172
- padding: 9px 16px;
173
- margin: 1px 8px;
229
+ width: calc(100% - 20px);
230
+ height: 30px;
231
+ padding: 0 8px;
232
+ margin: 1px 10px;
233
+ border: none;
234
+ background: transparent;
174
235
  border-radius: var(--radius);
175
236
  font-size: 13px;
176
- font-weight: 500;
237
+ font-weight: 450;
177
238
  color: var(--text-secondary);
178
239
  cursor: pointer;
179
- transition: all var(--transition);
240
+ transition: background var(--transition), color var(--transition);
180
241
  position: relative;
242
+ text-align: left;
243
+ white-space: nowrap;
181
244
  }
182
245
  .sidebar-item:hover {
183
246
  background: rgba(255, 255, 255, 0.04);
184
247
  color: var(--text);
185
248
  }
186
249
  .sidebar-item.active {
187
- background: rgba(255, 255, 255, 0.06);
188
- color: #f0f1f5;
189
- }
190
- .sidebar-item.active::before {
191
- content: "";
192
- position: absolute;
193
- left: -8px;
194
- top: 50%;
195
- transform: translateY(-50%);
196
- width: 3px;
197
- height: 16px;
198
- border-radius: 0 3px 3px 0;
199
- background: var(--accent-light);
250
+ background: rgba(255, 255, 255, 0.07);
251
+ color: var(--text);
252
+ font-weight: 500;
200
253
  }
201
254
  .sidebar-item.active .sidebar-icon {
202
255
  color: var(--accent-light);
@@ -206,9 +259,8 @@
206
259
  cursor: not-allowed;
207
260
  }
208
261
  .sidebar-item .lock-icon {
209
- position: absolute;
210
- right: 12px;
211
- font-size: 10px;
262
+ margin-left: auto;
263
+ display: flex;
212
264
  opacity: 0.6;
213
265
  }
214
266
  .sidebar-icon {
@@ -222,8 +274,100 @@
222
274
  .sidebar-icon svg {
223
275
  width: 16px;
224
276
  height: 16px;
225
- stroke: currentColor;
226
- fill: none;
277
+ }
278
+ .sidebar-label {
279
+ overflow: hidden;
280
+ text-overflow: ellipsis;
281
+ transition: opacity var(--transition);
282
+ }
283
+ .sidebar-kbd {
284
+ transition: opacity var(--transition);
285
+ }
286
+ .sidebar-footer {
287
+ display: flex;
288
+ align-items: center;
289
+ gap: 6px;
290
+ padding: 10px 10px 10px 14px;
291
+ border-top: 1px solid var(--border);
292
+ flex-shrink: 0;
293
+ }
294
+ .sidebar-status {
295
+ flex: 1;
296
+ display: flex;
297
+ align-items: center;
298
+ gap: 9px;
299
+ min-width: 0;
300
+ font-size: 11.5px;
301
+ color: var(--text-muted);
302
+ white-space: nowrap;
303
+ }
304
+ .sidebar-collapse {
305
+ width: 28px;
306
+ height: 28px;
307
+ display: grid;
308
+ place-items: center;
309
+ border: none;
310
+ background: transparent;
311
+ color: var(--text-muted);
312
+ border-radius: var(--radius);
313
+ cursor: pointer;
314
+ flex-shrink: 0;
315
+ }
316
+ .sidebar-collapse:hover {
317
+ background: rgba(255, 255, 255, 0.05);
318
+ color: var(--text);
319
+ }
320
+ .status-dot {
321
+ width: 7px;
322
+ height: 7px;
323
+ border-radius: 50%;
324
+ flex-shrink: 0;
325
+ background: var(--text-muted);
326
+ }
327
+ .status-dot.on,
328
+ .live-pill.on .status-dot {
329
+ background: var(--success);
330
+ box-shadow: 0 0 0 3px var(--success-glow);
331
+ }
332
+ .status-dot.off,
333
+ .live-pill.off .status-dot {
334
+ background: var(--error);
335
+ }
336
+
337
+ /* Collapsed (icon rail) */
338
+ .sidebar.collapsed {
339
+ width: var(--sidebar-w-collapsed);
340
+ }
341
+ .sidebar.collapsed .brand-text,
342
+ .sidebar.collapsed .sidebar-label,
343
+ .sidebar.collapsed .sidebar-kbd,
344
+ .sidebar.collapsed .lock-icon {
345
+ opacity: 0;
346
+ pointer-events: none;
347
+ }
348
+ .sidebar.collapsed .sidebar-section span {
349
+ visibility: hidden;
350
+ }
351
+ .sidebar.collapsed .sidebar-section::after {
352
+ content: "";
353
+ display: block;
354
+ height: 1px;
355
+ margin: -6px 4px 0;
356
+ background: var(--border);
357
+ }
358
+ .sidebar.collapsed .sidebar-search {
359
+ border-color: transparent;
360
+ background: transparent;
361
+ }
362
+ .sidebar.collapsed .sidebar-footer {
363
+ justify-content: center;
364
+ padding: 10px 0;
365
+ }
366
+ .sidebar.collapsed .sidebar-status {
367
+ display: none;
368
+ }
369
+ .sidebar-scrim {
370
+ display: none;
227
371
  }
228
372
 
229
373
  /* ── Main Area ── */
@@ -232,33 +376,113 @@
232
376
  display: flex;
233
377
  flex-direction: column;
234
378
  overflow: hidden;
379
+ min-width: 0;
235
380
  }
236
381
  .topbar {
237
- height: 61px;
382
+ height: var(--topbar-h);
238
383
  display: flex;
239
384
  align-items: center;
240
- justify-content: space-between;
241
- padding: 0 28px;
242
- background: var(--bg-surface);
385
+ gap: 12px;
386
+ padding: 0 20px 0 24px;
243
387
  border-bottom: 1px solid var(--border);
244
388
  flex-shrink: 0;
389
+ background: var(--bg);
390
+ }
391
+ .topbar-menu {
392
+ display: none;
393
+ border: none;
394
+ background: transparent;
395
+ color: var(--text-secondary);
396
+ padding: 6px;
397
+ margin-left: -6px;
398
+ border-radius: var(--radius);
399
+ cursor: pointer;
400
+ }
401
+ .topbar-crumbs {
402
+ display: flex;
403
+ align-items: center;
404
+ gap: 8px;
405
+ min-width: 0;
406
+ font-size: 13px;
407
+ }
408
+ .crumb-muted {
409
+ color: var(--text-muted);
410
+ white-space: nowrap;
411
+ }
412
+ .crumb-sep {
413
+ color: var(--text-muted);
414
+ opacity: 0.5;
245
415
  }
246
416
  .topbar h2 {
247
- font-size: 16px;
248
- font-weight: 600;
417
+ font-size: 13px;
418
+ font-weight: 500;
419
+ white-space: nowrap;
420
+ overflow: hidden;
421
+ text-overflow: ellipsis;
249
422
  }
250
- .topbar-badge {
251
- font-size: 11px;
252
- padding: 3px 10px;
253
- border-radius: 20px;
254
- background: var(--accent-glow);
255
- color: var(--accent-light);
423
+ .topbar-actions {
424
+ margin-left: auto;
425
+ display: flex;
426
+ align-items: center;
427
+ gap: 6px;
428
+ }
429
+ .topbar-search {
430
+ display: flex;
431
+ align-items: center;
432
+ gap: 8px;
433
+ height: 30px;
434
+ width: 260px;
435
+ padding: 0 6px 0 10px;
436
+ border: 1px solid var(--border);
437
+ border-radius: var(--radius);
438
+ background: rgba(255, 255, 255, 0.02);
439
+ color: var(--text-muted);
440
+ font-size: 12.5px;
441
+ cursor: pointer;
442
+ transition: all var(--transition);
443
+ }
444
+ .topbar-search span {
445
+ flex: 1;
446
+ text-align: left;
447
+ }
448
+ .topbar-search:hover {
449
+ border-color: var(--border-strong);
450
+ color: var(--text-secondary);
451
+ }
452
+ .live-pill {
453
+ display: inline-flex;
454
+ align-items: center;
455
+ gap: 7px;
456
+ height: 26px;
457
+ padding: 0 10px;
458
+ margin: 0 4px;
459
+ border-radius: 999px;
460
+ border: 1px solid var(--border);
461
+ font-size: 11.5px;
256
462
  font-weight: 500;
463
+ color: var(--text-secondary);
464
+ }
465
+ .btn-icon-ghost {
466
+ width: 30px;
467
+ height: 30px;
468
+ display: grid;
469
+ place-items: center;
470
+ border: none;
471
+ background: transparent;
472
+ color: var(--text-muted);
473
+ border-radius: var(--radius);
474
+ cursor: pointer;
475
+ text-decoration: none;
476
+ transition: all var(--transition);
477
+ }
478
+ .btn-icon-ghost:hover {
479
+ background: rgba(255, 255, 255, 0.05);
480
+ color: var(--text);
257
481
  }
258
482
  .content {
259
483
  flex: 1;
260
484
  overflow-y: auto;
261
- padding: 28px;
485
+ padding: 24px 28px 48px;
262
486
  }
263
487
 
264
488
  /* ── Cards ── */
@@ -266,21 +490,20 @@
266
490
  background: var(--bg-card);
267
491
  border: 1px solid var(--border);
268
492
  border-radius: var(--radius-lg);
269
- padding: 20px;
270
- transition: all var(--transition);
271
- }
272
- .card:hover {
273
- border-color: rgba(255, 255, 255, 0.1);
493
+ padding: 18px;
494
+ transition: border-color var(--transition), background var(--transition);
274
495
  }
275
496
  .card-header {
276
497
  display: flex;
277
498
  align-items: center;
278
499
  justify-content: space-between;
279
- margin-bottom: 16px;
500
+ gap: 12px;
501
+ margin-bottom: 14px;
280
502
  }
281
503
  .card-title {
282
- font-size: 14px;
504
+ font-size: 13px;
283
505
  font-weight: 600;
506
+ letter-spacing: -0.1px;
284
507
  }
285
508
  .card-subtitle {
286
509
  font-size: 12px;
@@ -292,17 +515,17 @@
292
515
  .stats-grid {
293
516
  display: grid;
294
517
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
295
- gap: 16px;
296
- margin-bottom: 24px;
518
+ gap: 12px;
519
+ margin-bottom: 20px;
297
520
  }
298
521
  .stat-card {
299
522
  background: var(--bg-card);
300
523
  border: 1px solid var(--border);
301
524
  border-radius: var(--radius-lg);
302
- padding: 18px 20px;
525
+ padding: 14px 16px;
303
526
  display: flex;
304
527
  flex-direction: column;
305
- gap: 8px;
528
+ gap: 6px;
306
529
  }
307
530
  .stat-card .stat-label {
308
531
  font-size: 12px;
@@ -310,9 +533,10 @@
310
533
  font-weight: 500;
311
534
  }
312
535
  .stat-card .stat-value {
313
- font-size: 28px;
314
- font-weight: 700;
315
- letter-spacing: -1px;
536
+ font-size: 24px;
537
+ font-weight: 600;
538
+ letter-spacing: -0.6px;
539
+ font-variant-numeric: tabular-nums;
316
540
  }
317
541
  .stat-card .stat-badge {
318
542
  display: inline-flex;
@@ -321,7 +545,7 @@
321
545
  font-size: 11px;
322
546
  font-weight: 500;
323
547
  padding: 2px 8px;
324
- border-radius: 20px;
548
+ border-radius: 999px;
325
549
  width: fit-content;
326
550
  }
327
551
  .stat-badge.success {
@@ -345,65 +569,70 @@
345
569
  .btn {
346
570
  display: inline-flex;
347
571
  align-items: center;
572
+ justify-content: center;
348
573
  gap: 6px;
349
- padding: 8px 16px;
574
+ height: 32px;
575
+ padding: 0 12px;
350
576
  border-radius: var(--radius);
351
577
  font-size: 13px;
352
578
  font-weight: 500;
353
579
  font-family: inherit;
354
- border: none;
580
+ border: 1px solid transparent;
355
581
  cursor: pointer;
356
- transition: all var(--transition);
582
+ transition: background var(--transition), border-color var(--transition), color var(--transition), box-shadow var(--transition);
357
583
  white-space: nowrap;
584
+ text-decoration: none;
358
585
  }
359
586
  .btn:disabled {
360
- opacity: 0.5;
587
+ opacity: 0.45;
361
588
  cursor: not-allowed;
362
589
  }
363
590
  .btn-primary {
364
591
  background: var(--accent);
365
- color: white;
366
- box-shadow: 0 0 20px var(--accent-glow);
592
+ color: #fff;
593
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 1px 2px rgba(0, 0, 0, 0.35);
367
594
  }
368
595
  .btn-primary:hover:not(:disabled) {
369
- background: var(--accent-light);
596
+ background: #6f9aff;
370
597
  }
371
598
  .btn-secondary {
372
- background: rgba(255, 255, 255, 0.06);
599
+ background: rgba(255, 255, 255, 0.05);
373
600
  color: var(--text);
374
- border: 1px solid var(--border);
601
+ border-color: var(--border);
375
602
  }
376
603
  .btn-secondary:hover:not(:disabled) {
377
- background: rgba(255, 255, 255, 0.1);
378
- border-color: rgba(255, 255, 255, 0.12);
604
+ background: rgba(255, 255, 255, 0.08);
605
+ border-color: var(--border-strong);
379
606
  }
380
607
  .btn-ghost {
381
608
  background: transparent;
382
609
  color: var(--text-secondary);
383
610
  }
384
611
  .btn-ghost:hover:not(:disabled) {
385
- background: rgba(255, 255, 255, 0.04);
612
+ background: rgba(255, 255, 255, 0.05);
386
613
  color: var(--text);
387
614
  }
388
615
  .btn-danger {
389
616
  background: var(--error-glow);
390
617
  color: var(--error);
391
- border: 1px solid rgba(239, 68, 68, 0.2);
618
+ border-color: rgba(242, 85, 90, 0.22);
392
619
  }
393
620
  .btn-danger:hover:not(:disabled) {
394
- background: rgba(239, 68, 68, 0.2);
621
+ background: rgba(242, 85, 90, 0.2);
395
622
  }
396
623
  .btn-sm {
397
- padding: 5px 10px;
624
+ height: 26px;
625
+ padding: 0 9px;
398
626
  font-size: 12px;
399
627
  }
400
628
  .btn-icon {
401
- padding: 6px;
629
+ width: 32px;
630
+ padding: 0;
402
631
  }
403
632
 
404
633
  /* ── Form elements ── */
405
634
  .form-group {
406
- margin-bottom: 16px;
635
+ margin-bottom: 14px;
407
636
  }
408
637
  .form-label {
409
638
  display: block;
@@ -415,7 +644,8 @@
415
644
  .form-input,
416
645
  .form-select {
417
646
  width: 100%;
418
- padding: 9px 12px;
647
+ height: 34px;
648
+ padding: 0 11px;
419
649
  background: var(--bg-input);
420
650
  border: 1px solid var(--border);
421
651
  border-radius: var(--radius);
@@ -423,23 +653,32 @@
423
653
  font-size: 13px;
424
654
  font-family: inherit;
425
655
  outline: none;
426
- transition: border-color var(--transition);
656
+ transition: border-color var(--transition), box-shadow var(--transition);
657
+ }
658
+ textarea.form-input {
659
+ height: auto;
660
+ padding: 9px 11px;
661
+ }
662
+ .form-input:hover,
663
+ .form-select:hover {
664
+ border-color: var(--border-strong);
427
665
  }
428
666
  .form-input:focus,
429
667
  .form-select:focus {
430
668
  border-color: var(--border-focus);
669
+ box-shadow: 0 0 0 3px var(--accent-glow);
431
670
  }
432
671
  .form-input::placeholder {
433
672
  color: var(--text-muted);
434
673
  }
435
674
  .form-select option {
436
- background: var(--bg-card);
675
+ background: var(--bg-elevated);
437
676
  }
438
677
 
439
678
  .form-toggle {
440
679
  position: relative;
441
- width: 36px;
442
- height: 20px;
680
+ width: 32px;
681
+ height: 18px;
443
682
  display: inline-block;
444
683
  }
445
684
  .form-toggle input {
@@ -451,8 +690,8 @@
451
690
  position: absolute;
452
691
  cursor: pointer;
453
692
  inset: 0;
454
- background: rgba(255, 255, 255, 0.1);
455
- border-radius: 20px;
693
+ background: rgba(255, 255, 255, 0.12);
694
+ border-radius: 999px;
456
695
  transition: var(--transition);
457
696
  }
458
697
  .form-toggle .slider::before {
@@ -460,33 +699,34 @@
460
699
  position: absolute;
461
700
  width: 14px;
462
701
  height: 14px;
463
- left: 3px;
464
- bottom: 3px;
702
+ left: 2px;
703
+ bottom: 2px;
465
704
  background: white;
466
705
  border-radius: 50%;
706
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
467
707
  transition: var(--transition);
468
708
  }
469
709
  .form-toggle input:checked + .slider {
470
710
  background: var(--accent);
471
711
  }
472
712
  .form-toggle input:checked + .slider::before {
473
- transform: translateX(16px);
713
+ transform: translateX(14px);
474
714
  }
475
715
 
476
716
  /* ── Grid layouts ── */
477
717
  .grid-2 {
478
718
  display: grid;
479
- grid-template-columns: 1fr 1fr;
480
- gap: 16px;
719
+ grid-template-columns: repeat(2, minmax(0, 1fr));
720
+ gap: 14px;
481
721
  }
482
722
  .grid-3 {
483
723
  display: grid;
484
- grid-template-columns: repeat(3, 1fr);
485
- gap: 16px;
724
+ grid-template-columns: repeat(3, minmax(0, 1fr));
725
+ gap: 14px;
486
726
  }
487
727
  .grid-4 {
488
728
  display: grid;
489
- grid-template-columns: repeat(4, 1fr);
729
+ grid-template-columns: repeat(4, minmax(0, 1fr));
490
730
  gap: 12px;
491
731
  }
492
732
 
@@ -497,10 +737,12 @@
497
737
  gap: 4px;
498
738
  font-size: 11px;
499
739
  font-weight: 500;
500
- padding: 3px 8px;
501
- border-radius: 20px;
502
- background: rgba(255, 255, 255, 0.07);
740
+ height: 20px;
741
+ padding: 0 7px;
742
+ border-radius: 999px;
743
+ background: rgba(255, 255, 255, 0.06);
503
744
  color: var(--text-secondary);
745
+ white-space: nowrap;
504
746
  }
505
747
  .badge-success {
506
748
  background: var(--success-glow);
@@ -519,7 +761,7 @@
519
761
  color: var(--info);
520
762
  }
521
763
  .badge-muted {
522
- background: rgba(255, 255, 255, 0.05);
764
+ background: rgba(255, 255, 255, 0.04);
523
765
  color: var(--text-muted);
524
766
  }
525
767
 
@@ -801,7 +1043,7 @@
801
1043
  background: rgba(255, 255, 255, 0.02);
802
1044
  }
803
1045
  .route-item.active {
804
- background: var(--accent-glow);
1046
+ background: rgba(255, 255, 255, 0.04);
805
1047
  border-left-color: var(--accent);
806
1048
  }
807
1049
  .route-item .ri-name {
@@ -819,33 +1061,33 @@
819
1061
  letter-spacing: 0.5px;
820
1062
  padding: 2px 7px;
821
1063
  border-radius: 3px;
822
- font-family: "SF Mono", "Fira Code", monospace;
1064
+ font-family: var(--mono);
823
1065
  text-align: center;
824
1066
  display: inline-block;
825
1067
  }
826
1068
  .route-method.get {
827
- background: rgba(34, 197, 94, 0.15);
828
- color: #22c55e;
1069
+ background: rgba(62, 207, 142, 0.12);
1070
+ color: #3ecf8e;
829
1071
  }
830
1072
  .route-method.post {
831
- background: rgba(59, 130, 246, 0.15);
832
- color: #3b82f6;
1073
+ background: rgba(91, 140, 255, 0.14);
1074
+ color: #8fb0ff;
833
1075
  }
834
1076
  .route-method.put {
835
- background: rgba(245, 158, 11, 0.15);
836
- color: #f59e0b;
1077
+ background: rgba(245, 165, 36, 0.13);
1078
+ color: #f5a524;
837
1079
  }
838
1080
  .route-method.patch {
839
- background: rgba(168, 85, 247, 0.15);
840
- color: #a855f7;
1081
+ background: rgba(180, 140, 255, 0.14);
1082
+ color: #b48cff;
841
1083
  }
842
1084
  .route-method.delete {
843
- background: rgba(239, 68, 68, 0.15);
844
- color: #ef4444;
1085
+ background: rgba(242, 85, 90, 0.13);
1086
+ color: #f2555a;
845
1087
  }
846
1088
  .route-method.multi {
847
- background: rgba(0, 94, 255, 0.15);
848
- color: #3daefd;
1089
+ background: var(--accent-glow);
1090
+ color: var(--accent-light);
849
1091
  }
850
1092
  .route-endpoint-row {
851
1093
  display: flex;
@@ -859,7 +1101,7 @@
859
1101
  border-bottom: none;
860
1102
  }
861
1103
  .route-endpoint-path {
862
- font-family: "SF Mono", "Fira Code", monospace;
1104
+ font-family: var(--mono);
863
1105
  font-size: 12px;
864
1106
  color: var(--text-secondary);
865
1107
  }
@@ -885,7 +1127,8 @@
885
1127
  margin-bottom: 16px;
886
1128
  }
887
1129
  .api-tester-method {
888
- padding: 8px 12px;
1130
+ height: 36px;
1131
+ padding: 0 10px;
889
1132
  border: 1px solid var(--border);
890
1133
  border-radius: var(--radius);
891
1134
  background: var(--bg-input);
@@ -898,24 +1141,29 @@
898
1141
  }
899
1142
  .api-tester-url {
900
1143
  flex: 1;
901
- padding: 8px 14px;
1144
+ min-width: 0;
1145
+ height: 36px;
1146
+ padding: 0 12px;
902
1147
  border: 1px solid var(--border);
903
1148
  border-radius: var(--radius);
904
1149
  background: var(--bg-input);
905
1150
  color: var(--text-primary);
906
- font-family: 'SF Mono', 'Fira Code', monospace;
1151
+ font-family: var(--mono);
907
1152
  font-size: 13px;
908
1153
  outline: none;
909
1154
  transition: border-color 0.15s;
910
1155
  }
911
1156
  .api-tester-url:focus {
912
- border-color: var(--accent);
1157
+ border-color: var(--border-focus);
1158
+ box-shadow: 0 0 0 3px var(--accent-glow);
913
1159
  }
914
1160
  .api-tester-url::placeholder {
915
1161
  color: var(--text-muted);
916
1162
  }
917
1163
  .api-tester-send {
918
- padding: 8px 20px;
1164
+ height: 36px;
1165
+ padding: 0 14px;
1166
+ white-space: nowrap;
919
1167
  border: none;
920
1168
  border-radius: var(--radius);
921
1169
  background: var(--accent);
@@ -967,7 +1215,7 @@
967
1215
  padding: 14px;
968
1216
  border: none;
969
1217
  outline: none;
970
- font-family: 'SF Mono', 'Fira Code', monospace;
1218
+ font-family: var(--mono);
971
1219
  font-size: 12px;
972
1220
  line-height: 1.6;
973
1221
  background: var(--bg-card);
@@ -990,7 +1238,7 @@
990
1238
  background: var(--bg-input);
991
1239
  color: var(--text-primary);
992
1240
  font-size: 12px;
993
- font-family: 'SF Mono', monospace;
1241
+ font-family: var(--mono);
994
1242
  outline: none;
995
1243
  }
996
1244
  .api-tester-kv-row input:focus {
@@ -1003,7 +1251,7 @@
1003
1251
  border-radius: 4px;
1004
1252
  font-size: 12px;
1005
1253
  font-weight: 600;
1006
- font-family: 'SF Mono', monospace;
1254
+ font-family: var(--mono);
1007
1255
  }
1008
1256
  .api-tester-status.s2xx { background: rgba(52,211,153,0.12); color: var(--success); }
1009
1257
  .api-tester-status.s3xx { background: rgba(96,165,250,0.12); color: #60a5fa; }
@@ -1012,7 +1260,7 @@
1012
1260
  .api-tester-status.s0xx { background: rgba(248,113,113,0.12); color: var(--danger); }
1013
1261
  .api-tester-response-body {
1014
1262
  padding: 14px;
1015
- font-family: 'SF Mono', 'Fira Code', monospace;
1263
+ font-family: var(--mono);
1016
1264
  font-size: 12px;
1017
1265
  line-height: 1.6;
1018
1266
  white-space: pre-wrap;
@@ -1067,7 +1315,7 @@
1067
1315
  .ws-log {
1068
1316
  max-height: 350px;
1069
1317
  overflow-y: auto;
1070
- font-family: 'SF Mono', 'Fira Code', monospace;
1318
+ font-family: var(--mono);
1071
1319
  font-size: 12px;
1072
1320
  line-height: 1.6;
1073
1321
  }
@@ -1190,7 +1438,7 @@
1190
1438
  /* ── Toast ── */
1191
1439
  .toast-container {
1192
1440
  position: fixed;
1193
- top: 16px;
1441
+ bottom: 16px;
1194
1442
  right: 16px;
1195
1443
  z-index: 1000;
1196
1444
  display: flex;
@@ -1198,24 +1446,32 @@
1198
1446
  gap: 8px;
1199
1447
  }
1200
1448
  .toast {
1201
- padding: 12px 16px;
1202
- border-radius: var(--radius);
1449
+ display: flex;
1450
+ align-items: center;
1451
+ gap: 10px;
1452
+ padding: 11px 14px;
1453
+ border-radius: var(--radius-lg);
1203
1454
  font-size: 13px;
1204
1455
  font-weight: 500;
1205
- background: var(--bg-card);
1206
- border: 1px solid var(--border);
1207
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
1456
+ background: var(--bg-elevated);
1457
+ border: 1px solid var(--border-strong);
1458
+ box-shadow: var(--shadow-lg);
1208
1459
  animation: slideIn 0.2s ease;
1209
1460
  max-width: 400px;
1210
1461
  }
1211
- .toast.success {
1212
- border-left: 3px solid var(--success);
1462
+ .toast::before {
1463
+ content: "";
1464
+ width: 7px;
1465
+ height: 7px;
1466
+ border-radius: 50%;
1467
+ flex-shrink: 0;
1468
+ background: var(--info);
1213
1469
  }
1214
- .toast.error {
1215
- border-left: 3px solid var(--error);
1470
+ .toast.success::before {
1471
+ background: var(--success);
1216
1472
  }
1217
- .toast.info {
1218
- border-left: 3px solid var(--info);
1473
+ .toast.error::before {
1474
+ background: var(--error);
1219
1475
  }
1220
1476
 
1221
1477
  @keyframes slideIn {
@@ -1233,8 +1489,8 @@
1233
1489
  .modal-overlay {
1234
1490
  position: fixed;
1235
1491
  inset: 0;
1236
- background: rgba(0, 0, 0, 0.6);
1237
- backdrop-filter: blur(4px);
1492
+ background: rgba(0, 0, 0, 0.55);
1493
+ backdrop-filter: blur(2px);
1238
1494
  display: flex;
1239
1495
  align-items: center;
1240
1496
  justify-content: center;
@@ -1246,11 +1502,12 @@
1246
1502
  border: 1px solid var(--border);
1247
1503
  border-radius: var(--radius-xl);
1248
1504
  padding: 24px;
1249
- min-width: 420px;
1250
- max-width: 560px;
1251
- max-height: 80vh;
1505
+ min-width: min(420px, calc(100vw - 32px));
1506
+ max-width: min(560px, calc(100vw - 32px));
1507
+ max-height: 85vh;
1252
1508
  overflow-y: auto;
1253
- box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
1509
+ background: var(--bg-elevated);
1510
+ box-shadow: var(--shadow-lg);
1254
1511
  animation: scaleIn 0.15s ease;
1255
1512
  }
1256
1513
  .modal-title {
@@ -1286,11 +1543,11 @@
1286
1543
 
1287
1544
  /* ── Code block ── */
1288
1545
  .code-block {
1289
- background: #11141e;
1546
+ background: var(--bg-input);
1290
1547
  border: 1px solid var(--border);
1291
1548
  border-radius: var(--radius);
1292
- padding: 16px;
1293
- font-family: "SF Mono", "Fira Code", monospace;
1549
+ padding: 14px 16px;
1550
+ font-family: var(--mono);
1294
1551
  font-size: 12px;
1295
1552
  line-height: 1.6;
1296
1553
  overflow-x: auto;
@@ -1408,7 +1665,7 @@
1408
1665
  border: 1px solid var(--border);
1409
1666
  border-radius: var(--radius);
1410
1667
  color: var(--text-primary);
1411
- font-family: "SF Mono", "Fira Code", "Cascadia Code", monospace;
1668
+ font-family: var(--mono);
1412
1669
  font-size: 13px;
1413
1670
  line-height: 1.6;
1414
1671
  padding: 14px 16px;
@@ -1437,14 +1694,14 @@
1437
1694
  line-height: 1.15;
1438
1695
  letter-spacing: 1px;
1439
1696
  white-space: pre;
1440
- background: linear-gradient(135deg, #3daefd, #0079ff, #005eff);
1697
+ background: linear-gradient(140deg, #8fb0ff, #5b8cff, #3a5fd9);
1441
1698
  -webkit-background-clip: text;
1442
1699
  -webkit-text-fill-color: transparent;
1443
1700
  user-select: none;
1444
1701
  text-align: center;
1445
1702
  }
1446
1703
  .splash-tagline {
1447
- font-family: "Noto Sans", sans-serif;
1704
+ font-family: var(--font);
1448
1705
  font-size: 16px;
1449
1706
  font-weight: 400;
1450
1707
  color: var(--text-secondary);
@@ -1454,14 +1711,14 @@
1454
1711
  .splash-company {
1455
1712
  position: absolute;
1456
1713
  bottom: 36px;
1457
- font-family: "Noto Sans", sans-serif;
1714
+ font-family: var(--font);
1458
1715
  font-size: 12px;
1459
1716
  color: var(--text-muted);
1460
1717
  letter-spacing: 0.3px;
1461
1718
  }
1462
1719
  .splash-company span {
1463
1720
  font-weight: 600;
1464
- background: linear-gradient(135deg, #3daefd, #005eff);
1721
+ background: linear-gradient(140deg, #8fb0ff, #3a5fd9);
1465
1722
  -webkit-background-clip: text;
1466
1723
  -webkit-text-fill-color: transparent;
1467
1724
  }
@@ -1497,14 +1754,14 @@
1497
1754
  min-width: 340px;
1498
1755
  }
1499
1756
  .passkey-card h2 {
1500
- font-family: "Noto Sans", sans-serif;
1757
+ font-family: var(--font);
1501
1758
  font-size: 20px;
1502
1759
  font-weight: 600;
1503
1760
  color: var(--text);
1504
1761
  margin: 0;
1505
1762
  }
1506
1763
  .passkey-card p {
1507
- font-family: "Noto Sans", sans-serif;
1764
+ font-family: var(--font);
1508
1765
  font-size: 13px;
1509
1766
  color: var(--text-secondary);
1510
1767
  margin: 0;
@@ -1518,7 +1775,7 @@
1518
1775
  padding: 0 14px;
1519
1776
  font-size: 16px;
1520
1777
  font-weight: 500;
1521
- font-family: "Noto Sans", sans-serif;
1778
+ font-family: var(--font);
1522
1779
  background: var(--bg);
1523
1780
  border: 1px solid var(--border);
1524
1781
  border-radius: 10px;
@@ -1528,15 +1785,15 @@
1528
1785
  box-sizing: border-box;
1529
1786
  }
1530
1787
  .passkey-field input:focus {
1531
- border-color: #0079ff;
1532
- box-shadow: 0 0 0 2px rgba(0, 94, 255, 0.15);
1788
+ border-color: var(--accent);
1789
+ box-shadow: 0 0 0 2px var(--accent-glow);
1533
1790
  }
1534
1791
  .passkey-field input.error {
1535
1792
  border-color: #ef4444;
1536
1793
  box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.15);
1537
1794
  }
1538
1795
  .passkey-error {
1539
- font-family: "Noto Sans", sans-serif;
1796
+ font-family: var(--font);
1540
1797
  font-size: 13px;
1541
1798
  color: #ef4444;
1542
1799
  min-height: 18px;
@@ -1544,11 +1801,11 @@
1544
1801
  .passkey-btn {
1545
1802
  width: 100%;
1546
1803
  padding: 12px;
1547
- font-family: "Noto Sans", sans-serif;
1804
+ font-family: var(--font);
1548
1805
  font-size: 14px;
1549
1806
  font-weight: 600;
1550
1807
  color: #fff;
1551
- background: linear-gradient(135deg, #0079ff, #005eff);
1808
+ background: var(--accent);
1552
1809
  border: none;
1553
1810
  border-radius: 10px;
1554
1811
  cursor: pointer;
@@ -1556,6 +1813,750 @@
1556
1813
  }
1557
1814
  .passkey-btn:hover { opacity: 0.9; }
1558
1815
  .passkey-btn:disabled { opacity: 0.5; cursor: not-allowed; }
1816
+
1817
+ /* ── Command palette / shortcuts ── */
1818
+ .palette-overlay {
1819
+ position: fixed;
1820
+ inset: 0;
1821
+ z-index: 950;
1822
+ background: rgba(0, 0, 0, 0.5);
1823
+ display: flex;
1824
+ justify-content: center;
1825
+ align-items: flex-start;
1826
+ padding: 12vh 16px 16px;
1827
+ }
1828
+ .palette {
1829
+ width: 100%;
1830
+ max-width: 600px;
1831
+ background: var(--bg-elevated);
1832
+ border-radius: var(--radius-xl);
1833
+ box-shadow: var(--shadow-lg);
1834
+ overflow: hidden;
1835
+ display: flex;
1836
+ flex-direction: column;
1837
+ max-height: 70vh;
1838
+ }
1839
+ .palette-input {
1840
+ display: flex;
1841
+ align-items: center;
1842
+ gap: 10px;
1843
+ padding: 0 16px;
1844
+ height: 50px;
1845
+ border-bottom: 1px solid var(--border);
1846
+ color: var(--text-muted);
1847
+ flex-shrink: 0;
1848
+ }
1849
+ .palette-input input {
1850
+ flex: 1;
1851
+ background: transparent;
1852
+ border: none;
1853
+ outline: none;
1854
+ color: var(--text);
1855
+ font-size: 14.5px;
1856
+ font-family: inherit;
1857
+ }
1858
+ .palette-input input::placeholder {
1859
+ color: var(--text-muted);
1860
+ }
1861
+ .palette-list {
1862
+ overflow-y: auto;
1863
+ padding: 6px;
1864
+ }
1865
+ .palette-group {
1866
+ padding: 10px 10px 4px;
1867
+ font-size: 11px;
1868
+ font-weight: 500;
1869
+ color: var(--text-muted);
1870
+ }
1871
+ .palette-item {
1872
+ display: flex;
1873
+ align-items: center;
1874
+ gap: 10px;
1875
+ height: 36px;
1876
+ padding: 0 10px;
1877
+ border-radius: var(--radius);
1878
+ font-size: 13px;
1879
+ color: var(--text-secondary);
1880
+ cursor: pointer;
1881
+ }
1882
+ .palette-item.active {
1883
+ background: rgba(255, 255, 255, 0.06);
1884
+ color: var(--text);
1885
+ }
1886
+ .palette-icon {
1887
+ display: flex;
1888
+ width: 18px;
1889
+ justify-content: center;
1890
+ color: var(--text-muted);
1891
+ }
1892
+ .palette-item.active .palette-icon {
1893
+ color: var(--accent-light);
1894
+ }
1895
+ .palette-label {
1896
+ white-space: nowrap;
1897
+ }
1898
+ .palette-sub {
1899
+ flex: 1;
1900
+ min-width: 0;
1901
+ font-size: 12px;
1902
+ color: var(--text-muted);
1903
+ white-space: nowrap;
1904
+ overflow: hidden;
1905
+ text-overflow: ellipsis;
1906
+ }
1907
+ .palette-item kbd {
1908
+ margin-left: auto;
1909
+ }
1910
+ .palette-empty {
1911
+ padding: 32px 16px;
1912
+ text-align: center;
1913
+ color: var(--text-muted);
1914
+ }
1915
+ .palette-footer {
1916
+ display: flex;
1917
+ gap: 16px;
1918
+ padding: 8px 14px;
1919
+ border-top: 1px solid var(--border);
1920
+ font-size: 11.5px;
1921
+ color: var(--text-muted);
1922
+ flex-shrink: 0;
1923
+ }
1924
+ .palette-footer span {
1925
+ display: inline-flex;
1926
+ align-items: center;
1927
+ gap: 4px;
1928
+ }
1929
+ .palette.shortcuts {
1930
+ max-width: 640px;
1931
+ }
1932
+ .shortcuts-head {
1933
+ display: flex;
1934
+ align-items: center;
1935
+ justify-content: space-between;
1936
+ padding: 10px 10px 10px 18px;
1937
+ border-bottom: 1px solid var(--border);
1938
+ font-weight: 600;
1939
+ }
1940
+ .shortcuts-body {
1941
+ display: grid;
1942
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1943
+ gap: 4px 20px;
1944
+ padding: 8px 14px 16px;
1945
+ overflow-y: auto;
1946
+ }
1947
+ .shortcuts-group:first-child {
1948
+ grid-column: 1 / -1;
1949
+ }
1950
+ .shortcut-row {
1951
+ display: flex;
1952
+ align-items: center;
1953
+ justify-content: space-between;
1954
+ gap: 12px;
1955
+ padding: 6px 10px;
1956
+ font-size: 12.5px;
1957
+ color: var(--text-secondary);
1958
+ }
1959
+ .shortcut-row > span:last-child {
1960
+ display: inline-flex;
1961
+ gap: 4px;
1962
+ }
1963
+
1964
+ /* ── Page header (shared) ── */
1965
+ .page-head {
1966
+ display: flex;
1967
+ align-items: flex-end;
1968
+ justify-content: space-between;
1969
+ gap: 16px;
1970
+ flex-wrap: wrap;
1971
+ margin-bottom: 20px;
1972
+ }
1973
+ .page-head h1 {
1974
+ font-size: 20px;
1975
+ font-weight: 600;
1976
+ letter-spacing: -0.4px;
1977
+ }
1978
+ .page-head .page-meta {
1979
+ margin-top: 4px;
1980
+ font-size: 12.5px;
1981
+ color: var(--text-muted);
1982
+ display: flex;
1983
+ flex-wrap: wrap;
1984
+ gap: 4px 12px;
1985
+ }
1986
+ .page-head .page-actions {
1987
+ display: flex;
1988
+ gap: 8px;
1989
+ flex-wrap: wrap;
1990
+ }
1991
+
1992
+ /* ── Dashboard overview ── */
1993
+ .ov-kpis {
1994
+ display: grid;
1995
+ grid-template-columns: repeat(4, minmax(0, 1fr));
1996
+ gap: 12px;
1997
+ margin-bottom: 14px;
1998
+ }
1999
+ .ov-kpi {
2000
+ background: var(--bg-card);
2001
+ border: 1px solid var(--border);
2002
+ border-radius: var(--radius-lg);
2003
+ padding: 14px 16px;
2004
+ min-width: 0;
2005
+ }
2006
+ .ov-kpi-label {
2007
+ display: flex;
2008
+ align-items: center;
2009
+ gap: 6px;
2010
+ font-size: 12px;
2011
+ color: var(--text-muted);
2012
+ font-weight: 500;
2013
+ }
2014
+ .ov-kpi-value {
2015
+ margin-top: 8px;
2016
+ font-size: 24px;
2017
+ font-weight: 600;
2018
+ letter-spacing: -0.6px;
2019
+ font-variant-numeric: tabular-nums;
2020
+ white-space: nowrap;
2021
+ }
2022
+ .ov-kpi-value small {
2023
+ font-size: 13px;
2024
+ font-weight: 500;
2025
+ color: var(--text-muted);
2026
+ letter-spacing: 0;
2027
+ margin-left: 3px;
2028
+ }
2029
+ .ov-kpi-sub {
2030
+ margin-top: 4px;
2031
+ font-size: 12px;
2032
+ color: var(--text-muted);
2033
+ white-space: nowrap;
2034
+ overflow: hidden;
2035
+ text-overflow: ellipsis;
2036
+ }
2037
+ .ov-row {
2038
+ display: grid;
2039
+ grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
2040
+ gap: 14px;
2041
+ margin-bottom: 14px;
2042
+ }
2043
+ .ov-row.even {
2044
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2045
+ }
2046
+ .ov-card {
2047
+ background: var(--bg-card);
2048
+ border: 1px solid var(--border);
2049
+ border-radius: var(--radius-lg);
2050
+ min-width: 0;
2051
+ display: flex;
2052
+ flex-direction: column;
2053
+ }
2054
+ .ov-card-head {
2055
+ display: flex;
2056
+ align-items: center;
2057
+ justify-content: space-between;
2058
+ gap: 10px;
2059
+ padding: 12px 16px;
2060
+ border-bottom: 1px solid var(--border);
2061
+ min-height: 46px;
2062
+ }
2063
+ .ov-card-title {
2064
+ font-size: 13px;
2065
+ font-weight: 600;
2066
+ }
2067
+ .ov-card-body {
2068
+ padding: 14px 16px;
2069
+ flex: 1;
2070
+ }
2071
+ .ov-chart {
2072
+ position: relative;
2073
+ height: 168px;
2074
+ }
2075
+ .ov-chart svg {
2076
+ display: block;
2077
+ width: 100%;
2078
+ height: 100%;
2079
+ overflow: visible;
2080
+ }
2081
+ .ov-chart .bar {
2082
+ fill: var(--accent);
2083
+ transition: fill var(--transition);
2084
+ }
2085
+ .ov-chart .bar.dim {
2086
+ fill: rgba(91, 140, 255, 0.45);
2087
+ }
2088
+ .ov-chart .grid {
2089
+ stroke: var(--border);
2090
+ stroke-width: 1;
2091
+ }
2092
+ .ov-chart .axis {
2093
+ fill: var(--text-muted);
2094
+ font-size: 10.5px;
2095
+ font-family: var(--font);
2096
+ }
2097
+ .ov-tip {
2098
+ position: absolute;
2099
+ pointer-events: none;
2100
+ transform: translate(-50%, calc(-100% - 8px));
2101
+ background: var(--bg-elevated);
2102
+ border: 1px solid var(--border-strong);
2103
+ border-radius: var(--radius);
2104
+ padding: 7px 10px;
2105
+ font-size: 12px;
2106
+ white-space: nowrap;
2107
+ box-shadow: var(--shadow-lg);
2108
+ z-index: 2;
2109
+ }
2110
+ .ov-tip b {
2111
+ font-weight: 600;
2112
+ font-variant-numeric: tabular-nums;
2113
+ }
2114
+ .ov-tip .muted {
2115
+ color: var(--text-muted);
2116
+ }
2117
+ .ov-list {
2118
+ display: flex;
2119
+ flex-direction: column;
2120
+ }
2121
+ .ov-list-row {
2122
+ display: flex;
2123
+ align-items: center;
2124
+ gap: 10px;
2125
+ padding: 0 16px;
2126
+ height: 36px;
2127
+ border-bottom: 1px solid var(--border);
2128
+ font-size: 12.5px;
2129
+ min-width: 0;
2130
+ }
2131
+ .ov-list-row:last-child {
2132
+ border-bottom: none;
2133
+ }
2134
+ .ov-list-row.clickable {
2135
+ cursor: pointer;
2136
+ }
2137
+ .ov-list-row.clickable:hover {
2138
+ background: rgba(255, 255, 255, 0.025);
2139
+ }
2140
+ .ov-path {
2141
+ flex: 1;
2142
+ min-width: 0;
2143
+ font-family: var(--mono);
2144
+ font-size: 12px;
2145
+ white-space: nowrap;
2146
+ overflow: hidden;
2147
+ text-overflow: ellipsis;
2148
+ }
2149
+ .ov-num {
2150
+ font-variant-numeric: tabular-nums;
2151
+ color: var(--text-muted);
2152
+ white-space: nowrap;
2153
+ }
2154
+ .ov-status {
2155
+ font-family: var(--mono);
2156
+ font-size: 11.5px;
2157
+ font-weight: 600;
2158
+ width: 32px;
2159
+ }
2160
+ .ov-status.ok { color: var(--success); }
2161
+ .ov-status.warn { color: var(--warning); }
2162
+ .ov-status.err { color: var(--error); }
2163
+ .ov-method {
2164
+ width: 52px;
2165
+ flex-shrink: 0;
2166
+ }
2167
+ .ov-empty {
2168
+ padding: 28px 16px;
2169
+ text-align: center;
2170
+ color: var(--text-muted);
2171
+ font-size: 12.5px;
2172
+ line-height: 1.6;
2173
+ }
2174
+ .ov-empty code {
2175
+ font-size: 11.5px;
2176
+ color: var(--text-secondary);
2177
+ background: rgba(255, 255, 255, 0.04);
2178
+ padding: 1px 5px;
2179
+ border-radius: 4px;
2180
+ }
2181
+ .ov-progress {
2182
+ height: 4px;
2183
+ border-radius: 999px;
2184
+ background: rgba(255, 255, 255, 0.06);
2185
+ overflow: hidden;
2186
+ }
2187
+ .ov-progress > span {
2188
+ display: block;
2189
+ height: 100%;
2190
+ border-radius: 999px;
2191
+ background: var(--accent);
2192
+ transition: width 400ms cubic-bezier(0.2, 0, 0, 1);
2193
+ }
2194
+ .ov-check {
2195
+ width: 16px;
2196
+ height: 16px;
2197
+ border-radius: 50%;
2198
+ display: grid;
2199
+ place-items: center;
2200
+ flex-shrink: 0;
2201
+ border: 1.5px solid var(--border-strong);
2202
+ color: transparent;
2203
+ }
2204
+ .ov-check.done {
2205
+ background: var(--success);
2206
+ border-color: var(--success);
2207
+ color: #0b0b0e;
2208
+ }
2209
+ .ov-meter {
2210
+ display: flex;
2211
+ flex-direction: column;
2212
+ gap: 6px;
2213
+ padding: 10px 16px;
2214
+ border-bottom: 1px solid var(--border);
2215
+ }
2216
+ .ov-meter:last-child {
2217
+ border-bottom: none;
2218
+ }
2219
+ .ov-meter-top {
2220
+ display: flex;
2221
+ justify-content: space-between;
2222
+ font-size: 12.5px;
2223
+ }
2224
+ .ov-meter-top span:last-child {
2225
+ color: var(--text-muted);
2226
+ font-variant-numeric: tabular-nums;
2227
+ }
2228
+ .ov-err {
2229
+ padding: 9px 16px;
2230
+ border-bottom: 1px solid var(--border);
2231
+ font-family: var(--mono);
2232
+ font-size: 11.5px;
2233
+ color: var(--error);
2234
+ white-space: nowrap;
2235
+ overflow: hidden;
2236
+ text-overflow: ellipsis;
2237
+ }
2238
+ .ov-err:last-child {
2239
+ border-bottom: none;
2240
+ }
2241
+ .ov-err span {
2242
+ color: var(--text-muted);
2243
+ margin-right: 8px;
2244
+ }
2245
+
2246
+ /* ── API tester: request tabs + history ── */
2247
+ .req-tabs {
2248
+ display: flex;
2249
+ align-items: flex-end;
2250
+ gap: 2px;
2251
+ margin-bottom: 12px;
2252
+ border-bottom: 1px solid var(--border);
2253
+ overflow-x: auto;
2254
+ scrollbar-width: none;
2255
+ }
2256
+ .req-tabs::-webkit-scrollbar {
2257
+ display: none;
2258
+ }
2259
+ .req-tab {
2260
+ display: inline-flex;
2261
+ align-items: center;
2262
+ gap: 7px;
2263
+ height: 32px;
2264
+ max-width: 220px;
2265
+ padding: 0 8px 0 12px;
2266
+ border: 1px solid transparent;
2267
+ border-bottom: none;
2268
+ border-radius: var(--radius) var(--radius) 0 0;
2269
+ font-size: 12px;
2270
+ color: var(--text-muted);
2271
+ cursor: pointer;
2272
+ flex-shrink: 0;
2273
+ position: relative;
2274
+ top: 1px;
2275
+ }
2276
+ .req-tab:hover {
2277
+ color: var(--text-secondary);
2278
+ background: rgba(255, 255, 255, 0.02);
2279
+ }
2280
+ .req-tab.active {
2281
+ color: var(--text);
2282
+ background: var(--bg-card);
2283
+ border-color: var(--border);
2284
+ }
2285
+ .req-tab-method {
2286
+ font-family: var(--mono);
2287
+ font-size: 10px;
2288
+ font-weight: 700;
2289
+ }
2290
+ .req-tab-label {
2291
+ overflow: hidden;
2292
+ text-overflow: ellipsis;
2293
+ white-space: nowrap;
2294
+ }
2295
+ .req-tab-close {
2296
+ width: 18px;
2297
+ height: 18px;
2298
+ display: grid;
2299
+ place-items: center;
2300
+ border-radius: 4px;
2301
+ border: none;
2302
+ background: transparent;
2303
+ color: inherit;
2304
+ opacity: 0;
2305
+ cursor: pointer;
2306
+ font-size: 14px;
2307
+ line-height: 1;
2308
+ }
2309
+ .req-tab:hover .req-tab-close,
2310
+ .req-tab.active .req-tab-close {
2311
+ opacity: 0.6;
2312
+ }
2313
+ .req-tab-close:hover {
2314
+ opacity: 1 !important;
2315
+ background: rgba(255, 255, 255, 0.08);
2316
+ }
2317
+ .req-tab-new {
2318
+ height: 28px;
2319
+ width: 28px;
2320
+ margin: 0 0 2px 4px;
2321
+ display: grid;
2322
+ place-items: center;
2323
+ border: none;
2324
+ border-radius: var(--radius);
2325
+ background: transparent;
2326
+ color: var(--text-muted);
2327
+ cursor: pointer;
2328
+ flex-shrink: 0;
2329
+ }
2330
+ .req-tab-new:hover {
2331
+ background: rgba(255, 255, 255, 0.05);
2332
+ color: var(--text);
2333
+ }
2334
+ .hist-panel {
2335
+ background: var(--bg-card);
2336
+ border: 1px solid var(--border);
2337
+ border-radius: var(--radius-lg);
2338
+ margin-bottom: 12px;
2339
+ overflow: hidden;
2340
+ }
2341
+ .hist-head {
2342
+ display: flex;
2343
+ align-items: center;
2344
+ gap: 8px;
2345
+ padding: 8px 10px 8px 14px;
2346
+ border-bottom: 1px solid var(--border);
2347
+ }
2348
+ .hist-head input {
2349
+ flex: 1;
2350
+ min-width: 0;
2351
+ height: 28px;
2352
+ padding: 0 10px;
2353
+ border-radius: var(--radius);
2354
+ border: 1px solid var(--border);
2355
+ background: var(--bg-input);
2356
+ color: var(--text);
2357
+ font-size: 12px;
2358
+ font-family: inherit;
2359
+ outline: none;
2360
+ }
2361
+ .hist-head input:focus {
2362
+ border-color: var(--border-focus);
2363
+ }
2364
+ .hist-list {
2365
+ max-height: 300px;
2366
+ overflow-y: auto;
2367
+ }
2368
+ .hist-row {
2369
+ display: flex;
2370
+ align-items: center;
2371
+ gap: 10px;
2372
+ height: 34px;
2373
+ padding: 0 14px;
2374
+ border-bottom: 1px solid var(--border);
2375
+ cursor: pointer;
2376
+ font-size: 12px;
2377
+ }
2378
+ .hist-row:last-child {
2379
+ border-bottom: none;
2380
+ }
2381
+ .hist-row:hover {
2382
+ background: rgba(255, 255, 255, 0.03);
2383
+ }
2384
+ .hist-row .hist-open {
2385
+ opacity: 0;
2386
+ }
2387
+ .hist-row:hover .hist-open {
2388
+ opacity: 1;
2389
+ }
2390
+
2391
+ /* ── Serial workspace ── */
2392
+ .serial-console {
2393
+ height: 420px;
2394
+ overflow-y: auto;
2395
+ background: var(--bg-input);
2396
+ border: 1px solid var(--border);
2397
+ border-radius: var(--radius);
2398
+ padding: 8px 0;
2399
+ font-family: var(--mono);
2400
+ font-size: 12px;
2401
+ line-height: 1.65;
2402
+ }
2403
+ .sc-line { display: flex; gap: 10px; padding: 0 12px; white-space: pre-wrap; word-break: break-all; }
2404
+ .sc-line:hover { background: rgba(255, 255, 255, 0.03); }
2405
+ .sc-ts { color: var(--text-muted); flex-shrink: 0; }
2406
+ .sc-dir { flex-shrink: 0; width: 14px; font-weight: 700; }
2407
+ .sc-rx .sc-dir { color: var(--success); }
2408
+ .sc-tx .sc-dir { color: var(--accent-light); }
2409
+ .sc-tx .sc-text { color: var(--accent-light); }
2410
+ .sc-text mark { background: rgba(245, 165, 36, 0.3); color: inherit; border-radius: 2px; }
2411
+ .sc-hex { color: var(--text-secondary); }
2412
+ .serial-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 10px; }
2413
+ .serial-toolbar .form-input, .serial-toolbar .form-select { height: 30px; font-size: 12.5px; }
2414
+ .chip-toggle {
2415
+ display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 10px;
2416
+ border-radius: var(--radius); border: 1px solid var(--border); background: transparent;
2417
+ color: var(--text-secondary); font-size: 12.5px; cursor: pointer;
2418
+ }
2419
+ .chip-toggle.on { color: var(--text); border-color: var(--border-focus); background: var(--accent-glow); }
2420
+ .cmd-grid { display: flex; flex-wrap: wrap; gap: 8px; }
2421
+ .serial-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
2422
+ .serial-stats .ov-kpi-value { font-size: 20px; }
2423
+ @media (max-width: 1200px) { .serial-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
2424
+ .chart-legend { display: flex; flex-wrap: wrap; gap: 14px; font-size: 12px; color: var(--text-secondary); margin-bottom: 8px; }
2425
+ .chart-legend i { display: inline-block; width: 10px; height: 3px; border-radius: 2px; margin-right: 6px; vertical-align: middle; }
2426
+ .series-pick { display: inline-flex; align-items: center; gap: 6px; height: 26px; padding: 0 9px; border-radius: 999px; border: 1px solid var(--border); font-size: 12px; cursor: pointer; color: var(--text-secondary); background: transparent; }
2427
+ .series-pick.on { color: var(--text); border-color: var(--border-strong); background: rgba(255, 255, 255, 0.05); }
2428
+ .series-pick i { width: 8px; height: 8px; border-radius: 50%; }
2429
+
2430
+ /* ── Responsive ── */
2431
+ @media (max-width: 1200px) {
2432
+ .ov-kpis {
2433
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2434
+ }
2435
+ .routes-layout {
2436
+ grid-template-columns: 280px minmax(0, 1fr);
2437
+ }
2438
+ .schema-builder {
2439
+ grid-template-columns: minmax(0, 1fr) 300px;
2440
+ }
2441
+ }
2442
+ @media (max-width: 1024px) {
2443
+ .ov-row,
2444
+ .ov-row.even {
2445
+ grid-template-columns: minmax(0, 1fr);
2446
+ }
2447
+ .grid-4 {
2448
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2449
+ }
2450
+ .grid-3 {
2451
+ grid-template-columns: repeat(2, minmax(0, 1fr));
2452
+ }
2453
+ .routes-layout,
2454
+ .schema-builder {
2455
+ grid-template-columns: minmax(0, 1fr);
2456
+ min-height: 0;
2457
+ }
2458
+ .routes-detail,
2459
+ .schema-builder-sidebar {
2460
+ position: static;
2461
+ }
2462
+ .topbar-search {
2463
+ width: auto;
2464
+ }
2465
+ .topbar-search span,
2466
+ .topbar-search kbd {
2467
+ display: none;
2468
+ }
2469
+ }
2470
+ @media (max-width: 860px) {
2471
+ .sidebar,
2472
+ .sidebar.collapsed {
2473
+ position: fixed;
2474
+ top: 0;
2475
+ bottom: 0;
2476
+ left: 0;
2477
+ width: var(--sidebar-w);
2478
+ transform: translateX(-100%);
2479
+ transition: transform 200ms cubic-bezier(0.2, 0, 0, 1);
2480
+ box-shadow: var(--shadow-lg);
2481
+ }
2482
+ .sidebar.open {
2483
+ transform: none;
2484
+ }
2485
+ .sidebar.collapsed .brand-text,
2486
+ .sidebar.collapsed .sidebar-label,
2487
+ .sidebar.collapsed .sidebar-kbd,
2488
+ .sidebar.collapsed .lock-icon {
2489
+ opacity: 1;
2490
+ pointer-events: auto;
2491
+ }
2492
+ .sidebar.collapsed .sidebar-section span {
2493
+ visibility: visible;
2494
+ }
2495
+ .sidebar.collapsed .sidebar-section::after {
2496
+ display: none;
2497
+ }
2498
+ .sidebar-collapse {
2499
+ display: none;
2500
+ }
2501
+ .sidebar-scrim {
2502
+ display: block;
2503
+ position: fixed;
2504
+ inset: 0;
2505
+ z-index: 39;
2506
+ background: rgba(0, 0, 0, 0.5);
2507
+ }
2508
+ .topbar {
2509
+ padding: 0 12px 0 16px;
2510
+ }
2511
+ .topbar-menu {
2512
+ display: grid;
2513
+ place-items: center;
2514
+ }
2515
+ .crumb-muted,
2516
+ .crumb-sep,
2517
+ .live-pill {
2518
+ display: none;
2519
+ }
2520
+ .content {
2521
+ padding: 16px 16px 40px;
2522
+ }
2523
+ .grid-2,
2524
+ .grid-3 {
2525
+ grid-template-columns: minmax(0, 1fr);
2526
+ }
2527
+ .api-tester-bar {
2528
+ flex-wrap: wrap;
2529
+ }
2530
+ .api-tester-url {
2531
+ flex-basis: calc(100% - 120px);
2532
+ }
2533
+ .palette-overlay {
2534
+ padding-top: 8vh;
2535
+ }
2536
+ .palette-footer {
2537
+ display: none;
2538
+ }
2539
+ .shortcuts-body {
2540
+ grid-template-columns: minmax(0, 1fr);
2541
+ }
2542
+ }
2543
+ @media (max-width: 520px) {
2544
+ .ov-kpis,
2545
+ .grid-4 {
2546
+ grid-template-columns: minmax(0, 1fr);
2547
+ }
2548
+ .toast-container {
2549
+ left: 16px;
2550
+ }
2551
+ }
2552
+ @media (prefers-reduced-motion: reduce) {
2553
+ *,
2554
+ *::before,
2555
+ *::after {
2556
+ transition-duration: 0ms !important;
2557
+ animation-duration: 0ms !important;
2558
+ }
2559
+ }
1559
2560
  </style>
1560
2561
  </head>
1561
2562
  <body>