@doquflow/cli 1.2.0 → 1.3.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.
@@ -0,0 +1,331 @@
1
+ "use strict";
2
+ /**
3
+ * docuflow review
4
+ *
5
+ * Review git changes and surface deterministic findings plus actionable
6
+ * improvements. Optional --ai mode appends Copilot analysis.
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getChangedFiles = getChangedFiles;
13
+ exports.getDiffText = getDiffText;
14
+ exports.buildDeterministicReview = buildDeterministicReview;
15
+ exports.runCopilotReview = runCopilotReview;
16
+ exports.run = run;
17
+ const node_path_1 = __importDefault(require("node:path"));
18
+ const node_child_process_1 = require("node:child_process");
19
+ const DIFF_CAP_BYTES = 200 * 1024;
20
+ const AI_DIFF_CAP_CHARS = 40_000;
21
+ const c = {
22
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
23
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
24
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
25
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
26
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
27
+ dim: (s) => `\x1b[2m${s}\x1b[0m`,
28
+ };
29
+ function runGit(projectPath, args) {
30
+ const result = (0, node_child_process_1.spawnSync)("git", args, { cwd: projectPath, encoding: "utf8" });
31
+ if (result.status !== 0) {
32
+ const stderr = (result.stderr ?? "").trim();
33
+ const badRef = /bad revision|unknown revision|ambiguous argument/i.test(stderr);
34
+ if (badRef) {
35
+ throw new Error(`Invalid git ref: ${args.join(" ")}`);
36
+ }
37
+ throw new Error(stderr || `git ${args.join(" ")} failed`);
38
+ }
39
+ return (result.stdout ?? "").trim();
40
+ }
41
+ function runGitAllowStatuses(projectPath, args, allowedStatuses) {
42
+ const result = (0, node_child_process_1.spawnSync)("git", args, { cwd: projectPath, encoding: "utf8" });
43
+ if (result.status === null || !allowedStatuses.includes(result.status)) {
44
+ const stderr = (result.stderr ?? "").trim();
45
+ const badRef = /bad revision|unknown revision|ambiguous argument/i.test(stderr);
46
+ if (badRef) {
47
+ throw new Error(`Invalid git ref: ${args.join(" ")}`);
48
+ }
49
+ throw new Error(stderr || `git ${args.join(" ")} failed`);
50
+ }
51
+ return (result.stdout ?? "").trim();
52
+ }
53
+ function ensureGitRepo(projectPath) {
54
+ try {
55
+ const out = runGit(projectPath, ["rev-parse", "--is-inside-work-tree"]);
56
+ if (out !== "true") {
57
+ throw new Error("not a git repository");
58
+ }
59
+ }
60
+ catch {
61
+ throw new Error(`No git repository detected at ${projectPath}`);
62
+ }
63
+ }
64
+ function parsePorcelainPaths(porcelain) {
65
+ const out = new Set();
66
+ for (const line of porcelain.split("\n")) {
67
+ const trimmed = line.trim();
68
+ if (!trimmed)
69
+ continue;
70
+ const payload = line.replace(/^[ MARCUD?!]{1,2}\s+/, "").trim();
71
+ if (!payload)
72
+ continue;
73
+ if (payload.includes(" -> ")) {
74
+ const parts = payload.split(" -> ");
75
+ out.add(parts[parts.length - 1].trim());
76
+ }
77
+ else {
78
+ out.add(payload);
79
+ }
80
+ }
81
+ return Array.from(out).sort((a, b) => a.localeCompare(b));
82
+ }
83
+ function capDiff(diffText) {
84
+ const bytes = Buffer.byteLength(diffText, "utf8");
85
+ if (bytes <= DIFF_CAP_BYTES)
86
+ return diffText;
87
+ const truncated = Buffer.from(diffText, "utf8").subarray(0, DIFF_CAP_BYTES).toString("utf8");
88
+ return `${truncated}\n\n[DOCUFLOW_DIFF_TRUNCATED: analyzed first ${DIFF_CAP_BYTES} bytes of ${bytes} bytes]\n`;
89
+ }
90
+ function pushUnique(arr, item) {
91
+ if (!arr.includes(item))
92
+ arr.push(item);
93
+ }
94
+ function getChangedFiles(projectPath, staged, sinceCommit) {
95
+ if (sinceCommit) {
96
+ const output = runGit(projectPath, ["diff", "--name-only", sinceCommit, "HEAD"]);
97
+ return output ? output.split("\n").filter(Boolean) : [];
98
+ }
99
+ if (staged) {
100
+ const output = runGit(projectPath, ["diff", "--name-only", "--cached"]);
101
+ return output ? output.split("\n").filter(Boolean) : [];
102
+ }
103
+ return parsePorcelainPaths(runGit(projectPath, ["status", "--porcelain"]));
104
+ }
105
+ function getDiffText(projectPath, staged, sinceCommit) {
106
+ if (sinceCommit) {
107
+ return capDiff(runGit(projectPath, ["diff", sinceCommit, "HEAD"]));
108
+ }
109
+ if (staged) {
110
+ return capDiff(runGit(projectPath, ["diff", "--cached"]));
111
+ }
112
+ const untracked = runGit(projectPath, ["ls-files", "--others", "--exclude-standard"])
113
+ .split("\n")
114
+ .map(line => line.trim())
115
+ .filter(Boolean);
116
+ const untrackedPatches = [];
117
+ for (const file of untracked) {
118
+ const patch = runGitAllowStatuses(projectPath, ["diff", "--no-index", "--", "/dev/null", file], [0, 1]);
119
+ if (patch) {
120
+ untrackedPatches.push(patch);
121
+ }
122
+ }
123
+ const stagedDiff = runGit(projectPath, ["diff", "--cached"]);
124
+ const workingDiff = runGit(projectPath, ["diff"]);
125
+ const joined = [
126
+ "=== STAGED DIFF ===",
127
+ stagedDiff,
128
+ "",
129
+ "=== WORKING TREE DIFF ===",
130
+ workingDiff,
131
+ "",
132
+ "=== UNTRACKED FILE DIFF ===",
133
+ untrackedPatches.join("\n"),
134
+ ].join("\n");
135
+ return capDiff(joined);
136
+ }
137
+ function buildDeterministicReview(changedFiles, diffText) {
138
+ const summary = [];
139
+ const critical = [];
140
+ const warnings = [];
141
+ const improvements = [];
142
+ summary.push(`Changed files: ${changedFiles.length}`);
143
+ for (const f of changedFiles.slice(0, 10)) {
144
+ summary.push(f);
145
+ }
146
+ if (changedFiles.length > 10) {
147
+ summary.push(`...and ${changedFiles.length - 10} more`);
148
+ }
149
+ const truncated = diffText.includes("[DOCUFLOW_DIFF_TRUNCATED:");
150
+ if (truncated) {
151
+ warnings.push("Large diff detected; review is partial due to diff size cap.");
152
+ improvements.push("Run focused reviews per file or per commit range for full coverage.");
153
+ }
154
+ const addedLines = diffText
155
+ .split("\n")
156
+ .filter(line => line.startsWith("+") && !line.startsWith("+++"))
157
+ .map(line => line.slice(1));
158
+ if (changedFiles.length > 0 && addedLines.length === 0) {
159
+ summary.push("Textual diff is empty (likely binary/rename-only changes).");
160
+ improvements.push("Manually review binary assets and metadata changes before commit.");
161
+ return { summary, critical, warnings, improvements };
162
+ }
163
+ const addedText = addedLines.join("\n");
164
+ if (/(AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{30,}|sk-[A-Za-z0-9]{20,}|-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----)/.test(addedText)) {
165
+ critical.push("Potential secret/key material detected in added lines.");
166
+ improvements.push("Remove credentials from code and load secrets via environment variables.");
167
+ }
168
+ if (/(password|token|secret)\s*[:=]\s*["'][^"']{4,}["']/i.test(addedText)) {
169
+ critical.push("Hardcoded credential-like value detected.");
170
+ }
171
+ if (/\b(eval|new Function)\s*\(/.test(addedText)) {
172
+ critical.push("Dynamic code execution (`eval`/`new Function`) detected.");
173
+ improvements.push("Replace dynamic execution with explicit parsing or whitelisted dispatch.");
174
+ }
175
+ if (/\bchild_process\.(exec|execSync)\s*\(/.test(addedText)) {
176
+ warnings.push("Shell execution added via child_process.exec/execSync.");
177
+ improvements.push("Prefer spawn/spawnSync with argument arrays and explicit input validation.");
178
+ }
179
+ if (/\bTODO\b|\bFIXME\b|\bHACK\b/.test(addedText)) {
180
+ warnings.push("TODO/FIXME/HACK markers found in added code.");
181
+ improvements.push("Resolve or ticket these markers before merge to avoid hidden follow-up work.");
182
+ }
183
+ if (/console\.log\s*\(/.test(addedText)) {
184
+ warnings.push("console.log statements found in added lines.");
185
+ improvements.push("Use structured logger patterns or remove debug logging before merge.");
186
+ }
187
+ if (/\bas any\b|:\s*any\b/.test(addedText)) {
188
+ warnings.push("Type safety weakened with `any` usage.");
189
+ improvements.push("Tighten types with explicit interfaces or narrow unions.");
190
+ }
191
+ if (/@ts-ignore/.test(addedText)) {
192
+ warnings.push("@ts-ignore found in added lines.");
193
+ improvements.push("Replace @ts-ignore with proper typing or guarded runtime checks.");
194
+ }
195
+ if (/catch\s*(\([^)]*\))?\s*\{\s*\}/.test(addedText)) {
196
+ warnings.push("Empty catch block detected.");
197
+ improvements.push("Handle caught errors explicitly and emit actionable context.");
198
+ }
199
+ const longLines = addedLines.filter(line => line.length > 160).length;
200
+ if (longLines > 0) {
201
+ warnings.push(`${longLines} long added line(s) (>160 chars) may hurt readability.`);
202
+ }
203
+ const hasTestFile = changedFiles.some(f => /(^|\/)(test|tests|__tests__)\/|\.test\.[a-z]+$|\.spec\.[a-z]+$/i.test(f));
204
+ if (!hasTestFile) {
205
+ improvements.push("Consider adding or updating tests for changed behavior.");
206
+ }
207
+ if (critical.length === 0 && warnings.length === 0) {
208
+ summary.push("No deterministic critical/warning findings detected.");
209
+ improvements.push("Quick manual pass for architecture consistency and naming is still recommended.");
210
+ }
211
+ return { summary, critical, warnings, improvements };
212
+ }
213
+ function buildCopilotPrompt(projectPath, changedFiles, diffText) {
214
+ const diffForPrompt = diffText.slice(0, AI_DIFF_CAP_CHARS);
215
+ return [
216
+ `Review these git changes for project: ${projectPath}`,
217
+ ``,
218
+ `Changed files:`,
219
+ changedFiles.slice(0, 40).map(f => `- ${f}`).join("\n") || "(none)",
220
+ ``,
221
+ `Diff:`,
222
+ diffForPrompt || "(no textual diff)",
223
+ ``,
224
+ `Return concise markdown with sections:`,
225
+ `1) Critical issues`,
226
+ `2) Warnings`,
227
+ `3) Concrete improvements`,
228
+ `Focus on correctness, security, and maintainability.`,
229
+ ].join("\n");
230
+ }
231
+ function runCopilotReview(prompt) {
232
+ const result = (0, node_child_process_1.spawnSync)("copilot", [
233
+ "--prompt", prompt,
234
+ "--allow-all-tools",
235
+ "--allow-all-paths",
236
+ "--no-ask-user",
237
+ "--output-format", "json"
238
+ ], { encoding: "utf8", timeout: 180_000 });
239
+ if (result.error || result.status !== 0)
240
+ return null;
241
+ let lastMessage = null;
242
+ for (const line of (result.stdout ?? "").split("\n")) {
243
+ const trimmed = line.trim();
244
+ if (!trimmed)
245
+ continue;
246
+ try {
247
+ const obj = JSON.parse(trimmed);
248
+ if (obj.type === "assistant.message" && obj.data?.content) {
249
+ lastMessage = obj.data.content;
250
+ }
251
+ }
252
+ catch {
253
+ // ignore malformed json lines
254
+ }
255
+ }
256
+ return lastMessage;
257
+ }
258
+ function printSection(title, lines, quiet) {
259
+ const label = quiet ? title : c.bold(title);
260
+ console.log(`\n${label}`);
261
+ if (lines.length === 0) {
262
+ console.log(" - none");
263
+ return;
264
+ }
265
+ for (const line of lines) {
266
+ console.log(` - ${line}`);
267
+ }
268
+ }
269
+ async function run(options = {}) {
270
+ const projectPath = node_path_1.default.resolve(options.projectPath ?? process.cwd());
271
+ const staged = !!options.staged;
272
+ const sinceCommit = options.sinceCommit;
273
+ const quiet = !!options.quiet;
274
+ const failOnCritical = !!options.failOnCritical;
275
+ const ai = !!options.ai;
276
+ try {
277
+ ensureGitRepo(projectPath);
278
+ }
279
+ catch (error) {
280
+ console.error(c.red(`✗ ${error.message}`));
281
+ process.exit(2);
282
+ }
283
+ let changedFiles = [];
284
+ let diffText = "";
285
+ try {
286
+ changedFiles = getChangedFiles(projectPath, staged, sinceCommit);
287
+ diffText = getDiffText(projectPath, staged, sinceCommit);
288
+ }
289
+ catch (error) {
290
+ const message = error.message;
291
+ if (message.startsWith("Invalid git ref:")) {
292
+ console.error(c.red(`✗ Invalid --since-commit ref: ${sinceCommit}`));
293
+ process.exit(2);
294
+ }
295
+ console.error(c.red(`✗ ${message}`));
296
+ process.exit(2);
297
+ }
298
+ if (changedFiles.length === 0) {
299
+ console.log(quiet ? "nothing to review" : c.cyan("Nothing to review: no changed files in selected scope."));
300
+ return;
301
+ }
302
+ const modeLabel = sinceCommit
303
+ ? `since ${sinceCommit}`
304
+ : staged
305
+ ? "staged changes"
306
+ : "working tree (staged + unstaged)";
307
+ if (!quiet) {
308
+ console.log(c.bold("\n🔍 DocuFlow Review\n"));
309
+ console.log(`Scope: ${c.cyan(modeLabel)}`);
310
+ }
311
+ const deterministic = buildDeterministicReview(changedFiles, diffText);
312
+ printSection("Summary", deterministic.summary, quiet);
313
+ printSection("Critical", deterministic.critical, quiet);
314
+ printSection("Warnings", deterministic.warnings, quiet);
315
+ printSection("Improvements", deterministic.improvements, quiet);
316
+ if (ai) {
317
+ const prompt = buildCopilotPrompt(projectPath, changedFiles, diffText);
318
+ const aiResult = runCopilotReview(prompt);
319
+ if (aiResult) {
320
+ const aiLabel = quiet ? "AI Review (Copilot)" : c.bold("\nAI Review (Copilot)");
321
+ console.log(`\n${aiLabel}`);
322
+ console.log(aiResult);
323
+ }
324
+ else {
325
+ deterministic.improvements.push("Copilot AI review unavailable; using deterministic review only");
326
+ }
327
+ }
328
+ if (failOnCritical && deterministic.critical.length > 0) {
329
+ process.exit(1);
330
+ }
331
+ }
@@ -16,6 +16,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.run = run;
18
18
  const node_child_process_1 = require("node:child_process");
19
+ const node_http_1 = __importDefault(require("node:http"));
19
20
  const node_path_1 = __importDefault(require("node:path"));
20
21
  const node_os_1 = __importDefault(require("node:os"));
21
22
  const node_fs_1 = __importDefault(require("node:fs"));
@@ -152,6 +153,27 @@ function openBrowser(url) {
152
153
  console.log(` (Could not auto-open browser — visit ${url} manually)`);
153
154
  });
154
155
  }
156
+ // ── Public API ────────────────────────────────────────────────────────────────
157
+ // ── Port conflict helper ──────────────────────────────────────────────────────
158
+ // Returns true if a DocuFlow server is already answering on this port.
159
+ function pingDocuflow(port) {
160
+ return new Promise(resolve => {
161
+ const req = node_http_1.default.get({ hostname: 'localhost', port, path: '/api/ping', timeout: 1500 }, (res) => {
162
+ let body = '';
163
+ res.on('data', (chunk) => { body += chunk; });
164
+ res.on('end', () => {
165
+ try {
166
+ resolve(JSON.parse(body).ok === true);
167
+ }
168
+ catch {
169
+ resolve(false);
170
+ }
171
+ });
172
+ });
173
+ req.on('error', () => resolve(false));
174
+ req.on('timeout', () => { req.destroy(); resolve(false); });
175
+ });
176
+ }
155
177
  async function run(opts = {}) {
156
178
  const port = opts.port ?? (process.env.DOCUFLOW_PORT ? parseInt(process.env.DOCUFLOW_PORT, 10) : 48821);
157
179
  // ── 1. Locate bundled UI ────────────────────────────────────────────────
@@ -349,14 +371,29 @@ async function run(opts = {}) {
349
371
  });
350
372
  server.on('error', (err) => {
351
373
  if (err.code === 'EADDRINUSE') {
352
- console.error(`\n ❌ Port ${port} is already in use.`);
353
- console.error(` Stop the other process or set DOCUFLOW_PORT=<port> to use a different port.`);
354
- console.error(` Note: the built UI targets port 48821 — custom ports require a UI rebuild.\n`);
374
+ // Check if it's already our own server before erroring
375
+ pingDocuflow(port).then(isDocuflow => {
376
+ if (isDocuflow) {
377
+ const url = `http://localhost:${port}`;
378
+ console.log('');
379
+ console.log(' ✅ DocuFlow is already running — reusing existing server.');
380
+ console.log(` 🌐 ${url}`);
381
+ console.log('');
382
+ if (!opts.noOpen)
383
+ openBrowser(url);
384
+ process.exit(0);
385
+ }
386
+ // Different process owns the port
387
+ console.error(`\n ❌ Port ${port} is already in use by another process.`);
388
+ console.error(` Find and stop it: lsof -ti:${port} | xargs kill`);
389
+ console.error(` Or try: DOCUFLOW_PORT=48822 docuflow ui\n`);
390
+ process.exit(1);
391
+ });
355
392
  }
356
393
  else {
357
394
  console.error(`\n ❌ Server error: ${err.message}\n`);
395
+ process.exit(1);
358
396
  }
359
- process.exit(1);
360
397
  });
361
398
  // Graceful shutdown
362
399
  const shutdown = (signal) => {
package/dist/index.js CHANGED
@@ -113,6 +113,16 @@ else if (cmd === 'sync') {
113
113
  quiet: hasFlag('--quiet', '-q'),
114
114
  allowDangerousPermissions: hasFlag('--allow-dangerous-permissions'),
115
115
  }));
116
+ // ── review — git change review & improvement suggestions ───────────────────────
117
+ }
118
+ else if (cmd === 'review') {
119
+ Promise.resolve().then(() => __importStar(require('./commands/review'))).then(m => m.run({
120
+ staged: hasFlag('--staged'),
121
+ sinceCommit: getFlagValue('--since-commit'),
122
+ ai: hasFlag('--ai'),
123
+ failOnCritical: hasFlag('--fail-on-critical'),
124
+ quiet: hasFlag('--quiet', '-q'),
125
+ }));
116
126
  }
117
127
  else {
118
128
  console.log(`DocuFlow v${version}`);
@@ -148,6 +158,12 @@ else {
148
158
  console.log(' sync --no-lint Skip health check (faster)');
149
159
  console.log(' sync --fail-on-score N Exit 1 if health score < N (default: 70)');
150
160
  console.log(' sync --quiet Suppress output (CI mode)');
161
+ console.log(' review Review current git changes and suggest improvements');
162
+ console.log(' review --staged Review staged changes only');
163
+ console.log(' review --since-commit REF Review changes since git ref (e.g. HEAD~1)');
164
+ console.log(' review --ai Append Copilot AI review to deterministic findings');
165
+ console.log(' review --fail-on-critical Exit 1 if critical findings are detected');
166
+ console.log(' review --quiet Compact output for CI/scripting');
151
167
  console.log('');
152
168
  console.log('Options:');
153
169
  console.log(' --version, -v Print version number');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doquflow/cli",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "CLI for setting up Docuflow in your project",
5
5
  "author": "Docuflow <hello@doquflows.dev>",
6
6
  "license": "MIT",
@@ -31,7 +31,7 @@
31
31
  "build": "tsc && node -e \"const fs=require('fs'),p=require('path'),src=p.join(process.cwd(),'../ui/dist'),dst=p.join(process.cwd(),'ui-dist');if(!fs.existsSync(src)){console.log('Warning: packages/ui/dist not found — run npm run build:ui first');process.exit(0)}fs.mkdirSync(dst,{recursive:true});fs.cpSync(src,dst,{recursive:true,force:true});console.log(' ✓ ui-dist synced from packages/ui/dist ('+(fs.readdirSync(dst).length)+' files at root)')\""
32
32
  },
33
33
  "dependencies": {
34
- "@doquflow/server": "1.2.0",
34
+ "@doquflow/server": "1.3.0",
35
35
  "cors": "^2.8.5",
36
36
  "express": "^4.19.2"
37
37
  },
@@ -0,0 +1 @@
1
+ :root{--df-bg: #0a0a0b;--df-surface: #111113;--df-surface-2: #161619;--df-surface-3: #1d1d22;--df-border: #1a1a1f;--df-border-2: #26262c;--df-border-3: #2c2c33;--df-border-hi: #3a3a44;--df-text: #ededee;--df-text-2: #d4d4d8;--df-text-3: #a1a1aa;--df-text-4: #6b6b74;--df-accent: #6366f1;--df-accent-hover: #5558e3;--df-accent-2: #818cf8;--df-accent-text: #a5b4fc;--df-accent-soft: rgba(99,102,241,.14);--df-accent-glow: rgba(99,102,241,.18);--df-accent-ring: rgba(99,102,241,.4);--df-accent-halo: rgba(99,102,241,.08);--df-green: #10b981;--df-green-text: #34d399;--df-green-soft: rgba(16,185,129,.12);--df-green-ring: rgba(16,185,129,.3);--df-amber: #f59e0b;--df-amber-text: #fbbf24;--df-amber-soft: rgba(245,158,11,.12);--df-amber-ring: rgba(245,158,11,.3);--df-red: #ef4444;--df-red-text: #f87171;--df-red-soft: rgba(239,68,68,.12);--df-red-ring: rgba(239,68,68,.3);--df-pink: #ec4899;--df-pink-text: #f472b6;--df-pink-soft: rgba(236,72,153,.12);--df-pink-ring: rgba(236,72,153,.3);--df-font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;--df-font-serif: "Source Serif 4", "Iowan Old Style", Georgia, serif;--df-font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;--df-r-sm: 4px;--df-r-md: 6px;--df-r-lg: 8px;--df-r-xl: 10px;--df-r-pill: 999px;--df-h-btn: 28px;--df-h-input: 30px;--df-h-bar: 44px;--df-w-rail: 60px;--df-w-rail-detail: 280px;--df-w-tree: 260px;--df-ease: cubic-bezier(.2,.7,.3,1);--df-fast: .12s;--df-base: .2s;--df-slow: .35s;--df-content-max: 720px;--df-content-pad: 56px}*,*:before,*:after{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{background:var(--df-bg);color:var(--df-text);font-family:var(--df-font-sans);font-feature-settings:"cv11","ss01";font-size:13px;line-height:1.5;letter-spacing:-.005em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}button{font-family:inherit}.df-mono{font-family:var(--df-font-mono);font-feature-settings:"cv01","cv02"}.df-serif{font-family:var(--df-font-serif)}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background:var(--df-border-2);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--df-border-3)}::-webkit-scrollbar-track{background:transparent}::selection{background:var(--df-accent-soft);color:var(--df-text)}.df-app{width:100vw;height:100vh;display:flex;flex-direction:column;overflow:hidden}.df-app__main{flex:1;display:flex;overflow:hidden;min-height:0}.df-view{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0;background:var(--df-bg)}@keyframes df-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes df-spin{to{transform:rotate(360deg)}}@keyframes df-pulse{0%,to{opacity:.4}50%{opacity:1}}@keyframes df-blink{0%,49%{opacity:1}50%,to{opacity:0}}@keyframes df-shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}@keyframes df-bar-grow{0%{transform:scaleY(0)}to{transform:scaleY(1)}}@keyframes df-page-enter{0%{opacity:0;transform:translate(8px)}to{opacity:1;transform:translate(0)}}.df-anim-fade{animation:df-fade-in var(--df-base) var(--df-ease) both}.df-anim-page{animation:df-page-enter var(--df-slow) var(--df-ease) both}.df-pill{display:inline-flex;align-items:center;gap:5px;padding:2px 7px;border-radius:var(--df-r-sm);font-size:11px;font-weight:500;font-family:var(--df-font-sans);background:var(--df-surface-3);border:1px solid var(--df-border-3);color:var(--df-text-3);white-space:nowrap}.df-pill--accent{background:var(--df-accent-soft);border-color:var(--df-accent-ring);color:var(--df-accent-text)}.df-pill--green{background:var(--df-green-soft);border-color:var(--df-green-ring);color:var(--df-green-text)}.df-pill--amber{background:var(--df-amber-soft);border-color:var(--df-amber-ring);color:var(--df-amber-text)}.df-pill--red{background:var(--df-red-soft);border-color:var(--df-red-ring);color:var(--df-red-text)}.df-pill--pink{background:var(--df-pink-soft);border-color:var(--df-pink-ring);color:var(--df-pink-text)}.df-pill__dot{width:5px;height:5px;border-radius:50%;background:currentColor}.df-btn{display:inline-flex;align-items:center;gap:6px;height:var(--df-h-btn);padding:0 10px;border-radius:var(--df-r-md);background:var(--df-surface-3);border:1px solid var(--df-border-3);color:var(--df-text);font-size:12px;font-weight:500;letter-spacing:-.005em;cursor:pointer;transition:background var(--df-fast),border-color var(--df-fast),color var(--df-fast);white-space:nowrap}.df-btn:hover{background:var(--df-surface-2)}.df-btn--primary{background:var(--df-accent);border-color:var(--df-accent);color:#fff}.df-btn--primary:hover{background:var(--df-accent-hover);border-color:var(--df-accent-hover)}.df-btn--ghost{background:transparent;border-color:transparent;color:var(--df-text-3)}.df-btn--ghost:hover{background:var(--df-surface-3);color:var(--df-text)}.df-btn--active{background:var(--df-surface-2);border-color:var(--df-border-hi)}.df-kbd{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;border-radius:var(--df-r-sm);background:var(--df-surface-3);border:1px solid var(--df-border-3);color:var(--df-text-3);font:11px/1 var(--df-font-mono)}.df-btn--primary .df-kbd{background:#ffffff2e;border:none;color:#fff}.df-card{background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl)}.df-card--padded{padding:18px}.df-card--rows>*+*{border-top:1px solid var(--df-border)}.df-card__row{display:flex;align-items:center;gap:14px;padding:12px 16px;font-size:12px}.df-eyebrow{font-size:11px;color:var(--df-text-4);text-transform:uppercase;letter-spacing:.08em}.df-h1{margin:0;font-size:24px;font-weight:600;letter-spacing:-.02em;color:var(--df-text)}.df-h1--display{font-size:26px}.df-h1--serif{font-family:var(--df-font-serif);font-weight:400;font-size:32px;letter-spacing:-.02em;line-height:1.15}.df-subtle{color:var(--df-text-4);font-size:13px}.df-topbar{height:var(--df-h-bar);display:flex;align-items:center;gap:12px;padding:0 16px;background:var(--df-bg);border-bottom:1px solid var(--df-border);flex-shrink:0;flex-wrap:nowrap;white-space:nowrap;overflow:hidden;min-width:0}.df-topbar>*{flex-shrink:0}.df-topbar__crumb{display:flex;align-items:center;gap:8px;font-size:13px}.df-topbar__sep{color:var(--df-border-3)}.df-topbar__meta{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--df-text-4);min-width:0;overflow:hidden;text-overflow:ellipsis}.df-topbar__meta>span:last-child{overflow:hidden;text-overflow:ellipsis}.df-topbar__divider{width:1px;height:18px;background:var(--df-border);margin:0 4px}.df-topbar__avatar{width:28px;height:28px;border-radius:50%;background:linear-gradient(135deg,var(--df-pink),var(--df-accent))}.df-rail{width:var(--df-w-rail);background:var(--df-bg);border-right:1px solid var(--df-border);display:flex;flex-direction:column;align-items:center;padding:12px 0;gap:2px;flex-shrink:0}.df-rail__logo{width:32px;height:32px;margin-bottom:14px;border-radius:var(--df-r-lg);background:linear-gradient(135deg,var(--df-accent),#a855f7);display:flex;align-items:center;justify-content:center;color:#fff}.df-rail__item{position:relative;width:40px;height:40px;display:flex;align-items:center;justify-content:center;background:transparent;border:none;border-radius:var(--df-r-lg);color:var(--df-text-4);cursor:pointer;transition:background var(--df-fast),color var(--df-fast)}.df-rail__item:hover{color:var(--df-text-3)}.df-rail__item--active{background:var(--df-surface-3);color:var(--df-text)}.df-rail__item--active:before{content:"";position:absolute;left:-6px;top:10px;bottom:10px;width:2px;border-radius:1px;background:var(--df-accent)}.df-rail__spacer{flex:1}.df-rail__groups{width:100%;padding:0 8px}.df-rail__group{margin-bottom:8px}.df-rail__group-label{font-size:9px;letter-spacing:.12em;color:var(--df-text-5);text-transform:uppercase;text-align:center;margin-bottom:4px}.df-rail__divider{width:20px;height:1px;margin:4px auto;background:var(--df-border-3)}.df-rail__project-picker{width:32px;margin-bottom:4px}.df-rail__project-picker-wrap{position:relative;width:32px;height:32px;border-radius:var(--df-r-lg);background:var(--df-surface-3);display:flex;align-items:center;justify-content:center;cursor:pointer;transition:background var(--df-fast)}.df-rail__project-picker-wrap:hover,.df-rail__project-picker-wrap.open{background:var(--df-surface-2)}.df-rail__project-picker-caret{position:absolute;right:2px;top:50%;transform:translateY(-50%);width:0;height:0;border:3.5px solid var(--df-text-4);border-width:3.5px 0 3.5px 4px;transition:transform var(--df-fast)}.df-rail__project-picker-wrap.open .df-rail__project-picker-caret{transform:translateY(-50%) rotate(-90deg)}.df-rail__project-picker-menu{position:absolute;top:38px;left:0;width:220px;padding:4px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-lg);box-shadow:var(--df-shadow);z-index:100;display:none}.df-rail__project-picker-wrap.open+.df-rail__project-picker-menu,.df-rail__project-picker-menu--open{display:block}.df-rail__project-picker-search{width:100%;padding:7px 10px;background:var(--df-bg);border:1px solid var(--df-border-2);border-radius:var(--df-r-sm);font-size:12px;color:var(--df-text);margin-bottom:4px}.df-rail__project-picker-list{max-height:180px;overflow-y:auto}.df-rail__project-picker-item{display:flex;align-items:center;gap:8px;padding:7px 8px;font-size:12px;color:var(--df-text-3);cursor:pointer;border-radius:var(--df-r-sm);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.df-rail__project-picker-item:hover,.df-rail__project-picker-item--selected{background:var(--df-accent-halo);color:var(--df-accent-text)}.df-rail__project-picker-icon{width:16px;height:16px;flex-shrink:0}.df-rail__project-picker-item-badge{font-size:10px;padding:1px 6px;border-radius:var(--df-r-pill);background:var(--df-accent-halo);color:var(--df-accent-text);border:1px solid var(--df-accent-ring);white-space:nowrap;flex-shrink:0}.df-rail__project-picker-item-name{flex:1;overflow:hidden;text-overflow:ellipsis}.df-rail__project-picker-form{padding:4px;border-top:1px solid var(--df-border);margin-top:4px}.df-rail__project-picker-name{width:100%;padding:6px 8px;margin-bottom:4px;background:var(--df-bg);border:1px solid var(--df-border-2);border-radius:var(--df-r-sm);font-size:12px;color:var(--df-text);outline:none}.df-rail__project-picker-name:focus{border-color:var(--df-accent-ring);box-shadow:0 0 0 3px var(--df-accent-halo)}.df-rail__project-picker-select{width:100%;padding:6px 8px;margin-bottom:4px;background:var(--df-bg);border:1px solid var(--df-border-2);border-radius:var(--df-r-sm);font-size:12px;color:var(--df-text)}.df-rail__project-picker-create{width:100%;padding:5px;margin-top:4px;background:var(--df-accent);border-radius:var(--df-r-sm);font-size:11px;font-weight:600;color:#fff;cursor:pointer}.df-rail__project-picker-create:hover{opacity:.9}.df-rail__tip{pointer-events:none;position:absolute;left:46px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-sm);padding:3px 8px;font-size:11px;color:var(--df-text-2);white-space:nowrap;z-index:200;box-shadow:var(--df-shadow);transform:translate(-6px);opacity:0;transition:all var(--df-fast) var(--df-ease)}.df-rail__item:hover .df-rail__tip{transform:translate(0);opacity:1}.df-rail__item:hover .df-rail__tip--lg{left:auto;right:-70px}.df-rail--collapsed{width:64px!important}.df-rail--collapsed .df-rail__groups,.df-rail--collapsed .df-rail__project-picker{display:none}.df-rail--collapsed .df-rail__item:not(.df-rail__project-picker-wrap):hover .df-rail__tip{display:none}.df-field{display:block}.df-field__label{font-size:11px;color:var(--df-text-4);text-transform:uppercase;letter-spacing:.08em;margin-bottom:6px}.df-field__value{padding:10px 12px;background:var(--df-surface);border:1px solid var(--df-border-2);border-radius:var(--df-r-lg);font-size:13px;color:var(--df-text)}.df-field__value--mono{font-family:var(--df-font-mono)}.df-code{background:var(--df-surface-3);border:1px solid var(--df-border-2);padding:1px 6px;border-radius:var(--df-r-sm);font-family:var(--df-font-mono);font-size:.82em;color:var(--df-accent-text)}.df-status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--df-text-4)}.df-status-dot--live{background:var(--df-green);animation:df-pulse 1.4s infinite}.df-status-dot--paused{background:var(--df-text-4)}.df-ask{flex:1;display:flex;flex-direction:column;overflow:hidden;background:var(--df-bg)}.df-ask__header{padding:40px var(--df-content-pad) 24px;border-bottom:1px solid var(--df-border)}.df-ask__eyebrow{display:flex;align-items:center;gap:8px;margin-bottom:10px}.df-ask__title-accent{color:var(--df-accent-text)}.df-ask__intro{margin:6px 0 0;color:var(--df-text-4);font-size:13px}.df-ask__box-wrap{margin-top:24px;position:relative}.df-ask__box{display:flex;align-items:center;gap:10px;padding:14px 18px;border-radius:var(--df-r-xl);background:var(--df-surface);border:1px solid var(--df-border-2);transition:all var(--df-base) var(--df-ease)}.df-ask__box--active{border-color:var(--df-accent-ring);box-shadow:0 0 0 4px var(--df-accent-halo)}.df-ask__box-input{flex:1;font-size:15px;color:var(--df-text);min-height:22px}.df-ask__placeholder{color:var(--df-text-4)}.df-ask__caret{display:inline-block;width:2px;height:16px;background:var(--df-accent-text);vertical-align:-2px;margin-left:1px;animation:df-blink .8s infinite}.df-ask__run{height:28px;padding:0 14px;border-radius:var(--df-r-md);background:var(--df-accent);color:#fff;border:none;font-size:12px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:5px}.df-ask__run:hover{background:var(--df-accent-hover)}.df-ask__reset{padding:4px 10px;border-radius:var(--df-r-md);background:transparent;color:var(--df-text-4);border:1px solid var(--df-border-3);font-size:11px;cursor:pointer}.df-ask__chips{margin-top:12px;display:flex;flex-wrap:wrap;gap:6px}.df-chip{padding:6px 11px;border-radius:var(--df-r-pill);background:transparent;border:1px solid var(--df-border-2);color:var(--df-text-3);font-size:12px;cursor:pointer;font-family:inherit;transition:all var(--df-fast)}.df-chip:hover{background:var(--df-surface-2);border-color:var(--df-border-hi);color:var(--df-text)}.df-ask__body{flex:1;display:flex;overflow:hidden;min-height:0}.df-ask__main{flex:1;padding:28px var(--df-content-pad) 56px;min-width:0;overflow:auto}.df-search__head{display:flex;align-items:center;gap:10px;color:var(--df-accent-text);font-size:13px;margin-bottom:18px}.df-search__spinner{width:14px;height:14px;border:2px solid var(--df-border-3);border-top-color:var(--df-accent);border-radius:50%;animation:df-spin .7s linear infinite}.df-search__stage{display:flex;align-items:center;gap:10px;padding:8px 0;font-size:12px;color:var(--df-text-4)}.df-search__stage--done{color:var(--df-green)}.df-search__skel{margin-top:24px;display:flex;flex-direction:column;gap:10px}.df-search__skel-bar{height:12px;border-radius:var(--df-r-sm);background:linear-gradient(90deg,var(--df-surface-2),var(--df-surface-3),var(--df-surface-2));background-size:200% 100%;animation:df-shimmer 1.4s infinite linear}.df-answer{max-width:var(--df-content-max)}.df-answer__meta{display:flex;align-items:center;gap:10px;margin-bottom:20px}.df-answer__doc{font-family:var(--df-font-serif);border-top:1px solid var(--df-border);border-bottom:1px solid var(--df-border);padding:28px 0 32px}.df-answer__h{margin:0 0 22px;font-size:24px;font-weight:400;color:var(--df-text);letter-spacing:-.01em;line-height:1.25}.df-answer__prose{font-size:16px;line-height:1.72;color:var(--df-text-2)}.df-answer__prose p{margin:0 0 16px}.df-answer__prose strong{color:var(--df-text);font-weight:600}.df-answer__sup{color:var(--df-accent-text);font-weight:600;margin-left:2px;font-family:var(--df-font-sans);font-size:.7em}.df-answer__list{margin:0 0 18px;padding-left:0;list-style:none}.df-answer__li{position:relative;padding:8px 0 8px 22px;margin-left:6px;border-left:1px solid var(--df-border-2)}.df-answer__num{position:absolute;left:-10px;top:11px;width:18px;height:18px;border-radius:50%;background:var(--df-bg);border:1px solid var(--df-border-hi);color:var(--df-accent-text);font-size:10.5px;font-weight:600;display:flex;align-items:center;justify-content:center;font-family:var(--df-font-sans)}.df-cites{margin-top:24px;font-family:var(--df-font-serif)}.df-cites__row{display:flex;gap:14px;padding:12px 0;border-top:1px solid var(--df-border)}.df-cites__row:first-child{border-top:none}.df-cites__num{width:24px;color:var(--df-accent-text);font-weight:600;font-family:var(--df-font-sans);font-size:12px;margin-top:2px}.df-cites__title{font-size:15px;color:var(--df-text)}.df-cites__path{font-family:var(--df-font-mono);font-size:11px;color:var(--df-text-4);margin-top:2px}.df-related{margin-top:28px;padding-top:20px;border-top:1px solid var(--df-border)}.df-related__list{display:flex;flex-direction:column;gap:6px}.df-related__item{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;background:transparent;border:1px solid var(--df-border);border-radius:var(--df-r-md);color:var(--df-text-3);font-size:13px;cursor:pointer;font-family:inherit;text-align:left;transition:border-color var(--df-fast),color var(--df-fast)}.df-related__item:hover{border-color:var(--df-border-3);color:var(--df-text)}.df-actions{margin-top:24px;display:flex;gap:8px}.df-cites-rail{width:300px;border-left:1px solid var(--df-border);padding:28px 20px;background:#0c0c0e;flex-shrink:0;overflow:auto}.df-cites-rail__list{display:flex;flex-direction:column;gap:8px}.df-cites-card{padding:12px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-lg);cursor:pointer;transition:border-color var(--df-fast)}.df-cites-card:hover{border-color:var(--df-border-3)}.df-cites-card__head{display:flex;align-items:center;gap:6px;margin-bottom:6px}.df-cites-card__num{width:18px;height:18px;border-radius:5px;background:var(--df-accent-soft);color:var(--df-accent-text);font-size:10px;font-weight:600;display:flex;align-items:center;justify-content:center;font-family:var(--df-font-mono)}.df-cites-card__title{font-size:13px;font-weight:500;color:var(--df-text);flex:1}.df-cites-card__path{font-size:11px;color:var(--df-text-4);font-family:var(--df-font-mono);margin-bottom:8px}.df-cites-card__foot{display:flex;align-items:center;gap:6px;font-size:10px}.df-activity__row{display:flex;align-items:center;gap:14px;padding:10px 14px;font-size:12px;border-top:1px solid var(--df-border)}.df-activity__row:first-child{border-top:none}.df-activity__time{width:48px;color:var(--df-text-4);font-size:11px;font-family:var(--df-font-mono)}.df-activity__target{flex:1;color:var(--df-text-3);font-family:var(--df-font-mono)}.df-activity__delta{color:var(--df-text-4)}.df-wiki{flex:1;display:flex;overflow:hidden}.df-tree{width:var(--df-w-tree);border-right:1px solid var(--df-border);padding:14px 10px;overflow:auto;flex-shrink:0}.df-tree__filter{display:flex;align-items:center;gap:6px;padding:6px 8px;margin-bottom:8px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-md);font-size:12px;color:var(--df-text-4)}.df-tree__heading{font-size:10px;color:var(--df-text-4);text-transform:uppercase;letter-spacing:.08em;padding:8px 8px 4px}.df-tree__row{display:flex;align-items:center;gap:6px;padding:5px 8px;border-radius:var(--df-r-sm);font-size:12px;color:var(--df-text-3);cursor:pointer;transition:background var(--df-fast)}.df-tree__row:hover{background:var(--df-surface-2)}.df-tree__row--active{background:var(--df-accent-soft);color:var(--df-accent-text)}.df-tree__row--active:hover{background:var(--df-accent-soft)}.df-tree__row--stale{color:var(--df-amber-text)}.df-tree__caret{width:11px;display:flex;color:var(--df-text-4)}.df-tree__indicator{width:5px;height:5px;border-radius:50%}.df-tree__indicator--stale{background:var(--df-amber)}.df-tree__indicator--highlight{background:var(--df-accent)}.df-page{flex:1;overflow:auto;padding:40px var(--df-content-pad);max-width:780px;font-family:var(--df-font-serif)}.df-page__crumb{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--df-text-4);margin-bottom:10px;font-family:var(--df-font-sans)}.df-page__crumb-active{color:var(--df-text-3)}.df-page__meta{display:flex;align-items:center;gap:8px;margin:14px 0 28px;font-family:var(--df-font-sans)}.df-page__path{font-size:11px;color:var(--df-text-4);font-family:var(--df-font-mono)}.df-page__prose{font-size:16px;line-height:1.72;color:var(--df-text-2)}.df-page__prose p:first-child{margin-top:0}.df-page__prose ul{padding-left:18px;line-height:1.7}.df-page__prose a{color:var(--df-accent-text);text-decoration:none}.df-page__prose a:hover{text-decoration:underline}.df-page__h3{font-family:var(--df-font-sans);font-size:13px;font-weight:600;color:var(--df-text);margin-top:28px;text-transform:uppercase;letter-spacing:.08em}.df-page__kv-row{display:flex;padding:8px 14px;border-top:1px solid var(--df-border);font-size:13px}.df-page__kv-row:first-child{border-top:none}.df-page__kv-key{width:120px;color:var(--df-accent-text);font-family:var(--df-font-mono)}.df-page__kv-val{color:var(--df-text-3)}.df-graph{flex:1;display:flex;overflow:hidden}.df-graph__canvas{flex:1;position:relative;overflow:hidden}.df-graph__grid{position:absolute;top:0;right:0;bottom:0;left:0;background-image:radial-gradient(circle,var(--df-border) 1px,transparent 1px);background-size:24px 24px;opacity:.5}.df-graph__legend{position:absolute;top:16px;left:16px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-lg);padding:10px 12px;display:flex;flex-direction:column;gap:6px;font-size:11px;z-index:2}.df-graph__legend-row{display:flex;align-items:center;gap:7px;color:var(--df-text-3);text-transform:capitalize}.df-graph__legend-swatch{width:8px;height:8px;border-radius:50%}.df-graph__controls{position:absolute;top:16px;right:16px;display:flex;gap:6px;z-index:2}.df-graph__svg{position:absolute;top:0;right:0;bottom:0;left:0}.df-graph__detail{width:var(--df-w-rail-detail);border-left:1px solid var(--df-border);padding:24px 20px;flex-shrink:0;overflow:auto}.df-graph__connection{display:flex;align-items:center;gap:8px;padding:7px 8px;border-radius:var(--df-r-sm);cursor:pointer;font-size:12px;color:var(--df-text-3)}.df-graph__connection:hover{background:var(--df-surface-2)}.df-graph__connection-dot{width:6px;height:6px;border-radius:50%}.df-health{flex:1;overflow:auto;padding:40px var(--df-content-pad)}.df-health__grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin:24px 0 32px}.df-stat{padding:18px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl)}.df-stat__num{font-size:34px;font-weight:600;letter-spacing:-.02em;margin-top:6px}.df-stat__num--green{color:var(--df-green)}.df-stat__num--amber{color:var(--df-amber-text)}.df-stat__num--red{color:var(--df-red)}.df-stat__bar{height:4px;background:var(--df-border);border-radius:2px;margin-top:10px;overflow:hidden}.df-stat__bar-fill{height:100%;background:linear-gradient(90deg,var(--df-green),var(--df-green-text));border-radius:2px}.df-stat__caption{font-size:11px;color:var(--df-text-4);margin-top:10px}.df-trend{background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl);padding:20px;margin-bottom:24px}.df-trend__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}.df-trend__title{font-size:13px;font-weight:500}.df-trend__bars{display:flex;align-items:flex-end;gap:6px;height:80px}.df-trend__bar{flex:1;border-radius:3px 3px 0 0;opacity:.85;transform-origin:bottom;animation:df-bar-grow .5s var(--df-ease) both}.df-issues__row{display:flex;align-items:center;gap:14px;padding:14px 16px;border-top:1px solid var(--df-border)}.df-issues__row:first-child{border-top:none}.df-issues__page{font-size:13px;font-weight:500;color:var(--df-text)}.df-issues__msg{flex:1;font-size:12px;color:var(--df-text-3)}.df-issues__age{font-size:11px;color:var(--df-text-4);font-family:var(--df-font-mono)}.df-sync{flex:1;overflow:auto;padding:40px var(--df-content-pad)}.df-sync__head{display:flex;align-items:center;justify-content:space-between}.df-sync__cards{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:24px 0 28px}.df-sync-card{padding:16px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl)}.df-sync-card__body{margin-top:8px;font-weight:500;display:flex;align-items:center;gap:8px}.df-sync-card__sub{font-size:11px;color:var(--df-text-4);margin-top:6px;font-family:var(--df-font-mono)}.df-sync-card__sub--green{color:var(--df-green);font-family:inherit}.df-timeline{background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl);padding:8px 0}.df-timeline__row{display:flex;align-items:center;gap:14px;padding:10px 18px;position:relative}.df-timeline__time{width:48px;font-size:11px;color:var(--df-text-4);font-family:var(--df-font-mono)}.df-timeline__line{position:absolute;left:78px;top:0;bottom:0;width:1px;background:var(--df-border)}.df-timeline__dot{position:relative;width:9px;height:9px;border-radius:50%;background:var(--df-border-3);z-index:1}.df-timeline__dot--commit{background:var(--df-pink)}.df-timeline__dot--sync{background:var(--df-accent)}.df-timeline__dot--done{background:var(--df-green);box-shadow:0 0 0 3px #10b9812e}.df-timeline__msg{flex:1;font-size:13px;color:var(--df-text-2)}.df-timeline__msg--done{color:var(--df-green)}.df-onboard{flex:1;display:flex;flex-direction:column;overflow:auto}.df-onboard__center{flex:1;display:flex;align-items:center;justify-content:center;padding:48px 32px}.df-onboard__inner{width:100%;max-width:640px}.df-onboard__steps{display:flex;align-items:center;gap:8px;margin-bottom:32px;font-size:12px}.df-onboard__step{display:flex;align-items:center;gap:8px;color:var(--df-text-4)}.df-onboard__step--active,.df-onboard__step--done{color:var(--df-text)}.df-onboard__step-num{width:22px;height:22px;border-radius:50%;background:var(--df-surface-3);color:#fff;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600}.df-onboard__step--active .df-onboard__step-num{background:var(--df-accent)}.df-onboard__step--done .df-onboard__step-num{background:var(--df-green)}.df-onboard__step-line{flex:1;height:1px;background:var(--df-border)}.df-onboard__step-line--done{background:var(--df-green)}.df-onboard__intro{color:var(--df-text-4);margin:6px 0 24px}.df-domains{display:grid;grid-template-columns:1fr 1fr;gap:10px}.df-domain{text-align:left;padding:18px;border-radius:var(--df-r-xl);background:var(--df-surface);border:1px solid var(--df-border);cursor:pointer;font-family:inherit;color:var(--df-text);transition:all var(--df-fast)}.df-domain--selected{background:var(--df-accent-halo);border-color:var(--df-accent)}.df-domain__icon{width:32px;height:32px;border-radius:var(--df-r-lg);background:var(--df-surface-3);display:flex;align-items:center;justify-content:center;margin-bottom:10px;color:var(--df-text-3)}.df-domain--selected .df-domain__icon{background:var(--df-accent-soft);color:var(--df-accent-text)}.df-domain__label{font-weight:500;font-size:14px}.df-domain__desc{font-size:12px;color:var(--df-text-4);margin-top:4px}.df-onboard__fields{display:flex;flex-direction:column;gap:14px}.df-dropzone{padding:32px;border:1.5px dashed var(--df-border-3);border-radius:12px;text-align:center;background:#0c0c0e}.df-dropzone__title{margin-top:12px;font-size:14px;color:var(--df-text)}.df-dropzone__sub{margin-top:4px;font-size:12px;color:var(--df-text-4)}.df-init-log{background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl);padding:16px;font-family:var(--df-font-mono);font-size:12px}.df-init-log__line{display:flex;gap:10px;padding:4px 0;color:var(--df-text-3)}.df-init-log__mark--ok{color:var(--df-green)}.df-init-log__mark--run{color:var(--df-accent-text)}.df-onboard__nav{display:flex;justify-content:space-between;margin-top:32px}
@@ -0,0 +1 @@
1
+ :root{--df-bg: #0a0a0b;--df-surface: #111113;--df-surface-2: #161619;--df-surface-3: #1d1d22;--df-border: #1a1a1f;--df-border-2: #26262c;--df-border-3: #2c2c33;--df-border-hi: #3a3a44;--df-text: #ededee;--df-text-2: #d4d4d8;--df-text-3: #a1a1aa;--df-text-4: #6b6b74;--df-accent: #6366f1;--df-accent-hover: #5558e3;--df-accent-2: #818cf8;--df-accent-text: #a5b4fc;--df-accent-soft: rgba(99,102,241,.14);--df-accent-glow: rgba(99,102,241,.18);--df-accent-ring: rgba(99,102,241,.4);--df-accent-halo: rgba(99,102,241,.08);--df-green: #10b981;--df-green-text: #34d399;--df-green-soft: rgba(16,185,129,.12);--df-green-ring: rgba(16,185,129,.3);--df-amber: #f59e0b;--df-amber-text: #fbbf24;--df-amber-soft: rgba(245,158,11,.12);--df-amber-ring: rgba(245,158,11,.3);--df-red: #ef4444;--df-red-text: #f87171;--df-red-soft: rgba(239,68,68,.12);--df-red-ring: rgba(239,68,68,.3);--df-pink: #ec4899;--df-pink-text: #f472b6;--df-pink-soft: rgba(236,72,153,.12);--df-pink-ring: rgba(236,72,153,.3);--df-font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;--df-font-serif: "Source Serif 4", "Iowan Old Style", Georgia, serif;--df-font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;--df-r-sm: 4px;--df-r-md: 6px;--df-r-lg: 8px;--df-r-xl: 10px;--df-r-pill: 999px;--df-h-btn: 28px;--df-h-input: 30px;--df-h-bar: 44px;--df-w-rail: 60px;--df-w-rail-detail: 280px;--df-w-tree: 260px;--df-ease: cubic-bezier(.2,.7,.3,1);--df-fast: .12s;--df-base: .2s;--df-slow: .35s;--df-content-max: 720px;--df-content-pad: 56px}*,*:before,*:after{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{background:var(--df-bg);color:var(--df-text);font-family:var(--df-font-sans);font-feature-settings:"cv11","ss01";font-size:13px;line-height:1.5;letter-spacing:-.005em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}button{font-family:inherit}.df-mono{font-family:var(--df-font-mono);font-feature-settings:"cv01","cv02"}.df-serif{font-family:var(--df-font-serif)}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background:var(--df-border-2);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--df-border-3)}::-webkit-scrollbar-track{background:transparent}::selection{background:var(--df-accent-soft);color:var(--df-text)}.df-app{width:100vw;height:100vh;display:flex;flex-direction:column;overflow:hidden}.df-app__main{flex:1;display:flex;overflow:hidden;min-height:0}.df-view{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0;background:var(--df-bg)}@keyframes df-fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes df-spin{to{transform:rotate(360deg)}}@keyframes df-pulse{0%,to{opacity:.4}50%{opacity:1}}@keyframes df-blink{0%,49%{opacity:1}50%,to{opacity:0}}@keyframes df-shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}@keyframes df-bar-grow{0%{transform:scaleY(0)}to{transform:scaleY(1)}}@keyframes df-page-enter{0%{opacity:0;transform:translate(8px)}to{opacity:1;transform:translate(0)}}.df-anim-fade{animation:df-fade-in var(--df-base) var(--df-ease) both}.df-anim-page{animation:df-page-enter var(--df-slow) var(--df-ease) both}.df-pill{display:inline-flex;align-items:center;gap:5px;padding:2px 7px;border-radius:var(--df-r-sm);font-size:11px;font-weight:500;font-family:var(--df-font-sans);background:var(--df-surface-3);border:1px solid var(--df-border-3);color:var(--df-text-3);white-space:nowrap}.df-pill--accent{background:var(--df-accent-soft);border-color:var(--df-accent-ring);color:var(--df-accent-text)}.df-pill--green{background:var(--df-green-soft);border-color:var(--df-green-ring);color:var(--df-green-text)}.df-pill--amber{background:var(--df-amber-soft);border-color:var(--df-amber-ring);color:var(--df-amber-text)}.df-pill--red{background:var(--df-red-soft);border-color:var(--df-red-ring);color:var(--df-red-text)}.df-pill--pink{background:var(--df-pink-soft);border-color:var(--df-pink-ring);color:var(--df-pink-text)}.df-pill__dot{width:5px;height:5px;border-radius:50%;background:currentColor}.df-btn{display:inline-flex;align-items:center;gap:6px;height:var(--df-h-btn);padding:0 10px;border-radius:var(--df-r-md);background:var(--df-surface-3);border:1px solid var(--df-border-3);color:var(--df-text);font-size:12px;font-weight:500;letter-spacing:-.005em;cursor:pointer;transition:background var(--df-fast),border-color var(--df-fast),color var(--df-fast);white-space:nowrap}.df-btn:hover{background:var(--df-surface-2)}.df-btn--primary{background:var(--df-accent);border-color:var(--df-accent);color:#fff}.df-btn--primary:hover{background:var(--df-accent-hover);border-color:var(--df-accent-hover)}.df-btn--ghost{background:transparent;border-color:transparent;color:var(--df-text-3)}.df-btn--ghost:hover{background:var(--df-surface-3);color:var(--df-text)}.df-btn--active{background:var(--df-surface-2);border-color:var(--df-border-hi)}.df-kbd{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;border-radius:var(--df-r-sm);background:var(--df-surface-3);border:1px solid var(--df-border-3);color:var(--df-text-3);font:11px/1 var(--df-font-mono)}.df-btn--primary .df-kbd{background:#ffffff2e;border:none;color:#fff}.df-card{background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl)}.df-card--padded{padding:18px}.df-card--rows>*+*{border-top:1px solid var(--df-border)}.df-card__row{display:flex;align-items:center;gap:14px;padding:12px 16px;font-size:12px}.df-eyebrow{font-size:11px;color:var(--df-text-4);text-transform:uppercase;letter-spacing:.08em}.df-h1{margin:0;font-size:24px;font-weight:600;letter-spacing:-.02em;color:var(--df-text)}.df-h1--display{font-size:26px}.df-h1--serif{font-family:var(--df-font-serif);font-weight:400;font-size:32px;letter-spacing:-.02em;line-height:1.15}.df-subtle{color:var(--df-text-4);font-size:13px}.df-topbar{height:var(--df-h-bar);display:flex;align-items:center;gap:12px;padding:0 16px;background:var(--df-bg);border-bottom:1px solid var(--df-border);flex-shrink:0;flex-wrap:nowrap;white-space:nowrap;overflow:hidden;min-width:0}.df-topbar>*{flex-shrink:0}.df-topbar__crumb{display:flex;align-items:center;gap:8px;font-size:13px}.df-topbar__sep{color:var(--df-border-3)}.df-topbar__meta{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--df-text-4);min-width:0;overflow:hidden;text-overflow:ellipsis}.df-topbar__meta>span:last-child{overflow:hidden;text-overflow:ellipsis}.df-topbar__divider{width:1px;height:18px;background:var(--df-border);margin:0 4px}.df-topbar__avatar{width:28px;height:28px;border-radius:50%;background:linear-gradient(135deg,var(--df-pink),var(--df-accent))}.df-rail{width:var(--df-w-rail);background:var(--df-bg);border-right:1px solid var(--df-border);display:flex;flex-direction:column;align-items:center;padding:12px 0;gap:2px;flex-shrink:0}.df-rail__logo{width:32px;height:32px;margin-bottom:14px;border-radius:var(--df-r-lg);background:linear-gradient(135deg,var(--df-accent),#a855f7);display:flex;align-items:center;justify-content:center;color:#fff}.df-rail__item{position:relative;width:40px;height:40px;display:flex;align-items:center;justify-content:center;background:transparent;border:none;border-radius:var(--df-r-lg);color:var(--df-text-4);cursor:pointer;transition:background var(--df-fast),color var(--df-fast)}.df-rail__item:hover{color:var(--df-text-3)}.df-rail__item--active{background:var(--df-surface-3);color:var(--df-text)}.df-rail__item--active:before{content:"";position:absolute;left:-6px;top:10px;bottom:10px;width:2px;border-radius:1px;background:var(--df-accent)}.df-rail__spacer{flex:1}.df-field{display:block}.df-field__label{font-size:11px;color:var(--df-text-4);text-transform:uppercase;letter-spacing:.08em;margin-bottom:6px}.df-field__value{padding:10px 12px;background:var(--df-surface);border:1px solid var(--df-border-2);border-radius:var(--df-r-lg);font-size:13px;color:var(--df-text)}.df-field__value--mono{font-family:var(--df-font-mono)}.df-code{background:var(--df-surface-3);border:1px solid var(--df-border-2);padding:1px 6px;border-radius:var(--df-r-sm);font-family:var(--df-font-mono);font-size:.82em;color:var(--df-accent-text)}.df-status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--df-text-4)}.df-status-dot--live{background:var(--df-green);animation:df-pulse 1.4s infinite}.df-status-dot--paused{background:var(--df-text-4)}.df-modal-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000008c;z-index:300;display:flex;align-items:flex-start;justify-content:center;padding-top:12vh}.df-cmd-palette{width:min(720px,calc(100vw - 48px));border:1px solid var(--df-border-2);border-radius:var(--df-r-xl);background:var(--df-bg);box-shadow:0 18px 48px #00000073;overflow:hidden}.df-cmd-palette__head{display:flex;gap:8px;padding:10px;border-bottom:1px solid var(--df-border)}.df-cmd-palette__input{flex:1;height:36px;padding:0 12px;border-radius:var(--df-r-md);border:1px solid var(--df-border-2);background:var(--df-surface);color:var(--df-text);font-size:13px;font-family:inherit;outline:none}.df-cmd-palette__close{height:36px;padding:0 10px;border-radius:var(--df-r-md);border:1px solid var(--df-border-2);background:var(--df-surface-3);color:var(--df-text-3);font-family:var(--df-font-mono);font-size:11px;cursor:pointer}.df-cmd-palette__list{max-height:56vh;overflow:auto}.df-cmd-palette__empty{padding:16px;color:var(--df-text-4);font-size:12px}.df-cmd-palette__item{width:100%;border:none;border-top:1px solid var(--df-border);background:transparent;color:var(--df-text);text-align:left;padding:12px 14px;cursor:pointer;font-family:inherit}.df-cmd-palette__item:first-child{border-top:none}.df-cmd-palette__item--active,.df-cmd-palette__item:hover{background:var(--df-surface)}.df-cmd-palette__title{font-size:13px;font-weight:600}.df-cmd-palette__meta{margin-top:3px;display:flex;gap:10px;font-size:11px;color:var(--df-text-4);text-transform:uppercase;letter-spacing:.04em}.df-cmd-palette__preview{margin-top:6px;color:var(--df-text-3);font-size:12px}.df-ask{flex:1;display:flex;flex-direction:column;overflow:hidden;background:var(--df-bg)}.df-ask__header{padding:40px var(--df-content-pad) 24px;border-bottom:1px solid var(--df-border)}.df-ask__eyebrow{display:flex;align-items:center;gap:8px;margin-bottom:10px}.df-ask__title-accent{color:var(--df-accent-text)}.df-ask__intro{margin:6px 0 0;color:var(--df-text-4);font-size:13px}.df-ask__box-wrap{margin-top:24px;position:relative}.df-ask__box{display:flex;align-items:center;gap:10px;padding:14px 18px;border-radius:var(--df-r-xl);background:var(--df-surface);border:1px solid var(--df-border-2);transition:all var(--df-base) var(--df-ease)}.df-ask__box--active{border-color:var(--df-accent-ring);box-shadow:0 0 0 4px var(--df-accent-halo)}.df-ask__box-input{flex:1;font-size:15px;color:var(--df-text);min-height:22px}.df-ask__placeholder{color:var(--df-text-4)}.df-ask__caret{display:inline-block;width:2px;height:16px;background:var(--df-accent-text);vertical-align:-2px;margin-left:1px;animation:df-blink .8s infinite}.df-ask__run{height:28px;padding:0 14px;border-radius:var(--df-r-md);background:var(--df-accent);color:#fff;border:none;font-size:12px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:5px}.df-ask__run:hover{background:var(--df-accent-hover)}.df-ask__reset{padding:4px 10px;border-radius:var(--df-r-md);background:transparent;color:var(--df-text-4);border:1px solid var(--df-border-3);font-size:11px;cursor:pointer}.df-ask__chips{margin-top:12px;display:flex;flex-wrap:wrap;gap:6px}.df-chip{padding:6px 11px;border-radius:var(--df-r-pill);background:transparent;border:1px solid var(--df-border-2);color:var(--df-text-3);font-size:12px;cursor:pointer;font-family:inherit;transition:all var(--df-fast)}.df-chip:hover{background:var(--df-surface-2);border-color:var(--df-border-hi);color:var(--df-text)}.df-ask__body{flex:1;display:flex;overflow:hidden;min-height:0}.df-ask__main{flex:1;padding:28px var(--df-content-pad) 56px;min-width:0;overflow:auto}.df-search__head{display:flex;align-items:center;gap:10px;color:var(--df-accent-text);font-size:13px;margin-bottom:18px}.df-search__spinner{width:14px;height:14px;border:2px solid var(--df-border-3);border-top-color:var(--df-accent);border-radius:50%;animation:df-spin .7s linear infinite}.df-search__stage{display:flex;align-items:center;gap:10px;padding:8px 0;font-size:12px;color:var(--df-text-4)}.df-search__stage--done{color:var(--df-green)}.df-search__skel{margin-top:24px;display:flex;flex-direction:column;gap:10px}.df-search__skel-bar{height:12px;border-radius:var(--df-r-sm);background:linear-gradient(90deg,var(--df-surface-2),var(--df-surface-3),var(--df-surface-2));background-size:200% 100%;animation:df-shimmer 1.4s infinite linear}.df-answer{max-width:var(--df-content-max)}.df-answer__meta{display:flex;align-items:center;gap:10px;margin-bottom:20px}.df-answer__doc{font-family:var(--df-font-serif);border-top:1px solid var(--df-border);border-bottom:1px solid var(--df-border);padding:28px 0 32px}.df-answer__h{margin:0 0 22px;font-size:24px;font-weight:400;color:var(--df-text);letter-spacing:-.01em;line-height:1.25}.df-answer__prose{font-size:16px;line-height:1.72;color:var(--df-text-2)}.df-answer__prose p{margin:0 0 16px}.df-answer__prose strong{color:var(--df-text);font-weight:600}.df-answer__sup{color:var(--df-accent-text);font-weight:600;margin-left:2px;font-family:var(--df-font-sans);font-size:.7em}.df-answer__list{margin:0 0 18px;padding-left:0;list-style:none}.df-answer__li{position:relative;padding:8px 0 8px 22px;margin-left:6px;border-left:1px solid var(--df-border-2)}.df-answer__num{position:absolute;left:-10px;top:11px;width:18px;height:18px;border-radius:50%;background:var(--df-bg);border:1px solid var(--df-border-hi);color:var(--df-accent-text);font-size:10.5px;font-weight:600;display:flex;align-items:center;justify-content:center;font-family:var(--df-font-sans)}.df-cites{margin-top:24px;font-family:var(--df-font-serif)}.df-cites__row{display:flex;gap:14px;padding:12px 0;border-top:1px solid var(--df-border)}.df-cites__row:first-child{border-top:none}.df-cites__num{width:24px;color:var(--df-accent-text);font-weight:600;font-family:var(--df-font-sans);font-size:12px;margin-top:2px}.df-cites__title{font-size:15px;color:var(--df-text)}.df-cites__path{font-family:var(--df-font-mono);font-size:11px;color:var(--df-text-4);margin-top:2px}.df-related{margin-top:28px;padding-top:20px;border-top:1px solid var(--df-border)}.df-related__list{display:flex;flex-direction:column;gap:6px}.df-related__item{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;background:transparent;border:1px solid var(--df-border);border-radius:var(--df-r-md);color:var(--df-text-3);font-size:13px;cursor:pointer;font-family:inherit;text-align:left;transition:border-color var(--df-fast),color var(--df-fast)}.df-related__item:hover{border-color:var(--df-border-3);color:var(--df-text)}.df-actions{margin-top:24px;display:flex;gap:8px}.df-cites-rail{width:300px;border-left:1px solid var(--df-border);padding:28px 20px;background:#0c0c0e;flex-shrink:0;overflow:auto}.df-cites-rail__list{display:flex;flex-direction:column;gap:8px}.df-cites-card{padding:12px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-lg);cursor:pointer;transition:border-color var(--df-fast)}.df-cites-card:hover{border-color:var(--df-border-3)}.df-cites-card__head{display:flex;align-items:center;gap:6px;margin-bottom:6px}.df-cites-card__num{width:18px;height:18px;border-radius:5px;background:var(--df-accent-soft);color:var(--df-accent-text);font-size:10px;font-weight:600;display:flex;align-items:center;justify-content:center;font-family:var(--df-font-mono)}.df-cites-card__title{font-size:13px;font-weight:500;color:var(--df-text);flex:1}.df-cites-card__path{font-size:11px;color:var(--df-text-4);font-family:var(--df-font-mono);margin-bottom:8px}.df-cites-card__foot{display:flex;align-items:center;gap:6px;font-size:10px}.df-activity__row{display:flex;align-items:center;gap:14px;padding:10px 14px;font-size:12px;border-top:1px solid var(--df-border)}.df-activity__row:first-child{border-top:none}.df-activity__time{width:48px;color:var(--df-text-4);font-size:11px;font-family:var(--df-font-mono)}.df-activity__target{flex:1;color:var(--df-text-3);font-family:var(--df-font-mono)}.df-activity__delta{color:var(--df-text-4)}.df-wiki{flex:1;display:flex;overflow:hidden}.df-tree{width:var(--df-w-tree);border-right:1px solid var(--df-border);padding:14px 10px;overflow:auto;flex-shrink:0}.df-tree__filter{display:flex;align-items:center;gap:6px;padding:6px 8px;margin-bottom:8px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-md);font-size:12px;color:var(--df-text-4)}.df-tree__heading{font-size:10px;color:var(--df-text-4);text-transform:uppercase;letter-spacing:.08em;padding:8px 8px 4px}.df-tree__row{display:flex;align-items:center;gap:6px;padding:5px 8px;border-radius:var(--df-r-sm);font-size:12px;color:var(--df-text-3);cursor:pointer;transition:background var(--df-fast)}.df-tree__row:hover{background:var(--df-surface-2)}.df-tree__row--active{background:var(--df-accent-soft);color:var(--df-accent-text)}.df-tree__row--active:hover{background:var(--df-accent-soft)}.df-tree__row--stale{color:var(--df-amber-text)}.df-tree__caret{width:11px;display:flex;color:var(--df-text-4)}.df-tree__indicator{width:5px;height:5px;border-radius:50%}.df-tree__indicator--stale{background:var(--df-amber)}.df-tree__indicator--highlight{background:var(--df-accent)}.df-page{flex:1;overflow:auto;padding:40px var(--df-content-pad);max-width:780px;font-family:var(--df-font-serif)}.df-page__crumb{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--df-text-4);margin-bottom:10px;font-family:var(--df-font-sans)}.df-page__crumb-active{color:var(--df-text-3)}.df-page__meta{display:flex;align-items:center;gap:8px;margin:14px 0 28px;font-family:var(--df-font-sans)}.df-page__path{font-size:11px;color:var(--df-text-4);font-family:var(--df-font-mono)}.df-page__prose{font-size:16px;line-height:1.72;color:var(--df-text-2)}.df-page__prose p:first-child{margin-top:0}.df-page__prose ul{padding-left:18px;line-height:1.7}.df-page__prose a{color:var(--df-accent-text);text-decoration:none}.df-page__prose a:hover{text-decoration:underline}.df-page__h3{font-family:var(--df-font-sans);font-size:13px;font-weight:600;color:var(--df-text);margin-top:28px;text-transform:uppercase;letter-spacing:.08em}.df-page__kv-row{display:flex;padding:8px 14px;border-top:1px solid var(--df-border);font-size:13px}.df-page__kv-row:first-child{border-top:none}.df-page__kv-key{width:120px;color:var(--df-accent-text);font-family:var(--df-font-mono)}.df-page__kv-val{color:var(--df-text-3)}.df-graph{flex:1;display:flex;overflow:hidden}.df-graph__canvas{flex:1;position:relative;overflow:hidden}.df-graph__grid{position:absolute;top:0;right:0;bottom:0;left:0;background-image:radial-gradient(circle,var(--df-border) 1px,transparent 1px);background-size:24px 24px;opacity:.5}.df-graph__legend{position:absolute;top:16px;left:16px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-lg);padding:10px 12px;display:flex;flex-direction:column;gap:6px;font-size:11px;z-index:2}.df-graph__legend-row{display:flex;align-items:center;gap:7px;color:var(--df-text-3);text-transform:capitalize}.df-graph__legend-swatch{width:8px;height:8px;border-radius:50%}.df-graph__controls{position:absolute;top:16px;right:16px;display:flex;gap:6px;z-index:2}.df-graph__svg{position:absolute;top:0;right:0;bottom:0;left:0}.df-graph__detail{width:var(--df-w-rail-detail);border-left:1px solid var(--df-border);padding:24px 20px;flex-shrink:0;overflow:auto}.df-graph__connection{display:flex;align-items:center;gap:8px;padding:7px 8px;border-radius:var(--df-r-sm);cursor:pointer;font-size:12px;color:var(--df-text-3)}.df-graph__connection:hover{background:var(--df-surface-2)}.df-graph__connection-dot{width:6px;height:6px;border-radius:50%}.df-health{flex:1;overflow:auto;padding:40px var(--df-content-pad)}.df-health__grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin:24px 0 32px}.df-stat{padding:18px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl)}.df-stat__num{font-size:34px;font-weight:600;letter-spacing:-.02em;margin-top:6px}.df-stat__num--green{color:var(--df-green)}.df-stat__num--amber{color:var(--df-amber-text)}.df-stat__num--red{color:var(--df-red)}.df-stat__bar{height:4px;background:var(--df-border);border-radius:2px;margin-top:10px;overflow:hidden}.df-stat__bar-fill{height:100%;background:linear-gradient(90deg,var(--df-green),var(--df-green-text));border-radius:2px}.df-stat__caption{font-size:11px;color:var(--df-text-4);margin-top:10px}.df-trend{background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl);padding:20px;margin-bottom:24px}.df-trend__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}.df-trend__title{font-size:13px;font-weight:500}.df-trend__bars{display:flex;align-items:flex-end;gap:6px;height:80px}.df-trend__bar{flex:1;border-radius:3px 3px 0 0;opacity:.85;transform-origin:bottom;animation:df-bar-grow .5s var(--df-ease) both}.df-issues__row{display:flex;align-items:center;gap:14px;padding:14px 16px;border-top:1px solid var(--df-border)}.df-issues__row:first-child{border-top:none}.df-issues__page{font-size:13px;font-weight:500;color:var(--df-text)}.df-issues__msg{flex:1;font-size:12px;color:var(--df-text-3)}.df-issues__age{font-size:11px;color:var(--df-text-4);font-family:var(--df-font-mono)}.df-sync{flex:1;overflow:auto;padding:40px var(--df-content-pad)}.df-sync__head{display:flex;align-items:center;justify-content:space-between}.df-sync__cards{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:24px 0 28px}.df-sync-card{padding:16px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl)}.df-sync-card__body{margin-top:8px;font-weight:500;display:flex;align-items:center;gap:8px}.df-sync-card__sub{font-size:11px;color:var(--df-text-4);margin-top:6px;font-family:var(--df-font-mono)}.df-sync-card__sub--green{color:var(--df-green);font-family:inherit}.df-timeline{background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl);padding:8px 0}.df-timeline__row{display:flex;align-items:center;gap:14px;padding:10px 18px;position:relative}.df-timeline__time{width:48px;font-size:11px;color:var(--df-text-4);font-family:var(--df-font-mono)}.df-timeline__line{position:absolute;left:78px;top:0;bottom:0;width:1px;background:var(--df-border)}.df-timeline__dot{position:relative;width:9px;height:9px;border-radius:50%;background:var(--df-border-3);z-index:1}.df-timeline__dot--commit{background:var(--df-pink)}.df-timeline__dot--sync{background:var(--df-accent)}.df-timeline__dot--done{background:var(--df-green);box-shadow:0 0 0 3px #10b9812e}.df-timeline__msg{flex:1;font-size:13px;color:var(--df-text-2)}.df-timeline__msg--done{color:var(--df-green)}.df-onboard{flex:1;display:flex;flex-direction:column;overflow:auto}.df-onboard__center{flex:1;display:flex;align-items:center;justify-content:center;padding:48px 32px}.df-onboard__inner{width:100%;max-width:640px}.df-onboard__steps{display:flex;align-items:center;gap:8px;margin-bottom:32px;font-size:12px}.df-onboard__step{display:flex;align-items:center;gap:8px;color:var(--df-text-4)}.df-onboard__step--active,.df-onboard__step--done{color:var(--df-text)}.df-onboard__step-num{width:22px;height:22px;border-radius:50%;background:var(--df-surface-3);color:#fff;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600}.df-onboard__step--active .df-onboard__step-num{background:var(--df-accent)}.df-onboard__step--done .df-onboard__step-num{background:var(--df-green)}.df-onboard__step-line{flex:1;height:1px;background:var(--df-border)}.df-onboard__step-line--done{background:var(--df-green)}.df-onboard__intro{color:var(--df-text-4);margin:6px 0 24px}.df-domains{display:grid;grid-template-columns:1fr 1fr;gap:10px}.df-domain{text-align:left;padding:18px;border-radius:var(--df-r-xl);background:var(--df-surface);border:1px solid var(--df-border);cursor:pointer;font-family:inherit;color:var(--df-text);transition:all var(--df-fast)}.df-domain--selected{background:var(--df-accent-halo);border-color:var(--df-accent)}.df-domain__icon{width:32px;height:32px;border-radius:var(--df-r-lg);background:var(--df-surface-3);display:flex;align-items:center;justify-content:center;margin-bottom:10px;color:var(--df-text-3)}.df-domain--selected .df-domain__icon{background:var(--df-accent-soft);color:var(--df-accent-text)}.df-domain__label{font-weight:500;font-size:14px}.df-domain__desc{font-size:12px;color:var(--df-text-4);margin-top:4px}.df-onboard__fields{display:flex;flex-direction:column;gap:14px}.df-onboard__input{width:100%;height:38px;padding:0 12px;border-radius:var(--df-r-lg);border:1px solid var(--df-border-2);background:var(--df-surface);color:var(--df-text);font-family:inherit;font-size:13px;outline:none}.df-onboard__input--mono{font-family:var(--df-font-mono)}.df-dropzone{padding:32px;border:1.5px dashed var(--df-border-3);border-radius:12px;text-align:center;background:#0c0c0e}.df-dropzone__title{margin-top:12px;font-size:14px;color:var(--df-text)}.df-dropzone__sub{margin-top:4px;font-size:12px;color:var(--df-text-4)}.df-init-log{background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl);padding:16px;font-family:var(--df-font-mono);font-size:12px}.df-init-log__line{display:flex;gap:10px;padding:4px 0;color:var(--df-text-3)}.df-init-log__mark--ok{color:var(--df-green)}.df-init-log__mark--run{color:var(--df-accent-text)}.df-onboard__nav{display:flex;justify-content:space-between;margin-top:32px}.df-settings{flex:1;overflow:auto;padding:40px var(--df-content-pad) 56px;max-width:980px}.df-settings__section{margin-top:20px;background:var(--df-surface);border:1px solid var(--df-border);border-radius:var(--df-r-xl);padding:16px}.df-settings__head{display:flex;align-items:center;justify-content:space-between;gap:12px}.df-settings__title{font-size:13px;color:var(--df-text);font-weight:600}.df-settings__kv{margin-top:8px;display:grid;grid-template-columns:120px 1fr;gap:10px;align-items:center;font-size:12px}.df-settings__kv>span{color:var(--df-text-4)}.df-settings__kv>code{color:var(--df-text-2);background:var(--df-surface-2);border:1px solid var(--df-border-2);border-radius:var(--df-r-sm);padding:4px 8px;font-family:var(--df-font-mono);overflow-wrap:anywhere}.df-settings__schema{margin-top:10px;width:100%;min-height:240px;border-radius:var(--df-r-md);border:1px solid var(--df-border-2);background:#0b0b0d;color:var(--df-text);padding:12px;font-size:12px;line-height:1.5;font-family:var(--df-font-mono);resize:vertical}.df-settings__bridge-row{margin:10px 0 12px;display:flex;flex-wrap:wrap;gap:8px}.df-settings__bridge{border:1px solid var(--df-border-2);background:transparent;color:var(--df-text-3);border-radius:var(--df-r-pill);font-size:12px;padding:6px 12px;cursor:pointer;font-family:inherit}.df-settings__bridge--active{background:var(--df-accent-soft);border-color:var(--df-accent-ring);color:var(--df-accent-text)}.df-settings__danger{border-color:var(--df-red-ring)}.df-settings__status{margin-top:12px;color:var(--df-accent-text);font-size:12px}