@a-company/paradigm 3.22.0 → 3.23.1

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.
@@ -59,7 +59,14 @@ function discoverPlugins() {
59
59
  let installedVersion = "unknown";
60
60
  if (fs.existsSync(pluginCacheDir)) {
61
61
  try {
62
- const versions = fs.readdirSync(pluginCacheDir).filter((d) => fs.statSync(path.join(pluginCacheDir, d)).isDirectory()).sort().reverse();
62
+ const versions = fs.readdirSync(pluginCacheDir).filter((d) => fs.statSync(path.join(pluginCacheDir, d)).isDirectory()).sort((a, b) => {
63
+ const pa = a.split(".").map(Number);
64
+ const pb = b.split(".").map(Number);
65
+ for (let i = 0; i < 3; i++) {
66
+ if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) - (pb[i] || 0);
67
+ }
68
+ return 0;
69
+ }).reverse();
63
70
  if (versions.length > 0) installedVersion = versions[0];
64
71
  } catch {
65
72
  }
@@ -76,7 +76,14 @@ function discoverPlugins() {
76
76
  let installedSha = "unknown";
77
77
  if (fs.existsSync(pluginCacheDir)) {
78
78
  try {
79
- const versions = fs.readdirSync(pluginCacheDir).filter((d) => fs.statSync(path.join(pluginCacheDir, d)).isDirectory()).sort().reverse();
79
+ const versions = fs.readdirSync(pluginCacheDir).filter((d) => fs.statSync(path.join(pluginCacheDir, d)).isDirectory()).sort((a, b) => {
80
+ const pa = a.split(".").map(Number);
81
+ const pb = b.split(".").map(Number);
82
+ for (let i = 0; i < 3; i++) {
83
+ if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) - (pb[i] || 0);
84
+ }
85
+ return 0;
86
+ }).reverse();
80
87
  if (versions.length > 0) {
81
88
  installedVersion = versions[0];
82
89
  const cachedPluginJson = readJsonSafe(
@@ -11,7 +11,7 @@ async function graphCommand(path, options) {
11
11
  const shouldOpen = options.open !== false;
12
12
  console.log(chalk.cyan("\nStarting Symbol Graph...\n"));
13
13
  try {
14
- const { startGraphServer } = await import("./graph-server-BPKQYSQK.js");
14
+ const { startGraphServer } = await import("./graph-server-BZ73HTAT.js");
15
15
  console.log(chalk.gray(`Project: ${projectDir}`));
16
16
  console.log(chalk.gray(`Port: ${port}`));
17
17
  console.log();
@@ -33,6 +33,7 @@ Error: Port ${port} is already in use.`));
33
33
  process.exit(1);
34
34
  }
35
35
  }
36
+ var GRAPHS_DIR = ".paradigm/graphs";
36
37
  var CATEGORY_PREFIXES = {
37
38
  component: "#",
38
39
  flow: "$",
@@ -117,8 +118,9 @@ function cliBuildGraphState(projectDir, symbolFilter, groups, links, graphName =
117
118
  }
118
119
  return { version: "1.0", name: graphName, projectId: pathMod.basename(projectDir), lastModified: (/* @__PURE__ */ new Date()).toISOString(), nodes, edges };
119
120
  }
120
- async function graphGenerateCommand(path, options) {
121
+ async function graphGenerateCommand(name, path, options) {
121
122
  const projectDir = path || process.cwd();
123
+ const slug = name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
122
124
  try {
123
125
  const symbolFilter = options.symbols ? options.symbols.split(",").map((s) => s.trim()) : void 0;
124
126
  const groups = options.group?.map((g) => {
@@ -140,15 +142,16 @@ async function graphGenerateCommand(path, options) {
140
142
  const colonIdx = rest.indexOf(":");
141
143
  return { source, target: colonIdx === -1 ? rest : rest.slice(0, colonIdx), label: colonIdx === -1 ? void 0 : rest.slice(colonIdx + 1) };
142
144
  });
143
- const state = cliBuildGraphState(projectDir, symbolFilter, groups, links, options.name || "Generated Graph");
145
+ const state = cliBuildGraphState(projectDir, symbolFilter, groups, links, name);
144
146
  const json = JSON.stringify(state, null, 2);
145
- if (options.output) {
146
- fs.writeFileSync(options.output, json, "utf8");
147
- console.log(chalk.green(`Graph written to ${options.output}`));
148
- console.log(chalk.gray(`${state.nodes.length} nodes, ${state.edges.length} edges`));
149
- } else {
150
- process.stdout.write(json + "\n");
151
- }
147
+ const graphsDir = pathMod.join(projectDir, GRAPHS_DIR);
148
+ if (!fs.existsSync(graphsDir)) fs.mkdirSync(graphsDir, { recursive: true });
149
+ const outPath = pathMod.join(graphsDir, `${slug}.graph.json`);
150
+ fs.writeFileSync(outPath, json, "utf8");
151
+ console.log(chalk.green(`Graph saved to ${outPath}`));
152
+ console.log(chalk.gray(`${state.nodes.length} nodes, ${state.edges.length} edges, ${(json.length / 1024).toFixed(1)} KB`));
153
+ console.log(chalk.gray(`
154
+ View: paradigm graph`));
152
155
  } catch (error) {
153
156
  console.error(chalk.red("Failed to generate graph:"), error.message);
154
157
  process.exit(1);
@@ -3,8 +3,8 @@ import "./chunk-ZXMDA7VB.js";
3
3
 
4
4
  // src/graph-server/index.ts
5
5
  import express from "express";
6
- import * as path2 from "path";
7
- import * as fs2 from "fs";
6
+ import * as path3 from "path";
7
+ import * as fs3 from "fs";
8
8
  import { fileURLToPath } from "url";
9
9
  import chalk from "chalk";
10
10
 
@@ -83,9 +83,71 @@ function createSymbolsRouter(projectDir) {
83
83
  return router;
84
84
  }
85
85
 
86
+ // src/graph-server/routes/graphs.ts
87
+ import { Router as Router2 } from "express";
88
+ import * as fs2 from "fs";
89
+ import * as path2 from "path";
90
+ var GRAPHS_DIR = ".paradigm/graphs";
91
+ function createGraphsRouter(projectDir) {
92
+ const router = Router2();
93
+ const graphsPath = path2.join(projectDir, GRAPHS_DIR);
94
+ router.get("/", (_req, res) => {
95
+ if (!fs2.existsSync(graphsPath)) {
96
+ res.json({ graphs: [] });
97
+ return;
98
+ }
99
+ try {
100
+ const files = fs2.readdirSync(graphsPath).filter((f) => f.endsWith(".graph.json"));
101
+ const graphs = files.map((file) => {
102
+ const filePath = path2.join(graphsPath, file);
103
+ const stat = fs2.statSync(filePath);
104
+ const slug = file.replace(/\.graph\.json$/, "");
105
+ let name = slug;
106
+ let nodeCount = 0;
107
+ let edgeCount = 0;
108
+ try {
109
+ const raw = JSON.parse(fs2.readFileSync(filePath, "utf8"));
110
+ name = raw.name || slug;
111
+ nodeCount = Array.isArray(raw.nodes) ? raw.nodes.length : 0;
112
+ edgeCount = Array.isArray(raw.edges) ? raw.edges.length : 0;
113
+ } catch {
114
+ }
115
+ return {
116
+ slug,
117
+ file,
118
+ name,
119
+ nodes: nodeCount,
120
+ edges: edgeCount,
121
+ size: stat.size,
122
+ modified: stat.mtime.toISOString()
123
+ };
124
+ });
125
+ graphs.sort((a, b) => b.modified.localeCompare(a.modified));
126
+ res.json({ graphs });
127
+ } catch (err) {
128
+ res.status(500).json({ error: "Failed to list graphs", details: err.message });
129
+ }
130
+ });
131
+ router.get("/:slug", (req, res) => {
132
+ const slug = req.params.slug;
133
+ const filePath = path2.join(graphsPath, `${slug}.graph.json`);
134
+ if (!fs2.existsSync(filePath)) {
135
+ res.status(404).json({ error: `Graph "${slug}" not found` });
136
+ return;
137
+ }
138
+ try {
139
+ const raw = fs2.readFileSync(filePath, "utf8");
140
+ res.type("application/json").send(raw);
141
+ } catch (err) {
142
+ res.status(500).json({ error: "Failed to read graph", details: err.message });
143
+ }
144
+ });
145
+ return router;
146
+ }
147
+
86
148
  // src/graph-server/index.ts
87
149
  var __filename = fileURLToPath(import.meta.url);
88
- var __dirname = path2.dirname(__filename);
150
+ var __dirname = path3.dirname(__filename);
89
151
  var log = {
90
152
  component(name) {
91
153
  const symbol = chalk.magenta(`#${name}`);
@@ -123,18 +185,19 @@ function createGraphApp(options) {
123
185
  next();
124
186
  });
125
187
  app.use("/api/symbols", createSymbolsRouter(options.projectDir));
188
+ app.use("/api/graphs", createGraphsRouter(options.projectDir));
126
189
  app.get("/api/health", (_req, res) => {
127
190
  res.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
128
191
  });
129
- let uiDistPath = path2.join(__dirname, "..", "graph-ui", "dist");
130
- if (!fs2.existsSync(uiDistPath)) {
131
- uiDistPath = path2.join(__dirname, "..", "..", "graph-ui", "dist");
192
+ let uiDistPath = path3.join(__dirname, "..", "graph-ui", "dist");
193
+ if (!fs3.existsSync(uiDistPath)) {
194
+ uiDistPath = path3.join(__dirname, "..", "..", "graph-ui", "dist");
132
195
  }
133
- if (fs2.existsSync(uiDistPath)) {
196
+ if (fs3.existsSync(uiDistPath)) {
134
197
  app.use(express.static(uiDistPath));
135
198
  app.get("{*path}", (req, res) => {
136
199
  if (!req.path.startsWith("/api")) {
137
- res.sendFile(path2.join(uiDistPath, "index.html"));
200
+ res.sendFile(path3.join(uiDistPath, "index.html"));
138
201
  }
139
202
  });
140
203
  } else {
package/dist/index.js CHANGED
@@ -300,11 +300,11 @@ teamCmd.action(async () => {
300
300
  });
301
301
  var pluginCmd = program.command("plugin").description("Plugin management commands");
302
302
  pluginCmd.command("check").description("Check for updates to installed Claude Code plugins").option("-u, --update", "Pull latest changes for all stale marketplace clones").action(async (options) => {
303
- const { pluginCheckCommand } = await import("./check-5RKOAN7S.js");
303
+ const { pluginCheckCommand } = await import("./check-OLI6AUS6.js");
304
304
  await pluginCheckCommand(options);
305
305
  });
306
306
  pluginCmd.action(async () => {
307
- const { pluginCheckCommand } = await import("./check-5RKOAN7S.js");
307
+ const { pluginCheckCommand } = await import("./check-OLI6AUS6.js");
308
308
  await pluginCheckCommand({});
309
309
  });
310
310
  var workspaceCmd = program.command("workspace").description("Multi-project workspace commands");
@@ -661,12 +661,12 @@ loreCmd.option("-p, --port <port>", "Port to run on", "3840").option("--no-open"
661
661
  await loreServeCommand(void 0, options);
662
662
  });
663
663
  var graphCmd = program.command("graph").description("Interactive symbol relationship graph").argument("[path]", "Project directory", void 0).option("-p, --port <port>", "Port to run on", "3841").option("--no-open", "Don't open browser automatically").action(async (path2, options) => {
664
- const { graphCommand } = await import("./graph-BFZXFAFL.js");
664
+ const { graphCommand } = await import("./graph-5VSRBRKZ.js");
665
665
  await graphCommand(path2, options);
666
666
  });
667
- graphCmd.command("generate").description("Generate GraphState JSON from symbols (for agents / piping)").argument("[path]", "Project directory", void 0).option("-s, --symbols <list>", "Comma-separated symbol names to include").option("-g, --group <spec...>", 'Group spec: "Label:#sym1,#sym2" (repeatable)').option("-l, --link <spec...>", 'Link spec: "Source>Target:label" (repeatable)').option("-n, --name <name>", "Graph name", "Generated Graph").option("-o, --output <file>", "Write to file instead of stdout").action(async (path2, options) => {
668
- const { graphGenerateCommand } = await import("./graph-BFZXFAFL.js");
669
- await graphGenerateCommand(path2, options);
667
+ graphCmd.command("generate").description("Generate a named graph file in .paradigm/graphs/").argument("<name>", "Graph name (used as filename: {name}.graph.json)").argument("[path]", "Project directory", void 0).option("-s, --symbols <list>", "Comma-separated symbol names to include").option("-g, --group <spec...>", 'Group spec: "Label:#sym1,#sym2" (repeatable)').option("-l, --link <spec...>", 'Link spec: "Source>Target:label" (repeatable)').action(async (name, path2, options) => {
668
+ const { graphGenerateCommand } = await import("./graph-5VSRBRKZ.js");
669
+ await graphGenerateCommand(name, path2, options);
670
670
  });
671
671
  var habitsCmd = program.command("habits").description("Behavioral habits - practice tracking and compliance");
672
672
  habitsCmd.command("list").alias("ls").description("List all configured habits").option("--trigger <trigger>", "Filter by trigger: preflight, postflight, on-stop, on-commit").option("--category <category>", "Filter by category: discovery, verification, testing, documentation, collaboration, security").option("--json", "Output as JSON").action(async (options) => {
package/dist/mcp.js CHANGED
@@ -88,7 +88,7 @@ import {
88
88
  import {
89
89
  getPluginUpdateNotice,
90
90
  schedulePluginUpdateCheck
91
- } from "./chunk-YT3QWWKP.js";
91
+ } from "./chunk-MP73YDXF.js";
92
92
 
93
93
  // ../paradigm-mcp/src/index.ts
94
94
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -12692,6 +12692,7 @@ function summarizeStep(step) {
12692
12692
  // ../paradigm-mcp/src/tools/graph.ts
12693
12693
  import * as fs22 from "fs";
12694
12694
  import * as path24 from "path";
12695
+ var GRAPHS_DIR = ".paradigm/graphs";
12695
12696
  var CATEGORY_PREFIXES = {
12696
12697
  component: "#",
12697
12698
  flow: "$",
@@ -12709,10 +12710,14 @@ function getGraphToolsList() {
12709
12710
  return [
12710
12711
  {
12711
12712
  name: "paradigm_graph_generate",
12712
- description: "Generate a GraphState JSON document for the Paradigm Symbol Graph UI. Accepts optional symbols (filter), groups (clustering), and links (edges between groups). Returns valid GraphState ready to load. ~200 tokens.",
12713
+ description: "Generate a named GraphState JSON file for the Paradigm Symbol Graph UI. Writes to .paradigm/graphs/{name}.graph.json. View saved graphs with `paradigm graph` CLI. Returns a summary with node/edge counts and file path. ~100 tokens.",
12713
12714
  inputSchema: {
12714
12715
  type: "object",
12715
12716
  properties: {
12717
+ name: {
12718
+ type: "string",
12719
+ description: 'Graph name (kebab-case). Used as filename: {name}.graph.json. E.g. "auth-flow", "full-project", "checkout-subsystem".'
12720
+ },
12716
12721
  symbols: {
12717
12722
  type: "array",
12718
12723
  items: { type: "string" },
@@ -12746,15 +12751,12 @@ function getGraphToolsList() {
12746
12751
  required: ["source", "target"]
12747
12752
  },
12748
12753
  description: "Edges between groups (by label name)."
12749
- },
12750
- name: {
12751
- type: "string",
12752
- description: 'Graph name (default: "Generated Graph").'
12753
12754
  }
12754
- }
12755
+ },
12756
+ required: ["name"]
12755
12757
  },
12756
12758
  annotations: {
12757
- readOnlyHint: true,
12759
+ readOnlyHint: false,
12758
12760
  destructiveHint: false
12759
12761
  }
12760
12762
  }
@@ -12765,16 +12767,31 @@ async function handleGraphTool(name, args, ctx) {
12765
12767
  return { handled: false, text: "" };
12766
12768
  }
12767
12769
  try {
12770
+ const graphName = args.name || "untitled";
12771
+ const slug = graphName.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
12768
12772
  const result = buildGraphState(
12769
12773
  ctx.rootDir,
12770
12774
  args.symbols,
12771
12775
  args.groups,
12772
12776
  args.links,
12773
- args.name || "Generated Graph"
12777
+ graphName
12774
12778
  );
12775
- const text = JSON.stringify(result, null, 2);
12776
- trackToolCall(text.length, name);
12777
- return { handled: true, text };
12779
+ const json = JSON.stringify(result, null, 2);
12780
+ const graphsDir = path24.join(ctx.rootDir, GRAPHS_DIR);
12781
+ if (!fs22.existsSync(graphsDir)) fs22.mkdirSync(graphsDir, { recursive: true });
12782
+ const outPath = path24.join(graphsDir, `${slug}.graph.json`);
12783
+ fs22.writeFileSync(outPath, json, "utf8");
12784
+ const summary = JSON.stringify({
12785
+ file: outPath,
12786
+ name: graphName,
12787
+ slug,
12788
+ nodes: result.nodes.length,
12789
+ edges: result.edges.length,
12790
+ size: `${(json.length / 1024).toFixed(1)} KB`,
12791
+ hint: `Graph saved. Run \`paradigm graph\` to view in browser.`
12792
+ }, null, 2);
12793
+ trackToolCall(summary.length, name);
12794
+ return { handled: true, text: summary };
12778
12795
  } catch (err2) {
12779
12796
  const text = JSON.stringify({ error: err2.message }, null, 2);
12780
12797
  trackToolCall(text.length, name);
@@ -13808,7 +13825,7 @@ function registerTools(server, getContext2, reloadContext2) {
13808
13825
  };
13809
13826
  }
13810
13827
  case "paradigm_plugin_check": {
13811
- const { runPluginUpdateCheck } = await import("./plugin-update-checker-S3W4BUJO.js");
13828
+ const { runPluginUpdateCheck } = await import("./plugin-update-checker-HMRPGY5Z.js");
13812
13829
  const results = await runPluginUpdateCheck();
13813
13830
  const updatable = results.filter((r) => r.hasRemoteUpdate || r.hasCacheStale);
13814
13831
  if (updatable.length === 0) {
@@ -3,7 +3,7 @@ import {
3
3
  getPluginUpdateNotice,
4
4
  runPluginUpdateCheck,
5
5
  schedulePluginUpdateCheck
6
- } from "./chunk-YT3QWWKP.js";
6
+ } from "./chunk-MP73YDXF.js";
7
7
  export {
8
8
  getPluginUpdateNotice,
9
9
  runPluginUpdateCheck,
@@ -1 +1 @@
1
- .react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}:root{--bg-base: #0a0a0f;--bg-panel: #0f172a;--bg-surface: #1e293b;--bg-hover: #334155;--text-primary: #e2e8f0;--text-secondary: #94a3b8;--text-muted: #64748b;--border: #1e293b;--border-focus: #475569;--color-component: #86efac;--color-flow: #fbbf24;--color-gate: #f87171;--color-signal: #fde047;--color-aspect: #a78bfa}*{margin:0;padding:0;box-sizing:border-box}body{background:var(--bg-base);color:var(--text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;overflow:hidden}.app{display:flex;height:100vh;width:100vw}.app__main{flex:1;display:flex;flex-direction:column;min-width:0}.symbol-panel{width:280px;min-width:280px;background:var(--bg-panel);border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden}.symbol-panel__header{display:flex;align-items:center;justify-content:space-between;padding:16px;border-bottom:1px solid var(--border)}.symbol-panel__header h2{font-size:14px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--text-secondary)}.symbol-panel__count{font-size:12px;background:var(--bg-surface);color:var(--text-muted);padding:2px 8px;border-radius:10px}.symbol-panel__search{margin:12px 16px;padding:8px 12px;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;color:var(--text-primary);font-size:13px;outline:none;transition:border-color .15s}.symbol-panel__search:focus{border-color:var(--border-focus)}.symbol-panel__search::placeholder{color:var(--text-muted)}.symbol-panel__list{flex:1;overflow-y:auto;padding:0 8px 16px}.symbol-panel__section{margin-top:4px}.symbol-panel__section-header{display:flex;align-items:center;gap:6px;width:100%;padding:6px 8px;background:none;border:none;font-size:12px;font-weight:600;cursor:pointer;text-transform:uppercase;letter-spacing:.05em}.symbol-panel__section-arrow{font-size:10px;width:12px}.symbol-panel__section-count{margin-left:auto;font-size:11px;opacity:.5;font-weight:400}.symbol-panel__section-items{padding:2px 0}.symbol-panel__item{display:flex;flex-direction:column;gap:2px;padding:6px 8px 6px 12px;margin:1px 0;border-left:2px solid transparent;border-radius:4px;cursor:grab;transition:background .1s}.symbol-panel__item:hover{background:var(--bg-surface)}.symbol-panel__item:active{cursor:grabbing}.symbol-panel__item-name{font-size:13px;font-weight:500;font-family:SF Mono,Fira Code,monospace}.symbol-panel__item-desc{font-size:11px;color:var(--text-muted);line-height:1.3}.toolbar{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--bg-panel);border-bottom:1px solid var(--border)}.toolbar__name{background:transparent;border:1px solid transparent;color:var(--text-primary);font-size:14px;font-weight:600;padding:4px 8px;border-radius:4px;width:200px;outline:none;transition:border-color .15s}.toolbar__name:hover,.toolbar__name:focus{border-color:var(--border-focus)}.toolbar__actions{display:flex;align-items:center;gap:6px;margin-left:auto}.toolbar__btn{padding:6px 12px;background:var(--bg-surface);border:1px solid var(--border);color:var(--text-secondary);font-size:12px;font-weight:500;border-radius:6px;cursor:pointer;transition:all .15s}.toolbar__btn:hover{background:var(--bg-hover);color:var(--text-primary)}.toolbar__btn--primary{background:#1d4ed8;border-color:#2563eb;color:#fff}.toolbar__btn--primary:hover{background:#2563eb}.toolbar__divider{width:1px;height:20px;background:var(--border);margin:0 4px}.canvas-wrapper{flex:1;position:relative}.paradigm-flow{background:var(--bg-base)!important}.react-flow__controls{background:var(--bg-panel)!important;border:1px solid var(--border)!important;border-radius:8px!important;overflow:hidden}.react-flow__controls-button{background:var(--bg-panel)!important;border-bottom:1px solid var(--border)!important;fill:var(--text-secondary)!important}.react-flow__controls-button:hover{background:var(--bg-surface)!important}.react-flow__minimap{border:1px solid var(--border)!important;border-radius:8px!important;overflow:hidden}.react-flow__edge-path{stroke:var(--text-muted)!important;stroke-width:2}.react-flow__edge.selected .react-flow__edge-path{stroke:var(--text-primary)!important}.react-flow__edge-text{fill:var(--text-secondary)!important;font-size:11px}.react-flow__edge-textbg{fill:var(--bg-panel)!important}.symbol-node{background:var(--bg-panel);border:1px solid var(--border);border-left:3px solid var(--color-component);border-radius:8px;padding:8px 12px;min-width:160px;max-width:240px;transition:border-color .15s}.symbol-node:hover{border-color:var(--border-focus)}.symbol-node__name{font-size:13px;font-weight:600;font-family:SF Mono,Fira Code,monospace;line-height:1.4}.symbol-node__desc{font-size:11px;color:var(--text-muted);line-height:1.3;margin-top:2px}.group-node{background:#1e293b80;border:2px dashed var(--border-focus);border-radius:12px;width:100%;height:100%;position:relative}.group-node__header{padding:8px 16px;border-bottom:1px solid var(--border);border-radius:12px 12px 0 0;background:#0f172acc;cursor:default}.group-node__label{font-size:13px;font-weight:600;color:var(--text-primary)}.group-node__input{background:var(--bg-surface);border:1px solid var(--border-focus);color:var(--text-primary);font-size:13px;font-weight:600;padding:2px 8px;border-radius:4px;outline:none;width:100%}.group-node__resizer-line{border-color:var(--color-component)!important}.group-node__resizer-handle{background:var(--color-component)!important;width:8px!important;height:8px!important;border-radius:2px!important}.group-handle{width:10px!important;height:10px!important;background:var(--bg-hover)!important;border:2px solid var(--text-muted)!important}.export-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0009;display:flex;align-items:center;justify-content:center;z-index:100}.export-dialog{background:var(--bg-panel);border:1px solid var(--border);border-radius:12px;width:640px;max-width:90vw;max-height:80vh;display:flex;flex-direction:column}.export-dialog__header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--border)}.export-dialog__header h3{font-size:16px;font-weight:600}.export-dialog__close{background:none;border:none;color:var(--text-muted);font-size:24px;cursor:pointer;line-height:1;padding:0 4px}.export-dialog__close:hover{color:var(--text-primary)}.export-dialog__content{flex:1;margin:16px 20px;padding:12px;background:var(--bg-base);border:1px solid var(--border);border-radius:8px;color:var(--text-primary);font-size:13px;font-family:SF Mono,Fira Code,monospace;resize:none;outline:none;overflow-y:auto}.export-dialog__actions{display:flex;gap:8px;padding:16px 20px;border-top:1px solid var(--border);justify-content:flex-end}.load-dialog{width:520px}.load-dialog__body{padding:16px 20px;display:flex;flex-direction:column;gap:12px}.load-dialog__section{display:flex;flex-direction:column;gap:8px}.load-dialog__label{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary)}.load-dialog__divider{display:flex;align-items:center;gap:12px;color:var(--text-muted);font-size:12px}.load-dialog__divider:before,.load-dialog__divider:after{content:"";flex:1;height:1px;background:var(--border)}.load-dialog__status{font-size:12px;padding:8px 12px;border-radius:6px}.load-dialog__status--error{background:#f871711a;color:#f87171;border:1px solid rgba(248,113,113,.2)}.load-dialog__status--success{background:#86efac1a;color:#86efac;border:1px solid rgba(134,239,172,.2)}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--bg-hover);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}
1
+ .react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}:root{--bg-base: #0a0a0f;--bg-panel: #0f172a;--bg-surface: #1e293b;--bg-hover: #334155;--text-primary: #e2e8f0;--text-secondary: #94a3b8;--text-muted: #64748b;--border: #1e293b;--border-focus: #475569;--color-component: #86efac;--color-flow: #fbbf24;--color-gate: #f87171;--color-signal: #fde047;--color-aspect: #a78bfa}*{margin:0;padding:0;box-sizing:border-box}body{background:var(--bg-base);color:var(--text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;overflow:hidden}.app{display:flex;height:100vh;width:100vw}.app__main{flex:1;display:flex;flex-direction:column;min-width:0}.symbol-panel{width:280px;min-width:280px;background:var(--bg-panel);border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden}.symbol-panel__header{display:flex;align-items:center;justify-content:space-between;padding:16px;border-bottom:1px solid var(--border)}.symbol-panel__header h2{font-size:14px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--text-secondary)}.symbol-panel__count{font-size:12px;background:var(--bg-surface);color:var(--text-muted);padding:2px 8px;border-radius:10px}.symbol-panel__search{margin:12px 16px;padding:8px 12px;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;color:var(--text-primary);font-size:13px;outline:none;transition:border-color .15s}.symbol-panel__search:focus{border-color:var(--border-focus)}.symbol-panel__search::placeholder{color:var(--text-muted)}.symbol-panel__list{flex:1;overflow-y:auto;padding:0 8px 16px}.symbol-panel__section{margin-top:4px}.symbol-panel__section-header{display:flex;align-items:center;gap:6px;width:100%;padding:6px 8px;background:none;border:none;font-size:12px;font-weight:600;cursor:pointer;text-transform:uppercase;letter-spacing:.05em}.symbol-panel__section-arrow{font-size:10px;width:12px}.symbol-panel__section-count{margin-left:auto;font-size:11px;opacity:.5;font-weight:400}.symbol-panel__section-items{padding:2px 0}.symbol-panel__item{display:flex;flex-direction:column;gap:2px;padding:6px 8px 6px 12px;margin:1px 0;border-left:2px solid transparent;border-radius:4px;cursor:grab;transition:background .1s}.symbol-panel__item:hover{background:var(--bg-surface)}.symbol-panel__item:active{cursor:grabbing}.symbol-panel__item-name{font-size:13px;font-weight:500;font-family:SF Mono,Fira Code,monospace}.symbol-panel__item-desc{font-size:11px;color:var(--text-muted);line-height:1.3}.toolbar{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--bg-panel);border-bottom:1px solid var(--border)}.toolbar__name{background:transparent;border:1px solid transparent;color:var(--text-primary);font-size:14px;font-weight:600;padding:4px 8px;border-radius:4px;width:200px;outline:none;transition:border-color .15s}.toolbar__name:hover,.toolbar__name:focus{border-color:var(--border-focus)}.toolbar__actions{display:flex;align-items:center;gap:6px;margin-left:auto}.toolbar__btn{padding:6px 12px;background:var(--bg-surface);border:1px solid var(--border);color:var(--text-secondary);font-size:12px;font-weight:500;border-radius:6px;cursor:pointer;transition:all .15s}.toolbar__btn:hover{background:var(--bg-hover);color:var(--text-primary)}.toolbar__btn--primary{background:#1d4ed8;border-color:#2563eb;color:#fff}.toolbar__btn--primary:hover{background:#2563eb}.toolbar__divider{width:1px;height:20px;background:var(--border);margin:0 4px}.canvas-wrapper{flex:1;position:relative}.paradigm-flow{background:var(--bg-base)!important}.react-flow__controls{background:var(--bg-panel)!important;border:1px solid var(--border)!important;border-radius:8px!important;overflow:hidden}.react-flow__controls-button{background:var(--bg-panel)!important;border-bottom:1px solid var(--border)!important;fill:var(--text-secondary)!important}.react-flow__controls-button:hover{background:var(--bg-surface)!important}.react-flow__minimap{border:1px solid var(--border)!important;border-radius:8px!important;overflow:hidden}.react-flow__edge-path{stroke:var(--text-muted)!important;stroke-width:2}.react-flow__edge.selected .react-flow__edge-path{stroke:var(--text-primary)!important}.react-flow__edge-text{fill:var(--text-secondary)!important;font-size:11px}.react-flow__edge-textbg{fill:var(--bg-panel)!important}.symbol-node{background:var(--bg-panel);border:1px solid var(--border);border-left:3px solid var(--color-component);border-radius:8px;padding:8px 12px;min-width:160px;max-width:240px;transition:border-color .15s}.symbol-node:hover{border-color:var(--border-focus)}.symbol-node__name{font-size:13px;font-weight:600;font-family:SF Mono,Fira Code,monospace;line-height:1.4}.symbol-node__desc{font-size:11px;color:var(--text-muted);line-height:1.3;margin-top:2px}.group-node{background:#1e293b80;border:2px dashed var(--border-focus);border-radius:12px;width:100%;height:100%;position:relative}.group-node__header{padding:8px 16px;border-bottom:1px solid var(--border);border-radius:12px 12px 0 0;background:#0f172acc;cursor:default}.group-node__label{font-size:13px;font-weight:600;color:var(--text-primary)}.group-node__input{background:var(--bg-surface);border:1px solid var(--border-focus);color:var(--text-primary);font-size:13px;font-weight:600;padding:2px 8px;border-radius:4px;outline:none;width:100%}.group-node__resizer-line{border-color:var(--color-component)!important}.group-node__resizer-handle{background:var(--color-component)!important;width:8px!important;height:8px!important;border-radius:2px!important}.group-handle{width:10px!important;height:10px!important;background:var(--bg-hover)!important;border:2px solid var(--text-muted)!important}.export-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0009;display:flex;align-items:center;justify-content:center;z-index:100}.export-dialog{background:var(--bg-panel);border:1px solid var(--border);border-radius:12px;width:640px;max-width:90vw;max-height:80vh;display:flex;flex-direction:column}.export-dialog__header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--border)}.export-dialog__header h3{font-size:16px;font-weight:600}.export-dialog__close{background:none;border:none;color:var(--text-muted);font-size:24px;cursor:pointer;line-height:1;padding:0 4px}.export-dialog__close:hover{color:var(--text-primary)}.export-dialog__content{flex:1;margin:16px 20px;padding:12px;background:var(--bg-base);border:1px solid var(--border);border-radius:8px;color:var(--text-primary);font-size:13px;font-family:SF Mono,Fira Code,monospace;resize:none;outline:none;overflow-y:auto}.export-dialog__actions{display:flex;gap:8px;padding:16px 20px;border-top:1px solid var(--border);justify-content:flex-end}.load-dialog{width:520px}.load-dialog__body{padding:16px 20px;display:flex;flex-direction:column;gap:12px}.load-dialog__section{display:flex;flex-direction:column;gap:8px}.load-dialog__label{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary)}.load-dialog__divider{display:flex;align-items:center;gap:12px;color:var(--text-muted);font-size:12px}.load-dialog__divider:before,.load-dialog__divider:after{content:"";flex:1;height:1px;background:var(--border)}.load-dialog__status{font-size:12px;padding:8px 12px;border-radius:6px}.load-dialog__status--error{background:#f871711a;color:#f87171;border:1px solid rgba(248,113,113,.2)}.load-dialog__status--success{background:#86efac1a;color:#86efac;border:1px solid rgba(134,239,172,.2)}.load-dialog__loading{color:#94a3b8;font-size:.85rem;padding:8px 0}.load-dialog__graph-list{display:flex;flex-direction:column;gap:4px;max-height:200px;overflow-y:auto}.load-dialog__graph-item{display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:8px 12px;background:#ffffff08;border:1px solid rgba(255,255,255,.06);border-radius:6px;cursor:pointer;text-align:left;color:inherit;font:inherit;transition:background .15s,border-color .15s}.load-dialog__graph-item:hover{background:#ffffff14;border-color:#7dd3fc4d}.load-dialog__graph-name{font-weight:500;font-size:.9rem;color:#e2e8f0}.load-dialog__graph-meta{font-size:.75rem;color:#64748b}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--bg-hover);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}