@aact/view 3.0.0-beta.22 → 3.0.0-beta.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/dist/index.d.ts +8 -0
- package/dist/index.js +46 -4
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +15 -0
- package/dist/server.js +23 -10
- package/dist/server.js.map +1 -1
- package/dist/ui/assets/index-BR_xeaLb.js +2 -0
- package/dist/ui/assets/index-BR_xeaLb.js.map +1 -0
- package/dist/ui/assets/index-CK7Lun-6.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +3 -3
- package/dist/ui/assets/index-D2ZA0Nkz.js +0 -4
- package/dist/ui/assets/index-D2ZA0Nkz.js.map +0 -1
- package/dist/ui/assets/index-DFjT4EUS.css +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-D2ZA0Nkz.js","names":[],"sources":["../../../ui/src/actions.ts","../../../ui/src/BoundaryNode.svelte","../../../ui/src/DatabaseNode.svelte","../../../ui/src/ElementNode.svelte","../../../ui/src/PersonNode.svelte","../../../ui/src/QueueNode.svelte","../../../ui/src/layoutWorkerClient.ts","../../../ui/src/layout.ts","../../../ui/src/App.svelte","../../../ui/src/main.ts"],"sourcesContent":["/**\n * Bridge between custom Svelte Flow nodes (which can't receive\n * props from App.svelte directly — Svelte Flow only forwards\n * `data` / `selected` / `dragging`) and the app-level state.\n *\n * App.svelte registers a `ViewActions` object via `setContext`.\n * Node components read it via `getContext` and call back when\n * the user interacts. Decoupling actions from data keeps the\n * `data` payload serialisable and avoids node re-renders when\n * the parent re-assigns a callback identity.\n */\nexport interface ViewActions {\n selectElement(name: string): void;\n selectBoundary(name: string): void;\n /** Drill-mode descent — replace the current scope with this\n * boundary's children. */\n enterBoundary(name: string, label: string): void;\n /** Expand-mode toggle — open/close the boundary inline without\n * hiding parent siblings. No-op outside Expand mode. */\n toggleBoundary(name: string, label: string): void;\n}\n\nexport const VIEW_ACTIONS = Symbol(\"aact-view:actions\");\n","<script lang=\"ts\">\n import { getContext } from \"svelte\";\n\n import { Handle, Position, type NodeProps } from \"@xyflow/svelte\";\n\n import { VIEW_ACTIONS, type ViewActions } from \"./actions.ts\";\n\n interface BoundaryNodeData {\n name: string;\n label: string;\n kind: string;\n childCount: number;\n expanded: boolean;\n canExpand: boolean;\n }\n\n let { data, selected }: NodeProps<{ data: BoundaryNodeData }> = $props();\n\n const actions = getContext<ViewActions>(VIEW_ACTIONS);\n\n // Boundary borders follow the same C4 progression as the elements\n // they wrap, just dashed and translucent so they read as containers\n // not as solid shapes.\n const palette: Record<string, string> = {\n Enterprise: \"#0b3b6c\",\n System: \"#1168bd\",\n Container: \"#438dd5\",\n Component: \"#85bbf0\",\n };\n const accent = $derived(palette[data.kind] ?? \"#94a3b8\");\n\n const onClick = (event: MouseEvent): void => {\n // Boundary headers absorb clicks; ignore clicks that bubble up\n // from interactive children (controls, child nodes) so we don't\n // double-fire selection.\n if (event.target !== event.currentTarget) {\n const isHeader = (event.target as HTMLElement).closest(\".header\");\n if (!isHeader) return;\n }\n actions?.selectBoundary(data.name);\n };\n\n const onDblClick = (event: MouseEvent): void => {\n event.stopPropagation();\n if (data.canExpand) {\n actions?.toggleBoundary(data.name, data.label);\n } else {\n actions?.enterBoundary(data.name, data.label);\n }\n };\n\n const onKeydown = (event: KeyboardEvent): void => {\n if (event.key === \"Enter\") {\n actions?.selectBoundary(data.name);\n return;\n }\n if (event.key !== \" \") return;\n event.preventDefault();\n if (data.canExpand) {\n actions?.toggleBoundary(data.name, data.label);\n } else {\n actions?.enterBoundary(data.name, data.label);\n }\n };\n</script>\n\n<div\n class=\"boundary\"\n class:expanded={data.expanded}\n class:is-selected={selected}\n style:--accent={accent}\n role=\"button\"\n tabindex=\"0\"\n aria-label={`${data.kind} boundary: ${data.label}`}\n onclick={onClick}\n ondblclick={onDblClick}\n onkeydown={onKeydown}\n>\n <Handle type=\"target\" position={Position.Left} />\n <header class=\"header\">\n <span class=\"chip\">{data.kind} boundary</span>\n <span class=\"label\">{data.label}</span>\n {#if !data.expanded}\n <span class=\"meta\">\n {data.childCount} child{data.childCount === 1 ? \"\" : \"ren\"} · dblclick to\n {data.canExpand ? \"expand\" : \"enter\"}\n </span>\n {/if}\n </header>\n <Handle type=\"source\" position={Position.Right} />\n</div>\n\n<style>\n .boundary {\n display: flex;\n flex-direction: column;\n border-radius: 16px;\n border: 2px dashed var(--accent, #94a3b8);\n background: color-mix(in srgb, var(--accent, #94a3b8) 8%, transparent);\n color: #e2e8f0;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n cursor: pointer;\n transition:\n background 120ms ease,\n box-shadow 120ms ease;\n backdrop-filter: blur(2px);\n }\n .boundary:hover {\n background: color-mix(in srgb, var(--accent, #94a3b8) 14%, transparent);\n }\n .boundary.expanded {\n cursor: default;\n }\n .boundary.is-selected {\n box-shadow:\n 0 0 0 1px var(--accent),\n 0 0 0 4px color-mix(in srgb, var(--accent) 30%, transparent);\n }\n .header {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 10px 14px;\n border-bottom: 1px dashed\n color-mix(in srgb, var(--accent) 60%, transparent);\n background: color-mix(in srgb, var(--accent) 18%, #0f172a);\n border-radius: 14px 14px 0 0;\n }\n .chip {\n align-self: flex-start;\n font-size: 9px;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n padding: 2px 8px;\n border-radius: 999px;\n background: var(--accent);\n color: white;\n font-weight: 700;\n }\n .label {\n font-size: 14px;\n font-weight: 700;\n line-height: 1.15;\n color: #f8fafc;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .meta {\n font-size: 10px;\n color: rgba(226, 232, 240, 0.6);\n }\n</style>\n","<script lang=\"ts\">\n import { getContext } from \"svelte\";\n\n import { Handle, Position, type NodeProps } from \"@xyflow/svelte\";\n\n import { VIEW_ACTIONS, type ViewActions } from \"./actions.ts\";\n\n interface DatabaseNodeData {\n name: string;\n label: string;\n kind: string;\n description: string;\n external: boolean;\n technology: string;\n }\n\n let { data, selected }: NodeProps<{ data: DatabaseNodeData }> = $props();\n\n const actions = getContext<ViewActions>(VIEW_ACTIONS);\n\n // Database fill follows the C4 container/system gradient. Externals\n // drop to neutral grey per Simon Brown's reference palette so the\n // \"ours vs theirs\" distinction stays at a glance.\n const fill = $derived(data.external ? \"#475569\" : \"#1168bd\");\n</script>\n\n<div\n class=\"db\"\n class:external={data.external}\n class:is-selected={selected}\n style:--fill={fill}\n role=\"button\"\n tabindex=\"0\"\n onclick={() => actions?.selectElement(data.name)}\n onkeydown={(event) => {\n if (event.key === \"Enter\") actions?.selectElement(data.name);\n }}\n>\n <Handle type=\"target\" position={Position.Left} />\n <div class=\"cyl-top\" aria-hidden=\"true\"></div>\n <div class=\"body\">\n <span class=\"kind\">{data.kind}</span>\n <span class=\"label\">{data.label}</span>\n {#if data.technology}\n <span class=\"tech\">[{data.technology}]</span>\n {/if}\n {#if data.description}\n <span class=\"desc\">{data.description}</span>\n {/if}\n </div>\n <Handle type=\"source\" position={Position.Right} />\n</div>\n\n<style>\n .db {\n position: relative;\n display: grid;\n grid-template-rows: 14px 1fr;\n padding: 0;\n border-radius: 14px 14px 22px 22px / 14px 14px 30px 30px;\n background: linear-gradient(\n 180deg,\n var(--fill) 0%,\n color-mix(in srgb, var(--fill) 80%, black) 100%\n );\n color: #f8fafc;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n cursor: pointer;\n box-shadow:\n 0 10px 28px -18px color-mix(in srgb, var(--fill) 70%, transparent),\n inset 0 1px 0 rgba(255, 255, 255, 0.1);\n transition:\n transform 120ms ease,\n box-shadow 120ms ease;\n }\n .db:hover {\n transform: translateY(-1px);\n }\n .db.is-selected {\n outline: 2px solid #38bdf8;\n outline-offset: 2px;\n }\n .cyl-top {\n height: 14px;\n background: rgba(0, 0, 0, 0.18);\n border-radius: 14px 14px 50% 50% / 14px 14px 100% 100%;\n border-bottom: 1px solid rgba(255, 255, 255, 0.15);\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 10px 14px 14px;\n overflow: hidden;\n }\n .kind {\n font-size: 9px;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: rgba(248, 250, 252, 0.78);\n font-weight: 700;\n }\n .label {\n font-size: 13px;\n font-weight: 700;\n line-height: 1.15;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n }\n .tech {\n font-size: 10px;\n color: rgba(248, 250, 252, 0.85);\n font-style: italic;\n }\n .desc {\n font-size: 11px;\n line-height: 1.3;\n color: rgba(248, 250, 252, 0.75);\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n }\n</style>\n","<script lang=\"ts\">\n import { getContext } from \"svelte\";\n\n import { Handle, Position, type NodeProps } from \"@xyflow/svelte\";\n\n import { VIEW_ACTIONS, type ViewActions } from \"./actions.ts\";\n\n interface ElementNodeData {\n name: string;\n label: string;\n kind: string;\n description: string;\n external: boolean;\n technology: string;\n }\n\n let { data, selected }: NodeProps<{ data: ElementNodeData }> = $props();\n\n const actions = getContext<ViewActions>(VIEW_ACTIONS);\n\n // Simon Brown / c4model.com canonical palette: deeper blue for\n // higher-level abstractions, fading to lighter shades as we drill\n // down. Externals collapse to neutral slate so they read as\n // \"someone else's box.\"\n const palette = (kind: string, external: boolean): string => {\n if (external) return \"#475569\";\n if (kind === \"System\") return \"#1168bd\";\n if (kind === \"Container\") return \"#438dd5\";\n if (kind === \"Component\") return \"#85bbf0\";\n return \"#1168bd\";\n };\n const fill = $derived(palette(data.kind, data.external));\n const textColor = $derived(\n data.kind === \"Component\" && !data.external ? \"#0f172a\" : \"#f8fafc\",\n );\n</script>\n\n<div\n class=\"el\"\n class:external={data.external}\n class:is-selected={selected}\n style:--fill={fill}\n style:--text={textColor}\n role=\"button\"\n tabindex=\"0\"\n onclick={() => actions?.selectElement(data.name)}\n onkeydown={(event) => {\n if (event.key === \"Enter\") actions?.selectElement(data.name);\n }}\n>\n <Handle type=\"target\" position={Position.Left} />\n <div class=\"head\">\n <span class=\"kind\">{data.kind}{data.external ? \" · external\" : \"\"}</span>\n </div>\n <span class=\"label\">{data.label}</span>\n {#if data.technology}\n <span class=\"tech\">[{data.technology}]</span>\n {/if}\n {#if data.description}\n <span class=\"desc\">{data.description}</span>\n {/if}\n <Handle type=\"source\" position={Position.Right} />\n</div>\n\n<style>\n .el {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 12px 14px 14px;\n border-radius: 12px;\n background: linear-gradient(\n 180deg,\n var(--fill) 0%,\n color-mix(in srgb, var(--fill) 82%, black) 100%\n );\n color: var(--text, #f8fafc);\n box-shadow:\n 0 10px 28px -18px color-mix(in srgb, var(--fill) 70%, transparent),\n inset 0 1px 0 rgba(255, 255, 255, 0.08);\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n cursor: pointer;\n transition:\n transform 120ms ease,\n box-shadow 120ms ease;\n }\n .el:hover {\n transform: translateY(-1px);\n box-shadow:\n 0 14px 36px -16px color-mix(in srgb, var(--fill) 80%, transparent),\n inset 0 1px 0 rgba(255, 255, 255, 0.12);\n }\n .el.is-selected {\n outline: 2px solid #38bdf8;\n outline-offset: 2px;\n }\n .head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n .kind {\n font-size: 9px;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: color-mix(in srgb, var(--text) 70%, transparent);\n font-weight: 700;\n }\n .label {\n font-size: 14px;\n font-weight: 700;\n line-height: 1.15;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n }\n .tech {\n font-size: 10px;\n color: color-mix(in srgb, var(--text) 85%, transparent);\n font-style: italic;\n }\n .desc {\n font-size: 11px;\n line-height: 1.3;\n color: color-mix(in srgb, var(--text) 78%, transparent);\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n }\n</style>\n","<script lang=\"ts\">\n import { getContext } from \"svelte\";\n\n import { Handle, Position, type NodeProps } from \"@xyflow/svelte\";\n\n import { VIEW_ACTIONS, type ViewActions } from \"./actions.ts\";\n\n interface PersonNodeData {\n name: string;\n label: string;\n description: string;\n external: boolean;\n technology: string;\n }\n\n let { data, selected }: NodeProps<{ data: PersonNodeData }> = $props();\n\n const actions = getContext<ViewActions>(VIEW_ACTIONS);\n</script>\n\n<div\n class=\"person\"\n class:external={data.external}\n class:is-selected={selected}\n role=\"button\"\n tabindex=\"0\"\n onclick={() => actions?.selectElement(data.name)}\n onkeydown={(event) => {\n if (event.key === \"Enter\") actions?.selectElement(data.name);\n }}\n>\n <Handle type=\"target\" position={Position.Left} />\n <div class=\"head\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" class=\"silhouette\" xmlns=\"http://www.w3.org/2000/svg\">\n <!-- Head + shoulders silhouette. Two distinct shapes so it\n reads as a person at a glance, with no overlap between\n the head circle and the rounded shoulders below. -->\n <circle cx=\"12\" cy=\"7\" r=\"4\" />\n <path d=\"M4 21c0-4.42 3.58-8 8-8s8 3.58 8 8\" />\n </svg>\n </div>\n <div class=\"body\">\n <span class=\"kind\">Person</span>\n <span class=\"label\">{data.label}</span>\n {#if data.description}\n <span class=\"desc\">{data.description}</span>\n {/if}\n </div>\n <Handle type=\"source\" position={Position.Right} />\n</div>\n\n<style>\n .person {\n display: grid;\n grid-template-rows: 36px 1fr;\n gap: 6px;\n padding: 12px 14px 14px;\n border-radius: 14px;\n background: linear-gradient(180deg, #08427b 0%, #073768 100%);\n color: #f8fafc;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n cursor: pointer;\n box-shadow:\n 0 10px 30px -18px rgba(8, 66, 123, 0.85),\n inset 0 1px 0 rgba(255, 255, 255, 0.08);\n transition:\n transform 120ms ease,\n box-shadow 120ms ease;\n }\n .person:hover {\n transform: translateY(-1px);\n box-shadow:\n 0 14px 40px -16px rgba(8, 66, 123, 0.95),\n inset 0 1px 0 rgba(255, 255, 255, 0.12);\n }\n .person.is-selected {\n outline: 2px solid #38bdf8;\n outline-offset: 2px;\n }\n .person.external {\n background: linear-gradient(180deg, #475569 0%, #334155 100%);\n }\n .head {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .silhouette {\n width: 28px;\n height: 28px;\n color: #f8fafc;\n opacity: 0.92;\n }\n .silhouette circle {\n fill: currentColor;\n }\n .silhouette path {\n fill: none;\n stroke: currentColor;\n stroke-width: 2;\n stroke-linecap: round;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: 2px;\n align-items: center;\n text-align: center;\n }\n .kind {\n font-size: 9px;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: rgba(248, 250, 252, 0.75);\n font-weight: 700;\n }\n .label {\n font-size: 14px;\n font-weight: 700;\n line-height: 1.15;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n }\n .desc {\n font-size: 11px;\n line-height: 1.25;\n color: rgba(248, 250, 252, 0.7);\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n }\n</style>\n","<script lang=\"ts\">\n import { getContext } from \"svelte\";\n\n import { Handle, Position, type NodeProps } from \"@xyflow/svelte\";\n\n import { VIEW_ACTIONS, type ViewActions } from \"./actions.ts\";\n\n interface QueueNodeData {\n name: string;\n label: string;\n kind: string;\n description: string;\n external: boolean;\n technology: string;\n }\n\n let { data, selected }: NodeProps<{ data: QueueNodeData }> = $props();\n\n const actions = getContext<ViewActions>(VIEW_ACTIONS);\n\n const fill = $derived(data.external ? \"#475569\" : \"#1168bd\");\n</script>\n\n<div\n class=\"q\"\n class:external={data.external}\n class:is-selected={selected}\n style:--fill={fill}\n role=\"button\"\n tabindex=\"0\"\n onclick={() => actions?.selectElement(data.name)}\n onkeydown={(event) => {\n if (event.key === \"Enter\") actions?.selectElement(data.name);\n }}\n>\n <Handle type=\"target\" position={Position.Left} />\n <div class=\"body\">\n <span class=\"kind\">{data.kind}</span>\n <span class=\"label\">{data.label}</span>\n {#if data.technology}\n <span class=\"tech\">[{data.technology}]</span>\n {/if}\n {#if data.description}\n <span class=\"desc\">{data.description}</span>\n {/if}\n </div>\n <Handle type=\"source\" position={Position.Right} />\n</div>\n\n<style>\n .q {\n display: flex;\n flex-direction: column;\n gap: 0;\n padding: 0;\n /* Pipe / capsule end-caps so it reads as a queue at a glance. */\n border-radius: 999px;\n background: linear-gradient(\n 180deg,\n var(--fill) 0%,\n color-mix(in srgb, var(--fill) 80%, black) 100%\n );\n color: #f8fafc;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n cursor: pointer;\n box-shadow:\n 0 10px 28px -18px color-mix(in srgb, var(--fill) 70%, transparent),\n inset 0 1px 0 rgba(255, 255, 255, 0.1);\n transition: transform 120ms ease;\n }\n .q:hover {\n transform: translateY(-1px);\n }\n .q.is-selected {\n outline: 2px solid #38bdf8;\n outline-offset: 2px;\n }\n .body {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 14px 22px;\n overflow: hidden;\n height: 100%;\n justify-content: center;\n }\n .kind {\n font-size: 9px;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: rgba(248, 250, 252, 0.78);\n font-weight: 700;\n }\n .label {\n font-size: 13px;\n font-weight: 700;\n line-height: 1.15;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n }\n .tech {\n font-size: 10px;\n color: rgba(248, 250, 252, 0.85);\n font-style: italic;\n }\n .desc {\n font-size: 11px;\n line-height: 1.3;\n color: rgba(248, 250, 252, 0.75);\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n }\n</style>\n","import ELK from \"elkjs/lib/elk.bundled.js\";\n\n/**\n * Why ELK runs on the main thread:\n *\n * `elkjs/lib/elk.bundled.js` internally spawns its own compute\n * kernel as a Web Worker via `require('./elk-worker.min.js')`.\n * That `require()` is dynamic UMD plumbing which Vite cannot\n * trace through, so when we wrap ELK in our OWN Worker the\n * bundled output ends up with `e('./elk-worker.min.js').Worker`\n * resolving to undefined → `new undefined()` → `TypeError: o is\n * not a constructor` at runtime. We tried `worker.format: \"es\"`\n * + `?worker` import; same failure.\n *\n * Layout performance for the model sizes aact view targets (50\n * nodes / 100 relations sub-second) doesn't justify the extra\n * infra to inline ELK's nested worker. If we ever need it we'll\n * either ship `elk-worker.min.js` as a separately-served asset\n * (`?url` import + `new ELK({ workerUrl })`) or vendor the\n * synchronous Java→JS fallback path. For now: in-process.\n */\nconst elk = new ELK();\n\nexport const runElkLayout = <T>(graph: unknown): Promise<T> =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ELK input types are deeply structural; the call sites already pass typed nodes/edges\n elk.layout(graph as any) as Promise<T>;\n","import { MarkerType, type Edge, type Node } from \"@xyflow/svelte\";\n\nimport type { Boundary, Element, Model } from \"./types.ts\";\nimport { runElkLayout } from \"./layoutWorkerClient.ts\";\n\n/**\n * Three layout strategies sharing one ELK pipeline:\n *\n * - `layoutScope` — Drill mode. Flat layout for the current\n * breadcrumb level; siblings only, parents are\n * replaced as the user descends.\n *\n * - `layoutNested` — Expand-in-place mode. Boundaries the user\n * toggles open render inline as containers,\n * with their children visible alongside parent\n * siblings.\n *\n * - `layoutFlat` — Full hierarchy. Every boundary in the model\n * starts expanded; user sees the whole tree at\n * once. Useful for an overview or print.\n *\n * Nested and Flat both share the same ELK `INCLUDE_CHILDREN` tree\n * and `parentId` flattening — Flat is just \"expanded = every\n * boundary name\" preconfigured.\n *\n * The id-prefix convention (`b:` for boundaries, `e:` for elements)\n * is exported so node components and click handlers can decode IDs.\n */\nconst LEAF_WIDTH = 220;\nconst LEAF_HEIGHT = 110;\nconst PERSON_WIDTH = 200;\nconst PERSON_HEIGHT = 130;\nconst BOUNDARY_MIN_WIDTH = 260;\nconst BOUNDARY_MIN_HEIGHT = 160;\n\nexport const elementId = (name: string): string => `e:${name}`;\nexport const boundaryId = (name: string): string => `b:${name}`;\n\nconst leafSize = (kind: Element[\"kind\"]): { width: number; height: number } =>\n kind === \"Person\"\n ? { width: PERSON_WIDTH, height: PERSON_HEIGHT }\n : { width: LEAF_WIDTH, height: LEAF_HEIGHT };\n\nconst elementNodeType = (kind: Element[\"kind\"]): string => {\n if (kind === \"Person\") return \"person\";\n if (kind === \"SystemDb\" || kind === \"ContainerDb\" || kind === \"ComponentDb\")\n return \"database\";\n if (\n kind === \"SystemQueue\" ||\n kind === \"ContainerQueue\" ||\n kind === \"ComponentQueue\"\n )\n return \"queue\";\n return \"element\";\n};\n\nconst elementNodeData = (e: Element): Record<string, unknown> => ({\n name: e.name,\n label: e.label,\n kind: e.kind,\n description: e.description ?? \"\",\n external: e.external,\n technology: e.technology ?? \"\",\n tags: e.tags,\n});\n\nconst boundaryNodeData = (\n b: Boundary,\n options: { expanded: boolean; canExpand: boolean },\n): Record<string, unknown> => ({\n name: b.name,\n label: b.label,\n kind: b.kind,\n childCount: b.elementNames.length + b.boundaryNames.length,\n expanded: options.expanded,\n canExpand: options.canExpand,\n});\n\nexport interface LayoutScope {\n readonly elements: readonly Element[];\n readonly boundaries: readonly Boundary[];\n readonly relations: ReadonlyArray<{\n readonly from: string;\n readonly to: string;\n readonly label?: string;\n readonly count?: number;\n readonly fromKind?: \"element\" | \"boundary\";\n readonly toKind?: \"element\" | \"boundary\";\n }>;\n}\n\nexport interface LayoutResult {\n readonly nodes: Node[];\n readonly edges: Edge[];\n}\n\n// Dense C4 landscapes routinely have 50+ relations passing through a\n// shared API gateway. Bumping `edgeEdge` / `edgeNode` spacing keeps\n// parallel edges visually separated while letting ELK pick the\n// routing strategy that works for the node layout. The xyflow-side\n// edge type (bezier / smoothstep / step) is chosen by the user from\n// the topbar — see `EdgeStyle` in App.svelte.\nconst layeredOptions = {\n \"elk.algorithm\": \"layered\",\n \"elk.direction\": \"RIGHT\",\n \"elk.layered.spacing.nodeNodeBetweenLayers\": \"90\",\n \"elk.spacing.nodeNode\": \"50\",\n \"elk.spacing.edgeEdge\": \"20\",\n \"elk.spacing.edgeNode\": \"30\",\n \"elk.layered.spacing.edgeEdgeBetweenLayers\": \"20\",\n \"elk.layered.spacing.edgeNodeBetweenLayers\": \"30\",\n \"elk.padding\": \"[top=48, left=44, bottom=44, right=44]\",\n};\n\nconst formatEdgeLabel = (\n label: string | undefined,\n count: number | undefined,\n): string | undefined => {\n if (!count || count <= 1) return label;\n return label ? `${label} · ×${count}` : `×${count}`;\n};\n\n/** ----------------------------------------------------------------\n * Drill mode (existing behaviour). One scope, flat layout.\n * ---------------------------------------------------------------- */\n\nexport const layoutScope = async (\n scope: LayoutScope,\n): Promise<LayoutResult> => {\n const edgeId = (\n r: LayoutScope[\"relations\"][number],\n ): { source: string; target: string } => ({\n source: r.fromKind === \"boundary\" ? boundaryId(r.from) : elementId(r.from),\n target: r.toKind === \"boundary\" ? boundaryId(r.to) : elementId(r.to),\n });\n\n const elkChildren = [\n ...scope.boundaries.map((b) => ({\n id: boundaryId(b.name),\n width: BOUNDARY_MIN_WIDTH,\n height: BOUNDARY_MIN_HEIGHT,\n })),\n ...scope.elements.map((e) => ({\n id: elementId(e.name),\n ...leafSize(e.kind),\n })),\n ];\n const elkEdges = scope.relations.map((r, index) => {\n const { source, target } = edgeId(r);\n return { id: `edge-${index}`, sources: [source], targets: [target] };\n });\n\n const result = await runElkLayout<ElkResultNode>({\n id: \"root\",\n layoutOptions: layeredOptions,\n children: elkChildren,\n edges: elkEdges,\n });\n\n const nodes: Node[] = [];\n for (const b of scope.boundaries) {\n const id = boundaryId(b.name);\n const laid = result.children?.find((c) => c.id === id);\n nodes.push({\n id,\n type: \"boundary\",\n position: { x: laid?.x ?? 0, y: laid?.y ?? 0 },\n data: boundaryNodeData(b, { expanded: false, canExpand: false }),\n style: `width: ${laid?.width ?? BOUNDARY_MIN_WIDTH}px; height: ${laid?.height ?? BOUNDARY_MIN_HEIGHT}px;`,\n });\n }\n for (const e of scope.elements) {\n const id = elementId(e.name);\n const laid = result.children?.find((c) => c.id === id);\n const { width, height } = leafSize(e.kind);\n nodes.push({\n id,\n type: elementNodeType(e.kind),\n position: { x: laid?.x ?? 0, y: laid?.y ?? 0 },\n data: elementNodeData(e),\n style: `width: ${width}px; height: ${height}px;`,\n });\n }\n\n const edges: Edge[] = scope.relations.map((r, index) => {\n const { source, target } = edgeId(r);\n return {\n id: `edge-${index}`,\n source,\n target,\n label: formatEdgeLabel(r.label, r.count),\n type: \"default\",\n animated: false,\n // Drill mode aggregates by construction — every surviving\n // relation crosses a Bounded Context boundary (intra-boundary\n // relations were filtered out by buildScopeRelations).\n data: { crossBoundary: true },\n markerEnd: {\n type: MarkerType.ArrowClosed,\n width: 24,\n height: 24,\n color: \"#cbd5e1\",\n },\n // @xyflow/svelte 1.x renders the label as an HTML <div>, so\n // styling goes through CSS / CSS variables (see App.svelte).\n // The SVG-era `labelBgStyle` / `labelBgPadding` props are\n // no-ops here — omitting them keeps the edge payload clean.\n style: \"stroke: #94a3b8; stroke-width: 1.8;\",\n };\n });\n\n return { nodes, edges };\n};\n\n/** ----------------------------------------------------------------\n * Shared ownership infrastructure (Drill aggregation + Nested\n * endpoint resolution).\n * ---------------------------------------------------------------- */\n\nconst buildParentMap = (model: Model): Map<string, string> => {\n const parent = new Map<string, string>();\n for (const b of Object.values(model.boundaries)) {\n for (const child of b.boundaryNames) parent.set(child, b.name);\n for (const el of b.elementNames) parent.set(el, b.name);\n }\n return parent;\n};\n\nconst buildOwnership = (\n model: Model,\n visibleBoundaryNames: ReadonlySet<string>,\n visibleElementNames: ReadonlySet<string>,\n): Map<string, { kind: \"element\" | \"boundary\"; name: string }> => {\n const owner = new Map<\n string,\n { kind: \"element\" | \"boundary\"; name: string }\n >();\n\n for (const name of visibleElementNames) {\n owner.set(name, { kind: \"element\", name });\n }\n\n const walk = (b: Boundary, top: Boundary): void => {\n for (const n of b.elementNames) {\n if (!owner.has(n)) {\n owner.set(n, { kind: \"boundary\", name: top.name });\n }\n }\n for (const child of b.boundaryNames) {\n const cb = model.boundaries[child];\n if (!cb) continue;\n walk(cb, top);\n }\n };\n for (const name of visibleBoundaryNames) {\n const b = model.boundaries[name];\n if (b) walk(b, b);\n }\n\n return owner;\n};\n\nconst buildScopeRelations = (\n model: Model,\n owner: ReadonlyMap<string, { kind: \"element\" | \"boundary\"; name: string }>,\n): LayoutScope[\"relations\"] => {\n const out = new Map<string, LayoutScope[\"relations\"][number]>();\n for (const el of Object.values(model.elements)) {\n for (const rel of el.relations) {\n const fromOwner = owner.get(el.name);\n const toOwner = owner.get(rel.to);\n if (!fromOwner || !toOwner) continue;\n const fromKey =\n fromOwner.kind === \"boundary\"\n ? boundaryId(fromOwner.name)\n : elementId(fromOwner.name);\n const toKey =\n toOwner.kind === \"boundary\"\n ? boundaryId(toOwner.name)\n : elementId(toOwner.name);\n if (fromKey === toKey) continue;\n const key = `${fromKey}->${toKey}`;\n const existing = out.get(key);\n if (existing) {\n out.set(key, {\n ...existing,\n count: (existing.count ?? 1) + 1,\n });\n continue;\n }\n out.set(key, {\n from: fromOwner.name,\n to: toOwner.name,\n label:\n fromOwner.kind === \"boundary\" || toOwner.kind === \"boundary\"\n ? undefined\n : rel.description,\n fromKind: fromOwner.kind,\n toKind: toOwner.kind,\n count: 1,\n });\n }\n }\n return [...out.values()];\n};\n\nexport const sliceModel = (\n model: Model,\n breadcrumb: readonly {\n readonly kind: \"landscape\" | \"boundary\";\n readonly name?: string;\n }[],\n): LayoutScope => {\n const top = breadcrumb[breadcrumb.length - 1] ?? { kind: \"landscape\" };\n\n if (top.kind === \"landscape\") {\n const rootBoundaries = (model.rootBoundaryNames ?? [])\n .map((n) => model.boundaries[n])\n .filter((b): b is Boundary => Boolean(b));\n const visibleBoundaryNames = new Set(rootBoundaries.map((b) => b.name));\n const bounded = new Set<string>();\n const walk = (b: Boundary): void => {\n for (const n of b.elementNames) bounded.add(n);\n for (const child of b.boundaryNames) {\n const cb = model.boundaries[child];\n if (cb) walk(cb);\n }\n };\n for (const b of rootBoundaries) walk(b);\n const standalone = Object.values(model.elements).filter(\n (e) => !bounded.has(e.name),\n );\n const visibleElementNames = new Set(standalone.map((e) => e.name));\n const owner = buildOwnership(\n model,\n visibleBoundaryNames,\n visibleElementNames,\n );\n return {\n boundaries: rootBoundaries,\n elements: standalone,\n relations: buildScopeRelations(model, owner),\n };\n }\n\n const b = top.name ? model.boundaries[top.name] : undefined;\n if (!b) return { boundaries: [], elements: [], relations: [] };\n\n const elements = b.elementNames\n .map((n) => model.elements[n])\n .filter((e): e is Element => Boolean(e));\n const boundaries = b.boundaryNames\n .map((n) => model.boundaries[n])\n .filter((nb): nb is Boundary => Boolean(nb));\n const visibleBoundaryNames = new Set(boundaries.map((nb) => nb.name));\n const visibleElementNames = new Set(elements.map((e) => e.name));\n const owner = buildOwnership(\n model,\n visibleBoundaryNames,\n visibleElementNames,\n );\n return {\n boundaries,\n elements,\n relations: buildScopeRelations(model, owner),\n };\n};\n\n/** ----------------------------------------------------------------\n * Nested / Flat modes — hierarchical layout with `parentId`.\n * ---------------------------------------------------------------- */\n\ninterface ElkInputNode {\n id: string;\n width?: number;\n height?: number;\n children?: ElkInputNode[];\n edges?: ElkInputEdge[];\n layoutOptions?: Record<string, string>;\n}\n\n// Expanded boundaries reserve extra top-padding so children render\n// below the BoundaryNode's header (kind chip + label + meta line)\n// instead of being painted on top of it. The header is ~76px tall —\n// 96 gives a clean margin.\nconst containerLayoutOptions: Record<string, string> = {\n ...layeredOptions,\n \"elk.padding\": \"[top=96, left=44, bottom=44, right=44]\",\n};\n\ninterface ElkInputEdge {\n id: string;\n sources: string[];\n targets: string[];\n}\n\nconst buildNestedTree = (\n model: Model,\n expanded: ReadonlySet<string>,\n rootBoundaries: readonly Boundary[],\n standalone: readonly Element[],\n edges: readonly ElkInputEdge[],\n): ElkInputNode => {\n const renderBoundary = (b: Boundary): ElkInputNode => {\n if (!expanded.has(b.name)) {\n return {\n id: boundaryId(b.name),\n width: BOUNDARY_MIN_WIDTH,\n height: BOUNDARY_MIN_HEIGHT,\n };\n }\n const children: ElkInputNode[] = [];\n for (const childName of b.boundaryNames) {\n const child = model.boundaries[childName];\n if (child) children.push(renderBoundary(child));\n }\n for (const childName of b.elementNames) {\n const child = model.elements[childName];\n if (child) {\n children.push({\n id: elementId(child.name),\n ...leafSize(child.kind),\n });\n }\n }\n return {\n id: boundaryId(b.name),\n children,\n layoutOptions: containerLayoutOptions,\n };\n };\n\n return {\n id: \"root\",\n layoutOptions: {\n ...layeredOptions,\n // INCLUDE_CHILDREN lets edges cross hierarchy levels — without\n // it `layered` errors on edges that span containers. With\n // edges in the input, ELK has the dependency data it needs to\n // build proper left-to-right layers; otherwise it stacks\n // everything in a single column.\n \"elk.hierarchyHandling\": \"INCLUDE_CHILDREN\",\n },\n children: [\n ...rootBoundaries.map(renderBoundary),\n ...standalone.map((e) => ({\n id: elementId(e.name),\n ...leafSize(e.kind),\n })),\n ],\n edges: [...edges],\n };\n};\n\n/**\n * Resolve a relation endpoint to the deepest visible node id.\n * Walks up the parent chain; if a parent isn't expanded, the\n * collapsed parent becomes the visible endpoint instead.\n */\nconst visibleEndpoint = (\n name: string,\n kindHint: \"element\" | \"boundary\",\n expanded: ReadonlySet<string>,\n parentMap: ReadonlyMap<string, string>,\n): { id: string; kind: \"element\" | \"boundary\"; name: string } => {\n let current = name;\n let kind: \"element\" | \"boundary\" = kindHint;\n for (;;) {\n const parent = parentMap.get(current);\n if (parent === undefined || expanded.has(parent)) {\n return {\n id: kind === \"boundary\" ? boundaryId(current) : elementId(current),\n kind,\n name: current,\n };\n }\n current = parent;\n kind = \"boundary\";\n }\n};\n\ninterface ElkResultNode {\n id: string;\n x?: number;\n y?: number;\n width?: number;\n height?: number;\n children?: readonly ElkResultNode[];\n}\n\n/**\n * Flatten ELK's nested result into Svelte Flow nodes. ELK returns\n * child positions relative to their parent — exactly what\n * `parentId` + `extent: \"parent\"` expects.\n */\nconst flattenElkResult = (\n results: readonly ElkResultNode[],\n model: Model,\n expanded: ReadonlySet<string>,\n parentId: string | undefined,\n): Node[] => {\n const out: Node[] = [];\n for (const r of results) {\n const x = r.x ?? 0;\n const y = r.y ?? 0;\n const width = r.width ?? 0;\n const height = r.height ?? 0;\n const isBoundary = r.id.startsWith(\"b:\");\n const name = r.id.slice(2);\n if (isBoundary) {\n const b = model.boundaries[name];\n if (!b) continue;\n const isExpanded = expanded.has(name);\n const node: Node = {\n id: r.id,\n type: \"boundary\",\n position: { x, y },\n data: boundaryNodeData(b, { expanded: isExpanded, canExpand: true }),\n style: `width: ${width}px; height: ${height}px;`,\n };\n if (parentId) {\n node.parentId = parentId;\n node.extent = \"parent\";\n }\n out.push(node);\n if (isExpanded && r.children?.length) {\n out.push(...flattenElkResult(r.children, model, expanded, r.id));\n }\n } else {\n const el = model.elements[name];\n if (!el) continue;\n const { width: dw, height: dh } = leafSize(el.kind);\n const node: Node = {\n id: r.id,\n type: elementNodeType(el.kind),\n position: { x, y },\n data: elementNodeData(el),\n style: `width: ${width || dw}px; height: ${height || dh}px;`,\n };\n if (parentId) {\n node.parentId = parentId;\n node.extent = \"parent\";\n }\n out.push(node);\n }\n }\n return out;\n};\n\n/**\n * \"Cross-boundary\" is a property of the original relation, not of\n * its visible-endpoint resolution. We compute it from the elements'\n * immediate boundary parents:\n * - both elements share a non-null immediate parent → intra\n * - everything else (different parents, one at root) → cross\n *\n * The flag travels with the edge as `data.crossBoundary` so\n * App.svelte's \"cross-boundary only\" filter can dim intra edges\n * without re-running ELK.\n */\nconst isCrossBoundary = (\n fromName: string,\n toName: string,\n parentMap: ReadonlyMap<string, string>,\n): boolean => {\n const fp = parentMap.get(fromName) ?? null;\n const tp = parentMap.get(toName) ?? null;\n return fp === null || tp === null || fp !== tp;\n};\n\nconst collectVisibleEdges = (\n model: Model,\n expanded: ReadonlySet<string>,\n parentMap: ReadonlyMap<string, string>,\n): Edge[] => {\n const seen = new Map<string, Edge>();\n let index = 0;\n for (const el of Object.values(model.elements)) {\n for (const rel of el.relations) {\n const from = visibleEndpoint(el.name, \"element\", expanded, parentMap);\n const to = visibleEndpoint(rel.to, \"element\", expanded, parentMap);\n if (from.id === to.id) continue;\n const key = `${from.id}->${to.id}`;\n const crossBoundary = isCrossBoundary(el.name, rel.to, parentMap);\n const existing = seen.get(key);\n if (existing) {\n const data = existing.data as\n | {\n readonly crossBoundary?: boolean;\n readonly primaryLabel?: string;\n readonly relationCount?: number;\n }\n | undefined;\n const relationCount = (data?.relationCount ?? 1) + 1;\n seen.set(key, {\n ...existing,\n label: formatEdgeLabel(data?.primaryLabel, relationCount),\n data: {\n ...data,\n crossBoundary: Boolean(data?.crossBoundary) || crossBoundary,\n relationCount,\n },\n });\n continue;\n }\n const primaryLabel =\n from.kind === \"element\" && to.kind === \"element\"\n ? rel.description\n : undefined;\n seen.set(key, {\n id: `edge-${index++}`,\n source: from.id,\n target: to.id,\n label: primaryLabel,\n type: \"default\",\n animated: false,\n data: { crossBoundary, primaryLabel, relationCount: 1 },\n markerEnd: {\n type: MarkerType.ArrowClosed,\n width: 24,\n height: 24,\n color: \"#cbd5e1\",\n },\n style: \"stroke: #94a3b8; stroke-width: 1.8;\",\n });\n }\n }\n return [...seen.values()];\n};\n\nconst collectStandaloneAndRoots = (\n model: Model,\n): { rootBoundaries: Boundary[]; standalone: Element[] } => {\n const rootBoundaries = (model.rootBoundaryNames ?? [])\n .map((n) => model.boundaries[n])\n .filter((b): b is Boundary => Boolean(b));\n const bounded = new Set<string>();\n const walk = (b: Boundary): void => {\n for (const n of b.elementNames) bounded.add(n);\n for (const child of b.boundaryNames) {\n const cb = model.boundaries[child];\n if (cb) walk(cb);\n }\n };\n for (const b of rootBoundaries) walk(b);\n const standalone = Object.values(model.elements).filter(\n (e) => !bounded.has(e.name),\n );\n return { rootBoundaries, standalone };\n};\n\nexport const layoutNested = async (\n model: Model,\n expanded: ReadonlySet<string>,\n): Promise<LayoutResult> => {\n const { rootBoundaries, standalone } = collectStandaloneAndRoots(model);\n const parentMap = buildParentMap(model);\n const edges = collectVisibleEdges(model, expanded, parentMap);\n\n // ELK and Svelte Flow share the same edge identity. ELK uses the\n // edges to compute layers (without them the layered algorithm\n // collapses to a single vertical column); Svelte Flow uses them\n // to render the lines after we hand back the layout result.\n const elkEdges: ElkInputEdge[] = edges.map((e) => ({\n id: e.id,\n sources: [e.source],\n targets: [e.target],\n }));\n\n const tree = buildNestedTree(\n model,\n expanded,\n rootBoundaries,\n standalone,\n elkEdges,\n );\n const result = await runElkLayout<ElkResultNode>(tree);\n const nodes = flattenElkResult(\n result.children ?? [],\n model,\n expanded,\n undefined,\n );\n return { nodes, edges };\n};\n\n/**\n * Flat mode = every boundary in the model is expanded from the\n * start. Use this for a single overview rendering of the full\n * tree (good for print / read-only big-picture view).\n */\nexport const layoutFlat = (model: Model): Promise<LayoutResult> => {\n const everyBoundary = new Set(Object.keys(model.boundaries));\n return layoutNested(model, everyBoundary);\n};\n","<script lang=\"ts\">\n import { setContext } from \"svelte\";\n\n import {\n SvelteFlow,\n SvelteFlowProvider,\n Background,\n Controls,\n MiniMap,\n MarkerType,\n type Node,\n type Edge,\n } from \"@xyflow/svelte\";\n import \"@xyflow/svelte/dist/style.css\";\n\n import BoundaryNode from \"./BoundaryNode.svelte\";\n import DatabaseNode from \"./DatabaseNode.svelte\";\n import ElementNode from \"./ElementNode.svelte\";\n import PersonNode from \"./PersonNode.svelte\";\n import QueueNode from \"./QueueNode.svelte\";\n import {\n layoutFlat,\n layoutNested,\n layoutScope,\n sliceModel,\n } from \"./layout.ts\";\n import type {\n BreadcrumbEntry,\n Element,\n Boundary,\n ModelIssue,\n ModelEnvelope,\n Relation,\n ServerMessage,\n ViewError,\n } from \"./types.ts\";\n import { VIEW_ACTIONS, type ViewActions } from \"./actions.ts\";\n\n type ViewMode = \"drill\" | \"expand\" | \"flat\";\n type EdgeStyle = \"bezier\" | \"smoothstep\" | \"step\";\n type EdgeFilter = \"all\" | \"cross-boundary\";\n interface IncomingRelation {\n readonly from: string;\n readonly relation: Relation;\n }\n\n // Persist edge-style + edge-filter choices across page reloads —\n // both are personal preferences with no model coupling, so we\n // bring them back next session instead of resetting.\n const EDGE_STYLE_KEY = \"aact-view:edge-style\";\n const EDGE_FILTER_KEY = \"aact-view:edge-filter\";\n const initialEdgeStyle =\n (typeof localStorage !== \"undefined\" &&\n (localStorage.getItem(EDGE_STYLE_KEY) as EdgeStyle | null)) ||\n \"bezier\";\n const initialEdgeFilter =\n (typeof localStorage !== \"undefined\" &&\n (localStorage.getItem(EDGE_FILTER_KEY) as EdgeFilter | null)) ||\n \"all\";\n\n let envelope = $state<ModelEnvelope | null>(null);\n let mode = $state<ViewMode>(\"drill\");\n let edgeStyle = $state<EdgeStyle>(initialEdgeStyle);\n let edgeFilter = $state<EdgeFilter>(initialEdgeFilter);\n let breadcrumb = $state<BreadcrumbEntry[]>([{ kind: \"landscape\" }]);\n let expanded = $state<Set<string>>(new Set());\n let selected = $state<\n | { kind: \"element\"; name: string }\n | { kind: \"boundary\"; name: string }\n | null\n >(null);\n let hoveredNodeId = $state<string | null>(null);\n let nodes = $state<Node[]>([]);\n let edges = $state<Edge[]>([]);\n let status = $state<\"connecting\" | \"live\" | \"lost\" | \"error\">(\n \"connecting\",\n );\n let loadError = $state<ViewError | null>(null);\n\n const nodeTypes = {\n element: ElementNode,\n person: PersonNode,\n database: DatabaseNode,\n queue: QueueNode,\n boundary: BoundaryNode,\n } as const;\n\n // Re-layout whenever model, mode, breadcrumb, or expanded set\n // changes. Each branch hands a different ELK invocation back the\n // same `{nodes, edges}` shape so the render code stays uniform.\n $effect(() => {\n if (!envelope) return;\n let cancelled = false;\n const run = async (): Promise<void> => {\n if (mode === \"drill\") {\n const scope = sliceModel(envelope!.data.model, breadcrumb);\n const result = await layoutScope(scope);\n if (cancelled) return;\n nodes = result.nodes;\n edges = result.edges;\n } else if (mode === \"expand\") {\n const result = await layoutNested(envelope!.data.model, expanded);\n if (cancelled) return;\n nodes = result.nodes;\n edges = result.edges;\n } else {\n const result = await layoutFlat(envelope!.data.model);\n if (cancelled) return;\n nodes = result.nodes;\n edges = result.edges;\n }\n };\n void run();\n return () => {\n cancelled = true;\n };\n });\n\n const sessionToken =\n typeof location !== \"undefined\"\n ? new URLSearchParams(location.search).get(\"token\")\n : null;\n\n const withSessionToken = (path: string): string =>\n sessionToken ? `${path}?token=${encodeURIComponent(sessionToken)}` : path;\n\n const fetchModel = async (): Promise<ModelEnvelope> => {\n const res = await fetch(withSessionToken(\"/api/model\"));\n if (!res.ok) throw new Error(`/api/model returned ${res.status}`);\n return (await res.json()) as ModelEnvelope;\n };\n\n const wsUrl = (() => {\n const proto = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n return `${proto}//${location.host}${withSessionToken(\"/api/ws\")}`;\n })();\n\n const clientError = (error: unknown): ViewError => ({\n message: error instanceof Error ? error.message : String(error),\n source: envelope?.meta.source ?? null,\n configPath: envelope?.meta.configPath ?? null,\n durationMs: 0,\n at: new Date().toISOString(),\n });\n\n const connect = (): void => {\n const ws = new WebSocket(wsUrl);\n ws.addEventListener(\"open\", () => {\n status = \"live\";\n });\n ws.addEventListener(\"message\", (ev) => {\n try {\n const payload = JSON.parse(ev.data) as ServerMessage;\n if (payload.type === \"model-update\") {\n envelope = payload.envelope;\n loadError = null;\n status = \"live\";\n }\n if (payload.type === \"model-error\") {\n loadError = payload.error;\n status = \"error\";\n }\n } catch {\n // ignore malformed payloads — server won't emit any\n }\n });\n ws.addEventListener(\"close\", () => {\n status = \"lost\";\n setTimeout(connect, 1000);\n });\n ws.addEventListener(\"error\", () => ws.close());\n };\n\n void fetchModel().then((env) => {\n envelope = env;\n loadError = null;\n connect();\n }).catch((error: unknown) => {\n loadError = clientError(error);\n status = \"error\";\n connect();\n });\n\n const onnodeclick = ({ node }: { node: Node }): void => {\n if (node.type === \"boundary\") {\n selected = { kind: \"boundary\", name: String(node.data.name) };\n } else {\n selected = { kind: \"element\", name: String(node.data.name) };\n }\n };\n\n // @xyflow/svelte 1.x exposes pointer events on the SvelteFlow\n // component as callback props. Pointer events fire for both mouse\n // and touch, so they cover the \"trace a relation\" UX better than\n // the deprecated mouse-only equivalents.\n const onnodepointerenter = ({ node }: { node: Node }): void => {\n hoveredNodeId = node.id;\n };\n const onnodepointerleave = (): void => {\n hoveredNodeId = null;\n };\n\n const actions: ViewActions = {\n selectElement: (name) => {\n selected = { kind: \"element\", name };\n },\n selectBoundary: (name) => {\n selected = { kind: \"boundary\", name };\n },\n enterBoundary: (name, label) => {\n // Drill-down only makes sense in Drill mode; in Expand mode\n // this is mapped to \"toggle\" by the BoundaryNode itself.\n if (mode !== \"drill\") return;\n breadcrumb = [...breadcrumb, { kind: \"boundary\", name, label }];\n selected = null;\n },\n toggleBoundary: (name) => {\n if (mode !== \"expand\") return;\n const next = new Set(expanded);\n if (next.has(name)) next.delete(name);\n else next.add(name);\n expanded = next;\n },\n };\n setContext(VIEW_ACTIONS, actions);\n\n const breadcrumbClick = (index: number): void => {\n breadcrumb = breadcrumb.slice(0, index + 1);\n selected = null;\n };\n\n const setMode = (next: ViewMode): void => {\n mode = next;\n // Mode change resets selection / breadcrumb so users don't\n // chase the wrong context when switching strategies.\n selected = null;\n if (next === \"drill\") {\n breadcrumb = [{ kind: \"landscape\" }];\n }\n if (next === \"expand\") {\n expanded = new Set();\n }\n };\n\n const collapseAll = (): void => {\n expanded = new Set();\n };\n const expandAll = (): void => {\n if (!envelope) return;\n expanded = new Set(Object.keys(envelope.data.model.boundaries));\n };\n\n const selectedElement = $derived<Element | null>(\n selected?.kind === \"element\" && envelope\n ? (envelope.data.model.elements[selected.name] ?? null)\n : null,\n );\n const selectedBoundary = $derived<Boundary | null>(\n selected?.kind === \"boundary\" && envelope\n ? (envelope.data.model.boundaries[selected.name] ?? null)\n : null,\n );\n const incomingRelations = $derived<readonly IncomingRelation[]>(\n selectedElement && envelope\n ? Object.values(envelope.data.model.elements).flatMap((el) =>\n el.relations\n .filter((rel) => rel.to === selectedElement.name)\n .map((relation) => ({ from: el.name, relation })),\n )\n : [],\n );\n const selectedIssues = $derived<readonly ModelIssue[]>(\n selected && envelope\n ? envelope.data.issues.filter((issue) =>\n selected.kind === \"element\"\n ? issue.element === selected.name\n : issue.boundary === selected.name,\n )\n : [],\n );\n\n const setEdgeStyle = (next: EdgeStyle): void => {\n edgeStyle = next;\n if (typeof localStorage !== \"undefined\") {\n localStorage.setItem(EDGE_STYLE_KEY, next);\n }\n };\n const setEdgeFilter = (next: EdgeFilter): void => {\n edgeFilter = next;\n if (typeof localStorage !== \"undefined\") {\n localStorage.setItem(EDGE_FILTER_KEY, next);\n }\n };\n\n // Dim edges that aren't incident to the hovered node so the user\n // can trace a single dependency through a crowded canvas. Strip\n // labels from non-incident edges as well — at 30+ relations the\n // label chips pile up faster than the lines do. Re-write\n // markerEnd color explicitly because SVG markers don't inherit\n // `stroke` from the referencing path. Override `type` so the\n // topbar style toggle applies to every edge without re-running\n // ELK.\n const isCross = (e: Edge): boolean =>\n Boolean((e.data as { crossBoundary?: boolean } | undefined)?.crossBoundary);\n\n const decoratedEdges = $derived<Edge[]>(\n edges.map((e) => {\n const incident =\n hoveredNodeId !== null &&\n (e.source === hoveredNodeId || e.target === hoveredNodeId);\n const filterActive = edgeFilter === \"cross-boundary\";\n const cross = isCross(e);\n const intraInFilter = filterActive && !cross;\n const crossInFilter = filterActive && cross;\n\n // Filter overrides default rendering: intra disappears almost\n // entirely, cross gets thicker bright stroke so it visibly\n // \"lights up\" as the interesting subgraph. Hover still wins\n // for incident edges so dependency tracing keeps working.\n if (intraInFilter && !incident) {\n return {\n ...e,\n type: edgeStyle,\n animated: false,\n label: undefined,\n style: \"stroke: #1e293b; stroke-width: 0.8; opacity: 0.12;\",\n markerEnd: {\n type: MarkerType.ArrowClosed,\n width: 16,\n height: 16,\n color: \"#1e293b\",\n },\n };\n }\n if (crossInFilter && !hoveredNodeId) {\n return {\n ...e,\n type: edgeStyle,\n animated: false,\n style: \"stroke: #38bdf8; stroke-width: 2.2; opacity: 1;\",\n markerEnd: {\n type: MarkerType.ArrowClosed,\n width: 26,\n height: 26,\n color: \"#38bdf8\",\n },\n };\n }\n if (!hoveredNodeId) {\n return { ...e, type: edgeStyle };\n }\n const color = incident ? \"#38bdf8\" : \"#475569\";\n return {\n ...e,\n type: edgeStyle,\n animated: incident,\n label: incident ? e.label : undefined,\n style: incident\n ? \"stroke: #38bdf8; stroke-width: 2.4; opacity: 1;\"\n : \"stroke: #475569; stroke-width: 1.2; opacity: 0.35;\",\n markerEnd: {\n type: MarkerType.ArrowClosed,\n width: 24,\n height: 24,\n color,\n },\n };\n }),\n );\n\n const summary = $derived<{\n elements: number;\n boundaries: number;\n relations: number;\n issues: number;\n } | null>(\n envelope\n ? {\n elements: Object.keys(envelope.data.model.elements).length,\n boundaries: Object.keys(envelope.data.model.boundaries).length,\n relations: Object.values(envelope.data.model.elements).reduce(\n (acc, el) => acc + el.relations.length,\n 0,\n ),\n issues: envelope.data.issues.length,\n }\n : null,\n );\n\n // Translate a SourceLocation into a deep link the OS knows. Vendor\n // schemes match aact's CLI link format so the IDE the user already\n // configured for `aact check` handles the click here too.\n const sourceUrl = (\n file: string,\n line: number,\n col: number,\n ): string => {\n const opener =\n (typeof window !== \"undefined\" &&\n (window as { __AACT_OPENER__?: string }).__AACT_OPENER__) ||\n \"vscode\";\n const encodedFile = file\n .split(\"/\")\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n return `${opener}://file/${encodedFile}:${line}:${col}`;\n };\n\n const propertyEntries = (\n properties: Readonly<Record<string, string>> | undefined,\n ): readonly (readonly [string, string])[] => Object.entries(properties ?? {});\n\n const issueMessage = (issue: ModelIssue): string =>\n issue.message ? `${issue.kind}: ${issue.message}` : issue.kind;\n\n const minimapNodeColor = (node: Node): string => {\n const kind = String((node.data as { kind?: string } | undefined)?.kind);\n const external = Boolean(\n (node.data as { external?: boolean } | undefined)?.external,\n );\n if (node.type === \"person\") return \"#08427b\";\n if (external) return \"#475569\";\n if (kind === \"System\") return \"#1168bd\";\n if (kind === \"Container\") return \"#438dd5\";\n if (kind === \"Component\") return \"#85bbf0\";\n return \"#64748b\";\n };\n</script>\n\n<svelte:head>\n <title>aact view</title>\n</svelte:head>\n\n<div class=\"app\">\n <header class=\"topbar\">\n <div class=\"brand\">\n <span class=\"logo\">aact</span>\n <span class=\"sep\" aria-hidden=\"true\">·</span>\n <span class=\"title\">view</span>\n {#if envelope?.data.model.workspace?.name}\n <span class=\"sep\" aria-hidden=\"true\">·</span>\n <span class=\"workspace\" title={envelope.data.model.workspace.description ?? \"\"}>\n {envelope.data.model.workspace.name}\n </span>\n {/if}\n <span class=\"status status-{status}\">\n {#if status === \"live\"}● live\n {:else if status === \"error\"}● reload error\n {:else if status === \"lost\"}● disconnected — retrying\n {:else}● connecting\n {/if}\n </span>\n </div>\n\n <div class=\"topbar-controls\">\n <div class=\"modes\" role=\"tablist\" aria-label=\"View mode\">\n <button\n role=\"tab\"\n class:active={mode === \"drill\"}\n aria-selected={mode === \"drill\"}\n onclick={() => setMode(\"drill\")}\n title=\"Replace the canvas with the boundary you double-click\"\n >Drill</button>\n <button\n role=\"tab\"\n class:active={mode === \"expand\"}\n aria-selected={mode === \"expand\"}\n onclick={() => setMode(\"expand\")}\n title=\"Open boundaries inline — parents stay visible\"\n >Expand</button>\n <button\n role=\"tab\"\n class:active={mode === \"flat\"}\n aria-selected={mode === \"flat\"}\n onclick={() => setMode(\"flat\")}\n title=\"Render every level of the hierarchy at once\"\n >Flat</button>\n </div>\n <div class=\"modes edge-modes\" role=\"tablist\" aria-label=\"Edge style\">\n <button\n role=\"tab\"\n class:active={edgeStyle === \"bezier\"}\n aria-selected={edgeStyle === \"bezier\"}\n onclick={() => setEdgeStyle(\"bezier\")}\n title=\"Smooth bezier curves\"\n >Curve</button>\n <button\n role=\"tab\"\n class:active={edgeStyle === \"smoothstep\"}\n aria-selected={edgeStyle === \"smoothstep\"}\n onclick={() => setEdgeStyle(\"smoothstep\")}\n title=\"Rounded 90° corners — Structurizr-style\"\n >Smooth</button>\n <button\n role=\"tab\"\n class:active={edgeStyle === \"step\"}\n aria-selected={edgeStyle === \"step\"}\n onclick={() => setEdgeStyle(\"step\")}\n title=\"Sharp 90° corners\"\n >Step</button>\n </div>\n <div class=\"modes edge-modes\" role=\"tablist\" aria-label=\"Edge filter\">\n <button\n role=\"tab\"\n class:active={edgeFilter === \"all\"}\n aria-selected={edgeFilter === \"all\"}\n onclick={() => setEdgeFilter(\"all\")}\n title=\"Show every relation\"\n >All</button>\n <button\n role=\"tab\"\n class:active={edgeFilter === \"cross-boundary\"}\n aria-selected={edgeFilter === \"cross-boundary\"}\n onclick={() => setEdgeFilter(\"cross-boundary\")}\n title=\"Highlight relations that cross a Bounded Context; intra-boundary stays faint\"\n >Cross-BC</button>\n </div>\n </div>\n\n <div class=\"context\">\n {#if mode === \"drill\"}\n <nav class=\"breadcrumb\" aria-label=\"Drill path\">\n {#each breadcrumb as crumb, i (i)}\n {#if i > 0}<span class=\"bsep\" aria-hidden=\"true\">/</span>{/if}\n <button class=\"bcrumb\" onclick={() => breadcrumbClick(i)}>\n {crumb.kind === \"landscape\" ? \"Landscape\" : crumb.label}\n </button>\n {/each}\n </nav>\n {:else if mode === \"expand\"}\n <div class=\"expand-controls\">\n <button class=\"ghost\" onclick={expandAll}>Expand all</button>\n <button class=\"ghost\" onclick={collapseAll}>Collapse all</button>\n <span class=\"hint\">double-click a boundary to toggle</span>\n </div>\n {:else}\n <span class=\"hint\">full hierarchy — read-only overview</span>\n {/if}\n </div>\n </header>\n\n <main>\n <div class=\"graph\">\n <SvelteFlowProvider>\n <SvelteFlow\n {nodes}\n edges={decoratedEdges}\n {nodeTypes}\n {onnodeclick}\n {onnodepointerenter}\n {onnodepointerleave}\n fitView\n fitViewOptions={{ padding: 0.18, duration: 400 }}\n nodesDraggable={false}\n nodesConnectable={false}\n elementsSelectable\n panOnDrag\n zoomOnDoubleClick={false}\n minZoom={0.1}\n maxZoom={2}\n defaultEdgeOptions={{ type: edgeStyle, animated: false }}\n >\n <Background />\n <Controls />\n <MiniMap\n pannable\n zoomable\n nodeColor={minimapNodeColor}\n maskColor=\"rgba(15, 23, 42, 0.7)\"\n style=\"background: #0b1220;\"\n />\n </SvelteFlow>\n </SvelteFlowProvider>\n\n <aside class=\"legend\" aria-label=\"C4 element palette\">\n <span class=\"legend-row\"><span class=\"swatch\" style=\"background: #08427b;\"></span>Person</span>\n <span class=\"legend-row\"><span class=\"swatch\" style=\"background: #1168bd;\"></span>System</span>\n <span class=\"legend-row\"><span class=\"swatch\" style=\"background: #438dd5;\"></span>Container</span>\n <span class=\"legend-row\"><span class=\"swatch\" style=\"background: #85bbf0;\"></span>Component</span>\n <span class=\"legend-row\"><span class=\"swatch\" style=\"background: #475569;\"></span>External</span>\n </aside>\n\n {#if loadError}\n <aside class=\"error-overlay\" role=\"status\" aria-live=\"polite\">\n <span class=\"error-kicker\">Reload failed</span>\n <p>{loadError.message}</p>\n <div class=\"error-meta\">\n {#if loadError.source}<span>{loadError.source}</span>{/if}\n <span>{new Date(loadError.at).toLocaleTimeString()}</span>\n {#if loadError.durationMs > 0}<span>{loadError.durationMs} ms</span>{/if}\n </div>\n </aside>\n {/if}\n </div>\n\n <aside class=\"details\">\n {#if selectedElement}\n <h2>{selectedElement.kind}{selectedElement.external ? \" · external\" : \"\"}</h2>\n <h3 class=\"title\">{selectedElement.label}</h3>\n {#if selectedElement.technology}\n <p class=\"tech\">[{selectedElement.technology}]</p>\n {/if}\n {#if selectedElement.description}\n <p class=\"desc\">{selectedElement.description}</p>\n {/if}\n {#if selectedElement.tags.length}\n <div class=\"field\">\n <span class=\"k\">tags</span>\n <span class=\"v\">\n {#each selectedElement.tags as t (t)}\n <span class=\"tag\">{t}</span>\n {/each}\n </span>\n </div>\n {/if}\n {#if propertyEntries(selectedElement.properties).length}\n <div class=\"field\">\n <span class=\"k\">props</span>\n <span class=\"v props\">\n {#each propertyEntries(selectedElement.properties) as [key, value] (key)}\n <span class=\"prop\"><span class=\"prop-key\">{key}</span>{value}</span>\n {/each}\n </span>\n </div>\n {/if}\n {#if selectedElement.sourceLocation}\n <div class=\"field\">\n <span class=\"k\">source</span>\n <span class=\"v\">\n <a href={sourceUrl(selectedElement.sourceLocation.file, selectedElement.sourceLocation.start.line, selectedElement.sourceLocation.start.col)}>\n {selectedElement.sourceLocation.file.split(\"/\").pop()}:{selectedElement.sourceLocation.start.line}:{selectedElement.sourceLocation.start.col}\n </a>\n </span>\n </div>\n {/if}\n {#if selectedIssues.length}\n <h4>Issues</h4>\n <ul class=\"issues\">\n {#each selectedIssues as issue, i (i)}\n <li>{issueMessage(issue)}</li>\n {/each}\n </ul>\n {/if}\n {#if selectedElement.relations.length}\n <h4>Outgoing relations</h4>\n <ul class=\"relations\">\n {#each selectedElement.relations as rel, i (i)}\n <li>\n <span class=\"arrow\">→</span>\n <span class=\"to\">{rel.to}</span>\n {#if rel.description}<span class=\"rdesc\">{rel.description}</span>{/if}\n {#if rel.technology}<span class=\"rmeta\">[{rel.technology}]</span>{/if}\n </li>\n {/each}\n </ul>\n {/if}\n {#if incomingRelations.length}\n <h4>Incoming relations</h4>\n <ul class=\"relations\">\n {#each incomingRelations as item, i (i)}\n <li>\n <span class=\"arrow\">←</span>\n <span class=\"to\">{item.from}</span>\n {#if item.relation.description}<span class=\"rdesc\">{item.relation.description}</span>{/if}\n {#if item.relation.technology}<span class=\"rmeta\">[{item.relation.technology}]</span>{/if}\n </li>\n {/each}\n </ul>\n {/if}\n {:else if selectedBoundary}\n <h2>{selectedBoundary.kind} boundary</h2>\n <h3 class=\"title\">{selectedBoundary.label}</h3>\n {#if selectedBoundary.description}\n <p class=\"desc\">{selectedBoundary.description}</p>\n {/if}\n <div class=\"field\">\n <span class=\"k\">children</span>\n <span class=\"v\">{selectedBoundary.elementNames.length} elements · {selectedBoundary.boundaryNames.length} boundaries</span>\n </div>\n {#if selectedBoundary.tags.length}\n <div class=\"field\">\n <span class=\"k\">tags</span>\n <span class=\"v\">\n {#each selectedBoundary.tags as t (t)}\n <span class=\"tag\">{t}</span>\n {/each}\n </span>\n </div>\n {/if}\n {#if propertyEntries(selectedBoundary.properties).length}\n <div class=\"field\">\n <span class=\"k\">props</span>\n <span class=\"v props\">\n {#each propertyEntries(selectedBoundary.properties) as [key, value] (key)}\n <span class=\"prop\"><span class=\"prop-key\">{key}</span>{value}</span>\n {/each}\n </span>\n </div>\n {/if}\n {#if selectedBoundary.sourceLocation}\n <div class=\"field\">\n <span class=\"k\">source</span>\n <span class=\"v\">\n <a href={sourceUrl(selectedBoundary.sourceLocation.file, selectedBoundary.sourceLocation.start.line, selectedBoundary.sourceLocation.start.col)}>\n {selectedBoundary.sourceLocation.file.split(\"/\").pop()}:{selectedBoundary.sourceLocation.start.line}:{selectedBoundary.sourceLocation.start.col}\n </a>\n </span>\n </div>\n {/if}\n {#if selectedIssues.length}\n <h4>Issues</h4>\n <ul class=\"issues\">\n {#each selectedIssues as issue, i (i)}\n <li>{issueMessage(issue)}</li>\n {/each}\n </ul>\n {/if}\n <p class=\"hint\">\n {#if mode === \"drill\"}Double-click to enter this boundary.\n {:else if mode === \"expand\"}Double-click to {expanded.has(selectedBoundary.name) ? \"collapse\" : \"expand\"} this boundary.\n {:else}This boundary is part of the full hierarchy.\n {/if}\n </p>\n {:else if envelope?.data.model.workspace}\n <h2>Workspace</h2>\n <h3 class=\"title\">{envelope.data.model.workspace.name ?? \"(unnamed)\"}</h3>\n {#if envelope.data.model.workspace.description}\n <p class=\"desc\">{envelope.data.model.workspace.description}</p>\n {/if}\n {#if summary}\n <div class=\"stats\">\n <div><span class=\"num\">{summary.elements}</span> elements</div>\n <div><span class=\"num\">{summary.boundaries}</span> boundaries</div>\n <div><span class=\"num\">{summary.relations}</span> relations</div>\n {#if summary.issues > 0}\n <div class=\"warn\"><span class=\"num\">{summary.issues}</span> loader issues</div>\n {/if}\n </div>\n {/if}\n {#if envelope.data.issues.length}\n <h4>Loader issues</h4>\n <ul class=\"issues\">\n {#each envelope.data.issues as issue, i (i)}\n <li>{issueMessage(issue)}</li>\n {/each}\n </ul>\n {/if}\n <p class=\"hint\">\n Click a node to inspect. Switch modes in the top bar to\n change how the hierarchy unfolds.\n </p>\n {:else}\n <p class=\"hint\">Loading model…</p>\n {/if}\n </aside>\n </main>\n</div>\n\n<style>\n :global(html, body) {\n margin: 0;\n height: 100%;\n background: #0b1220;\n color: #e2e8f0;\n font-family:\n -apple-system, BlinkMacSystemFont, \"Segoe UI\", Inter, Roboto, sans-serif;\n }\n :global(body) {\n overflow: hidden;\n }\n .app {\n display: grid;\n grid-template-rows: auto 1fr;\n height: 100vh;\n }\n .topbar {\n display: grid;\n grid-template-columns: 1fr auto 1fr;\n align-items: center;\n gap: 16px;\n padding: 10px 18px;\n background: linear-gradient(180deg, #0f172a 0%, #0b1220 100%);\n border-bottom: 1px solid #1e293b;\n }\n .brand {\n display: flex;\n align-items: baseline;\n gap: 8px;\n min-width: 0;\n }\n .logo {\n font-size: 14px;\n font-weight: 800;\n letter-spacing: 0.02em;\n color: #f8fafc;\n }\n .title {\n font-size: 12px;\n color: #94a3b8;\n font-weight: 600;\n }\n .workspace {\n font-size: 13px;\n color: #cbd5e1;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 340px;\n }\n .sep {\n color: #475569;\n font-size: 10px;\n }\n .status {\n font-size: 11px;\n margin-left: 4px;\n color: #94a3b8;\n }\n .status-live {\n color: #34d399;\n }\n .status-lost {\n color: #f87171;\n }\n .status-error {\n color: #fbbf24;\n }\n .topbar-controls {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n }\n .modes {\n display: inline-flex;\n background: #0f172a;\n border: 1px solid #1e293b;\n border-radius: 999px;\n padding: 3px;\n }\n .edge-modes button {\n padding: 5px 10px;\n font-size: 11px;\n }\n .modes button {\n appearance: none;\n border: 0;\n background: transparent;\n color: #94a3b8;\n padding: 5px 14px;\n font-size: 12px;\n font-weight: 600;\n border-radius: 999px;\n cursor: pointer;\n letter-spacing: 0.02em;\n }\n .modes button:hover {\n color: #e2e8f0;\n }\n .modes button.active {\n background: #38bdf8;\n color: #0b1220;\n }\n .context {\n justify-self: end;\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 12px;\n min-width: 0;\n }\n .breadcrumb {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n }\n .bcrumb {\n appearance: none;\n border: 0;\n background: transparent;\n color: #38bdf8;\n cursor: pointer;\n font-size: 12px;\n padding: 2px 4px;\n border-radius: 4px;\n }\n .bcrumb:hover {\n background: rgba(56, 189, 248, 0.1);\n }\n .bsep {\n color: #475569;\n }\n .expand-controls {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .ghost {\n appearance: none;\n border: 1px solid #1e293b;\n background: #0f172a;\n color: #cbd5e1;\n padding: 4px 10px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n }\n .ghost:hover {\n background: #1e293b;\n color: #f8fafc;\n }\n .hint {\n color: #64748b;\n font-size: 11px;\n }\n\n main {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 360px;\n background: #1e293b;\n overflow: hidden;\n }\n .graph,\n .details {\n background: #0b1220;\n overflow: hidden;\n position: relative;\n }\n .graph {\n position: relative;\n }\n\n .legend {\n position: absolute;\n bottom: 14px;\n left: 14px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 10px 12px;\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid #1e293b;\n border-radius: 10px;\n font-size: 11px;\n color: #cbd5e1;\n z-index: 4;\n backdrop-filter: blur(6px);\n }\n .legend-row {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .swatch {\n width: 12px;\n height: 12px;\n border-radius: 3px;\n }\n .error-overlay {\n position: absolute;\n top: 18px;\n left: 18px;\n z-index: 5;\n max-width: min(520px, calc(100% - 36px));\n padding: 14px 16px;\n border-radius: 8px;\n border: 1px solid #b45309;\n background: rgba(69, 26, 3, 0.92);\n box-shadow: 0 18px 50px -28px rgba(0, 0, 0, 0.8);\n backdrop-filter: blur(6px);\n }\n .error-kicker {\n display: block;\n margin-bottom: 6px;\n font-size: 10px;\n font-weight: 800;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: #fbbf24;\n }\n .error-overlay p {\n margin: 0;\n color: #fff7ed;\n font-size: 13px;\n line-height: 1.4;\n overflow-wrap: anywhere;\n }\n .error-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n margin-top: 8px;\n font-size: 10px;\n color: #fed7aa;\n }\n\n .details {\n padding: 20px;\n overflow: auto;\n border-left: 1px solid #1e293b;\n }\n .details h2 {\n margin: 0;\n font-size: 11px;\n font-weight: 800;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: #94a3b8;\n }\n .details h3 {\n margin: 6px 0 10px;\n font-size: 18px;\n font-weight: 800;\n line-height: 1.2;\n color: #f8fafc;\n }\n .details h4 {\n margin: 18px 0 8px;\n font-size: 11px;\n font-weight: 800;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: #94a3b8;\n }\n .tech {\n margin: 0 0 10px;\n font-size: 12px;\n font-style: italic;\n color: #94a3b8;\n }\n .desc {\n margin: 0 0 14px;\n font-size: 13px;\n line-height: 1.45;\n color: #cbd5e1;\n }\n .field {\n display: flex;\n gap: 8px;\n margin-bottom: 6px;\n font-size: 12px;\n color: #cbd5e1;\n }\n .field .k {\n color: #64748b;\n min-width: 70px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n font-size: 10px;\n padding-top: 2px;\n }\n .field a {\n color: #38bdf8;\n text-decoration: none;\n }\n .field a:hover {\n text-decoration: underline;\n }\n .tag {\n display: inline-block;\n font-size: 10px;\n padding: 1px 7px;\n border-radius: 999px;\n background: #1e293b;\n color: #cbd5e1;\n margin-right: 4px;\n }\n .props {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n .prop {\n display: inline-flex;\n gap: 5px;\n max-width: 100%;\n padding: 2px 7px;\n border-radius: 6px;\n background: #0f172a;\n color: #cbd5e1;\n border: 1px solid #1e293b;\n font-size: 10px;\n overflow-wrap: anywhere;\n }\n .prop-key {\n color: #38bdf8;\n font-weight: 700;\n }\n .relations {\n list-style: none;\n padding: 0;\n margin: 0;\n font-size: 12px;\n }\n .relations li {\n display: flex;\n gap: 6px;\n align-items: baseline;\n padding: 4px 0;\n color: #cbd5e1;\n }\n .arrow {\n color: #38bdf8;\n }\n .to {\n font-weight: 700;\n color: #e2e8f0;\n }\n .rdesc {\n color: #94a3b8;\n }\n .rmeta {\n font-size: 10px;\n color: #64748b;\n font-style: italic;\n }\n .issues {\n list-style: none;\n padding: 0;\n margin: 0;\n font-size: 12px;\n }\n .issues li {\n margin: 6px 0;\n padding: 8px 10px;\n border-radius: 8px;\n border: 1px solid #92400e;\n background: rgba(69, 26, 3, 0.45);\n color: #fed7aa;\n line-height: 1.35;\n overflow-wrap: anywhere;\n }\n .stats {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 8px;\n margin: 14px 0;\n }\n .stats > div {\n background: #0f172a;\n border: 1px solid #1e293b;\n border-radius: 8px;\n padding: 8px 12px;\n font-size: 11px;\n color: #94a3b8;\n }\n .stats .num {\n font-size: 18px;\n font-weight: 800;\n color: #f8fafc;\n display: block;\n line-height: 1.1;\n }\n .stats .warn {\n border-color: #b45309;\n color: #fbbf24;\n }\n :global(.svelte-flow) {\n background: #0b1220;\n /* xyflow exposes edge styling via CSS variables. Setting them\n here overrides the defaults baked into\n @xyflow/svelte/dist/style.css regardless of which template\n (default / smoothstep / straight) renders the edge.\n Edge labels are HTML <div>s, not SVG <text>, so they need\n HTML CSS background / color — labelBgStyle prop is ignored\n in @xyflow/svelte 1.x. */\n --xy-edge-stroke-default: #94a3b8;\n --xy-edge-stroke-selected-default: #38bdf8;\n --xy-edge-stroke-width-default: 1.8;\n --xy-connectionline-stroke-default: #38bdf8;\n --xy-edge-label-color-default: #f8fafc;\n --xy-edge-label-background-color-default: #1e293b;\n }\n :global(.svelte-flow__edge-label) {\n background: #1e293b;\n color: #f8fafc;\n padding: 3px 8px;\n border-radius: 6px;\n border: 1px solid #475569;\n font-size: 11px;\n font-weight: 700;\n box-shadow: 0 4px 12px -8px rgba(0, 0, 0, 0.6);\n white-space: nowrap;\n max-width: 240px;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n :global(.svelte-flow__background) {\n background-color: #0b1220;\n }\n :global(.svelte-flow__edge-path) {\n stroke: #94a3b8;\n stroke-width: 1.8;\n }\n :global(.svelte-flow__edge.selected .svelte-flow__edge-path) {\n stroke: #38bdf8;\n stroke-width: 2.4;\n }\n :global(.svelte-flow__edge-text) {\n fill: #f8fafc;\n font-size: 11px;\n font-weight: 700;\n }\n :global(.svelte-flow__edge-textbg) {\n fill: #1e293b;\n stroke: #475569;\n stroke-width: 1;\n }\n :global(.svelte-flow__arrowhead polyline),\n :global(.svelte-flow__arrowhead path) {\n fill: #cbd5e1;\n stroke: #cbd5e1;\n }\n /* Hide connection handles. xyflow still needs the <Handle>\n components to compute edge endpoints, but the default `o` dot\n visually competes with the arrowhead at the node border. We\n keep size > 0 so the layout math is intact, just invisible. */\n :global(.svelte-flow__handle) {\n width: 6px;\n height: 6px;\n background: transparent;\n border: 0;\n min-width: 0;\n min-height: 0;\n opacity: 0;\n pointer-events: none;\n }\n :global(.svelte-flow__controls) {\n background: #0f172a;\n border: 1px solid #1e293b;\n border-radius: 8px;\n overflow: hidden;\n }\n :global(.svelte-flow__controls-button) {\n background: #0f172a;\n border-bottom: 1px solid #1e293b;\n color: #cbd5e1;\n }\n :global(.svelte-flow__controls-button:hover) {\n background: #1e293b;\n }\n :global(.svelte-flow__minimap) {\n border: 1px solid #1e293b;\n border-radius: 8px;\n overflow: hidden;\n }\n</style>\n","import { mount } from \"svelte\";\n\nimport App from \"./App.svelte\";\n\nconst target = document.querySelector(\"#app\");\nif (!target) {\n throw new Error(\"aact view: #app mount point missing in index.html\");\n}\nmount(App, { target });\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.boundary.svelte-11zjl56{border:2px dashed var(--accent,#94a3b8);background:color-mix(in srgb, var(--accent,#94a3b8) 8%, transparent);color:#e2e8f0;box-sizing:border-box;cursor:pointer;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);border-radius:16px;flex-direction:column;width:100%;height:100%;transition:background .12s,box-shadow .12s;display:flex}.boundary.svelte-11zjl56:hover{background:color-mix(in srgb, var(--accent,#94a3b8) 14%, transparent)}.boundary.expanded.svelte-11zjl56{cursor:default}.boundary.is-selected.svelte-11zjl56{box-shadow:0 0 0 1px var(--accent), 0 0 0 4px color-mix(in srgb, var(--accent) 30%, transparent)}.header.svelte-11zjl56{border-bottom:1px dashed color-mix(in srgb, var(--accent) 60%, transparent);background:color-mix(in srgb, var(--accent) 18%, #0f172a);border-radius:14px 14px 0 0;flex-direction:column;gap:4px;padding:10px 14px;display:flex}.chip.svelte-11zjl56{letter-spacing:.14em;text-transform:uppercase;background:var(--accent);color:#fff;border-radius:999px;align-self:flex-start;padding:2px 8px;font-size:9px;font-weight:700}.label.svelte-11zjl56{color:#f8fafc;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:700;line-height:1.15;overflow:hidden}.meta.svelte-11zjl56{color:#e2e8f099;font-size:10px}.db.svelte-1okyz27{background:linear-gradient(180deg, var(--fill) 0%, color-mix(in srgb, var(--fill) 80%, black) 100%);color:#f8fafc;box-sizing:border-box;cursor:pointer;width:100%;height:100%;box-shadow:0 10px 28px -18px color-mix(in srgb, var(--fill) 70%, transparent), inset 0 1px 0 #ffffff1a;border-radius:14px 14px 22px 22px/14px 14px 30px 30px;grid-template-rows:14px 1fr;padding:0;transition:transform .12s,box-shadow .12s;display:grid;position:relative}.db.svelte-1okyz27:hover{transform:translateY(-1px)}.db.is-selected.svelte-1okyz27{outline-offset:2px;outline:2px solid #38bdf8}.cyl-top.svelte-1okyz27{background:#0000002e;border-bottom:1px solid #ffffff26;border-radius:14px 14px 50% 50%/14px 14px 100% 100%;height:14px}.body.svelte-1okyz27{flex-direction:column;gap:2px;padding:10px 14px 14px;display:flex;overflow:hidden}.kind.svelte-1okyz27{letter-spacing:.14em;text-transform:uppercase;color:#f8fafcc7;font-size:9px;font-weight:700}.label.svelte-1okyz27{text-overflow:ellipsis;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:13px;font-weight:700;line-height:1.15;display:-webkit-box;overflow:hidden}.tech.svelte-1okyz27{color:#f8fafcd9;font-size:10px;font-style:italic}.desc.svelte-1okyz27{color:#f8fafcbf;text-overflow:ellipsis;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:11px;line-height:1.3;display:-webkit-box;overflow:hidden}.el.svelte-698jog{background:linear-gradient(180deg, var(--fill) 0%, color-mix(in srgb, var(--fill) 82%, black) 100%);color:var(--text,#f8fafc);box-shadow:0 10px 28px -18px color-mix(in srgb, var(--fill) 70%, transparent), inset 0 1px 0 #ffffff14;box-sizing:border-box;cursor:pointer;border-radius:12px;flex-direction:column;gap:4px;width:100%;height:100%;padding:12px 14px 14px;transition:transform .12s,box-shadow .12s;display:flex}.el.svelte-698jog:hover{box-shadow:0 14px 36px -16px color-mix(in srgb, var(--fill) 80%, transparent), inset 0 1px 0 #ffffff1f;transform:translateY(-1px)}.el.is-selected.svelte-698jog{outline-offset:2px;outline:2px solid #38bdf8}.head.svelte-698jog{justify-content:space-between;align-items:center;display:flex}.kind.svelte-698jog{letter-spacing:.14em;text-transform:uppercase;color:color-mix(in srgb, var(--text) 70%, transparent);font-size:9px;font-weight:700}.label.svelte-698jog{text-overflow:ellipsis;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:14px;font-weight:700;line-height:1.15;display:-webkit-box;overflow:hidden}.tech.svelte-698jog{color:color-mix(in srgb, var(--text) 85%, transparent);font-size:10px;font-style:italic}.desc.svelte-698jog{color:color-mix(in srgb, var(--text) 78%, transparent);text-overflow:ellipsis;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:11px;line-height:1.3;display:-webkit-box;overflow:hidden}.person.svelte-64vle7{color:#f8fafc;box-sizing:border-box;cursor:pointer;background:linear-gradient(#08427b 0%,#073768 100%);border-radius:14px;grid-template-rows:36px 1fr;gap:6px;width:100%;height:100%;padding:12px 14px 14px;transition:transform .12s,box-shadow .12s;display:grid;box-shadow:0 10px 30px -18px #08427bd9,inset 0 1px #ffffff14}.person.svelte-64vle7:hover{transform:translateY(-1px);box-shadow:0 14px 40px -16px #08427bf2,inset 0 1px #ffffff1f}.person.is-selected.svelte-64vle7{outline-offset:2px;outline:2px solid #38bdf8}.person.external.svelte-64vle7{background:linear-gradient(#475569 0%,#334155 100%)}.head.svelte-64vle7{justify-content:center;align-items:center;display:flex}.silhouette.svelte-64vle7{color:#f8fafc;opacity:.92;width:28px;height:28px}.silhouette.svelte-64vle7 circle:where(.svelte-64vle7){fill:currentColor}.silhouette.svelte-64vle7 path:where(.svelte-64vle7){fill:none;stroke:currentColor;stroke-width:2px;stroke-linecap:round}.body.svelte-64vle7{text-align:center;flex-direction:column;align-items:center;gap:2px;display:flex}.kind.svelte-64vle7{letter-spacing:.14em;text-transform:uppercase;color:#f8fafcbf;font-size:9px;font-weight:700}.label.svelte-64vle7{text-overflow:ellipsis;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:14px;font-weight:700;line-height:1.15;display:-webkit-box;overflow:hidden}.desc.svelte-64vle7{color:#f8fafcb3;text-overflow:ellipsis;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:11px;line-height:1.25;display:-webkit-box;overflow:hidden}.q.svelte-1s4sqjz{background:linear-gradient(180deg, var(--fill) 0%, color-mix(in srgb, var(--fill) 80%, black) 100%);color:#f8fafc;box-sizing:border-box;cursor:pointer;width:100%;height:100%;box-shadow:0 10px 28px -18px color-mix(in srgb, var(--fill) 70%, transparent), inset 0 1px 0 #ffffff1a;border-radius:999px;flex-direction:column;gap:0;padding:0;transition:transform .12s;display:flex}.q.svelte-1s4sqjz:hover{transform:translateY(-1px)}.q.is-selected.svelte-1s4sqjz{outline-offset:2px;outline:2px solid #38bdf8}.body.svelte-1s4sqjz{flex-direction:column;justify-content:center;gap:2px;height:100%;padding:14px 22px;display:flex;overflow:hidden}.kind.svelte-1s4sqjz{letter-spacing:.14em;text-transform:uppercase;color:#f8fafcc7;font-size:9px;font-weight:700}.label.svelte-1s4sqjz{text-overflow:ellipsis;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:13px;font-weight:700;line-height:1.15;display:-webkit-box;overflow:hidden}.tech.svelte-1s4sqjz{color:#f8fafcd9;font-size:10px;font-style:italic}.desc.svelte-1s4sqjz{color:#f8fafcbf;text-overflow:ellipsis;-webkit-line-clamp:1;-webkit-box-orient:vertical;font-size:11px;line-height:1.3;display:-webkit-box;overflow:hidden}html,body{color:#e2e8f0;background:#0b1220;height:100%;margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Inter,Roboto,sans-serif}body{overflow:hidden}.app.svelte-1r8vfx3{grid-template-rows:auto 1fr;height:100vh;display:grid}.topbar.svelte-1r8vfx3{background:linear-gradient(#0f172a 0%,#0b1220 100%);border-bottom:1px solid #1e293b;grid-template-columns:1fr auto 1fr;align-items:center;gap:16px;padding:10px 18px;display:grid}.brand.svelte-1r8vfx3{align-items:baseline;gap:8px;min-width:0;display:flex}.logo.svelte-1r8vfx3{letter-spacing:.02em;color:#f8fafc;font-size:14px;font-weight:800}.title.svelte-1r8vfx3{color:#94a3b8;font-size:12px;font-weight:600}.workspace.svelte-1r8vfx3{color:#cbd5e1;text-overflow:ellipsis;white-space:nowrap;max-width:340px;font-size:13px;font-weight:600;overflow:hidden}.sep.svelte-1r8vfx3{color:#475569;font-size:10px}.status.svelte-1r8vfx3{color:#94a3b8;margin-left:4px;font-size:11px}.status-live.svelte-1r8vfx3{color:#34d399}.status-lost.svelte-1r8vfx3{color:#f87171}.status-error.svelte-1r8vfx3{color:#fbbf24}.topbar-controls.svelte-1r8vfx3{align-items:center;gap:8px;display:inline-flex}.modes.svelte-1r8vfx3{background:#0f172a;border:1px solid #1e293b;border-radius:999px;padding:3px;display:inline-flex}.edge-modes.svelte-1r8vfx3 button:where(.svelte-1r8vfx3){padding:5px 10px;font-size:11px}.modes.svelte-1r8vfx3 button:where(.svelte-1r8vfx3){appearance:none;color:#94a3b8;cursor:pointer;letter-spacing:.02em;background:0 0;border:0;border-radius:999px;padding:5px 14px;font-size:12px;font-weight:600}.modes.svelte-1r8vfx3 button:where(.svelte-1r8vfx3):hover{color:#e2e8f0}.modes.svelte-1r8vfx3 button.active:where(.svelte-1r8vfx3){color:#0b1220;background:#38bdf8}.context.svelte-1r8vfx3{justify-self:end;align-items:center;gap:10px;min-width:0;font-size:12px;display:flex}.breadcrumb.svelte-1r8vfx3{flex-wrap:wrap;align-items:center;gap:4px;display:flex}.bcrumb.svelte-1r8vfx3{appearance:none;color:#38bdf8;cursor:pointer;background:0 0;border:0;border-radius:4px;padding:2px 4px;font-size:12px}.bcrumb.svelte-1r8vfx3:hover{background:#38bdf81a}.bsep.svelte-1r8vfx3{color:#475569}.expand-controls.svelte-1r8vfx3{align-items:center;gap:8px;display:flex}.ghost.svelte-1r8vfx3{appearance:none;color:#cbd5e1;cursor:pointer;background:#0f172a;border:1px solid #1e293b;border-radius:999px;padding:4px 10px;font-size:11px;font-weight:600}.ghost.svelte-1r8vfx3:hover{color:#f8fafc;background:#1e293b}.hint.svelte-1r8vfx3{color:#64748b;font-size:11px}main.svelte-1r8vfx3{background:#1e293b;grid-template-columns:minmax(0,1fr) 360px;display:grid;overflow:hidden}.graph.svelte-1r8vfx3,.details.svelte-1r8vfx3{background:#0b1220;position:relative;overflow:hidden}.graph.svelte-1r8vfx3{position:relative}.legend.svelte-1r8vfx3{color:#cbd5e1;z-index:4;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#0f172ad9;border:1px solid #1e293b;border-radius:10px;flex-direction:column;gap:4px;padding:10px 12px;font-size:11px;display:flex;position:absolute;bottom:14px;left:14px}.legend-row.svelte-1r8vfx3{align-items:center;gap:8px;display:flex}.swatch.svelte-1r8vfx3{border-radius:3px;width:12px;height:12px}.error-overlay.svelte-1r8vfx3{z-index:5;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#451a03eb;border:1px solid #b45309;border-radius:8px;max-width:min(520px,100% - 36px);padding:14px 16px;position:absolute;top:18px;left:18px;box-shadow:0 18px 50px -28px #000c}.error-kicker.svelte-1r8vfx3{letter-spacing:.14em;text-transform:uppercase;color:#fbbf24;margin-bottom:6px;font-size:10px;font-weight:800;display:block}.error-overlay.svelte-1r8vfx3 p:where(.svelte-1r8vfx3){color:#fff7ed;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.4}.error-meta.svelte-1r8vfx3{color:#fed7aa;flex-wrap:wrap;gap:8px;margin-top:8px;font-size:10px;display:flex}.details.svelte-1r8vfx3{border-left:1px solid #1e293b;padding:20px;overflow:auto}.details.svelte-1r8vfx3 h2:where(.svelte-1r8vfx3){letter-spacing:.14em;text-transform:uppercase;color:#94a3b8;margin:0;font-size:11px;font-weight:800}.details.svelte-1r8vfx3 h3:where(.svelte-1r8vfx3){color:#f8fafc;margin:6px 0 10px;font-size:18px;font-weight:800;line-height:1.2}.details.svelte-1r8vfx3 h4:where(.svelte-1r8vfx3){letter-spacing:.14em;text-transform:uppercase;color:#94a3b8;margin:18px 0 8px;font-size:11px;font-weight:800}.tech.svelte-1r8vfx3{color:#94a3b8;margin:0 0 10px;font-size:12px;font-style:italic}.desc.svelte-1r8vfx3{color:#cbd5e1;margin:0 0 14px;font-size:13px;line-height:1.45}.field.svelte-1r8vfx3{color:#cbd5e1;gap:8px;margin-bottom:6px;font-size:12px;display:flex}.field.svelte-1r8vfx3 .k:where(.svelte-1r8vfx3){color:#64748b;letter-spacing:.08em;text-transform:uppercase;min-width:70px;padding-top:2px;font-size:10px}.field.svelte-1r8vfx3 a:where(.svelte-1r8vfx3){color:#38bdf8;text-decoration:none}.field.svelte-1r8vfx3 a:where(.svelte-1r8vfx3):hover{text-decoration:underline}.tag.svelte-1r8vfx3{color:#cbd5e1;background:#1e293b;border-radius:999px;margin-right:4px;padding:1px 7px;font-size:10px;display:inline-block}.props.svelte-1r8vfx3{flex-wrap:wrap;gap:4px;display:flex}.prop.svelte-1r8vfx3{color:#cbd5e1;overflow-wrap:anywhere;background:#0f172a;border:1px solid #1e293b;border-radius:6px;gap:5px;max-width:100%;padding:2px 7px;font-size:10px;display:inline-flex}.prop-key.svelte-1r8vfx3{color:#38bdf8;font-weight:700}.relations.svelte-1r8vfx3{margin:0;padding:0;font-size:12px;list-style:none}.relations.svelte-1r8vfx3 li:where(.svelte-1r8vfx3){color:#cbd5e1;align-items:baseline;gap:6px;padding:4px 0;display:flex}.arrow.svelte-1r8vfx3{color:#38bdf8}.to.svelte-1r8vfx3{color:#e2e8f0;font-weight:700}.rdesc.svelte-1r8vfx3{color:#94a3b8}.rmeta.svelte-1r8vfx3{color:#64748b;font-size:10px;font-style:italic}.issues.svelte-1r8vfx3{margin:0;padding:0;font-size:12px;list-style:none}.issues.svelte-1r8vfx3 li:where(.svelte-1r8vfx3){color:#fed7aa;overflow-wrap:anywhere;background:#451a0373;border:1px solid #92400e;border-radius:8px;margin:6px 0;padding:8px 10px;line-height:1.35}.stats.svelte-1r8vfx3{grid-template-columns:repeat(2,1fr);gap:8px;margin:14px 0;display:grid}.stats.svelte-1r8vfx3>div:where(.svelte-1r8vfx3){color:#94a3b8;background:#0f172a;border:1px solid #1e293b;border-radius:8px;padding:8px 12px;font-size:11px}.stats.svelte-1r8vfx3 .num:where(.svelte-1r8vfx3){color:#f8fafc;font-size:18px;font-weight:800;line-height:1.1;display:block}.stats.svelte-1r8vfx3 .warn:where(.svelte-1r8vfx3){color:#fbbf24;border-color:#b45309}.svelte-flow{--xy-edge-stroke-default:#94a3b8;--xy-edge-stroke-selected-default:#38bdf8;--xy-edge-stroke-width-default:1.8;--xy-connectionline-stroke-default:#38bdf8;--xy-edge-label-color-default:#f8fafc;--xy-edge-label-background-color-default:#1e293b;background:#0b1220}.svelte-flow__edge-label{color:#f8fafc;white-space:nowrap;text-overflow:ellipsis;background:#1e293b;border:1px solid #475569;border-radius:6px;max-width:240px;padding:3px 8px;font-size:11px;font-weight:700;overflow:hidden;box-shadow:0 4px 12px -8px #0009}.svelte-flow__background{background-color:#0b1220}.svelte-flow__edge-path{stroke:#94a3b8;stroke-width:1.8px}.svelte-flow__edge.selected .svelte-flow__edge-path{stroke:#38bdf8;stroke-width:2.4px}.svelte-flow__edge-text{fill:#f8fafc;font-size:11px;font-weight:700}.svelte-flow__edge-textbg{fill:#1e293b;stroke:#475569;stroke-width:1px}.svelte-flow__arrowhead polyline,.svelte-flow__arrowhead path{fill:#cbd5e1;stroke:#cbd5e1}.svelte-flow__handle{opacity:0;pointer-events:none;background:0 0;border:0;width:6px;min-width:0;height:6px;min-height:0}.svelte-flow__controls{background:#0f172a;border:1px solid #1e293b;border-radius:8px;overflow:hidden}.svelte-flow__controls-button{color:#cbd5e1;background:#0f172a;border-bottom:1px solid #1e293b}.svelte-flow__controls-button:hover{background:#1e293b}.svelte-flow__minimap{border:1px solid #1e293b;border-radius:8px;overflow:hidden}
|