openreport 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/bin/openreport.ts +6 -0
  4. package/package.json +61 -0
  5. package/src/agents/api-documentation.ts +66 -0
  6. package/src/agents/architecture-analyst.ts +46 -0
  7. package/src/agents/code-quality-reviewer.ts +59 -0
  8. package/src/agents/dependency-analyzer.ts +51 -0
  9. package/src/agents/onboarding-guide.ts +59 -0
  10. package/src/agents/orchestrator.ts +41 -0
  11. package/src/agents/performance-analyzer.ts +57 -0
  12. package/src/agents/registry.ts +50 -0
  13. package/src/agents/security-auditor.ts +61 -0
  14. package/src/agents/test-coverage-analyst.ts +58 -0
  15. package/src/agents/todo-generator.ts +50 -0
  16. package/src/app/App.tsx +151 -0
  17. package/src/app/theme.ts +54 -0
  18. package/src/cli.ts +145 -0
  19. package/src/commands/init.ts +81 -0
  20. package/src/commands/interactive.tsx +29 -0
  21. package/src/commands/list.ts +53 -0
  22. package/src/commands/run.ts +168 -0
  23. package/src/commands/view.tsx +52 -0
  24. package/src/components/generation/AgentStatusItem.tsx +125 -0
  25. package/src/components/generation/AgentStatusList.tsx +70 -0
  26. package/src/components/generation/ProgressSummary.tsx +107 -0
  27. package/src/components/generation/StreamingOutput.tsx +154 -0
  28. package/src/components/layout/Container.tsx +24 -0
  29. package/src/components/layout/Footer.tsx +52 -0
  30. package/src/components/layout/Header.tsx +50 -0
  31. package/src/components/report/MarkdownRenderer.tsx +50 -0
  32. package/src/components/report/ReportCard.tsx +31 -0
  33. package/src/components/report/ScrollableView.tsx +164 -0
  34. package/src/config/cli-detection.ts +130 -0
  35. package/src/config/cli-model.ts +397 -0
  36. package/src/config/cli-prompt-formatter.ts +129 -0
  37. package/src/config/defaults.ts +79 -0
  38. package/src/config/loader.ts +168 -0
  39. package/src/config/ollama.ts +48 -0
  40. package/src/config/providers.ts +199 -0
  41. package/src/config/resolve-provider.ts +62 -0
  42. package/src/config/saver.ts +50 -0
  43. package/src/config/schema.ts +51 -0
  44. package/src/errors.ts +34 -0
  45. package/src/hooks/useReportGeneration.ts +199 -0
  46. package/src/hooks/useTerminalSize.ts +35 -0
  47. package/src/ingestion/context-selector.ts +247 -0
  48. package/src/ingestion/file-tree.ts +227 -0
  49. package/src/ingestion/token-budget.ts +52 -0
  50. package/src/pipeline/agent-runner.ts +360 -0
  51. package/src/pipeline/combiner.ts +199 -0
  52. package/src/pipeline/context.ts +108 -0
  53. package/src/pipeline/extraction.ts +153 -0
  54. package/src/pipeline/progress.ts +192 -0
  55. package/src/pipeline/runner.ts +526 -0
  56. package/src/report/html-renderer.ts +294 -0
  57. package/src/report/html-script.ts +123 -0
  58. package/src/report/html-styles.ts +1127 -0
  59. package/src/report/md-to-html.ts +153 -0
  60. package/src/report/open-browser.ts +22 -0
  61. package/src/schemas/findings.ts +48 -0
  62. package/src/schemas/report.ts +64 -0
  63. package/src/screens/ConfigScreen.tsx +271 -0
  64. package/src/screens/GenerationScreen.tsx +278 -0
  65. package/src/screens/HistoryScreen.tsx +108 -0
  66. package/src/screens/HomeScreen.tsx +143 -0
  67. package/src/screens/ViewerScreen.tsx +82 -0
  68. package/src/storage/metadata.ts +69 -0
  69. package/src/storage/report-store.ts +128 -0
  70. package/src/tools/get-file-tree.ts +157 -0
  71. package/src/tools/get-git-info.ts +123 -0
  72. package/src/tools/glob.ts +48 -0
  73. package/src/tools/grep.ts +149 -0
  74. package/src/tools/index.ts +30 -0
  75. package/src/tools/list-directory.ts +57 -0
  76. package/src/tools/read-file.ts +52 -0
  77. package/src/tools/read-package-json.ts +48 -0
  78. package/src/tools/run-command.ts +154 -0
  79. package/src/tools/shared-ignore.ts +58 -0
  80. package/src/types/index.ts +127 -0
  81. package/src/types/marked-terminal.d.ts +17 -0
  82. package/src/utils/debug.ts +25 -0
  83. package/src/utils/file-utils.ts +77 -0
  84. package/src/utils/format.ts +56 -0
  85. package/src/utils/grade-colors.ts +43 -0
  86. package/src/utils/project-detector.ts +296 -0
