polycodegraph 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 (67) hide show
  1. codegraph/__init__.py +10 -0
  2. codegraph/analysis/__init__.py +30 -0
  3. codegraph/analysis/_common.py +125 -0
  4. codegraph/analysis/blast_radius.py +63 -0
  5. codegraph/analysis/cycles.py +79 -0
  6. codegraph/analysis/dataflow.py +861 -0
  7. codegraph/analysis/dead_code.py +165 -0
  8. codegraph/analysis/hotspots.py +68 -0
  9. codegraph/analysis/infrastructure.py +439 -0
  10. codegraph/analysis/metrics.py +52 -0
  11. codegraph/analysis/report.py +222 -0
  12. codegraph/analysis/roles.py +323 -0
  13. codegraph/analysis/untested.py +79 -0
  14. codegraph/cli.py +1506 -0
  15. codegraph/config.py +64 -0
  16. codegraph/embed/__init__.py +35 -0
  17. codegraph/embed/chunker.py +120 -0
  18. codegraph/embed/embedder.py +113 -0
  19. codegraph/embed/query.py +181 -0
  20. codegraph/embed/store.py +360 -0
  21. codegraph/graph/__init__.py +0 -0
  22. codegraph/graph/builder.py +212 -0
  23. codegraph/graph/schema.py +69 -0
  24. codegraph/graph/store_networkx.py +55 -0
  25. codegraph/graph/store_sqlite.py +249 -0
  26. codegraph/mcp_server/__init__.py +6 -0
  27. codegraph/mcp_server/server.py +933 -0
  28. codegraph/parsers/__init__.py +0 -0
  29. codegraph/parsers/base.py +70 -0
  30. codegraph/parsers/go.py +570 -0
  31. codegraph/parsers/python.py +1707 -0
  32. codegraph/parsers/typescript.py +1397 -0
  33. codegraph/py.typed +0 -0
  34. codegraph/resolve/__init__.py +4 -0
  35. codegraph/resolve/calls.py +480 -0
  36. codegraph/review/__init__.py +31 -0
  37. codegraph/review/baseline.py +32 -0
  38. codegraph/review/differ.py +211 -0
  39. codegraph/review/hook.py +70 -0
  40. codegraph/review/risk.py +219 -0
  41. codegraph/review/rules.py +342 -0
  42. codegraph/viz/__init__.py +17 -0
  43. codegraph/viz/_style.py +45 -0
  44. codegraph/viz/dashboard.py +740 -0
  45. codegraph/viz/diagrams.py +370 -0
  46. codegraph/viz/explore.py +453 -0
  47. codegraph/viz/hld.py +683 -0
  48. codegraph/viz/html.py +115 -0
  49. codegraph/viz/mermaid.py +111 -0
  50. codegraph/viz/svg.py +77 -0
  51. codegraph/web/__init__.py +4 -0
  52. codegraph/web/server.py +165 -0
  53. codegraph/web/static/app.css +664 -0
  54. codegraph/web/static/app.js +919 -0
  55. codegraph/web/static/index.html +112 -0
  56. codegraph/web/static/views/architecture.js +1671 -0
  57. codegraph/web/static/views/graph3d.css +564 -0
  58. codegraph/web/static/views/graph3d.js +999 -0
  59. codegraph/web/static/views/graph3d_transform.js +984 -0
  60. codegraph/workspace/__init__.py +34 -0
  61. codegraph/workspace/config.py +110 -0
  62. codegraph/workspace/operations.py +294 -0
  63. polycodegraph-0.1.0.dist-info/METADATA +687 -0
  64. polycodegraph-0.1.0.dist-info/RECORD +67 -0
  65. polycodegraph-0.1.0.dist-info/WHEEL +4 -0
  66. polycodegraph-0.1.0.dist-info/entry_points.txt +2 -0
  67. polycodegraph-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,664 @@
