codemap-python 0.1.0__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 (58) hide show
  1. analysis/__init__.py +1 -0
  2. analysis/architecture/__init__.py +1 -0
  3. analysis/architecture/architecture_engine.py +155 -0
  4. analysis/architecture/dependency_cycles.py +103 -0
  5. analysis/architecture/risk_radar.py +220 -0
  6. analysis/call_graph/__init__.py +1 -0
  7. analysis/call_graph/call_extractor.py +91 -0
  8. analysis/call_graph/call_graph_builder.py +1 -0
  9. analysis/call_graph/call_resolver.py +56 -0
  10. analysis/call_graph/context_models.py +1 -0
  11. analysis/call_graph/cross_file_resolver.py +122 -0
  12. analysis/call_graph/execution_tracker.py +1 -0
  13. analysis/call_graph/flow_builder.py +1 -0
  14. analysis/call_graph/models.py +1 -0
  15. analysis/core/__init__.py +1 -0
  16. analysis/core/ast_context.py +1 -0
  17. analysis/core/ast_parser.py +8 -0
  18. analysis/core/class_extractor.py +35 -0
  19. analysis/core/function_extractor.py +16 -0
  20. analysis/core/import_extractor.py +43 -0
  21. analysis/explain/__init__.py +1 -0
  22. analysis/explain/docstring_extractor.py +45 -0
  23. analysis/explain/explain_runner.py +177 -0
  24. analysis/explain/repo_summary_generator.py +138 -0
  25. analysis/explain/return_analyzer.py +114 -0
  26. analysis/explain/risk_flags.py +1 -0
  27. analysis/explain/signature_extractor.py +104 -0
  28. analysis/explain/summary_generator.py +282 -0
  29. analysis/graph/__init__.py +1 -0
  30. analysis/graph/callgraph_index.py +117 -0
  31. analysis/graph/entrypoint_detector.py +1 -0
  32. analysis/graph/impact_analyzer.py +210 -0
  33. analysis/indexing/__init__.py +1 -0
  34. analysis/indexing/import_resolver.py +156 -0
  35. analysis/indexing/symbol_index.py +150 -0
  36. analysis/runners/__init__.py +1 -0
  37. analysis/runners/phase4_runner.py +137 -0
  38. analysis/utils/__init__.py +1 -0
  39. analysis/utils/ast_helpers.py +1 -0
  40. analysis/utils/cache_manager.py +659 -0
  41. analysis/utils/path_resolver.py +1 -0
  42. analysis/utils/repo_fetcher.py +469 -0
  43. cli.py +1728 -0
  44. codemap_cli.py +11 -0
  45. codemap_python-0.1.0.dist-info/METADATA +399 -0
  46. codemap_python-0.1.0.dist-info/RECORD +58 -0
  47. codemap_python-0.1.0.dist-info/WHEEL +5 -0
  48. codemap_python-0.1.0.dist-info/entry_points.txt +2 -0
  49. codemap_python-0.1.0.dist-info/top_level.txt +5 -0
  50. security_utils.py +51 -0
  51. ui/__init__.py +1 -0
  52. ui/app.py +2160 -0
  53. ui/device_id.py +27 -0
  54. ui/static/app.js +2703 -0
  55. ui/static/styles.css +1268 -0
  56. ui/templates/index.html +231 -0
  57. ui/utils/__init__.py +1 -0
  58. ui/utils/registry_manager.py +190 -0