@@ -0,0 +1,1127 @@
1
+ export const STYLES = `
2
+ /* ================================================================
3
+ OPENREPORT - Retro-Tech Theme
4
+ A modern retro-futuristic design system
5
+ ================================================================ */
6
+
7
+ /* -- CSS Variables / Dark Theme (default) -- */
8
+ :root {
9
+ --bg: #0a0e1a;
10
+ --bg-surface: #0f1628;
11
+ --bg-surface2: #161d33;
12
+ --bg-surface3: #1c2541;
13
+ --bg-surface-hover: #1a2340;
14
+ --text: #e0e6f0;
15
+ --text-dim: #7a85a0;
16
+ --text-muted: #4a5470;
17
+ --border: #1e2a4a;
18
+ --border-subtle: #151d35;
19
+ --accent: #818cf8;
20
+ --accent-dim: rgba(129, 140, 248, 0.15);
21
+ --accent-glow: rgba(129, 140, 248, 0.3);
22
+ --neon-green: #00ff88;
23
+ --neon-cyan: #22d3ee;
24
+ --neon-purple: #a78bfa;
25
+ --critical: #ff3366;
26
+ --critical-bg: rgba(255, 51, 102, 0.08);
27
+ --critical-border: rgba(255, 51, 102, 0.25);
28
+ --critical-glow: rgba(255, 51, 102, 0.15);
29
+ --warning: #fbbf24;
30
+ --warning-bg: rgba(251, 191, 36, 0.08);
31
+ --warning-border: rgba(251, 191, 36, 0.25);
32
+ --warning-glow: rgba(251, 191, 36, 0.15);
33
+ --info: #38bdf8;
34
+ --info-bg: rgba(56, 189, 248, 0.08);
35
+ --info-border: rgba(56, 189, 248, 0.25);
36
+ --info-glow: rgba(56, 189, 248, 0.15);
37
+ --suggestion: #a78bfa;
38
+ --suggestion-bg: rgba(167, 139, 250, 0.08);
39
+ --suggestion-border: rgba(167, 139, 250, 0.25);
40
+ --suggestion-glow: rgba(167, 139, 250, 0.15);
41
+ --sidebar-w: 280px;
42
+ --radius: 8px;
43
+ --radius-lg: 12px;
44
+ --font-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
45
+ --font-mono: "Geist Mono", "JetBrains Mono", "Fira Code", "SF Mono", "Cascadia Code", "Consolas", monospace;
46
+ --transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
47
+ --shadow-glow: 0 0 30px rgba(129, 140, 248, 0.06);
48
+ --grid-color: rgba(129, 140, 248, 0.03);
49
+ }
50
+
51
+ /* -- Light Theme -- */
52
+ .light-theme {
53
+ --bg: #f8f9fc;
54
+ --bg-surface: #ffffff;
55
+ --bg-surface2: #f1f3f8;
56
+ --bg-surface3: #e8ecf4;
57
+ --bg-surface-hover: #eef1f8;
58
+ --text: #1a1f36;
59
+ --text-dim: #5a6178;
60
+ --text-muted: #9ca3b8;
61
+ --border: #e2e6f0;
62
+ --border-subtle: #edf0f7;
63
+ --accent: #6366f1;
64
+ --accent-dim: rgba(99, 102, 241, 0.08);
65
+ --accent-glow: rgba(99, 102, 241, 0.15);
66
+ --neon-green: #059669;
67
+ --neon-cyan: #0891b2;
68
+ --neon-purple: #7c3aed;
69
+ --critical: #dc2626;
70
+ --critical-bg: rgba(220, 38, 38, 0.05);
71
+ --critical-border: rgba(220, 38, 38, 0.2);
72
+ --critical-glow: transparent;
73
+ --warning: #d97706;
74
+ --warning-bg: rgba(217, 119, 6, 0.05);
75
+ --warning-border: rgba(217, 119, 6, 0.2);
76
+ --warning-glow: transparent;
77
+ --info: #0284c7;
78
+ --info-bg: rgba(2, 132, 199, 0.05);
79
+ --info-border: rgba(2, 132, 199, 0.2);
80
+ --info-glow: transparent;
81
+ --suggestion: #7c3aed;
82
+ --suggestion-bg: rgba(124, 58, 237, 0.05);
83
+ --suggestion-border: rgba(124, 58, 237, 0.2);
84
+ --suggestion-glow: transparent;
85
+ --shadow-glow: 0 1px 3px rgba(0, 0, 0, 0.06);
86
+ --grid-color: transparent;
87
+ }
88
+
89
+ /* -- Reset -- */
90
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
91
+ html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
92
+
93
+ body {
94
+ font-family: var(--font-sans);
95
+ background: var(--bg);
96
+ color: var(--text);
97
+ line-height: 1.7;
98
+ font-size: 15px;
99
+ -webkit-font-smoothing: antialiased;
100
+ -moz-osx-font-smoothing: grayscale;
101
+ overflow-x: hidden;
102
+ }
103
+
104
+ /* Subtle background grid (dark only) */
105
+ body::before {
106
+ content: "";
107
+ position: fixed;
108
+ inset: 0;
109
+ background-image:
110
+ linear-gradient(var(--grid-color) 1px, transparent 1px),
111
+ linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
112
+ background-size: 60px 60px;
113
+ pointer-events: none;
114
+ z-index: 0;
115
+ }
116
+
117
+ /* Scanline overlay - very subtle CRT effect (dark only) */
118
+ .scanline-overlay {
119
+ position: fixed;
120
+ inset: 0;
121
+ background: repeating-linear-gradient(
122
+ 0deg,
123
+ transparent,
124
+ transparent 2px,
125
+ rgba(0, 0, 0, 0.015) 2px,
126
+ rgba(0, 0, 0, 0.015) 4px
127
+ );
128
+ pointer-events: none;
129
+ z-index: 9999;
130
+ }
131
+ .light-theme .scanline-overlay { display: none; }
132
+ .light-theme body::before { display: none; }
133
+
134
+ /* -- Links -- */
135
+ a { color: var(--accent); text-decoration: none; transition: color var(--transition); }
136
+ a:hover { color: var(--neon-cyan); text-decoration: underline; text-underline-offset: 2px; }
137
+
138
+ /* ================================================================
139
+ SIDEBAR
140
+ ================================================================ */
141
+ .sidebar {
142
+ position: fixed; left: 0; top: 0; bottom: 0;
143
+ width: var(--sidebar-w);
144
+ background: var(--bg-surface);
145
+ border-right: 1px solid var(--border);
146
+ display: flex; flex-direction: column;
147
+ overflow-y: auto;
148
+ z-index: 100;
149
+ }
150
+
151
+ .sidebar-header {
152
+ display: flex; justify-content: space-between; align-items: center;
153
+ padding: 1.25rem 1.25rem 1rem;
154
+ border-bottom: 1px solid var(--border);
155
+ }
156
+
157
+ .brand {
158
+ font-family: var(--font-mono);
159
+ font-weight: 700;
160
+ font-size: 0.85rem;
161
+ letter-spacing: 0.1em;
162
+ color: var(--text);
163
+ user-select: none;
164
+ }
165
+ .brand-bracket {
166
+ color: var(--text-muted);
167
+ font-weight: 400;
168
+ }
169
+ .brand-accent {
170
+ color: var(--accent);
171
+ text-shadow: 0 0 20px var(--accent-glow);
172
+ }
173
+ .light-theme .brand-accent {
174
+ text-shadow: none;
175
+ }
176
+
177
+ .theme-toggle {
178
+ background: var(--bg-surface2);
179
+ border: 1px solid var(--border);
180
+ color: var(--text-dim);
181
+ border-radius: var(--radius);
182
+ padding: 0.4rem;
183
+ cursor: pointer;
184
+ display: flex; align-items: center; justify-content: center;
185
+ transition: all var(--transition);
186
+ line-height: 1;
187
+ }
188
+ .theme-toggle:hover {
189
+ color: var(--accent);
190
+ border-color: var(--accent);
191
+ background: var(--accent-dim);
192
+ }
193
+ .theme-icon--light { display: none; }
194
+ .light-theme .theme-icon--dark { display: none; }
195
+ .light-theme .theme-icon--light { display: block; }
196
+
197
+ .sidebar-project {
198
+ padding: 1rem 1.25rem;
199
+ border-bottom: 1px solid var(--border);
200
+ display: flex; flex-direction: column; gap: 0.25rem;
201
+ }
202
+ .sidebar-project-label {
203
+ font-family: var(--font-mono);
204
+ font-size: 0.6rem;
205
+ font-weight: 600;
206
+ letter-spacing: 0.15em;
207
+ color: var(--text-muted);
208
+ text-transform: uppercase;
209
+ }
210
+ .sidebar-project-name {
211
+ font-size: 0.875rem;
212
+ font-weight: 600;
213
+ color: var(--text);
214
+ white-space: nowrap;
215
+ overflow: hidden;
216
+ text-overflow: ellipsis;
217
+ }
218
+
219
+ .toc-label {
220
+ font-family: var(--font-mono);
221
+ font-size: 0.6rem;
222
+ font-weight: 600;
223
+ letter-spacing: 0.15em;
224
+ color: var(--text-muted);
225
+ padding: 1rem 1.25rem 0.5rem;
226
+ text-transform: uppercase;
227
+ }
228
+
229
+ .toc { list-style: none; flex: 1; padding: 0 0 0.5rem; }
230
+ .toc li a {
231
+ display: flex; align-items: center; gap: 0.75rem;
232
+ padding: 0.5rem 1.25rem;
233
+ font-size: 0.82rem;
234
+ color: var(--text-dim);
235
+ transition: all var(--transition);
236
+ border-left: 2px solid transparent;
237
+ text-decoration: none;
238
+ }
239
+ .toc-index {
240
+ font-family: var(--font-mono);
241
+ font-size: 0.65rem;
242
+ color: var(--text-muted);
243
+ min-width: 1.25rem;
244
+ transition: color var(--transition);
245
+ }
246
+ .toc li a:hover,
247
+ .toc li a.active {
248
+ color: var(--text);
249
+ background: var(--bg-surface2);
250
+ border-left-color: var(--accent);
251
+ text-decoration: none;
252
+ }
253
+ .toc li a:hover .toc-index,
254
+ .toc li a.active .toc-index {
255
+ color: var(--accent);
256
+ }
257
+
258
+ .sidebar-footer {
259
+ padding: 1rem 1.25rem;
260
+ border-top: 1px solid var(--border);
261
+ display: flex; flex-direction: column; gap: 0.5rem;
262
+ }
263
+ .sidebar-footer-row {
264
+ display: flex; justify-content: space-between; align-items: center;
265
+ }
266
+ .meta-label {
267
+ font-family: var(--font-mono);
268
+ font-size: 0.6rem;
269
+ font-weight: 600;
270
+ letter-spacing: 0.12em;
271
+ color: var(--text-muted);
272
+ text-transform: uppercase;
273
+ }
274
+ .meta-value {
275
+ font-size: 0.75rem;
276
+ color: var(--text-dim);
277
+ font-family: var(--font-mono);
278
+ }
279
+
280
+ .menu-toggle {
281
+ display: none;
282
+ position: fixed; top: 1rem; left: 1rem; z-index: 200;
283
+ background: var(--bg-surface);
284
+ border: 1px solid var(--border);
285
+ color: var(--text);
286
+ padding: 0.5rem;
287
+ border-radius: var(--radius);
288
+ cursor: pointer;
289
+ line-height: 1;
290
+ transition: all var(--transition);
291
+ }
292
+ .menu-toggle:hover {
293
+ border-color: var(--accent);
294
+ color: var(--accent);
295
+ }
296
+
297
+ /* ================================================================
298
+ MAIN CONTENT
299
+ ================================================================ */
300
+ main {
301
+ position: relative;
302
+ z-index: 1;
303
+ margin-left: var(--sidebar-w);
304
+ padding: 2.5rem 4rem 5rem;
305
+ }
306
+
307
+ /* ================================================================
308
+ HEADER
309
+ ================================================================ */
310
+ header {
311
+ margin-bottom: 3rem;
312
+ padding-bottom: 2rem;
313
+ border-bottom: 1px solid var(--border);
314
+ }
315
+
316
+ .header-top {
317
+ display: flex;
318
+ justify-content: space-between;
319
+ align-items: flex-start;
320
+ gap: 2rem;
321
+ flex-wrap: wrap;
322
+ }
323
+
324
+ .report-title {
325
+ display: flex;
326
+ align-items: baseline;
327
+ gap: 1rem;
328
+ flex-wrap: wrap;
329
+ }
330
+ .report-title h1 {
331
+ font-family: var(--font-mono);
332
+ font-size: 2rem;
333
+ font-weight: 700;
334
+ letter-spacing: -0.02em;
335
+ line-height: 1.2;
336
+ background: linear-gradient(135deg, var(--text) 0%, var(--text-dim) 100%);
337
+ -webkit-background-clip: text;
338
+ background-clip: text;
339
+ }
340
+ .light-theme .report-title h1 {
341
+ background: none;
342
+ -webkit-background-clip: unset;
343
+ background-clip: unset;
344
+ color: var(--text);
345
+ }
346
+ .report-type {
347
+ font-family: var(--font-mono);
348
+ font-size: 0.7rem;
349
+ font-weight: 600;
350
+ color: var(--accent);
351
+ background: var(--accent-dim);
352
+ padding: 0.25rem 0.75rem;
353
+ border-radius: 100px;
354
+ letter-spacing: 0.05em;
355
+ text-transform: uppercase;
356
+ border: 1px solid rgba(129, 140, 248, 0.15);
357
+ white-space: nowrap;
358
+ }
359
+
360
+ /* Grade Badge */
361
+ .header-badges { display: flex; }
362
+ .grade-badge {
363
+ position: relative;
364
+ display: flex;
365
+ flex-direction: column;
366
+ align-items: center;
367
+ justify-content: center;
368
+ width: 4.5rem;
369
+ height: 4.5rem;
370
+ border-radius: var(--radius-lg);
371
+ background: var(--bg-surface2);
372
+ border: 1px solid var(--border);
373
+ overflow: hidden;
374
+ }
375
+ .grade-glow {
376
+ position: absolute;
377
+ inset: 0;
378
+ opacity: 0.12;
379
+ filter: blur(12px);
380
+ border-radius: inherit;
381
+ z-index: 0;
382
+ }
383
+ .light-theme .grade-glow { opacity: 0.08; }
384
+ .grade-letter {
385
+ position: relative;
386
+ z-index: 1;
387
+ font-family: var(--font-mono);
388
+ font-weight: 800;
389
+ font-size: 1.75rem;
390
+ line-height: 1;
391
+ color: var(--grade-color);
392
+ text-shadow: 0 0 20px color-mix(in srgb, var(--grade-color) 40%, transparent);
393
+ }
394
+ .light-theme .grade-letter { text-shadow: none; }
395
+ .grade-label {
396
+ position: relative;
397
+ z-index: 1;
398
+ font-family: var(--font-mono);
399
+ font-size: 0.55rem;
400
+ font-weight: 600;
401
+ letter-spacing: 0.15em;
402
+ color: var(--text-muted);
403
+ margin-top: 0.15rem;
404
+ }
405
+
406
+ /* Header Meta Chips */
407
+ .header-meta {
408
+ display: flex;
409
+ flex-wrap: wrap;
410
+ gap: 0.6rem;
411
+ margin-top: 1.25rem;
412
+ }
413
+ .meta-chip {
414
+ display: inline-flex;
415
+ align-items: center;
416
+ gap: 0.4rem;
417
+ font-family: var(--font-mono);
418
+ font-size: 0.75rem;
419
+ color: var(--text-dim);
420
+ background: var(--bg-surface);
421
+ border: 1px solid var(--border);
422
+ border-radius: 100px;
423
+ padding: 0.35rem 0.85rem;
424
+ transition: all var(--transition);
425
+ }
426
+ .meta-chip svg { color: var(--text-muted); flex-shrink: 0; }
427
+ .meta-chip:hover { border-color: var(--accent); color: var(--text); }
428
+ .meta-chip:hover svg { color: var(--accent); }
429
+
430
+ /* ================================================================
431
+ SECTIONS
432
+ ================================================================ */
433
+ section { margin-bottom: 3.5rem; }
434
+
435
+ h2 {
436
+ font-family: var(--font-mono);
437
+ font-size: 1.35rem;
438
+ font-weight: 700;
439
+ letter-spacing: -0.01em;
440
+ margin-bottom: 1.25rem;
441
+ padding-bottom: 0.75rem;
442
+ border-bottom: 1px solid var(--border);
443
+ display: flex;
444
+ align-items: baseline;
445
+ gap: 0.75rem;
446
+ }
447
+ .section-index {
448
+ font-family: var(--font-mono);
449
+ font-size: 0.7rem;
450
+ font-weight: 600;
451
+ color: var(--accent);
452
+ opacity: 0.6;
453
+ letter-spacing: 0.05em;
454
+ min-width: 1.5rem;
455
+ }
456
+
457
+ h3 {
458
+ font-family: var(--font-sans);
459
+ font-size: 1.1rem;
460
+ font-weight: 600;
461
+ margin: 1.75rem 0 0.75rem;
462
+ display: flex;
463
+ align-items: center;
464
+ gap: 0.5rem;
465
+ }
466
+ .h3-marker {
467
+ font-family: var(--font-mono);
468
+ color: var(--accent);
469
+ opacity: 0.4;
470
+ font-weight: 400;
471
+ font-size: 0.85em;
472
+ }
473
+
474
+ h4, h5, h6 {
475
+ font-family: var(--font-sans);
476
+ font-weight: 600;
477
+ margin: 1.25rem 0 0.5rem;
478
+ }
479
+ h4 { font-size: 1rem; }
480
+ h5 { font-size: 0.9rem; }
481
+ h6 { font-size: 0.85rem; color: var(--text-dim); }
482
+
483
+ p { margin-bottom: 0.75rem; }
484
+ ul, ol { margin: 0.5rem 0 1rem 1.5rem; }
485
+ li { margin-bottom: 0.35rem; }
486
+ li::marker { color: var(--text-muted); }
487
+ strong { font-weight: 600; }
488
+ em { color: var(--text-dim); }
489
+
490
+ /* ================================================================
491
+ SEVERITY CARDS
492
+ ================================================================ */
493
+ .severity-cards {
494
+ display: grid;
495
+ grid-template-columns: repeat(5, 1fr);
496
+ gap: 0.75rem;
497
+ }
498
+
499
+ .severity-card {
500
+ background: var(--bg-surface);
501
+ border: 1px solid var(--border);
502
+ border-radius: var(--radius-lg);
503
+ padding: 0;
504
+ text-align: center;
505
+ transition: all var(--transition);
506
+ overflow: hidden;
507
+ position: relative;
508
+ }
509
+ .severity-card::before {
510
+ content: "";
511
+ position: absolute;
512
+ top: 0; left: 0; right: 0;
513
+ height: 2px;
514
+ }
515
+ .severity-card:hover {
516
+ transform: translateY(-2px);
517
+ box-shadow: var(--shadow-glow);
518
+ }
519
+ .severity-card-inner {
520
+ padding: 1.25rem 0.75rem;
521
+ display: flex;
522
+ flex-direction: column;
523
+ align-items: center;
524
+ gap: 0.35rem;
525
+ }
526
+
527
+ .severity-icon { color: var(--text-muted); line-height: 1; }
528
+
529
+ .severity-card.critical::before { background: var(--critical); box-shadow: 0 0 12px var(--critical-glow); }
530
+ .severity-card.critical { border-color: var(--critical-border); background: var(--critical-bg); }
531
+ .severity-card.critical .severity-icon { color: var(--critical); }
532
+
533
+ .severity-card.warning::before { background: var(--warning); box-shadow: 0 0 12px var(--warning-glow); }
534
+ .severity-card.warning { border-color: var(--warning-border); background: var(--warning-bg); }
535
+ .severity-card.warning .severity-icon { color: var(--warning); }
536
+
537
+ .severity-card.info::before { background: var(--info); box-shadow: 0 0 12px var(--info-glow); }
538
+ .severity-card.info { border-color: var(--info-border); background: var(--info-bg); }
539
+ .severity-card.info .severity-icon { color: var(--info); }
540
+
541
+ .severity-card.suggestion::before { background: var(--suggestion); box-shadow: 0 0 12px var(--suggestion-glow); }
542
+ .severity-card.suggestion { border-color: var(--suggestion-border); background: var(--suggestion-bg); }
543
+ .severity-card.suggestion .severity-icon { color: var(--suggestion); }
544
+
545
+ .severity-card.total::before { background: var(--accent); }
546
+ .severity-card.total .severity-icon { color: var(--accent); }
547
+
548
+ .severity-count {
549
+ display: block;
550
+ font-family: var(--font-mono);
551
+ font-size: 2rem;
552
+ font-weight: 800;
553
+ line-height: 1;
554
+ letter-spacing: -0.02em;
555
+ }
556
+ .severity-card.critical .severity-count { color: var(--critical); text-shadow: 0 0 20px var(--critical-glow); }
557
+ .severity-card.warning .severity-count { color: var(--warning); text-shadow: 0 0 20px var(--warning-glow); }
558
+ .severity-card.info .severity-count { color: var(--info); text-shadow: 0 0 20px var(--info-glow); }
559
+ .severity-card.suggestion .severity-count { color: var(--suggestion); text-shadow: 0 0 20px var(--suggestion-glow); }
560
+ .severity-card.total .severity-count { color: var(--accent); }
561
+ .light-theme .severity-count { text-shadow: none; }
562
+
563
+ .severity-label {
564
+ font-family: var(--font-mono);
565
+ font-size: 0.65rem;
566
+ font-weight: 600;
567
+ color: var(--text-muted);
568
+ text-transform: uppercase;
569
+ letter-spacing: 0.1em;
570
+ }
571
+
572
+ /* ================================================================
573
+ SUB-REPORTS
574
+ ================================================================ */
575
+ .sub-summary {
576
+ color: var(--text-dim);
577
+ font-size: 0.95rem;
578
+ margin-bottom: 1.75rem;
579
+ padding-left: 1rem;
580
+ border-left: 2px solid var(--border);
581
+ font-style: italic;
582
+ }
583
+ .report-section { margin-bottom: 1.75rem; }
584
+ .summary-text { line-height: 1.8; }
585
+
586
+ /* ================================================================
587
+ CODE BLOCKS
588
+ ================================================================ */
589
+ pre {
590
+ background: var(--bg-surface);
591
+ border: 1px solid var(--border);
592
+ border-radius: var(--radius);
593
+ padding: 1rem 1.25rem;
594
+ overflow-x: auto;
595
+ font-size: 0.82rem;
596
+ margin: 1rem 0 1.25rem;
597
+ position: relative;
598
+ line-height: 1.6;
599
+ }
600
+ /* Terminal top bar decoration */
601
+ pre::before {
602
+ content: "";
603
+ display: block;
604
+ height: 3px;
605
+ margin: -1rem -1.25rem 0.75rem;
606
+ background: linear-gradient(90deg,
607
+ var(--critical) 0%, var(--critical) 20%,
608
+ var(--warning) 20%, var(--warning) 40%,
609
+ var(--neon-green) 40%, var(--neon-green) 60%,
610
+ var(--info) 60%, var(--info) 80%,
611
+ var(--accent) 80%, var(--accent) 100%
612
+ );
613
+ border-radius: var(--radius) var(--radius) 0 0;
614
+ opacity: 0.5;
615
+ }
616
+ .light-theme pre::before { opacity: 0.35; }
617
+
618
+ code {
619
+ font-family: var(--font-mono);
620
+ font-size: 0.85em;
621
+ }
622
+ code.inline {
623
+ background: var(--bg-surface2);
624
+ padding: 0.15rem 0.45rem;
625
+ border-radius: 4px;
626
+ font-size: 0.83em;
627
+ border: 1px solid var(--border-subtle);
628
+ color: var(--neon-cyan);
629
+ }
630
+ .light-theme code.inline { color: var(--accent); }
631
+
632
+ /* ================================================================
633
+ TABLES
634
+ ================================================================ */
635
+ .table-wrap {
636
+ overflow-x: auto;
637
+ margin: 1rem 0;
638
+ border-radius: var(--radius);
639
+ border: 1px solid var(--border);
640
+ }
641
+ table {
642
+ width: 100%;
643
+ border-collapse: collapse;
644
+ font-size: 0.875rem;
645
+ }
646
+ th, td {
647
+ padding: 0.6rem 1rem;
648
+ text-align: left;
649
+ border-bottom: 1px solid var(--border-subtle);
650
+ }
651
+ th {
652
+ font-family: var(--font-mono);
653
+ font-weight: 600;
654
+ font-size: 0.7rem;
655
+ color: var(--text-muted);
656
+ text-transform: uppercase;
657
+ letter-spacing: 0.08em;
658
+ background: var(--bg-surface);
659
+ border-bottom-color: var(--border);
660
+ }
661
+ tr:last-child td { border-bottom: none; }
662
+ tr:hover td { background: var(--bg-surface-hover); }
663
+
664
+ /* ================================================================
665
+ FINDINGS
666
+ ================================================================ */
667
+ .findings-section { margin-top: 2rem; }
668
+ .findings-count {
669
+ font-family: var(--font-mono);
670
+ font-size: 0.75rem;
671
+ font-weight: 600;
672
+ color: var(--text-muted);
673
+ background: var(--bg-surface2);
674
+ padding: 0.1rem 0.5rem;
675
+ border-radius: 100px;
676
+ margin-left: 0.25rem;
677
+ }
678
+
679
+ .finding {
680
+ background: var(--bg-surface);
681
+ border: 1px solid var(--border);
682
+ border-radius: var(--radius);
683
+ margin-bottom: 0.6rem;
684
+ transition: all var(--transition);
685
+ overflow: hidden;
686
+ }
687
+ .finding:hover { border-color: color-mix(in srgb, var(--border) 50%, var(--text-muted)); }
688
+
689
+ .finding summary {
690
+ padding: 0.75rem 1rem;
691
+ cursor: pointer;
692
+ display: flex;
693
+ align-items: center;
694
+ gap: 0.65rem;
695
+ list-style: none;
696
+ font-weight: 500;
697
+ font-size: 0.92rem;
698
+ user-select: none;
699
+ transition: background var(--transition);
700
+ }
701
+ .finding summary:hover { background: var(--bg-surface-hover); }
702
+ .finding summary::-webkit-details-marker { display: none; }
703
+ .finding summary::marker { content: ""; }
704
+
705
+ .finding-chevron {
706
+ color: var(--text-muted);
707
+ transition: transform var(--transition);
708
+ flex-shrink: 0;
709
+ display: flex;
710
+ align-items: center;
711
+ }
712
+ .finding[open] .finding-chevron { transform: rotate(90deg); }
713
+
714
+ .finding-title { flex: 1; }
715
+
716
+ .finding-body {
717
+ padding: 0 1rem 1.25rem;
718
+ padding-left: 1rem;
719
+ animation: fadeIn 0.2s ease;
720
+ }
721
+ @keyframes fadeIn {
722
+ from { opacity: 0; transform: translateY(-4px); }
723
+ to { opacity: 1; transform: translateY(0); }
724
+ }
725
+ .finding-body p {
726
+ color: var(--text-dim);
727
+ font-size: 0.9rem;
728
+ line-height: 1.7;
729
+ }
730
+ .finding-files {
731
+ margin: 0.75rem 0;
732
+ display: flex;
733
+ flex-wrap: wrap;
734
+ align-items: center;
735
+ gap: 0.4rem;
736
+ }
737
+ .finding-files-label {
738
+ font-family: var(--font-mono);
739
+ font-size: 0.6rem;
740
+ font-weight: 700;
741
+ letter-spacing: 0.12em;
742
+ color: var(--text-muted);
743
+ margin-right: 0.25rem;
744
+ }
745
+ .finding-files code.inline { font-size: 0.78em; }
746
+
747
+ .finding-recommendation {
748
+ margin-top: 0.75rem;
749
+ padding: 0.85rem 1rem;
750
+ background: var(--bg-surface2);
751
+ border-radius: var(--radius);
752
+ font-size: 0.88rem;
753
+ line-height: 1.65;
754
+ border: 1px solid var(--border-subtle);
755
+ }
756
+ .finding-rec-label {
757
+ display: block;
758
+ font-family: var(--font-mono);
759
+ font-size: 0.6rem;
760
+ font-weight: 700;
761
+ letter-spacing: 0.12em;
762
+ color: var(--accent);
763
+ margin-bottom: 0.35rem;
764
+ }
765
+
766
+ /* Finding severity left border */
767
+ .finding-critical { border-left: 3px solid var(--critical); }
768
+ .finding-warning { border-left: 3px solid var(--warning); }
769
+ .finding-info { border-left: 3px solid var(--info); }
770
+ .finding-suggestion { border-left: 3px solid var(--suggestion); }
771
+
772
+ /* ================================================================
773
+ BADGES
774
+ ================================================================ */
775
+ .badge {
776
+ font-family: var(--font-mono);
777
+ font-size: 0.6rem;
778
+ font-weight: 700;
779
+ text-transform: uppercase;
780
+ padding: 0.2rem 0.55rem;
781
+ border-radius: 4px;
782
+ letter-spacing: 0.06em;
783
+ white-space: nowrap;
784
+ flex-shrink: 0;
785
+ }
786
+ .badge-critical {
787
+ background: var(--critical-bg);
788
+ color: var(--critical);
789
+ border: 1px solid var(--critical-border);
790
+ }
791
+ .badge-warning {
792
+ background: var(--warning-bg);
793
+ color: var(--warning);
794
+ border: 1px solid var(--warning-border);
795
+ }
796
+ .badge-info {
797
+ background: var(--info-bg);
798
+ color: var(--info);
799
+ border: 1px solid var(--info-border);
800
+ }
801
+ .badge-suggestion {
802
+ background: var(--suggestion-bg);
803
+ color: var(--suggestion);
804
+ border: 1px solid var(--suggestion-border);
805
+ }
806
+
807
+ .effort {
808
+ font-family: var(--font-mono);
809
+ font-size: 0.6rem;
810
+ font-weight: 600;
811
+ padding: 0.15rem 0.5rem;
812
+ border-radius: 100px;
813
+ margin-left: auto;
814
+ background: var(--bg-surface2);
815
+ color: var(--text-dim);
816
+ text-transform: uppercase;
817
+ letter-spacing: 0.06em;
818
+ display: inline-flex;
819
+ align-items: center;
820
+ gap: 0.3rem;
821
+ white-space: nowrap;
822
+ flex-shrink: 0;
823
+ }
824
+ .effort-dot {
825
+ display: inline-block;
826
+ width: 5px;
827
+ height: 5px;
828
+ border-radius: 50%;
829
+ background: var(--text-muted);
830
+ }
831
+ .effort-low .effort-dot { background: var(--neon-green); }
832
+ .effort-medium .effort-dot { background: var(--warning); }
833
+ .effort-high .effort-dot { background: var(--critical); }
834
+
835
+ /* ================================================================
836
+ CHECKLISTS (Todo)
837
+ ================================================================ */
838
+ .checklist {
839
+ list-style: none;
840
+ margin: 0.75rem 0 1rem 0;
841
+ padding: 0;
842
+ }
843
+ .checklist-item {
844
+ display: flex;
845
+ align-items: flex-start;
846
+ gap: 0.65rem;
847
+ padding: 0.55rem 0.85rem;
848
+ margin-bottom: 0.25rem;
849
+ border-radius: var(--radius);
850
+ font-size: 0.9rem;
851
+ line-height: 1.6;
852
+ cursor: pointer;
853
+ user-select: none;
854
+ transition: all var(--transition);
855
+ border: 1px solid transparent;
856
+ }
857
+ .checklist-item:hover {
858
+ background: var(--bg-surface-hover);
859
+ border-color: var(--border-subtle);
860
+ }
861
+ .checklist-item.checked .checklist-text {
862
+ color: var(--text-muted);
863
+ text-decoration: line-through;
864
+ text-decoration-color: var(--text-muted);
865
+ }
866
+ .checklist-text {
867
+ flex: 1;
868
+ min-width: 0;
869
+ word-wrap: break-word;
870
+ overflow-wrap: break-word;
871
+ }
872
+ .checklist-text code.inline {
873
+ word-break: break-all;
874
+ }
875
+
876
+ .checkbox {
877
+ flex-shrink: 0;
878
+ display: inline-flex;
879
+ align-items: center;
880
+ justify-content: center;
881
+ width: 1.2rem;
882
+ height: 1.2rem;
883
+ margin-top: 0.2rem;
884
+ border: 2px solid var(--text-muted);
885
+ border-radius: 4px;
886
+ font-size: 0.7rem;
887
+ color: transparent;
888
+ background: transparent;
889
+ transition: all var(--transition);
890
+ }
891
+ .checkbox-checked {
892
+ background: var(--neon-green);
893
+ border-color: var(--neon-green);
894
+ color: #000;
895
+ }
896
+ .light-theme .checkbox-checked { background: #059669; border-color: #059669; color: #fff; }
897
+
898
+ /* ================================================================
899
+ TODO SECTION
900
+ ================================================================ */
901
+ .todo-section {
902
+ position: relative;
903
+ }
904
+ .todo-section::before {
905
+ content: "";
906
+ position: absolute;
907
+ top: 0; left: -1rem; bottom: 0;
908
+ width: 3px;
909
+ border-radius: 2px;
910
+ background: linear-gradient(180deg, var(--critical) 0%, var(--warning) 35%, var(--info) 70%, var(--suggestion) 100%);
911
+ opacity: 0.5;
912
+ }
913
+
914
+ .todo-header {
915
+ display: flex;
916
+ justify-content: space-between;
917
+ align-items: center;
918
+ flex-wrap: wrap;
919
+ gap: 0.75rem;
920
+ margin-bottom: 1.25rem;
921
+ }
922
+
923
+ .todo-copy-btn {
924
+ font-family: var(--font-mono);
925
+ font-size: 0.7rem;
926
+ font-weight: 600;
927
+ letter-spacing: 0.04em;
928
+ color: var(--accent);
929
+ background: var(--accent-dim);
930
+ border: 1px solid rgba(129, 140, 248, 0.2);
931
+ border-radius: 100px;
932
+ padding: 0.35rem 0.9rem;
933
+ cursor: pointer;
934
+ display: inline-flex;
935
+ align-items: center;
936
+ gap: 0.4rem;
937
+ transition: all var(--transition);
938
+ text-transform: uppercase;
939
+ }
940
+ .todo-copy-btn:hover {
941
+ background: var(--accent);
942
+ color: #fff;
943
+ border-color: var(--accent);
944
+ }
945
+
946
+ .todo-priority-group {
947
+ margin-bottom: 1.75rem;
948
+ }
949
+ .todo-priority-label {
950
+ font-family: var(--font-mono);
951
+ font-size: 0.7rem;
952
+ font-weight: 700;
953
+ letter-spacing: 0.1em;
954
+ text-transform: uppercase;
955
+ padding: 0.35rem 0.75rem;
956
+ border-radius: var(--radius);
957
+ margin-bottom: 0.6rem;
958
+ display: inline-flex;
959
+ align-items: center;
960
+ gap: 0.4rem;
961
+ }
962
+ .todo-priority-label.priority-critical {
963
+ color: var(--critical);
964
+ background: var(--critical-bg);
965
+ border: 1px solid var(--critical-border);
966
+ }
967
+ .todo-priority-label.priority-quickwins {
968
+ color: var(--warning);
969
+ background: var(--warning-bg);
970
+ border: 1px solid var(--warning-border);
971
+ }
972
+ .todo-priority-label.priority-planned {
973
+ color: var(--info);
974
+ background: var(--info-bg);
975
+ border: 1px solid var(--info-border);
976
+ }
977
+ .todo-priority-label.priority-nicetohave {
978
+ color: var(--suggestion);
979
+ background: var(--suggestion-bg);
980
+ border: 1px solid var(--suggestion-border);
981
+ }
982
+
983
+ /* ================================================================
984
+ RESPONSIVE
985
+ ================================================================ */
986
+ @media (max-width: 1024px) {
987
+ .severity-cards { grid-template-columns: repeat(3, 1fr); }
988
+ }
989
+
990
+ @media (max-width: 768px) {
991
+ .sidebar {
992
+ transform: translateX(-100%);
993
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
994
+ }
995
+ .sidebar.open {
996
+ transform: translateX(0);
997
+ box-shadow: 4px 0 40px rgba(0, 0, 0, 0.4);
998
+ }
999
+ .menu-toggle { display: flex; align-items: center; justify-content: center; }
1000
+ main { margin-left: 0; padding: 1.5rem 1.25rem 3rem; }
1001
+ .header-top { flex-direction: column; gap: 1rem; }
1002
+ .report-title h1 { font-size: 1.5rem; }
1003
+ .severity-cards {
1004
+ grid-template-columns: repeat(2, 1fr);
1005
+ gap: 0.5rem;
1006
+ }
1007
+ .severity-card-inner { padding: 1rem 0.5rem; }
1008
+ .severity-count { font-size: 1.5rem; }
1009
+ .header-meta { flex-direction: column; gap: 0.35rem; }
1010
+ .meta-chip { font-size: 0.7rem; }
1011
+ .grade-badge { width: 3.5rem; height: 3.5rem; }
1012
+ .grade-letter { font-size: 1.35rem; }
1013
+ }
1014
+
1015
+ @media (max-width: 480px) {
1016
+ .severity-cards { grid-template-columns: repeat(2, 1fr); }
1017
+ .severity-card:last-child { grid-column: 1 / -1; }
1018
+ }
1019
+
1020
+ /* ================================================================
1021
+ PRINT STYLES
1022
+ ================================================================ */
1023
+ @media print {
1024
+ .sidebar, .menu-toggle, .theme-toggle, .scanline-overlay { display: none !important; }
1025
+ body::before { display: none !important; }
1026
+ main { margin-left: 0; padding: 0; }
1027
+ body {
1028
+ background: #fff;
1029
+ color: #1a1a1a;
1030
+ font-size: 11pt;
1031
+ line-height: 1.5;
1032
+ }
1033
+ a { color: #1a1a1a; }
1034
+
1035
+ h1, h2, h3 { font-family: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
1036
+ h2 { font-size: 14pt; border-bottom: 1px solid #ddd; }
1037
+
1038
+ .report-title h1 {
1039
+ background: none;
1040
+ -webkit-background-clip: unset;
1041
+ background-clip: unset;
1042
+ color: #1a1a1a;
1043
+ }
1044
+
1045
+ .severity-cards { gap: 0.5rem; }
1046
+ .severity-card {
1047
+ border: 1px solid #ddd;
1048
+ background: #f9f9f9;
1049
+ break-inside: avoid;
1050
+ }
1051
+ .severity-card::before { display: none; }
1052
+ .severity-count { text-shadow: none; }
1053
+
1054
+ .finding { break-inside: avoid; border: 1px solid #ddd; }
1055
+ .finding-critical { border-left: 3px solid #dc2626; }
1056
+ .finding-warning { border-left: 3px solid #d97706; }
1057
+ .finding-info { border-left: 3px solid #0284c7; }
1058
+ .finding-suggestion { border-left: 3px solid #7c3aed; }
1059
+ details { open: true; }
1060
+ details[open] > summary { font-weight: 700; }
1061
+ details > .finding-body { display: block !important; }
1062
+ .finding-body { animation: none !important; }
1063
+ .finding-chevron { display: none; }
1064
+
1065
+ pre {
1066
+ white-space: pre-wrap;
1067
+ word-wrap: break-word;
1068
+ border: 1px solid #ddd;
1069
+ background: #f5f5f5;
1070
+ }
1071
+ pre::before { display: none; }
1072
+ code.inline { border: 1px solid #ddd; background: #f0f0f0; color: #1a1a1a; }
1073
+
1074
+ .grade-badge {
1075
+ border: 2px solid currentColor;
1076
+ }
1077
+ .grade-glow { display: none; }
1078
+ .grade-letter { text-shadow: none; }
1079
+
1080
+ .badge, .severity-card, .grade-badge {
1081
+ print-color-adjust: exact;
1082
+ -webkit-print-color-adjust: exact;
1083
+ }
1084
+
1085
+ .meta-chip { border: 1px solid #ddd; background: #f9f9f9; }
1086
+ .meta-chip svg { display: none; }
1087
+
1088
+ .report-type { border: 1px solid #ddd; background: #f0f0f0; color: #333; }
1089
+ .section-index, .toc-index, .h3-marker { color: #999; }
1090
+
1091
+ .sub-summary { border-left-color: #ccc; color: #555; }
1092
+ .todo-copy-btn { display: none; }
1093
+ .todo-section::before { background: #999; }
1094
+ .checkbox { border-color: #999; }
1095
+ .checkbox-checked { background: #059669; border-color: #059669; color: #fff; print-color-adjust: exact; -webkit-print-color-adjust: exact; }
1096
+
1097
+ .finding-recommendation { border: 1px solid #ddd; background: #fafafa; }
1098
+ .finding-rec-label { color: #333; }
1099
+ }
1100
+
1101
+ /* ================================================================
1102
+ SCROLLBAR (Webkit)
1103
+ ================================================================ */
1104
+ ::-webkit-scrollbar { width: 6px; height: 6px; }
1105
+ ::-webkit-scrollbar-track { background: transparent; }
1106
+ ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
1107
+ ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
1108
+
1109
+ /* ================================================================
1110
+ SELECTION
1111
+ ================================================================ */
1112
+ ::selection {
1113
+ background: var(--accent);
1114
+ color: #fff;
1115
+ }
1116
+
1117
+ /* ================================================================
1118
+ FOCUS VISIBLE
1119
+ ================================================================ */
1120
+ :focus-visible {
1121
+ outline: 2px solid var(--accent);
1122
+ outline-offset: 2px;
1123
+ border-radius: 2px;
1124
+ }
1125
+ `;
1126
+
1127
+ export function getStyles(): string { return STYLES; }