1
+ /* ===========================================================
2
+ codegraph — refined design system
3
+ - Inter for UI text, JetBrains Mono for code/identifiers
4
+ - Layered ink palette + indigo brand + cyan/violet accents
5
+ - Subtle vignette background + soft elevation on cards
6
+ =========================================================== */
7
+
8
+ :root {
9
+ --bg-0: #05070d;
10
+ --bg-1: #0a0f1c;
11
+ --bg-2: #0f1626;
12
+ --bg-3: #161f33;
13
+ --bg-4: #1d2942;
14
+ --line: rgba(91, 107, 140, 0.18);
15
+ --line-strong: rgba(91, 107, 140, 0.32);
16
+ --txt-0: #e6ecf5;
17
+ --txt-1: #c4cfe2;
18
+ --txt-2: #8b9ab8;
19
+ --txt-3: #5b6b8c;
20
+ --brand: #818cf8;
21
+ --brand-strong: #6366f1;
22
+ --accent-cyan: #22d3ee;
23
+ --accent-emerald: #34d399;
24
+ --accent-amber: #fbbf24;
25
+ --accent-rose: #f87171;
26
+ --accent-violet: #a78bfa;
27
+ }
28
+
29
+ /* Background: deep navy with two soft radial highlights for warmth */
30
+ body { background: var(--bg-0); }
31
+ .app-bg {
32
+ position: fixed; inset: 0; z-index: -1; pointer-events: none;
33
+ background:
34
+ radial-gradient(900px 600px at 12% -10%, rgba(99,102,241,0.18), transparent 60%),
35
+ radial-gradient(800px 540px at 100% 0%, rgba(34,211,238,0.10), transparent 65%),
36
+ radial-gradient(700px 500px at 50% 110%, rgba(167,139,250,0.10), transparent 60%),
37
+ linear-gradient(180deg, #05070d 0%, #07091a 100%);
38
+ }
39
+
40
+ /* Typography */
41
+ body { font-feature-settings: "cv02","cv03","cv04","cv11"; letter-spacing: -0.005em; }
42
+ h1, h2, h3 { letter-spacing: -0.015em; }
43
+ .tnum, .stat-num, table.data td.num, table.data th.num {
44
+ font-feature-settings: "tnum", "ss01"; font-variant-numeric: tabular-nums;
45
+ }
46
+ code, .mono, .qn-mono {
47
+ font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
48
+ font-feature-settings: "calt" 0;
49
+ }
50
+
51
+ /* Scrollbars */
52
+ * { scrollbar-width: thin; scrollbar-color: var(--bg-4) transparent; }
53
+ *::-webkit-scrollbar { width: 10px; height: 10px; }
54
+ *::-webkit-scrollbar-track { background: transparent; }
55
+ *::-webkit-scrollbar-thumb {
56
+ background: var(--bg-4); border-radius: 5px; border: 2px solid transparent;
57
+ background-clip: padding-box;
58
+ }
59
+ *::-webkit-scrollbar-thumb:hover { background: #3b4a6a; background-clip: padding-box; }
60
+
61
+ /* ---------- Sidebar nav ---------- */
62
+ .nav-item {
63
+ display: flex; align-items: center; gap: 10px;
64
+ padding: 8px 10px; border-radius: 7px;
65
+ font-size: 13px; color: var(--txt-2);
66
+ cursor: pointer; transition: color .15s, background .15s, box-shadow .15s;
67
+ border: 1px solid transparent;
68
+ }
69
+ .nav-item:hover { color: var(--txt-0); background: rgba(29,41,66,0.55); }
70
+ .nav-item.active {
71
+ color: var(--txt-0);
72
+ background: linear-gradient(90deg, rgba(99,102,241,0.18), rgba(99,102,241,0.04));
73
+ box-shadow: inset 3px 0 0 0 var(--brand);
74
+ }
75
+ .nav-item.active svg { color: var(--brand); }
76
+ .nav-item svg { width: 16px; height: 16px; flex: none; transition: color .15s; }
77
+ .nav-section {
78
+ font-size: 10px; text-transform: uppercase; letter-spacing: 0.14em;
79
+ color: var(--txt-3); padding: 16px 10px 6px; font-weight: 600;
80
+ }
81
+
82
+ /* ---------- Cards / panels ---------- */
83
+ .panel {
84
+ background: linear-gradient(180deg, rgba(22,31,51,0.85), rgba(15,22,38,0.85));
85
+ border: 1px solid var(--line); border-radius: 14px;
86
+ box-shadow: 0 1px 0 0 rgba(255,255,255,0.03) inset,
87
+ 0 12px 32px -16px rgba(0,0,0,0.6);
88
+ backdrop-filter: blur(2px);
89
+ }
90
+ .stat-card {
91
+ position: relative; overflow: hidden;
92
+ background: linear-gradient(135deg, rgba(22,31,51,0.85), rgba(10,15,28,0.85));
93
+ border: 1px solid var(--line); border-radius: 14px;
94
+ padding: 18px 20px; transition: border-color .2s, transform .2s;
95
+ }
96
+ .stat-card::before {
97
+ content: ""; position: absolute; inset: -1px; border-radius: 14px; padding: 1px;
98
+ background: linear-gradient(135deg, rgba(129,140,248,0.20), transparent 60%);
99
+ -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
100
+ -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none;
101
+ }
102
+ .stat-card:hover { border-color: var(--line-strong); transform: translateY(-1px); }
103
+ .stat-num {
104
+ font-size: 28px; font-weight: 600; letter-spacing: -0.025em;
105
+ color: var(--txt-0); line-height: 1.1;
106
+ }
107
+ .stat-lbl {
108
+ font-size: 10px; text-transform: uppercase;
109
+ letter-spacing: 0.12em; color: var(--txt-2); margin-top: 8px;
110
+ font-weight: 600;
111
+ }
112
+
113
+ /* ---------- D3 chart polish ---------- */
114
+ .d3-axis text { fill: var(--txt-2); font-size: 11px; }
115
+ .d3-axis line, .d3-axis path { stroke: var(--line-strong); }
116
+ .d3-label { fill: var(--txt-1); font-size: 11px; font-variant-numeric: tabular-nums; }
117
+
118
+ /* ---------- Matrix ---------- */
119
+ .matrix-wrap {
120
+ overflow: auto; max-height: 78vh; border-radius: 12px;
121
+ border: 1px solid var(--line); background: var(--bg-1);
122
+ }
123
+ table.matrix { border-collapse: separate; border-spacing: 0; font-size: 11px; }
124
+ table.matrix th, table.matrix td { border: none; padding: 0; }
125
+ table.matrix .corner {
126
+ position: sticky; top: 0; left: 0; z-index: 4;
127
+ background: var(--bg-2);
128
+ }
129
+ table.matrix thead th {
130
+ position: sticky; top: 0; z-index: 3; background: var(--bg-2);
131
+ padding: 6px 4px; min-width: 22px; text-align: center;
132
+ transform: rotate(-45deg) translateY(8px);
133
+ transform-origin: bottom left; height: 110px; vertical-align: bottom;
134
+ font-weight: 500; color: var(--txt-2); white-space: nowrap;
135
+ font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 10.5px;
136
+ }
137
+ table.matrix tbody th {
138
+ position: sticky; left: 0; z-index: 2; background: var(--bg-2);
139
+ padding: 4px 12px; text-align: right; color: var(--txt-2);
140
+ white-space: nowrap; font-weight: 500;
141
+ max-width: 280px; overflow: hidden; text-overflow: ellipsis;
142
+ font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 11px;
143
+ }
144
+ table.matrix td.cell {
145
+ width: 22px; height: 22px; text-align: center;
146
+ color: #fff; cursor: default; transition: outline .1s;
147
+ font-variant-numeric: tabular-nums;
148
+ }
149
+ table.matrix td.cell:hover { outline: 2px solid var(--brand); outline-offset: -1px; }
150
+
151
+ /* ---------- Mermaid ---------- */
152
+ .mermaid-host {
153
+ padding: 28px;
154
+ background:
155
+ radial-gradient(800px 400px at 50% -20%, rgba(99,102,241,0.07), transparent 60%),
156
+ var(--bg-2);
157
+ border-radius: 12px; border: 1px solid var(--line); overflow: auto;
158
+ }
159
+ .mermaid-host .mermaid { display: flex; justify-content: center; }
160
+ .mermaid-host svg {
161
+ max-width: 100% !important; height: auto !important;
162
+ filter: drop-shadow(0 8px 24px rgba(0,0,0,0.45));
163
+ }
164
+ .mermaid-host .cluster rect { rx: 14; ry: 14; }
165
+
166
+ /* ---------- Flow list ---------- */
167
+ .flow-item {
168
+ padding: 11px 13px; border-radius: 9px; cursor: pointer;
169
+ border: 1px solid transparent; transition: background .15s, border-color .15s;
170
+ }
171
+ .flow-item:hover { background: rgba(22,31,51,0.7); }
172
+ .flow-item.active {
173
+ background: linear-gradient(90deg, rgba(99,102,241,0.18), rgba(99,102,241,0.05));
174
+ border-color: rgba(129,140,248,0.45);
175
+ box-shadow: 0 0 0 1px rgba(129,140,248,0.18), 0 6px 16px -8px rgba(99,102,241,0.5);
176
+ }
177
+ .flow-item .qn {
178
+ font-family: "JetBrains Mono", ui-monospace, monospace;
179
+ font-size: 12.5px; font-weight: 500; color: var(--txt-0);
180
+ line-height: 1.45; word-break: break-word;
181
+ }
182
+ .flow-item .qn .qn-dim { color: var(--txt-3); }
183
+ .flow-item .qn .qn-key { color: var(--brand); }
184
+ .flow-item .meta {
185
+ font-size: 11px; color: var(--txt-2); margin-top: 5px;
186
+ display: flex; align-items: center; gap: 6px;
187
+ }
188
+ .flow-item .meta svg { color: var(--accent-amber); }
189
+
190
+ /* ---------- Pill ---------- */
191
+ .pill {
192
+ display: inline-flex; align-items: center; gap: 4px;
193
+ padding: 2.5px 9px; border-radius: 999px;
194
+ background: rgba(29,41,66,0.7);
195
+ border: 1px solid var(--line);
196
+ font-size: 11px; color: var(--txt-1); font-weight: 500;
197
+ font-variant-numeric: tabular-nums;
198
+ }
199
+ .pill-warm { color: var(--accent-amber); border-color: rgba(251,191,36,0.35);
200
+ background: rgba(251,191,36,0.08); }
201
+ .pill-hot { color: var(--accent-rose); border-color: rgba(248,113,113,0.35);
202
+ background: rgba(248,113,113,0.08); }
203
+ .pill-cool { color: var(--accent-cyan); border-color: rgba(34,211,238,0.35);
204
+ background: rgba(34,211,238,0.08); }
205
+ .pill-good { color: var(--accent-emerald); border-color: rgba(52,211,153,0.35);
206
+ background: rgba(52,211,153,0.08); }
207
+ .pill svg { width: 11px; height: 11px; }
208
+
209
+ /* ---------- Layer swatch ---------- */
210
+ .swatch {
211
+ width: 12px; height: 12px; border-radius: 3px; flex: none;
212
+ box-shadow: 0 0 0 1px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.18);
213
+ }
214
+
215
+ /* ---------- Link ---------- */
216
+ .link {
217
+ color: var(--brand); text-decoration: none;
218
+ text-decoration-color: rgba(129,140,248,0.4);
219
+ text-underline-offset: 3px;
220
+ }
221
+ .link:hover { color: #c7d2fe; text-decoration: underline; }
222
+
223
+ /* ---------- Inline code ---------- */
224
+ code {
225
+ background: rgba(10,15,28,0.7);
226
+ padding: 1.5px 7px; border-radius: 5px;
227
+ font-size: 12px; border: 1px solid var(--line);
228
+ color: var(--txt-1);
229
+ font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
230
+ font-feature-settings: "calt" 0;
231
+ }
232
+ code .qn-dim { color: var(--txt-3); }
233
+
234
+ /* ---------- Tables ---------- */
235
+ table.data { width: 100%; border-collapse: collapse; font-size: 13px; }
236
+ table.data th {
237
+ text-align: left; padding: 10px 12px;
238
+ border-bottom: 1px solid var(--line);
239
+ color: var(--txt-2); font-weight: 600; font-size: 10.5px;
240
+ text-transform: uppercase; letter-spacing: 0.1em;
241
+ }
242
+ table.data td {
243
+ padding: 10px 12px; border-bottom: 1px solid var(--line);
244
+ color: var(--txt-1);
245
+ }
246
+ table.data tr:last-child td { border-bottom: none; }
247
+ table.data tr:hover td { background: rgba(29,41,66,0.35); }
248
+ table.data td.num, table.data th.num {
249
+ text-align: right; font-variant-numeric: tabular-nums;
250
+ }
251
+
252
+ /* ---------- Toast ---------- */
253
+ .toast {
254
+ background: linear-gradient(180deg, rgba(22,31,51,0.95), rgba(15,22,38,0.95));
255
+ border: 1px solid var(--line-strong);
256
+ border-left: 3px solid var(--brand);
257
+ padding: 10px 14px; border-radius: 9px;
258
+ font-size: 13px; color: var(--txt-0);
259
+ box-shadow: 0 12px 32px -8px rgba(0,0,0,0.6);
260
+ animation: slide .2s ease;
261
+ backdrop-filter: blur(6px);
262
+ }
263
+ .toast.error { border-left-color: var(--accent-rose); }
264
+ .toast.success { border-left-color: var(--accent-emerald); }
265
+ @keyframes slide {
266
+ from { transform: translateX(20px); opacity: 0; }
267
+ to { transform: translateX(0); opacity: 1; }
268
+ }
269
+
270
+ /* ---------- Loading spinner ---------- */
271
+ .spinner {
272
+ width: 16px; height: 16px; border-radius: 50%;
273
+ border: 2px solid var(--line-strong); border-top-color: var(--brand);
274
+ animation: spin .7s linear infinite;
275
+ display: inline-block;
276
+ }
277
+ @keyframes spin { to { transform: rotate(360deg); } }
278
+
279
+ /* ---------- Help banner ---------- */
280
+ .help-card {
281
+ background:
282
+ linear-gradient(135deg, rgba(129,140,248,0.10), rgba(34,211,238,0.04) 60%, transparent),
283
+ rgba(15,22,38,0.5);
284
+ border: 1px solid rgba(129,140,248,0.28);
285
+ border-radius: 12px; padding: 14px 18px;
286
+ display: flex; align-items: flex-start; gap: 12px;
287
+ font-size: 13px; line-height: 1.6; color: var(--txt-1);
288
+ }
289
+ .help-card .icon { color: var(--brand); flex: none; margin-top: 2px; }
290
+ .help-card b { color: var(--txt-0); font-weight: 600; }
291
+
292
+ /* ---------- Section heading ---------- */
293
+ .section-h {
294
+ display: flex; align-items: center; justify-content: space-between;
295
+ margin-bottom: 14px; gap: 12px;
296
+ }
297
+ .section-h h2 {
298
+ font-size: 11px; color: var(--txt-2);
299
+ text-transform: uppercase; letter-spacing: 0.14em;
300
+ font-weight: 700; margin: 0;
301
+ }
302
+
303
+ /* ---------- Search input ---------- */
304
+ input.search {
305
+ width: 100%; padding: 9px 12px 9px 34px;
306
+ background: rgba(10,15,28,0.7); color: var(--txt-0);
307
+ border: 1px solid var(--line); border-radius: 9px;
308
+ font-size: 13px; transition: border-color .15s, box-shadow .15s;
309
+ }
310
+ input.search::placeholder { color: var(--txt-3); }
311
+ input.search:focus {
312
+ outline: none; border-color: var(--brand);
313
+ box-shadow: 0 0 0 3px rgba(129,140,248,0.15);
314
+ }
315
+ .search-wrap { position: relative; }
316
+ .search-wrap > svg {
317
+ position: absolute; left: 11px; top: 50%;
318
+ transform: translateY(-50%); color: var(--txt-2);
319
+ width: 14px; height: 14px;
320
+ }
321
+
322
+ /* ---------- Qualname helpers (dimmed dotted prefix) ---------- */
323
+ .qn-mono { font-family: "JetBrains Mono", ui-monospace, monospace; }
324
+ .qn-mono .qn-dim { color: var(--txt-3); }
325
+ .qn-mono .qn-key { color: var(--txt-0); }
326
+
327
+ /* ---------- Icon button (header) ---------- */
328
+ .icon-btn {
329
+ width: 32px; height: 32px; display: inline-flex;
330
+ align-items: center; justify-content: center;
331
+ border-radius: 8px; color: var(--txt-2);
332
+ border: 1px solid var(--line);
333
+ background: rgba(22,31,51,0.6);
334
+ cursor: pointer; transition: color .15s, background .15s, border-color .15s;
335
+ }
336
+ .icon-btn:hover {
337
+ color: var(--txt-0); background: rgba(29,41,66,0.8);
338
+ border-color: var(--line-strong);
339
+ }
340
+ .icon-btn svg { width: 16px; height: 16px; }
341
+
342
+ /* Default = dark mode visible icon */
343
+ html.theme-light .theme-dark-only { display: none !important; }
344
+ html:not(.theme-light) .theme-light-only { display: none !important; }
345
+
346
+ /* ---------- Sidebar collapsed ---------- */
347
+ html.sb-collapsed #sidebar {
348
+ width: 64px !important;
349
+ }
350
+ html.sb-collapsed #sidebar .sb-label,
351
+ html.sb-collapsed #sidebar .nav-section,
352
+ html.sb-collapsed #sidebar .nav-item span { display: none; }
353
+ html.sb-collapsed #sidebar .nav-item { justify-content: center; padding: 8px; }
354
+ html.sb-collapsed #sidebar #rebuild-btn { padding: 8px 0; }
355
+
356
+ /* =========================================================
357
+ Light theme palette
358
+ ========================================================= */
359
+ html.theme-light {
360
+ --bg-0: #f4f6fb;
361
+ --bg-1: #ffffff;
362
+ --bg-2: #f7f9fd;
363
+ --bg-3: #eef2f9;
364
+ --bg-4: #dde4f0;
365
+ --line: rgba(15, 23, 42, 0.10);
366
+ --line-strong: rgba(15, 23, 42, 0.18);
367
+ --txt-0: #0f172a;
368
+ --txt-1: #1e293b;
369
+ --txt-2: #475569;
370
+ --txt-3: #94a3b8;
371
+ --brand: #4f46e5;
372
+ --brand-strong: #4338ca;
373
+ --accent-cyan: #0891b2;
374
+ --accent-emerald: #059669;
375
+ --accent-amber: #b45309;
376
+ --accent-rose: #dc2626;
377
+ --accent-violet: #7c3aed;
378
+ }
379
+ html.theme-light body { background: var(--bg-0); color: var(--txt-0); }
380
+ html.theme-light .app-bg {
381
+ background:
382
+ radial-gradient(900px 600px at 12% -10%, rgba(99,102,241,0.10), transparent 60%),
383
+ radial-gradient(800px 540px at 100% 0%, rgba(8,145,178,0.08), transparent 65%),
384
+ radial-gradient(700px 500px at 50% 110%, rgba(124,58,237,0.07), transparent 60%),
385
+ linear-gradient(180deg, #f4f6fb 0%, #eef2f9 100%);
386
+ }
387
+ html.theme-light .panel,
388
+ html.theme-light .stat-card {
389
+ background: linear-gradient(180deg, #ffffff, #f7f9fd);
390
+ box-shadow: 0 1px 0 0 rgba(255,255,255,1) inset,
391
+ 0 8px 24px -16px rgba(15,23,42,0.18);
392
+ }
393
+ html.theme-light .stat-card::before {
394
+ background: linear-gradient(135deg, rgba(99,102,241,0.18), transparent 60%);
395
+ }
396
+ html.theme-light aside,
397
+ html.theme-light header {
398
+ background: rgba(255,255,255,0.78) !important;
399
+ }
400
+ html.theme-light .nav-item:hover { background: rgba(99,102,241,0.07); }
401
+ html.theme-light .nav-item.active {
402
+ background: linear-gradient(90deg, rgba(99,102,241,0.16), rgba(99,102,241,0.04));
403
+ }
404
+ html.theme-light .matrix-wrap,
405
+ html.theme-light table.matrix .corner,
406
+ html.theme-light table.matrix thead th,
407
+ html.theme-light table.matrix tbody th { background: #ffffff; }
408
+ html.theme-light .mermaid-host {
409
+ background:
410
+ radial-gradient(800px 400px at 50% -20%, rgba(99,102,241,0.06), transparent 60%),
411
+ #ffffff;
412
+ }
413
+ html.theme-light .pill { background: rgba(99,102,241,0.08); color: var(--txt-1); }
414
+ html.theme-light code {
415
+ background: rgba(15,23,42,0.04); color: var(--txt-1);
416
+ }
417
+ html.theme-light input.search { background: #ffffff; color: var(--txt-0); }
418
+ html.theme-light .icon-btn { background: rgba(255,255,255,0.7); }
419
+ html.theme-light .icon-btn:hover { background: #ffffff; }
420
+ html.theme-light .help-card {
421
+ background: linear-gradient(135deg, rgba(99,102,241,0.08), rgba(8,145,178,0.04) 60%, transparent),
422
+ #ffffff;
423
+ border-color: rgba(99,102,241,0.25);
424
+ }
425
+ html.theme-light .toast {
426
+ background: #ffffff;
427
+ box-shadow: 0 12px 32px -8px rgba(15,23,42,0.18);
428
+ }
429
+ html.theme-light .flow-item:hover { background: rgba(99,102,241,0.06); }
430
+ html.theme-light .flow-item.active {
431
+ background: linear-gradient(90deg, rgba(99,102,241,0.14), rgba(99,102,241,0.04));
432
+ border-color: rgba(99,102,241,0.4);
433
+ }
434
+ html.theme-light .qn-mono .qn-key { color: var(--txt-0); }
435
+ html.theme-light .swatch { box-shadow: 0 0 0 1px rgba(15,23,42,0.15), inset 0 1px 0 rgba(255,255,255,0.6); }
436
+
437
+ /* ---------- Semantic text helpers (theme-aware) ---------- */
438
+ .text-app { color: var(--txt-0); }
439
+ .text-app-1 { color: var(--txt-1); }
440
+ .text-app-2 { color: var(--txt-2); }
441
+ .text-app-3 { color: var(--txt-3); }
442
+
443
+ /* ---------- HLD Navigator ---------- */
444
+ .hld-cols {
445
+ display: grid; gap: 12px;
446
+ grid-template-columns: minmax(0,1fr) minmax(0,1fr) minmax(0,1.3fr);
447
+ background: rgba(15,22,38,0.4);
448
+ border: 1px solid var(--line);
449
+ border-radius: 12px; padding: 10px;
450
+ }
451
+ @media (max-width: 900px) { .hld-cols { grid-template-columns: 1fr; } }
452
+ .hld-col {
453
+ background: var(--bg-2);
454
+ border: 1px solid var(--line);
455
+ border-radius: 10px; padding: 8px;
456
+ max-height: 460px; overflow-y: auto;
457
+ }
458
+ .hld-col-h {
459
+ font-size: 10.5px; font-weight: 700; letter-spacing: 0.12em;
460
+ text-transform: uppercase; color: var(--txt-2);
461
+ padding: 4px 8px 8px;
462
+ }
463
+ .hld-row {
464
+ display: flex; align-items: center; gap: 9px;
465
+ padding: 8px 9px; border-radius: 8px; cursor: pointer;
466
+ border: 1px solid transparent;
467
+ transition: background .12s, border-color .12s;
468
+ }
469
+ .hld-row:hover { background: rgba(99,102,241,0.08); }
470
+ .hld-row.active {
471
+ background: linear-gradient(90deg, rgba(99,102,241,0.18), rgba(99,102,241,0.04));
472
+ border-color: rgba(129,140,248,0.4);
473
+ }
474
+ .hld-row-t {
475
+ font-size: 13px; font-weight: 500; color: var(--txt-0);
476
+ line-height: 1.35; word-break: break-word;
477
+ }
478
+ .hld-row-s {
479
+ font-size: 11px; color: var(--txt-2);
480
+ margin-top: 2px; word-break: break-all;
481
+ }
482
+ .hld-ico { width: 14px; height: 14px; flex: none; color: var(--txt-2); }
483
+ .hld-chev { width: 14px; height: 14px; flex: none; color: var(--txt-3); }
484
+ .hld-empty { padding: 14px 10px; font-size: 12px; color: var(--txt-3); font-style: italic; }
485
+
486
+ .hld-crumb {
487
+ display: flex; align-items: center; gap: 6px;
488
+ font-size: 12px; color: var(--txt-2); flex-wrap: wrap;
489
+ }
490
+ .crumb-link { color: var(--brand); cursor: pointer; }
491
+ .crumb-link:hover { text-decoration: underline; }
492
+ .crumb-sep { color: var(--txt-3); }
493
+
494
+ .hld-detail {
495
+ margin-top: 14px;
496
+ }
497
+ .hld-detail:empty { display: none; }
498
+ .hld-detail-head {
499
+ background: rgba(99,102,241,0.06);
500
+ border: 1px solid rgba(129,140,248,0.25);
501
+ border-radius: 10px; padding: 12px 14px;
502
+ display: flex; align-items: flex-start; gap: 10px;
503
+ }
504
+ .hld-detail-title {
505
+ font-size: 14px; font-weight: 600; color: var(--txt-0);
506
+ word-break: break-word; line-height: 1.35;
507
+ }
508
+ .hld-detail-meta {
509
+ display: flex; gap: 6px; flex-wrap: wrap; align-items: center;
510
+ margin-top: 6px;
511
+ }
512
+ .call-row {
513
+ display: flex; align-items: center; gap: 8px;
514
+ padding: 7px 9px; border-radius: 7px; cursor: pointer;
515
+ font-size: 12.5px; color: var(--txt-1);
516
+ border: 1px solid transparent;
517
+ transition: background .12s, border-color .12s;
518
+ }
519
+ .call-row:hover {
520
+ background: rgba(99,102,241,0.08);
521
+ border-color: rgba(129,140,248,0.3);
522
+ }
523
+ .call-row .hld-ico { color: var(--brand); }
524
+
525
+ /* =========================================================
526
+ Light theme: override Tailwind ink-* utilities so they
527
+ read as theme-aware values. Tailwind CDN injects fixed
528
+ hex; we win with !important + html.theme-light prefix.
529
+ ========================================================= */
530
+ html.theme-light {
531
+ /* Body text default */
532
+ color: var(--txt-0);
533
+ }
534
+ html.theme-light .text-ink-50,
535
+ html.theme-light .text-ink-100 { color: var(--txt-0) !important; }
536
+ html.theme-light .text-ink-200 { color: var(--txt-2) !important; }
537
+ html.theme-light .text-ink-300 { color: var(--txt-3) !important; }
538
+ html.theme-light .text-ink-950 { color: #ffffff !important; }
539
+ html.theme-light .bg-ink-600,
540
+ html.theme-light .bg-ink-700,
541
+ html.theme-light .bg-ink-700\/60,
542
+ html.theme-light .bg-ink-700\/80,
543
+ html.theme-light .bg-ink-700\/95,
544
+ html.theme-light .bg-ink-900,
545
+ html.theme-light .bg-ink-900\/70,
546
+ html.theme-light .bg-ink-900\/80,
547
+ html.theme-light .bg-ink-950 {
548
+ background-color: rgba(255,255,255,0.78) !important;
549
+ }
550
+ html.theme-light .border-ink-500\/60,
551
+ html.theme-light .border-ink-500\/80,
552
+ html.theme-light .border-ink-600,
553
+ html.theme-light .border-ink-600\/60 {
554
+ border-color: var(--line-strong) !important;
555
+ }
556
+ html.theme-light input,
557
+ html.theme-light input.search { color: var(--txt-0); }
558
+ html.theme-light .text-accent-amber { color: #b45309 !important; }
559
+ html.theme-light .text-accent-rose { color: #be123c !important; }
560
+ html.theme-light .hld-col { background: #ffffff; }
561
+ html.theme-light .hld-cols { background: rgba(99,102,241,0.04); }
562
+ html.theme-light .hld-detail-head { background: rgba(99,102,241,0.06); }
563
+ html.theme-light .stat-num { color: var(--txt-0); }
564
+ html.theme-light .stat-lbl { color: var(--txt-2); }
565
+ html.theme-light .nav-item { color: var(--txt-2); }
566
+ html.theme-light .nav-item:hover,
567
+ html.theme-light .nav-item.active { color: var(--txt-0); }
568
+ html.theme-light table.data td { color: var(--txt-1); }
569
+ html.theme-light table.data th { color: var(--txt-2); }
570
+ html.theme-light .toast { color: var(--txt-0); }
571
+ html.theme-light .pill { color: var(--txt-1); }
572
+
573
+ /* ---------- HLD focus graph (D3 SVG) ---------- */
574
+ .hld-focus {
575
+ display: block; width: 100%; height: 320px;
576
+ margin-top: 14px; border-radius: 12px;
577
+ background:
578
+ radial-gradient(600px 320px at 50% 50%, rgba(99,102,241,0.06), transparent 70%),
579
+ var(--bg-2);
580
+ border: 1px solid var(--line);
581
+ }
582
+ .focus-edge {
583
+ fill: none; stroke-width: 1.5;
584
+ stroke-dasharray: 6 6;
585
+ animation: focus-flow 1.6s linear infinite;
586
+ }
587
+ .focus-in { stroke: var(--accent-cyan); stroke-dashoffset: 0; }
588
+ .focus-out { stroke: var(--brand); animation-direction: reverse; }
589
+ @keyframes focus-flow { to { stroke-dashoffset: -24; } }
590
+ .focus-dot { stroke: var(--bg-1); stroke-width: 2; }
591
+ .focus-dot-in { fill: var(--accent-cyan); }
592
+ .focus-dot-out { fill: var(--brand); }
593
+ .focus-core { fill: var(--brand-strong); stroke: var(--bg-1); stroke-width: 3; }
594
+ .focus-core-ring {
595
+ fill: none; stroke: var(--brand); stroke-width: 1.5;
596
+ stroke-dasharray: 4 4;
597
+ animation: focus-spin 8s linear infinite;
598
+ transform-origin: center;
599
+ }
600
+ @keyframes focus-spin { to { stroke-dashoffset: -64; } }
601
+ .focus-core-label {
602
+ fill: #ffffff; font-size: 11px; font-weight: 600;
603
+ font-family: "JetBrains Mono", ui-monospace, monospace;
604
+ paint-order: stroke; pointer-events: none;
605
+ }
606
+ .focus-label {
607
+ fill: var(--txt-1); font-size: 11px;
608
+ font-family: "JetBrains Mono", ui-monospace, monospace;
609
+ pointer-events: none;
610
+ }
611
+ .focus-caption {
612
+ fill: var(--txt-2); font-size: 10.5px;
613
+ text-transform: uppercase; letter-spacing: 0.1em; font-weight: 600;
614
+ }
615
+ .focus-node:hover .focus-dot { stroke: var(--brand); stroke-width: 3; }
616
+ .focus-node:hover .focus-label { fill: var(--txt-0); }
617
+
618
+ /* ---------- Sidebar collapse: fully icon-only ---------- */
619
+ html.sb-collapsed #sidebar > div:first-child {
620
+ /* shrink the header so logo centers nicely */
621
+ padding: 18px 10px;
622
+ }
623
+ html.sb-collapsed #sidebar > div:first-child > div:last-child { display: none; }
624
+ html.sb-collapsed #sidebar > div:last-child {
625
+ /* footer (rebuild + last-built) */
626
+ padding: 8px 8px 12px;
627
+ }
628
+ html.sb-collapsed #sidebar #rebuild-btn span { display: none; }
629
+ html.sb-collapsed #sidebar #last-built { display: none; }
630
+ html.sb-collapsed #sidebar .nav-section { display: none; }
631
+ html.sb-collapsed #sidebar .nav-item span { display: none; }
632
+ html.sb-collapsed #sidebar .nav-item { padding: 9px 0; justify-content: center; }
633
+ html.sb-collapsed #sidebar .nav-item.active { box-shadow: inset 3px 0 0 0 var(--brand); }
634
+
635
+ /* ---------- Light theme: extra Tailwind utility coverage ---------- */
636
+ html.theme-light .hover\:bg-ink-600:hover,
637
+ html.theme-light .hover\:bg-ink-700:hover,
638
+ html.theme-light .hover\:bg-ink-700\/60:hover { background-color: rgba(99,102,241,0.08) !important; }
639
+ html.theme-light .hover\:border-brand-500:hover { border-color: var(--brand) !important; }
640
+ html.theme-light .text-brand-500 { color: var(--brand) !important; }
641
+ html.theme-light .group:hover .group-hover\:bg-brand-600 { background-color: var(--brand) !important; }
642
+ html.theme-light .group:hover .group-hover\:text-white { color: #ffffff !important; }
643
+ html.theme-light .from-brand-500 { --tw-gradient-from: #6366f1 var(--tw-gradient-from-position) !important; }
644
+ html.theme-light .via-brand-600 { --tw-gradient-via: #4f46e5 var(--tw-gradient-via-position) !important; }
645
+ html.theme-light .to-accent-cyan { --tw-gradient-to: #0891b2 var(--tw-gradient-to-position) !important; }
646
+
647
+ /* Crumb / page title default text */
648
+ html.theme-light #page-title { color: var(--txt-0); }
649
+ html.theme-light #crumb { color: var(--txt-2); }
650
+
651
+ /* Mermaid container in light mode (reduce harsh contrast) */
652
+ html.theme-light .mermaid-host svg {
653
+ filter: drop-shadow(0 6px 16px rgba(15,23,42,0.10));
654
+ }
655
+
656
+ /* Pyvis pages render their own dark bg; in light mode show a thin
657
+ hint banner above the iframe-style links so users know they open
658
+ externally and inherit dark styling. */
659
+ html.theme-light .pyvis-warn { display: flex !important; }
660
+ .pyvis-warn { display: none; }
661
+
662
+ .bg-app-1 { background: var(--bg-1); }
663
+ .bg-app-2 { background: var(--bg-2); }
664
+ .bg-app-3 { background: var(--bg-3); }