mcp-vector-search 0.12.6__py3-none-any.whl → 1.1.22__py3-none-any.whl

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 (92) hide show
  1. mcp_vector_search/__init__.py +3 -3
  2. mcp_vector_search/analysis/__init__.py +111 -0
  3. mcp_vector_search/analysis/baseline/__init__.py +68 -0
  4. mcp_vector_search/analysis/baseline/comparator.py +462 -0
  5. mcp_vector_search/analysis/baseline/manager.py +621 -0
  6. mcp_vector_search/analysis/collectors/__init__.py +74 -0
  7. mcp_vector_search/analysis/collectors/base.py +164 -0
  8. mcp_vector_search/analysis/collectors/cohesion.py +463 -0
  9. mcp_vector_search/analysis/collectors/complexity.py +743 -0
  10. mcp_vector_search/analysis/collectors/coupling.py +1162 -0
  11. mcp_vector_search/analysis/collectors/halstead.py +514 -0
  12. mcp_vector_search/analysis/collectors/smells.py +325 -0
  13. mcp_vector_search/analysis/debt.py +516 -0
  14. mcp_vector_search/analysis/interpretation.py +685 -0
  15. mcp_vector_search/analysis/metrics.py +414 -0
  16. mcp_vector_search/analysis/reporters/__init__.py +7 -0
  17. mcp_vector_search/analysis/reporters/console.py +646 -0
  18. mcp_vector_search/analysis/reporters/markdown.py +480 -0
  19. mcp_vector_search/analysis/reporters/sarif.py +377 -0
  20. mcp_vector_search/analysis/storage/__init__.py +93 -0
  21. mcp_vector_search/analysis/storage/metrics_store.py +762 -0
  22. mcp_vector_search/analysis/storage/schema.py +245 -0
  23. mcp_vector_search/analysis/storage/trend_tracker.py +560 -0
  24. mcp_vector_search/analysis/trends.py +308 -0
  25. mcp_vector_search/analysis/visualizer/__init__.py +90 -0
  26. mcp_vector_search/analysis/visualizer/d3_data.py +534 -0
  27. mcp_vector_search/analysis/visualizer/exporter.py +484 -0
  28. mcp_vector_search/analysis/visualizer/html_report.py +2895 -0
  29. mcp_vector_search/analysis/visualizer/schemas.py +525 -0
  30. mcp_vector_search/cli/commands/analyze.py +1062 -0
  31. mcp_vector_search/cli/commands/chat.py +1455 -0
  32. mcp_vector_search/cli/commands/index.py +621 -5
  33. mcp_vector_search/cli/commands/index_background.py +467 -0
  34. mcp_vector_search/cli/commands/init.py +13 -0
  35. mcp_vector_search/cli/commands/install.py +597 -335
  36. mcp_vector_search/cli/commands/install_old.py +8 -4
  37. mcp_vector_search/cli/commands/mcp.py +78 -6
  38. mcp_vector_search/cli/commands/reset.py +68 -26
  39. mcp_vector_search/cli/commands/search.py +224 -8
  40. mcp_vector_search/cli/commands/setup.py +1184 -0
  41. mcp_vector_search/cli/commands/status.py +339 -5
  42. mcp_vector_search/cli/commands/uninstall.py +276 -357
  43. mcp_vector_search/cli/commands/visualize/__init__.py +39 -0
  44. mcp_vector_search/cli/commands/visualize/cli.py +292 -0
  45. mcp_vector_search/cli/commands/visualize/exporters/__init__.py +12 -0
  46. mcp_vector_search/cli/commands/visualize/exporters/html_exporter.py +33 -0
  47. mcp_vector_search/cli/commands/visualize/exporters/json_exporter.py +33 -0
  48. mcp_vector_search/cli/commands/visualize/graph_builder.py +647 -0
  49. mcp_vector_search/cli/commands/visualize/layout_engine.py +469 -0
  50. mcp_vector_search/cli/commands/visualize/server.py +600 -0
  51. mcp_vector_search/cli/commands/visualize/state_manager.py +428 -0
  52. mcp_vector_search/cli/commands/visualize/templates/__init__.py +16 -0
  53. mcp_vector_search/cli/commands/visualize/templates/base.py +234 -0
  54. mcp_vector_search/cli/commands/visualize/templates/scripts.py +4542 -0
  55. mcp_vector_search/cli/commands/visualize/templates/styles.py +2522 -0
  56. mcp_vector_search/cli/didyoumean.py +27 -2
  57. mcp_vector_search/cli/main.py +127 -160
  58. mcp_vector_search/cli/output.py +158 -13
  59. mcp_vector_search/config/__init__.py +4 -0
  60. mcp_vector_search/config/default_thresholds.yaml +52 -0
  61. mcp_vector_search/config/settings.py +12 -0
  62. mcp_vector_search/config/thresholds.py +273 -0
  63. mcp_vector_search/core/__init__.py +16 -0
  64. mcp_vector_search/core/auto_indexer.py +3 -3
  65. mcp_vector_search/core/boilerplate.py +186 -0
  66. mcp_vector_search/core/config_utils.py +394 -0
  67. mcp_vector_search/core/database.py +406 -94
  68. mcp_vector_search/core/embeddings.py +24 -0
  69. mcp_vector_search/core/exceptions.py +11 -0
  70. mcp_vector_search/core/git.py +380 -0
  71. mcp_vector_search/core/git_hooks.py +4 -4
  72. mcp_vector_search/core/indexer.py +632 -54
  73. mcp_vector_search/core/llm_client.py +756 -0
  74. mcp_vector_search/core/models.py +91 -1
  75. mcp_vector_search/core/project.py +17 -0
  76. mcp_vector_search/core/relationships.py +473 -0
  77. mcp_vector_search/core/scheduler.py +11 -11
  78. mcp_vector_search/core/search.py +179 -29
  79. mcp_vector_search/mcp/server.py +819 -9
  80. mcp_vector_search/parsers/python.py +285 -5
  81. mcp_vector_search/utils/__init__.py +2 -0
  82. mcp_vector_search/utils/gitignore.py +0 -3
  83. mcp_vector_search/utils/gitignore_updater.py +212 -0
  84. mcp_vector_search/utils/monorepo.py +66 -4
  85. mcp_vector_search/utils/timing.py +10 -6
  86. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.1.22.dist-info}/METADATA +184 -53
  87. mcp_vector_search-1.1.22.dist-info/RECORD +120 -0
  88. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.1.22.dist-info}/WHEEL +1 -1
  89. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.1.22.dist-info}/entry_points.txt +1 -0
  90. mcp_vector_search/cli/commands/visualize.py +0 -1467
  91. mcp_vector_search-0.12.6.dist-info/RECORD +0 -68
  92. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.1.22.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,2522 @@