ui/static/styles.css ADDED
@@ -0,0 +1,1268 @@
1
+ :root {
2
+ --bg: #f3f5f8;
3
+ --panel: #f8fafb;
4
+ --line: #d5dbe3;
5
+ --text: #1f2937;
6
+ --muted: #6b7280;
7
+ --accent: #0b5ed7;
8
+ --active-bg: #edf3ff;
9
+ --active-border: #4f84ff;
10
+ }
11
+
12
+ * {
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ body {
17
+ margin: 0;
18
+ font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
19
+ background: var(--bg);
20
+ color: var(--text);
21
+ }
22
+
23
+ .topbar {
24
+ min-height: 64px;
25
+ padding: 8px 18px;
26
+ display: flex;
27
+ align-items: center;
28
+ justify-content: space-between;
29
+ border-bottom: 1px solid var(--line);
30
+ background: #fff;
31
+ box-shadow: 0 1px 0 rgba(31, 41, 55, 0.03);
32
+ gap: 10px;
33
+ }
34
+
35
+ .workspace-controls {
36
+ display: flex;
37
+ gap: 8px;
38
+ align-items: center;
39
+ flex-wrap: wrap;
40
+ }
41
+
42
+ .add-repo-inline {
43
+ max-width: 1440px;
44
+ margin: 8px auto 0;
45
+ border: 1px solid var(--line);
46
+ border-radius: 10px;
47
+ background: #fff;
48
+ box-shadow: 0 2px 8px rgba(31, 41, 55, 0.05);
49
+ padding: 12px 14px;
50
+ }
51
+
52
+ .add-repo-header {
53
+ display: flex;
54
+ justify-content: space-between;
55
+ align-items: center;
56
+ margin-bottom: 8px;
57
+ }
58
+
59
+ .repo-select {
60
+ border: 1px solid var(--line);
61
+ background: #fff;
62
+ border-radius: 8px;
63
+ font-size: 12px;
64
+ padding: 6px 10px;
65
+ color: var(--text);
66
+ min-width: 180px;
67
+ }
68
+
69
+ .repo-btn {
70
+ border: 1px solid var(--line);
71
+ background: #fff;
72
+ border-radius: 8px;
73
+ font-size: 12px;
74
+ padding: 6px 10px;
75
+ cursor: pointer;
76
+ color: #334155;
77
+ }
78
+
79
+ .repo-btn.danger {
80
+ border-color: #e6b8b8;
81
+ color: #8f2f2f;
82
+ background: #fff7f7;
83
+ }
84
+
85
+ .repo-btn.danger:hover {
86
+ border-color: #de9f9f;
87
+ background: #ffefef;
88
+ }
89
+
90
+ .repo-btn:hover,
91
+ .repo-select:hover {
92
+ border-color: #b8c3d1;
93
+ }
94
+
95
+ .repo-btn.small {
96
+ font-size: 11px;
97
+ padding: 4px 8px;
98
+ }
99
+
100
+ .repo-btn.is-loading {
101
+ opacity: 0.9;
102
+ }
103
+
104
+ .title {
105
+ font-weight: 600;
106
+ font-size: 14px;
107
+ letter-spacing: 0.06em;
108
+ text-transform: uppercase;
109
+ color: #4b5563;
110
+ }
111
+
112
+ .brand {
113
+ display: flex;
114
+ flex-direction: column;
115
+ gap: 2px;
116
+ }
117
+
118
+ .repo-name-wrap {
119
+ display: flex;
120
+ align-items: center;
121
+ gap: 8px;
122
+ }
123
+
124
+ .repo-name {
125
+ font-size: 20px;
126
+ font-weight: 700;
127
+ line-height: 1.2;
128
+ }
129
+
130
+ .meta {
131
+ color: var(--muted);
132
+ font-size: 13px;
133
+ white-space: nowrap;
134
+ overflow: hidden;
135
+ text-overflow: ellipsis;
136
+ max-width: 55vw;
137
+ }
138
+
139
+ .layout {
140
+ display: grid;
141
+ grid-template-columns: 1fr 1fr 1fr;
142
+ gap: 14px;
143
+ padding: 16px;
144
+ height: calc(100vh - 64px);
145
+ min-height: 560px;
146
+ }
147
+
148
+ .shell {
149
+ max-width: 1440px;
150
+ margin: 0 auto;
151
+ }
152
+
153
+ .panel {
154
+ background: var(--panel);
155
+ border: 1px solid var(--line);
156
+ border-radius: 12px;
157
+ padding: 16px;
158
+ overflow: auto;
159
+ box-shadow: 0 2px 8px rgba(31, 41, 55, 0.04);
160
+ transition: box-shadow 140ms ease, border-color 140ms ease;
161
+ }
162
+
163
+ .panel h2 {
164
+ margin: 0 0 14px;
165
+ font-size: 17px;
166
+ font-weight: 700;
167
+ padding-bottom: 8px;
168
+ border-bottom: 1px solid #e4e9ef;
169
+ }
170
+
171
+ .view-toggle {
172
+ display: flex;
173
+ gap: 8px;
174
+ margin-bottom: 10px;
175
+ }
176
+
177
+ .tab-btn {
178
+ border: 1px solid var(--line);
179
+ background: #fff;
180
+ border-radius: 7px;
181
+ padding: 5px 10px;
182
+ font-size: 12px;
183
+ cursor: pointer;
184
+ color: #334155;
185
+ }
186
+
187
+ .tab-btn.active {
188
+ background: #eef4ff;
189
+ border-color: #b8cdf5;
190
+ color: #173d7a;
191
+ }
192
+
193
+ .graph-controls {
194
+ display: flex;
195
+ flex-wrap: wrap;
196
+ gap: 8px 12px;
197
+ margin-bottom: 10px;
198
+ font-size: 12px;
199
+ }
200
+
201
+ .graph-controls select,
202
+ .graph-controls input[type="text"] {
203
+ border: 1px solid var(--line);
204
+ border-radius: 6px;
205
+ padding: 4px 8px;
206
+ font-size: 12px;
207
+ background: #fff;
208
+ }
209
+
210
+ .tree ul {
211
+ list-style: none;
212
+ margin: 0;
213
+ padding-left: 14px;
214
+ }
215
+
216
+ .tree-item {
217
+ cursor: pointer;
218
+ margin: 3px 0;
219
+ font-size: 13px;
220
+ display: inline-block;
221
+ padding: 2px 4px;
222
+ border-radius: 4px;
223
+ }
224
+
225
+ .tree-item.file:hover,
226
+ .symbol-link:hover {
227
+ color: var(--accent);
228
+ background: #eaf2ff;
229
+ }
230
+
231
+ .tree-item.file.active-file {
232
+ background: #eaf2ff;
233
+ border-left: 3px solid var(--active-border);
234
+ color: #0f3f9c;
235
+ }
236
+
237
+ .status {
238
+ font-size: 12px;
239
+ color: var(--muted);
240
+ margin-bottom: 8px;
241
+ }
242
+
243
+ .content {
244
+ font-size: 13px;
245
+ line-height: 1.45;
246
+ }
247
+
248
+ .search-wrap {
249
+ position: relative;
250
+ margin-bottom: 12px;
251
+ }
252
+
253
+ .recent-wrap {
254
+ margin-bottom: 14px;
255
+ border-top: 1px solid #e8edf3;
256
+ padding-top: 8px;
257
+ }
258
+
259
+ #recent-symbols-wrap,
260
+ #recent-files-wrap {
261
+ margin-bottom: 10px;
262
+ }
263
+
264
+ #recent-symbols .symbol-link,
265
+ #recent-files .symbol-link {
266
+ margin-bottom: 4px;
267
+ }
268
+
269
+ #symbol-search-input {
270
+ width: 100%;
271
+ border: 1px solid var(--line);
272
+ border-radius: 8px;
273
+ padding: 8px 10px;
274
+ font-size: 13px;
275
+ outline: none;
276
+ background: #fff;
277
+ }
278
+
279
+ #symbol-search-input:focus {
280
+ border-color: #8eb4ff;
281
+ box-shadow: 0 0 0 2px rgba(79, 132, 255, 0.15);
282
+ }
283
+
284
+ .search-results {
285
+ position: absolute;
286
+ z-index: 8;
287
+ top: calc(100% + 6px);
288
+ left: 0;
289
+ right: 0;
290
+ max-height: 280px;
291
+ overflow: auto;
292
+ background: #fff;
293
+ border: 1px solid var(--line);
294
+ border-radius: 8px;
295
+ box-shadow: 0 8px 20px rgba(31, 41, 55, 0.12);
296
+ }
297
+
298
+ .search-row {
299
+ width: 100%;
300
+ border: none;
301
+ background: transparent;
302
+ text-align: left;
303
+ padding: 8px 10px;
304
+ border-bottom: 1px solid #eef1f4;
305
+ cursor: pointer;
306
+ }
307
+
308
+ .search-row:hover {
309
+ background: #f5f8ff;
310
+ }
311
+
312
+ .search-primary {
313
+ font-size: 13px;
314
+ font-weight: 600;
315
+ }
316
+
317
+ .search-secondary {
318
+ font-size: 12px;
319
+ color: var(--muted);
320
+ margin-top: 2px;
321
+ }
322
+
323
+ .search-more {
324
+ padding: 8px 10px;
325
+ font-size: 12px;
326
+ color: var(--muted);
327
+ }
328
+
329
+ .hidden {
330
+ display: none !important;
331
+ }
332
+
333
+ .muted {
334
+ color: var(--muted);
335
+ }
336
+
337
+ .block {
338
+ border: 1px solid var(--line);
339
+ border-radius: 6px;
340
+ padding: 8px;
341
+ margin-bottom: 8px;
342
+ }
343
+
344
+ .card {
345
+ border: 1px solid var(--line);
346
+ border-radius: 10px;
347
+ padding: 14px;
348
+ margin-bottom: 16px;
349
+ background: #fff;
350
+ transition: opacity 160ms ease, transform 160ms ease;
351
+ }
352
+
353
+ .repo-row {
354
+ border: 1px solid #e3e8ef;
355
+ border-radius: 8px;
356
+ background: #fff;
357
+ padding: 8px;
358
+ margin-bottom: 8px;
359
+ }
360
+
361
+ .repo-row-header {
362
+ display: flex;
363
+ justify-content: space-between;
364
+ align-items: center;
365
+ gap: 8px;
366
+ }
367
+
368
+ .repo-row-name {
369
+ font-weight: 600;
370
+ }
371
+
372
+ .repo-badge {
373
+ border-radius: 999px;
374
+ border: 1px solid #d6dbe5;
375
+ font-size: 10px;
376
+ padding: 2px 7px;
377
+ text-transform: uppercase;
378
+ letter-spacing: 0.04em;
379
+ }
380
+
381
+ .repo-badge.analyzed {
382
+ background: #eff8ef;
383
+ color: #2d6d3a;
384
+ border-color: #cbe6d2;
385
+ }
386
+
387
+ .repo-badge.private {
388
+ background: #eef5ff;
389
+ color: #1f4a85;
390
+ border-color: #c7daff;
391
+ }
392
+
393
+ .repo-badge.not-analyzed {
394
+ background: #fff5ef;
395
+ color: #8a4e14;
396
+ border-color: #f0d8c2;
397
+ }
398
+
399
+ .repo-badge.expiring {
400
+ background: #fff8ea;
401
+ color: #8a5f14;
402
+ border-color: #eddab4;
403
+ }
404
+
405
+ .repo-row-actions {
406
+ display: flex;
407
+ flex-wrap: wrap;
408
+ gap: 6px;
409
+ margin-top: 7px;
410
+ }
411
+
412
+ .repo-policy-select {
413
+ border: 1px solid var(--line);
414
+ border-radius: 6px;
415
+ padding: 4px 8px;
416
+ font-size: 12px;
417
+ background: #fff;
418
+ color: var(--text);
419
+ }
420
+
421
+ .missing-analysis-cta {
422
+ border: 1px solid #f0d8c2;
423
+ border-radius: 9px;
424
+ background: #fff9f3;
425
+ color: #5b3a12;
426
+ padding: 10px 11px;
427
+ margin-bottom: 10px;
428
+ }
429
+
430
+ .missing-analysis-token {
431
+ margin-top: 4px;
432
+ width: 100%;
433
+ border: 1px solid #d9c8b4;
434
+ border-radius: 7px;
435
+ padding: 6px 8px;
436
+ font-size: 12px;
437
+ background: #fff;
438
+ }
439
+
440
+ .analysis-run-status {
441
+ margin-top: 6px;
442
+ }
443
+
444
+ .analysis-run-error {
445
+ margin-top: 6px;
446
+ padding: 7px 9px;
447
+ border: 1px solid #e9b4b4;
448
+ border-radius: 7px;
449
+ background: #fff2f2;
450
+ color: #8f2f2f;
451
+ font-size: 12px;
452
+ }
453
+
454
+ .modal-tabs {
455
+ display: flex;
456
+ gap: 8px;
457
+ margin-bottom: 10px;
458
+ }
459
+
460
+ .modal-form {
461
+ display: flex;
462
+ flex-direction: column;
463
+ gap: 8px;
464
+ }
465
+
466
+ .modal-form label {
467
+ display: flex;
468
+ flex-direction: column;
469
+ gap: 4px;
470
+ font-size: 12px;
471
+ color: #4b5563;
472
+ }
473
+
474
+ .modal-form input,
475
+ .modal-form select {
476
+ border: 1px solid var(--line);
477
+ border-radius: 6px;
478
+ padding: 7px 9px;
479
+ font-size: 12px;
480
+ background: #fff;
481
+ }
482
+
483
+ .modal-actions {
484
+ display: flex;
485
+ flex-wrap: wrap;
486
+ gap: 8px;
487
+ margin-top: 4px;
488
+ }
489
+
490
+ .private-mode {
491
+ border: 1px solid #d8eadf;
492
+ background: #f4fbf6;
493
+ color: #275d37;
494
+ border-radius: 8px;
495
+ padding: 7px 9px;
496
+ font-size: 12px;
497
+ line-height: 1.35;
498
+ }
499
+
500
+ .toast {
501
+ position: fixed;
502
+ right: 16px;
503
+ bottom: 16px;
504
+ z-index: 40;
505
+ background: #1f2937;
506
+ color: #fff;
507
+ border-radius: 8px;
508
+ padding: 8px 12px;
509
+ font-size: 12px;
510
+ box-shadow: 0 8px 22px rgba(0, 0, 0, 0.2);
511
+ }
512
+
513
+ .toast.error {
514
+ background: #8f2f2f;
515
+ }
516
+
517
+ .confirm-modal {
518
+ position: fixed;
519
+ inset: 0;
520
+ display: flex;
521
+ align-items: center;
522
+ justify-content: center;
523
+ background: rgba(15, 23, 42, 0.28);
524
+ z-index: 1200;
525
+ pointer-events: auto;
526
+ }
527
+
528
+ .confirm-card {
529
+ width: min(460px, calc(100vw - 32px));
530
+ background: #fff;
531
+ border: 1px solid #d8dee8;
532
+ border-radius: 12px;
533
+ box-shadow: 0 18px 48px rgba(0, 0, 0, 0.2);
534
+ padding: 14px;
535
+ pointer-events: auto;
536
+ position: relative;
537
+ z-index: 1201;
538
+ }
539
+
540
+ .settings-card {
541
+ width: min(520px, calc(100vw - 32px));
542
+ display: flex;
543
+ flex-direction: column;
544
+ gap: 8px;
545
+ }
546
+
547
+ .settings-card label {
548
+ display: flex;
549
+ flex-direction: column;
550
+ gap: 4px;
551
+ font-size: 12px;
552
+ color: #4b5563;
553
+ }
554
+
555
+ .settings-card input,
556
+ .settings-card select {
557
+ border: 1px solid var(--line);
558
+ border-radius: 6px;
559
+ padding: 6px 8px;
560
+ font-size: 12px;
561
+ background: #fff;
562
+ }
563
+
564
+ body.modal-open {
565
+ overflow: hidden;
566
+ }
567
+
568
+ .privacy-controls {
569
+ display: grid;
570
+ grid-template-columns: 1fr 1fr;
571
+ gap: 8px;
572
+ margin: 10px 0;
573
+ }
574
+
575
+ .privacy-controls label {
576
+ display: flex;
577
+ flex-direction: column;
578
+ gap: 4px;
579
+ font-size: 12px;
580
+ color: #4b5563;
581
+ }
582
+
583
+ .privacy-controls input {
584
+ border: 1px solid var(--line);
585
+ border-radius: 6px;
586
+ padding: 6px 8px;
587
+ font-size: 12px;
588
+ background: #fff;
589
+ }
590
+
591
+ .privacy-actions {
592
+ display: flex;
593
+ flex-wrap: wrap;
594
+ gap: 8px;
595
+ margin-bottom: 10px;
596
+ }
597
+
598
+ .privacy-confirm {
599
+ margin: 8px 0 10px;
600
+ border: 1px solid #f2d7bf;
601
+ border-radius: 8px;
602
+ background: #fff9f2;
603
+ padding: 8px;
604
+ }
605
+
606
+ .privacy-warning {
607
+ border: 1px solid #f2d7bf;
608
+ border-radius: 8px;
609
+ background: #fff8ef;
610
+ color: #825017;
611
+ padding: 7px 9px;
612
+ font-size: 12px;
613
+ margin-bottom: 6px;
614
+ }
615
+
616
+ .expires-chip {
617
+ display: inline-flex;
618
+ align-items: center;
619
+ border-radius: 999px;
620
+ border: 1px solid #f0c89f;
621
+ background: #fff3e4;
622
+ color: #8a4e14;
623
+ font-size: 10px;
624
+ padding: 2px 8px;
625
+ letter-spacing: 0.04em;
626
+ text-transform: uppercase;
627
+ }
628
+
629
+ .graph-card {
630
+ min-height: 180px;
631
+ }
632
+
633
+ .graph-legend {
634
+ display: flex;
635
+ gap: 12px;
636
+ align-items: center;
637
+ margin-bottom: 10px;
638
+ }
639
+
640
+ .legend-item {
641
+ font-size: 12px;
642
+ color: var(--muted);
643
+ }
644
+
645
+ .dot {
646
+ display: inline-block;
647
+ width: 8px;
648
+ height: 8px;
649
+ border-radius: 50%;
650
+ margin-right: 5px;
651
+ }
652
+
653
+ .dot.local {
654
+ background: #2d6cdf;
655
+ }
656
+
657
+ .dot.builtin {
658
+ background: #7c8ea5;
659
+ }
660
+
661
+ .dot.external {
662
+ background: #a8b3bf;
663
+ }
664
+
665
+ .graph-edge-row {
666
+ display: flex;
667
+ align-items: center;
668
+ gap: 6px;
669
+ margin: 4px 0;
670
+ }
671
+
672
+ .edge-arrow {
673
+ color: #64748b;
674
+ font-size: 12px;
675
+ }
676
+
677
+ .graph-node {
678
+ border: 1px solid #dbe2ec;
679
+ border-radius: 8px;
680
+ padding: 5px 8px;
681
+ background: #fff;
682
+ min-width: 120px;
683
+ }
684
+
685
+ .graph-node.kind-local {
686
+ border-color: #c4d7fa;
687
+ background: #f7faff;
688
+ }
689
+
690
+ .graph-node.kind-builtin {
691
+ border-color: #d8dde5;
692
+ background: #f8fafc;
693
+ }
694
+
695
+ .graph-node.kind-external {
696
+ border-color: #dfe3e8;
697
+ background: #fafbfc;
698
+ }
699
+
700
+ .graph-node.graph-clickable {
701
+ cursor: pointer;
702
+ }
703
+
704
+ .graph-node.graph-clickable:hover {
705
+ border-color: #9ebaf0;
706
+ background: #eef4ff;
707
+ }
708
+
709
+ .graph-node.graph-match {
710
+ box-shadow: 0 0 0 2px rgba(52, 116, 231, 0.2);
711
+ }
712
+
713
+ .arch-grid {
714
+ display: grid;
715
+ grid-template-columns: repeat(2, minmax(0, 1fr));
716
+ gap: 10px;
717
+ margin-bottom: 12px;
718
+ }
719
+
720
+ .kpi-card {
721
+ border: 1px solid var(--line);
722
+ border-radius: 10px;
723
+ background: #fff;
724
+ padding: 10px;
725
+ }
726
+
727
+ .kpi-label {
728
+ font-size: 12px;
729
+ color: var(--muted);
730
+ margin-bottom: 4px;
731
+ }
732
+
733
+ .kpi-value {
734
+ font-size: 22px;
735
+ font-weight: 700;
736
+ color: #1f2f4a;
737
+ }
738
+
739
+ .arch-row {
740
+ width: 100%;
741
+ border: 1px solid #e3e8ef;
742
+ background: #fff;
743
+ border-radius: 8px;
744
+ padding: 7px 9px;
745
+ margin-bottom: 6px;
746
+ text-align: left;
747
+ cursor: pointer;
748
+ }
749
+
750
+ .arch-row:hover {
751
+ border-color: #c8d9f6;
752
+ background: #f7fbff;
753
+ }
754
+
755
+ .arch-name {
756
+ font-weight: 600;
757
+ margin-right: 6px;
758
+ }
759
+
760
+ .risk-pill {
761
+ display: inline-block;
762
+ border-radius: 999px;
763
+ padding: 1px 8px;
764
+ font-size: 11px;
765
+ text-transform: uppercase;
766
+ letter-spacing: 0.04em;
767
+ margin-right: 8px;
768
+ border: 1px solid transparent;
769
+ }
770
+
771
+ .risk-pill.high {
772
+ background: #fff1f1;
773
+ color: #a12828;
774
+ border-color: #f2c6c6;
775
+ }
776
+
777
+ .risk-pill.medium {
778
+ background: #fff8ea;
779
+ color: #8a5f14;
780
+ border-color: #eddab4;
781
+ }
782
+
783
+ .risk-pill.low {
784
+ background: #eff8ef;
785
+ color: #2d6d3a;
786
+ border-color: #cbe6d2;
787
+ }
788
+
789
+ .risk-hotspot-row {
790
+ display: block;
791
+ }
792
+
793
+ .risk-file-row {
794
+ border: 1px solid #e3e8ef;
795
+ border-radius: 8px;
796
+ padding: 7px 9px;
797
+ margin-bottom: 6px;
798
+ background: #fff;
799
+ }
800
+
801
+ .risk-target {
802
+ border: 1px solid #e3e8ef;
803
+ border-radius: 8px;
804
+ padding: 8px 10px;
805
+ margin-bottom: 6px;
806
+ background: #fff;
807
+ }
808
+
809
+ .impact-card .section-title {
810
+ margin-top: 10px;
811
+ }
812
+
813
+ .impact-node-row {
814
+ display: block;
815
+ }
816
+
817
+ .impact-distance {
818
+ display: inline-block;
819
+ min-width: 28px;
820
+ text-align: center;
821
+ border: 1px solid #d4dcea;
822
+ border-radius: 999px;
823
+ background: #f5f8ff;
824
+ color: #224777;
825
+ font-size: 11px;
826
+ padding: 1px 6px;
827
+ margin-right: 8px;
828
+ }
829
+
830
+ .impact-file-row {
831
+ display: flex;
832
+ justify-content: space-between;
833
+ gap: 8px;
834
+ border: 1px solid #e3e8ef;
835
+ border-radius: 8px;
836
+ padding: 6px 9px;
837
+ margin-bottom: 6px;
838
+ background: #fff;
839
+ }
840
+
841
+ .impact-truncated {
842
+ margin-top: 8px;
843
+ padding: 8px 10px;
844
+ }
845
+
846
+ .impact-empty-state {
847
+ color: var(--text);
848
+ }
849
+
850
+ .impact-empty-title {
851
+ font-size: 15px;
852
+ font-weight: 700;
853
+ margin-bottom: 8px;
854
+ }
855
+
856
+ .impact-command {
857
+ margin: 10px 0 8px;
858
+ padding: 8px 10px;
859
+ border: 1px solid #e7d9c8;
860
+ border-radius: 8px;
861
+ background: #fff;
862
+ font-family: Consolas, "Courier New", monospace;
863
+ font-size: 12px;
864
+ white-space: pre-wrap;
865
+ word-break: break-word;
866
+ }
867
+
868
+ .impact-truncated-banner {
869
+ margin-top: 8px;
870
+ padding: 8px 10px;
871
+ border: 1px solid #f2d7bf;
872
+ border-radius: 8px;
873
+ background: #fff7ed;
874
+ color: #7a4b12;
875
+ font-size: 12px;
876
+ }
877
+
878
+ .impact-section-badge {
879
+ display: inline-block;
880
+ margin-left: 8px;
881
+ padding: 1px 7px;
882
+ border-radius: 999px;
883
+ border: 1px solid #f0c9a8;
884
+ background: #fff3e6;
885
+ color: #8a4e14;
886
+ font-size: 10px;
887
+ letter-spacing: 0.05em;
888
+ vertical-align: middle;
889
+ }
890
+
891
+ .cycle-row {
892
+ display: flex;
893
+ justify-content: space-between;
894
+ align-items: center;
895
+ gap: 8px;
896
+ border: 1px solid #e3e8ef;
897
+ border-radius: 8px;
898
+ padding: 7px 9px;
899
+ margin-bottom: 6px;
900
+ background: #fff;
901
+ }
902
+
903
+ .copy-cycle {
904
+ border: 1px solid var(--line);
905
+ border-radius: 6px;
906
+ background: #fff;
907
+ font-size: 12px;
908
+ padding: 3px 7px;
909
+ cursor: pointer;
910
+ }
911
+
912
+ .copy-cycle:hover {
913
+ background: #f5f8ff;
914
+ }
915
+
916
+ .repo-refresh-btn {
917
+ border: 1px solid var(--line);
918
+ border-radius: 6px;
919
+ background: #fff;
920
+ font-size: 12px;
921
+ padding: 3px 7px;
922
+ cursor: pointer;
923
+ margin-bottom: 10px;
924
+ }
925
+
926
+ .repo-refresh-btn:hover {
927
+ background: #f5f8ff;
928
+ }
929
+
930
+ .arch-one-liner {
931
+ font-size: 14px;
932
+ font-weight: 600;
933
+ margin-bottom: 8px;
934
+ }
935
+
936
+ .arch-bullets {
937
+ margin: 8px 0;
938
+ padding-left: 18px;
939
+ }
940
+
941
+ .arch-bullets li {
942
+ margin: 4px 0;
943
+ }
944
+
945
+ .ok-cycle {
946
+ color: #2f6f43;
947
+ border: 1px solid #d6eadb;
948
+ background: #f5fcf7;
949
+ border-radius: 8px;
950
+ padding: 8px 10px;
951
+ }
952
+
953
+ .arch-missing {
954
+ border-color: #f2d7bf;
955
+ background: #fffaf5;
956
+ }
957
+
958
+ .line {
959
+ display: flex;
960
+ justify-content: space-between;
961
+ gap: 8px;
962
+ margin: 5px 0;
963
+ }
964
+
965
+ .label {
966
+ font-weight: 600;
967
+ }
968
+
969
+ .section-title {
970
+ margin-top: 14px;
971
+ margin-bottom: 8px;
972
+ font-weight: 600;
973
+ font-size: 14px;
974
+ text-transform: uppercase;
975
+ letter-spacing: 0.05em;
976
+ color: #4b5563;
977
+ }
978
+
979
+ .sub-title {
980
+ margin-top: 6px;
981
+ margin-bottom: 3px;
982
+ font-weight: 600;
983
+ color: var(--muted);
984
+ }
985
+
986
+ .symbol-title {
987
+ font-weight: 700;
988
+ font-size: 14px;
989
+ margin-bottom: 8px;
990
+ }
991
+
992
+ .symbol-title-main {
993
+ font-weight: 600;
994
+ font-size: 22px;
995
+ margin-bottom: 6px;
996
+ line-height: 1.2;
997
+ }
998
+
999
+ .symbol-name {
1000
+ font-weight: 700;
1001
+ }
1002
+
1003
+ .symbol-class {
1004
+ margin-bottom: 10px;
1005
+ }
1006
+
1007
+ .symbol-methods {
1008
+ margin-left: 12px;
1009
+ margin-top: 4px;
1010
+ }
1011
+
1012
+ .symbol-method-row {
1013
+ display: flex;
1014
+ align-items: center;
1015
+ gap: 6px;
1016
+ margin: 3px 0;
1017
+ }
1018
+
1019
+ .method-prefix {
1020
+ color: var(--muted);
1021
+ font-size: 12px;
1022
+ }
1023
+
1024
+ .kv {
1025
+ margin: 4px 0;
1026
+ }
1027
+
1028
+ .symbol-link {
1029
+ cursor: pointer;
1030
+ color: var(--text);
1031
+ text-decoration: none;
1032
+ font-weight: 600;
1033
+ border-radius: 6px;
1034
+ padding: 3px 6px;
1035
+ display: inline-block;
1036
+ border-left: 2px solid transparent;
1037
+ transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
1038
+ }
1039
+
1040
+ .symbol-link.active {
1041
+ background: var(--active-bg);
1042
+ border-left-color: var(--active-border);
1043
+ color: #0f3f9c;
1044
+ }
1045
+
1046
+ .symbol-class-name {
1047
+ border-radius: 6px;
1048
+ padding: 2px 4px;
1049
+ }
1050
+
1051
+ .symbol-class-name.active-class {
1052
+ background: #eaf2ff;
1053
+ color: #0f3f9c;
1054
+ }
1055
+
1056
+ .breadcrumbs {
1057
+ font-size: 12px;
1058
+ color: var(--muted);
1059
+ margin-bottom: 8px;
1060
+ line-height: 1.5;
1061
+ }
1062
+
1063
+ .crumb-link {
1064
+ cursor: pointer;
1065
+ border-radius: 4px;
1066
+ padding: 1px 4px;
1067
+ }
1068
+
1069
+ .crumb-link:hover {
1070
+ color: var(--accent);
1071
+ background: #edf3ff;
1072
+ }
1073
+
1074
+ .crumb-sep {
1075
+ margin: 0 5px;
1076
+ color: #9aa3af;
1077
+ }
1078
+
1079
+ .chips {
1080
+ display: flex;
1081
+ flex-wrap: wrap;
1082
+ gap: 6px;
1083
+ margin-bottom: 10px;
1084
+ }
1085
+
1086
+ .chip {
1087
+ border: 1px solid #cfd8e3;
1088
+ border-radius: 999px;
1089
+ background: #f6f9ff;
1090
+ color: #21406f;
1091
+ font-size: 12px;
1092
+ padding: 4px 10px;
1093
+ cursor: pointer;
1094
+ }
1095
+
1096
+ .chip:hover {
1097
+ background: #eaf2ff;
1098
+ }
1099
+
1100
+ .connection-link {
1101
+ cursor: pointer;
1102
+ color: var(--accent);
1103
+ border-radius: 4px;
1104
+ padding: 2px 5px;
1105
+ text-decoration: none;
1106
+ transition: background 120ms ease, color 120ms ease;
1107
+ }
1108
+
1109
+ .connection-link:hover {
1110
+ text-decoration: underline;
1111
+ background: #eef4ff;
1112
+ }
1113
+
1114
+ .connection-muted {
1115
+ color: var(--muted);
1116
+ }
1117
+
1118
+ .conn-arrow {
1119
+ color: #5f8fe2;
1120
+ margin-right: 4px;
1121
+ font-size: 11px;
1122
+ }
1123
+
1124
+ .empty-state {
1125
+ border: 1px solid #d8e7db;
1126
+ background: #f5faf5;
1127
+ color: #3e6b49;
1128
+ border-radius: 8px;
1129
+ padding: 8px 10px;
1130
+ font-size: 12px;
1131
+ margin-top: 4px;
1132
+ }
1133
+
1134
+ .fade-panel {
1135
+ animation: panelFade 180ms ease;
1136
+ }
1137
+
1138
+ .shimmer-card {
1139
+ position: relative;
1140
+ overflow: hidden;
1141
+ }
1142
+
1143
+ .shimmer-card::after {
1144
+ content: "";
1145
+ position: absolute;
1146
+ top: 0;
1147
+ left: -120px;
1148
+ height: 100%;
1149
+ width: 120px;
1150
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(235, 241, 250, 0.85), rgba(255, 255, 255, 0));
1151
+ animation: shimmer 700ms linear infinite;
1152
+ }
1153
+
1154
+ .shimmer-line {
1155
+ height: 11px;
1156
+ border-radius: 5px;
1157
+ background: #edf1f6;
1158
+ margin-bottom: 8px;
1159
+ }
1160
+
1161
+ .shimmer-line.w60 {
1162
+ width: 60%;
1163
+ }
1164
+
1165
+ .shimmer-line.w75 {
1166
+ width: 75%;
1167
+ }
1168
+
1169
+ .shimmer-line.w90 {
1170
+ width: 90%;
1171
+ }
1172
+
1173
+ @keyframes shimmer {
1174
+ 0% {
1175
+ left: -120px;
1176
+ }
1177
+ 100% {
1178
+ left: calc(100% + 120px);
1179
+ }
1180
+ }
1181
+
1182
+ @keyframes panelFade {
1183
+ from {
1184
+ opacity: 0.75;
1185
+ transform: translateY(4px);
1186
+ }
1187
+ to {
1188
+ opacity: 1;
1189
+ transform: translateY(0);
1190
+ }
1191
+ }
1192
+
1193
+ .path {
1194
+ color: var(--muted);
1195
+ font-size: 12px;
1196
+ }
1197
+
1198
+ .divider {
1199
+ border-top: 1px solid var(--line);
1200
+ margin: 10px 0;
1201
+ }
1202
+
1203
+ @media (max-width: 1000px) {
1204
+ .layout {
1205
+ grid-template-columns: 1fr;
1206
+ height: auto;
1207
+ min-height: auto;
1208
+ }
1209
+
1210
+ .panel {
1211
+ min-height: 280px;
1212
+ }
1213
+
1214
+ .topbar {
1215
+ padding: 8px 12px;
1216
+ min-height: 56px;
1217
+ height: auto;
1218
+ flex-wrap: wrap;
1219
+ align-items: flex-start;
1220
+ }
1221
+
1222
+ .title {
1223
+ font-size: 18px;
1224
+ }
1225
+
1226
+ .meta {
1227
+ max-width: 100%;
1228
+ font-size: 12px;
1229
+ }
1230
+
1231
+ .panel h2 {
1232
+ font-size: 16px;
1233
+ }
1234
+
1235
+ .privacy-controls {
1236
+ grid-template-columns: 1fr;
1237
+ }
1238
+
1239
+ .symbol-title-main {
1240
+ font-size: 18px;
1241
+ }
1242
+ }
1243
+
1244
+ @media (max-width: 640px) {
1245
+ .layout {
1246
+ padding: 10px;
1247
+ gap: 10px;
1248
+ }
1249
+
1250
+ .panel {
1251
+ padding: 12px;
1252
+ border-radius: 9px;
1253
+ }
1254
+
1255
+ .card {
1256
+ padding: 10px;
1257
+ }
1258
+
1259
+ .section-title {
1260
+ font-size: 13px;
1261
+ }
1262
+
1263
+ .content,
1264
+ .tree-item,
1265
+ .symbol-link {
1266
+ font-size: 12.5px;
1267
+ }
1268
+ }