@vibecodeqa/cli 0.36.0 → 0.36.2
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.
- package/dist/monitor.js +116 -6
- package/dist/report/html.js +1 -1
- package/dist/report/pages.d.ts +1 -1
- package/dist/report/pages.js +37 -2
- package/dist/report/styles.d.ts +1 -1
- package/dist/report/styles.js +9 -0
- package/package.json +1 -1
package/dist/monitor.js
CHANGED
|
@@ -78,9 +78,31 @@ function copyToClipboard(text) {
|
|
|
78
78
|
return false;
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
-
function buildFixPrompt(checkName, issue) {
|
|
81
|
+
function buildFixPrompt(checkName, issue, cwd) {
|
|
82
82
|
const loc = issue.file ? `${issue.file}${issue.line ? `:${issue.line}` : ""}` : "";
|
|
83
|
-
|
|
83
|
+
let prompt = `Fix this ${issue.severity} in ${loc || "the project"}:\n${issue.message}${issue.rule ? ` (${issue.rule})` : ""}\nCheck: ${checkName}`;
|
|
84
|
+
// Include source context if available
|
|
85
|
+
if (cwd && issue.file && issue.line) {
|
|
86
|
+
try {
|
|
87
|
+
const fullPath = join(cwd, issue.file);
|
|
88
|
+
if (existsSync(fullPath)) {
|
|
89
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
90
|
+
const lines = content.split("\n");
|
|
91
|
+
const target = issue.line - 1;
|
|
92
|
+
const start = Math.max(0, target - 3);
|
|
93
|
+
const end = Math.min(lines.length, target + 4);
|
|
94
|
+
const snippet = lines.slice(start, end).map((l, i) => {
|
|
95
|
+
const num = start + i + 1;
|
|
96
|
+
const marker = num === issue.line ? ">>>" : " ";
|
|
97
|
+
return `${marker} ${num}: ${l}`;
|
|
98
|
+
}).join("\n");
|
|
99
|
+
prompt += `\n\nSource:\n${snippet}`;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch { /* ignore */ }
|
|
103
|
+
}
|
|
104
|
+
prompt += "\n\nAnalyze the code, explain the issue, and provide the fix.";
|
|
105
|
+
return prompt;
|
|
84
106
|
}
|
|
85
107
|
// ── Scan via child process — UI never freezes ──
|
|
86
108
|
function runScanProcess(cwd, skipTests) {
|
|
@@ -252,6 +274,65 @@ function CheckDetail({ check, height, cursor, copied }) {
|
|
|
252
274
|
return (_jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [_jsxs(Text, { children: [_jsx(Text, { color: sel ? "white" : "gray", children: sel ? "▸" : " " }), _jsxs(Text, { color: sc(iss.severity), bold: true, children: [iss.severity[0].toUpperCase(), " "] }), iss.file && _jsxs(Text, { color: "cyan", children: [String(iss.file), iss.line ? `:${iss.line}` : "", " "] }), iss.rule && _jsxs(Text, { dimColor: true, children: ["(", iss.rule, ")"] })] }), _jsxs(Text, { wrap: "wrap", children: [_jsx(Text, { color: sel ? "white" : "gray", children: " " }), _jsx(Text, { color: sel ? "white" : undefined, children: iss.message })] })] }, idx));
|
|
253
275
|
}), remaining > 0 && _jsxs(Text, { dimColor: true, children: [" +", remaining, " more (\u2193 to scroll)"] })] }))] }));
|
|
254
276
|
}
|
|
277
|
+
function readSourceContext(cwd, file, line, rule) {
|
|
278
|
+
if (!file || typeof file !== "string")
|
|
279
|
+
return null;
|
|
280
|
+
const fullPath = join(cwd, file);
|
|
281
|
+
try {
|
|
282
|
+
if (!existsSync(fullPath))
|
|
283
|
+
return null;
|
|
284
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
285
|
+
const allLines = content.split("\n");
|
|
286
|
+
const target = (line ?? 1) - 1; // 0-indexed
|
|
287
|
+
const contextRadius = 8;
|
|
288
|
+
const start = Math.max(0, target - contextRadius);
|
|
289
|
+
const end = Math.min(allLines.length, target + contextRadius + 1);
|
|
290
|
+
// Determine which lines to highlight based on rule
|
|
291
|
+
const highlightSet = new Set();
|
|
292
|
+
highlightSet.add(target);
|
|
293
|
+
// For multi-line issues, highlight the block
|
|
294
|
+
if (rule === "empty-catch" || rule === "fallback-catch" || rule === "no-assertions" || rule === "empty-test") {
|
|
295
|
+
// Highlight from target to closing brace
|
|
296
|
+
let depth = 0;
|
|
297
|
+
for (let i = target; i < Math.min(target + 15, allLines.length); i++) {
|
|
298
|
+
highlightSet.add(i);
|
|
299
|
+
depth += (allLines[i].match(/\{/g) || []).length;
|
|
300
|
+
depth -= (allLines[i].match(/\}/g) || []).length;
|
|
301
|
+
if (depth <= 0 && i > target)
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
else if (rule === "duplicate-code" || rule === "commented-out-code") {
|
|
306
|
+
// Highlight a block of lines
|
|
307
|
+
for (let i = target; i < Math.min(target + 6, allLines.length); i++) {
|
|
308
|
+
highlightSet.add(i);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
else if (rule === "high-complexity" || rule === "long-function") {
|
|
312
|
+
// Highlight function signature + a few lines
|
|
313
|
+
for (let i = target; i < Math.min(target + 3, allLines.length); i++) {
|
|
314
|
+
highlightSet.add(i);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const lines = [];
|
|
318
|
+
for (let i = start; i < end; i++) {
|
|
319
|
+
lines.push({ num: i + 1, text: allLines[i], highlight: highlightSet.has(i) });
|
|
320
|
+
}
|
|
321
|
+
return { lines, filePath: file };
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function IssueDetail({ issue, checkName, cwd, height, copied }) {
|
|
328
|
+
const ctx = readSourceContext(cwd, issue.file, issue.line, issue.rule);
|
|
329
|
+
const prompt = buildFixPrompt(checkName, issue, cwd);
|
|
330
|
+
// Split height: source gets top half, prompt gets bottom
|
|
331
|
+
const srcHeight = ctx ? Math.min(ctx.lines.length + 2, Math.floor((height - 8) * 0.6)) : 0;
|
|
332
|
+
const promptHeight = height - 8 - srcHeight;
|
|
333
|
+
const promptLines = prompt.split("\n");
|
|
334
|
+
return (_jsxs(Box, { flexDirection: "column", height: height, paddingX: 1, overflowY: "hidden", children: [_jsx(Text, { bold: true, color: "magenta", children: " \u25C8 Issue Detail" }), _jsxs(Text, { children: [_jsxs(Text, { color: sc(issue.severity), bold: true, children: [" ", issue.severity.toUpperCase(), " "] }), _jsx(Text, { dimColor: true, children: checkName }), issue.rule && _jsxs(Text, { dimColor: true, children: [" \u00B7 ", issue.rule] }), copied && _jsx(Text, { color: "green", bold: true, children: " \u2713 Copied!" })] }), _jsxs(Text, { wrap: "wrap", children: [" ", issue.message] }), issue.file && (_jsxs(Text, { color: "cyan", children: [" ", issue.file, issue.line ? `:${issue.line}` : ""] })), ctx && (_jsxs(Box, { flexDirection: "column", height: srcHeight, overflowY: "hidden", children: [_jsxs(Text, { dimColor: true, children: [" \u2500\u2500\u2500 ", ctx.filePath, " \u2500\u2500\u2500"] }), ctx.lines.slice(0, srcHeight - 2).map((l) => (_jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: l.highlight ? "yellow" : "gray", children: l.highlight ? "▸" : " " }), _jsxs(Text, { dimColor: true, children: [String(l.num).padStart(4), "\u2502"] }), _jsx(Text, { color: l.highlight ? "white" : undefined, children: l.text })] }, l.num))), _jsx(Text, { dimColor: true, children: " \u2500\u2500\u2500" })] })), _jsxs(Box, { flexDirection: "column", height: Math.max(3, promptHeight), overflowY: "hidden", marginTop: ctx ? 0 : 1, children: [_jsxs(Text, { bold: true, color: "green", children: [" Fix prompt ", _jsx(Text, { dimColor: true, children: "(y to copy)" })] }), promptLines.slice(0, Math.max(1, promptHeight - 1)).map((line, i) => (_jsxs(Text, { dimColor: true, wrap: "truncate", children: [" ", line] }, i)))] })] }));
|
|
335
|
+
}
|
|
255
336
|
function MonitorApp({ cwd }) {
|
|
256
337
|
const { exit } = useApp();
|
|
257
338
|
const { stdout } = useStdout();
|
|
@@ -371,10 +452,18 @@ function MonitorApp({ cwd }) {
|
|
|
371
452
|
exit();
|
|
372
453
|
return;
|
|
373
454
|
}
|
|
374
|
-
// Esc: drill up or quit
|
|
455
|
+
// Esc: drill up one level or quit
|
|
375
456
|
if (key.escape) {
|
|
376
457
|
if (mode.view === "config") {
|
|
377
458
|
setPendingCfg(null);
|
|
459
|
+
setMode({ view: "dashboard" });
|
|
460
|
+
setCursor(0);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (mode.view === "issue-detail") {
|
|
464
|
+
setMode({ view: "check-detail", checkName: mode.checkName });
|
|
465
|
+
setCursor(mode.issueIdx);
|
|
466
|
+
return;
|
|
378
467
|
}
|
|
379
468
|
if (mode.view !== "dashboard") {
|
|
380
469
|
setMode({ view: "dashboard" });
|
|
@@ -468,7 +557,7 @@ function MonitorApp({ cwd }) {
|
|
|
468
557
|
return;
|
|
469
558
|
}
|
|
470
559
|
}
|
|
471
|
-
// ── Check detail: ↑↓ scroll, Enter copies
|
|
560
|
+
// ── Check detail: ↑↓ scroll, Enter drills into issue, y copies prompt ──
|
|
472
561
|
if (mode.view === "check-detail") {
|
|
473
562
|
const check = state.checks.find((c) => c.name === mode.checkName);
|
|
474
563
|
if (check) {
|
|
@@ -477,7 +566,11 @@ function MonitorApp({ cwd }) {
|
|
|
477
566
|
if (key.downArrow)
|
|
478
567
|
setCursor((c) => Math.min(check.issues.length - 1, c + 1));
|
|
479
568
|
if (key.return && check.issues[cursor]) {
|
|
480
|
-
|
|
569
|
+
setMode({ view: "issue-detail", checkName: mode.checkName, issueIdx: cursor });
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
if (input === "y" && check.issues[cursor]) {
|
|
573
|
+
const prompt = buildFixPrompt(check.name, check.issues[cursor], cwd);
|
|
481
574
|
if (copyToClipboard(prompt)) {
|
|
482
575
|
setCopied(true);
|
|
483
576
|
addLog(`Copied fix prompt for ${check.name}:${check.issues[cursor].file || ""}`, "info");
|
|
@@ -486,6 +579,18 @@ function MonitorApp({ cwd }) {
|
|
|
486
579
|
}
|
|
487
580
|
}
|
|
488
581
|
}
|
|
582
|
+
// ── Issue detail: y copies prompt ──
|
|
583
|
+
if (mode.view === "issue-detail") {
|
|
584
|
+
const check = state.checks.find((c) => c.name === mode.checkName);
|
|
585
|
+
if (check && check.issues[mode.issueIdx] && input === "y") {
|
|
586
|
+
const prompt = buildFixPrompt(check.name, check.issues[mode.issueIdx], cwd);
|
|
587
|
+
if (copyToClipboard(prompt)) {
|
|
588
|
+
setCopied(true);
|
|
589
|
+
addLog(`Copied fix prompt`, "info");
|
|
590
|
+
setTimeout(() => setCopied(false), 2000);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
489
594
|
// ── Trends: ↑↓ scroll ──
|
|
490
595
|
if (mode.view === "trends") {
|
|
491
596
|
if (key.upArrow)
|
|
@@ -497,9 +602,14 @@ function MonitorApp({ cwd }) {
|
|
|
497
602
|
const proj = basename(cwd);
|
|
498
603
|
const p = monCfg.panels;
|
|
499
604
|
// ── Render views ──
|
|
605
|
+
if (mode.view === "issue-detail") {
|
|
606
|
+
const check = state.checks.find((c) => c.name === mode.checkName);
|
|
607
|
+
const issue = check?.issues[mode.issueIdx];
|
|
608
|
+
return (_jsxs(Box, { flexDirection: "column", height: rows, children: [_jsx(Header, { proj: proj, stack: stack, workspace: workspace, state: state }), issue ? (_jsx(IssueDetail, { issue: issue, checkName: mode.checkName, cwd: cwd, height: rows - 3, copied: copied })) : (_jsx(Text, { dimColor: true, children: " Issue not found" })), _jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, children: "Esc back \u00B7 y copy fix prompt \u00B7 q quit" }) })] }));
|
|
609
|
+
}
|
|
500
610
|
if (mode.view === "check-detail") {
|
|
501
611
|
const check = state.checks.find((c) => c.name === mode.checkName);
|
|
502
|
-
return (_jsxs(Box, { flexDirection: "column", height: rows, children: [_jsx(Header, { proj: proj, stack: stack, workspace: workspace, state: state }), check ? _jsx(CheckDetail, { check: check, height: rows - 3, cursor: cursor, copied: copied }) : _jsx(Text, { dimColor: true, children: " Check not found" }), _jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, children: "Esc back \u00B7 \u2191\u2193 select \u00B7 Enter copy
|
|
612
|
+
return (_jsxs(Box, { flexDirection: "column", height: rows, children: [_jsx(Header, { proj: proj, stack: stack, workspace: workspace, state: state }), check ? _jsx(CheckDetail, { check: check, height: rows - 3, cursor: cursor, copied: copied }) : _jsx(Text, { dimColor: true, children: " Check not found" }), _jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, children: "Esc back \u00B7 \u2191\u2193 select \u00B7 Enter view source \u00B7 y copy prompt \u00B7 q quit" }) })] }));
|
|
503
613
|
}
|
|
504
614
|
if (mode.view === "trends") {
|
|
505
615
|
return (_jsx(Box, { flexDirection: "column", height: rows, children: _jsx(TrendsScreen, { cwd: cwd, height: rows }) }));
|
package/dist/report/html.js
CHANGED
|
@@ -102,7 +102,7 @@ export function generatePages(report, historyDir) {
|
|
|
102
102
|
for (let i = 0; i < GROUPS.length; i++) {
|
|
103
103
|
const g = GROUPS[i];
|
|
104
104
|
const cs = catScores[i];
|
|
105
|
-
pages.set(g.file, w(g.id, categoryPage(cs, fl, allChecks)));
|
|
105
|
+
pages.set(g.file, w(g.id, categoryPage(cs, fl, allChecks, report.meta.cwd)));
|
|
106
106
|
}
|
|
107
107
|
// Feature Map (Pro page — reads dead-patterns check details)
|
|
108
108
|
const deadPatternsCheck = checkMap.get("dead-patterns");
|
package/dist/report/pages.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export interface FileEntry {
|
|
|
16
16
|
}
|
|
17
17
|
type FL = (path: string, line?: number) => string;
|
|
18
18
|
export declare function overviewPage(report: VibeReport, active: CheckResult[], totalIssues: number, catScores: CatScore[], allChecks: CheckResult[], topFiles: FileEntry[], fl: FL, historyDir?: string): string;
|
|
19
|
-
export declare function categoryPage(cs: CatScore, fl: FL, allChecks?: CheckResult[]): string;
|
|
19
|
+
export declare function categoryPage(cs: CatScore, fl: FL, allChecks?: CheckResult[], cwd?: string): string;
|
|
20
20
|
export declare function issuesPage(allChecks: CheckResult[], totalIssues: number, fl: FL): string;
|
|
21
21
|
export declare function filesPage(topFiles: FileEntry[], fileIssues: Map<string, {
|
|
22
22
|
errors: number;
|
package/dist/report/pages.js
CHANGED
|
@@ -1,10 +1,36 @@
|
|
|
1
1
|
/** Page renderers for the HTML report. */
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
2
4
|
import { getCheckMeta } from "../check-meta.js";
|
|
3
5
|
import { buildCoverageMapInput, generateCoverageMap } from "../diagrams/coverage.js";
|
|
4
6
|
import { loadHistory } from "../history.js";
|
|
5
7
|
import { generateArchSVG, generateDSM, generateLayerDiagram, generatePackageDiagram, generateSequenceDiagram, } from "../runners/architecture.js";
|
|
6
8
|
import { det, e, gc, pc } from "./components.js";
|
|
7
9
|
import { buildPyramid, buildRadar, buildRing, buildTimeline } from "./svg.js";
|
|
10
|
+
/** Read source lines around an issue for inline display in the report. */
|
|
11
|
+
function readSourceSnippet(cwd, file, line, radius = 4) {
|
|
12
|
+
try {
|
|
13
|
+
const fullPath = join(cwd, file);
|
|
14
|
+
if (!existsSync(fullPath))
|
|
15
|
+
return null;
|
|
16
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
17
|
+
const lines = content.split("\n");
|
|
18
|
+
const target = line - 1;
|
|
19
|
+
const start = Math.max(0, target - radius);
|
|
20
|
+
const end = Math.min(lines.length, target + radius + 1);
|
|
21
|
+
let html = "";
|
|
22
|
+
for (let i = start; i < end; i++) {
|
|
23
|
+
const num = String(i + 1).padStart(4);
|
|
24
|
+
const hl = i === target;
|
|
25
|
+
const cls = hl ? "src-hl" : "src-ln";
|
|
26
|
+
html += `<div class="${cls}"><span class="src-num">${num}</span>${e(lines[i])}</div>`;
|
|
27
|
+
}
|
|
28
|
+
return html;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
8
34
|
// ── Overview ──────────────────────────────────────────────────────────
|
|
9
35
|
export function overviewPage(report, active, totalIssues, catScores, allChecks, topFiles, fl, historyDir) {
|
|
10
36
|
const hero = `<div class="hero">
|
|
@@ -114,7 +140,7 @@ ${fileHotspotsHtml}
|
|
|
114
140
|
<div class="stack">${stackHtml}</div>`;
|
|
115
141
|
}
|
|
116
142
|
// ── Single category page ──────────────────────────────────────────
|
|
117
|
-
export function categoryPage(cs, fl, allChecks) {
|
|
143
|
+
export function categoryPage(cs, fl, allChecks, cwd) {
|
|
118
144
|
const checkSections = cs.checks
|
|
119
145
|
.map((c) => {
|
|
120
146
|
const meta = getCheckMeta(c.name);
|
|
@@ -148,7 +174,16 @@ export function categoryPage(cs, fl, allChecks) {
|
|
|
148
174
|
const snippetBtn = iss.snippet
|
|
149
175
|
? `<button class="cp-btn" data-prompt="${e(iss.snippet)}" title="Copy snippet to search">\ud83d\udd0d</button>`
|
|
150
176
|
: "";
|
|
151
|
-
|
|
177
|
+
// Source code snippet (collapsible)
|
|
178
|
+
let srcBlock = "";
|
|
179
|
+
if (cwd && iss.line && typeof iss.file === "string") {
|
|
180
|
+
const src = readSourceSnippet(cwd, iss.file, iss.line);
|
|
181
|
+
if (src) {
|
|
182
|
+
const fixPrompt = `Fix this ${iss.severity} in ${iss.file}:${iss.line}\n${iss.message}${iss.rule ? ` (${iss.rule})` : ""}\nCheck: ${c.name}\n\nAnalyze the code, explain the issue, and provide the fix.`;
|
|
183
|
+
srcBlock = `<div class="src-block">${src}<div class="src-prompt"><button class="cp-btn src-fix-btn" data-prompt="${e(fixPrompt)}" title="Copy fix prompt with source context">Copy fix prompt</button></div></div>`;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
issuesHtml += `<div class="ir ${iss.severity}"><span class="is">${iss.severity[0].toUpperCase()}</span>${iss.line ? `<span class="il">${iss.line}</span>` : ""}<span class="im">${e(iss.message)}</span>${iss.rule ? `<span class="iru">${e(iss.rule)}</span>` : ""}${snippetBtn}<button class="cp-btn" data-prompt="${e(prompt)}" title="Copy fix prompt">\ud83d\udccb</button></div>${srcBlock}`;
|
|
152
187
|
}
|
|
153
188
|
issuesHtml += `</div>`;
|
|
154
189
|
}
|
package/dist/report/styles.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** All CSS for the HTML report, extracted for maintainability. */
|
|
2
|
-
export declare const CSS = "\n:root{--bg:#09090b;--card:#111115;--border:#1e1e24;--text:#e5e5e5;--muted:#6b7280;--pass:#22c55e;--fail:#ef4444;--warn:#eab308;--info:#6366f1;--accent:#818cf8;--side-w:200px;--top-h:42px;--nav-bg:#0c0c0fdd;--side-bg:#0c0c0f;--hover:#14141a;--dim:#555;--card-alt:#0d0d12}\n[data-theme=\"light\"]{--bg:#f5f5f7;--card:#ffffff;--border:#e2e4e9;--text:#1a1a2e;--muted:#64748b;--pass:#16a34a;--fail:#dc2626;--warn:#ca8a04;--info:#4f46e5;--accent:#4f46e5;--nav-bg:#ffffffee;--side-bg:#fafafa;--hover:#eef0f5;--dim:#94a3b8;--card-alt:#f0f0f5}\nhtml{font-size:17px}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:\"Inter\",system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.5}\ncode{font-family:\"SF Mono\",Menlo,monospace;font-size:0.85em}\n\n/* \u2500\u2500 Top nav \u2500\u2500 */\n.top{position:sticky;top:0;z-index:30;background:var(--nav-bg);backdrop-filter:blur(12px);border-bottom:1px solid var(--border);padding:0 1.5rem;display:flex;align-items:center;height:var(--top-h)}\n.logo{font-weight:800;font-size:1rem;margin-right:0.5rem;flex-shrink:0;text-decoration:none;color:var(--text)}\n.logo span{color:var(--accent)}\n.nav-project{font-size:0.72rem;color:var(--muted);font-weight:600;margin-right:1rem;padding:0.2rem 0.5rem;background:var(--card);border:1px solid var(--border);border-radius:4px;flex-shrink:0}\n.nav-scroll{display:flex;align-items:center;gap:0;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;flex:1}\n.nav-scroll::-webkit-scrollbar{display:none}\n.tn{padding:0 0.7rem;font-size:0.78rem;color:var(--muted);text-decoration:none;border-bottom:2px solid transparent;transition:all 0.15s;white-space:nowrap;line-height:var(--top-h)}\n.tn:hover{color:var(--text)}\n.tn.active{color:var(--text);border-bottom-color:var(--accent)}\n.hamburger{display:none;background:none;border:none;color:var(--muted);font-size:1.3rem;cursor:pointer;padding:0 0.4rem;line-height:var(--top-h)}\n\n/* \u2500\u2500 Sidebar \u2500\u2500 */\n.side{position:fixed;top:var(--top-h);left:0;bottom:0;width:var(--side-w);background:var(--side-bg);border-right:1px solid var(--border);overflow-y:auto;padding:0.6rem 0;font-size:0.7rem;z-index:20}\n.side-section{padding:0.3rem 0;border-bottom:1px solid var(--border)}\n.side-section:last-child{border-bottom:none}\n.side-label{padding:0.2rem 0.8rem;font-size:0.6rem;text-transform:uppercase;letter-spacing:0.05em;color:var(--dim);font-weight:600}\n.side-score{font-size:1.4rem;font-weight:900;padding:0.2rem 0.8rem}\n.side-cat{display:block;padding:0.3rem 0.8rem;color:var(--muted);font-weight:600;cursor:pointer;text-decoration:none;font-size:0.72rem}\n.side-cat:hover{background:var(--hover);color:var(--text)}\n.side-cat-active{color:var(--text);font-weight:700;border-left:2px solid var(--accent);padding-left:calc(0.8rem - 2px)}\n.side-cat-title{padding:0.3rem 0.8rem;font-size:0.65rem;text-transform:uppercase;letter-spacing:0.04em;color:var(--accent);font-weight:700}\n.side-check{display:block;padding:0.15rem 0.8rem 0.15rem 0.8rem;color:var(--muted);cursor:pointer;text-decoration:none;font-size:0.65rem}\n.side-check:hover{color:var(--text);background:#14141a}\n.side-check span{display:inline-block;min-width:2.5rem;font-weight:700;font-size:0.6rem}\n.side-stat{padding:0.15rem 0.8rem;font-size:0.7rem;color:var(--muted)}\n.side-stat span{font-weight:800;font-size:0.8rem}\n.side-views{padding-top:0.3rem}\n.side-views .side-check{padding-left:0.8rem}\n\n/* \u2500\u2500 Content \u2500\u2500 */\n.content{margin-left:var(--side-w);padding:1.5rem 2rem;max-width:960px}\n\n/* \u2500\u2500 Overview \u2500\u2500 */\n.dash{display:flex;gap:2rem;margin-bottom:2rem;align-items:center;flex-wrap:wrap}\n.hero{display:flex;align-items:center;gap:1rem}\n.hero svg{width:100px;height:100px}\n.hc{display:flex;flex-direction:column}\n.hg{font-size:2.5rem;font-weight:900;line-height:1}\n.hs{font-size:1rem;font-weight:600}\n.hd{font-size:0.68rem;color:var(--muted)}\n.radar{flex:1;display:flex;justify-content:center}\n.radar svg{max-width:240px;width:100%}\n.cats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:0.6rem;margin-bottom:2rem}\n.cc{background:var(--card);border:1px solid var(--border);border-radius:0.6rem;padding:0.8rem;transition:border-color 0.15s;text-decoration:none;color:var(--text);display:block}\n.cc:hover{border-color:var(--accent)}\n.cc-s{font-size:1.8rem;font-weight:900}\n.cc-l{font-size:0.75rem;color:var(--muted)}\n.cc-m{margin-top:0.3rem;display:flex;gap:0.25rem}\n.mc{font-size:0.65rem;font-weight:800}\nh3{font-size:0.85rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.04em;margin-bottom:0.5rem}\n\n/* \u2500\u2500 Overview sections \u2500\u2500 */\n.ov-section{margin-bottom:1.5rem}\n.ov-issue{font-size:0.68rem;font-family:\"SF Mono\",monospace;padding:0.2rem 0;display:flex;gap:0.4rem;align-items:baseline;border-bottom:1px solid var(--border)}\n.ov-issue .is{flex-shrink:0}\n.ov-issue.error .is{color:var(--fail)}\n.ov-issue.warning .is{color:var(--warn)}\n.ov-check{color:var(--muted);width:70px;flex-shrink:0;font-size:0.62rem}\n.ov-loc{color:var(--accent);flex-shrink:0;font-size:0.62rem;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.ov-msg{flex:1;word-break:break-word}\n.ov-link{display:block;margin-top:0.5rem;font-size:0.72rem;color:var(--accent);text-decoration:none}\n.ov-link:hover{text-decoration:underline}\n\n/* \u2500\u2500 Timeline \u2500\u2500 */\n.timeline{margin:0.5rem 0;overflow-x:auto}\n.timeline svg{max-width:100%}\n\n/* \u2500\u2500 Bar chart \u2500\u2500 */\n.bars{margin-bottom:1.5rem}\n.brow{display:flex;align-items:center;gap:0.4rem;margin-bottom:0.25rem;font-size:0.72rem}\n.bl{width:90px;text-align:right;color:var(--muted);flex-shrink:0}\n.bb{flex:1;height:14px;background:var(--card);border-radius:3px;overflow:hidden;border:1px solid var(--border)}\n.bf{height:100%;border-radius:2px}\n.bv{width:36px;font-weight:700;font-size:0.68rem}\n.stack{display:flex;gap:0.35rem;flex-wrap:wrap;margin-top:1rem}\n.stack span{background:var(--card);border:1px solid var(--border);padding:0.1rem 0.45rem;border-radius:9999px;font-size:0.62rem;color:var(--muted)}\n\n/* \u2500\u2500 Workspace / Repo structure \u2500\u2500 */\n.ws-info{display:flex;gap:0.6rem;align-items:center;flex-wrap:wrap;margin-bottom:0.5rem;font-size:0.72rem;color:var(--muted)}\n.ws-badge{background:var(--accent);color:#fff;padding:0.15rem 0.5rem;border-radius:4px;font-size:0.65rem;font-weight:700}\n.ws-pkgs{display:flex;flex-direction:column;gap:0.15rem}\n.ws-pkg{display:flex;gap:0.6rem;align-items:center;font-size:0.68rem;padding:0.15rem 0.4rem;background:var(--card);border-radius:4px}\n.ws-path{font-family:monospace;color:var(--text);min-width:140px}\n.ws-name{color:var(--muted);flex:1}\n.ws-flags{color:var(--muted);font-size:0.6rem}\n.ws-more{font-size:0.62rem;color:var(--muted);padding:0.2rem 0.4rem}\n\n/* \u2500\u2500 Category pages \u2500\u2500 */\n.cat-head{margin-bottom:0.3rem}\n.bar2{height:4px;background:var(--card);border-radius:2px;margin-bottom:1.5rem;overflow:hidden}\n.bf2{height:100%;border-radius:2px}\n.check-section{margin-bottom:2.5rem;padding-top:0.5rem;border-top:1px solid var(--border)}\n.check-section:first-of-type{border-top:none}\n\n/* \u2500\u2500 Check detail \u2500\u2500 */\n.ch-head{display:flex;align-items:center;gap:0.7rem;margin-bottom:0.8rem}\n.ch-g{font-size:2rem;font-weight:900}\n.ch-s{display:block;font-size:0.7rem;color:var(--muted)}\n.pri{font-size:0.62rem;font-weight:700;text-transform:uppercase;letter-spacing:0.04em;padding:0.15rem 0.5rem;border-radius:9999px;border:1px solid currentColor;flex-shrink:0}\n.info-panel{background:var(--card-alt);border:1px solid var(--border);border-radius:0.5rem;padding:0.7rem 0.9rem;margin-bottom:1rem;font-size:0.72rem;line-height:1.6}\n.ip-row{margin-bottom:0.4rem;display:flex;gap:0.5rem}\n.ip-row:last-child{margin-bottom:0}\n.ip-label{color:var(--accent);font-weight:700;min-width:2.5rem;flex-shrink:0}\n.skip-r{color:var(--muted);font-style:italic;font-size:0.78rem}\n.kvs{display:flex;gap:0.6rem;flex-wrap:wrap;margin-bottom:1rem}\n.kv{background:var(--card);border:1px solid var(--border);border-radius:0.4rem;padding:0.3rem 0.6rem;font-size:0.7rem}\n.k{color:var(--muted);margin-right:0.3rem}\n.v{font-weight:600}\n\n/* \u2500\u2500 Issue list grouped by file \u2500\u2500 */\n.iss-list{margin-top:1rem}\n.fg{margin-bottom:0.8rem}\n.fn{font-size:0.72rem;font-weight:600;font-family:\"SF Mono\",monospace;padding:0.3rem 0;border-bottom:1px solid var(--border);margin-bottom:0.2rem;display:flex;align-items:center;gap:0.5rem}\n.fc{background:var(--border);border-radius:9999px;padding:0 0.4rem;font-size:0.6rem;color:var(--muted)}\n.ir{font-size:0.65rem;font-family:\"SF Mono\",monospace;padding:0.12rem 0 0.12rem 0.5rem;display:flex;gap:0.4rem;align-items:baseline}\n.is{font-weight:800;font-size:0.55rem;width:0.9rem;text-align:center;border-radius:2px;flex-shrink:0}\n.ir.error .is{color:var(--fail);background:#ef444418}\n.ir.warning .is{color:var(--warn);background:#eab30818}\n.ir.info .is{color:var(--info);background:#6366f118}\n.il{color:var(--accent);min-width:2rem;flex-shrink:0}\n.im{flex:1;word-break:break-word}\n.iru{color:var(--dim);font-size:0.55rem}\n\n/* \u2500\u2500 All issues table \u2500\u2500 */\n.isf{color:var(--muted);font-size:0.75rem;margin-bottom:0.8rem}\n.it{width:100%;border-collapse:collapse;font-size:0.68rem}\n.it th{text-align:left;padding:0.35rem 0.4rem;color:var(--muted);font-size:0.62rem;text-transform:uppercase;border-bottom:1px solid var(--border)}\n.it td{padding:0.25rem 0.4rem;border-bottom:1px solid var(--border);font-family:\"SF Mono\",monospace;font-size:0.62rem}\n.it tr.error .is2{color:var(--fail)}\n.it tr.warning .is2{color:var(--warn)}\n.is2{font-weight:800;width:1rem}\n.ic2{color:var(--muted);width:70px}\n.il2{color:var(--muted)}\n.iru2{color:var(--dim);font-size:0.58rem}\n\n/* \u2500\u2500 File health \u2500\u2500 */\n.fr{display:flex;align-items:center;gap:0.5rem;margin-bottom:0.3rem;font-size:0.7rem}\n.ff{width:200px;font-family:\"SF Mono\",monospace;font-size:0.65rem;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.fb{flex:1;height:12px;background:var(--card);border-radius:3px;overflow:hidden;border:1px solid var(--border)}\n.fbf{height:100%;border-radius:2px}\n.fv{width:50px;font-size:0.65rem;color:var(--muted);flex-shrink:0}\n.hm-row{display:flex;align-items:center;gap:0.5rem;margin-bottom:0.2rem;font-size:0.7rem}\n.hm-name{width:200px;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:\"SF Mono\",monospace;font-size:0.65rem}\n.hm-bar{height:14px;border-radius:3px;min-width:4px}\n.hm-count{color:var(--muted);font-size:0.65rem;flex-shrink:0;min-width:50px}\n.hm-checks{font-size:0.58rem;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n\n/* \u2500\u2500 Premium cards \u2500\u2500 */\n.pro-card{background:linear-gradient(135deg,#0f0f1a 0%,#13131f 100%);border:1px solid #2a2a3d;border-radius:0.75rem;padding:1.5rem;position:relative;overflow:hidden}\n.pro-card::before{content:\"\";position:absolute;top:-50%;right:-50%;width:200%;height:200%;background:radial-gradient(circle,#6366f108 0%,transparent 70%);pointer-events:none}\n.pro-badge{display:inline-block;background:linear-gradient(135deg,#6366f1,#818cf8);color:#fff;font-size:0.6rem;font-weight:800;padding:0.15rem 0.5rem;border-radius:9999px;letter-spacing:0.06em;margin-bottom:0.6rem}\n.pro-desc{color:var(--muted);font-size:0.78rem;line-height:1.6;margin-bottom:0.8rem}\n.pro-cta{color:#6366f1;font-size:0.72rem;font-weight:600;margin-top:1rem}\n.sn-pro{opacity:0.7}\n\n/* \u2500\u2500 Trends page \u2500\u2500 */\n.trend-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:1rem;margin-top:0.5rem}\n.trend-card{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:0.8rem}\n.trend-header{display:flex;align-items:center;gap:0.5rem;margin-bottom:0.3rem}\n.trend-name{font-size:0.78rem;font-weight:700;flex:1}\n.trend-score{font-size:1.1rem;font-weight:900}\n.trend-chart{overflow:hidden}\n.trend-chart svg{width:100%;height:60px}\n.trend-table{margin-bottom:1.5rem}\n.trend-row{display:flex;align-items:center;gap:0.5rem;padding:0.25rem 0;border-bottom:1px solid var(--border);font-size:0.75rem}\n.trend-row-name{flex:1;font-weight:600}\n.trend-row-val{width:2rem;text-align:center;color:var(--muted)}\n.trend-row-arrow{color:var(--muted);font-size:0.6rem}\n.trend-row-delta{width:2.5rem;text-align:right;font-weight:700}\n\n.footer{text-align:center;color:var(--muted);font-size:0.58rem;margin-top:2rem;padding:0.8rem 0;border-top:1px solid var(--border)}\n.footer a{color:var(--muted)}\n.muted{color:var(--muted)}\n.deeper-tools code{background:var(--border);padding:0.1rem 0.4rem;border-radius:4px;font-size:0.62rem;color:var(--accent);margin-right:0.3rem}\n.flink{color:var(--accent);text-decoration:none;font-family:\"SF Mono\",monospace}.flink:hover{text-decoration:underline}\n.arch-svg{margin:1rem 0;overflow-x:auto;-webkit-overflow-scrolling:touch}\n.arch-svg svg{border-radius:8px}\n.cp-btn{background:none;border:none;cursor:pointer;font-size:0.6rem;opacity:0.3;padding:0 0.2rem;flex-shrink:0}.cp-btn:hover{opacity:1}\n.ir:hover .cp-btn{opacity:0.6}\n\n/* \u2500\u2500 Mobile: hamburger collapses both navs \u2500\u2500 */\n@media(max-width:768px){\n.hamburger{display:block}\n.nav-scroll{display:none}\n.nav-scroll.open{display:flex;position:absolute;top:var(--top-h);left:0;right:0;background:var(--bg);border-bottom:1px solid var(--border);flex-wrap:wrap;padding:0.3rem 0.5rem;z-index:25}\n.side{display:none}\n.side.open{display:block;z-index:25}\n.top{padding:0 0.8rem}\n.logo{font-size:0.85rem;margin-right:0.5rem}\n.content{margin-left:0;padding:0.8rem}\n.cats{grid-template-columns:1fr 1fr}\n.dash{flex-direction:column;gap:1rem}\n.hero svg{width:80px;height:80px}\n.hg{font-size:2rem}\n.radar svg{max-width:180px}\n.bl{width:60px;font-size:0.62rem}\n.bv{width:30px;font-size:0.6rem}\n.it{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch}\n.ff{width:120px;font-size:0.58rem}\n.hm-name{width:120px;font-size:0.58rem}\n.hm-checks{display:none}\n.ov-check{width:50px}\n.ov-loc{max-width:120px}\n.ir{font-size:0.6rem}\n.ch-head{flex-wrap:wrap}\n.ch-g{font-size:1.5rem}\n.info-panel{font-size:0.68rem;padding:0.5rem 0.6rem}\n.ip-row{flex-direction:column;gap:0.1rem}\n.kvs{gap:0.4rem}\n.kv{font-size:0.62rem;padding:0.2rem 0.4rem}\n.arch-svg svg{min-width:400px}\n}\n@media(max-width:480px){\n.cats{grid-template-columns:1fr}\n.tn{padding:0 0.4rem;font-size:0.65rem}\n.ff{width:90px}\n.hm-name{width:90px}\n.ov-check{display:none}\n}\n\n/* \u2500\u2500 Feature Map (Pro) \u2500\u2500 */\n.fm-header{margin-bottom:1.5rem}\n.fm-header h2{display:flex;align-items:center;gap:0.6rem}\n.fm-stats{display:flex;gap:1.5rem;margin-bottom:2rem;padding:1rem 1.2rem;background:var(--card);border:1px solid var(--border);border-radius:12px}\n.fm-stat{display:flex;flex-direction:column;align-items:center}\n.fm-stat-n{font-size:1.6rem;font-weight:900;line-height:1.2}\n.fm-stat-l{font-size:0.65rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.04em;font-weight:600}\n.fm-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:1rem}\n.fm-card{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:1.2rem;transition:border-color 0.15s}\n.fm-card:hover{border-color:#333}\n.fm-card-issue{border-color:#eab30830;background:linear-gradient(135deg,var(--card) 0%,#1a1a0f 100%)}\n.fm-card-top{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:0.4rem}\n.fm-card-label{font-weight:800;font-size:0.95rem}\n.fm-card-desc{font-size:0.72rem;color:var(--muted);margin-bottom:0.5rem;line-height:1.4}\n.fm-card-dir{font-size:0.65rem;color:var(--dim);font-family:\"SF Mono\",monospace;margin-bottom:0.6rem}\n.fm-card-badge{font-size:0.6rem;font-weight:700;padding:0.15rem 0.5rem;border-radius:9999px;white-space:nowrap}\n.fm-ok{background:#22c55e18;color:var(--pass)}\n.fm-warn{background:#eab30818;color:var(--warn)}\n.fm-info{background:#6366f118;color:var(--info)}\n.fm-card-files{display:flex;flex-direction:column;gap:0.15rem;margin-bottom:0.6rem}\n.fm-file{font-size:0.68rem;color:var(--muted);font-family:\"SF Mono\",monospace}\n.fm-file a{color:var(--accent);text-decoration:none}\n.fm-file a:hover{text-decoration:underline}\n.fm-more{color:var(--dim);font-style:italic}\n.fm-findings{margin-top:0.6rem;padding-top:0.6rem;border-top:1px solid var(--border);display:flex;flex-direction:column;gap:0.3rem}\n.fm-finding{display:flex;align-items:baseline;gap:0.4rem;font-size:0.68rem;line-height:1.4}\n.fm-f-sev{font-weight:800;font-size:0.6rem;width:1rem;flex-shrink:0}\n.fm-f-warn .fm-f-sev{color:var(--warn)}\n.fm-f-info .fm-f-sev{color:var(--info)}\n.fm-f-loc{color:var(--dim);font-family:\"SF Mono\",monospace;flex-shrink:0}\n.fm-f-loc a{color:var(--accent);text-decoration:none}\n.fm-f-msg{color:var(--text)}\n.fm-f-rule{color:var(--dim);font-size:0.6rem;font-family:\"SF Mono\",monospace}\n\n/* Teaser (no Pro key) */\n.fm-teaser{margin-top:1.5rem}\n.fm-teaser-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:1rem;margin-bottom:2rem}\n.fm-card-blur{filter:blur(3px);opacity:0.5;pointer-events:none;user-select:none}\n.fm-cta{text-align:center;padding:2rem;background:linear-gradient(135deg,#0f0f1a,#13131f);border:1px solid #2a2a3d;border-radius:12px}\n.fm-cta code{background:#1a1a2e;padding:0.2rem 0.5rem;border-radius:4px;font-size:0.8rem}\n@media(max-width:640px){\n.fm-grid,.fm-teaser-grid{grid-template-columns:1fr}\n.fm-stats{flex-wrap:wrap;gap:1rem}\n}\n\n/* \u2500\u2500 Preferences panel \u2500\u2500 */\n.prefs-btn{background:none;border:1px solid var(--border);color:var(--muted);font-size:0.72rem;cursor:pointer;padding:0.2rem 0.5rem;border-radius:6px;margin-left:auto;flex-shrink:0;font-family:inherit;line-height:1.4}\n.prefs-btn:hover{color:var(--text);border-color:var(--dim)}\n.prefs-panel{display:none;position:absolute;top:var(--top-h);right:1rem;background:var(--card);border:1px solid var(--border);border-radius:10px;padding:0.8rem 1rem;z-index:40;min-width:200px;box-shadow:0 8px 30px #0008}\n.prefs-panel.open{display:block}\n.prefs-label{font-size:0.6rem;text-transform:uppercase;letter-spacing:0.05em;color:var(--dim);font-weight:600;margin-bottom:0.3rem}\n.prefs-label:not(:first-child){margin-top:0.7rem}\n.prefs-row{display:flex;gap:0.3rem}\n.prefs-opt{background:var(--card-alt);border:1px solid var(--border);color:var(--muted);font-size:0.68rem;padding:0.25rem 0.6rem;border-radius:6px;cursor:pointer;font-family:inherit;transition:all 0.1s}\n.prefs-opt:hover{color:var(--text);border-color:var(--dim)}\n.prefs-opt.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n[data-theme=\"light\"] .prefs-panel{box-shadow:0 8px 30px #0002}\n";
|
|
2
|
+
export declare const CSS = "\n:root{--bg:#09090b;--card:#111115;--border:#1e1e24;--text:#e5e5e5;--muted:#6b7280;--pass:#22c55e;--fail:#ef4444;--warn:#eab308;--info:#6366f1;--accent:#818cf8;--side-w:200px;--top-h:42px;--nav-bg:#0c0c0fdd;--side-bg:#0c0c0f;--hover:#14141a;--dim:#555;--card-alt:#0d0d12}\n[data-theme=\"light\"]{--bg:#f5f5f7;--card:#ffffff;--border:#e2e4e9;--text:#1a1a2e;--muted:#64748b;--pass:#16a34a;--fail:#dc2626;--warn:#ca8a04;--info:#4f46e5;--accent:#4f46e5;--nav-bg:#ffffffee;--side-bg:#fafafa;--hover:#eef0f5;--dim:#94a3b8;--card-alt:#f0f0f5}\nhtml{font-size:17px}\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:\"Inter\",system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.5}\ncode{font-family:\"SF Mono\",Menlo,monospace;font-size:0.85em}\n\n/* \u2500\u2500 Top nav \u2500\u2500 */\n.top{position:sticky;top:0;z-index:30;background:var(--nav-bg);backdrop-filter:blur(12px);border-bottom:1px solid var(--border);padding:0 1.5rem;display:flex;align-items:center;height:var(--top-h)}\n.logo{font-weight:800;font-size:1rem;margin-right:0.5rem;flex-shrink:0;text-decoration:none;color:var(--text)}\n.logo span{color:var(--accent)}\n.nav-project{font-size:0.72rem;color:var(--muted);font-weight:600;margin-right:1rem;padding:0.2rem 0.5rem;background:var(--card);border:1px solid var(--border);border-radius:4px;flex-shrink:0}\n.nav-scroll{display:flex;align-items:center;gap:0;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;flex:1}\n.nav-scroll::-webkit-scrollbar{display:none}\n.tn{padding:0 0.7rem;font-size:0.78rem;color:var(--muted);text-decoration:none;border-bottom:2px solid transparent;transition:all 0.15s;white-space:nowrap;line-height:var(--top-h)}\n.tn:hover{color:var(--text)}\n.tn.active{color:var(--text);border-bottom-color:var(--accent)}\n.hamburger{display:none;background:none;border:none;color:var(--muted);font-size:1.3rem;cursor:pointer;padding:0 0.4rem;line-height:var(--top-h)}\n\n/* \u2500\u2500 Sidebar \u2500\u2500 */\n.side{position:fixed;top:var(--top-h);left:0;bottom:0;width:var(--side-w);background:var(--side-bg);border-right:1px solid var(--border);overflow-y:auto;padding:0.6rem 0;font-size:0.7rem;z-index:20}\n.side-section{padding:0.3rem 0;border-bottom:1px solid var(--border)}\n.side-section:last-child{border-bottom:none}\n.side-label{padding:0.2rem 0.8rem;font-size:0.6rem;text-transform:uppercase;letter-spacing:0.05em;color:var(--dim);font-weight:600}\n.side-score{font-size:1.4rem;font-weight:900;padding:0.2rem 0.8rem}\n.side-cat{display:block;padding:0.3rem 0.8rem;color:var(--muted);font-weight:600;cursor:pointer;text-decoration:none;font-size:0.72rem}\n.side-cat:hover{background:var(--hover);color:var(--text)}\n.side-cat-active{color:var(--text);font-weight:700;border-left:2px solid var(--accent);padding-left:calc(0.8rem - 2px)}\n.side-cat-title{padding:0.3rem 0.8rem;font-size:0.65rem;text-transform:uppercase;letter-spacing:0.04em;color:var(--accent);font-weight:700}\n.side-check{display:block;padding:0.15rem 0.8rem 0.15rem 0.8rem;color:var(--muted);cursor:pointer;text-decoration:none;font-size:0.65rem}\n.side-check:hover{color:var(--text);background:#14141a}\n.side-check span{display:inline-block;min-width:2.5rem;font-weight:700;font-size:0.6rem}\n.side-stat{padding:0.15rem 0.8rem;font-size:0.7rem;color:var(--muted)}\n.side-stat span{font-weight:800;font-size:0.8rem}\n.side-views{padding-top:0.3rem}\n.side-views .side-check{padding-left:0.8rem}\n\n/* \u2500\u2500 Content \u2500\u2500 */\n.content{margin-left:var(--side-w);padding:1.5rem 2rem;max-width:960px}\n\n/* \u2500\u2500 Overview \u2500\u2500 */\n.dash{display:flex;gap:2rem;margin-bottom:2rem;align-items:center;flex-wrap:wrap}\n.hero{display:flex;align-items:center;gap:1rem}\n.hero svg{width:100px;height:100px}\n.hc{display:flex;flex-direction:column}\n.hg{font-size:2.5rem;font-weight:900;line-height:1}\n.hs{font-size:1rem;font-weight:600}\n.hd{font-size:0.68rem;color:var(--muted)}\n.radar{flex:1;display:flex;justify-content:center}\n.radar svg{max-width:240px;width:100%}\n.cats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:0.6rem;margin-bottom:2rem}\n.cc{background:var(--card);border:1px solid var(--border);border-radius:0.6rem;padding:0.8rem;transition:border-color 0.15s;text-decoration:none;color:var(--text);display:block}\n.cc:hover{border-color:var(--accent)}\n.cc-s{font-size:1.8rem;font-weight:900}\n.cc-l{font-size:0.75rem;color:var(--muted)}\n.cc-m{margin-top:0.3rem;display:flex;gap:0.25rem}\n.mc{font-size:0.65rem;font-weight:800}\nh3{font-size:0.85rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.04em;margin-bottom:0.5rem}\n\n/* \u2500\u2500 Overview sections \u2500\u2500 */\n.ov-section{margin-bottom:1.5rem}\n.ov-issue{font-size:0.68rem;font-family:\"SF Mono\",monospace;padding:0.2rem 0;display:flex;gap:0.4rem;align-items:baseline;border-bottom:1px solid var(--border)}\n.ov-issue .is{flex-shrink:0}\n.ov-issue.error .is{color:var(--fail)}\n.ov-issue.warning .is{color:var(--warn)}\n.ov-check{color:var(--muted);width:70px;flex-shrink:0;font-size:0.62rem}\n.ov-loc{color:var(--accent);flex-shrink:0;font-size:0.62rem;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.ov-msg{flex:1;word-break:break-word}\n.ov-link{display:block;margin-top:0.5rem;font-size:0.72rem;color:var(--accent);text-decoration:none}\n.ov-link:hover{text-decoration:underline}\n\n/* \u2500\u2500 Timeline \u2500\u2500 */\n.timeline{margin:0.5rem 0;overflow-x:auto}\n.timeline svg{max-width:100%}\n\n/* \u2500\u2500 Bar chart \u2500\u2500 */\n.bars{margin-bottom:1.5rem}\n.brow{display:flex;align-items:center;gap:0.4rem;margin-bottom:0.25rem;font-size:0.72rem}\n.bl{width:90px;text-align:right;color:var(--muted);flex-shrink:0}\n.bb{flex:1;height:14px;background:var(--card);border-radius:3px;overflow:hidden;border:1px solid var(--border)}\n.bf{height:100%;border-radius:2px}\n.bv{width:36px;font-weight:700;font-size:0.68rem}\n.stack{display:flex;gap:0.35rem;flex-wrap:wrap;margin-top:1rem}\n.stack span{background:var(--card);border:1px solid var(--border);padding:0.1rem 0.45rem;border-radius:9999px;font-size:0.62rem;color:var(--muted)}\n\n/* \u2500\u2500 Workspace / Repo structure \u2500\u2500 */\n.ws-info{display:flex;gap:0.6rem;align-items:center;flex-wrap:wrap;margin-bottom:0.5rem;font-size:0.72rem;color:var(--muted)}\n.ws-badge{background:var(--accent);color:#fff;padding:0.15rem 0.5rem;border-radius:4px;font-size:0.65rem;font-weight:700}\n.ws-pkgs{display:flex;flex-direction:column;gap:0.15rem}\n.ws-pkg{display:flex;gap:0.6rem;align-items:center;font-size:0.68rem;padding:0.15rem 0.4rem;background:var(--card);border-radius:4px}\n.ws-path{font-family:monospace;color:var(--text);min-width:140px}\n.ws-name{color:var(--muted);flex:1}\n.ws-flags{color:var(--muted);font-size:0.6rem}\n.ws-more{font-size:0.62rem;color:var(--muted);padding:0.2rem 0.4rem}\n\n/* \u2500\u2500 Category pages \u2500\u2500 */\n.cat-head{margin-bottom:0.3rem}\n.bar2{height:4px;background:var(--card);border-radius:2px;margin-bottom:1.5rem;overflow:hidden}\n.bf2{height:100%;border-radius:2px}\n.check-section{margin-bottom:2.5rem;padding-top:0.5rem;border-top:1px solid var(--border)}\n.check-section:first-of-type{border-top:none}\n\n/* \u2500\u2500 Check detail \u2500\u2500 */\n.ch-head{display:flex;align-items:center;gap:0.7rem;margin-bottom:0.8rem}\n.ch-g{font-size:2rem;font-weight:900}\n.ch-s{display:block;font-size:0.7rem;color:var(--muted)}\n.pri{font-size:0.62rem;font-weight:700;text-transform:uppercase;letter-spacing:0.04em;padding:0.15rem 0.5rem;border-radius:9999px;border:1px solid currentColor;flex-shrink:0}\n.info-panel{background:var(--card-alt);border:1px solid var(--border);border-radius:0.5rem;padding:0.7rem 0.9rem;margin-bottom:1rem;font-size:0.72rem;line-height:1.6}\n.ip-row{margin-bottom:0.4rem;display:flex;gap:0.5rem}\n.ip-row:last-child{margin-bottom:0}\n.ip-label{color:var(--accent);font-weight:700;min-width:2.5rem;flex-shrink:0}\n.skip-r{color:var(--muted);font-style:italic;font-size:0.78rem}\n.kvs{display:flex;gap:0.6rem;flex-wrap:wrap;margin-bottom:1rem}\n.kv{background:var(--card);border:1px solid var(--border);border-radius:0.4rem;padding:0.3rem 0.6rem;font-size:0.7rem}\n.k{color:var(--muted);margin-right:0.3rem}\n.v{font-weight:600}\n\n/* \u2500\u2500 Issue list grouped by file \u2500\u2500 */\n.iss-list{margin-top:1rem}\n.fg{margin-bottom:0.8rem}\n.fn{font-size:0.72rem;font-weight:600;font-family:\"SF Mono\",monospace;padding:0.3rem 0;border-bottom:1px solid var(--border);margin-bottom:0.2rem;display:flex;align-items:center;gap:0.5rem}\n.fc{background:var(--border);border-radius:9999px;padding:0 0.4rem;font-size:0.6rem;color:var(--muted)}\n.ir{font-size:0.65rem;font-family:\"SF Mono\",monospace;padding:0.12rem 0 0.12rem 0.5rem;display:flex;gap:0.4rem;align-items:baseline}\n.is{font-weight:800;font-size:0.55rem;width:0.9rem;text-align:center;border-radius:2px;flex-shrink:0}\n.ir.error .is{color:var(--fail);background:#ef444418}\n.ir.warning .is{color:var(--warn);background:#eab30818}\n.ir.info .is{color:var(--info);background:#6366f118}\n.il{color:var(--accent);min-width:2rem;flex-shrink:0}\n.im{flex:1;word-break:break-word}\n.iru{color:var(--dim);font-size:0.55rem}\n\n/* \u2500\u2500 Source code snippets \u2500\u2500 */\n.src-block{background:var(--card-alt);border:1px solid var(--border);border-radius:6px;margin:0.3rem 0 0.5rem 0.5rem;padding:0.3rem 0;font-family:\"SF Mono\",Menlo,monospace;font-size:0.62rem;line-height:1.6;overflow-x:auto}\n.src-ln{padding:0 0.5rem;white-space:pre}\n.src-hl{padding:0 0.5rem;white-space:pre;background:#eab30815;border-left:2px solid var(--warn)}\n.src-num{color:var(--dim);margin-right:0.5rem;user-select:none;display:inline-block;min-width:2.5rem;text-align:right}\n.src-prompt{padding:0.3rem 0.5rem;border-top:1px solid var(--border);display:flex;justify-content:flex-end}\n.src-fix-btn{background:var(--card);border:1px solid var(--border);color:var(--accent);font-size:0.62rem;padding:0.2rem 0.6rem;border-radius:4px;cursor:pointer;font-family:inherit}\n.src-fix-btn:hover{background:var(--accent);color:#fff;border-color:var(--accent)}\n\n/* \u2500\u2500 All issues table \u2500\u2500 */\n.isf{color:var(--muted);font-size:0.75rem;margin-bottom:0.8rem}\n.it{width:100%;border-collapse:collapse;font-size:0.68rem}\n.it th{text-align:left;padding:0.35rem 0.4rem;color:var(--muted);font-size:0.62rem;text-transform:uppercase;border-bottom:1px solid var(--border)}\n.it td{padding:0.25rem 0.4rem;border-bottom:1px solid var(--border);font-family:\"SF Mono\",monospace;font-size:0.62rem}\n.it tr.error .is2{color:var(--fail)}\n.it tr.warning .is2{color:var(--warn)}\n.is2{font-weight:800;width:1rem}\n.ic2{color:var(--muted);width:70px}\n.il2{color:var(--muted)}\n.iru2{color:var(--dim);font-size:0.58rem}\n\n/* \u2500\u2500 File health \u2500\u2500 */\n.fr{display:flex;align-items:center;gap:0.5rem;margin-bottom:0.3rem;font-size:0.7rem}\n.ff{width:200px;font-family:\"SF Mono\",monospace;font-size:0.65rem;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.fb{flex:1;height:12px;background:var(--card);border-radius:3px;overflow:hidden;border:1px solid var(--border)}\n.fbf{height:100%;border-radius:2px}\n.fv{width:50px;font-size:0.65rem;color:var(--muted);flex-shrink:0}\n.hm-row{display:flex;align-items:center;gap:0.5rem;margin-bottom:0.2rem;font-size:0.7rem}\n.hm-name{width:200px;flex-shrink:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:\"SF Mono\",monospace;font-size:0.65rem}\n.hm-bar{height:14px;border-radius:3px;min-width:4px}\n.hm-count{color:var(--muted);font-size:0.65rem;flex-shrink:0;min-width:50px}\n.hm-checks{font-size:0.58rem;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n\n/* \u2500\u2500 Premium cards \u2500\u2500 */\n.pro-card{background:linear-gradient(135deg,#0f0f1a 0%,#13131f 100%);border:1px solid #2a2a3d;border-radius:0.75rem;padding:1.5rem;position:relative;overflow:hidden}\n.pro-card::before{content:\"\";position:absolute;top:-50%;right:-50%;width:200%;height:200%;background:radial-gradient(circle,#6366f108 0%,transparent 70%);pointer-events:none}\n.pro-badge{display:inline-block;background:linear-gradient(135deg,#6366f1,#818cf8);color:#fff;font-size:0.6rem;font-weight:800;padding:0.15rem 0.5rem;border-radius:9999px;letter-spacing:0.06em;margin-bottom:0.6rem}\n.pro-desc{color:var(--muted);font-size:0.78rem;line-height:1.6;margin-bottom:0.8rem}\n.pro-cta{color:#6366f1;font-size:0.72rem;font-weight:600;margin-top:1rem}\n.sn-pro{opacity:0.7}\n\n/* \u2500\u2500 Trends page \u2500\u2500 */\n.trend-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:1rem;margin-top:0.5rem}\n.trend-card{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:0.8rem}\n.trend-header{display:flex;align-items:center;gap:0.5rem;margin-bottom:0.3rem}\n.trend-name{font-size:0.78rem;font-weight:700;flex:1}\n.trend-score{font-size:1.1rem;font-weight:900}\n.trend-chart{overflow:hidden}\n.trend-chart svg{width:100%;height:60px}\n.trend-table{margin-bottom:1.5rem}\n.trend-row{display:flex;align-items:center;gap:0.5rem;padding:0.25rem 0;border-bottom:1px solid var(--border);font-size:0.75rem}\n.trend-row-name{flex:1;font-weight:600}\n.trend-row-val{width:2rem;text-align:center;color:var(--muted)}\n.trend-row-arrow{color:var(--muted);font-size:0.6rem}\n.trend-row-delta{width:2.5rem;text-align:right;font-weight:700}\n\n.footer{text-align:center;color:var(--muted);font-size:0.58rem;margin-top:2rem;padding:0.8rem 0;border-top:1px solid var(--border)}\n.footer a{color:var(--muted)}\n.muted{color:var(--muted)}\n.deeper-tools code{background:var(--border);padding:0.1rem 0.4rem;border-radius:4px;font-size:0.62rem;color:var(--accent);margin-right:0.3rem}\n.flink{color:var(--accent);text-decoration:none;font-family:\"SF Mono\",monospace}.flink:hover{text-decoration:underline}\n.arch-svg{margin:1rem 0;overflow-x:auto;-webkit-overflow-scrolling:touch}\n.arch-svg svg{border-radius:8px}\n.cp-btn{background:none;border:none;cursor:pointer;font-size:0.6rem;opacity:0.3;padding:0 0.2rem;flex-shrink:0}.cp-btn:hover{opacity:1}\n.ir:hover .cp-btn{opacity:0.6}\n\n/* \u2500\u2500 Mobile: hamburger collapses both navs \u2500\u2500 */\n@media(max-width:768px){\n.hamburger{display:block}\n.nav-scroll{display:none}\n.nav-scroll.open{display:flex;position:absolute;top:var(--top-h);left:0;right:0;background:var(--bg);border-bottom:1px solid var(--border);flex-wrap:wrap;padding:0.3rem 0.5rem;z-index:25}\n.side{display:none}\n.side.open{display:block;z-index:25}\n.top{padding:0 0.8rem}\n.logo{font-size:0.85rem;margin-right:0.5rem}\n.content{margin-left:0;padding:0.8rem}\n.cats{grid-template-columns:1fr 1fr}\n.dash{flex-direction:column;gap:1rem}\n.hero svg{width:80px;height:80px}\n.hg{font-size:2rem}\n.radar svg{max-width:180px}\n.bl{width:60px;font-size:0.62rem}\n.bv{width:30px;font-size:0.6rem}\n.it{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch}\n.ff{width:120px;font-size:0.58rem}\n.hm-name{width:120px;font-size:0.58rem}\n.hm-checks{display:none}\n.ov-check{width:50px}\n.ov-loc{max-width:120px}\n.ir{font-size:0.6rem}\n.ch-head{flex-wrap:wrap}\n.ch-g{font-size:1.5rem}\n.info-panel{font-size:0.68rem;padding:0.5rem 0.6rem}\n.ip-row{flex-direction:column;gap:0.1rem}\n.kvs{gap:0.4rem}\n.kv{font-size:0.62rem;padding:0.2rem 0.4rem}\n.arch-svg svg{min-width:400px}\n}\n@media(max-width:480px){\n.cats{grid-template-columns:1fr}\n.tn{padding:0 0.4rem;font-size:0.65rem}\n.ff{width:90px}\n.hm-name{width:90px}\n.ov-check{display:none}\n}\n\n/* \u2500\u2500 Feature Map (Pro) \u2500\u2500 */\n.fm-header{margin-bottom:1.5rem}\n.fm-header h2{display:flex;align-items:center;gap:0.6rem}\n.fm-stats{display:flex;gap:1.5rem;margin-bottom:2rem;padding:1rem 1.2rem;background:var(--card);border:1px solid var(--border);border-radius:12px}\n.fm-stat{display:flex;flex-direction:column;align-items:center}\n.fm-stat-n{font-size:1.6rem;font-weight:900;line-height:1.2}\n.fm-stat-l{font-size:0.65rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.04em;font-weight:600}\n.fm-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:1rem}\n.fm-card{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:1.2rem;transition:border-color 0.15s}\n.fm-card:hover{border-color:#333}\n.fm-card-issue{border-color:#eab30830;background:linear-gradient(135deg,var(--card) 0%,#1a1a0f 100%)}\n.fm-card-top{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:0.4rem}\n.fm-card-label{font-weight:800;font-size:0.95rem}\n.fm-card-desc{font-size:0.72rem;color:var(--muted);margin-bottom:0.5rem;line-height:1.4}\n.fm-card-dir{font-size:0.65rem;color:var(--dim);font-family:\"SF Mono\",monospace;margin-bottom:0.6rem}\n.fm-card-badge{font-size:0.6rem;font-weight:700;padding:0.15rem 0.5rem;border-radius:9999px;white-space:nowrap}\n.fm-ok{background:#22c55e18;color:var(--pass)}\n.fm-warn{background:#eab30818;color:var(--warn)}\n.fm-info{background:#6366f118;color:var(--info)}\n.fm-card-files{display:flex;flex-direction:column;gap:0.15rem;margin-bottom:0.6rem}\n.fm-file{font-size:0.68rem;color:var(--muted);font-family:\"SF Mono\",monospace}\n.fm-file a{color:var(--accent);text-decoration:none}\n.fm-file a:hover{text-decoration:underline}\n.fm-more{color:var(--dim);font-style:italic}\n.fm-findings{margin-top:0.6rem;padding-top:0.6rem;border-top:1px solid var(--border);display:flex;flex-direction:column;gap:0.3rem}\n.fm-finding{display:flex;align-items:baseline;gap:0.4rem;font-size:0.68rem;line-height:1.4}\n.fm-f-sev{font-weight:800;font-size:0.6rem;width:1rem;flex-shrink:0}\n.fm-f-warn .fm-f-sev{color:var(--warn)}\n.fm-f-info .fm-f-sev{color:var(--info)}\n.fm-f-loc{color:var(--dim);font-family:\"SF Mono\",monospace;flex-shrink:0}\n.fm-f-loc a{color:var(--accent);text-decoration:none}\n.fm-f-msg{color:var(--text)}\n.fm-f-rule{color:var(--dim);font-size:0.6rem;font-family:\"SF Mono\",monospace}\n\n/* Teaser (no Pro key) */\n.fm-teaser{margin-top:1.5rem}\n.fm-teaser-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:1rem;margin-bottom:2rem}\n.fm-card-blur{filter:blur(3px);opacity:0.5;pointer-events:none;user-select:none}\n.fm-cta{text-align:center;padding:2rem;background:linear-gradient(135deg,#0f0f1a,#13131f);border:1px solid #2a2a3d;border-radius:12px}\n.fm-cta code{background:#1a1a2e;padding:0.2rem 0.5rem;border-radius:4px;font-size:0.8rem}\n@media(max-width:640px){\n.fm-grid,.fm-teaser-grid{grid-template-columns:1fr}\n.fm-stats{flex-wrap:wrap;gap:1rem}\n}\n\n/* \u2500\u2500 Preferences panel \u2500\u2500 */\n.prefs-btn{background:none;border:1px solid var(--border);color:var(--muted);font-size:0.72rem;cursor:pointer;padding:0.2rem 0.5rem;border-radius:6px;margin-left:auto;flex-shrink:0;font-family:inherit;line-height:1.4}\n.prefs-btn:hover{color:var(--text);border-color:var(--dim)}\n.prefs-panel{display:none;position:absolute;top:var(--top-h);right:1rem;background:var(--card);border:1px solid var(--border);border-radius:10px;padding:0.8rem 1rem;z-index:40;min-width:200px;box-shadow:0 8px 30px #0008}\n.prefs-panel.open{display:block}\n.prefs-label{font-size:0.6rem;text-transform:uppercase;letter-spacing:0.05em;color:var(--dim);font-weight:600;margin-bottom:0.3rem}\n.prefs-label:not(:first-child){margin-top:0.7rem}\n.prefs-row{display:flex;gap:0.3rem}\n.prefs-opt{background:var(--card-alt);border:1px solid var(--border);color:var(--muted);font-size:0.68rem;padding:0.25rem 0.6rem;border-radius:6px;cursor:pointer;font-family:inherit;transition:all 0.1s}\n.prefs-opt:hover{color:var(--text);border-color:var(--dim)}\n.prefs-opt.active{background:var(--accent);color:#fff;border-color:var(--accent)}\n[data-theme=\"light\"] .prefs-panel{box-shadow:0 8px 30px #0002}\n";
|
package/dist/report/styles.js
CHANGED
|
@@ -131,6 +131,15 @@ h3{font-size:0.85rem;color:var(--muted);text-transform:uppercase;letter-spacing:
|
|
|
131
131
|
.im{flex:1;word-break:break-word}
|
|
132
132
|
.iru{color:var(--dim);font-size:0.55rem}
|
|
133
133
|
|
|
134
|
+
/* ── Source code snippets ── */
|
|
135
|
+
.src-block{background:var(--card-alt);border:1px solid var(--border);border-radius:6px;margin:0.3rem 0 0.5rem 0.5rem;padding:0.3rem 0;font-family:"SF Mono",Menlo,monospace;font-size:0.62rem;line-height:1.6;overflow-x:auto}
|
|
136
|
+
.src-ln{padding:0 0.5rem;white-space:pre}
|
|
137
|
+
.src-hl{padding:0 0.5rem;white-space:pre;background:#eab30815;border-left:2px solid var(--warn)}
|
|
138
|
+
.src-num{color:var(--dim);margin-right:0.5rem;user-select:none;display:inline-block;min-width:2.5rem;text-align:right}
|
|
139
|
+
.src-prompt{padding:0.3rem 0.5rem;border-top:1px solid var(--border);display:flex;justify-content:flex-end}
|
|
140
|
+
.src-fix-btn{background:var(--card);border:1px solid var(--border);color:var(--accent);font-size:0.62rem;padding:0.2rem 0.6rem;border-radius:4px;cursor:pointer;font-family:inherit}
|
|
141
|
+
.src-fix-btn:hover{background:var(--accent);color:#fff;border-color:var(--accent)}
|
|
142
|
+
|
|
134
143
|
/* ── All issues table ── */
|
|
135
144
|
.isf{color:var(--muted);font-size:0.75rem;margin-bottom:0.8rem}
|
|
136
145
|
.it{width:100%;border-collapse:collapse;font-size:0.68rem}
|