@a-company/paradigm 3.22.0 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
@@ -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
@@ -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);
@@ -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)}