1
+ """CSS styles for the visualization interface.
2
+
3
+ This module contains all CSS styling for the D3.js code graph visualization,
4
+ organized into logical sections for maintainability.
5
+ """
6
+
7
+
8
+ def get_base_styles() -> str:
9
+ """Get base styles for body and core layout.
10
+
11
+ Returns:
12
+ CSS string for base styling
13
+ """
14
+ return """
15
+ /* CSS Variables for Theme Support */
16
+ :root {
17
+ --bg-primary: #0d1117;
18
+ --bg-secondary: #161b22;
19
+ --bg-tertiary: #21262d;
20
+ --text-primary: #c9d1d9;
21
+ --text-secondary: #8b949e;
22
+ --text-tertiary: #6e7681;
23
+ --border-primary: #30363d;
24
+ --border-secondary: #21262d;
25
+ --accent: #58a6ff;
26
+ --accent-hover: #79c0ff;
27
+ --success: #238636;
28
+ --warning: #d29922;
29
+ --error: #da3633;
30
+ --shadow: rgba(0, 0, 0, 0.4);
31
+ }
32
+
33
+ [data-theme="light"] {
34
+ --bg-primary: #ffffff;
35
+ --bg-secondary: #f6f8fa;
36
+ --bg-tertiary: #eaeef2;
37
+ --text-primary: #24292f;
38
+ --text-secondary: #57606a;
39
+ --text-tertiary: #6e7781;
40
+ --border-primary: #d0d7de;
41
+ --border-secondary: #d8dee4;
42
+ --accent: #0969da;
43
+ --accent-hover: #0550ae;
44
+ --success: #1a7f37;
45
+ --warning: #9a6700;
46
+ --error: #cf222e;
47
+ --shadow: rgba(31, 35, 40, 0.15);
48
+ }
49
+
50
+ body {
51
+ margin: 0;
52
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
53
+ background: var(--bg-primary);
54
+ color: var(--text-primary);
55
+ overflow: hidden;
56
+ transition: background-color 0.3s ease, color 0.3s ease;
57
+ }
58
+
59
+ h1 { margin: 0 0 4px 0; font-size: 18px; color: var(--text-primary); }
60
+ h3 { margin: 16px 0 8px 0; font-size: 14px; color: var(--text-secondary); }
61
+
62
+ .version-badge {
63
+ font-size: 10px;
64
+ color: var(--text-tertiary);
65
+ margin-bottom: 16px;
66
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
67
+ padding: 2px 6px;
68
+ background: var(--bg-tertiary);
69
+ border-radius: 4px;
70
+ display: inline-block;
71
+ }
72
+ """
73
+
74
+
75
+ def get_controls_styles() -> str:
76
+ """Get styles for the control panel.
77
+
78
+ Returns:
79
+ CSS string for control panel styling
80
+ """
81
+ return """
82
+ #controls {
83
+ position: absolute;
84
+ top: 20px;
85
+ left: 20px;
86
+ background: var(--bg-primary);
87
+ border: 1px solid var(--border-primary);
88
+ border-radius: 6px;
89
+ padding: 16px;
90
+ min-width: 250px;
91
+ max-height: 80vh;
92
+ overflow-y: auto;
93
+ box-shadow: 0 8px 24px var(--shadow);
94
+ z-index: 500;
95
+ transition: background-color 0.3s ease, border-color 0.3s ease;
96
+ }
97
+
98
+ .control-group {
99
+ margin-bottom: 12px;
100
+ }
101
+
102
+ label {
103
+ display: block;
104
+ margin-bottom: 4px;
105
+ font-size: 12px;
106
+ color: var(--text-secondary);
107
+ }
108
+
109
+ input[type="file"] {
110
+ width: 100%;
111
+ padding: 6px;
112
+ background: var(--bg-secondary);
113
+ border: 1px solid var(--border-primary);
114
+ border-radius: 6px;
115
+ color: var(--text-primary);
116
+ font-size: 12px;
117
+ }
118
+
119
+ .legend {
120
+ background: var(--bg-secondary);
121
+ border: 1px solid var(--border-primary);
122
+ border-radius: 6px;
123
+ padding: 12px;
124
+ font-size: 13px;
125
+ max-width: 300px;
126
+ margin-top: 16px;
127
+ box-shadow: 0 8px 24px var(--shadow);
128
+ }
129
+
130
+ .legend-category {
131
+ margin-bottom: 12px;
132
+ padding-bottom: 8px;
133
+ border-bottom: 1px solid var(--border-secondary);
134
+ }
135
+
136
+ .legend-category:last-child {
137
+ margin-bottom: 0;
138
+ padding-bottom: 0;
139
+ border-bottom: none;
140
+ }
141
+
142
+ .legend-title {
143
+ font-weight: 600;
144
+ color: var(--text-primary);
145
+ margin-bottom: 8px;
146
+ font-size: 12px;
147
+ text-transform: uppercase;
148
+ letter-spacing: 0.5px;
149
+ }
150
+
151
+ .legend-item {
152
+ display: flex;
153
+ align-items: center;
154
+ margin-bottom: 6px;
155
+ padding-left: 8px;
156
+ }
157
+
158
+ .legend-item:last-child {
159
+ margin-bottom: 0;
160
+ }
161
+
162
+ .legend-color {
163
+ width: 12px;
164
+ height: 12px;
165
+ border-radius: 50%;
166
+ margin-right: 8px;
167
+ }
168
+
169
+ /* Report buttons in sidebar */
170
+ .report-btn {
171
+ cursor: pointer;
172
+ padding: 10px 12px !important;
173
+ background: var(--bg-tertiary);
174
+ border: 1px solid var(--border-primary);
175
+ border-radius: 6px;
176
+ margin-bottom: 8px !important;
177
+ transition: all 0.2s ease;
178
+ }
179
+
180
+ .report-btn:hover {
181
+ background: var(--accent);
182
+ border-color: var(--accent);
183
+ color: white;
184
+ transform: translateX(4px);
185
+ }
186
+
187
+ .report-btn:hover span {
188
+ color: white !important;
189
+ }
190
+
191
+ .report-icon {
192
+ margin-right: 10px;
193
+ font-size: 16px;
194
+ }
195
+
196
+ .stats {
197
+ margin-top: 16px;
198
+ padding-top: 16px;
199
+ border-top: 1px solid var(--border-primary);
200
+ font-size: 12px;
201
+ color: var(--text-secondary);
202
+ }
203
+
204
+ .toggle-switch-container {
205
+ display: flex;
206
+ align-items: center;
207
+ justify-content: center;
208
+ gap: 12px;
209
+ padding: 10px;
210
+ background: var(--bg-secondary);
211
+ border: 1px solid var(--border-primary);
212
+ border-radius: 6px;
213
+ }
214
+
215
+ .toggle-label {
216
+ font-size: 13px;
217
+ color: var(--text-secondary);
218
+ font-weight: 500;
219
+ transition: color 0.2s ease;
220
+ }
221
+
222
+ .toggle-label.active {
223
+ color: var(--accent);
224
+ }
225
+
226
+ .toggle-switch {
227
+ position: relative;
228
+ display: inline-block;
229
+ width: 48px;
230
+ height: 24px;
231
+ margin: 0;
232
+ }
233
+
234
+ .toggle-switch input {
235
+ opacity: 0;
236
+ width: 100%;
237
+ height: 100%;
238
+ position: absolute;
239
+ top: 0;
240
+ left: 0;
241
+ cursor: pointer;
242
+ z-index: 2;
243
+ }
244
+
245
+ .toggle-slider {
246
+ position: absolute;
247
+ cursor: pointer;
248
+ top: 0;
249
+ left: 0;
250
+ right: 0;
251
+ bottom: 0;
252
+ background-color: var(--border-primary);
253
+ transition: 0.3s;
254
+ border-radius: 24px;
255
+ border: 1px solid var(--border-primary);
256
+ }
257
+
258
+ .toggle-slider:before {
259
+ position: absolute;
260
+ content: "";
261
+ height: 16px;
262
+ width: 16px;
263
+ left: 3px;
264
+ bottom: 3px;
265
+ background-color: var(--text-secondary);
266
+ transition: 0.3s;
267
+ border-radius: 50%;
268
+ }
269
+
270
+ .toggle-switch input:checked + .toggle-slider {
271
+ background-color: var(--success);
272
+ border-color: var(--success);
273
+ }
274
+
275
+ .toggle-switch input:checked + .toggle-slider:before {
276
+ transform: translateX(24px);
277
+ background-color: var(--bg-primary);
278
+ }
279
+
280
+ .toggle-slider:hover {
281
+ opacity: 0.8;
282
+ }
283
+
284
+ .toggle-switch input:checked + .toggle-slider:hover {
285
+ opacity: 0.9;
286
+ }
287
+
288
+ /* Filter buttons */
289
+ .filter-buttons {
290
+ display: flex;
291
+ gap: 4px;
292
+ background: var(--bg-secondary);
293
+ border: 1px solid var(--border-primary);
294
+ border-radius: 6px;
295
+ padding: 4px;
296
+ }
297
+
298
+ .filter-btn {
299
+ flex: 1;
300
+ padding: 8px 12px;
301
+ background: transparent;
302
+ border: none;
303
+ border-radius: 4px;
304
+ color: var(--text-secondary);
305
+ font-size: 12px;
306
+ font-weight: 500;
307
+ cursor: pointer;
308
+ transition: all 0.2s ease;
309
+ }
310
+
311
+ .filter-btn:hover {
312
+ background: var(--bg-tertiary);
313
+ color: var(--text-primary);
314
+ }
315
+
316
+ .filter-btn.active {
317
+ background: var(--accent);
318
+ color: var(--bg-primary);
319
+ }
320
+
321
+ .filter-btn.active:hover {
322
+ background: var(--accent-hover);
323
+ }
324
+ """
325
+
326
+
327
+ def get_graph_styles() -> str:
328
+ """Get styles for the graph SVG element.
329
+
330
+ Returns:
331
+ CSS string for graph styling
332
+ """
333
+ return """
334
+ #main-container {
335
+ position: fixed;
336
+ left: 0;
337
+ top: 0;
338
+ right: 0;
339
+ bottom: 0;
340
+ transition: right 0.3s ease-in-out;
341
+ }
342
+
343
+ #main-container.viewer-open {
344
+ right: 450px;
345
+ }
346
+
347
+ /* When viewer is expanded, handled via JS style.right */
348
+
349
+ #graph {
350
+ width: 100%;
351
+ height: 100%;
352
+ }
353
+ """
354
+
355
+
356
+ def get_node_styles() -> str:
357
+ """Get styles for graph nodes.
358
+
359
+ Returns:
360
+ CSS string for node styling including different node types
361
+ """
362
+ return """
363
+ .node circle {
364
+ cursor: pointer;
365
+ stroke: #c9d1d9;
366
+ stroke-width: 2px;
367
+ pointer-events: all;
368
+ }
369
+
370
+ .node.module circle { fill: #238636; }
371
+ .node.class circle { fill: #1f6feb; }
372
+ .node.function circle { fill: #d29922; }
373
+ .node.method circle { fill: #8957e5; }
374
+ .node.code circle { fill: #6e7681; }
375
+ .node.file circle {
376
+ fill: none;
377
+ stroke: #58a6ff;
378
+ stroke-width: 2px;
379
+ stroke-dasharray: 5,3;
380
+ opacity: 0.6;
381
+ }
382
+ .node.directory circle {
383
+ fill: none;
384
+ stroke: #79c0ff;
385
+ stroke-width: 2px;
386
+ stroke-dasharray: 3,3;
387
+ opacity: 0.5;
388
+ }
389
+ .node.subproject circle { fill: #da3633; stroke-width: 3px; }
390
+
391
+ /* Non-code document nodes - squares */
392
+ .node.docstring rect:not(.hit-area) { fill: #8b949e; }
393
+ .node.comment rect:not(.hit-area) { fill: #6e7681; }
394
+ .node rect:not(.hit-area) {
395
+ cursor: pointer;
396
+ stroke: #c9d1d9;
397
+ stroke-width: 2px;
398
+ pointer-events: all;
399
+ }
400
+
401
+ /* Hit area for file/directory nodes - transparent clickable rectangle */
402
+ .node rect.hit-area {
403
+ fill: transparent;
404
+ stroke: none;
405
+ pointer-events: all;
406
+ cursor: pointer;
407
+ }
408
+
409
+ /* Debug mode: uncomment to visualize hit areas */
410
+ /* .node rect.hit-area { fill: rgba(255, 0, 0, 0.1); stroke: red; stroke-width: 1; } */
411
+
412
+ /* File type icon styling */
413
+ .node path.file-icon {
414
+ fill: currentColor;
415
+ stroke: none;
416
+ pointer-events: none;
417
+ cursor: pointer;
418
+ }
419
+
420
+ .node text {
421
+ font-size: 14px;
422
+ fill: #c9d1d9;
423
+ /* text-anchor set by JS based on layout */
424
+ pointer-events: none;
425
+ user-select: none;
426
+ }
427
+
428
+ .node.highlighted circle,
429
+ .node.highlighted rect {
430
+ stroke: #f0e68c;
431
+ stroke-width: 3px;
432
+ filter: drop-shadow(0 0 8px #f0e68c);
433
+ }
434
+
435
+ /* Node loading spinner */
436
+ .node-loading {
437
+ stroke: #2196F3;
438
+ stroke-width: 3;
439
+ fill: none;
440
+ animation: spin 1s linear infinite;
441
+ }
442
+
443
+ .node-loading-overlay {
444
+ fill: rgba(255, 255, 255, 0.8);
445
+ pointer-events: none;
446
+ }
447
+ """
448
+
449
+
450
+ def get_link_styles() -> str:
451
+ """Get styles for graph links (edges).
452
+
453
+ Returns:
454
+ CSS string for link styling including semantic similarity and cycles
455
+ """
456
+ return """
457
+ .link {
458
+ fill: none;
459
+ stroke: #c9d1d9;
460
+ stroke-opacity: 0.8;
461
+ stroke-width: 1.5px;
462
+ }
463
+
464
+ .link.dependency {
465
+ stroke: #d29922;
466
+ stroke-opacity: 0.8;
467
+ stroke-width: 2px;
468
+ stroke-dasharray: 5,5;
469
+ }
470
+
471
+ /* Semantic relationship links - colored by similarity */
472
+ .link.semantic {
473
+ stroke-opacity: 0.7;
474
+ stroke-dasharray: 4,4;
475
+ }
476
+
477
+ .link.semantic.sim-high { stroke: #00ff00; stroke-width: 4px; }
478
+ .link.semantic.sim-medium-high { stroke: #88ff00; stroke-width: 3px; }
479
+ .link.semantic.sim-medium { stroke: #ffff00; stroke-width: 2.5px; }
480
+ .link.semantic.sim-low { stroke: #ffaa00; stroke-width: 2px; }
481
+ .link.semantic.sim-very-low { stroke: #ff0000; stroke-width: 1.5px; }
482
+
483
+ /* Circular dependency links - highest visual priority */
484
+ .link.cycle {
485
+ stroke: #ff4444 !important;
486
+ stroke-width: 3px !important;
487
+ stroke-dasharray: 8, 4;
488
+ stroke-opacity: 0.8;
489
+ animation: pulse-cycle 2s infinite;
490
+ }
491
+
492
+ @keyframes pulse-cycle {
493
+ 0%, 100% { stroke-opacity: 0.8; }
494
+ 50% { stroke-opacity: 1.0; }
495
+ }
496
+ """
497
+
498
+
499
+ def get_tooltip_styles() -> str:
500
+ """Get styles for tooltips.
501
+
502
+ Returns:
503
+ CSS string for tooltip styling
504
+ """
505
+ return """
506
+ .tooltip {
507
+ position: absolute;
508
+ padding: 12px;
509
+ background: var(--bg-primary);
510
+ opacity: 0.95;
511
+ border: 1px solid var(--border-primary);
512
+ border-radius: 6px;
513
+ pointer-events: none;
514
+ display: none;
515
+ font-size: 12px;
516
+ max-width: 300px;
517
+ box-shadow: 0 8px 24px var(--shadow);
518
+ }
519
+
520
+ .caller-link {
521
+ color: var(--accent);
522
+ text-decoration: none;
523
+ cursor: pointer;
524
+ transition: color 0.2s;
525
+ }
526
+
527
+ .caller-link:hover {
528
+ color: var(--accent-hover);
529
+ text-decoration: underline;
530
+ }
531
+ """
532
+
533
+
534
+ def get_breadcrumb_styles() -> str:
535
+ """Get styles for breadcrumb navigation.
536
+
537
+ Returns:
538
+ CSS string for breadcrumb styling
539
+ """
540
+ return """
541
+ /* Breadcrumb navigation */
542
+ .breadcrumb-nav {
543
+ margin: 0 0 10px 0;
544
+ padding: 8px 12px;
545
+ background: var(--bg-secondary);
546
+ border: 1px solid var(--border-primary);
547
+ border-radius: 4px;
548
+ font-size: 12px;
549
+ line-height: 1.6;
550
+ overflow-x: auto;
551
+ white-space: nowrap;
552
+ }
553
+
554
+ .breadcrumb-root {
555
+ color: var(--accent);
556
+ cursor: pointer;
557
+ font-weight: 500;
558
+ transition: color 0.2s;
559
+ }
560
+
561
+ .breadcrumb-root:hover {
562
+ color: var(--accent-hover);
563
+ text-decoration: underline;
564
+ }
565
+
566
+ .breadcrumb-link {
567
+ color: var(--accent);
568
+ cursor: pointer;
569
+ transition: color 0.2s;
570
+ }
571
+
572
+ .breadcrumb-link:hover {
573
+ color: var(--accent-hover);
574
+ text-decoration: underline;
575
+ }
576
+
577
+ .breadcrumb-separator {
578
+ color: var(--text-tertiary);
579
+ margin: 0 6px;
580
+ }
581
+
582
+ .breadcrumb-current {
583
+ color: var(--text-primary);
584
+ font-weight: 600;
585
+ }
586
+ """
587
+
588
+
589
+ def get_content_pane_styles() -> str:
590
+ """Get styles for the viewer panel (code/file/directory viewer).
591
+
592
+ Returns:
593
+ CSS string for viewer panel styling
594
+ """
595
+ return """
596
+ .viewer-panel {
597
+ position: fixed;
598
+ top: 0;
599
+ right: 0;
600
+ width: 450px;
601
+ height: 100vh;
602
+ background: var(--bg-primary);
603
+ opacity: 0.98;
604
+ border-left: 1px solid var(--border-primary);
605
+ overflow-y: auto;
606
+ box-shadow: -4px 0 24px var(--shadow);
607
+ transform: translateX(100%);
608
+ transition: transform 0.3s ease-in-out;
609
+ z-index: 1000;
610
+ }
611
+
612
+ .viewer-panel.open {
613
+ transform: translateX(0);
614
+ }
615
+
616
+ .viewer-panel.expanded {
617
+ width: 70vw;
618
+ max-width: 1200px;
619
+ }
620
+
621
+ .viewer-header {
622
+ position: sticky;
623
+ top: 0;
624
+ background: var(--bg-primary);
625
+ opacity: 0.98;
626
+ padding: 16px 20px;
627
+ border-bottom: 1px solid var(--border-primary);
628
+ z-index: 1;
629
+ }
630
+
631
+ .viewer-header-buttons {
632
+ position: absolute;
633
+ top: 12px;
634
+ right: 12px;
635
+ display: flex;
636
+ gap: 8px;
637
+ }
638
+
639
+ .viewer-expand-btn {
640
+ cursor: pointer;
641
+ color: var(--text-primary);
642
+ font-size: 16px;
643
+ line-height: 1;
644
+ background: var(--bg-tertiary);
645
+ border: 1px solid var(--border-primary);
646
+ padding: 6px 8px;
647
+ transition: color 0.2s, background 0.2s, border-color 0.2s;
648
+ border-radius: 4px;
649
+ display: flex;
650
+ align-items: center;
651
+ justify-content: center;
652
+ }
653
+
654
+ .viewer-expand-btn:hover {
655
+ color: var(--accent);
656
+ background: var(--border-primary);
657
+ border-color: var(--accent);
658
+ }
659
+
660
+ .viewer-title {
661
+ font-size: 16px;
662
+ font-weight: bold;
663
+ color: var(--accent);
664
+ margin: 0 0 8px 0;
665
+ padding-right: 80px;
666
+ }
667
+
668
+ .section-nav {
669
+ margin-top: 8px;
670
+ }
671
+
672
+ .section-nav select {
673
+ background: var(--bg-tertiary);
674
+ color: var(--text-primary);
675
+ border: 1px solid var(--border-primary);
676
+ border-radius: 6px;
677
+ padding: 6px 10px;
678
+ font-size: 12px;
679
+ cursor: pointer;
680
+ width: 100%;
681
+ max-width: 250px;
682
+ }
683
+
684
+ .section-nav select:hover {
685
+ border-color: var(--accent);
686
+ }
687
+
688
+ .section-nav select:focus {
689
+ outline: none;
690
+ border-color: var(--accent);
691
+ box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.2);
692
+ }
693
+
694
+ .viewer-close-btn {
695
+ cursor: pointer;
696
+ color: var(--text-primary);
697
+ font-size: 18px;
698
+ line-height: 1;
699
+ background: var(--bg-tertiary);
700
+ border: 1px solid var(--border-primary);
701
+ padding: 6px 10px;
702
+ transition: color 0.2s, background 0.2s, border-color 0.2s;
703
+ border-radius: 4px;
704
+ display: flex;
705
+ align-items: center;
706
+ justify-content: center;
707
+ }
708
+
709
+ .viewer-close-btn:hover {
710
+ color: var(--error);
711
+ background: var(--border-primary);
712
+ border-color: var(--error);
713
+ }
714
+
715
+ .viewer-content {
716
+ padding: 20px;
717
+ }
718
+
719
+ .viewer-section {
720
+ margin-bottom: 24px;
721
+ }
722
+
723
+ .viewer-section-title {
724
+ font-size: 13px;
725
+ font-weight: 600;
726
+ color: #8b949e;
727
+ text-transform: uppercase;
728
+ letter-spacing: 0.5px;
729
+ margin-bottom: 12px;
730
+ }
731
+
732
+ .viewer-info-grid {
733
+ display: grid;
734
+ gap: 8px;
735
+ }
736
+
737
+ .viewer-info-row {
738
+ display: flex;
739
+ font-size: 13px;
740
+ }
741
+
742
+ .viewer-info-label {
743
+ color: #8b949e;
744
+ min-width: 100px;
745
+ font-weight: 500;
746
+ }
747
+
748
+ .viewer-info-value {
749
+ color: #c9d1d9;
750
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
751
+ }
752
+
753
+ .viewer-info-value.clickable {
754
+ color: #58a6ff;
755
+ cursor: pointer;
756
+ text-decoration: underline;
757
+ text-decoration-style: dotted;
758
+ text-underline-offset: 2px;
759
+ }
760
+
761
+ .viewer-info-value.clickable:hover {
762
+ color: #79c0ff;
763
+ text-decoration-style: solid;
764
+ }
765
+
766
+ .viewer-content pre {
767
+ margin: 0;
768
+ padding: 16px;
769
+ background: #0d1117;
770
+ border: 1px solid #30363d;
771
+ border-radius: 6px;
772
+ overflow-x: auto;
773
+ font-size: 12px;
774
+ line-height: 1.6;
775
+ }
776
+
777
+ .viewer-content code {
778
+ color: #c9d1d9;
779
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
780
+ }
781
+
782
+ .chunk-list {
783
+ display: flex;
784
+ flex-direction: column;
785
+ gap: 8px;
786
+ }
787
+
788
+ .chunk-list-item {
789
+ display: flex;
790
+ align-items: center;
791
+ gap: 10px;
792
+ padding: 10px 12px;
793
+ background: #161b22;
794
+ border: 1px solid #30363d;
795
+ border-radius: 6px;
796
+ cursor: pointer;
797
+ transition: all 0.2s ease;
798
+ }
799
+
800
+ .chunk-list-item:hover {
801
+ background: #21262d;
802
+ border-color: #58a6ff;
803
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
804
+ }
805
+
806
+ /* Relationship tags for callers/callees */
807
+ .relationship-tag {
808
+ display: inline-block;
809
+ padding: 2px 8px;
810
+ border-radius: 12px;
811
+ font-size: 11px;
812
+ cursor: pointer;
813
+ transition: all 0.2s ease;
814
+ }
815
+
816
+ .relationship-tag.caller {
817
+ background: rgba(88, 166, 255, 0.15);
818
+ color: #58a6ff;
819
+ border: 1px solid rgba(88, 166, 255, 0.3);
820
+ }
821
+
822
+ .relationship-tag.caller:hover {
823
+ background: rgba(88, 166, 255, 0.3);
824
+ border-color: #58a6ff;
825
+ }
826
+
827
+ .relationship-tag.callee {
828
+ background: rgba(240, 136, 62, 0.15);
829
+ color: #f0883e;
830
+ border: 1px solid rgba(240, 136, 62, 0.3);
831
+ }
832
+
833
+ .relationship-tag.callee:hover {
834
+ background: rgba(240, 136, 62, 0.3);
835
+ border-color: #f0883e;
836
+ }
837
+
838
+ /* Semantic similarity items */
839
+ .semantic-item {
840
+ display: flex;
841
+ align-items: center;
842
+ gap: 8px;
843
+ padding: 6px 10px;
844
+ background: #161b22;
845
+ border: 1px solid #30363d;
846
+ border-radius: 4px;
847
+ cursor: pointer;
848
+ transition: all 0.2s ease;
849
+ }
850
+
851
+ .semantic-item:hover {
852
+ background: #21262d;
853
+ border-color: #a371f7;
854
+ }
855
+
856
+ .semantic-score {
857
+ font-size: 11px;
858
+ font-weight: 600;
859
+ color: #a371f7;
860
+ background: rgba(163, 113, 247, 0.15);
861
+ padding: 2px 6px;
862
+ border-radius: 4px;
863
+ min-width: 36px;
864
+ text-align: center;
865
+ }
866
+
867
+ .semantic-name {
868
+ flex: 1;
869
+ color: #c9d1d9;
870
+ font-size: 12px;
871
+ overflow: hidden;
872
+ text-overflow: ellipsis;
873
+ white-space: nowrap;
874
+ }
875
+
876
+ .semantic-type {
877
+ font-size: 10px;
878
+ color: #8b949e;
879
+ text-transform: uppercase;
880
+ }
881
+
882
+ /* External Calls/Callers Styles */
883
+ .external-call-item {
884
+ display: flex;
885
+ align-items: center;
886
+ gap: 10px;
887
+ padding: 8px 12px;
888
+ background: #161b22;
889
+ border: 1px solid #30363d;
890
+ border-radius: 6px;
891
+ cursor: pointer;
892
+ transition: all 0.2s ease;
893
+ }
894
+
895
+ .external-call-item:hover {
896
+ background: #21262d;
897
+ border-color: #58a6ff;
898
+ transform: translateX(4px);
899
+ }
900
+
901
+ .external-call-icon {
902
+ font-size: 14px;
903
+ font-weight: bold;
904
+ color: #58a6ff;
905
+ width: 20px;
906
+ text-align: center;
907
+ }
908
+
909
+ .external-call-name {
910
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
911
+ font-size: 12px;
912
+ font-weight: 600;
913
+ color: #58a6ff;
914
+ flex-shrink: 0;
915
+ }
916
+
917
+ .external-call-path {
918
+ font-size: 11px;
919
+ color: #8b949e;
920
+ flex: 1;
921
+ overflow: hidden;
922
+ text-overflow: ellipsis;
923
+ white-space: nowrap;
924
+ text-align: right;
925
+ }
926
+
927
+ .chunk-icon {
928
+ font-size: 16px;
929
+ flex-shrink: 0;
930
+ }
931
+
932
+ .chunk-info {
933
+ flex: 1;
934
+ min-width: 0;
935
+ }
936
+
937
+ .chunk-name {
938
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
939
+ font-size: 13px;
940
+ color: #c9d1d9;
941
+ font-weight: 500;
942
+ overflow: hidden;
943
+ text-overflow: ellipsis;
944
+ white-space: nowrap;
945
+ }
946
+
947
+ .chunk-meta {
948
+ font-size: 11px;
949
+ color: #8b949e;
950
+ margin-top: 2px;
951
+ }
952
+
953
+ .dir-list {
954
+ display: flex;
955
+ flex-direction: column;
956
+ gap: 6px;
957
+ }
958
+
959
+ .dir-list-item {
960
+ display: flex;
961
+ align-items: center;
962
+ gap: 10px;
963
+ padding: 10px 12px;
964
+ background: #161b22;
965
+ border: 1px solid #30363d;
966
+ border-radius: 6px;
967
+ cursor: pointer;
968
+ transition: all 0.2s ease;
969
+ }
970
+
971
+ .dir-list-item:hover {
972
+ background: #21262d;
973
+ border-color: #58a6ff;
974
+ }
975
+
976
+ .dir-icon {
977
+ font-size: 16px;
978
+ flex-shrink: 0;
979
+ }
980
+
981
+ .dir-name {
982
+ flex: 1;
983
+ font-size: 13px;
984
+ color: #c9d1d9;
985
+ overflow: hidden;
986
+ text-overflow: ellipsis;
987
+ white-space: nowrap;
988
+ }
989
+
990
+ .dir-type {
991
+ font-size: 11px;
992
+ color: #8b949e;
993
+ text-transform: uppercase;
994
+ }
995
+
996
+ .dir-arrow {
997
+ color: #58a6ff;
998
+ font-size: 14px;
999
+ opacity: 0;
1000
+ transition: opacity 0.2s ease;
1001
+ }
1002
+
1003
+ .dir-list-item:hover .dir-arrow {
1004
+ opacity: 1;
1005
+ }
1006
+
1007
+ .dir-list-item.clickable {
1008
+ cursor: pointer;
1009
+ }
1010
+
1011
+ /* Navigation bar styles */
1012
+ .navigation-bar {
1013
+ display: flex;
1014
+ align-items: center;
1015
+ gap: 8px;
1016
+ padding: 8px 0;
1017
+ margin-bottom: 12px;
1018
+ border-bottom: 1px solid #30363d;
1019
+ }
1020
+
1021
+ .nav-btn {
1022
+ width: 28px;
1023
+ height: 28px;
1024
+ display: flex;
1025
+ align-items: center;
1026
+ justify-content: center;
1027
+ background: #21262d;
1028
+ border: 1px solid #30363d;
1029
+ border-radius: 4px;
1030
+ color: #c9d1d9;
1031
+ cursor: pointer;
1032
+ font-size: 14px;
1033
+ transition: all 0.2s ease;
1034
+ }
1035
+
1036
+ .nav-btn:hover:not(.disabled) {
1037
+ background: #30363d;
1038
+ border-color: #58a6ff;
1039
+ }
1040
+
1041
+ .nav-btn.disabled {
1042
+ opacity: 0.4;
1043
+ cursor: not-allowed;
1044
+ }
1045
+
1046
+ .breadcrumb-trail {
1047
+ display: flex;
1048
+ align-items: center;
1049
+ flex-wrap: wrap;
1050
+ gap: 4px;
1051
+ flex: 1;
1052
+ min-width: 0;
1053
+ overflow: hidden;
1054
+ }
1055
+
1056
+ .breadcrumb-separator {
1057
+ color: #484f58;
1058
+ font-size: 12px;
1059
+ }
1060
+
1061
+ .breadcrumb-item {
1062
+ font-size: 12px;
1063
+ color: #8b949e;
1064
+ max-width: 120px;
1065
+ overflow: hidden;
1066
+ text-overflow: ellipsis;
1067
+ white-space: nowrap;
1068
+ }
1069
+
1070
+ .breadcrumb-item.clickable {
1071
+ color: #58a6ff;
1072
+ cursor: pointer;
1073
+ }
1074
+
1075
+ .breadcrumb-item.clickable:hover {
1076
+ text-decoration: underline;
1077
+ }
1078
+
1079
+ .breadcrumb-item.current {
1080
+ color: #c9d1d9;
1081
+ font-weight: 500;
1082
+ }
1083
+
1084
+ /* Node highlight animation - temporary focus */
1085
+ .node-highlight circle {
1086
+ stroke: #58a6ff !important;
1087
+ stroke-width: 4px !important;
1088
+ filter: drop-shadow(0 0 8px rgba(88, 166, 255, 0.8));
1089
+ }
1090
+
1091
+ .node-highlight text {
1092
+ fill: #58a6ff !important;
1093
+ font-weight: bold !important;
1094
+ }
1095
+
1096
+ /* Selected node - persistent highlight for node shown in viewer */
1097
+ .node-selected circle {
1098
+ stroke: #f0883e !important;
1099
+ stroke-width: 5px !important;
1100
+ filter: drop-shadow(0 0 12px rgba(240, 136, 62, 0.9));
1101
+ animation: selected-pulse 2s ease-in-out infinite;
1102
+ }
1103
+
1104
+ .node-selected text {
1105
+ fill: #f0883e !important;
1106
+ font-weight: bold !important;
1107
+ }
1108
+
1109
+ @keyframes selected-pulse {
1110
+ 0%, 100% { filter: drop-shadow(0 0 12px rgba(240, 136, 62, 0.9)); }
1111
+ 50% { filter: drop-shadow(0 0 20px rgba(240, 136, 62, 1.0)); }
1112
+ }
1113
+ """
1114
+
1115
+
1116
+ def get_code_chunks_styles() -> str:
1117
+ """Get styles for code chunks section in file viewer.
1118
+
1119
+ Returns:
1120
+ CSS string for code chunks styling
1121
+ """
1122
+ return """
1123
+ /* Code chunks section */
1124
+ .code-chunks-section {
1125
+ margin: 0 0 20px 0;
1126
+ padding: 15px;
1127
+ background: #161b22;
1128
+ border-radius: 6px;
1129
+ border: 1px solid #30363d;
1130
+ }
1131
+
1132
+ .section-header {
1133
+ margin: 0 0 12px 0;
1134
+ font-size: 13px;
1135
+ font-weight: 600;
1136
+ color: #c9d1d9;
1137
+ text-transform: uppercase;
1138
+ letter-spacing: 0.5px;
1139
+ }
1140
+
1141
+ .code-chunks-list {
1142
+ display: flex;
1143
+ flex-direction: column;
1144
+ gap: 6px;
1145
+ }
1146
+
1147
+ .code-chunk-item {
1148
+ display: flex;
1149
+ align-items: center;
1150
+ gap: 8px;
1151
+ padding: 8px 12px;
1152
+ background: #0d1117;
1153
+ border: 1px solid #30363d;
1154
+ border-radius: 4px;
1155
+ cursor: pointer;
1156
+ transition: all 0.2s ease;
1157
+ }
1158
+
1159
+ .code-chunk-item:hover {
1160
+ background: #21262d;
1161
+ border-color: #58a6ff;
1162
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
1163
+ }
1164
+
1165
+ .chunk-icon {
1166
+ font-size: 16px;
1167
+ flex-shrink: 0;
1168
+ }
1169
+
1170
+ .chunk-name {
1171
+ flex: 1;
1172
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
1173
+ font-size: 13px;
1174
+ color: #c9d1d9;
1175
+ font-weight: 500;
1176
+ overflow: hidden;
1177
+ text-overflow: ellipsis;
1178
+ white-space: nowrap;
1179
+ }
1180
+
1181
+ .line-range {
1182
+ font-size: 11px;
1183
+ color: #8b949e;
1184
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
1185
+ background: #161b22;
1186
+ padding: 2px 6px;
1187
+ border-radius: 3px;
1188
+ flex-shrink: 0;
1189
+ }
1190
+
1191
+ .chunk-type {
1192
+ font-size: 11px;
1193
+ color: #ffffff;
1194
+ background: #6e7681;
1195
+ padding: 2px 8px;
1196
+ border-radius: 12px;
1197
+ text-transform: lowercase;
1198
+ flex-shrink: 0;
1199
+ }
1200
+
1201
+ /* Type-specific colors for chunk badges */
1202
+ .code-chunk-item[data-type="function"] .chunk-type {
1203
+ background: #d29922;
1204
+ }
1205
+
1206
+ .code-chunk-item[data-type="class"] .chunk-type {
1207
+ background: #1f6feb;
1208
+ }
1209
+
1210
+ .code-chunk-item[data-type="method"] .chunk-type {
1211
+ background: #8957e5;
1212
+ }
1213
+
1214
+ .code-chunk-item[data-type="code"] .chunk-type {
1215
+ background: #6e7681;
1216
+ }
1217
+ """
1218
+
1219
+
1220
+ def get_reset_button_styles() -> str:
1221
+ """Get styles for the reset view button.
1222
+
1223
+ Returns:
1224
+ CSS string for reset button styling
1225
+ """
1226
+ return """
1227
+ #reset-view-btn {
1228
+ position: fixed;
1229
+ top: 20px;
1230
+ right: 460px;
1231
+ padding: 8px 16px;
1232
+ background: #21262d;
1233
+ border: 1px solid #30363d;
1234
+ border-radius: 6px;
1235
+ color: #c9d1d9;
1236
+ font-size: 14px;
1237
+ cursor: pointer;
1238
+ display: flex;
1239
+ align-items: center;
1240
+ gap: 8px;
1241
+ z-index: 100;
1242
+ transition: all 0.2s;
1243
+ }
1244
+
1245
+ #reset-view-btn:hover {
1246
+ background: #30363d;
1247
+ border-color: #58a6ff;
1248
+ transform: translateY(-1px);
1249
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
1250
+ }
1251
+ """
1252
+
1253
+
1254
+ def get_spinner_styles() -> str:
1255
+ """Get styles for the loading spinner animation.
1256
+
1257
+ Returns:
1258
+ CSS string for spinner styling and animation
1259
+ """
1260
+ return """
1261
+ /* Loading spinner animation */
1262
+ @keyframes spin {
1263
+ 0% { transform: rotate(0deg); }
1264
+ 100% { transform: rotate(360deg); }
1265
+ }
1266
+
1267
+ .spinner {
1268
+ display: inline-block;
1269
+ width: 20px;
1270
+ height: 20px;
1271
+ border: 3px solid #30363d;
1272
+ border-top-color: #58a6ff;
1273
+ border-radius: 50%;
1274
+ animation: spin 0.8s linear infinite;
1275
+ margin-right: 8px;
1276
+ vertical-align: middle;
1277
+ }
1278
+ """
1279
+
1280
+
1281
+ def get_theme_toggle_styles() -> str:
1282
+ """Get styles for the theme toggle button.
1283
+
1284
+ Returns:
1285
+ CSS string for theme toggle styling
1286
+ """
1287
+ return """
1288
+ .theme-toggle-icon-btn {
1289
+ width: 36px;
1290
+ height: 36px;
1291
+ padding: 0;
1292
+ background: var(--bg-tertiary);
1293
+ border: 1px solid var(--border-primary);
1294
+ border-radius: 6px;
1295
+ color: var(--text-primary);
1296
+ cursor: pointer;
1297
+ display: flex;
1298
+ align-items: center;
1299
+ justify-content: center;
1300
+ transition: all 0.2s ease;
1301
+ flex-shrink: 0;
1302
+ }
1303
+
1304
+ .theme-toggle-icon-btn:hover {
1305
+ background: var(--accent);
1306
+ border-color: var(--accent-hover);
1307
+ transform: scale(1.05);
1308
+ }
1309
+
1310
+ .theme-toggle-icon-btn .theme-icon {
1311
+ font-size: 18px;
1312
+ line-height: 1;
1313
+ }
1314
+
1315
+ /* Complexity grade colors for nodes */
1316
+ .grade-A { fill: #238636 !important; stroke: #2ea043; }
1317
+ .grade-B { fill: #1f6feb !important; stroke: #388bfd; }
1318
+ .grade-C { fill: #d29922 !important; stroke: #e0ac3a; }
1319
+ .grade-D { fill: #f0883e !important; stroke: #f59f5f; }
1320
+ .grade-F { fill: #da3633 !important; stroke: #f85149; }
1321
+
1322
+ /* Code smell indicator - red border */
1323
+ .has-smells circle {
1324
+ stroke: var(--error) !important;
1325
+ stroke-width: 3px !important;
1326
+ stroke-dasharray: 5, 3;
1327
+ }
1328
+
1329
+ /* Circular dependency indicator */
1330
+ .in-cycle circle {
1331
+ stroke: #ff4444 !important;
1332
+ stroke-width: 3px !important;
1333
+ animation: pulse-border 1.5s infinite;
1334
+ }
1335
+
1336
+ @keyframes pulse-border {
1337
+ 0%, 100% { stroke-opacity: 0.8; }
1338
+ 50% { stroke-opacity: 1.0; }
1339
+ }
1340
+ """
1341
+
1342
+
1343
+ def get_search_styles() -> str:
1344
+ """Get styles for the search box and results dropdown.
1345
+
1346
+ Returns:
1347
+ CSS string for search styling
1348
+ """
1349
+ return """
1350
+ /* Search box styles */
1351
+ .search-container {
1352
+ position: relative;
1353
+ margin-bottom: 16px;
1354
+ z-index: 100;
1355
+ }
1356
+
1357
+ #search-input {
1358
+ width: 100%;
1359
+ padding: 10px 12px;
1360
+ background: var(--bg-secondary);
1361
+ border: 1px solid var(--border-primary);
1362
+ border-radius: 6px;
1363
+ color: var(--text-primary);
1364
+ font-size: 13px;
1365
+ outline: none;
1366
+ transition: border-color 0.2s, box-shadow 0.2s;
1367
+ box-sizing: border-box;
1368
+ position: relative;
1369
+ z-index: 101;
1370
+ cursor: text;
1371
+ }
1372
+
1373
+ #search-input:focus {
1374
+ border-color: var(--accent);
1375
+ box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.2);
1376
+ }
1377
+
1378
+ #search-input::placeholder {
1379
+ color: var(--text-secondary);
1380
+ }
1381
+
1382
+ /* Search results dropdown */
1383
+ .search-results {
1384
+ position: absolute;
1385
+ top: 100%;
1386
+ left: 0;
1387
+ right: 0;
1388
+ max-height: 300px;
1389
+ overflow-y: auto;
1390
+ background: var(--bg-secondary);
1391
+ border: 1px solid var(--border-primary);
1392
+ border-top: none;
1393
+ border-radius: 0 0 6px 6px;
1394
+ z-index: 1000;
1395
+ display: none;
1396
+ box-shadow: 0 4px 12px var(--shadow);
1397
+ }
1398
+
1399
+ .search-results.visible {
1400
+ display: block;
1401
+ }
1402
+
1403
+ .search-result-item {
1404
+ display: flex;
1405
+ align-items: center;
1406
+ gap: 10px;
1407
+ padding: 10px 12px;
1408
+ cursor: pointer;
1409
+ border-bottom: 1px solid var(--border-secondary);
1410
+ transition: background 0.15s;
1411
+ }
1412
+
1413
+ .search-result-item:last-child {
1414
+ border-bottom: none;
1415
+ }
1416
+
1417
+ .search-result-item:hover,
1418
+ .search-result-item.selected {
1419
+ background: var(--bg-tertiary);
1420
+ }
1421
+
1422
+ .search-result-icon {
1423
+ font-size: 14px;
1424
+ flex-shrink: 0;
1425
+ width: 20px;
1426
+ text-align: center;
1427
+ }
1428
+
1429
+ .search-result-info {
1430
+ flex: 1;
1431
+ min-width: 0;
1432
+ overflow: hidden;
1433
+ }
1434
+
1435
+ .search-result-name {
1436
+ font-size: 13px;
1437
+ color: var(--text-primary);
1438
+ font-weight: 500;
1439
+ overflow: hidden;
1440
+ text-overflow: ellipsis;
1441
+ white-space: nowrap;
1442
+ }
1443
+
1444
+ .search-result-name mark {
1445
+ background: rgba(88, 166, 255, 0.3);
1446
+ color: var(--accent);
1447
+ border-radius: 2px;
1448
+ padding: 0 2px;
1449
+ }
1450
+
1451
+ .search-result-path {
1452
+ font-size: 11px;
1453
+ color: var(--text-secondary);
1454
+ overflow: hidden;
1455
+ text-overflow: ellipsis;
1456
+ white-space: nowrap;
1457
+ margin-top: 2px;
1458
+ }
1459
+
1460
+ .search-result-type {
1461
+ font-size: 10px;
1462
+ color: var(--text-secondary);
1463
+ background: var(--bg-tertiary);
1464
+ padding: 2px 6px;
1465
+ border-radius: 10px;
1466
+ text-transform: uppercase;
1467
+ flex-shrink: 0;
1468
+ }
1469
+
1470
+ .search-no-results {
1471
+ padding: 20px;
1472
+ text-align: center;
1473
+ color: var(--text-secondary);
1474
+ font-size: 13px;
1475
+ }
1476
+
1477
+ .search-hint {
1478
+ padding: 8px 12px;
1479
+ font-size: 11px;
1480
+ color: var(--text-tertiary);
1481
+ background: var(--bg-primary);
1482
+ border-top: 1px solid var(--border-secondary);
1483
+ }
1484
+ """
1485
+
1486
+
1487
+ def get_complexity_report_styles() -> str:
1488
+ """Get styles for the complexity report.
1489
+
1490
+ Returns:
1491
+ CSS string for complexity report styling
1492
+ """
1493
+ return """
1494
+ /* Complexity Report Styles */
1495
+ .complexity-report {
1496
+ padding: 0;
1497
+ }
1498
+
1499
+ /* Summary Section */
1500
+ .complexity-summary {
1501
+ margin-bottom: 24px;
1502
+ }
1503
+
1504
+ .summary-grid {
1505
+ display: grid;
1506
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
1507
+ gap: 12px;
1508
+ margin-bottom: 20px;
1509
+ }
1510
+
1511
+ .summary-card {
1512
+ background: var(--bg-secondary);
1513
+ border: 1px solid var(--border-primary);
1514
+ border-radius: 6px;
1515
+ padding: 16px;
1516
+ text-align: center;
1517
+ }
1518
+
1519
+ .summary-label {
1520
+ font-size: 11px;
1521
+ color: var(--text-secondary);
1522
+ text-transform: uppercase;
1523
+ letter-spacing: 0.5px;
1524
+ margin-bottom: 8px;
1525
+ }
1526
+
1527
+ .summary-value {
1528
+ font-size: 24px;
1529
+ font-weight: bold;
1530
+ color: var(--accent);
1531
+ }
1532
+
1533
+ /* Grade Distribution */
1534
+ .grade-distribution {
1535
+ background: var(--bg-secondary);
1536
+ border: 1px solid var(--border-primary);
1537
+ border-radius: 6px;
1538
+ padding: 16px;
1539
+ }
1540
+
1541
+ .distribution-title {
1542
+ font-size: 13px;
1543
+ font-weight: 600;
1544
+ color: var(--text-primary);
1545
+ margin-bottom: 12px;
1546
+ text-transform: uppercase;
1547
+ letter-spacing: 0.5px;
1548
+ }
1549
+
1550
+ .distribution-bars {
1551
+ display: flex;
1552
+ flex-direction: column;
1553
+ gap: 8px;
1554
+ }
1555
+
1556
+ .distribution-row {
1557
+ display: grid;
1558
+ grid-template-columns: 40px 1fr 100px;
1559
+ gap: 12px;
1560
+ align-items: center;
1561
+ }
1562
+
1563
+ .distribution-grade {
1564
+ font-size: 14px;
1565
+ font-weight: bold;
1566
+ text-align: center;
1567
+ }
1568
+
1569
+ .distribution-bar-container {
1570
+ background: var(--bg-tertiary);
1571
+ border-radius: 4px;
1572
+ height: 24px;
1573
+ overflow: hidden;
1574
+ border: 1px solid var(--border-primary);
1575
+ }
1576
+
1577
+ .distribution-bar {
1578
+ height: 100%;
1579
+ border-radius: 3px;
1580
+ transition: width 0.3s ease;
1581
+ opacity: 0.8;
1582
+ }
1583
+
1584
+ .distribution-count {
1585
+ font-size: 12px;
1586
+ color: var(--text-secondary);
1587
+ text-align: right;
1588
+ }
1589
+
1590
+ /* Hotspots Section */
1591
+ .complexity-hotspots {
1592
+ margin-top: 24px;
1593
+ }
1594
+
1595
+ .section-title {
1596
+ font-size: 14px;
1597
+ font-weight: 600;
1598
+ color: var(--text-primary);
1599
+ margin-bottom: 12px;
1600
+ text-transform: uppercase;
1601
+ letter-spacing: 0.5px;
1602
+ }
1603
+
1604
+ .hotspots-table-container {
1605
+ background: var(--bg-secondary);
1606
+ border: 1px solid var(--border-primary);
1607
+ border-radius: 6px;
1608
+ overflow: hidden;
1609
+ }
1610
+
1611
+ .hotspots-table {
1612
+ width: 100%;
1613
+ border-collapse: collapse;
1614
+ font-size: 13px;
1615
+ }
1616
+
1617
+ .hotspots-table thead {
1618
+ background: var(--bg-tertiary);
1619
+ position: sticky;
1620
+ top: 0;
1621
+ z-index: 10;
1622
+ }
1623
+
1624
+ .hotspots-table th {
1625
+ padding: 12px;
1626
+ text-align: left;
1627
+ font-weight: 600;
1628
+ color: var(--text-secondary);
1629
+ text-transform: uppercase;
1630
+ font-size: 11px;
1631
+ letter-spacing: 0.5px;
1632
+ border-bottom: 1px solid var(--border-primary);
1633
+ }
1634
+
1635
+ .hotspots-table tbody tr {
1636
+ border-bottom: 1px solid var(--border-secondary);
1637
+ }
1638
+
1639
+ .hotspots-table tbody tr:last-child {
1640
+ border-bottom: none;
1641
+ }
1642
+
1643
+ .hotspot-row {
1644
+ cursor: pointer;
1645
+ transition: background 0.2s ease;
1646
+ }
1647
+
1648
+ .hotspot-row:hover {
1649
+ background: var(--bg-tertiary);
1650
+ }
1651
+
1652
+ .hotspots-table td {
1653
+ padding: 12px;
1654
+ color: var(--text-primary);
1655
+ }
1656
+
1657
+ .hotspot-name {
1658
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
1659
+ font-weight: 500;
1660
+ color: var(--accent);
1661
+ }
1662
+
1663
+ .hotspot-file {
1664
+ color: var(--text-secondary);
1665
+ font-size: 12px;
1666
+ max-width: 200px;
1667
+ overflow: hidden;
1668
+ text-overflow: ellipsis;
1669
+ white-space: nowrap;
1670
+ }
1671
+
1672
+ .hotspot-lines {
1673
+ text-align: center;
1674
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
1675
+ font-size: 12px;
1676
+ }
1677
+
1678
+ .hotspot-complexity {
1679
+ text-align: center;
1680
+ font-weight: bold;
1681
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
1682
+ }
1683
+
1684
+ .hotspot-grade {
1685
+ text-align: center;
1686
+ }
1687
+
1688
+ .grade-badge {
1689
+ display: inline-block;
1690
+ padding: 4px 10px;
1691
+ border-radius: 12px;
1692
+ font-weight: bold;
1693
+ font-size: 11px;
1694
+ color: white;
1695
+ min-width: 28px;
1696
+ text-align: center;
1697
+ }
1698
+ """
1699
+
1700
+
1701
+ def get_code_smells_styles() -> str:
1702
+ """Get styles for the code smells report.
1703
+
1704
+ Returns:
1705
+ CSS string for code smells styling
1706
+ """
1707
+ return """
1708
+ /* Code Smells Report Styles */
1709
+ .code-smells-report {
1710
+ padding: 0;
1711
+ }
1712
+
1713
+ /* Smell Type Filters */
1714
+ .smell-filters {
1715
+ background: var(--bg-secondary);
1716
+ border: 1px solid var(--border-primary);
1717
+ border-radius: 6px;
1718
+ padding: 16px;
1719
+ margin-bottom: 20px;
1720
+ }
1721
+
1722
+ .filter-title {
1723
+ font-size: 12px;
1724
+ font-weight: 600;
1725
+ color: var(--text-primary);
1726
+ margin-bottom: 12px;
1727
+ text-transform: uppercase;
1728
+ letter-spacing: 0.5px;
1729
+ }
1730
+
1731
+ .filter-checkboxes {
1732
+ display: grid;
1733
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
1734
+ gap: 10px;
1735
+ }
1736
+
1737
+ .filter-checkbox-item {
1738
+ display: flex;
1739
+ align-items: center;
1740
+ gap: 8px;
1741
+ padding: 8px 12px;
1742
+ background: var(--bg-tertiary);
1743
+ border: 1px solid var(--border-primary);
1744
+ border-radius: 4px;
1745
+ cursor: pointer;
1746
+ transition: all 0.2s ease;
1747
+ }
1748
+
1749
+ .filter-checkbox-item:hover {
1750
+ background: var(--bg-primary);
1751
+ border-color: var(--accent);
1752
+ }
1753
+
1754
+ .filter-checkbox-item input[type="checkbox"] {
1755
+ cursor: pointer;
1756
+ width: 16px;
1757
+ height: 16px;
1758
+ }
1759
+
1760
+ .filter-checkbox-label {
1761
+ flex: 1;
1762
+ font-size: 12px;
1763
+ color: var(--text-primary);
1764
+ cursor: pointer;
1765
+ }
1766
+
1767
+ .filter-checkbox-count {
1768
+ font-size: 11px;
1769
+ color: var(--text-secondary);
1770
+ background: var(--bg-secondary);
1771
+ padding: 2px 8px;
1772
+ border-radius: 10px;
1773
+ }
1774
+
1775
+ /* Smell Summary Cards */
1776
+ .smell-summary-grid {
1777
+ display: grid;
1778
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
1779
+ gap: 12px;
1780
+ margin-bottom: 24px;
1781
+ }
1782
+
1783
+ .smell-summary-card {
1784
+ background: var(--bg-secondary);
1785
+ border: 1px solid var(--border-primary);
1786
+ border-radius: 6px;
1787
+ padding: 16px;
1788
+ }
1789
+
1790
+ .smell-summary-card.warning {
1791
+ border-left: 3px solid var(--warning);
1792
+ }
1793
+
1794
+ .smell-summary-card.error {
1795
+ border-left: 3px solid var(--error);
1796
+ }
1797
+
1798
+ .smell-card-header {
1799
+ display: flex;
1800
+ align-items: center;
1801
+ gap: 8px;
1802
+ margin-bottom: 8px;
1803
+ }
1804
+
1805
+ .smell-card-icon {
1806
+ font-size: 18px;
1807
+ }
1808
+
1809
+ .smell-card-title {
1810
+ font-size: 11px;
1811
+ color: var(--text-secondary);
1812
+ text-transform: uppercase;
1813
+ letter-spacing: 0.5px;
1814
+ flex: 1;
1815
+ }
1816
+
1817
+ .smell-card-count {
1818
+ font-size: 24px;
1819
+ font-weight: bold;
1820
+ color: var(--text-primary);
1821
+ }
1822
+
1823
+ /* Smells Table */
1824
+ .smells-table-container {
1825
+ background: var(--bg-secondary);
1826
+ border: 1px solid var(--border-primary);
1827
+ border-radius: 6px;
1828
+ overflow: hidden;
1829
+ }
1830
+
1831
+ .smells-table {
1832
+ width: 100%;
1833
+ border-collapse: collapse;
1834
+ font-size: 13px;
1835
+ }
1836
+
1837
+ .smells-table thead {
1838
+ background: var(--bg-tertiary);
1839
+ position: sticky;
1840
+ top: 0;
1841
+ z-index: 10;
1842
+ }
1843
+
1844
+ .smells-table th {
1845
+ padding: 12px;
1846
+ text-align: left;
1847
+ font-weight: 600;
1848
+ color: var(--text-secondary);
1849
+ text-transform: uppercase;
1850
+ font-size: 11px;
1851
+ letter-spacing: 0.5px;
1852
+ border-bottom: 1px solid var(--border-primary);
1853
+ }
1854
+
1855
+ .smells-table tbody tr {
1856
+ border-bottom: 1px solid var(--border-secondary);
1857
+ }
1858
+
1859
+ .smells-table tbody tr:last-child {
1860
+ border-bottom: none;
1861
+ }
1862
+
1863
+ .smell-row {
1864
+ cursor: pointer;
1865
+ transition: background 0.2s ease;
1866
+ }
1867
+
1868
+ .smell-row:hover {
1869
+ background: var(--bg-tertiary);
1870
+ }
1871
+
1872
+ .smells-table td {
1873
+ padding: 12px;
1874
+ color: var(--text-primary);
1875
+ }
1876
+
1877
+ .smell-type-badge {
1878
+ display: inline-block;
1879
+ padding: 4px 10px;
1880
+ border-radius: 12px;
1881
+ font-weight: 500;
1882
+ font-size: 11px;
1883
+ background: var(--bg-tertiary);
1884
+ color: var(--text-primary);
1885
+ white-space: nowrap;
1886
+ }
1887
+
1888
+ .severity-badge {
1889
+ display: inline-flex;
1890
+ align-items: center;
1891
+ gap: 4px;
1892
+ padding: 4px 10px;
1893
+ border-radius: 12px;
1894
+ font-weight: bold;
1895
+ font-size: 11px;
1896
+ min-width: 70px;
1897
+ justify-content: center;
1898
+ }
1899
+
1900
+ .severity-badge.warning {
1901
+ background: rgba(210, 153, 34, 0.2);
1902
+ color: var(--warning);
1903
+ border: 1px solid var(--warning);
1904
+ }
1905
+
1906
+ .severity-badge.error {
1907
+ background: rgba(218, 54, 51, 0.2);
1908
+ color: var(--error);
1909
+ border: 1px solid var(--error);
1910
+ }
1911
+
1912
+ .smell-name {
1913
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
1914
+ font-weight: 500;
1915
+ color: var(--accent);
1916
+ }
1917
+
1918
+ .smell-file {
1919
+ color: var(--text-secondary);
1920
+ font-size: 12px;
1921
+ max-width: 200px;
1922
+ overflow: hidden;
1923
+ text-overflow: ellipsis;
1924
+ white-space: nowrap;
1925
+ }
1926
+
1927
+ .smell-details {
1928
+ font-size: 12px;
1929
+ color: var(--text-secondary);
1930
+ }
1931
+ """
1932
+
1933
+
1934
+ def get_dependencies_styles() -> str:
1935
+ """Get styles for the dependencies report.
1936
+
1937
+ Returns:
1938
+ CSS string for dependencies styling
1939
+ """
1940
+ return """
1941
+ /* Dependencies Report Styles */
1942
+ .dependencies-report {
1943
+ padding: 0;
1944
+ }
1945
+
1946
+ .dependency-summary {
1947
+ margin-bottom: 24px;
1948
+ }
1949
+
1950
+ /* Circular Dependencies Warning */
1951
+ .circular-deps-warning {
1952
+ background: rgba(218, 54, 51, 0.1);
1953
+ border: 2px solid var(--error);
1954
+ border-radius: 6px;
1955
+ padding: 16px;
1956
+ margin-bottom: 24px;
1957
+ }
1958
+
1959
+ .warning-header {
1960
+ display: flex;
1961
+ align-items: center;
1962
+ gap: 12px;
1963
+ margin-bottom: 12px;
1964
+ }
1965
+
1966
+ .warning-icon {
1967
+ font-size: 24px;
1968
+ }
1969
+
1970
+ .warning-title {
1971
+ font-size: 14px;
1972
+ font-weight: 600;
1973
+ color: var(--error);
1974
+ text-transform: uppercase;
1975
+ letter-spacing: 0.5px;
1976
+ }
1977
+
1978
+ .cycle-list {
1979
+ display: flex;
1980
+ flex-direction: column;
1981
+ gap: 8px;
1982
+ padding-left: 36px;
1983
+ }
1984
+
1985
+ .cycle-item {
1986
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
1987
+ font-size: 12px;
1988
+ color: var(--text-primary);
1989
+ padding: 8px 12px;
1990
+ background: var(--bg-secondary);
1991
+ border-left: 3px solid var(--error);
1992
+ border-radius: 4px;
1993
+ overflow: hidden;
1994
+ text-overflow: ellipsis;
1995
+ white-space: nowrap;
1996
+ }
1997
+
1998
+ /* Dependencies Table */
1999
+ .dependencies-table-section {
2000
+ margin-top: 24px;
2001
+ }
2002
+
2003
+ .dependencies-table-container {
2004
+ background: var(--bg-secondary);
2005
+ border: 1px solid var(--border-primary);
2006
+ border-radius: 6px;
2007
+ overflow: hidden;
2008
+ }
2009
+
2010
+ .dependencies-table {
2011
+ width: 100%;
2012
+ border-collapse: collapse;
2013
+ font-size: 13px;
2014
+ }
2015
+
2016
+ .dependencies-table thead {
2017
+ background: var(--bg-tertiary);
2018
+ position: sticky;
2019
+ top: 0;
2020
+ z-index: 10;
2021
+ }
2022
+
2023
+ .dependencies-table th {
2024
+ padding: 12px;
2025
+ text-align: left;
2026
+ font-weight: 600;
2027
+ color: var(--text-secondary);
2028
+ text-transform: uppercase;
2029
+ font-size: 11px;
2030
+ letter-spacing: 0.5px;
2031
+ border-bottom: 1px solid var(--border-primary);
2032
+ }
2033
+
2034
+ .dependencies-table th:nth-child(2),
2035
+ .dependencies-table th:nth-child(3),
2036
+ .dependencies-table th:nth-child(4) {
2037
+ text-align: center;
2038
+ }
2039
+
2040
+ .dependencies-table th:nth-child(5) {
2041
+ width: 50px;
2042
+ text-align: center;
2043
+ }
2044
+
2045
+ .dependencies-table tbody tr.dependency-row {
2046
+ border-bottom: 1px solid var(--border-secondary);
2047
+ transition: background 0.2s ease;
2048
+ }
2049
+
2050
+ .dependencies-table tbody tr.dependency-row:hover {
2051
+ background: var(--bg-tertiary);
2052
+ }
2053
+
2054
+ .dependencies-table tbody tr.dependency-row.in-cycle {
2055
+ background: rgba(218, 54, 51, 0.05);
2056
+ }
2057
+
2058
+ .dependencies-table tbody tr.dependency-row.in-cycle:hover {
2059
+ background: rgba(218, 54, 51, 0.1);
2060
+ }
2061
+
2062
+ .dependencies-table td {
2063
+ padding: 12px;
2064
+ color: var(--text-primary);
2065
+ }
2066
+
2067
+ .dep-file {
2068
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2069
+ font-weight: 500;
2070
+ color: var(--accent);
2071
+ }
2072
+
2073
+ .dep-count {
2074
+ text-align: center;
2075
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2076
+ color: var(--text-secondary);
2077
+ }
2078
+
2079
+ .dep-total {
2080
+ text-align: center;
2081
+ font-weight: bold;
2082
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2083
+ color: var(--text-primary);
2084
+ }
2085
+
2086
+ .dep-expand {
2087
+ text-align: center;
2088
+ }
2089
+
2090
+ .expand-btn {
2091
+ background: var(--bg-tertiary);
2092
+ border: 1px solid var(--border-primary);
2093
+ border-radius: 4px;
2094
+ padding: 4px 10px;
2095
+ cursor: pointer;
2096
+ color: var(--text-primary);
2097
+ font-size: 12px;
2098
+ transition: all 0.2s ease;
2099
+ }
2100
+
2101
+ .expand-btn:hover {
2102
+ background: var(--accent);
2103
+ border-color: var(--accent);
2104
+ color: var(--bg-primary);
2105
+ }
2106
+
2107
+ /* Dependency Details Row */
2108
+ .dependency-details {
2109
+ background: var(--bg-primary);
2110
+ }
2111
+
2112
+ .dependency-details td {
2113
+ padding: 0 !important;
2114
+ }
2115
+
2116
+ .dependency-details-content {
2117
+ padding: 16px 20px;
2118
+ display: grid;
2119
+ grid-template-columns: 1fr 1fr;
2120
+ gap: 20px;
2121
+ }
2122
+
2123
+ .dependency-section {
2124
+ background: var(--bg-secondary);
2125
+ border: 1px solid var(--border-primary);
2126
+ border-radius: 6px;
2127
+ padding: 12px;
2128
+ }
2129
+
2130
+ .dependency-section-title {
2131
+ font-size: 12px;
2132
+ font-weight: 600;
2133
+ color: var(--text-primary);
2134
+ margin-bottom: 10px;
2135
+ text-transform: uppercase;
2136
+ letter-spacing: 0.5px;
2137
+ }
2138
+
2139
+ .dependency-list {
2140
+ display: flex;
2141
+ flex-wrap: wrap;
2142
+ gap: 6px;
2143
+ }
2144
+
2145
+ .dependency-item {
2146
+ display: inline-block;
2147
+ padding: 4px 10px;
2148
+ background: var(--bg-tertiary);
2149
+ border: 1px solid var(--border-primary);
2150
+ border-radius: 12px;
2151
+ font-size: 11px;
2152
+ color: var(--text-primary);
2153
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2154
+ transition: all 0.2s ease;
2155
+ cursor: default;
2156
+ }
2157
+
2158
+ .dependency-item:hover {
2159
+ background: var(--accent);
2160
+ border-color: var(--accent);
2161
+ color: var(--bg-primary);
2162
+ }
2163
+
2164
+ .dependency-item-empty {
2165
+ color: var(--text-tertiary);
2166
+ font-size: 12px;
2167
+ font-style: italic;
2168
+ }
2169
+
2170
+ .dependency-item-more {
2171
+ color: var(--text-secondary);
2172
+ font-size: 11px;
2173
+ padding: 4px 10px;
2174
+ font-style: italic;
2175
+ }
2176
+ """
2177
+
2178
+
2179
+ def get_trends_styles() -> str:
2180
+ """Get styles for the trends/metrics snapshot report.
2181
+
2182
+ Returns:
2183
+ CSS string for trends styling
2184
+ """
2185
+ return """
2186
+ /* Trends Report Styles */
2187
+ .trends-report {
2188
+ padding: 0;
2189
+ }
2190
+
2191
+ /* Snapshot Banner */
2192
+ .snapshot-banner {
2193
+ background: var(--bg-secondary);
2194
+ border: 2px solid var(--accent);
2195
+ border-radius: 8px;
2196
+ padding: 20px;
2197
+ margin-bottom: 24px;
2198
+ }
2199
+
2200
+ .snapshot-header {
2201
+ display: flex;
2202
+ align-items: center;
2203
+ gap: 16px;
2204
+ margin-bottom: 12px;
2205
+ }
2206
+
2207
+ .snapshot-icon {
2208
+ font-size: 32px;
2209
+ flex-shrink: 0;
2210
+ }
2211
+
2212
+ .snapshot-info {
2213
+ flex: 1;
2214
+ }
2215
+
2216
+ .snapshot-title {
2217
+ font-size: 18px;
2218
+ font-weight: bold;
2219
+ color: var(--accent);
2220
+ margin-bottom: 4px;
2221
+ }
2222
+
2223
+ .snapshot-timestamp {
2224
+ font-size: 13px;
2225
+ color: var(--text-secondary);
2226
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2227
+ }
2228
+
2229
+ .snapshot-description {
2230
+ font-size: 13px;
2231
+ color: var(--text-secondary);
2232
+ line-height: 1.6;
2233
+ }
2234
+
2235
+ /* Metrics Section */
2236
+ .metrics-section {
2237
+ margin-bottom: 24px;
2238
+ }
2239
+
2240
+ .metrics-grid {
2241
+ display: grid;
2242
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
2243
+ gap: 16px;
2244
+ }
2245
+
2246
+ .metric-card {
2247
+ background: var(--bg-secondary);
2248
+ border: 1px solid var(--border-primary);
2249
+ border-radius: 8px;
2250
+ padding: 20px;
2251
+ text-align: center;
2252
+ transition: all 0.2s ease;
2253
+ }
2254
+
2255
+ .metric-card:hover {
2256
+ border-color: var(--accent);
2257
+ transform: translateY(-2px);
2258
+ box-shadow: 0 4px 12px var(--shadow);
2259
+ }
2260
+
2261
+ .metric-icon {
2262
+ font-size: 32px;
2263
+ margin-bottom: 12px;
2264
+ }
2265
+
2266
+ .metric-value {
2267
+ font-size: 32px;
2268
+ font-weight: bold;
2269
+ color: var(--accent);
2270
+ margin-bottom: 8px;
2271
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2272
+ }
2273
+
2274
+ .metric-label {
2275
+ font-size: 12px;
2276
+ color: var(--text-secondary);
2277
+ text-transform: uppercase;
2278
+ letter-spacing: 0.5px;
2279
+ }
2280
+
2281
+ /* Health Score Section */
2282
+ .health-section {
2283
+ margin-bottom: 24px;
2284
+ }
2285
+
2286
+ .health-card {
2287
+ background: var(--bg-secondary);
2288
+ border: 1px solid var(--border-primary);
2289
+ border-radius: 8px;
2290
+ padding: 24px;
2291
+ }
2292
+
2293
+ .health-score-display {
2294
+ display: flex;
2295
+ align-items: center;
2296
+ justify-content: center;
2297
+ gap: 16px;
2298
+ margin-bottom: 16px;
2299
+ }
2300
+
2301
+ .health-score-value {
2302
+ font-size: 48px;
2303
+ font-weight: bold;
2304
+ color: var(--accent);
2305
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2306
+ }
2307
+
2308
+ .health-score-label {
2309
+ font-size: 24px;
2310
+ font-weight: 600;
2311
+ color: var(--text-primary);
2312
+ }
2313
+
2314
+ .health-progress-container {
2315
+ background: var(--bg-tertiary);
2316
+ border: 1px solid var(--border-primary);
2317
+ border-radius: 12px;
2318
+ height: 32px;
2319
+ overflow: hidden;
2320
+ margin-bottom: 16px;
2321
+ }
2322
+
2323
+ .health-progress-bar {
2324
+ height: 100%;
2325
+ border-radius: 10px;
2326
+ transition: width 0.5s ease;
2327
+ opacity: 0.9;
2328
+ }
2329
+
2330
+ .health-description {
2331
+ font-size: 14px;
2332
+ color: var(--text-secondary);
2333
+ text-align: center;
2334
+ line-height: 1.6;
2335
+ }
2336
+
2337
+ /* Distribution Section */
2338
+ .distribution-section,
2339
+ .size-distribution-section {
2340
+ margin-bottom: 24px;
2341
+ }
2342
+
2343
+ .distribution-chart {
2344
+ background: var(--bg-secondary);
2345
+ border: 1px solid var(--border-primary);
2346
+ border-radius: 8px;
2347
+ padding: 20px;
2348
+ }
2349
+
2350
+ .distribution-bar-row {
2351
+ display: grid;
2352
+ grid-template-columns: 180px 1fr 80px;
2353
+ gap: 16px;
2354
+ align-items: center;
2355
+ margin-bottom: 12px;
2356
+ }
2357
+
2358
+ .distribution-bar-row:last-child {
2359
+ margin-bottom: 0;
2360
+ }
2361
+
2362
+ .distribution-bar-label {
2363
+ display: flex;
2364
+ align-items: center;
2365
+ gap: 8px;
2366
+ font-size: 13px;
2367
+ }
2368
+
2369
+ .distribution-grade {
2370
+ font-size: 16px;
2371
+ font-weight: bold;
2372
+ min-width: 24px;
2373
+ }
2374
+
2375
+ .distribution-range {
2376
+ font-size: 12px;
2377
+ color: var(--text-secondary);
2378
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2379
+ }
2380
+
2381
+ .size-label {
2382
+ font-size: 13px;
2383
+ color: var(--text-primary);
2384
+ }
2385
+
2386
+ .distribution-bar-container {
2387
+ background: var(--bg-tertiary);
2388
+ border: 1px solid var(--border-primary);
2389
+ border-radius: 6px;
2390
+ height: 28px;
2391
+ overflow: hidden;
2392
+ }
2393
+
2394
+ .distribution-bar-fill {
2395
+ height: 100%;
2396
+ border-radius: 5px;
2397
+ transition: width 0.3s ease;
2398
+ opacity: 0.8;
2399
+ }
2400
+
2401
+ .distribution-bar-value {
2402
+ font-size: 13px;
2403
+ font-weight: 600;
2404
+ color: var(--text-primary);
2405
+ text-align: right;
2406
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2407
+ }
2408
+
2409
+ /* Trends Chart Styles */
2410
+ .trends-section {
2411
+ margin-top: 32px;
2412
+ }
2413
+
2414
+ .trends-container {
2415
+ display: flex;
2416
+ flex-direction: column;
2417
+ gap: 24px;
2418
+ margin-bottom: 16px;
2419
+ }
2420
+
2421
+ .trend-chart {
2422
+ background: var(--bg-secondary);
2423
+ border: 1px solid var(--border-primary);
2424
+ border-radius: 8px;
2425
+ padding: 20px;
2426
+ overflow-x: auto;
2427
+ }
2428
+
2429
+ .trend-chart svg {
2430
+ display: block;
2431
+ margin: 0 auto;
2432
+ }
2433
+
2434
+ .trend-info {
2435
+ font-size: 12px;
2436
+ color: var(--text-secondary);
2437
+ text-align: center;
2438
+ margin-top: 8px;
2439
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2440
+ }
2441
+
2442
+ /* Future Section (fallback when no trend data) */
2443
+ .future-section {
2444
+ margin-top: 32px;
2445
+ }
2446
+
2447
+ .future-placeholder {
2448
+ background: var(--bg-secondary);
2449
+ border: 2px dashed var(--border-primary);
2450
+ border-radius: 8px;
2451
+ padding: 40px;
2452
+ text-align: center;
2453
+ }
2454
+
2455
+ .future-icon {
2456
+ font-size: 48px;
2457
+ margin-bottom: 16px;
2458
+ }
2459
+
2460
+ .future-title {
2461
+ font-size: 18px;
2462
+ font-weight: bold;
2463
+ color: var(--text-primary);
2464
+ margin-bottom: 16px;
2465
+ }
2466
+
2467
+ .future-description {
2468
+ font-size: 14px;
2469
+ color: var(--text-secondary);
2470
+ line-height: 1.8;
2471
+ max-width: 600px;
2472
+ margin: 0 auto;
2473
+ }
2474
+
2475
+ .future-description code {
2476
+ background: var(--bg-tertiary);
2477
+ padding: 2px 6px;
2478
+ border-radius: 3px;
2479
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
2480
+ font-size: 12px;
2481
+ }
2482
+
2483
+ .future-description ul {
2484
+ text-align: left;
2485
+ margin: 16px auto 0;
2486
+ padding-left: 20px;
2487
+ max-width: 400px;
2488
+ }
2489
+
2490
+ .future-description li {
2491
+ margin-bottom: 8px;
2492
+ }
2493
+ """
2494
+
2495
+
2496
+ def get_all_styles() -> str:
2497
+ """Get all CSS styles combined.
2498
+
2499
+ Returns:
2500
+ Complete CSS string for the visualization
2501
+ """
2502
+ return "".join(
2503
+ [
2504
+ get_base_styles(),
2505
+ get_controls_styles(),
2506
+ get_graph_styles(),
2507
+ get_node_styles(),
2508
+ get_link_styles(),
2509
+ get_tooltip_styles(),
2510
+ get_breadcrumb_styles(),
2511
+ get_content_pane_styles(),
2512
+ get_code_chunks_styles(),
2513
+ get_reset_button_styles(),
2514
+ get_spinner_styles(),
2515
+ get_theme_toggle_styles(),
2516
+ get_search_styles(),
2517
+ get_complexity_report_styles(),
2518
+ get_code_smells_styles(),
2519
+ get_dependencies_styles(),
2520
+ get_trends_styles(),
2521
+ ]
2522
+ )