@shahmilsaari/memory-core 1.0.30 → 1.0.31
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/{chunk-M7NKSXFS.js → chunk-4ZSVQMI7.js} +52 -0
- package/dist/{chunk-OHVCPFEY.js → chunk-KNZ3JNHE.js} +12 -2
- package/dist/cli.js +4 -4
- package/dist/dashboard/assets/index-B5TFTqLb.js +2 -0
- package/dist/dashboard/assets/index-Cfkgvz08.css +1 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/{dashboard-server-OHVL64F2.js → dashboard-server-FMKL4KZG.js} +198 -3
- package/dist/{db-PRDHI2CN.js → db-Y6BXHLRN.js} +9 -1
- package/package.json +7 -7
- package/dist/dashboard/assets/index-B4vD0HC8.css +0 -1
- package/dist/dashboard/assets/index-CesnieMi.js +0 -2
|
@@ -6,23 +6,28 @@ import {
|
|
|
6
6
|
embed,
|
|
7
7
|
inferProjectArchitectures,
|
|
8
8
|
startWatch
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KNZ3JNHE.js";
|
|
10
10
|
import {
|
|
11
11
|
getChatProviderLabel
|
|
12
12
|
} from "./chunk-PQBWHAZN.js";
|
|
13
13
|
import {
|
|
14
14
|
Config,
|
|
15
15
|
closePool,
|
|
16
|
+
deleteArchProfile,
|
|
16
17
|
deleteMemory,
|
|
18
|
+
getArchProfile,
|
|
17
19
|
getPool,
|
|
20
|
+
listArchProfiles,
|
|
18
21
|
listMemories,
|
|
22
|
+
saveArchProfile,
|
|
19
23
|
saveMemory,
|
|
20
24
|
updateMemory
|
|
21
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-4ZSVQMI7.js";
|
|
22
26
|
import "./chunk-ZZBQEXEO.js";
|
|
23
27
|
|
|
24
28
|
// src/dashboard-server.ts
|
|
25
29
|
import { createHash } from "crypto";
|
|
30
|
+
import { execSync } from "child_process";
|
|
26
31
|
import { createReadStream, existsSync, mkdirSync, readFileSync, watch, writeFileSync } from "fs";
|
|
27
32
|
import { createServer } from "http";
|
|
28
33
|
import { basename, dirname, extname, join, normalize, relative, resolve } from "path";
|
|
@@ -74,12 +79,20 @@ function readViolationHistory() {
|
|
|
74
79
|
return [];
|
|
75
80
|
}
|
|
76
81
|
}
|
|
82
|
+
function getGitAuthor(file) {
|
|
83
|
+
try {
|
|
84
|
+
return execSync(`git log --format="%an" -1 -- "${file}"`, { cwd: projectRoot, stdio: ["ignore", "pipe", "ignore"], timeout: 2e3 }).toString().trim() || void 0;
|
|
85
|
+
} catch {
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
77
89
|
function appendViolationHistory(file, violations, timestamp) {
|
|
78
90
|
try {
|
|
79
91
|
const archmindDir = join(projectRoot, ".archmind");
|
|
80
92
|
mkdirSync(archmindDir, { recursive: true });
|
|
81
93
|
const history = readViolationHistory();
|
|
82
|
-
|
|
94
|
+
const author = getGitAuthor(file);
|
|
95
|
+
history.unshift({ timestamp, file, violations, author });
|
|
83
96
|
if (history.length > HISTORY_MAX) history.length = HISTORY_MAX;
|
|
84
97
|
writeFileSync(historyPath(), JSON.stringify(history, null, 2), "utf-8");
|
|
85
98
|
} catch {
|
|
@@ -680,6 +693,117 @@ async function handleApi(req, res, url) {
|
|
|
680
693
|
sendJson(res, 200, { ok: true, message: "Tune started" });
|
|
681
694
|
return;
|
|
682
695
|
}
|
|
696
|
+
if (req.method === "GET" && url.pathname === "/api/analytics") {
|
|
697
|
+
const history = readViolationHistory();
|
|
698
|
+
const archRules = archState.rules;
|
|
699
|
+
const now = Date.now();
|
|
700
|
+
const DAY = 864e5;
|
|
701
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
702
|
+
for (let i = 29; i >= 0; i--) {
|
|
703
|
+
const d = new Date(now - i * DAY).toISOString().slice(0, 10);
|
|
704
|
+
buckets.set(d, { violations: 0, files: /* @__PURE__ */ new Set() });
|
|
705
|
+
}
|
|
706
|
+
for (const entry of history) {
|
|
707
|
+
const d = entry.timestamp.slice(0, 10);
|
|
708
|
+
if (buckets.has(d)) {
|
|
709
|
+
const b = buckets.get(d);
|
|
710
|
+
b.violations += entry.violations.length;
|
|
711
|
+
b.files.add(entry.file);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
const trends = Array.from(buckets.entries()).map(([date, b]) => ({ date, violations: b.violations, files: b.files.size }));
|
|
715
|
+
const fileMap = /* @__PURE__ */ new Map();
|
|
716
|
+
for (const entry of history) {
|
|
717
|
+
const existing = fileMap.get(entry.file) ?? { count: 0, lastViolation: "", resolved: 0 };
|
|
718
|
+
existing.count += entry.violations.length;
|
|
719
|
+
if (!existing.lastViolation || entry.timestamp > existing.lastViolation) existing.lastViolation = entry.timestamp;
|
|
720
|
+
if (entry.resolved) existing.resolved++;
|
|
721
|
+
fileMap.set(entry.file, existing);
|
|
722
|
+
}
|
|
723
|
+
const fileHeat = Array.from(fileMap.entries()).map(([file, v]) => ({ file, ...v })).sort((a, b) => b.count - a.count).slice(0, 20);
|
|
724
|
+
const ruleHits = /* @__PURE__ */ new Map();
|
|
725
|
+
for (const entry of history) {
|
|
726
|
+
for (const v of entry.violations) {
|
|
727
|
+
const key = v.rule ?? "";
|
|
728
|
+
ruleHits.set(key, (ruleHits.get(key) ?? 0) + 1);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
const statsRules = (() => {
|
|
732
|
+
try {
|
|
733
|
+
return readJsonFile(join(projectRoot, ".memory-core-stats.json"), {}).rules ?? {};
|
|
734
|
+
} catch {
|
|
735
|
+
return {};
|
|
736
|
+
}
|
|
737
|
+
})();
|
|
738
|
+
const ruleEffectiveness = archRules.map((r) => ({
|
|
739
|
+
id: r.id,
|
|
740
|
+
name: r.name,
|
|
741
|
+
fromLayer: r.fromLayer,
|
|
742
|
+
toLayer: r.toLayer,
|
|
743
|
+
allowed: r.allowed,
|
|
744
|
+
enforcement: r.enforcement,
|
|
745
|
+
hitCount: (statsRules[r.id] ?? 0) + (ruleHits.get(r.name) ?? 0),
|
|
746
|
+
lastFired: history.find((e) => e.violations.some((v) => v.rule === r.name || v.rule === r.id))?.timestamp ?? null
|
|
747
|
+
})).sort((a, b) => b.hitCount - a.hitCount);
|
|
748
|
+
const authorMap = /* @__PURE__ */ new Map();
|
|
749
|
+
for (const entry of history) {
|
|
750
|
+
const author = entry.author ?? "Unknown";
|
|
751
|
+
const existing = authorMap.get(author) ?? { violations: 0, files: /* @__PURE__ */ new Set(), lastSeen: "" };
|
|
752
|
+
existing.violations += entry.violations.length;
|
|
753
|
+
existing.files.add(entry.file);
|
|
754
|
+
if (!existing.lastSeen || entry.timestamp > existing.lastSeen) existing.lastSeen = entry.timestamp;
|
|
755
|
+
authorMap.set(author, existing);
|
|
756
|
+
}
|
|
757
|
+
const teamActivity = Array.from(authorMap.entries()).map(([author, v]) => ({ author, violations: v.violations, files: v.files.size, lastSeen: v.lastSeen })).sort((a, b) => b.violations - a.violations);
|
|
758
|
+
sendJson(res, 200, {
|
|
759
|
+
trends,
|
|
760
|
+
fileHeat,
|
|
761
|
+
ruleEffectiveness,
|
|
762
|
+
teamActivity,
|
|
763
|
+
summary: {
|
|
764
|
+
total: history.reduce((s, e) => s + e.violations.length, 0),
|
|
765
|
+
resolved: history.filter((e) => e.resolved).length,
|
|
766
|
+
open: history.filter((e) => !e.resolved).length,
|
|
767
|
+
uniqueFiles: new Set(history.map((e) => e.file)).size
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
if (req.method === "DELETE" && url.pathname === "/api/history") {
|
|
773
|
+
try {
|
|
774
|
+
const path = historyPath();
|
|
775
|
+
if (existsSync(path)) writeFileSync(path, "[]", "utf-8");
|
|
776
|
+
scheduleSnapshotBroadcast();
|
|
777
|
+
sendJson(res, 200, { ok: true });
|
|
778
|
+
} catch (err) {
|
|
779
|
+
sendJson(res, 500, { error: err.message });
|
|
780
|
+
}
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
if (req.method === "POST" && url.pathname === "/api/history/resolve") {
|
|
784
|
+
const body = await readBody(req);
|
|
785
|
+
const timestamp = typeof body.timestamp === "string" ? body.timestamp : "";
|
|
786
|
+
if (!timestamp) {
|
|
787
|
+
sendJson(res, 400, { error: "timestamp required" });
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
try {
|
|
791
|
+
const history = readViolationHistory();
|
|
792
|
+
const entry = history.find((e) => e.timestamp === timestamp);
|
|
793
|
+
if (!entry) {
|
|
794
|
+
sendJson(res, 404, { error: "Entry not found" });
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
entry.resolved = !entry.resolved;
|
|
798
|
+
entry.resolvedAt = entry.resolved ? (/* @__PURE__ */ new Date()).toISOString() : void 0;
|
|
799
|
+
writeFileSync(historyPath(), JSON.stringify(history, null, 2), "utf-8");
|
|
800
|
+
scheduleSnapshotBroadcast();
|
|
801
|
+
sendJson(res, 200, { ok: true, resolved: entry.resolved });
|
|
802
|
+
} catch (err) {
|
|
803
|
+
sendJson(res, 500, { error: err.message });
|
|
804
|
+
}
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
683
807
|
if (req.method === "POST" && url.pathname === "/api/arch/layers") {
|
|
684
808
|
const body = await readBody(req);
|
|
685
809
|
const name = typeof body.name === "string" ? body.name.trim() : "";
|
|
@@ -774,6 +898,77 @@ async function handleApi(req, res, url) {
|
|
|
774
898
|
sendJson(res, 200, { ok: true, arch });
|
|
775
899
|
return;
|
|
776
900
|
}
|
|
901
|
+
if (req.method === "GET" && url.pathname === "/api/arch/profiles") {
|
|
902
|
+
try {
|
|
903
|
+
const projectConfig = readProjectConfig();
|
|
904
|
+
const profiles = await listArchProfiles(projectConfig?.projectName ?? void 0);
|
|
905
|
+
sendJson(res, 200, { profiles });
|
|
906
|
+
} catch {
|
|
907
|
+
sendJson(res, 200, { profiles: [] });
|
|
908
|
+
}
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
if (req.method === "POST" && url.pathname === "/api/arch/profiles") {
|
|
912
|
+
const body = await readBody(req);
|
|
913
|
+
const name = typeof body.name === "string" ? body.name.trim() : "";
|
|
914
|
+
if (!name) {
|
|
915
|
+
sendJson(res, 400, { error: "name is required" });
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
const projectConfig = readProjectConfig();
|
|
919
|
+
const arch = projectConfig?.backendArchitecture ?? projectConfig?.frontendFramework ?? "custom";
|
|
920
|
+
const layers = archState.layers;
|
|
921
|
+
const rules = archState.rules;
|
|
922
|
+
try {
|
|
923
|
+
const profile = await saveArchProfile({
|
|
924
|
+
name,
|
|
925
|
+
archType: arch,
|
|
926
|
+
layers,
|
|
927
|
+
rules,
|
|
928
|
+
projectName: typeof body.projectScoped === "boolean" && body.projectScoped ? projectConfig?.projectName ?? void 0 : void 0
|
|
929
|
+
});
|
|
930
|
+
sendJson(res, 201, { ok: true, profile });
|
|
931
|
+
} catch (err) {
|
|
932
|
+
sendJson(res, 500, { error: err.message });
|
|
933
|
+
}
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
const profileMatch = url.pathname.match(/^\/api\/arch\/profiles\/(\d+)$/);
|
|
937
|
+
if (profileMatch) {
|
|
938
|
+
const profileId = parseInt(profileMatch[1], 10);
|
|
939
|
+
if (req.method === "DELETE") {
|
|
940
|
+
try {
|
|
941
|
+
const deleted = await deleteArchProfile(profileId);
|
|
942
|
+
sendJson(res, deleted ? 200 : 404, deleted ? { ok: true } : { error: "Profile not found" });
|
|
943
|
+
} catch (err) {
|
|
944
|
+
sendJson(res, 500, { error: err.message });
|
|
945
|
+
}
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
if (req.method === "POST" && url.pathname.endsWith("/apply")) {
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
const profileApplyMatch = url.pathname.match(/^\/api\/arch\/profiles\/(\d+)\/apply$/);
|
|
952
|
+
if (profileApplyMatch && req.method === "POST") {
|
|
953
|
+
const profileId = parseInt(profileApplyMatch[1], 10);
|
|
954
|
+
try {
|
|
955
|
+
const profile = await getArchProfile(profileId);
|
|
956
|
+
if (!profile) {
|
|
957
|
+
sendJson(res, 404, { error: "Profile not found" });
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
const archmindDir = join(projectRoot, ".archmind");
|
|
961
|
+
mkdirSync(archmindDir, { recursive: true });
|
|
962
|
+
writeFileSync(join(archmindDir, "layers.json"), JSON.stringify({ layers: profile.layers }, null, 2) + "\n", "utf-8");
|
|
963
|
+
writeFileSync(join(archmindDir, "rules.json"), JSON.stringify({ rules: profile.rules }, null, 2) + "\n", "utf-8");
|
|
964
|
+
readArchState();
|
|
965
|
+
scheduleSnapshotBroadcast();
|
|
966
|
+
sendJson(res, 200, { ok: true, profile });
|
|
967
|
+
} catch (err) {
|
|
968
|
+
sendJson(res, 500, { error: err.message });
|
|
969
|
+
}
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
777
972
|
sendJson(res, 404, { error: "Not found" });
|
|
778
973
|
} catch (err) {
|
|
779
974
|
sendJson(res, 500, { error: err.message });
|
|
@@ -1,27 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
closePool,
|
|
4
|
+
deleteArchProfile,
|
|
4
5
|
deleteMemories,
|
|
5
6
|
deleteMemory,
|
|
7
|
+
getArchProfile,
|
|
6
8
|
getMemory,
|
|
7
9
|
getPool,
|
|
8
10
|
hashMemoryContent,
|
|
11
|
+
listArchProfiles,
|
|
9
12
|
listMemories,
|
|
10
13
|
runMigrations,
|
|
14
|
+
saveArchProfile,
|
|
11
15
|
saveMemory,
|
|
12
16
|
searchMemories,
|
|
13
17
|
updateMemory,
|
|
14
18
|
upsertMemory
|
|
15
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-4ZSVQMI7.js";
|
|
16
20
|
export {
|
|
17
21
|
closePool,
|
|
22
|
+
deleteArchProfile,
|
|
18
23
|
deleteMemories,
|
|
19
24
|
deleteMemory,
|
|
25
|
+
getArchProfile,
|
|
20
26
|
getMemory,
|
|
21
27
|
getPool,
|
|
22
28
|
hashMemoryContent,
|
|
29
|
+
listArchProfiles,
|
|
23
30
|
listMemories,
|
|
24
31
|
runMigrations,
|
|
32
|
+
saveArchProfile,
|
|
25
33
|
saveMemory,
|
|
26
34
|
searchMemories,
|
|
27
35
|
updateMemory,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shahmilsaari/memory-core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"description": "Universal AI memory core — generate AI context files from architecture profiles with RAG support",
|
|
5
5
|
"homepage": "https://memory-core.shahmilsaari.my/",
|
|
6
6
|
"type": "module",
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"release:patch": "npm version patch --no-git-tag-version && npm run build && npm publish --access public",
|
|
18
18
|
"release:minor": "npm version minor --no-git-tag-version && npm run build && npm publish --access public",
|
|
19
19
|
"release:major": "npm version major --no-git-tag-version && npm run build && npm publish --access public",
|
|
20
|
-
"docs:start": "npm run
|
|
21
|
-
"docs:build": "
|
|
22
|
-
"docs:serve": "npm run
|
|
23
|
-
"site:build": "npm run
|
|
24
|
-
"site:serve": "
|
|
25
|
-
"site:start": "npm
|
|
20
|
+
"docs:start": "npm --prefix website run start",
|
|
21
|
+
"docs:build": "npm --prefix website run build",
|
|
22
|
+
"docs:serve": "npm --prefix website run serve",
|
|
23
|
+
"site:build": "npm --prefix website run build",
|
|
24
|
+
"site:serve": "npm --prefix website run serve",
|
|
25
|
+
"site:start": "npm --prefix website run start",
|
|
26
26
|
"typecheck": "tsc --noEmit",
|
|
27
27
|
"lint": "node scripts/lint.mjs",
|
|
28
28
|
"smoke:pack": "node scripts/pack-smoke.mjs",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
:root{color-scheme:light dark;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}body{margin:0;min-width:320px;min-height:100vh}button,input,select,textarea{font:inherit}button{border:0}:root{--primary: #0040e0;--primary-dim: #2e5bff;--primary-container: #efefff;--on-primary: #ffffff;--surface: #f8f9fb;--surface-low: #f3f4f6;--surface-mid: #edeef0;--surface-high: #e7e8ea;--surface-highest: #e1e2e4;--on-surface: #191c1e;--on-surface-var: #434656;--outline: #747688;--outline-var: #c4c5d9;--error: #ba1a1a;--error-bg: #ffdad6;--tertiary: #993100;--green: #10b981;--green-bg: rgba(16,185,129,.1);--green-border: rgba(16,185,129,.3);--mono: "JetBrains Mono", "SFMono-Regular", Consolas, monospace;--sans: "Hanken Grotesk", Inter, ui-sans-serif, system-ui, sans-serif}body{margin:0;background:var(--surface);color:var(--on-surface);font-family:var(--sans);font-size:14px;overflow:hidden;height:100vh}*{box-sizing:border-box}::-webkit-scrollbar{width:5px;height:5px}::-webkit-scrollbar-track{background:var(--surface-low)}::-webkit-scrollbar-thumb{background:var(--outline-var);border-radius:4px}.shell.svelte-d3ct2b{display:flex;flex-direction:column;height:100vh;overflow:hidden}.topbar.svelte-d3ct2b{display:flex;align-items:center;gap:16px;height:64px;padding:0 24px;background:var(--surface);border-bottom:1px solid var(--outline-var);flex-shrink:0;z-index:30}.topbar-brand.svelte-d3ct2b{display:flex;align-items:center;gap:24px;flex-shrink:0}.brand-name.svelte-d3ct2b{font-size:18px;font-weight:700;color:var(--on-surface);font-family:var(--sans);letter-spacing:-.02em}.topbar-nav.svelte-d3ct2b{display:flex;gap:2px}.tab-btn.svelte-d3ct2b{padding:6px 12px;background:transparent;border:none;border-bottom:2px solid transparent;color:var(--on-surface-var);font-family:var(--mono);font-size:11px;font-weight:600;letter-spacing:.04em;cursor:pointer;text-transform:uppercase;transition:color .15s,border-color .15s}.tab-btn.svelte-d3ct2b:hover{color:var(--primary)}.tab-active.svelte-d3ct2b{color:var(--primary)!important;border-bottom-color:var(--primary);font-weight:700}.topbar-search.svelte-d3ct2b{flex:1;max-width:480px;margin:0 auto;position:relative}.search-icon.svelte-d3ct2b{position:absolute;left:12px;top:50%;transform:translateY(-50%);color:var(--on-surface-var);font-size:18px;pointer-events:none;line-height:1}.search-input.svelte-d3ct2b{width:100%;height:36px;padding:0 12px 0 36px;background:var(--surface-mid);border:1px solid var(--outline-var);border-radius:8px;color:var(--on-surface);font-family:var(--sans);font-size:13px;outline:none;transition:border-color .15s}.search-input.svelte-d3ct2b:focus{border-color:var(--primary-dim)}.topbar-actions.svelte-d3ct2b{display:flex;align-items:center;gap:4px;flex-shrink:0}.icon-btn.svelte-d3ct2b{width:34px;height:34px;display:flex;align-items:center;justify-content:center;background:transparent;border:none;border-radius:8px;color:var(--on-surface-var);cursor:pointer;transition:background .15s,color .15s}.icon-btn.svelte-d3ct2b:hover{background:var(--surface-low);color:var(--primary)}.icon-btn-active.svelte-d3ct2b{color:var(--primary)!important;background:var(--primary-container)!important}.avatar.svelte-d3ct2b{width:32px;height:32px;border-radius:50%;background:var(--primary-dim);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:13px;margin-left:8px;border:1px solid var(--outline-var);flex-shrink:0;cursor:default}.body.svelte-d3ct2b{display:flex;flex:1;min-height:0;overflow:hidden}.sidebar.svelte-d3ct2b{width:64px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;padding:16px 0;background:#fff;border-right:1px solid var(--outline-var);z-index:20}.sidebar-logo.svelte-d3ct2b{width:40px;height:40px;background:var(--primary-dim);border-radius:4px;display:flex;align-items:center;justify-content:center;color:#fff;margin-bottom:24px}.sidebar-nav.svelte-d3ct2b{display:flex;flex-direction:column;gap:8px}.side-btn.svelte-d3ct2b{width:36px;height:36px;display:flex;align-items:center;justify-content:center;background:transparent;border:none;border-right:2px solid transparent;color:var(--on-surface-var);cursor:pointer;transition:color .15s;margin-right:-1px}.side-btn.svelte-d3ct2b:hover{color:var(--primary)}.side-btn-active.svelte-d3ct2b{color:var(--primary)!important;background:#0040e014;border-right-color:var(--primary)}.sidebar-footer-dot.svelte-d3ct2b{margin-top:auto;width:8px;height:8px;border-radius:50%;background:var(--outline)}.dot-live.svelte-d3ct2b{background:var(--green)!important;box-shadow:0 0 6px var(--green)}.content.svelte-d3ct2b{flex:1;min-width:0;display:flex;flex-direction:column;overflow:hidden;background:var(--surface)}.health-bar.svelte-d3ct2b{display:flex;align-items:center;gap:8px;padding:6px 24px;border-bottom:1px solid var(--outline-var);background:#fff;flex-shrink:0;flex-wrap:wrap}.health-label.svelte-d3ct2b{font-family:var(--mono);font-size:10px;font-weight:700;color:var(--outline);text-transform:uppercase;letter-spacing:.06em;margin-right:4px}.health-badge.svelte-d3ct2b{display:flex;align-items:center;gap:4px;padding:2px 8px;border-radius:4px;font-family:var(--mono);font-size:10px;font-weight:700}.health-green.svelte-d3ct2b{background:var(--green-bg);color:var(--green);border:1px solid var(--green-border)}.health-blue.svelte-d3ct2b{background:#0040e014;color:var(--primary);border:1px solid rgba(0,64,224,.2)}.health-warn.svelte-d3ct2b{background:#ba1a1a14;color:var(--error);border:1px solid rgba(186,26,26,.25)}.health-error.svelte-d3ct2b{font-family:var(--mono);font-size:10px;color:var(--error);font-weight:700}.dot.svelte-d3ct2b{width:6px;height:6px;border-radius:50%;flex-shrink:0}.dot-green.svelte-d3ct2b{background:var(--green)}.dot-blue.svelte-d3ct2b{background:var(--primary)}.dot-warn.svelte-d3ct2b{background:var(--error)}.dot-pulse.svelte-d3ct2b{animation:svelte-d3ct2b-pulse 1.4s ease-in-out infinite}@keyframes svelte-d3ct2b-pulse{0%,to{opacity:1}50%{opacity:.35}}.filter-bar.svelte-d3ct2b{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 24px;background:var(--surface-low);border-bottom:1px solid var(--outline-var);flex-shrink:0}.filter-left.svelte-d3ct2b,.filter-right.svelte-d3ct2b{display:flex;align-items:center;gap:8px}.chip.svelte-d3ct2b{display:flex;align-items:center;gap:4px;padding:4px 10px;border-radius:8px;font-family:var(--mono);font-size:11px;font-weight:600;cursor:pointer;white-space:nowrap;border:none}.chip-primary.svelte-d3ct2b{background:var(--primary-dim);color:#fff}.chip-close.svelte-d3ct2b{background:transparent;border:none;color:#fffc;cursor:pointer;padding:0;font-size:10px;line-height:1}.chip-outline.svelte-d3ct2b{background:var(--surface);color:var(--on-surface-var);border:1px solid var(--outline-var);transition:border-color .15s}.chip-outline.svelte-d3ct2b:hover{border-color:var(--primary-dim)}.chevron.svelte-d3ct2b{transition:transform .2s}.chevron-open.svelte-d3ct2b{transform:rotate(180deg)}.service-dropdown-wrap.svelte-d3ct2b{position:relative}.dropdown.svelte-d3ct2b{position:absolute;top:calc(100% + 4px);left:0;min-width:180px;background:#fff;border:1px solid var(--outline-var);border-radius:8px;box-shadow:0 8px 24px #0000001f;z-index:100;overflow:hidden;animation:svelte-d3ct2b-dropIn .12s ease}@keyframes svelte-d3ct2b-dropIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.dropdown-item.svelte-d3ct2b{display:flex;align-items:center;gap:8px;width:100%;padding:10px 14px;background:transparent;border:none;color:var(--on-surface-var);font-family:var(--sans);font-size:13px;font-weight:500;cursor:pointer;transition:background .12s;text-align:left}.dropdown-item.svelte-d3ct2b:hover{background:var(--surface-low)}.dropdown-item-active.svelte-d3ct2b{color:var(--primary);background:var(--primary-container)}.dropdown-item-active.svelte-d3ct2b:hover{background:var(--primary-container)}.dropdown-badge.svelte-d3ct2b{margin-left:auto;background:var(--error);color:#fff;border-radius:999px;padding:1px 6px;font-size:10px;font-weight:700}.divider-v.svelte-d3ct2b{width:1px;height:28px;background:var(--outline-var);margin:0 4px}.metrics-strip.svelte-d3ct2b{display:flex;align-items:center;gap:24px}.metric-item.svelte-d3ct2b{display:flex;flex-direction:column;align-items:center}.metric-label.svelte-d3ct2b{font-family:var(--mono);font-size:9px;font-weight:700;color:var(--outline);text-transform:uppercase;letter-spacing:.05em;line-height:1}.metric-value.svelte-d3ct2b{font-family:var(--mono);font-size:14px;font-weight:700;color:var(--on-surface);line-height:1.4}.metric-value-warn.svelte-d3ct2b{color:var(--error)}.live-badge.svelte-d3ct2b{display:flex;align-items:center;gap:6px;padding:4px 10px;border:1px solid var(--outline-var);border-radius:8px;background:#fff;font-family:var(--mono);font-size:11px;font-weight:600;color:var(--on-surface);white-space:nowrap}.feed-area.svelte-d3ct2b{flex:1;min-height:0;overflow-y:auto;padding:12px 24px;background:#fff;font-family:var(--mono);font-size:12px}.log-row.svelte-d3ct2b{display:flex;align-items:baseline;gap:12px;padding:3px 8px;border-radius:4px;transition:background .1s;min-height:22px}.log-row.svelte-d3ct2b:hover{background:var(--surface-low)}.log-row-warn.svelte-d3ct2b{background:#ba1a1a0a}.log-row-fail.svelte-d3ct2b{background:#9931000a}.log-time.svelte-d3ct2b{width:80px;flex-shrink:0;color:var(--outline)}.log-label.svelte-d3ct2b{width:56px;flex-shrink:0;font-weight:700}.label-sys.svelte-d3ct2b{color:var(--primary)}.label-ok.svelte-d3ct2b{color:var(--green)}.label-warn.svelte-d3ct2b{color:var(--tertiary)}.label-info.svelte-d3ct2b{color:var(--on-surface-var)}.label-hook.svelte-d3ct2b{color:var(--error)}.label-chck.svelte-d3ct2b{color:var(--outline)}.log-msg.svelte-d3ct2b{flex:1;min-width:0;color:var(--on-surface-var);word-break:break-all;line-height:1.5}.log-msg.svelte-d3ct2b strong:where(.svelte-d3ct2b){color:var(--on-surface);font-weight:600}.copy-btn.svelte-d3ct2b{opacity:0;background:transparent;border:none;color:var(--outline);cursor:pointer;font-size:14px;padding:0 4px;transition:opacity .15s,color .15s;flex-shrink:0}.log-row.svelte-d3ct2b:hover .copy-btn:where(.svelte-d3ct2b){opacity:1}.copy-btn.svelte-d3ct2b:hover{color:var(--primary)}.log-detail.svelte-d3ct2b{display:flex;gap:8px;padding:3px 8px 3px 148px;font-size:11px;border-left:2px solid rgba(153,49,0,.3);margin-left:8px;margin-bottom:2px}.detail-index.svelte-d3ct2b{color:var(--outline);flex-shrink:0;width:24px}.detail-body.svelte-d3ct2b{color:var(--on-surface-var);flex:1;min-width:0;line-height:1.5}.detail-fix.svelte-d3ct2b{color:var(--primary)}.cursor-blink.svelte-d3ct2b{animation:svelte-d3ct2b-blink 1s step-start infinite}@keyframes svelte-d3ct2b-blink{0%,to{opacity:1}50%{opacity:0}}.section-header.svelte-d3ct2b{display:flex;align-items:baseline;gap:12px;padding:8px 8px 10px;border-bottom:1px solid var(--outline-var);margin-bottom:8px}.section-title.svelte-d3ct2b{font-family:var(--sans);font-size:14px;font-weight:700;color:var(--on-surface)}.section-meta.svelte-d3ct2b{font-size:11px;color:var(--outline);font-family:var(--mono)}.rules-toolbar.svelte-d3ct2b{display:flex;gap:8px;padding:8px;margin-bottom:4px}.rules-select.svelte-d3ct2b,.rules-input.svelte-d3ct2b,.rules-textarea.svelte-d3ct2b{padding:6px 10px;background:var(--surface-low);border:1px solid var(--outline-var);border-radius:6px;color:var(--on-surface);font-family:var(--sans);font-size:13px;outline:none;transition:border-color .15s}.rules-select.svelte-d3ct2b:focus,.rules-input.svelte-d3ct2b:focus,.rules-textarea.svelte-d3ct2b:focus{border-color:var(--primary-dim)}.rules-textarea.svelte-d3ct2b{resize:vertical;flex:1;min-width:0}.rule-form-wrap.svelte-d3ct2b{padding:0 8px 8px;border-bottom:1px solid var(--outline-var);margin-bottom:8px}.rule-form.svelte-d3ct2b{display:flex;flex-direction:column;gap:8px}.rule-form-row.svelte-d3ct2b{display:flex;gap:8px;align-items:flex-start}.add-btn.svelte-d3ct2b{padding:8px 16px;background:var(--primary);color:var(--on-primary);border:none;border-radius:6px;font-family:var(--mono);font-size:12px;font-weight:700;cursor:pointer;white-space:nowrap;transition:background .15s;align-self:flex-end}.add-btn.svelte-d3ct2b:hover:not(:disabled){background:var(--primary-dim)}.add-btn.svelte-d3ct2b:disabled{opacity:.5;cursor:not-allowed}.rule-list.svelte-d3ct2b{display:flex;flex-direction:column;gap:4px;overflow-y:auto;max-height:400px;padding:0 8px}.rule-row.svelte-d3ct2b{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--outline-var);border-radius:6px;background:var(--surface-low);font-size:12px;min-width:0;transition:background .1s}.rule-row.svelte-d3ct2b:hover{background:var(--surface-mid)}.rule-badge.svelte-d3ct2b{padding:2px 7px;background:var(--primary-container);color:var(--primary);border-radius:4px;font-family:var(--mono);font-size:10px;font-weight:700;text-transform:uppercase;flex-shrink:0}.rule-scope.svelte-d3ct2b{color:var(--outline);font-family:var(--mono);font-size:10px;font-weight:600;flex-shrink:0}.rule-content.svelte-d3ct2b{flex:1;min-width:0;color:var(--on-surface);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rule-reason.svelte-d3ct2b{color:var(--on-surface-var);font-size:11px;flex-shrink:0;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.del-btn.svelte-d3ct2b{background:transparent;border:none;color:var(--outline);cursor:pointer;font-size:12px;padding:2px 6px;border-radius:4px;flex-shrink:0;transition:background .1s,color .1s}.del-btn.svelte-d3ct2b:hover{background:var(--error-bg);color:var(--error)}.metrics-footer.svelte-d3ct2b{display:flex;align-items:center;justify-content:space-between;height:48px;padding:0 24px;border-top:1px solid var(--outline-var);background:var(--surface);flex-shrink:0}.footer-left.svelte-d3ct2b,.footer-right.svelte-d3ct2b{display:flex;align-items:center;gap:24px}.footer-metric.svelte-d3ct2b{display:flex;align-items:center;gap:6px}.footer-label.svelte-d3ct2b{font-family:var(--mono);font-size:10px;font-weight:700;color:var(--outline);text-transform:uppercase;letter-spacing:.04em}.footer-val.svelte-d3ct2b{font-family:var(--mono);font-size:14px;font-weight:700;color:var(--on-surface)}.footer-val-error.svelte-d3ct2b{color:var(--error)}.footer-unit.svelte-d3ct2b{font-family:var(--mono);font-size:9px;color:var(--outline);text-transform:uppercase}.storage-bar-wrap.svelte-d3ct2b{display:flex;align-items:center;gap:8px}.storage-bar.svelte-d3ct2b{width:96px;height:6px;background:var(--surface-mid);border-radius:999px;overflow:hidden}.storage-fill.svelte-d3ct2b{height:100%;background:var(--primary-dim);border-radius:999px;transition:width .6s ease}.cli-btn.svelte-d3ct2b{display:flex;align-items:center;gap:6px;padding:5px 12px;background:var(--surface-high);border:none;border-radius:4px;color:var(--on-surface);font-family:var(--mono);font-size:11px;font-weight:700;cursor:pointer;transition:background .15s}.cli-btn.svelte-d3ct2b:hover{background:var(--outline-var)}:root[data-theme=dark]{--primary: #b8c3ff;--primary-dim: #4d6dff;--primary-container: #1a2340;--on-primary: #001b3e;--surface: #111318;--surface-low: #0c0e12;--surface-mid: #1e2024;--surface-high: #282a2e;--surface-highest: #37393e;--on-surface: #e2e2e8;--on-surface-var: #c4c5d9;--outline: #747688;--outline-var: #3a3c4a;--error: #ffb4ab;--error-bg: rgba(147,0,10,.22);--tertiary: #ffb59b;--green: #03f59b;--green-bg: rgba(3,245,155,.1);--green-border: rgba(3,245,155,.28)}html[data-theme=dark] .topbar.svelte-d3ct2b{background:#1a1c20;border-bottom-color:var(--outline-var)}html[data-theme=dark] .sidebar.svelte-d3ct2b{background:#0c0e12;border-right-color:var(--outline-var)}html[data-theme=dark] .health-bar.svelte-d3ct2b{background:#1a1c20;border-bottom-color:var(--outline-var)}html[data-theme=dark] .filter-bar.svelte-d3ct2b{background:#111318;border-bottom-color:var(--outline-var)}html[data-theme=dark] .feed-area.svelte-d3ct2b{background:#0c0e12}html[data-theme=dark] .metrics-footer.svelte-d3ct2b{background:#111318;border-top-color:var(--outline-var)}html[data-theme=dark] .search-input.svelte-d3ct2b{background:#1e2024;border-color:var(--outline-var);color:var(--on-surface)}html[data-theme=dark] .dropdown.svelte-d3ct2b{background:#1e2024;border-color:var(--outline-var);box-shadow:0 8px 24px #00000073}html[data-theme=dark] .dropdown-item.svelte-d3ct2b:hover{background:#282a2e}html[data-theme=dark] .dropdown-item-active.svelte-d3ct2b{background:var(--primary-container);color:var(--primary)}html[data-theme=dark] .chip-outline.svelte-d3ct2b,html[data-theme=dark] .live-badge.svelte-d3ct2b{background:#1e2024}html[data-theme=dark] .rule-row.svelte-d3ct2b{background:#1e2024;border-color:var(--outline-var)}html[data-theme=dark] .rule-row.svelte-d3ct2b:hover{background:#282a2e}html[data-theme=dark] .rules-select.svelte-d3ct2b,html[data-theme=dark] .rules-input.svelte-d3ct2b,html[data-theme=dark] .rules-textarea.svelte-d3ct2b{background:#1e2024;border-color:var(--outline-var);color:var(--on-surface)}html[data-theme=dark] .log-row.svelte-d3ct2b:hover{background:#1e2024}html[data-theme=dark] .log-row-warn.svelte-d3ct2b{background:#ffb4ab0d}html[data-theme=dark] .log-row-fail.svelte-d3ct2b{background:#ffba200a}html[data-theme=dark] .section-header.svelte-d3ct2b{border-bottom-color:var(--outline-var)}html[data-theme=dark] .storage-bar.svelte-d3ct2b{background:#282a2e}html[data-theme=dark] .badge-warn.svelte-d3ct2b{background:#422006;color:#fbbf24}html[data-theme=dark] .log-detail.svelte-d3ct2b{border-left-color:#ffba204d}html[data-theme=dark] .history-entry.svelte-d3ct2b{border-color:var(--outline-var);background:#1a1c20}html[data-theme=dark] .history-header.svelte-d3ct2b{background:#1e2024;border-bottom-color:var(--outline-var)}html[data-theme=dark] .history-violation.svelte-d3ct2b{border-bottom-color:var(--outline-var)}html[data-theme=dark] .arch-node-panel.svelte-d3ct2b{background:#1a1c20;border-color:var(--outline-var)}html[data-theme=dark] .arch-node-panel-path.svelte-d3ct2b{background:#1e2024}html[data-theme=dark] .arch-rule-row.svelte-d3ct2b{background:#1a1c20;border-color:var(--outline-var)}html[data-theme=dark] .arch-svg.svelte-d3ct2b{background:#0c0e12;border-color:var(--outline-var)}html[data-theme=dark] .footer-actions.svelte-d3ct2b .action-btn:where(.svelte-d3ct2b){background:#1e2024}html[data-theme=dark] .cli-btn.svelte-d3ct2b{background:#1e2024}html[data-theme=dark] .modal-status-row.svelte-d3ct2b{border-bottom-color:var(--outline-var)}html[data-theme=dark] .modal-input.svelte-d3ct2b{background:#1e2024;border-color:var(--outline-var);color:var(--on-surface)}html[data-theme=dark] .modal-btn.svelte-d3ct2b{background:#1e2024;border-color:var(--outline-var);color:var(--on-surface-var)}html[data-theme=dark] .modal-btn.svelte-d3ct2b:hover:not(:disabled){background:#282a2e}html[data-theme=dark] .rule-form-wrap.svelte-d3ct2b{border-bottom-color:var(--outline-var)}@media (max-width: 768px){.sidebar.svelte-d3ct2b,.topbar-nav.svelte-d3ct2b,.metrics-strip.svelte-d3ct2b{display:none}.filter-bar.svelte-d3ct2b,.feed-area.svelte-d3ct2b{padding:8px 12px}.metrics-footer.svelte-d3ct2b{padding:0 12px;gap:12px}.footer-metric.svelte-d3ct2b:nth-child(n+2){display:none}}.footer-actions.svelte-d3ct2b{display:flex;gap:6px;align-items:center;margin-right:12px}.action-btn.svelte-d3ct2b{font-size:11px;font-family:var(--mono);padding:4px 10px;border-radius:6px;border:1px solid var(--outline-var);background:var(--surface-low);color:var(--on-surface-var);cursor:pointer;transition:background .15s,border-color .15s}.action-btn.svelte-d3ct2b:hover:not(:disabled){background:var(--primary-container);border-color:var(--primary);color:var(--primary)}.action-btn.svelte-d3ct2b:disabled{opacity:.5;cursor:not-allowed}.action-btn-warn.svelte-d3ct2b:hover:not(:disabled){background:#fff3e0;border-color:#f59e0b;color:#b45309}.modal-backdrop.svelte-d3ct2b{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000073;display:flex;align-items:center;justify-content:center;z-index:200}.modal.svelte-d3ct2b{background:var(--surface);border:1px solid var(--outline-var);border-radius:12px;width:480px;max-width:calc(100vw - 32px);box-shadow:0 8px 32px #0000002e;overflow:hidden}.modal-header.svelte-d3ct2b{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 12px;border-bottom:1px solid var(--outline-var)}.modal-title.svelte-d3ct2b{font-size:14px;font-weight:600;color:var(--on-surface)}.modal-close.svelte-d3ct2b{background:none;border:none;cursor:pointer;color:var(--outline);font-size:16px;line-height:1}.modal-section.svelte-d3ct2b{padding:16px 20px;border-bottom:1px solid var(--outline-var)}.modal-section.svelte-d3ct2b:last-child{border-bottom:none}.modal-section-title.svelte-d3ct2b{font-size:11px;font-weight:600;letter-spacing:.06em;color:var(--outline);text-transform:uppercase;margin-bottom:12px}.modal-row.svelte-d3ct2b{display:grid;grid-template-columns:100px 1fr;gap:8px;align-items:center;margin-bottom:10px}.modal-label.svelte-d3ct2b{font-size:12px;color:var(--on-surface-var)}.modal-input.svelte-d3ct2b{font-size:12px;font-family:var(--mono);padding:6px 10px;border:1px solid var(--outline-var);border-radius:6px;background:var(--surface-low);color:var(--on-surface);outline:none;width:100%}.modal-input.svelte-d3ct2b:focus{border-color:var(--primary)}.modal-row-actions.svelte-d3ct2b{display:flex;gap:8px}.modal-btn.svelte-d3ct2b{font-size:12px;padding:6px 14px;border:1px solid var(--outline-var);border-radius:6px;background:var(--surface-low);color:var(--on-surface-var);cursor:pointer}.modal-btn.svelte-d3ct2b:hover:not(:disabled){background:var(--surface-mid)}.modal-btn.svelte-d3ct2b:disabled{opacity:.5;cursor:not-allowed}.modal-btn-primary.svelte-d3ct2b{background:var(--primary);color:var(--on-primary);border-color:var(--primary)}.modal-btn-primary.svelte-d3ct2b:hover:not(:disabled){background:var(--primary-dim)}.modal-msg.svelte-d3ct2b{font-size:12px;margin-top:8px;padding:6px 10px;border-radius:6px}.modal-msg-ok.svelte-d3ct2b{background:var(--green-bg);color:var(--green);border:1px solid var(--green-border)}.modal-msg-err.svelte-d3ct2b{background:var(--error-bg);color:var(--error);border:1px solid var(--error)}.modal-status-row.svelte-d3ct2b{display:flex;justify-content:space-between;padding:4px 0;border-bottom:1px solid var(--surface-mid)}.modal-status-row.svelte-d3ct2b:last-child{border-bottom:none}.modal-status-label.svelte-d3ct2b{font-size:11px;color:var(--outline)}.modal-status-val.svelte-d3ct2b{font-size:11px;font-family:var(--mono);color:var(--on-surface)}html[data-theme=dark] .modal.svelte-d3ct2b{background:var(--surface);border-color:var(--outline-var)}.arch-graph-wrap.svelte-d3ct2b{display:flex;flex-direction:column;gap:16px;padding:16px}.arch-svg.svelte-d3ct2b{display:block;border:1px solid var(--outline-var);border-radius:8px;background:var(--surface-low);width:100%;max-width:640px}.arch-node-rect.svelte-d3ct2b{fill:var(--surface-mid);stroke:var(--outline-var);stroke-width:1.5}.arch-node-domain.arch-node-rect.svelte-d3ct2b{fill:#eff6ff;stroke:#3b82f6}.arch-node-application.arch-node-rect.svelte-d3ct2b{fill:#f0fdf4;stroke:#22c55e}.arch-node-infrastructure.arch-node-rect.svelte-d3ct2b{fill:#fff7ed;stroke:#f97316}.arch-node-api.arch-node-rect.svelte-d3ct2b{fill:#faf5ff;stroke:#a855f7}.arch-node-shared.arch-node-rect.svelte-d3ct2b{fill:#f8fafc;stroke:#94a3b8}.arch-node-controllers.arch-node-rect.svelte-d3ct2b{fill:#eff6ff;stroke:#3b82f6}.arch-node-handlers.arch-node-rect.svelte-d3ct2b{fill:#faf5ff;stroke:#a855f7}.arch-node-services.arch-node-rect.svelte-d3ct2b{fill:#f0fdf4;stroke:#22c55e}.arch-node-repositories.arch-node-rect.svelte-d3ct2b{fill:#fff7ed;stroke:#f97316}.arch-node-modules.arch-node-rect.svelte-d3ct2b{fill:#eef2ff;stroke:#6366f1}.arch-node-common.arch-node-rect.svelte-d3ct2b{fill:#f8fafc;stroke:#94a3b8}.arch-node-models.arch-node-rect.svelte-d3ct2b{fill:#f0fdfa;stroke:#14b8a6}.arch-node-views.arch-node-rect.svelte-d3ct2b{fill:#fefce8;stroke:#eab308}.arch-node-pages.arch-node-rect.svelte-d3ct2b,.arch-node-screens.arch-node-rect.svelte-d3ct2b,.arch-node-routes.arch-node-rect.svelte-d3ct2b{fill:#eff6ff;stroke:#3b82f6}.arch-node-components.arch-node-rect.svelte-d3ct2b{fill:#fdf2f8;stroke:#ec4899}.arch-node-hooks.arch-node-rect.svelte-d3ct2b{fill:#f5f3ff;stroke:#8b5cf6}.arch-node-composables.arch-node-rect.svelte-d3ct2b{fill:#ecfeff;stroke:#06b6d4}.arch-node-store.arch-node-rect.svelte-d3ct2b,.arch-node-stores.arch-node-rect.svelte-d3ct2b{fill:#fffbeb;stroke:#f59e0b}.arch-node-lib.arch-node-rect.svelte-d3ct2b{fill:#f0fdfa;stroke:#14b8a6}.arch-node-utils.arch-node-rect.svelte-d3ct2b{fill:#f8fafc;stroke:#94a3b8}.arch-node-guards.arch-node-rect.svelte-d3ct2b{fill:#fff1f2;stroke:#f43f5e}.arch-node-server.arch-node-rect.svelte-d3ct2b{fill:#fff7ed;stroke:#f97316}.arch-node-ports.arch-node-rect.svelte-d3ct2b{fill:#ecfeff;stroke:#06b6d4}.arch-node-adapters.arch-node-rect.svelte-d3ct2b{fill:#f0fdfa;stroke:#14b8a6}html[data-theme=dark] .arch-node-domain.arch-node-rect.svelte-d3ct2b{fill:#1e3a5f;stroke:#3b82f6}html[data-theme=dark] .arch-node-application.arch-node-rect.svelte-d3ct2b{fill:#14352a;stroke:#22c55e}html[data-theme=dark] .arch-node-infrastructure.arch-node-rect.svelte-d3ct2b{fill:#3d2006;stroke:#f97316}html[data-theme=dark] .arch-node-api.arch-node-rect.svelte-d3ct2b{fill:#2e1a47;stroke:#a855f7}html[data-theme=dark] .arch-node-shared.arch-node-rect.svelte-d3ct2b{fill:#1e2535;stroke:#94a3b8}html[data-theme=dark] .arch-node-controllers.arch-node-rect.svelte-d3ct2b{fill:#1e3a5f;stroke:#3b82f6}html[data-theme=dark] .arch-node-handlers.arch-node-rect.svelte-d3ct2b{fill:#2e1a47;stroke:#a855f7}html[data-theme=dark] .arch-node-services.arch-node-rect.svelte-d3ct2b{fill:#14352a;stroke:#22c55e}html[data-theme=dark] .arch-node-repositories.arch-node-rect.svelte-d3ct2b{fill:#3d2006;stroke:#f97316}html[data-theme=dark] .arch-node-modules.arch-node-rect.svelte-d3ct2b{fill:#1e1b4b;stroke:#6366f1}html[data-theme=dark] .arch-node-common.arch-node-rect.svelte-d3ct2b{fill:#1e2535;stroke:#94a3b8}html[data-theme=dark] .arch-node-models.arch-node-rect.svelte-d3ct2b{fill:#0f2922;stroke:#14b8a6}html[data-theme=dark] .arch-node-views.arch-node-rect.svelte-d3ct2b{fill:#29240a;stroke:#eab308}html[data-theme=dark] .arch-node-pages.arch-node-rect.svelte-d3ct2b,html[data-theme=dark] .arch-node-screens.arch-node-rect.svelte-d3ct2b,html[data-theme=dark] .arch-node-routes.arch-node-rect.svelte-d3ct2b{fill:#1e3a5f;stroke:#3b82f6}html[data-theme=dark] .arch-node-components.arch-node-rect.svelte-d3ct2b{fill:#3d0e2e;stroke:#ec4899}html[data-theme=dark] .arch-node-hooks.arch-node-rect.svelte-d3ct2b{fill:#1e1547;stroke:#8b5cf6}html[data-theme=dark] .arch-node-composables.arch-node-rect.svelte-d3ct2b{fill:#042934;stroke:#06b6d4}html[data-theme=dark] .arch-node-store.arch-node-rect.svelte-d3ct2b,html[data-theme=dark] .arch-node-stores.arch-node-rect.svelte-d3ct2b{fill:#2d200a;stroke:#f59e0b}html[data-theme=dark] .arch-node-lib.arch-node-rect.svelte-d3ct2b{fill:#0f2922;stroke:#14b8a6}html[data-theme=dark] .arch-node-utils.arch-node-rect.svelte-d3ct2b{fill:#1e2535;stroke:#94a3b8}html[data-theme=dark] .arch-node-guards.arch-node-rect.svelte-d3ct2b{fill:#3d0a14;stroke:#f43f5e}html[data-theme=dark] .arch-node-server.arch-node-rect.svelte-d3ct2b{fill:#3d2006;stroke:#f97316}html[data-theme=dark] .arch-node-ports.arch-node-rect.svelte-d3ct2b{fill:#042934;stroke:#06b6d4}html[data-theme=dark] .arch-node-adapters.arch-node-rect.svelte-d3ct2b{fill:#0f2922;stroke:#14b8a6}.arch-node-label.svelte-d3ct2b{font-family:var(--mono);font-size:11px;font-weight:600;fill:var(--on-surface)}.arch-node-desc.svelte-d3ct2b{font-family:var(--sans);font-size:9px;fill:var(--outline)}.arch-node-clickable.svelte-d3ct2b{cursor:pointer}.arch-node-clickable.svelte-d3ct2b:hover .arch-node-rect:where(.svelte-d3ct2b){filter:brightness(.95)}html[data-theme=dark] .arch-node-clickable.svelte-d3ct2b:hover .arch-node-rect:where(.svelte-d3ct2b){filter:brightness(1.15)}.arch-node-panel.svelte-d3ct2b{border:1px solid var(--outline-var);border-radius:8px;background:var(--surface-low);padding:12px 16px;max-width:640px;display:flex;flex-direction:column;gap:10px}.arch-node-panel-header.svelte-d3ct2b{display:flex;align-items:center;gap:10px}.arch-node-panel-name.svelte-d3ct2b{font-family:var(--mono);font-weight:700;font-size:13px;color:var(--on-surface)}.arch-node-panel-meta.svelte-d3ct2b{font-size:12px;color:var(--outline);flex:1}.arch-node-panel-close.svelte-d3ct2b{background:none;border:none;cursor:pointer;color:var(--outline);font-size:14px;padding:0;line-height:1}.arch-node-panel-close.svelte-d3ct2b:hover{color:var(--on-surface)}.arch-node-panel-paths.svelte-d3ct2b{display:flex;flex-direction:column;gap:4px}.arch-node-panel-section.svelte-d3ct2b{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--outline);margin-bottom:2px}.arch-node-panel-path.svelte-d3ct2b{font-family:var(--mono);font-size:11px;color:var(--cyan, #22d3ee);background:var(--surface-mid);padding:3px 8px;border-radius:4px}.arch-node-panel-rule.svelte-d3ct2b{display:flex;align-items:center;gap:8px;font-size:12px}.arch-legend.svelte-d3ct2b{display:flex;gap:16px;align-items:center;font-size:11px;color:var(--outline)}.legend-item.svelte-d3ct2b{display:flex;align-items:center;gap:6px}.arch-rule-list.svelte-d3ct2b{display:flex;flex-direction:column;gap:4px;max-width:640px}.arch-rule-row.svelte-d3ct2b{display:flex;align-items:center;gap:8px;padding:6px 10px;background:var(--surface-low);border-radius:4px;border:1px solid var(--outline-var)}.tab-badge.svelte-d3ct2b{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:16px;padding:0 5px;border-radius:8px;background:var(--error);color:#fff;font-size:10px;font-weight:700;margin-left:4px;vertical-align:middle}.history-list.svelte-d3ct2b{display:flex;flex-direction:column;gap:8px;max-width:760px}.history-entry.svelte-d3ct2b{border:1px solid var(--outline-var);border-radius:6px;background:var(--surface-low);overflow:hidden}.history-header.svelte-d3ct2b{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;border-bottom:1px solid var(--outline-var);background:var(--surface-mid)}.history-file.svelte-d3ct2b{font-family:var(--mono);font-size:12px;font-weight:600;color:var(--cyan, #22d3ee)}.history-time.svelte-d3ct2b{font-size:11px;color:var(--outline)}.history-violation.svelte-d3ct2b{display:flex;align-items:center;gap:8px;padding:6px 12px;border-bottom:1px solid var(--outline-var);flex-wrap:wrap}.history-violation.svelte-d3ct2b:last-child{border-bottom:none}.history-badge.svelte-d3ct2b{flex-shrink:0;font-family:var(--mono);font-size:10px;font-weight:700;padding:2px 6px;border-radius:3px;background:var(--error-bg);color:var(--error);white-space:nowrap}.history-rule.svelte-d3ct2b{font-size:12px;font-weight:600;color:var(--on-surface)}.history-issue.svelte-d3ct2b{font-size:12px;color:var(--outline)}.arch-rule-badge.svelte-d3ct2b{font-size:10px;font-family:var(--mono);font-weight:700;padding:2px 6px;border-radius:3px}.badge-block.svelte-d3ct2b{background:var(--error-bg);color:var(--error)}.badge-warn.svelte-d3ct2b{background:#fef3c7;color:#92400e}.badge-allow.svelte-d3ct2b{background:var(--green-bg);color:var(--green)}.arch-rule-layers.svelte-d3ct2b{font-family:var(--mono);font-size:11px;color:var(--on-surface);white-space:nowrap}.arch-rule-name.svelte-d3ct2b{font-size:11px;color:var(--outline);flex:1}.arch-edit-btn.svelte-d3ct2b{padding:4px 10px;font-family:var(--mono);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;background:var(--surface-mid);border:1px solid var(--outline-var);border-radius:4px;color:var(--on-surface-var);cursor:pointer;transition:background .15s,color .15s}.arch-edit-btn.svelte-d3ct2b:hover{background:var(--primary-container);color:var(--primary);border-color:var(--primary-dim)}.arch-edit-btn-active.svelte-d3ct2b{background:var(--primary-container)!important;color:var(--primary)!important;border-color:var(--primary-dim)!important}.arch-reset-btn.svelte-d3ct2b{color:var(--tertiary)!important;border-color:var(--tertiary)!important}.arch-reset-btn.svelte-d3ct2b:hover{background:#fff3eb!important}html[data-theme=dark] .arch-reset-btn.svelte-d3ct2b:hover{background:#3d1a00!important}.arch-rule-del.svelte-d3ct2b{background:none;border:none;color:var(--outline);cursor:pointer;font-size:12px;padding:0 4px;line-height:1;transition:color .15s}.arch-rule-del.svelte-d3ct2b:hover{color:var(--error)}.arch-add-form.svelte-d3ct2b{display:flex;flex-direction:column;gap:8px;background:var(--surface-low);border:1px solid var(--outline-var);border-radius:6px;padding:12px;max-width:640px}.arch-add-form-title.svelte-d3ct2b{font-family:var(--mono);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--outline)}.arch-add-row.svelte-d3ct2b{display:flex;gap:8px;flex-wrap:wrap;align-items:flex-end}.arch-add-input.svelte-d3ct2b{height:30px;padding:0 8px;background:var(--surface);border:1px solid var(--outline-var);border-radius:4px;color:var(--on-surface);font-family:var(--mono);font-size:11px;outline:none;min-width:80px}.arch-add-input.svelte-d3ct2b:focus{border-color:var(--primary-dim)}.arch-add-select.svelte-d3ct2b{height:30px;padding:0 6px;background:var(--surface);border:1px solid var(--outline-var);border-radius:4px;color:var(--on-surface);font-family:var(--mono);font-size:11px;outline:none}.arch-add-submit.svelte-d3ct2b{height:30px;padding:0 12px;background:var(--primary);border:none;border-radius:4px;color:#fff;font-family:var(--mono);font-size:11px;font-weight:700;cursor:pointer;transition:background .15s}.arch-add-submit.svelte-d3ct2b:hover{background:var(--primary-dim)}.arch-add-submit.svelte-d3ct2b:disabled{opacity:.5;cursor:default}.arch-add-label.svelte-d3ct2b{font-size:10px;color:var(--outline);font-family:var(--mono)}.arch-add-field.svelte-d3ct2b{display:flex;flex-direction:column;gap:2px}
|