dsh-codegraph-visualizer 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +391 -226
  2. package/assets/icon-180.png +0 -0
  3. package/assets/icon.svg +30 -0
  4. package/cordis.patch.yml +22 -17
  5. package/dist/CodeGraphAdapter-C8JvcS7m.js +10 -0
  6. package/dist/CodeGraphAdapter-eyrhs0K0.js +422 -0
  7. package/dist/CodeGraphAdapter-eyrhs0K0.js.map +1 -0
  8. package/dist/FileSystemAdapter-CgasSGbB.js +524 -0
  9. package/dist/FileSystemAdapter-CgasSGbB.js.map +1 -0
  10. package/dist/LensAdapter-C9Saf_i_.js +89 -0
  11. package/dist/LensAdapter-C9Saf_i_.js.map +1 -0
  12. package/dist/Logger-DUIJSeNu.js +80 -0
  13. package/dist/Logger-DUIJSeNu.js.map +1 -0
  14. package/dist/TreeSitterAdapter-C-EWy8br.js +631 -0
  15. package/dist/TreeSitterAdapter-C-EWy8br.js.map +1 -0
  16. package/dist/TreeSitterAdapter-C6FcO2_s.js +8 -0
  17. package/dist/client/index.css +8900 -1777
  18. package/dist/client/index.css.map +1 -0
  19. package/dist/client/index.d.ts +634 -0
  20. package/dist/client/index.d.ts.map +1 -0
  21. package/dist/client/index.esm.js +57219 -20978
  22. package/dist/client/index.js.map +1 -0
  23. package/dist/client/{index.js → worker/layoutWorker.js} +7657 -8787
  24. package/dist/client.js +90067 -0
  25. package/dist/codeGraphDb-BT9nZCEO.js +357 -0
  26. package/dist/codeGraphDb-BT9nZCEO.js.map +1 -0
  27. package/dist/codeGraphDb-Bg7bWud2.js +9 -0
  28. package/dist/codeGraphRows-BhZX34uB.js +6 -0
  29. package/dist/codeGraphRows-C7hqu35E.js +246 -0
  30. package/dist/codeGraphRows-C7hqu35E.js.map +1 -0
  31. package/dist/constants-CQq93l3e.js +399 -0
  32. package/dist/constants-CQq93l3e.js.map +1 -0
  33. package/dist/graphFingerprint-CeARo7jG.js +4 -0
  34. package/dist/graphFingerprint-PuxORZUF.js +277 -0
  35. package/dist/graphFingerprint-PuxORZUF.js.map +1 -0
  36. package/dist/graphMetrics-C0F30730.js +555 -0
  37. package/dist/graphMetrics-C0F30730.js.map +1 -0
  38. package/dist/index.d.ts +572 -9
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +14734 -2003
  41. package/dist/index.js.map +1 -1
  42. package/dist/inheritanceEnhancer-Bi3UoYJS.js +291 -0
  43. package/dist/inheritanceEnhancer-Bi3UoYJS.js.map +1 -0
  44. package/dist/layerUtils-DDm-EsaD.js +72 -0
  45. package/dist/layerUtils-DDm-EsaD.js.map +1 -0
  46. package/dist/nativeIndex-Cx7RLXUp.js +5 -0
  47. package/dist/nativeIndex-DlSpD611.js +347 -0
  48. package/dist/nativeIndex-DlSpD611.js.map +1 -0
  49. package/dist/treeSitterExtractors-B1ybKNrC.js +394 -0
  50. package/dist/treeSitterExtractors-B1ybKNrC.js.map +1 -0
  51. package/dist/types-BUDxI_00.js +23 -0
  52. package/dist/types-BUDxI_00.js.map +1 -0
  53. package/locale/en.json +6 -0
  54. package/locale/zh-CN.json +6 -0
  55. package/locale/zh.json +6 -0
  56. package/package.json +100 -20
  57. package/dist/client-cjs/index.cjs +0 -44283
  58. package/dist/client-cjs/index.css +0 -2404
@@ -1,2404 +0,0 @@
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
-