@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.
@@ -6,23 +6,28 @@ import {
6
6
  embed,
7
7
  inferProjectArchitectures,
8
8
  startWatch
9
- } from "./chunk-OHVCPFEY.js";
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-M7NKSXFS.js";
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
- history.unshift({ timestamp, file, violations });
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-M7NKSXFS.js";
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.30",
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 site:start",
21
- "docs:build": "node scripts/build-static-docs.mjs",
22
- "docs:serve": "npm run site:serve",
23
- "site:build": "npm run docs:build && node scripts/assemble-static-site.mjs",
24
- "site:serve": "node scripts/serve-static-site.mjs --dir site-build --host 127.0.0.1 --port 3010",
25
- "site:start": "npm run site:build && npm run site:serve",
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}