dsh-codegraph-visualizer 0.1.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.
@@ -0,0 +1,2404 @@
1
+ /* ============================================================================
2
+ * DSH CodeGraph Visualizer — Modern UI Styles
3
+ * Follows dsh-web-ui design tokens (--dsw-* CSS custom properties).
4
+ * WCAG 2.2 AA compliant contrast, backdrop-blur glassmorphism, smooth motion.
5
+ * ============================================================================ */
6
+
7
+ :root {
8
+ /* DSH theme bridge — consume host --dsw-* tokens with safe fallbacks.
9
+ * DSH does not expose CSS custom properties; fallbacks below match the
10
+ * actual computed values from DSH's light theme (measured via DevTools). */
11
+ --cg-bg: var(--dsw-bg, #ffffff);
12
+ --cg-surface: var(--dsw-surface, #f9fafb);
13
+ --cg-surface-hover: var(--dsw-surface-hover, #f3f4f6);
14
+ --cg-surface-active: var(--dsw-surface-active, #e5e7eb);
15
+ --cg-border: var(--dsw-border, rgba(0, 0, 0, 0.04));
16
+ --cg-border-strong: var(--dsw-border-strong, rgba(0, 0, 0, 0.1));
17
+ --cg-text: var(--dsw-fg, #0f1115);
18
+ --cg-text-secondary: var(--dsw-fg-secondary, #61666b);
19
+ --cg-text-tertiary: var(--dsw-fg-tertiary, #9ca0a5);
20
+ --cg-accent: var(--dsw-accent, #263148);
21
+ --cg-accent-hover: var(--dsw-accent-hover, #1a2230);
22
+ --cg-accent-soft: var(--dsw-accent-soft, rgba(38, 49, 72, 0.1));
23
+ --cg-success: #10b981;
24
+ --cg-warning: #f59e0b;
25
+ --cg-error: #ef4444;
26
+ --cg-info: #3b82f6;
27
+
28
+ /* Node type semantic colors — light theme */
29
+ --cg-node-default: #263148;
30
+ --cg-node-function: #059669;
31
+ --cg-node-class: #1a2230;
32
+ --cg-node-variable: #d97706;
33
+ --cg-node-module: #db2777;
34
+ --cg-node-interface: #0d9488;
35
+
36
+ /* Edge type semantic colors — light theme */
37
+ --cg-edge-default: rgba(0, 0, 0, 0.1);
38
+ --cg-edge-call: #3b82f6;
39
+ --cg-edge-import: #10b981;
40
+ --cg-edge-extend: #ec4899;
41
+ --cg-edge-implement: #0d9488;
42
+ --cg-edge-dependency: #f59e0b;
43
+
44
+ /* Highlight / analysis colors — light theme */
45
+ --cg-hover-border: #1a2230;
46
+ --cg-impact-d1: #f59e0b;
47
+ --cg-impact-d2: #fbbf24;
48
+ --cg-impact-d3: #fde68a;
49
+ --cg-inheritance-extend: #ec4899;
50
+ --cg-inheritance-implement: #14b8a6;
51
+ --cg-cluster-bg: rgba(38, 49, 72, 0.10);
52
+ --cg-cluster-border: #263148;
53
+ --cg-cluster-hover-bg: rgba(38, 49, 72, 0.25);
54
+ --cg-cluster-hover-border: #1a2230;
55
+ --cg-cluster-edge: #263148;
56
+ --cg-cluster-edge-label-bg: #f9fafb;
57
+
58
+ /* Typography — match DSH's actual font stack including CJK fonts */
59
+ --cg-font-sans: var(--dsw-font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif);
60
+ --cg-font-mono: var(--dsw-font-mono, "JetBrains Mono", "Fira Code", Consolas, "Microsoft YaHei", monospace);
61
+
62
+ /* Elevation */
63
+ --cg-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
64
+ --cg-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
65
+ --cg-shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.14);
66
+
67
+ /* Radii */
68
+ --cg-radius: 12px;
69
+ --cg-radius-sm: 8px;
70
+ --cg-radius-xs: 4px;
71
+
72
+ /* Motion */
73
+ --cg-ease: cubic-bezier(0.4, 0, 0.2, 1);
74
+ --cg-ease-out: cubic-bezier(0, 0, 0.2, 1);
75
+ --cg-transition: 180ms var(--cg-ease);
76
+ --cg-transition-slow: 280ms var(--cg-ease);
77
+
78
+ /* Layout */
79
+ --cg-toolbar-h: 44px;
80
+ --cg-statusbar-h: 28px;
81
+ }
82
+
83
+ /* DSH Dark theme — activated when body[data-ds-dark-theme] is set.
84
+ * Values measured from DSH's actual dark theme via DevTools. */
85
+ body[data-ds-dark-theme] {
86
+ --cg-bg: var(--dsw-bg, #151517);
87
+ --cg-surface: var(--dsw-surface, #232324);
88
+ --cg-surface-hover: var(--dsw-surface-hover, #2a2a2c);
89
+ --cg-surface-active: var(--dsw-surface-active, #333335);
90
+ --cg-border: var(--dsw-border, rgba(255, 255, 255, 0.08));
91
+ --cg-border-strong: var(--dsw-border-strong, rgba(255, 255, 255, 0.14));
92
+ --cg-text: var(--dsw-fg, #f9fafb);
93
+ --cg-text-secondary: var(--dsw-fg-secondary, #cfd3d6);
94
+ --cg-text-tertiary: var(--dsw-fg-tertiary, #a8acb0);
95
+ --cg-accent: var(--dsw-accent, #6366f1);
96
+ --cg-accent-hover: var(--dsw-accent-hover, #818cf8);
97
+ --cg-accent-soft: var(--dsw-accent-soft, rgba(99, 102, 241, 0.12));
98
+
99
+ /* Node type semantic colors — dark theme */
100
+ --cg-node-default: #6366f1;
101
+ --cg-node-function: #10b981;
102
+ --cg-node-class: #818cf8;
103
+ --cg-node-variable: #f59e0b;
104
+ --cg-node-module: #ec4899;
105
+ --cg-node-interface: #14b8a6;
106
+
107
+ /* Edge type semantic colors — dark theme */
108
+ --cg-edge-default: rgba(255, 255, 255, 0.14);
109
+ --cg-edge-call: #60a5fa;
110
+ --cg-edge-import: #34d399;
111
+ --cg-edge-extend: #f472b6;
112
+ --cg-edge-implement: #2dd4bf;
113
+ --cg-edge-dependency: #fbbf24;
114
+
115
+ /* Highlight / analysis colors — dark theme */
116
+ --cg-hover-border: #818cf8;
117
+ --cg-impact-d1: #f59e0b;
118
+ --cg-impact-d2: #fbbf24;
119
+ --cg-impact-d3: #fde68a;
120
+ --cg-inheritance-extend: #f472b6;
121
+ --cg-inheritance-implement: #2dd4bf;
122
+ --cg-cluster-bg: rgba(99, 102, 241, 0.15);
123
+ --cg-cluster-border: #818cf8;
124
+ --cg-cluster-hover-bg: rgba(99, 102, 241, 0.35);
125
+ --cg-cluster-hover-border: #a5b4fc;
126
+ --cg-cluster-edge: #818cf8;
127
+ --cg-cluster-edge-label-bg: #232324;
128
+
129
+ --cg-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.18);
130
+ --cg-shadow: 0 4px 16px rgba(0, 0, 0, 0.28);
131
+ --cg-shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.36);
132
+ }
133
+
134
+ /* ---- Panel container ------------------------------------------------------ */
135
+
136
+ .graph-panel {
137
+ position: relative;
138
+ box-sizing: border-box;
139
+ width: 100%;
140
+ height: 100%;
141
+ z-index: 1000;
142
+ display: flex;
143
+ flex-direction: column;
144
+ background: var(--cg-surface);
145
+ border: 1px solid var(--cg-border);
146
+ border-radius: var(--cg-radius);
147
+ box-shadow: var(--cg-shadow-lg);
148
+ overflow: hidden;
149
+ pointer-events: auto;
150
+ font-family: var(--cg-font-sans);
151
+ color: var(--cg-text);
152
+ transition:
153
+ opacity var(--cg-transition),
154
+ transform var(--cg-transition);
155
+ contain: layout paint style;
156
+ }
157
+
158
+ .graph-panel.collapsed {
159
+ width: 52px;
160
+ height: 52px;
161
+ border-radius: 50%;
162
+ box-shadow: var(--cg-shadow);
163
+ }
164
+
165
+ .graph-panel.collapsed .graph-toolbar,
166
+ .graph-panel.collapsed .graph-container,
167
+ .graph-panel.collapsed .search-bar,
168
+ .graph-panel.collapsed .loading-overlay,
169
+ .graph-panel.collapsed .error-overlay,
170
+ .graph-panel.collapsed .empty-state,
171
+ .graph-panel.collapsed .node-detail-panel,
172
+ .graph-panel.collapsed .status-bar,
173
+ .graph-panel.collapsed .mini-map {
174
+ display: none;
175
+ }
176
+
177
+ .graph-panel.collapsed .collapse-fab {
178
+ display: flex;
179
+ }
180
+
181
+ /* ---- Collapse FAB --------------------------------------------------------- */
182
+
183
+ .collapse-fab {
184
+ display: none;
185
+ align-items: center;
186
+ justify-content: center;
187
+ width: 100%;
188
+ height: 100%;
189
+ cursor: pointer;
190
+ font-size: 22px;
191
+ color: var(--cg-text);
192
+ user-select: none;
193
+ transition: transform var(--cg-transition);
194
+ }
195
+
196
+ .collapse-fab:hover {
197
+ transform: scale(1.08);
198
+ }
199
+
200
+ /* ---- Toolbar ------------------------------------------------------------- */
201
+
202
+ .graph-toolbar {
203
+ display: flex;
204
+ align-items: center;
205
+ gap: 6px;
206
+ min-height: var(--cg-toolbar-h);
207
+ padding: 4px 10px;
208
+ background: var(--cg-surface);
209
+ border-bottom: 1px solid var(--cg-border);
210
+ flex-shrink: 0;
211
+ flex-wrap: wrap;
212
+ overflow: visible;
213
+ }
214
+
215
+
216
+ .toolbar-left {
217
+ display: flex;
218
+ align-items: center;
219
+ gap: 6px;
220
+ font-size: 12px;
221
+ color: var(--cg-text-secondary);
222
+ white-space: nowrap;
223
+ font-variant-numeric: tabular-nums;
224
+ }
225
+
226
+ .toolbar-center {
227
+ display: flex;
228
+ align-items: center;
229
+ gap: 8px;
230
+ flex: 1;
231
+ justify-content: center;
232
+ }
233
+
234
+ .toolbar-right {
235
+ display: flex;
236
+ align-items: center;
237
+ gap: 6px;
238
+ }
239
+
240
+ .toolbar-group {
241
+ display: flex;
242
+ align-items: center;
243
+ gap: 3px;
244
+ }
245
+
246
+ .toolbar-separator {
247
+ width: 1px;
248
+ height: 18px;
249
+ background: var(--cg-border);
250
+ opacity: 0.6;
251
+ flex-shrink: 0;
252
+ }
253
+
254
+ .node-count {
255
+ font-weight: 600;
256
+ letter-spacing: 0.01em;
257
+ }
258
+
259
+ .node-count .dot-sep {
260
+ color: var(--cg-text-tertiary);
261
+ margin: 0 4px;
262
+ }
263
+
264
+ /* ---- Type badges (node type stats in toolbar) ---------------------------- */
265
+
266
+ .type-badge {
267
+ display: inline-flex;
268
+ align-items: center;
269
+ padding: 1px 6px;
270
+ font-size: 10px;
271
+ font-weight: 600;
272
+ font-family: var(--cg-font-mono);
273
+ border-radius: var(--cg-radius-xs);
274
+ letter-spacing: 0.02em;
275
+ white-space: nowrap;
276
+ }
277
+
278
+ .type-badge.function {
279
+ background: rgba(16, 185, 129, 0.14);
280
+ color: var(--cg-success);
281
+ }
282
+
283
+ .type-badge.class {
284
+ background: var(--cg-accent-soft);
285
+ color: var(--cg-accent-hover);
286
+ }
287
+
288
+ .type-badge.interface {
289
+ background: rgba(20, 184, 166, 0.14);
290
+ color: #14b8a6;
291
+ }
292
+
293
+ /* ---- Layout switcher (segmented control) --------------------------------- */
294
+
295
+ .layout-buttons {
296
+ display: flex;
297
+ gap: 2px;
298
+ background: var(--cg-bg);
299
+ border: 1px solid var(--cg-border);
300
+ border-radius: var(--cg-radius-sm);
301
+ padding: 2px;
302
+ }
303
+
304
+ .layout-btn {
305
+ padding: 3px 8px;
306
+ border: none;
307
+ background: transparent;
308
+ color: var(--cg-text-secondary);
309
+ font-size: 10px;
310
+ font-weight: 500;
311
+ border-radius: var(--cg-radius-xs);
312
+ cursor: pointer;
313
+ transition: all var(--cg-transition);
314
+ text-transform: capitalize;
315
+ font-family: var(--cg-font-sans);
316
+ }
317
+
318
+ .layout-btn:hover {
319
+ color: var(--cg-text);
320
+ background: var(--cg-surface-hover);
321
+ }
322
+
323
+ .layout-btn.active {
324
+ color: var(--cg-text);
325
+ background: var(--cg-accent);
326
+ box-shadow: 0 1px 3px rgba(99, 102, 241, 0.4);
327
+ }
328
+
329
+ /* ---- Graph type switcher (segmented control) ----------------------------- */
330
+
331
+ .graph-type-buttons {
332
+ display: flex;
333
+ gap: 2px;
334
+ background: var(--cg-bg);
335
+ border: 1px solid var(--cg-border);
336
+ border-radius: var(--cg-radius-sm);
337
+ padding: 2px;
338
+ }
339
+
340
+ .graph-type-btn {
341
+ padding: 3px 8px;
342
+ border: none;
343
+ background: transparent;
344
+ color: var(--cg-text-secondary);
345
+ font-size: 10px;
346
+ font-weight: 500;
347
+ border-radius: var(--cg-radius-xs);
348
+ cursor: pointer;
349
+ transition: all var(--cg-transition);
350
+ font-family: var(--cg-font-sans);
351
+ }
352
+
353
+ .graph-type-btn:hover {
354
+ color: var(--cg-text);
355
+ background: var(--cg-surface-hover);
356
+ }
357
+
358
+ .graph-type-btn.active {
359
+ color: var(--cg-text);
360
+ background: var(--cg-success);
361
+ box-shadow: 0 1px 3px rgba(16, 185, 129, 0.4);
362
+ }
363
+
364
+ /* ---- Select -------------------------------------------------------------- */
365
+
366
+ .filter-select {
367
+ padding: 5px 24px 5px 8px;
368
+ background: var(--cg-bg);
369
+ border: 1px solid var(--cg-border);
370
+ border-radius: var(--cg-radius-sm);
371
+ color: var(--cg-text);
372
+ font-size: 11px;
373
+ font-family: var(--cg-font-sans);
374
+ cursor: pointer;
375
+ outline: none;
376
+ appearance: none;
377
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='%239ca0b8' d='M0 0l5 6 5-6z'/%3E%3C/svg%3E");
378
+ background-repeat: no-repeat;
379
+ background-position: right 8px center;
380
+ transition: border-color var(--cg-transition);
381
+ }
382
+
383
+ .filter-select:hover {
384
+ border-color: var(--cg-accent);
385
+ }
386
+
387
+ .filter-select:focus-visible {
388
+ border-color: var(--cg-accent);
389
+ box-shadow: 0 0 0 2px var(--cg-accent-soft);
390
+ }
391
+
392
+ .depth-select {
393
+ padding: 5px 24px 5px 8px;
394
+ background: var(--cg-bg);
395
+ border: 1px solid var(--cg-border);
396
+ border-radius: var(--cg-radius-sm);
397
+ color: var(--cg-text);
398
+ font-size: 11px;
399
+ font-family: var(--cg-font-sans);
400
+ cursor: pointer;
401
+ outline: none;
402
+ appearance: none;
403
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='%239ca0b8' d='M0 0l5 6 5-6z'/%3E%3C/svg%3E");
404
+ background-repeat: no-repeat;
405
+ background-position: right 8px center;
406
+ transition: border-color var(--cg-transition);
407
+ }
408
+
409
+ .depth-select:hover {
410
+ border-color: var(--cg-accent);
411
+ }
412
+
413
+ .depth-select:focus-visible {
414
+ border-color: var(--cg-accent);
415
+ box-shadow: 0 0 0 2px var(--cg-accent-soft);
416
+ }
417
+
418
+ /* ---- Icon buttons -------------------------------------------------------- */
419
+
420
+ .search-btn,
421
+ .theme-btn,
422
+ .export-btn,
423
+ .collapse-btn,
424
+ .chain-btn,
425
+ .cycle-btn,
426
+ .impact-btn,
427
+ .inheritance-btn,
428
+ .minimap-btn,
429
+ .refresh-btn {
430
+ width: 28px;
431
+ height: 28px;
432
+ display: flex;
433
+ align-items: center;
434
+ justify-content: center;
435
+ border: 1px solid var(--cg-border);
436
+ background: var(--cg-bg);
437
+ border-radius: var(--cg-radius-sm);
438
+ cursor: pointer;
439
+ font-size: 14px;
440
+ transition: all var(--cg-transition);
441
+ position: relative;
442
+ flex-shrink: 0;
443
+ }
444
+
445
+ .search-btn:hover,
446
+ .theme-btn:hover,
447
+ .export-btn:hover,
448
+ .collapse-btn:hover,
449
+ .chain-btn:hover,
450
+ .cycle-btn:hover,
451
+ .impact-btn:hover,
452
+ .inheritance-btn:hover,
453
+ .minimap-btn:hover,
454
+ .refresh-btn:hover {
455
+ background: var(--cg-surface-hover);
456
+ border-color: var(--cg-accent);
457
+ transform: translateY(-1px);
458
+ }
459
+
460
+ .search-btn:focus-visible,
461
+ .theme-btn:focus-visible,
462
+ .chain-btn:focus-visible,
463
+ .cycle-btn:focus-visible,
464
+ .impact-btn:focus-visible,
465
+ .inheritance-btn:focus-visible {
466
+ outline: 2px solid var(--cg-accent);
467
+ outline-offset: 2px;
468
+ }
469
+
470
+ .search-btn.active,
471
+ .chain-btn.active,
472
+ .cycle-btn.active,
473
+ .impact-btn.active,
474
+ .inheritance-btn.active,
475
+ .minimap-btn.active {
476
+ background: var(--cg-accent);
477
+ border-color: var(--cg-accent-hover);
478
+ color: var(--cg-text);
479
+ box-shadow: 0 1px 4px rgba(99, 102, 241, 0.45);
480
+ }
481
+
482
+ /* ---- Export menu --------------------------------------------------------- */
483
+
484
+ .export-menu {
485
+ position: relative;
486
+ }
487
+
488
+ .export-dropdown {
489
+ position: absolute;
490
+ top: 100%;
491
+ right: 0;
492
+ margin-top: 6px;
493
+ background: var(--cg-surface);
494
+ border: 1px solid var(--cg-border);
495
+ border-radius: var(--cg-radius-sm);
496
+ box-shadow: var(--cg-shadow);
497
+ display: flex;
498
+ flex-direction: column;
499
+ gap: 2px;
500
+ padding: 4px;
501
+ z-index: 20;
502
+ min-width: 120px;
503
+ animation: cg-dropdown-in 120ms var(--cg-ease-out);
504
+ }
505
+
506
+ @keyframes cg-dropdown-in {
507
+ from { opacity: 0; transform: translateY(-4px); }
508
+ to { opacity: 1; transform: translateY(0); }
509
+ }
510
+
511
+ .export-dropdown button {
512
+ padding: 7px 14px;
513
+ border: none;
514
+ background: transparent;
515
+ color: var(--cg-text);
516
+ font-size: 12px;
517
+ font-family: var(--cg-font-sans);
518
+ border-radius: var(--cg-radius-xs);
519
+ cursor: pointer;
520
+ text-align: left;
521
+ transition: background var(--cg-transition);
522
+ }
523
+
524
+ .export-dropdown button:hover {
525
+ background: var(--cg-surface-hover);
526
+ }
527
+
528
+ /* ---- Search bar ---------------------------------------------------------- */
529
+
530
+ .search-bar {
531
+ display: flex;
532
+ align-items: center;
533
+ gap: 8px;
534
+ padding: 8px 12px;
535
+ background: var(--cg-bg);
536
+ border-bottom: 1px solid var(--cg-border);
537
+ flex-shrink: 0;
538
+ animation: cg-slide-down 160ms var(--cg-ease-out);
539
+ }
540
+
541
+ @keyframes cg-slide-down {
542
+ from { opacity: 0; transform: translateY(-8px); }
543
+ to { opacity: 1; transform: translateY(0); }
544
+ }
545
+
546
+ .search-bar input {
547
+ flex: 1;
548
+ padding: 7px 12px;
549
+ background: var(--cg-surface);
550
+ border: 1px solid var(--cg-border);
551
+ border-radius: var(--cg-radius-sm);
552
+ color: var(--cg-text);
553
+ font-size: 13px;
554
+ font-family: var(--cg-font-sans);
555
+ outline: none;
556
+ transition: border-color var(--cg-transition), box-shadow var(--cg-transition);
557
+ }
558
+
559
+ .search-bar input:focus {
560
+ border-color: var(--cg-accent);
561
+ box-shadow: 0 0 0 3px var(--cg-accent-soft);
562
+ }
563
+
564
+ .search-bar input::placeholder {
565
+ color: var(--cg-text-tertiary);
566
+ }
567
+
568
+ .search-bar button {
569
+ width: 30px;
570
+ height: 30px;
571
+ border: 1px solid var(--cg-border);
572
+ background: var(--cg-surface);
573
+ border-radius: var(--cg-radius-sm);
574
+ color: var(--cg-text-secondary);
575
+ cursor: pointer;
576
+ font-size: 13px;
577
+ transition: all var(--cg-transition);
578
+ }
579
+
580
+ .search-bar button:hover {
581
+ background: var(--cg-surface-hover);
582
+ color: var(--cg-text);
583
+ }
584
+
585
+ .search-hint {
586
+ font-size: 10px;
587
+ color: var(--cg-text-tertiary);
588
+ margin-left: 4px;
589
+ font-family: var(--cg-font-mono);
590
+ white-space: nowrap;
591
+ }
592
+
593
+ /* ---- Overlays (loading / error / empty) ---------------------------------- */
594
+
595
+ .error-boundary-fallback {
596
+ position: absolute;
597
+ inset: 0;
598
+ display: flex;
599
+ align-items: center;
600
+ justify-content: center;
601
+ flex-direction: column;
602
+ gap: 14px;
603
+ background: var(--cg-bg);
604
+ z-index: 10;
605
+ padding: 24px;
606
+ }
607
+
608
+ .error-boundary-fallback h3 {
609
+ margin: 0;
610
+ font-size: 16px;
611
+ font-weight: 600;
612
+ color: var(--cg-error);
613
+ }
614
+
615
+ .error-boundary-fallback p {
616
+ margin: 0;
617
+ font-size: 13px;
618
+ color: var(--cg-text-secondary);
619
+ text-align: center;
620
+ max-width: 320px;
621
+ word-break: break-word;
622
+ }
623
+
624
+ .error-boundary-fallback button {
625
+ padding: 6px 16px;
626
+ border-radius: var(--cg-radius-xs);
627
+ border: 1px solid var(--cg-border-strong);
628
+ background: var(--cg-surface);
629
+ color: var(--cg-text);
630
+ font-size: 13px;
631
+ cursor: pointer;
632
+ transition: background var(--cg-transition);
633
+ }
634
+
635
+ .error-boundary-fallback button:hover {
636
+ background: var(--cg-surface-hover);
637
+ }
638
+
639
+ .loading-overlay,
640
+ .error-overlay,
641
+ .empty-state {
642
+ position: absolute;
643
+ inset: 0;
644
+ display: flex;
645
+ align-items: center;
646
+ justify-content: center;
647
+ flex-direction: column;
648
+ gap: 14px;
649
+ background: var(--cg-bg);
650
+ z-index: 5;
651
+ }
652
+
653
+ .loading-overlay {
654
+ opacity: 0.9;
655
+ backdrop-filter: blur(4px);
656
+ }
657
+
658
+ .spinner {
659
+ width: 40px;
660
+ height: 40px;
661
+ position: relative;
662
+ }
663
+
664
+ .spinner::before,
665
+ .spinner::after {
666
+ content: '';
667
+ position: absolute;
668
+ inset: 0;
669
+ border-radius: 50%;
670
+ border: 2px solid transparent;
671
+ }
672
+
673
+ .spinner::before {
674
+ border-top-color: var(--cg-accent);
675
+ border-right-color: var(--cg-accent);
676
+ animation: cg-spin 0.8s var(--cg-ease) infinite;
677
+ }
678
+
679
+ .spinner::after {
680
+ border-bottom-color: var(--cg-accent-hover);
681
+ border-left-color: var(--cg-accent-hover);
682
+ animation: cg-spin 1.2s var(--cg-ease) infinite reverse;
683
+ inset: 6px;
684
+ }
685
+
686
+ @keyframes cg-spin {
687
+ to { transform: rotate(360deg); }
688
+ }
689
+
690
+ @keyframes cg-pulse {
691
+ 0%, 100% { opacity: 1; }
692
+ 50% { opacity: 0.55; }
693
+ }
694
+
695
+ .loading-overlay span,
696
+ .empty-state span {
697
+ color: var(--cg-text-secondary);
698
+ font-size: 13px;
699
+ }
700
+
701
+ .empty-state .empty-icon {
702
+ font-size: 40px;
703
+ opacity: 0.5;
704
+ }
705
+
706
+ .error-overlay span {
707
+ color: var(--cg-error);
708
+ font-size: 13px;
709
+ }
710
+
711
+ /* ---- Graph container ----------------------------------------------------- */
712
+
713
+ .graph-container {
714
+ flex: 1;
715
+ min-height: 0;
716
+ position: relative;
717
+ background: var(--cg-bg);
718
+ }
719
+
720
+ .graph-container canvas {
721
+ display: block;
722
+ }
723
+
724
+ /* ---- Node detail panel --------------------------------------------------- */
725
+
726
+ .node-detail-panel {
727
+ position: absolute;
728
+ left: 12px;
729
+ top: 12px;
730
+ width: 260px;
731
+ max-height: calc(100% - 24px);
732
+ background: var(--cg-surface);
733
+ border: 1px solid var(--cg-border);
734
+ border-radius: var(--cg-radius);
735
+ box-shadow: var(--cg-shadow);
736
+ padding: 14px;
737
+ z-index: 6;
738
+ overflow-y: auto;
739
+ backdrop-filter: blur(12px);
740
+ -webkit-backdrop-filter: blur(12px);
741
+ animation: cg-slide-right 160ms var(--cg-ease-out);
742
+ }
743
+
744
+ @keyframes cg-slide-right {
745
+ from { opacity: 0; transform: translateX(-12px); }
746
+ to { opacity: 1; transform: translateX(0); }
747
+ }
748
+
749
+ .node-detail-panel h3 {
750
+ margin: 0 0 10px;
751
+ font-size: 14px;
752
+ color: var(--cg-text);
753
+ font-weight: 600;
754
+ word-break: break-word;
755
+ }
756
+
757
+ .node-detail-panel .detail-header {
758
+ display: flex;
759
+ align-items: center;
760
+ gap: 8px;
761
+ margin-bottom: 10px;
762
+ }
763
+
764
+ .node-detail-panel .detail-header h3 {
765
+ margin: 0;
766
+ flex: 1;
767
+ }
768
+
769
+ .node-detail-panel .detail-type-icon {
770
+ display: inline-flex;
771
+ align-items: center;
772
+ justify-content: center;
773
+ width: 24px;
774
+ height: 24px;
775
+ border: 1.5px solid;
776
+ border-radius: var(--cg-radius-xs);
777
+ font-size: 10px;
778
+ font-weight: 700;
779
+ font-family: var(--cg-font-mono);
780
+ flex-shrink: 0;
781
+ }
782
+
783
+ .node-detail-panel .detail-row {
784
+ display: flex;
785
+ justify-content: space-between;
786
+ gap: 8px;
787
+ padding: 5px 0;
788
+ font-size: 12px;
789
+ border-bottom: 1px solid var(--cg-border);
790
+ }
791
+
792
+ .node-detail-panel .detail-label {
793
+ color: var(--cg-text-secondary);
794
+ flex-shrink: 0;
795
+ font-weight: 500;
796
+ }
797
+
798
+ .node-detail-panel .detail-value {
799
+ color: var(--cg-text);
800
+ text-align: right;
801
+ word-break: break-all;
802
+ font-family: var(--cg-font-mono);
803
+ font-size: 11px;
804
+ }
805
+
806
+ .node-detail-panel .close-btn {
807
+ position: absolute;
808
+ top: 10px;
809
+ right: 10px;
810
+ width: 24px;
811
+ height: 24px;
812
+ border: none;
813
+ background: transparent;
814
+ color: var(--cg-text-secondary);
815
+ cursor: pointer;
816
+ font-size: 14px;
817
+ border-radius: var(--cg-radius-xs);
818
+ transition: all var(--cg-transition);
819
+ display: flex;
820
+ align-items: center;
821
+ justify-content: center;
822
+ }
823
+
824
+ .node-detail-panel .close-btn:hover {
825
+ background: var(--cg-surface-hover);
826
+ color: var(--cg-text);
827
+ }
828
+
829
+ /* ---- Status bar ---------------------------------------------------------- */
830
+
831
+ .status-bar {
832
+ display: flex;
833
+ align-items: center;
834
+ gap: 12px;
835
+ height: var(--cg-statusbar-h);
836
+ padding: 0 12px;
837
+ background: var(--cg-surface);
838
+ border-top: 1px solid var(--cg-border);
839
+ font-size: 11px;
840
+ color: var(--cg-text-secondary);
841
+ flex-shrink: 0;
842
+ font-variant-numeric: tabular-nums;
843
+ }
844
+
845
+ .status-bar .status-item {
846
+ display: flex;
847
+ align-items: center;
848
+ gap: 4px;
849
+ white-space: nowrap;
850
+ }
851
+
852
+ .status-bar .status-dot {
853
+ width: 7px;
854
+ height: 7px;
855
+ border-radius: 50%;
856
+ background: var(--cg-success);
857
+ flex-shrink: 0;
858
+ }
859
+
860
+ .status-bar .status-dot.loading {
861
+ background: var(--cg-warning);
862
+ animation: cg-pulse 1s ease-in-out infinite;
863
+ }
864
+
865
+ .status-bar .status-dot.error {
866
+ background: var(--cg-error);
867
+ }
868
+
869
+ .status-bar .status-workspace {
870
+ color: var(--cg-accent);
871
+ font-weight: 500;
872
+ max-width: 200px;
873
+ overflow: hidden;
874
+ text-overflow: ellipsis;
875
+ white-space: nowrap;
876
+ padding: 0 6px;
877
+ border-left: 1px solid var(--cg-border);
878
+ margin-left: 4px;
879
+ font-family: var(--cg-font-mono);
880
+ font-size: 10px;
881
+ }
882
+
883
+ .status-bar .status-truncated {
884
+ color: var(--cg-warning);
885
+ font-size: 11px;
886
+ padding: 0 4px;
887
+ border-left: 1px solid var(--cg-border);
888
+ margin-left: 4px;
889
+ cursor: help;
890
+ }
891
+
892
+ .status-bar .status-spacer {
893
+ flex: 1;
894
+ }
895
+
896
+ .status-bar .status-time {
897
+ color: var(--cg-text-tertiary);
898
+ font-family: var(--cg-font-mono);
899
+ }
900
+
901
+ /* ---- Mini-map ------------------------------------------------------------ */
902
+
903
+ .mini-map {
904
+ position: absolute;
905
+ right: 12px;
906
+ bottom: calc(var(--cg-statusbar-h) + 12px);
907
+ width: 200px;
908
+ background: var(--cg-surface);
909
+ border: 1px solid var(--cg-border);
910
+ border-radius: var(--cg-radius);
911
+ box-shadow: var(--cg-shadow);
912
+ z-index: 6;
913
+ backdrop-filter: blur(10px);
914
+ -webkit-backdrop-filter: blur(10px);
915
+ overflow: hidden;
916
+ animation: cg-slide-up 160ms var(--cg-ease-out);
917
+ }
918
+
919
+ @keyframes cg-slide-up {
920
+ from { opacity: 0; transform: translateY(8px); }
921
+ to { opacity: 1; transform: translateY(0); }
922
+ }
923
+
924
+ .mini-map-header {
925
+ padding: 7px 12px;
926
+ font-size: 11px;
927
+ font-weight: 600;
928
+ color: var(--cg-text-secondary);
929
+ border-bottom: 1px solid var(--cg-border);
930
+ text-transform: uppercase;
931
+ letter-spacing: 0.06em;
932
+ display: flex;
933
+ justify-content: space-between;
934
+ align-items: center;
935
+ }
936
+
937
+ .mini-map-content {
938
+ padding: 10px 12px;
939
+ }
940
+
941
+ .mini-map-thumbnail {
942
+ position: relative;
943
+ margin-bottom: 8px;
944
+ border: 1px solid var(--cg-border);
945
+ border-radius: var(--cg-radius-sm);
946
+ overflow: hidden;
947
+ background: var(--cg-surface);
948
+ }
949
+
950
+ .mini-map-viewport {
951
+ border: 2px solid var(--cg-accent);
952
+ background: rgba(99, 102, 241, 0.1);
953
+ pointer-events: none;
954
+ transition: all 0.3s ease;
955
+ }
956
+
957
+ .mini-map-stats {
958
+ display: flex;
959
+ flex-direction: column;
960
+ gap: 6px;
961
+ }
962
+
963
+ .mini-map-stats div {
964
+ display: flex;
965
+ align-items: center;
966
+ gap: 8px;
967
+ font-size: 11px;
968
+ color: var(--cg-text-secondary);
969
+ }
970
+
971
+ .mini-map-stats .dot {
972
+ width: 9px;
973
+ height: 9px;
974
+ border-radius: 50%;
975
+ flex-shrink: 0;
976
+ }
977
+
978
+ .mini-map-total {
979
+ margin-top: 8px;
980
+ padding-top: 8px;
981
+ border-top: 1px solid var(--cg-border);
982
+ font-size: 11px;
983
+ font-weight: 600;
984
+ color: var(--cg-text);
985
+ }
986
+
987
+ /* ---- Tooltip (node hover) ------------------------------------------------ */
988
+
989
+ .cg-tooltip {
990
+ position: fixed;
991
+ z-index: 9999;
992
+ background: var(--cg-surface);
993
+ border: 1px solid var(--cg-border-strong);
994
+ border-radius: var(--cg-radius-sm);
995
+ box-shadow: var(--cg-shadow);
996
+ padding: 8px 12px;
997
+ font-size: 12px;
998
+ font-family: var(--cg-font-sans);
999
+ color: var(--cg-text);
1000
+ pointer-events: none;
1001
+ max-width: 320px;
1002
+ backdrop-filter: blur(12px);
1003
+ -webkit-backdrop-filter: blur(12px);
1004
+ animation: cg-tooltip-in 100ms var(--cg-ease-out);
1005
+ }
1006
+
1007
+ @keyframes cg-tooltip-in {
1008
+ from { opacity: 0; transform: translateY(4px); }
1009
+ to { opacity: 1; transform: translateY(0); }
1010
+ }
1011
+
1012
+ .cg-tooltip .tooltip-name {
1013
+ font-weight: 600;
1014
+ margin-bottom: 2px;
1015
+ }
1016
+
1017
+ .cg-tooltip .tooltip-path {
1018
+ color: var(--cg-text-secondary);
1019
+ font-family: var(--cg-font-mono);
1020
+ font-size: 11px;
1021
+ word-break: break-all;
1022
+ }
1023
+
1024
+ .cg-tooltip .tooltip-type {
1025
+ display: inline-block;
1026
+ margin-top: 4px;
1027
+ padding: 1px 6px;
1028
+ border-radius: var(--cg-radius-xs);
1029
+ font-size: 10px;
1030
+ font-weight: 600;
1031
+ text-transform: uppercase;
1032
+ background: var(--cg-accent-soft);
1033
+ color: var(--cg-accent-hover);
1034
+ }
1035
+
1036
+ .cg-tooltip .tooltip-edge-source {
1037
+ font-weight: 600;
1038
+ margin-bottom: 2px;
1039
+ }
1040
+
1041
+ .cg-tooltip .tooltip-edge-arrow {
1042
+ color: var(--cg-text-secondary);
1043
+ font-size: 11px;
1044
+ margin-bottom: 2px;
1045
+ }
1046
+
1047
+ .cg-tooltip .tooltip-edge-target {
1048
+ font-weight: 600;
1049
+ margin-bottom: 4px;
1050
+ }
1051
+
1052
+ /* ---- Resize handle ------------------------------------------------------- */
1053
+
1054
+ .graph-panel.resizable .resize-handle {
1055
+ position: absolute;
1056
+ width: 18px;
1057
+ height: 18px;
1058
+ bottom: 0;
1059
+ right: 0;
1060
+ cursor: nwse-resize;
1061
+ z-index: 10;
1062
+ }
1063
+
1064
+ .graph-panel.resizable .resize-handle::after {
1065
+ content: '';
1066
+ position: absolute;
1067
+ bottom: 4px;
1068
+ right: 4px;
1069
+ width: 10px;
1070
+ height: 10px;
1071
+ border-right: 2px solid var(--cg-text-tertiary);
1072
+ border-bottom: 2px solid var(--cg-text-tertiary);
1073
+ transition: border-color var(--cg-transition);
1074
+ }
1075
+
1076
+ .graph-panel.resizable .resize-handle:hover::after {
1077
+ border-right-color: var(--cg-accent);
1078
+ border-bottom-color: var(--cg-accent);
1079
+ }
1080
+
1081
+ /* ---- Scrollbar styling --------------------------------------------------- */
1082
+
1083
+ .node-detail-panel::-webkit-scrollbar,
1084
+ .mini-map::-webkit-scrollbar {
1085
+ width: 6px;
1086
+ }
1087
+
1088
+ .node-detail-panel::-webkit-scrollbar-track,
1089
+ .mini-map::-webkit-scrollbar-track {
1090
+ background: transparent;
1091
+ }
1092
+
1093
+ .node-detail-panel::-webkit-scrollbar-thumb,
1094
+ .mini-map::-webkit-scrollbar-thumb {
1095
+ background: var(--cg-border-strong);
1096
+ border-radius: 3px;
1097
+ }
1098
+
1099
+ .node-detail-panel::-webkit-scrollbar-thumb:hover,
1100
+ .mini-map::-webkit-scrollbar-thumb:hover {
1101
+ background: var(--cg-text-tertiary);
1102
+ }
1103
+
1104
+ /* ---- Responsive ---------------------------------------------------------- */
1105
+
1106
+ /* Small panels (DSH sidebar tab, narrow bottom panel) */
1107
+ @media (max-width: 480px) {
1108
+ .graph-panel {
1109
+ border-radius: var(--cg-radius-sm);
1110
+ }
1111
+
1112
+ .graph-toolbar {
1113
+ padding: 0 8px;
1114
+ gap: 4px;
1115
+ }
1116
+
1117
+ .toolbar-left {
1118
+ font-size: 11px;
1119
+ }
1120
+
1121
+ .toolbar-center {
1122
+ gap: 4px;
1123
+ }
1124
+
1125
+ .toolbar-right {
1126
+ gap: 4px;
1127
+ }
1128
+
1129
+ .layout-btn,
1130
+ .graph-type-btn {
1131
+ padding: 3px 6px;
1132
+ font-size: 10px;
1133
+ }
1134
+
1135
+ .search-btn,
1136
+ .theme-btn,
1137
+ .export-btn,
1138
+ .collapse-btn,
1139
+ .chain-btn,
1140
+ .cycle-btn,
1141
+ .minimap-btn,
1142
+ .refresh-btn,
1143
+ .import-btn,
1144
+ .legend-btn,
1145
+ .lang-btn {
1146
+ width: 26px;
1147
+ height: 26px;
1148
+ font-size: 12px;
1149
+ }
1150
+
1151
+ .node-detail-panel {
1152
+ width: calc(100% - 24px);
1153
+ left: 12px;
1154
+ top: 12px;
1155
+ }
1156
+
1157
+ .legend-panel {
1158
+ width: 140px;
1159
+ }
1160
+
1161
+ .mini-map {
1162
+ width: 140px;
1163
+ }
1164
+
1165
+ .type-badge {
1166
+ display: none;
1167
+ }
1168
+
1169
+ .toolbar-separator {
1170
+ display: none;
1171
+ }
1172
+
1173
+ .graph-type-buttons {
1174
+ display: none;
1175
+ }
1176
+
1177
+ }
1178
+
1179
+ /* Medium panels (DSH sidebar medium width) */
1180
+ @media (max-width: 768px) {
1181
+ .graph-toolbar {
1182
+ padding: 0 8px;
1183
+ gap: 6px;
1184
+ }
1185
+
1186
+ .toolbar-center {
1187
+ gap: 6px;
1188
+ }
1189
+
1190
+ .toolbar-right {
1191
+ gap: 6px;
1192
+ }
1193
+
1194
+ .layout-btn,
1195
+ .graph-type-btn {
1196
+ padding: 3px 8px;
1197
+ font-size: 11px;
1198
+ }
1199
+
1200
+ .node-detail-panel {
1201
+ width: 220px;
1202
+ }
1203
+
1204
+ .legend-panel {
1205
+ width: 160px;
1206
+ }
1207
+
1208
+ .mini-map {
1209
+ width: 160px;
1210
+ }
1211
+
1212
+ .filter-select {
1213
+ font-size: 11px;
1214
+ }
1215
+
1216
+ .toolbar-separator {
1217
+ margin: 0 2px;
1218
+ }
1219
+
1220
+ }
1221
+
1222
+ /* Very small panels */
1223
+ @media (max-width: 320px) {
1224
+ .graph-toolbar {
1225
+ gap: 2px;
1226
+ }
1227
+
1228
+ .layout-buttons,
1229
+ .graph-type-buttons {
1230
+ padding: 1px;
1231
+ }
1232
+
1233
+ .layout-btn,
1234
+ .graph-type-btn {
1235
+ padding: 2px 4px;
1236
+ font-size: 9px;
1237
+ }
1238
+
1239
+ .filter-select {
1240
+ padding: 3px 20px 3px 6px;
1241
+ font-size: 10px;
1242
+ }
1243
+
1244
+ .node-count {
1245
+ font-size: 10px;
1246
+ }
1247
+
1248
+ .legend-panel,
1249
+ .mini-map {
1250
+ width: 120px;
1251
+ }
1252
+ }
1253
+
1254
+ /* Large screens — allow fixed floating panel */
1255
+ @media (min-width: 1200px) {
1256
+ .graph-panel.floating {
1257
+ position: fixed;
1258
+ right: 16px;
1259
+ bottom: 16px;
1260
+ width: 640px;
1261
+ height: 520px;
1262
+ }
1263
+ }
1264
+
1265
+ /* ---- Reduced motion ------------------------------------------------------ */
1266
+
1267
+ @media (prefers-reduced-motion: reduce) {
1268
+ *,
1269
+ *::before,
1270
+ *::after {
1271
+ animation-duration: 0.01ms !important;
1272
+ transition-duration: 0.01ms !important;
1273
+ }
1274
+ }
1275
+
1276
+ /* ---- Import button + Legend button + Lang button (share icon-button styles) -- */
1277
+
1278
+ .import-btn,
1279
+ .legend-btn,
1280
+ .lang-btn {
1281
+ width: 30px;
1282
+ height: 30px;
1283
+ display: flex;
1284
+ align-items: center;
1285
+ justify-content: center;
1286
+ border: 1px solid var(--cg-border);
1287
+ background: var(--cg-bg);
1288
+ border-radius: var(--cg-radius-sm);
1289
+ cursor: pointer;
1290
+ color: var(--cg-text-secondary);
1291
+ transition: all var(--cg-transition);
1292
+ flex-shrink: 0;
1293
+ }
1294
+
1295
+ .import-btn:hover,
1296
+ .legend-btn:hover,
1297
+ .lang-btn:hover {
1298
+ background: var(--cg-surface-hover);
1299
+ border-color: var(--cg-accent);
1300
+ color: var(--cg-text);
1301
+ transform: translateY(-1px);
1302
+ }
1303
+
1304
+ .import-btn:focus-visible,
1305
+ .legend-btn:focus-visible,
1306
+ .lang-btn:focus-visible {
1307
+ outline: 2px solid var(--cg-accent);
1308
+ outline-offset: 2px;
1309
+ }
1310
+
1311
+ .import-btn.active,
1312
+ .legend-btn.active,
1313
+ .lang-btn.active {
1314
+ background: var(--cg-accent);
1315
+ border-color: var(--cg-accent-hover);
1316
+ color: var(--cg-text);
1317
+ box-shadow: 0 1px 4px rgba(99, 102, 241, 0.45);
1318
+ }
1319
+
1320
+ .lang-label {
1321
+ font-size: 11px;
1322
+ font-weight: 600;
1323
+ font-family: var(--cg-font-sans);
1324
+ }
1325
+
1326
+ /* ---- Search bar icon ----------------------------------------------------- */
1327
+
1328
+ .search-bar-icon {
1329
+ color: var(--cg-text-tertiary);
1330
+ flex-shrink: 0;
1331
+ }
1332
+
1333
+ /* ---- Empty state (enhanced) ---------------------------------------------- */
1334
+
1335
+ .empty-state .empty-icon {
1336
+ font-size: 40px;
1337
+ opacity: 0.5;
1338
+ color: var(--cg-text-tertiary);
1339
+ }
1340
+
1341
+ .empty-state .empty-title {
1342
+ font-size: 15px;
1343
+ font-weight: 600;
1344
+ color: var(--cg-text);
1345
+ }
1346
+
1347
+ .empty-state .empty-subtitle {
1348
+ font-size: 12px;
1349
+ color: var(--cg-text-secondary);
1350
+ max-width: 280px;
1351
+ text-align: center;
1352
+ line-height: 1.5;
1353
+ }
1354
+
1355
+ .empty-actions {
1356
+ display: flex;
1357
+ gap: 10px;
1358
+ align-items: center;
1359
+ }
1360
+
1361
+ .empty-import-btn {
1362
+ display: inline-flex;
1363
+ align-items: center;
1364
+ gap: 6px;
1365
+ padding: 8px 16px;
1366
+ background: var(--cg-accent);
1367
+ color: var(--cg-text);
1368
+ border: none;
1369
+ border-radius: var(--cg-radius-sm);
1370
+ font-size: 13px;
1371
+ font-weight: 500;
1372
+ font-family: var(--cg-font-sans);
1373
+ cursor: pointer;
1374
+ transition: all var(--cg-transition);
1375
+ box-shadow: 0 2px 8px rgba(99, 102, 241, 0.3);
1376
+ }
1377
+
1378
+ .empty-import-btn:hover {
1379
+ background: var(--cg-accent-hover);
1380
+ transform: translateY(-1px);
1381
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
1382
+ }
1383
+
1384
+ .empty-scan-btn {
1385
+ display: inline-flex;
1386
+ align-items: center;
1387
+ gap: 6px;
1388
+ padding: 8px 16px;
1389
+ background: var(--cg-surface);
1390
+ color: var(--cg-text);
1391
+ border: 1px solid var(--cg-border-strong);
1392
+ border-radius: var(--cg-radius-sm);
1393
+ font-size: 13px;
1394
+ font-weight: 500;
1395
+ font-family: var(--cg-font-sans);
1396
+ cursor: pointer;
1397
+ transition: all var(--cg-transition);
1398
+ }
1399
+
1400
+ .empty-scan-btn:hover {
1401
+ background: var(--cg-surface-hover);
1402
+ transform: translateY(-1px);
1403
+ }
1404
+
1405
+ .empty-prereq-warning {
1406
+ display: flex;
1407
+ flex-direction: column;
1408
+ gap: 10px;
1409
+ padding: 12px 14px;
1410
+ background: rgba(245, 158, 11, 0.08);
1411
+ border: 1px solid rgba(245, 158, 11, 0.25);
1412
+ border-radius: var(--cg-radius-sm);
1413
+ color: var(--cg-text-primary);
1414
+ font-size: 12px;
1415
+ line-height: 1.4;
1416
+ max-width: 400px;
1417
+ text-align: left;
1418
+ }
1419
+
1420
+ .prereq-item {
1421
+ display: flex;
1422
+ flex-direction: column;
1423
+ gap: 4px;
1424
+ padding: 8px 0;
1425
+ border-top: 1px solid rgba(245, 158, 11, 0.15);
1426
+ }
1427
+
1428
+ .prereq-item:first-of-type {
1429
+ border-top: none;
1430
+ padding-top: 4px;
1431
+ }
1432
+
1433
+ .prereq-item-header {
1434
+ display: flex;
1435
+ align-items: center;
1436
+ gap: 6px;
1437
+ }
1438
+
1439
+ .prereq-status-dot {
1440
+ width: 8px;
1441
+ height: 8px;
1442
+ border-radius: 50%;
1443
+ flex-shrink: 0;
1444
+ }
1445
+
1446
+ .prereq-status-dot.ok {
1447
+ background: var(--cg-success, #22c55e);
1448
+ }
1449
+
1450
+ .prereq-status-dot.missing {
1451
+ background: #ef4444;
1452
+ }
1453
+
1454
+ .prereq-item-label {
1455
+ font-weight: 600;
1456
+ color: var(--cg-text-primary);
1457
+ }
1458
+
1459
+ .prereq-item-status {
1460
+ font-size: 11px;
1461
+ color: #ef4444;
1462
+ margin-left: auto;
1463
+ }
1464
+
1465
+ .prereq-item-desc {
1466
+ font-size: 11px;
1467
+ color: var(--cg-text-tertiary);
1468
+ padding-left: 14px;
1469
+ }
1470
+
1471
+ .watch-indicator {
1472
+ color: var(--cg-success, #22c55e);
1473
+ font-size: 8px;
1474
+ animation: pulse 2s ease-in-out infinite;
1475
+ }
1476
+
1477
+ @keyframes pulse {
1478
+ 0%, 100% { opacity: 1; }
1479
+ 50% { opacity: 0.4; }
1480
+ }
1481
+
1482
+ /* ---- Node detail extra properties ---------------------------------------- */
1483
+
1484
+ .node-detail-panel .detail-extra {
1485
+ margin-top: 10px;
1486
+ padding-top: 8px;
1487
+ border-top: 1px solid var(--cg-border);
1488
+ }
1489
+
1490
+ .node-detail-panel .detail-extra-title {
1491
+ font-size: 10px;
1492
+ font-weight: 600;
1493
+ text-transform: uppercase;
1494
+ letter-spacing: 0.06em;
1495
+ color: var(--cg-text-tertiary);
1496
+ margin-bottom: 6px;
1497
+ }
1498
+
1499
+ /* ---- Import panel -------------------------------------------------------- */
1500
+
1501
+ .import-panel {
1502
+ position: absolute;
1503
+ inset: var(--cg-toolbar-h) 0 var(--cg-statusbar-h) 0;
1504
+ background: var(--cg-bg);
1505
+ z-index: 15;
1506
+ display: flex;
1507
+ flex-direction: column;
1508
+ animation: cg-slide-down 160ms var(--cg-ease-out);
1509
+ }
1510
+
1511
+ .import-header {
1512
+ display: flex;
1513
+ align-items: center;
1514
+ justify-content: space-between;
1515
+ padding: 10px 14px;
1516
+ border-bottom: 1px solid var(--cg-border);
1517
+ }
1518
+
1519
+ .import-title {
1520
+ font-size: 13px;
1521
+ font-weight: 600;
1522
+ color: var(--cg-text);
1523
+ }
1524
+
1525
+ .import-close {
1526
+ width: 26px;
1527
+ height: 26px;
1528
+ display: flex;
1529
+ align-items: center;
1530
+ justify-content: center;
1531
+ border: none;
1532
+ background: transparent;
1533
+ color: var(--cg-text-secondary);
1534
+ cursor: pointer;
1535
+ border-radius: var(--cg-radius-xs);
1536
+ transition: all var(--cg-transition);
1537
+ }
1538
+
1539
+ .import-close:hover {
1540
+ background: var(--cg-surface-hover);
1541
+ color: var(--cg-text);
1542
+ }
1543
+
1544
+ .import-tabs {
1545
+ display: flex;
1546
+ gap: 2px;
1547
+ padding: 8px 14px;
1548
+ border-bottom: 1px solid var(--cg-border);
1549
+ }
1550
+
1551
+ .import-tabs button {
1552
+ display: inline-flex;
1553
+ align-items: center;
1554
+ gap: 6px;
1555
+ padding: 6px 14px;
1556
+ border: 1px solid var(--cg-border);
1557
+ background: transparent;
1558
+ color: var(--cg-text-secondary);
1559
+ font-size: 12px;
1560
+ font-family: var(--cg-font-sans);
1561
+ border-radius: var(--cg-radius-sm);
1562
+ cursor: pointer;
1563
+ transition: all var(--cg-transition);
1564
+ }
1565
+
1566
+ .import-tabs button:hover {
1567
+ background: var(--cg-surface-hover);
1568
+ color: var(--cg-text);
1569
+ }
1570
+
1571
+ .import-tabs button.active {
1572
+ background: var(--cg-accent);
1573
+ border-color: var(--cg-accent-hover);
1574
+ color: var(--cg-text);
1575
+ }
1576
+
1577
+ .import-body {
1578
+ flex: 1;
1579
+ padding: 16px 14px;
1580
+ overflow-y: auto;
1581
+ display: flex;
1582
+ flex-direction: column;
1583
+ gap: 12px;
1584
+ }
1585
+
1586
+
1587
+ .paste-zone,
1588
+ .workspace-zone {
1589
+ display: flex;
1590
+ flex-direction: column;
1591
+ gap: 10px;
1592
+ flex: 1;
1593
+ }
1594
+
1595
+ .workspace-zone {
1596
+ padding: 4px 0;
1597
+ }
1598
+
1599
+ .workspace-path-row {
1600
+ display: flex;
1601
+ align-items: center;
1602
+ gap: 6px;
1603
+ }
1604
+
1605
+ .workspace-path-icon {
1606
+ color: var(--cg-text-tertiary);
1607
+ }
1608
+
1609
+ .workspace-path-label {
1610
+ font-size: 12px;
1611
+ font-weight: 500;
1612
+ color: var(--cg-text-secondary);
1613
+ }
1614
+
1615
+ .workspace-path-value {
1616
+ padding: 8px 12px;
1617
+ background: var(--cg-surface);
1618
+ border: 1px solid var(--cg-border);
1619
+ border-radius: var(--cg-radius-sm);
1620
+ color: var(--cg-text);
1621
+ font-size: 12px;
1622
+ font-family: var(--cg-font-mono);
1623
+ word-break: break-all;
1624
+ line-height: 1.5;
1625
+ }
1626
+
1627
+ .workspace-hint {
1628
+ font-size: 11px;
1629
+ color: var(--cg-text-tertiary);
1630
+ }
1631
+
1632
+ .workspace-path-input {
1633
+ padding: 8px 12px;
1634
+ background: var(--cg-surface);
1635
+ border: 1px solid var(--cg-border);
1636
+ border-radius: var(--cg-radius-sm);
1637
+ color: var(--cg-text);
1638
+ font-size: 12px;
1639
+ font-family: var(--cg-font-mono);
1640
+ outline: none;
1641
+ transition: border-color var(--cg-transition);
1642
+ }
1643
+
1644
+ .workspace-path-input:focus {
1645
+ border-color: var(--cg-accent);
1646
+ box-shadow: 0 0 0 3px var(--cg-accent-soft);
1647
+ }
1648
+
1649
+ .workspace-actions {
1650
+ display: flex;
1651
+ gap: 8px;
1652
+ flex-wrap: wrap;
1653
+ }
1654
+
1655
+ .import-submit.secondary {
1656
+ background: var(--cg-surface);
1657
+ color: var(--cg-text);
1658
+ border: 1px solid var(--cg-border);
1659
+ }
1660
+
1661
+ .import-submit.secondary:hover:not(:disabled) {
1662
+ border-color: var(--cg-accent);
1663
+ color: var(--cg-accent);
1664
+ background: var(--cg-accent-soft);
1665
+ }
1666
+
1667
+ .watch-toggle {
1668
+ display: flex;
1669
+ align-items: center;
1670
+ gap: 6px;
1671
+ padding: 6px 14px;
1672
+ background: transparent;
1673
+ color: var(--cg-text-secondary);
1674
+ border: 1px solid var(--cg-border);
1675
+ border-radius: var(--cg-radius-sm);
1676
+ font-size: 12px;
1677
+ font-family: var(--cg-font-sans);
1678
+ cursor: pointer;
1679
+ transition: all var(--cg-transition);
1680
+ align-self: flex-start;
1681
+ }
1682
+
1683
+ .watch-toggle:hover {
1684
+ border-color: var(--cg-accent);
1685
+ color: var(--cg-accent);
1686
+ }
1687
+
1688
+ .watch-toggle.active {
1689
+ background: var(--cg-accent-soft);
1690
+ border-color: var(--cg-accent);
1691
+ color: var(--cg-accent);
1692
+ }
1693
+
1694
+ .init-feedback {
1695
+ padding: 6px 12px;
1696
+ border-radius: var(--cg-radius-sm);
1697
+ font-size: 12px;
1698
+ }
1699
+
1700
+ .init-feedback.ok {
1701
+ background: var(--cg-success-soft, rgba(34, 197, 94, 0.1));
1702
+ color: var(--cg-success, #22c55e);
1703
+ }
1704
+
1705
+ .init-feedback.err {
1706
+ background: var(--cg-error-soft, rgba(239, 68, 68, 0.1));
1707
+ color: var(--cg-error, #ef4444);
1708
+ }
1709
+
1710
+ .prereq-warning {
1711
+ display: flex;
1712
+ align-items: center;
1713
+ gap: 8px;
1714
+ padding: 8px 14px;
1715
+ margin: 0 14px 8px;
1716
+ background: rgba(245, 158, 11, 0.1);
1717
+ border: 1px solid rgba(245, 158, 11, 0.3);
1718
+ border-radius: var(--cg-radius-sm);
1719
+ color: #f59e0b;
1720
+ font-size: 12px;
1721
+ line-height: 1.4;
1722
+ flex-wrap: wrap;
1723
+ }
1724
+
1725
+ .prereq-install {
1726
+ display: flex;
1727
+ align-items: center;
1728
+ gap: 6px;
1729
+ width: 100%;
1730
+ padding-top: 6px;
1731
+ }
1732
+
1733
+ .prereq-install code {
1734
+ flex: 1;
1735
+ padding: 4px 8px;
1736
+ background: rgba(245, 158, 11, 0.12);
1737
+ border: 1px dashed rgba(245, 158, 11, 0.4);
1738
+ border-radius: var(--cg-radius-sm);
1739
+ font-family: var(--cg-font-mono);
1740
+ font-size: 11px;
1741
+ color: #fbbf24;
1742
+ overflow-x: auto;
1743
+ white-space: nowrap;
1744
+ }
1745
+
1746
+ .prereq-copy {
1747
+ flex-shrink: 0;
1748
+ padding: 4px 10px;
1749
+ background: transparent;
1750
+ border: 1px solid rgba(245, 158, 11, 0.4);
1751
+ border-radius: var(--cg-radius-sm);
1752
+ color: #f59e0b;
1753
+ font-size: 11px;
1754
+ cursor: pointer;
1755
+ transition: all var(--cg-transition);
1756
+ }
1757
+
1758
+ .prereq-copy:hover {
1759
+ background: rgba(245, 158, 11, 0.15);
1760
+ }
1761
+
1762
+ .paste-input {
1763
+ flex: 1;
1764
+ min-height: 160px;
1765
+ padding: 10px 12px;
1766
+ background: var(--cg-surface);
1767
+ border: 1px solid var(--cg-border);
1768
+ border-radius: var(--cg-radius-sm);
1769
+ color: var(--cg-text);
1770
+ font-size: 12px;
1771
+ font-family: var(--cg-font-mono);
1772
+ resize: vertical;
1773
+ outline: none;
1774
+ transition: border-color var(--cg-transition);
1775
+ }
1776
+
1777
+ .paste-input:focus {
1778
+ border-color: var(--cg-accent);
1779
+ box-shadow: 0 0 0 3px var(--cg-accent-soft);
1780
+ }
1781
+
1782
+
1783
+ .import-submit {
1784
+ align-self: flex-start;
1785
+ padding: 8px 18px;
1786
+ background: var(--cg-accent);
1787
+ color: var(--cg-text);
1788
+ border: none;
1789
+ border-radius: var(--cg-radius-sm);
1790
+ font-size: 13px;
1791
+ font-weight: 500;
1792
+ font-family: var(--cg-font-sans);
1793
+ cursor: pointer;
1794
+ transition: all var(--cg-transition);
1795
+ }
1796
+
1797
+ .import-submit:hover:not(:disabled) {
1798
+ background: var(--cg-accent-hover);
1799
+ transform: translateY(-1px);
1800
+ }
1801
+
1802
+ .import-submit:disabled {
1803
+ opacity: 0.6;
1804
+ cursor: not-allowed;
1805
+ }
1806
+
1807
+ .import-feedback {
1808
+ display: flex;
1809
+ align-items: center;
1810
+ gap: 6px;
1811
+ padding: 8px 14px;
1812
+ margin: 0 14px 12px;
1813
+ border-radius: var(--cg-radius-sm);
1814
+ font-size: 12px;
1815
+ }
1816
+
1817
+ .import-feedback.ok {
1818
+ background: rgba(16, 185, 129, 0.12);
1819
+ color: var(--cg-success);
1820
+ }
1821
+
1822
+ .import-feedback.err {
1823
+ background: rgba(239, 68, 68, 0.12);
1824
+ color: var(--cg-error);
1825
+ }
1826
+
1827
+ /* ---- Legend panel -------------------------------------------------------- */
1828
+
1829
+ .legend-panel {
1830
+ position: absolute;
1831
+ left: 12px;
1832
+ bottom: calc(var(--cg-statusbar-h) + 12px);
1833
+ width: 180px;
1834
+ background: var(--cg-surface);
1835
+ border: 1px solid var(--cg-border);
1836
+ border-radius: var(--cg-radius);
1837
+ box-shadow: var(--cg-shadow);
1838
+ z-index: 6;
1839
+ backdrop-filter: blur(10px);
1840
+ -webkit-backdrop-filter: blur(10px);
1841
+ overflow: hidden;
1842
+ animation: cg-slide-up 160ms var(--cg-ease-out);
1843
+ }
1844
+
1845
+ .legend-header {
1846
+ padding: 7px 12px;
1847
+ font-size: 11px;
1848
+ font-weight: 600;
1849
+ color: var(--cg-text-secondary);
1850
+ border-bottom: 1px solid var(--cg-border);
1851
+ text-transform: uppercase;
1852
+ letter-spacing: 0.06em;
1853
+ display: flex;
1854
+ justify-content: space-between;
1855
+ align-items: center;
1856
+ }
1857
+
1858
+ .legend-close {
1859
+ background: transparent;
1860
+ border: none;
1861
+ color: var(--cg-text-secondary);
1862
+ cursor: pointer;
1863
+ font-size: 14px;
1864
+ padding: 0 4px;
1865
+ border-radius: var(--cg-radius-xs);
1866
+ line-height: 1;
1867
+ }
1868
+
1869
+ .legend-close:hover {
1870
+ color: var(--cg-text);
1871
+ }
1872
+
1873
+ .legend-body {
1874
+ padding: 10px 12px;
1875
+ display: flex;
1876
+ flex-direction: column;
1877
+ gap: 12px;
1878
+ }
1879
+
1880
+ .legend-section-title {
1881
+ font-size: 10px;
1882
+ font-weight: 600;
1883
+ color: var(--cg-text-tertiary);
1884
+ text-transform: uppercase;
1885
+ letter-spacing: 0.04em;
1886
+ margin-bottom: 4px;
1887
+ }
1888
+
1889
+ .legend-row {
1890
+ display: flex;
1891
+ align-items: center;
1892
+ gap: 8px;
1893
+ font-size: 11px;
1894
+ color: var(--cg-text-secondary);
1895
+ padding: 2px 0;
1896
+ }
1897
+
1898
+ .legend-swatch {
1899
+ width: 10px;
1900
+ height: 10px;
1901
+ border-radius: 50%;
1902
+ flex-shrink: 0;
1903
+ }
1904
+
1905
+ .legend-line {
1906
+ width: 18px;
1907
+ height: 0;
1908
+ border-top: 2px solid var(--cg-text-secondary);
1909
+ flex-shrink: 0;
1910
+ }
1911
+
1912
+ /* ---- Workspace selector --------------------------------------------------- */
1913
+
1914
+ .workspace-selector {
1915
+ position: relative;
1916
+ display: inline-flex;
1917
+ align-items: center;
1918
+ flex-shrink: 0;
1919
+ }
1920
+
1921
+ .workspace-trigger {
1922
+ display: inline-flex;
1923
+ align-items: center;
1924
+ gap: 4px;
1925
+ padding: 3px 8px;
1926
+ background: var(--cg-surface-hover);
1927
+ border: 1px solid var(--cg-border);
1928
+ border-radius: var(--cg-radius-xs);
1929
+ color: var(--cg-text);
1930
+ font-size: 12px;
1931
+ font-family: var(--cg-font-sans);
1932
+ cursor: pointer;
1933
+ transition: background var(--cg-transition), border-color var(--cg-transition);
1934
+ max-width: 160px;
1935
+ }
1936
+
1937
+ .workspace-trigger:hover {
1938
+ background: var(--cg-surface-active);
1939
+ border-color: var(--cg-border-strong);
1940
+ }
1941
+
1942
+ .workspace-trigger:focus-visible {
1943
+ outline: 2px solid var(--cg-accent);
1944
+ outline-offset: 1px;
1945
+ }
1946
+
1947
+ .workspace-name {
1948
+ overflow: hidden;
1949
+ text-overflow: ellipsis;
1950
+ white-space: nowrap;
1951
+ font-weight: 500;
1952
+ }
1953
+
1954
+ .workspace-chevron {
1955
+ opacity: 0.6;
1956
+ flex-shrink: 0;
1957
+ }
1958
+
1959
+ .workspace-dropdown {
1960
+ position: absolute;
1961
+ top: calc(100% + 4px);
1962
+ left: 0;
1963
+ min-width: 240px;
1964
+ max-width: 320px;
1965
+ background: var(--cg-surface);
1966
+ border: 1px solid var(--cg-border-strong);
1967
+ border-radius: var(--cg-radius-sm);
1968
+ box-shadow: var(--cg-shadow-lg);
1969
+ z-index: 1100;
1970
+ overflow: hidden;
1971
+ animation: ws-slide-in 120ms var(--cg-ease-out);
1972
+ }
1973
+
1974
+ .workspace-dropdown-portal {
1975
+ position: fixed;
1976
+ z-index: 9999;
1977
+ }
1978
+
1979
+ @keyframes ws-slide-in {
1980
+ from { opacity: 0; transform: translateY(-4px); }
1981
+ to { opacity: 1; transform: translateY(0); }
1982
+ }
1983
+
1984
+ .workspace-dropdown-header {
1985
+ display: flex;
1986
+ align-items: center;
1987
+ justify-content: space-between;
1988
+ padding: 8px 10px;
1989
+ border-bottom: 1px solid var(--cg-border);
1990
+ font-size: 11px;
1991
+ color: var(--cg-text-tertiary);
1992
+ text-transform: uppercase;
1993
+ letter-spacing: 0.04em;
1994
+ }
1995
+
1996
+ .workspace-add-btn {
1997
+ display: inline-flex;
1998
+ align-items: center;
1999
+ justify-content: center;
2000
+ width: 22px;
2001
+ height: 22px;
2002
+ background: transparent;
2003
+ border: 1px solid var(--cg-border);
2004
+ border-radius: var(--cg-radius-xs);
2005
+ color: var(--cg-text-secondary);
2006
+ cursor: pointer;
2007
+ transition: background var(--cg-transition), color var(--cg-transition);
2008
+ }
2009
+
2010
+ .workspace-add-btn:hover {
2011
+ background: var(--cg-accent-soft);
2012
+ color: var(--cg-accent);
2013
+ border-color: var(--cg-accent);
2014
+ }
2015
+
2016
+ .workspace-add-form {
2017
+ display: flex;
2018
+ align-items: center;
2019
+ gap: 4px;
2020
+ padding: 8px 10px;
2021
+ border-bottom: 1px solid var(--cg-border);
2022
+ }
2023
+
2024
+ .workspace-add-form input {
2025
+ flex: 1;
2026
+ padding: 4px 8px;
2027
+ background: var(--cg-bg);
2028
+ border: 1px solid var(--cg-border);
2029
+ border-radius: var(--cg-radius-xs);
2030
+ color: var(--cg-text);
2031
+ font-size: 12px;
2032
+ font-family: var(--cg-font-mono);
2033
+ outline: none;
2034
+ }
2035
+
2036
+ .workspace-add-form input:focus {
2037
+ border-color: var(--cg-accent);
2038
+ }
2039
+
2040
+ .workspace-add-form button {
2041
+ display: inline-flex;
2042
+ align-items: center;
2043
+ justify-content: center;
2044
+ width: 26px;
2045
+ height: 26px;
2046
+ background: var(--cg-accent);
2047
+ border: none;
2048
+ border-radius: var(--cg-radius-xs);
2049
+ color: white;
2050
+ cursor: pointer;
2051
+ transition: background var(--cg-transition);
2052
+ }
2053
+
2054
+ .workspace-add-form button:disabled {
2055
+ opacity: 0.4;
2056
+ cursor: not-allowed;
2057
+ }
2058
+
2059
+ .workspace-add-form button:not(:disabled):hover {
2060
+ background: var(--cg-accent-hover);
2061
+ }
2062
+
2063
+ .workspace-list {
2064
+ max-height: 260px;
2065
+ overflow-y: auto;
2066
+ padding: 4px 0;
2067
+ }
2068
+
2069
+ .workspace-item {
2070
+ display: grid;
2071
+ grid-template-columns: auto 1fr auto auto;
2072
+ align-items: center;
2073
+ gap: 6px;
2074
+ padding: 7px 10px;
2075
+ cursor: pointer;
2076
+ transition: background var(--cg-transition);
2077
+ position: relative;
2078
+ }
2079
+
2080
+ .workspace-item:hover {
2081
+ background: var(--cg-surface-hover);
2082
+ }
2083
+
2084
+ .workspace-item.current {
2085
+ background: var(--cg-accent-soft);
2086
+ }
2087
+
2088
+ .workspace-item-name {
2089
+ font-size: 12px;
2090
+ font-weight: 500;
2091
+ color: var(--cg-text);
2092
+ overflow: hidden;
2093
+ text-overflow: ellipsis;
2094
+ white-space: nowrap;
2095
+ }
2096
+
2097
+ .workspace-item-path {
2098
+ grid-column: 2;
2099
+ font-size: 10px;
2100
+ color: var(--cg-text-tertiary);
2101
+ font-family: var(--cg-font-mono);
2102
+ overflow: hidden;
2103
+ text-overflow: ellipsis;
2104
+ white-space: nowrap;
2105
+ line-height: 1.2;
2106
+ }
2107
+
2108
+ .workspace-item-time {
2109
+ font-size: 10px;
2110
+ color: var(--cg-text-tertiary);
2111
+ white-space: nowrap;
2112
+ }
2113
+
2114
+ .workspace-item-badge {
2115
+ font-size: 9px;
2116
+ padding: 1px 5px;
2117
+ background: var(--cg-accent);
2118
+ color: white;
2119
+ border-radius: 3px;
2120
+ text-transform: uppercase;
2121
+ letter-spacing: 0.03em;
2122
+ white-space: nowrap;
2123
+ }
2124
+
2125
+ .workspace-item-remove {
2126
+ display: inline-flex;
2127
+ align-items: center;
2128
+ justify-content: center;
2129
+ width: 18px;
2130
+ height: 18px;
2131
+ background: transparent;
2132
+ border: none;
2133
+ border-radius: 3px;
2134
+ color: var(--cg-text-tertiary);
2135
+ cursor: pointer;
2136
+ opacity: 0;
2137
+ transition: opacity var(--cg-transition), color var(--cg-transition);
2138
+ }
2139
+
2140
+ .workspace-item:hover .workspace-item-remove {
2141
+ opacity: 1;
2142
+ }
2143
+
2144
+ .workspace-item-remove:hover {
2145
+ color: var(--cg-error);
2146
+ background: rgba(239, 68, 68, 0.1);
2147
+ }
2148
+
2149
+ .workspace-empty {
2150
+ padding: 16px 10px;
2151
+ text-align: center;
2152
+ font-size: 12px;
2153
+ color: var(--cg-text-tertiary);
2154
+ }
2155
+
2156
+ /* ---- Keyboard help -------------------------------------------------------- */
2157
+
2158
+ .keyboard-help-overlay {
2159
+ position: fixed;
2160
+ inset: 0;
2161
+ background: rgba(0, 0, 0, 0.3);
2162
+ backdrop-filter: blur(2px);
2163
+ z-index: 10000;
2164
+ display: flex;
2165
+ align-items: center;
2166
+ justify-content: center;
2167
+ animation: cg-fade-in 120ms var(--cg-ease-out);
2168
+ }
2169
+
2170
+ .keyboard-help-panel {
2171
+ background: var(--cg-surface);
2172
+ border: 1px solid var(--cg-border-strong);
2173
+ border-radius: var(--cg-radius);
2174
+ box-shadow: var(--cg-shadow-lg);
2175
+ min-width: 280px;
2176
+ max-width: 360px;
2177
+ padding: 0;
2178
+ animation: cg-slide-up 160ms var(--cg-ease-out);
2179
+ }
2180
+
2181
+ .keyboard-help-header {
2182
+ display: flex;
2183
+ align-items: center;
2184
+ justify-content: space-between;
2185
+ padding: 12px 16px;
2186
+ border-bottom: 1px solid var(--cg-border);
2187
+ font-size: 14px;
2188
+ font-weight: 600;
2189
+ color: var(--cg-text);
2190
+ }
2191
+
2192
+ .keyboard-help-close {
2193
+ width: 24px;
2194
+ height: 24px;
2195
+ display: inline-flex;
2196
+ align-items: center;
2197
+ justify-content: center;
2198
+ background: transparent;
2199
+ border: none;
2200
+ border-radius: var(--cg-radius-xs);
2201
+ color: var(--cg-text-tertiary);
2202
+ cursor: pointer;
2203
+ font-size: 16px;
2204
+ transition: color var(--cg-transition), background var(--cg-transition);
2205
+ }
2206
+
2207
+ .keyboard-help-close:hover {
2208
+ color: var(--cg-text);
2209
+ background: var(--cg-surface-hover);
2210
+ }
2211
+
2212
+ .keyboard-help-list {
2213
+ padding: 8px 16px 16px;
2214
+ display: flex;
2215
+ flex-direction: column;
2216
+ gap: 8px;
2217
+ }
2218
+
2219
+ .keyboard-help-item {
2220
+ display: flex;
2221
+ align-items: center;
2222
+ justify-content: space-between;
2223
+ gap: 12px;
2224
+ }
2225
+
2226
+ .keyboard-help-key {
2227
+ display: inline-flex;
2228
+ align-items: center;
2229
+ justify-content: center;
2230
+ min-width: 32px;
2231
+ height: 24px;
2232
+ padding: 0 8px;
2233
+ background: var(--cg-surface-active);
2234
+ border: 1px solid var(--cg-border-strong);
2235
+ border-radius: var(--cg-radius-xs);
2236
+ font-family: var(--cg-font-mono);
2237
+ font-size: 11px;
2238
+ color: var(--cg-text);
2239
+ box-shadow: 0 1px 0 var(--cg-border-strong);
2240
+ }
2241
+
2242
+ .keyboard-help-desc {
2243
+ font-size: 13px;
2244
+ color: var(--cg-text-secondary);
2245
+ }
2246
+
2247
+ @keyframes cg-fade-in {
2248
+ from { opacity: 0; }
2249
+ to { opacity: 1; }
2250
+ }
2251
+
2252
+ @keyframes cg-slide-up {
2253
+ from { opacity: 0; transform: translateY(8px); }
2254
+ to { opacity: 1; transform: translateY(0); }
2255
+ }
2256
+
2257
+ /* ---- Expandable node indicators ------------------------------------------- */
2258
+
2259
+ .node-detail-panel .detail-expand-hint {
2260
+ margin-top: 8px;
2261
+ padding: 6px 10px;
2262
+ background: var(--cg-accent-soft);
2263
+ border: 1px solid var(--cg-accent);
2264
+ border-radius: var(--cg-radius-xs);
2265
+ font-size: 11px;
2266
+ color: var(--cg-accent);
2267
+ display: flex;
2268
+ align-items: center;
2269
+ gap: 6px;
2270
+ }
2271
+
2272
+ .node-detail-panel .detail-connections {
2273
+ margin-top: 8px;
2274
+ padding-top: 8px;
2275
+ border-top: 1px solid var(--cg-border);
2276
+ }
2277
+
2278
+ .node-detail-panel .detail-connections-title {
2279
+ font-size: 10px;
2280
+ font-weight: 600;
2281
+ text-transform: uppercase;
2282
+ letter-spacing: 0.06em;
2283
+ color: var(--cg-text-tertiary);
2284
+ margin-bottom: 6px;
2285
+ }
2286
+
2287
+ .node-detail-panel .detail-connection-item {
2288
+ display: flex;
2289
+ align-items: center;
2290
+ gap: 6px;
2291
+ padding: 3px 0;
2292
+ font-size: 11px;
2293
+ color: var(--cg-text-secondary);
2294
+ }
2295
+
2296
+ .node-detail-panel .detail-connection-type {
2297
+ display: inline-block;
2298
+ padding: 1px 5px;
2299
+ border-radius: 3px;
2300
+ font-size: 9px;
2301
+ font-weight: 600;
2302
+ text-transform: uppercase;
2303
+ background: var(--cg-surface-active);
2304
+ color: var(--cg-text-tertiary);
2305
+ flex-shrink: 0;
2306
+ }
2307
+
2308
+ .node-detail-panel .detail-connection-name {
2309
+ overflow: hidden;
2310
+ text-overflow: ellipsis;
2311
+ white-space: nowrap;
2312
+ }
2313
+
2314
+ /* ---- Depth level indicator ------------------------------------------------ */
2315
+
2316
+ .depth-level-indicator {
2317
+ display: inline-flex;
2318
+ align-items: center;
2319
+ gap: 3px;
2320
+ padding: 2px 8px;
2321
+ background: var(--cg-accent-soft);
2322
+ border: 1px solid var(--cg-accent);
2323
+ border-radius: 10px;
2324
+ font-size: 10px;
2325
+ font-weight: 600;
2326
+ color: var(--cg-accent);
2327
+ white-space: nowrap;
2328
+ }
2329
+
2330
+ .depth-level-dot {
2331
+ width: 6px;
2332
+ height: 6px;
2333
+ border-radius: 50%;
2334
+ background: var(--cg-accent);
2335
+ }
2336
+
2337
+ .depth-level-dot.active {
2338
+ background: var(--cg-success);
2339
+ box-shadow: 0 0 4px var(--cg-success);
2340
+ }
2341
+
2342
+ /* ---- Expanded node badge in detail panel ---------------------------------- */
2343
+
2344
+ .node-detail-panel .detail-expanded-badge {
2345
+ display: inline-flex;
2346
+ align-items: center;
2347
+ gap: 4px;
2348
+ padding: 2px 8px;
2349
+ background: rgba(16, 185, 129, 0.12);
2350
+ border: 1px solid rgba(16, 185, 129, 0.3);
2351
+ border-radius: 10px;
2352
+ font-size: 10px;
2353
+ font-weight: 600;
2354
+ color: var(--cg-success);
2355
+ margin-left: 6px;
2356
+ }
2357
+
2358
+ /* ---- Collapse-all button -------------------------------------------------- */
2359
+
2360
+ .collapse-all-btn {
2361
+ display: inline-flex;
2362
+ align-items: center;
2363
+ gap: 4px;
2364
+ padding: 3px 8px;
2365
+ background: var(--cg-surface-hover);
2366
+ border: 1px solid var(--cg-border);
2367
+ border-radius: var(--cg-radius-xs);
2368
+ font-size: 10px;
2369
+ color: var(--cg-text-secondary);
2370
+ cursor: pointer;
2371
+ transition: all var(--cg-transition);
2372
+ white-space: nowrap;
2373
+ }
2374
+
2375
+ .collapse-all-btn:hover {
2376
+ background: var(--cg-surface-active);
2377
+ color: var(--cg-text);
2378
+ border-color: var(--cg-border-strong);
2379
+ }
2380
+
2381
+ /* ---- Smooth graph transitions --------------------------------------------- */
2382
+
2383
+ .graph-container {
2384
+ transition: opacity 200ms var(--cg-ease);
2385
+ }
2386
+
2387
+ .graph-container.loading {
2388
+ opacity: 0.4;
2389
+ }
2390
+
2391
+ /* ---- Responsive improvements ---------------------------------------------- */
2392
+
2393
+ @media (max-width: 768px) {
2394
+ .depth-level-indicator {
2395
+ display: none;
2396
+ }
2397
+ }
2398
+
2399
+ @media (max-width: 480px) {
2400
+ .collapse-all-btn {
2401
+ display: none;
2402
+ }
2403
+ }
2404
+