@clazic/urban 0.2.4 → 0.2.6

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.
@@ -0,0 +1,799 @@
1
+ const fs = require('fs');
2
+ const file = 'web/ui.html';
3
+ let html = fs.readFileSync(file, 'utf8');
4
+
5
+ const newCss = `
6
+ /* ─── CSS Variables (Design System) ─── */
7
+ :root {
8
+ color-scheme: dark;
9
+ /* 배경: 잉크 다크 */
10
+ --bg: #0f0f0f;
11
+ --surface: #1a1a1a;
12
+ --surface-raised: #2a2a2a;
13
+ --border: #333333;
14
+ --border-subtle: #222222;
15
+ /* 텍스트 */
16
+ --text: #f3f4f6;
17
+ --text-secondary: #9ca3af;
18
+ --text-tertiary: #6b7280;
19
+ /* accent: 오렌지/레드 */
20
+ --accent: #d9381e;
21
+ --accent-dim: #a62b16;
22
+ /* 상태색 */
23
+ --error: #ef4444;
24
+ --success: #10b981;
25
+ --warning: #f59e0b;
26
+ /* 스페이싱 */
27
+ --space-1: 4px;
28
+ --space-2: 8px;
29
+ --space-3: 12px;
30
+ --space-4: 16px;
31
+ --space-5: 20px;
32
+ --space-6: 24px;
33
+ /* 타입 스케일 */
34
+ --text-xs: 12px;
35
+ --text-sm: 13px;
36
+ --text-base: 15px;
37
+ --text-lg: 18px;
38
+ --text-xl: 22px;
39
+ --text-2xl: 32px;
40
+ /* 폰트 */
41
+ --font-sans: 'Pretendard Variable', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
42
+ --font-serif: 'Fraunces', 'Pretendard Variable', ui-serif, Georgia, serif;
43
+ --font-mono: 'JetBrains Mono', 'SF Mono', 'Menlo', monospace;
44
+ }
45
+
46
+ [data-theme="light"] {
47
+ color-scheme: light;
48
+ /* 라이트: 연한 그레이 배경에 화이트 표면 */
49
+ --bg: #e5e5e5;
50
+ --surface: #ffffff;
51
+ --surface-raised: #f9fafb;
52
+ --border: #e5e7eb;
53
+ --border-subtle: #f3f4f6;
54
+ --text: #111827;
55
+ --text-secondary: #4b5563;
56
+ --text-tertiary: #9ca3af;
57
+ --accent: #d9381e;
58
+ --accent-dim: #f87171;
59
+ }
60
+
61
+ [data-theme="system"] {
62
+ color-scheme: light dark;
63
+ }
64
+
65
+ /* ─── Reset & Base ─── */
66
+ * {
67
+ margin: 0;
68
+ padding: 0;
69
+ box-sizing: border-box;
70
+ }
71
+
72
+ ::selection {
73
+ background: color-mix(in srgb, var(--accent) 28%, transparent);
74
+ color: var(--text);
75
+ }
76
+
77
+ :focus-visible {
78
+ outline: 2px solid var(--accent);
79
+ outline-offset: 2px;
80
+ }
81
+
82
+ html, body {
83
+ width: 100%;
84
+ height: 100%;
85
+ }
86
+
87
+ body {
88
+ font-family: var(--font-sans);
89
+ font-size: 14px;
90
+ background: var(--bg);
91
+ color: var(--text);
92
+ line-height: 1.5;
93
+ display: flex;
94
+ flex-direction: column;
95
+ -webkit-font-smoothing: antialiased;
96
+ -moz-osx-font-smoothing: grayscale;
97
+ }
98
+
99
+ /* ─── Layout (Floating Panels) ─── */
100
+ .layout {
101
+ display: flex;
102
+ flex: 1;
103
+ min-height: 0;
104
+ padding: 16px;
105
+ gap: 16px;
106
+ }
107
+
108
+ .sidebar {
109
+ width: 56px;
110
+ background: var(--surface);
111
+ border: 1px solid var(--border);
112
+ border-radius: 16px;
113
+ display: flex;
114
+ flex-direction: column;
115
+ align-items: center;
116
+ padding: var(--space-4) 0;
117
+ gap: 4px;
118
+ transition: width 0.25s cubic-bezier(0.16,1,0.3,1);
119
+ position: relative;
120
+ z-index: 100;
121
+ box-shadow: 0 4px 12px rgba(0,0,0,0.03);
122
+ }
123
+
124
+ .sidebar.expanded {
125
+ width: 240px;
126
+ align-items: stretch;
127
+ padding-left: var(--space-3);
128
+ padding-right: var(--space-3);
129
+ }
130
+
131
+ .sidebar-item {
132
+ width: 40px;
133
+ height: 40px;
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: center;
137
+ cursor: pointer;
138
+ border-radius: 10px;
139
+ transition: background .12s, color .12s;
140
+ flex-shrink: 0;
141
+ position: relative;
142
+ font-size: 16px;
143
+ color: var(--text-tertiary);
144
+ border: none;
145
+ background: transparent;
146
+ }
147
+
148
+ .sidebar.expanded .sidebar-item {
149
+ width: 100%;
150
+ height: auto;
151
+ justify-content: flex-start;
152
+ padding: 10px var(--space-4);
153
+ gap: var(--space-3);
154
+ border-radius: 10px;
155
+ }
156
+
157
+ .sidebar-item:hover {
158
+ background: var(--surface-raised);
159
+ color: var(--text);
160
+ }
161
+
162
+ .sidebar-item.active {
163
+ background: var(--surface-raised);
164
+ color: var(--accent);
165
+ font-weight: 600;
166
+ }
167
+
168
+ /* 커스텀 툴팁 (접힌 상태) */
169
+ .sidebar:not(.expanded) .sidebar-item[data-tooltip]::after {
170
+ content: attr(data-tooltip);
171
+ position: absolute;
172
+ left: calc(100% + 12px);
173
+ top: 50%;
174
+ transform: translateY(-50%);
175
+ background: var(--text);
176
+ color: var(--surface);
177
+ font-size: 12px;
178
+ font-weight: 500;
179
+ padding: 6px 12px;
180
+ border-radius: 6px;
181
+ white-space: nowrap;
182
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
183
+ opacity: 0;
184
+ pointer-events: none;
185
+ transition: opacity 0.1s 0.4s;
186
+ z-index: 300;
187
+ }
188
+ .sidebar:not(.expanded) .sidebar-item[data-tooltip]:hover::after {
189
+ opacity: 1;
190
+ }
191
+
192
+ .sidebar-label {
193
+ display: none;
194
+ font-size: var(--text-sm);
195
+ font-weight: 500;
196
+ letter-spacing: 0.01em;
197
+ }
198
+
199
+ .sidebar.expanded .sidebar-label {
200
+ display: inline;
201
+ }
202
+
203
+ /* ─── Sidebar Brand ─── */
204
+ .sidebar-brand {
205
+ display: flex;
206
+ align-items: center;
207
+ gap: var(--space-3);
208
+ padding-bottom: var(--space-4);
209
+ margin-bottom: var(--space-2);
210
+ border-bottom: 1px solid var(--border-subtle);
211
+ width: 100%;
212
+ justify-content: center;
213
+ overflow: hidden;
214
+ flex-shrink: 0;
215
+ }
216
+ .sidebar.expanded .sidebar-brand { justify-content: flex-start; padding-left: var(--space-2); padding-right: var(--space-2); }
217
+ .sidebar-logo {
218
+ width: 36px;
219
+ height: 36px;
220
+ border-radius: 10px;
221
+ background: var(--accent);
222
+ display: flex;
223
+ align-items: center;
224
+ justify-content: center;
225
+ color: #ffffff;
226
+ font-size: 16px;
227
+ flex-shrink: 0;
228
+ }
229
+ .sidebar-brand-name {
230
+ display: none;
231
+ flex-direction: column;
232
+ gap: 2px;
233
+ }
234
+ .sidebar.expanded .sidebar-brand-name { display: flex; }
235
+ .sidebar-brand-name strong {
236
+ font-family: var(--font-serif);
237
+ font-size: var(--text-base);
238
+ font-weight: 600;
239
+ color: var(--text);
240
+ line-height: 1;
241
+ letter-spacing: -0.01em;
242
+ }
243
+ .sidebar-brand-name small {
244
+ font-family: var(--font-sans);
245
+ font-size: 11px;
246
+ color: var(--text-tertiary);
247
+ line-height: 1;
248
+ }
249
+
250
+ /* ─── Sidebar Spacer & Footer ─── */
251
+ .sidebar-spacer { flex: 1; }
252
+ .sidebar-footer {
253
+ display: flex;
254
+ flex-direction: column;
255
+ gap: var(--space-1);
256
+ width: 100%;
257
+ padding-top: var(--space-4);
258
+ border-top: 1px solid var(--border-subtle);
259
+ flex-shrink: 0;
260
+ }
261
+ #sidebar-pin-btn i { transition: transform 0.2s, color 0.2s; }
262
+ #sidebar-pin-btn.pinned { color: var(--accent); }
263
+ #sidebar-pin-btn.pinned i { transform: rotate(45deg); }
264
+
265
+ .main-container {
266
+ flex: 1;
267
+ display: flex;
268
+ flex-direction: column;
269
+ background: var(--surface);
270
+ border: 1px solid var(--border);
271
+ border-radius: 16px;
272
+ overflow: hidden;
273
+ box-shadow: 0 4px 12px rgba(0,0,0,0.03);
274
+ }
275
+
276
+ header {
277
+ height: 56px;
278
+ background: var(--surface);
279
+ border-bottom: 1px solid var(--border-subtle);
280
+ display: flex;
281
+ align-items: center;
282
+ justify-content: space-between;
283
+ padding: 0 var(--space-5);
284
+ flex-shrink: 0;
285
+ gap: var(--space-4);
286
+ }
287
+
288
+ .header-left {
289
+ display: flex;
290
+ align-items: center;
291
+ gap: var(--space-3);
292
+ font-size: var(--text-sm);
293
+ font-weight: 600;
294
+ color: var(--text);
295
+ min-width: 0;
296
+ }
297
+
298
+ .header-center {
299
+ flex: 1;
300
+ max-width: 480px;
301
+ }
302
+
303
+ .search-input {
304
+ width: 100%;
305
+ padding: 10px 16px;
306
+ background: var(--bg);
307
+ border: 1px solid var(--border);
308
+ border-radius: 20px;
309
+ color: var(--text);
310
+ font-size: var(--text-sm);
311
+ font-family: var(--font-sans);
312
+ transition: all .2s;
313
+ }
314
+
315
+ .search-input::placeholder {
316
+ color: var(--text-tertiary);
317
+ }
318
+
319
+ .search-input:focus {
320
+ outline: none;
321
+ background: var(--surface);
322
+ border-color: var(--accent);
323
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 20%, transparent);
324
+ }
325
+
326
+ .icon-button {
327
+ width: 36px;
328
+ height: 36px;
329
+ display: flex;
330
+ align-items: center;
331
+ justify-content: center;
332
+ background: transparent;
333
+ border: 1px solid var(--border);
334
+ cursor: pointer;
335
+ color: var(--text-secondary);
336
+ transition: all .2s;
337
+ border-radius: 10px;
338
+ font-size: 15px;
339
+ }
340
+
341
+ .icon-button:hover {
342
+ color: var(--text);
343
+ background: var(--surface-raised);
344
+ border-color: var(--text-tertiary);
345
+ }
346
+
347
+ .header-right {
348
+ display: flex;
349
+ align-items: center;
350
+ gap: var(--space-2);
351
+ }
352
+
353
+ .content {
354
+ flex: 1;
355
+ overflow: hidden;
356
+ display: flex;
357
+ flex-direction: column;
358
+ }
359
+
360
+ .page {
361
+ display: none;
362
+ animation: pageIn 0.3s cubic-bezier(0.16, 1, 0.3, 1);
363
+ }
364
+
365
+ .page.active {
366
+ display: flex;
367
+ flex-direction: column;
368
+ flex: 1;
369
+ overflow-y: auto;
370
+ overflow-x: hidden;
371
+ }
372
+
373
+ #page-search.active { overflow: hidden; }
374
+ #page-search .page-inner { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-height: 0; }
375
+
376
+ @keyframes pageIn {
377
+ from { opacity: 0; transform: translateY(10px); }
378
+ to { opacity: 1; transform: translateY(0); }
379
+ }
380
+
381
+ .page-inner {
382
+ max-width: 1200px;
383
+ margin: 0 auto;
384
+ padding: var(--space-6) var(--space-6);
385
+ width: 100%;
386
+ }
387
+ .page-inner.narrow { max-width: 760px; }
388
+
389
+ footer {
390
+ height: 40px;
391
+ background: var(--surface);
392
+ border-top: 1px solid var(--border-subtle);
393
+ display: grid;
394
+ grid-template-columns: 1fr auto 1fr;
395
+ align-items: center;
396
+ padding: 0 var(--space-5);
397
+ font-size: 12px;
398
+ color: var(--text-tertiary);
399
+ flex-shrink: 0;
400
+ }
401
+ .footer-left { display: flex; align-items: center; gap: var(--space-2); }
402
+ .footer-right { display: flex; justify-content: flex-end; align-items: center; }
403
+
404
+ .status-indicator {
405
+ width: 8px;
406
+ height: 8px;
407
+ border-radius: 50%;
408
+ background: var(--success);
409
+ }
410
+ .status-indicator.disconnected {
411
+ background: var(--text-tertiary);
412
+ animation: pulse 2s infinite;
413
+ }
414
+ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
415
+
416
+ /* ─── Cards & Sections ─── */
417
+ h1 {
418
+ font-family: var(--font-sans);
419
+ font-size: var(--text-2xl);
420
+ font-weight: 700;
421
+ letter-spacing: -0.03em;
422
+ margin-bottom: var(--space-2);
423
+ line-height: 1.2;
424
+ color: var(--text);
425
+ }
426
+
427
+ h2 {
428
+ font-size: var(--text-sm);
429
+ font-weight: 600;
430
+ letter-spacing: 0.05em;
431
+ color: var(--text-secondary);
432
+ margin-bottom: var(--space-4);
433
+ padding-top: var(--space-6);
434
+ padding-bottom: var(--space-2);
435
+ border-bottom: 1px solid var(--border-subtle);
436
+ border-top: none;
437
+ }
438
+ h2:first-child { padding-top: 0; }
439
+
440
+ .subtitle {
441
+ color: var(--text-tertiary);
442
+ font-size: var(--text-base);
443
+ margin-bottom: var(--space-6);
444
+ }
445
+
446
+ /* 다크 테마 카드 디자인 반영 */
447
+ .stat-card {
448
+ background: #1a1a1a;
449
+ color: #ffffff;
450
+ padding: var(--space-5);
451
+ border-radius: 16px;
452
+ border: 1px solid #333;
453
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
454
+ position: relative;
455
+ overflow: hidden;
456
+ transition: transform 0.2s, box-shadow 0.2s;
457
+ }
458
+
459
+ [data-theme="dark"] .stat-card {
460
+ background: #222;
461
+ }
462
+
463
+ .stat-card:hover {
464
+ transform: translateY(-2px);
465
+ box-shadow: 0 8px 24px rgba(0,0,0,0.15);
466
+ }
467
+
468
+ .stat-card::before {
469
+ content: '';
470
+ position: absolute;
471
+ top: var(--space-4);
472
+ left: var(--space-4);
473
+ width: 32px;
474
+ height: 32px;
475
+ border-radius: 50%;
476
+ background: color-mix(in srgb, var(--accent) 20%, transparent);
477
+ display: flex;
478
+ align-items: center;
479
+ justify-content: center;
480
+ color: var(--accent);
481
+ font-family: 'Font Awesome 6 Free';
482
+ font-weight: 900;
483
+ content: '\\f080'; /* fa-chart-bar */
484
+ font-size: 14px;
485
+ }
486
+
487
+ .stat-card:nth-child(2)::before { content: '\\f1c0'; } /* fa-database */
488
+ .stat-card:nth-child(3)::before { content: '\\f0e7'; } /* fa-bolt */
489
+
490
+ .stat-label {
491
+ font-size: 13px;
492
+ color: #9ca3af;
493
+ margin-top: 40px;
494
+ margin-bottom: 8px;
495
+ font-weight: 500;
496
+ }
497
+
498
+ .stat-value {
499
+ font-family: var(--font-sans);
500
+ font-size: 24px;
501
+ font-weight: 600;
502
+ color: #ffffff;
503
+ }
504
+
505
+ /* ─── Stat Bar (Hero) ─── */
506
+ .stat-bar {
507
+ display: flex;
508
+ align-items: stretch;
509
+ border: 1px solid var(--border);
510
+ border-radius: 16px;
511
+ background: var(--surface);
512
+ overflow: hidden;
513
+ margin-bottom: var(--space-6);
514
+ box-shadow: 0 2px 8px rgba(0,0,0,0.02);
515
+ }
516
+ .stat-primary {
517
+ display: flex;
518
+ flex-direction: column;
519
+ justify-content: center;
520
+ gap: 8px;
521
+ padding: var(--space-5) var(--space-6);
522
+ border-right: 1px solid var(--border);
523
+ min-width: 180px;
524
+ background: color-mix(in srgb, var(--accent) 5%, transparent);
525
+ }
526
+ .stat-primary-value {
527
+ font-family: var(--font-sans);
528
+ font-size: 40px;
529
+ font-weight: 700;
530
+ line-height: 1;
531
+ color: var(--text);
532
+ letter-spacing: -0.03em;
533
+ }
534
+ .stat-primary-label {
535
+ font-size: 12px;
536
+ color: var(--accent);
537
+ font-weight: 600;
538
+ }
539
+ .stat-secondaries { display: flex; flex: 1; }
540
+ .stat-secondary {
541
+ display: flex;
542
+ flex-direction: column;
543
+ justify-content: center;
544
+ gap: 6px;
545
+ padding: var(--space-4) var(--space-5);
546
+ border-right: 1px solid var(--border-subtle);
547
+ flex: 1;
548
+ }
549
+ .stat-secondary:last-child { border-right: none; }
550
+ .stat-secondary-value {
551
+ font-family: var(--font-sans);
552
+ font-size: 20px;
553
+ font-weight: 600;
554
+ color: var(--text);
555
+ }
556
+ .stat-secondary-label {
557
+ font-size: 12px;
558
+ color: var(--text-tertiary);
559
+ font-weight: 500;
560
+ }
561
+
562
+ .list-item {
563
+ padding: 16px;
564
+ border-bottom: 1px solid var(--border-subtle);
565
+ display: flex;
566
+ justify-content: space-between;
567
+ align-items: center;
568
+ gap: var(--space-3);
569
+ position: relative;
570
+ transition: background 0.15s;
571
+ }
572
+ .list-item:last-child { border-bottom: none; }
573
+ .list-item:hover { background: var(--surface-raised); }
574
+
575
+ .list-item-title {
576
+ font-size: 15px;
577
+ font-weight: 600;
578
+ flex: 1;
579
+ word-break: break-word;
580
+ line-height: 1.4;
581
+ color: var(--text);
582
+ margin-bottom: 4px;
583
+ }
584
+
585
+ .list-item-meta {
586
+ font-family: var(--font-sans);
587
+ font-size: 12px;
588
+ color: var(--text-tertiary);
589
+ display: flex;
590
+ gap: var(--space-3);
591
+ align-items: center;
592
+ }
593
+
594
+ .badge {
595
+ display: inline-flex;
596
+ align-items: center;
597
+ gap: 4px;
598
+ padding: 2px 8px;
599
+ background: color-mix(in srgb, var(--accent) 15%, transparent);
600
+ color: var(--accent);
601
+ border-radius: 6px;
602
+ font-size: 11px;
603
+ font-weight: 600;
604
+ }
605
+ .badge.error { background: color-mix(in srgb, var(--error) 15%, transparent); color: var(--error); }
606
+ .badge.success { background: color-mix(in srgb, var(--success) 15%, transparent); color: var(--success); }
607
+ .badge.warning { background: color-mix(in srgb, var(--warning) 15%, transparent); color: var(--warning); }
608
+
609
+ /* ─── Buttons ─── */
610
+ .button {
611
+ display: inline-flex;
612
+ align-items: center;
613
+ justify-content: center;
614
+ gap: 6px;
615
+ height: 36px;
616
+ padding: 0 16px;
617
+ background: var(--surface-raised);
618
+ color: var(--text);
619
+ border: 1px solid var(--border);
620
+ border-radius: 10px;
621
+ font-size: 13px;
622
+ font-weight: 600;
623
+ cursor: pointer;
624
+ transition: all .2s;
625
+ font-family: var(--font-sans);
626
+ white-space: nowrap;
627
+ }
628
+ .button i { font-size: 13px; color: var(--text-tertiary); transition: color .2s; }
629
+ .button:hover { background: var(--border-subtle); border-color: var(--text-tertiary); }
630
+ .button:hover i { color: var(--text); }
631
+ .button:active { transform: scale(0.98); }
632
+
633
+ .button-primary {
634
+ background: var(--accent);
635
+ color: #ffffff;
636
+ border-color: var(--accent);
637
+ }
638
+ .button-primary i { color: #ffffff; }
639
+ .button-primary:hover {
640
+ background: var(--accent-dim);
641
+ border-color: var(--accent-dim);
642
+ color: #ffffff;
643
+ }
644
+
645
+ .button-danger {
646
+ background: transparent;
647
+ color: var(--error);
648
+ border-color: color-mix(in srgb, var(--error) 30%, transparent);
649
+ }
650
+ .button-danger:hover { background: color-mix(in srgb, var(--error) 10%, transparent); border-color: var(--error); }
651
+
652
+ /* ─── Forms ─── */
653
+ .form-group { margin-bottom: var(--space-4); }
654
+ input[type="text"], input[type="email"], input[type="password"], input[type="number"], input[type="date"], select, textarea {
655
+ width: 100%;
656
+ padding: 10px 14px;
657
+ background: var(--bg);
658
+ border: 1px solid var(--border);
659
+ border-radius: 8px;
660
+ color: var(--text);
661
+ font-family: var(--font-sans);
662
+ font-size: 14px;
663
+ transition: all .2s;
664
+ }
665
+ input:focus, select:focus, textarea:focus {
666
+ outline: none;
667
+ background: var(--surface);
668
+ border-color: var(--accent);
669
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 20%, transparent);
670
+ }
671
+ label {
672
+ display: block;
673
+ font-size: 13px;
674
+ font-weight: 600;
675
+ margin-bottom: 6px;
676
+ color: var(--text-secondary);
677
+ }
678
+
679
+ /* ─── Tabs ─── */
680
+ .tab-bar {
681
+ display: flex;
682
+ border-bottom: 1px solid var(--border-subtle);
683
+ margin-bottom: var(--space-5);
684
+ gap: var(--space-4);
685
+ }
686
+ .tab-btn {
687
+ padding: 10px 4px;
688
+ background: none;
689
+ border: none;
690
+ border-bottom: 2px solid transparent;
691
+ cursor: pointer;
692
+ font-size: 14px;
693
+ font-weight: 600;
694
+ color: var(--text-tertiary);
695
+ margin-bottom: -1px;
696
+ transition: all .2s;
697
+ font-family: var(--font-sans);
698
+ }
699
+ .tab-btn:hover { color: var(--text); }
700
+ .tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); }
701
+ .search-tab { display: none; }
702
+ .search-tab.active { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow: hidden; }
703
+
704
+ /* ─── Utility ─── */
705
+ .empty-state {
706
+ display: flex;
707
+ flex-direction: column;
708
+ align-items: center;
709
+ justify-content: center;
710
+ padding: var(--space-6);
711
+ color: var(--text-tertiary);
712
+ font-size: 14px;
713
+ font-weight: 500;
714
+ gap: 12px;
715
+ min-height: 120px;
716
+ }
717
+ .loading {
718
+ display: inline-block;
719
+ width: 20px;
720
+ height: 20px;
721
+ border: 3px solid var(--border-subtle);
722
+ border-top-color: var(--accent);
723
+ border-radius: 50%;
724
+ animation: spin 0.8s linear infinite;
725
+ }
726
+ @keyframes spin { to { transform: rotate(360deg); } }
727
+ .hidden { display: none !important; }
728
+ .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
729
+ @media (max-width: 900px) { .grid-2 { grid-template-columns: 1fr; } .header-center { display: none; } }
730
+
731
+ /* ─── Scrollbar ─── */
732
+ * { scrollbar-width: thin; scrollbar-color: var(--border-subtle) transparent; }
733
+ *::-webkit-scrollbar { width: 6px; height: 6px; }
734
+ *::-webkit-scrollbar-track { background: transparent; }
735
+ *::-webkit-scrollbar-thumb { background: var(--border-subtle); border-radius: 4px; }
736
+ *::-webkit-scrollbar-thumb:hover { background: var(--text-tertiary); }
737
+
738
+ /* ─── Custom UI Elements ─── */
739
+ .stage-chip {
740
+ display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px;
741
+ background: var(--surface-raised); border: 1px solid var(--border); border-radius: 20px;
742
+ font-size: 11px; font-weight: 600; color: var(--text-secondary); cursor: pointer; transition: all .2s;
743
+ }
744
+ .stage-chip.active { color: var(--accent); border-color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
745
+ .stage-chip.active::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; animation: pulse 1.5s infinite; }
746
+
747
+ .source-pill {
748
+ display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px;
749
+ background: var(--surface-raised); border: 1px solid var(--border); border-radius: 20px;
750
+ font-size: 13px; font-weight: 500; color: var(--text-secondary); cursor: pointer; transition: all .2s;
751
+ }
752
+ .source-pill input[type=checkbox] { position: absolute; opacity: 0; width: 0; height: 0; }
753
+ .source-pill:has(input:checked) { border-color: var(--accent); background: var(--accent); color: #fff; }
754
+
755
+ /* Markdown Styles (Minimalistic) */
756
+ .markdown { line-height: 1.6; color: var(--text); }
757
+ .markdown h1, .markdown h2, .markdown h3 { margin-top: 1.5em; margin-bottom: 0.5em; color: var(--text); font-weight: 700; }
758
+ .markdown h1 { font-size: 1.8em; border-bottom: 1px solid var(--border-subtle); padding-bottom: 0.3em; }
759
+ .markdown p { margin-bottom: 1em; }
760
+ .markdown a { color: var(--accent); text-decoration: none; font-weight: 500; }
761
+ .markdown a:hover { text-decoration: underline; }
762
+ .markdown pre { background: var(--bg); padding: 1em; border-radius: 8px; overflow-x: auto; border: 1px solid var(--border); }
763
+ .markdown code { font-family: var(--font-mono); font-size: 0.9em; background: var(--bg); padding: 0.2em 0.4em; border-radius: 4px; color: var(--accent); }
764
+ .markdown pre code { background: transparent; padding: 0; color: inherit; }
765
+
766
+ /* Command Palette */
767
+ .cmd-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(4px); z-index: 1000; display: flex; align-items: flex-start; justify-content: center; padding-top: 10vh; }
768
+ .cmd-box { width: 600px; background: var(--surface); border-radius: 16px; box-shadow: 0 20px 40px rgba(0,0,0,0.2); overflow: hidden; border: 1px solid var(--border); }
769
+ .cmd-input-wrap { padding: 16px 20px; border-bottom: 1px solid var(--border-subtle); display: flex; align-items: center; gap: 12px; }
770
+ .cmd-input { flex: 1; border: none; background: transparent; font-size: 18px; color: var(--text); outline: none; }
771
+
772
+ /* Drawer */
773
+ .drawer-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.3); z-index: 900; opacity: 0; pointer-events: none; transition: opacity .2s; }
774
+ .drawer-overlay.open { opacity: 1; pointer-events: auto; }
775
+ .drawer { position: fixed; top: 0; right: 0; bottom: 0; width: 500px; background: var(--surface); box-shadow: -4px 0 24px rgba(0,0,0,0.1); transform: translateX(100%); transition: transform .3s cubic-bezier(0.16,1,0.3,1); z-index: 901; display: flex; flex-direction: column; }
776
+ .drawer.open { transform: translateX(0); }
777
+ .drawer-header { padding: 20px; border-bottom: 1px solid var(--border-subtle); display: flex; justify-content: space-between; align-items: center; }
778
+ .drawer-title { font-size: 18px; font-weight: 700; }
779
+ .drawer-body { flex: 1; overflow-y: auto; padding: 24px; }
780
+ .drawer-actions { padding: 16px 20px; border-top: 1px solid var(--border-subtle); background: var(--surface-raised); }
781
+
782
+ /* Wiki Nav */
783
+ #wiki-nav { width: 240px; border-right: 1px solid var(--border-subtle); overflow-y: auto; padding: 20px 12px; }
784
+ .wiki-nav-item { padding: 8px 12px; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500; color: var(--text-secondary); transition: all .2s; }
785
+ .wiki-nav-item:hover { background: var(--surface-raised); color: var(--text); }
786
+ .wiki-nav-item.active { background: color-mix(in srgb, var(--accent) 10%, transparent); color: var(--accent); }
787
+ `;
788
+
789
+ // Extract everything from <style> to </style>
790
+ const startIdx = html.indexOf('<style>');
791
+ const endIdx = html.indexOf('</style>', startIdx);
792
+
793
+ if (startIdx !== -1 && endIdx !== -1) {
794
+ const finalHtml = html.substring(0, startIdx + 7) + '\n' + newCss + '\n ' + html.substring(endIdx);
795
+ fs.writeFileSync(file, finalHtml, 'utf8');
796
+ console.log('Successfully updated CSS block in ui.html');
797
+ } else {
798
+ console.error('Could not find <style> block in ui.html');
799
+ }