pmx-canvas 0.7.3 → 0.8.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.
Files changed (235) hide show
  1. package/.github/extensions/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
  2. package/.github/extensions/pmx-canvas/extension.mjs +25 -172
  3. package/.github/extensions/pmx-canvas/mcp-bootstrap.ts +198 -0
  4. package/.github/extensions/pmx-canvas/runtime.d.mts +41 -0
  5. package/.github/extensions/pmx-canvas/runtime.json +3 -0
  6. package/.github/extensions/pmx-canvas/runtime.mjs +194 -0
  7. package/.github/extensions/pmx-canvas/start-mcp.mjs +51 -0
  8. package/.github/extensions/pmx-canvas/tools.json +2560 -0
  9. package/CHANGELOG.md +47 -0
  10. package/Readme.md +21 -7
  11. package/dist/canvas/fonts/OFL.txt +93 -0
  12. package/dist/canvas/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  13. package/dist/canvas/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  14. package/dist/canvas/fonts/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
  15. package/dist/canvas/fonts/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
  16. package/dist/canvas/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
  17. package/dist/canvas/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
  18. package/dist/canvas/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
  19. package/dist/canvas/fonts/ibm-plex-sans-latin-ext-400-normal.woff2 +0 -0
  20. package/dist/canvas/fonts/ibm-plex-sans-latin-ext-500-normal.woff2 +0 -0
  21. package/dist/canvas/fonts/ibm-plex-sans-latin-ext-600-normal.woff2 +0 -0
  22. package/dist/canvas/global.css +723 -672
  23. package/dist/canvas/index.js +90 -88
  24. package/dist/canvas/mcp-app.html +7878 -0
  25. package/dist/canvas/mermaid-entry.js +1 -1
  26. package/dist/canvas/surface-theme.css +151 -46
  27. package/dist/json-render/index.css +1 -1
  28. package/dist/types/cli/commands/record.d.ts +1 -1
  29. package/dist/types/client/canvas/NodeContextMark.d.ts +24 -0
  30. package/dist/types/client/canvas/SessionReceipt.d.ts +3 -1
  31. package/dist/types/client/icons.d.ts +1 -2
  32. package/dist/types/client/mcp-app/index.d.ts +1 -0
  33. package/dist/types/client/nodes/ax-node-actions.d.ts +2 -2
  34. package/dist/types/client/nodes/markdown-sanitize.d.ts +2 -0
  35. package/dist/types/client/nodes/use-workbench-asset.d.ts +2 -0
  36. package/dist/types/client/state/attention-store.d.ts +0 -5
  37. package/dist/types/client/state/context-status-store.d.ts +53 -0
  38. package/dist/types/client/state/intent-bridge.d.ts +3 -0
  39. package/dist/types/client/state/near-pin-store.d.ts +16 -0
  40. package/dist/types/client/state/presence-store.d.ts +5 -0
  41. package/dist/types/client/state/session-store.d.ts +33 -3
  42. package/dist/types/client/state/workbench-transport.d.ts +16 -0
  43. package/dist/types/client/theme/tokens.d.ts +1 -3
  44. package/dist/types/client/types.d.ts +9 -0
  45. package/dist/types/json-render/server.d.ts +1 -1
  46. package/dist/types/mcp/app-server.d.ts +3 -0
  47. package/dist/types/mcp/canvas-access.d.ts +1 -1
  48. package/dist/types/mcp/canvas-app.d.ts +4 -0
  49. package/dist/types/mcp/workbench-app.d.ts +4 -0
  50. package/dist/types/server/agent-presence.d.ts +1 -1
  51. package/dist/types/server/ax-state.d.ts +1 -1
  52. package/dist/types/server/canvas-db.d.ts +8 -0
  53. package/dist/types/server/canvas-geometry.d.ts +25 -0
  54. package/dist/types/server/canvas-operations.d.ts +1 -11
  55. package/dist/types/server/canvas-state.d.ts +25 -3
  56. package/dist/types/server/context-brief.d.ts +8 -1
  57. package/dist/types/server/context-reads.d.ts +30 -7
  58. package/dist/types/server/index.d.ts +6 -1
  59. package/dist/types/server/mcp-app-runtime.d.ts +1 -0
  60. package/dist/types/server/operations/http.d.ts +2 -0
  61. package/dist/types/server/operations/invoker.d.ts +4 -2
  62. package/dist/types/server/operations/ops/nodes.d.ts +0 -6
  63. package/dist/types/server/server.d.ts +1 -0
  64. package/dist/types/server/spatial-analysis.d.ts +2 -0
  65. package/dist/types/shared/agent-context.d.ts +22 -0
  66. package/dist/types/shared/agent-presence.d.ts +3 -10
  67. package/dist/types/shared/canvas-app.d.ts +54 -0
  68. package/dist/types/shared/themes.d.ts +1 -1
  69. package/docs/RELEASE.md +7 -3
  70. package/docs/agent-plugin.md +123 -0
  71. package/docs/ax-state-contract.md +40 -0
  72. package/docs/cli.md +7 -2
  73. package/docs/design/AgentContext.dc.html +186 -0
  74. package/docs/design/Before.dc.html +208 -0
  75. package/docs/design/BoardPins.dc.html +151 -0
  76. package/docs/design/Chrome.dc.html +208 -0
  77. package/docs/design/Context.dc.html +239 -0
  78. package/docs/design/Flows.dc.html +181 -0
  79. package/docs/design/Home.dc.html +209 -0
  80. package/docs/design/HomeGraph.dc.html +211 -0
  81. package/docs/design/HomeMap.dc.html +117 -0
  82. package/docs/design/HomeTeam.dc.html +176 -0
  83. package/docs/design/Light.dc.html +28 -0
  84. package/docs/design/Main.dc.html +280 -0
  85. package/docs/design/NearPin.dc.html +260 -0
  86. package/docs/design/Pane600.dc.html +120 -0
  87. package/docs/design/Relations.dc.html +297 -0
  88. package/docs/design/Themes.dc.html +121 -0
  89. package/docs/design/TokenSystem.dc.html +136 -0
  90. package/docs/design/Tokens.dc.html +163 -0
  91. package/docs/design/Types1.dc.html +177 -0
  92. package/docs/design/Types2.dc.html +226 -0
  93. package/docs/design/Types3.dc.html +195 -0
  94. package/docs/design/Uses.dc.html +152 -0
  95. package/docs/design/Vision.dc.html +116 -0
  96. package/docs/design/Zoom.dc.html +82 -0
  97. package/docs/design/canvas.json +274 -0
  98. package/docs/design.md +214 -0
  99. package/docs/environment.md +1 -1
  100. package/docs/http-api.md +80 -15
  101. package/docs/mcp.md +198 -3
  102. package/docs/node-types.md +34 -10
  103. package/docs/plans/plan-009-tech-debt-backlog.md +1 -1
  104. package/docs/plans/plan-015-design-foundation-wave-0.md +177 -0
  105. package/docs/plans/plan-016-context-made-visible-wave-1.md +148 -0
  106. package/docs/product-vision-2026-09.md +47 -7
  107. package/docs/screenshot.png +0 -0
  108. package/docs/sdk.md +1 -0
  109. package/package.json +10 -4
  110. package/plugins/pmx-canvas/LICENSE +21 -0
  111. package/plugins/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
  112. package/plugins/pmx-canvas/assets/preview.png +0 -0
  113. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/extension.mjs +930 -0
  114. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +3 -0
  115. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.mjs +194 -0
  116. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/steering-delivery.mjs +79 -0
  117. package/plugins/pmx-canvas/mcp.json +12 -0
  118. package/plugins/pmx-canvas/plugin.json +24 -0
  119. package/plugins/pmx-canvas/runtime.json +3 -0
  120. package/plugins/pmx-canvas/runtime.mjs +194 -0
  121. package/plugins/pmx-canvas/start-mcp.mjs +51 -0
  122. package/plugins/pmx-canvas/tools.json +2560 -0
  123. package/skills/pmx-canvas/SKILL.md +10 -7
  124. package/skills/pmx-canvas/references/full-reference.md +11 -7
  125. package/skills/pmx-canvas/references/github-copilot-app-adapter.md +20 -8
  126. package/skills/pmx-canvas/references/installing-pmx-canvas.md +6 -6
  127. package/skills/pmx-canvas-testing/SKILL.md +5 -4
  128. package/src/cli/commands/copilot.ts +5 -0
  129. package/src/cli/commands/view.ts +1 -1
  130. package/src/cli/index.ts +8 -3
  131. package/src/client/App.tsx +6 -1
  132. package/src/client/canvas/AgentPresenceLayer.tsx +3 -3
  133. package/src/client/canvas/AnnotationLayer.tsx +1 -1
  134. package/src/client/canvas/CanvasNode.tsx +32 -49
  135. package/src/client/canvas/CanvasViewport.tsx +0 -2
  136. package/src/client/canvas/CommandPalette.tsx +3 -2
  137. package/src/client/canvas/ContextMenu.tsx +11 -0
  138. package/src/client/canvas/EdgeLayer.tsx +1 -1
  139. package/src/client/canvas/ExportDialog.tsx +33 -6
  140. package/src/client/canvas/IntentLayer.tsx +2 -2
  141. package/src/client/canvas/Minimap.tsx +12 -7
  142. package/src/client/canvas/NodeContextMark.tsx +156 -0
  143. package/src/client/canvas/SessionPanel.tsx +4 -7
  144. package/src/client/canvas/SessionReceipt.tsx +114 -17
  145. package/src/client/canvas/ShortcutOverlay.tsx +6 -1
  146. package/src/client/canvas/SnapshotPanel.tsx +11 -2
  147. package/src/client/canvas/ToolRail.tsx +12 -9
  148. package/src/client/canvas/TopBar.tsx +16 -11
  149. package/src/client/icons.tsx +2 -12
  150. package/src/client/mcp-app/index.tsx +137 -0
  151. package/src/client/mcp-app/style.css +10 -0
  152. package/src/client/nodes/AttachmentNode.tsx +8 -1
  153. package/src/client/nodes/AxStepControls.tsx +1 -1
  154. package/src/client/nodes/ContextNode.tsx +9 -9
  155. package/src/client/nodes/ExtAppFrame.tsx +13 -8
  156. package/src/client/nodes/FileNode.tsx +8 -5
  157. package/src/client/nodes/ImageNode.tsx +4 -2
  158. package/src/client/nodes/InlineMarkdownEditor.tsx +2 -1
  159. package/src/client/nodes/LedgerNode.tsx +2 -2
  160. package/src/client/nodes/MarkdownNode.tsx +44 -9
  161. package/src/client/nodes/McpAppNode.tsx +6 -4
  162. package/src/client/nodes/PromptNode.tsx +5 -17
  163. package/src/client/nodes/ResponseNode.tsx +3 -15
  164. package/src/client/nodes/StatusNode.tsx +2 -2
  165. package/src/client/nodes/StatusSummary.tsx +3 -1
  166. package/src/client/nodes/TraceNode.tsx +6 -4
  167. package/src/client/nodes/WebpageNode.tsx +1 -1
  168. package/src/client/nodes/ax-node-actions.ts +2 -2
  169. package/src/client/nodes/iframe-document-url.ts +3 -2
  170. package/src/client/nodes/markdown-sanitize.ts +10 -0
  171. package/src/client/nodes/surface-url.ts +10 -0
  172. package/src/client/nodes/use-surface-frame.ts +3 -1
  173. package/src/client/nodes/use-workbench-asset.ts +26 -0
  174. package/src/client/state/attention-bridge.ts +0 -8
  175. package/src/client/state/attention-store.ts +0 -17
  176. package/src/client/state/canvas-store.ts +4 -2
  177. package/src/client/state/context-status-store.ts +66 -0
  178. package/src/client/state/human-store.ts +2 -0
  179. package/src/client/state/iframe-mode.ts +5 -0
  180. package/src/client/state/intent-bridge.ts +10 -4
  181. package/src/client/state/near-pin-store.ts +53 -0
  182. package/src/client/state/presence-store.ts +5 -10
  183. package/src/client/state/session-store.ts +106 -9
  184. package/src/client/state/sse-bridge.ts +26 -7
  185. package/src/client/state/theme-override.ts +1 -1
  186. package/src/client/state/workbench-transport.ts +36 -0
  187. package/src/client/theme/global.css +723 -672
  188. package/src/client/theme/surface-theme.css +151 -46
  189. package/src/client/theme/tokens.ts +7 -11
  190. package/src/client/types.ts +10 -0
  191. package/src/json-render/server.ts +71 -14
  192. package/src/mcp/app-server.ts +64 -0
  193. package/src/mcp/canvas-access.ts +14 -11
  194. package/src/mcp/canvas-app.ts +318 -0
  195. package/src/mcp/server.ts +1 -1
  196. package/src/mcp/workbench-app.ts +211 -0
  197. package/src/server/agent-presence.ts +45 -6
  198. package/src/server/ax-context.ts +1 -1
  199. package/src/server/ax-state.ts +1 -1
  200. package/src/server/board-export.ts +5 -2
  201. package/src/server/canvas-db.ts +46 -12
  202. package/src/server/canvas-geometry.ts +64 -0
  203. package/src/server/canvas-operations.ts +6 -24
  204. package/src/server/canvas-state.ts +105 -15
  205. package/src/server/canvas-validation.ts +19 -4
  206. package/src/server/context-brief.ts +39 -2
  207. package/src/server/context-reads.ts +86 -15
  208. package/src/server/demo-state.json +31 -31
  209. package/src/server/html-surface.ts +4 -5
  210. package/src/server/index.ts +19 -3
  211. package/src/server/mcp-app-runtime.ts +11 -0
  212. package/src/server/operations/composites.ts +4 -3
  213. package/src/server/operations/http.ts +4 -4
  214. package/src/server/operations/invoker.ts +13 -4
  215. package/src/server/operations/ops/ax-read.ts +1 -1
  216. package/src/server/operations/ops/ax-timeline.ts +37 -0
  217. package/src/server/operations/ops/boards.ts +1 -1
  218. package/src/server/operations/ops/canvas-wire.ts +3 -6
  219. package/src/server/operations/ops/intent.ts +31 -2
  220. package/src/server/operations/ops/json-render.ts +1 -1
  221. package/src/server/operations/ops/nodes.ts +8 -76
  222. package/src/server/operations/ops/query.ts +8 -2
  223. package/src/server/operations/ops/snapshots.ts +4 -1
  224. package/src/server/operations/ops/viewport.ts +29 -5
  225. package/src/server/operations/registry.ts +38 -4
  226. package/src/server/scope-fence.ts +55 -10
  227. package/src/server/server.ts +83 -5
  228. package/src/server/spatial-analysis.ts +2 -2
  229. package/src/server/workboard.ts +6 -1
  230. package/src/{server → shared}/agent-context.ts +2 -2
  231. package/src/shared/agent-presence.ts +3 -15
  232. package/src/shared/canvas-app.ts +62 -0
  233. package/src/shared/themes.ts +5 -5
  234. package/src/client/canvas/FocusFieldLayer.tsx +0 -116
  235. package/src/client/canvas/kind-colors.ts +0 -23
@@ -0,0 +1,280 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>PMX Canvas — proposed</title>
6
+ <script src="./support.js"></script>
7
+ </head>
8
+ <body>
9
+ <x-dc>
10
+ <helmet>
11
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&amp;family=IBM+Plex+Sans:wght@400;500;600&amp;display=swap">
12
+ <style>
13
+ body{margin:0}
14
+ </style>
15
+ </helmet>
16
+ <div style="position: relative; width: 1440px; height: 900px; overflow: hidden; background: {{c.bg}}; color: {{c.text}}; font-family: 'IBM Plex Sans', system-ui, sans-serif; font-size: 13px; line-height: 1.5">
17
+
18
+ <nav aria-label="Tools" style="position: absolute; left: 0; top: 0; width: 52px; height: 900px; box-sizing: border-box; padding: 8px 0; background: {{c.panel}}; border-right: 1px solid {{c.line}}; display: flex; flex-direction: column; align-items: center; gap: 4px">
19
+ <button aria-label="Home" style="{{s.rail}}"><svg width="20" height="20" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><rect x="4" y="4" width="16" height="16" rx="4"></rect><rect x="9" y="9" width="6" height="6" rx="1.5"></rect></svg></button>
20
+ <div style="width: 24px; height: 1px; margin: 6px 0; background: {{c.line}}"></div>
21
+ <button aria-label="Select (V)" style="{{s.railOn}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><path d="M5 3.5l13 7.5-5.6 1.6L10.8 18z"></path></svg></button>
22
+ <button aria-label="Pan (Space)" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><path d="M8 12V6.5a1.5 1.5 0 0 1 3 0V11M11 10.5V5a1.5 1.5 0 0 1 3 0v6M14 10.5V7a1.5 1.5 0 0 1 3 0v6.5a6.5 6.5 0 0 1-6.5 6.5h-.6a6 6 0 0 1-5-2.7l-1.8-3a1.5 1.5 0 0 1 2.5-1.6L8 14"></path></svg></button>
23
+ <button aria-label="Connect (C)" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><circle cx="6" cy="6" r="2.2"></circle><circle cx="18" cy="18" r="2.2"></circle><path d="M7.6 7.6l8.8 8.8"></path></svg></button>
24
+ <div style="width: 24px; height: 1px; margin: 6px 0; background: {{c.line}}"></div>
25
+ <button aria-label="Markdown note (M)" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><rect x="4" y="5" width="16" height="14" rx="2"></rect><path d="M8 10h8M8 14h5"></path></svg></button>
26
+ <button aria-label="Attach files" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><path d="M12 15V4M7.5 8.5L12 4l4.5 4.5M5 19.5h14"></path></svg></button>
27
+ <button aria-label="Webpage (W)" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><rect x="3.5" y="5" width="17" height="14" rx="2"></rect><path d="M3.5 9h17"></path></svg></button>
28
+ <button aria-label="Group (G)" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 3 3"><rect x="4" y="4" width="16" height="16" rx="3"></rect></svg></button>
29
+ <button aria-label="Draw (A)" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><path d="M4 20l4.2-1L19 8.2 15.8 5 5 15.8z"></path></svg></button>
30
+ <button aria-label="Text note" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><path d="M5.5 6h13M12 6v13"></path></svg></button>
31
+ <div style="width: 24px; height: 1px; margin: 6px 0; background: {{c.line}}"></div>
32
+ <button aria-label="Search and commands (⌘K)" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><circle cx="11" cy="11" r="6"></circle><path d="M20 20l-4.6-4.6"></path></svg></button>
33
+ <button aria-label="Arrange" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><rect x="4" y="4" width="6" height="6" rx="1.2"></rect><rect x="14" y="4" width="6" height="6" rx="1.2"></rect><rect x="4" y="14" width="6" height="6" rx="1.2"></rect><rect x="14" y="14" width="6" height="6" rx="1.2"></rect></svg></button>
34
+ <div style="flex: 1"></div>
35
+ <button aria-label="Settings: theme, snapshots, minimap, shortcuts, trace, feedback" style="{{s.rail}}"><svg width="18" height="18" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><path d="M4 7h9M17 7h3M4 17h3M11 17h9"></path><circle cx="15" cy="7" r="2"></circle><circle cx="9" cy="17" r="2"></circle></svg></button>
36
+ </nav>
37
+
38
+ <header style="position: absolute; left: 52px; top: 0; right: 0; height: 48px; box-sizing: border-box; padding: 0 12px 0 16px; display: flex; align-items: center; gap: 8px; background: {{c.panel}}; border-bottom: 1px solid {{c.line}}">
39
+ <span style="width: 8px; height: 8px; border-radius: 999px; background: {{c.ok}}"></span>
40
+ <button style="{{s.ghost}} font-size: 13px; font-weight: 600; color: {{c.text}}; gap: 6px">Release review<svg width="14" height="14" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round"><path d="M7 10l5 5 5-5"></path></svg></button>
41
+ <span style="font-size: 11px; color: {{c.dim}}">70 nodes</span>
42
+ <div style="flex: 1"></div>
43
+ <button style="{{s.pill}}"><span style="width: 7px; height: 7px; border-radius: 999px; background: {{c.dim}}"></span>Start agent session<span style="font-size: 11px; color: {{c.dim}}">beta</span></button>
44
+ <div style="width: 1px; height: 20px; margin: 0 4px; background: {{c.line}}"></div>
45
+ <button style="{{s.btn}}">Export</button>
46
+ <button style="{{s.btn}}">Present</button>
47
+ <div style="width: 1px; height: 20px; margin: 0 4px; background: {{c.line}}"></div>
48
+ <button aria-label="Zoom out" style="{{s.icon28}}"><svg width="16" height="16" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round"><circle cx="11" cy="11" r="6"></circle><path d="M8.5 11h5M20 20l-4.6-4.6"></path></svg></button>
49
+ <span style="font-size: 12px; font-weight: 500; color: {{c.soft}}; font-variant-numeric: tabular-nums; width: 40px; text-align: center">100%</span>
50
+ <button aria-label="Zoom in" style="{{s.icon28}}"><svg width="16" height="16" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round"><circle cx="11" cy="11" r="6"></circle><path d="M8.5 11h5M11 8.5v5M20 20l-4.6-4.6"></path></svg></button>
51
+ <button aria-label="Fit all (F)" style="{{s.icon28}}"><svg width="16" height="16" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round"><path d="M4 9V4h5M15 4h5v5M20 15v5h-5M9 20H4v-5"></path></svg></button>
52
+ </header>
53
+
54
+ <main style="position: absolute; left: 52px; top: 48px; width: 1388px; height: 852px; overflow: hidden; background-color: {{c.bg}}; background-image: radial-gradient({{c.dot}} 1px, transparent 1.2px); background-size: 24px 24px">
55
+
56
+ <div style="position: absolute; left: 48px; top: 20px; width: 900px">
57
+ <h2 style="margin: 0; font-size: 20px; line-height: 28px; font-weight: 600; letter-spacing: -0.01em; color: {{c.text}}">① Start here</h2>
58
+ <p style="margin: 2px 0 0; font-size: 12px; color: {{c.muted}}">What the agent is doing, what context it holds, what it decided, and the tool calls behind it.</p>
59
+ </div>
60
+
61
+ <section style="{{s.nodePinned}}">
62
+ <div style="{{s.head}}">
63
+ <svg width="16" height="16" viewBox="0 0 24 24" style="flex-shrink: 0; color: {{c.muted}}; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><rect x="4" y="5" width="16" height="14" rx="2"></rect><path d="M8 10h8M8 14h5"></path></svg>
64
+ <span style="{{s.title}}">PMX Canvas — guided tour</span>
65
+ <button aria-label="Expand (Enter)" style="{{s.expand}}"><svg width="13" height="13" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round"><path d="M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7"></path></svg></button>
66
+ <span role="img" aria-label="In agent context" style="{{s.pinOn}}"><svg width="10" height="10" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round"><path d="M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20"></path></svg></span>
67
+ </div>
68
+ <div style="padding: 14px 16px; display: flex; flex-direction: column; gap: 10px">
69
+ <div style="font-size: 15px; font-weight: 600; line-height: 1.35">PMX Canvas</div>
70
+ <p style="margin: 0; font-size: 12px; line-height: 1.6; color: {{c.soft}}">An infinite spatial canvas that agents drive over <strong style="color: {{c.text}}; font-weight: 600">MCP</strong>, HTTP or the Bun SDK — and that humans steer by pinning nodes.</p>
71
+ <div style="display: grid; grid-template-columns: 120px 1fr; font-size: 12px; border: 1px solid {{c.line}}; border-radius: 6px; overflow: hidden">
72
+ <div style="{{s.th}}">Band</div><div style="{{s.th}}">Shows</div>
73
+ <div style="{{s.td}}">① Start here</div><div style="{{s.tdm}}">status · context · ledger · trace</div>
74
+ <div style="{{s.td}}">② Files &amp; review</div><div style="{{s.tdm}}">file · CSV · diff · image · webpage</div>
75
+ <div style="{{s.td}}">③ Diagrams</div><div style="{{s.tdm}}">mermaid · raw HTML · MCP app</div>
76
+ <div style="{{s.td}}">④ Charts</div><div style="{{s.tdm}}">all 12 graph types</div>
77
+ </div>
78
+ <p style="margin: 0; font-size: 12px; line-height: 1.6; color: {{c.soft}}">Pin a node in the browser and the agent reads it back from <code style="font-family: 'IBM Plex Mono', monospace; font-size: 11px; padding: 1px 5px; border-radius: 4px; background: {{c.panel2}}; color: {{c.text}}">canvas://pinned-context</code>.</p>
79
+ </div>
80
+ </section>
81
+
82
+ <section style="{{s.node}} left: 480px; top: 88px; width: 340px; height: 140px">
83
+ <div style="position: absolute; left: 0; right: 0; top: 0; height: 2px; background: {{c.attn}}"></div>
84
+ <div style="{{s.head}}">
85
+ <svg width="16" height="16" viewBox="0 0 24 24" style="flex-shrink: 0; color: {{c.muted}}; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><circle cx="12" cy="12" r="8"></circle><path d="M8 12h2l1.5-3 2 6 1.5-3h1"></path></svg>
86
+ <span style="{{s.title}}">Agent</span>
87
+ <span style="font-size: 11px; font-weight: 500; padding: 1px 8px; border-radius: 999px; background: {{c.attnA}}; color: {{c.attn}}">agent editing</span>
88
+ <button aria-label="Add to context (P)" style="{{s.pinOff}}"><svg width="10" height="10" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round"><path d="M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20"></path></svg></button>
89
+ </div>
90
+ <div style="padding: 10px 14px; display: flex; flex-direction: column; gap: 6px; font-size: 12px">
91
+ <div style="display: flex; align-items: center; gap: 8px"><span style="width: 7px; height: 7px; border-radius: 999px; background: {{c.attn}}"></span><span style="font-weight: 600">Tooling</span><span style="color: {{c.muted}}">Rebuilding the release checklist</span></div>
92
+ <div style="font-family: 'IBM Plex Mono', monospace; font-size: 12px; color: {{c.soft}}">canvas_render · release-auditor</div>
93
+ <div style="display: flex; align-items: center; gap: 10px"><div style="flex: 1; height: 4px; border-radius: 999px; background: {{c.line}}; overflow: hidden"><div style="width: 60%; height: 4px; background: {{c.ok}}"></div></div><span style="font-size: 11px; color: {{c.muted}}">3 of 5 gates green</span></div>
94
+ </div>
95
+ </section>
96
+
97
+ <div style="position: absolute; left: 649px; top: 228px; width: 1.5px; height: 44px; background: {{c.line}}"></div>
98
+ <span style="{{s.edgeLabel}} left: 626px; top: 239px">runs</span>
99
+
100
+ <div style="{{s.trace}} left: 480px; top: 272px; width: 340px; height: 56px">
101
+ <svg width="16" height="16" viewBox="0 0 24 24" style="flex-shrink: 0; color: {{c.ok}}; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round"><path d="M5 12.5l4.5 4.5L19 7.5"></path></svg>
102
+ <div style="flex: 1; min-width: 0"><div style="font-family: 'IBM Plex Mono', monospace; font-size: 12px; font-weight: 500">canvas_query · search</div><div style="font-size: 11px; color: {{c.muted}}">7 nodes matched “release”</div></div>
103
+ <span style="font-size: 11px; color: {{c.dim}}; font-variant-numeric: tabular-nums">38 ms</span>
104
+ </div>
105
+
106
+ <div style="position: absolute; left: 649px; top: 328px; width: 1.5px; height: 44px; background: {{c.line}}"></div>
107
+ <span style="{{s.edgeLabel}} left: 628px; top: 339px">then</span>
108
+
109
+ <div style="{{s.trace}} left: 480px; top: 372px; width: 340px; height: 56px">
110
+ <span style="width: 16px; display: flex; justify-content: center"><span style="width: 8px; height: 8px; border-radius: 999px; background: {{c.attn}}; box-shadow: 0 0 0 4px {{c.attnA}}"></span></span>
111
+ <div style="flex: 1; min-width: 0"><div style="font-family: 'IBM Plex Mono', monospace; font-size: 12px; font-weight: 500">edit_file · CHANGELOG.md</div><div style="font-size: 11px; color: {{c.muted}}">Writing 0.4.7 highlights</div></div>
112
+ <span style="font-size: 11px; color: {{c.dim}}; font-variant-numeric: tabular-nums">1.2 s</span>
113
+ </div>
114
+
115
+ <section style="{{s.node}} left: 852px; top: 88px; width: 420px; height: 340px">
116
+ <div style="{{s.head}}">
117
+ <svg width="16" height="16" viewBox="0 0 24 24" style="flex-shrink: 0; color: {{c.muted}}; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><path d="M4 4v16h16M8 16v-4M12 16V8M16 16v-6"></path></svg>
118
+ <span style="{{s.title}}">Merged PRs per week</span>
119
+ <button aria-label="Expand (Enter)" style="{{s.expand}}"><svg width="13" height="13" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round"><path d="M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7"></path></svg></button>
120
+ <button aria-label="Add to context (P)" style="{{s.pinOff}}"><svg width="10" height="10" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round"><path d="M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20"></path></svg></button>
121
+ <button aria-label="More actions" style="{{s.ibtnOn}}"><svg width="16" height="16" viewBox="0 0 24 24" style="fill: currentColor; stroke: none"><circle cx="6" cy="12" r="1.4"></circle><circle cx="12" cy="12" r="1.4"></circle><circle cx="18" cy="12" r="1.4"></circle></svg></button>
122
+ <button aria-label="Close" style="{{s.ibtn}}"><svg width="14" height="14" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round"><path d="M7 7l10 10M17 7L7 17"></path></svg></button>
123
+ </div>
124
+ <div style="padding: 12px 16px 14px; flex: 1; display: flex; flex-direction: column; gap: 10px">
125
+ <div style="display: flex; align-items: baseline; justify-content: space-between"><span style="font-size: 11px; color: {{c.muted}}">bar · W23–W28</span><span style="font-size: 11px; color: {{c.muted}}"><span style="display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 6px; background: {{c.accent}}"></span>merged</span></div>
126
+ <div style="flex: 1; position: relative; display: flex; align-items: flex-end; gap: 18px; padding: 0 4px; border-bottom: 1px solid {{c.line}}; background-image: linear-gradient({{c.line}} 1px, transparent 1px); background-size: 100% 56px">
127
+ <sc-for list="{{bars}}" as="b" hint-placeholder-count="6">
128
+ <div style="flex: 1; display: flex; flex-direction: column; justify-content: flex-end; height: 100%"><div style="height: {{b.h}}px; border-radius: 4px 4px 0 0; background: {{b.fill}}"></div></div>
129
+ </sc-for>
130
+ </div>
131
+ <div style="display: flex; gap: 18px; padding: 0 4px">
132
+ <sc-for list="{{bars}}" as="b" hint-placeholder-count="6">
133
+ <span style="flex: 1; text-align: center; font-size: 11px; color: {{c.muted}}">{{b.label}}</span>
134
+ </sc-for>
135
+ </div>
136
+ </div>
137
+ </section>
138
+
139
+ <div style="position: absolute; left: 48px; top: 456px; width: 900px">
140
+ <h2 style="margin: 0; font-size: 20px; line-height: 28px; font-weight: 600; letter-spacing: -0.01em; color: {{c.text}}">② Files &amp; review</h2>
141
+ <p style="margin: 2px 0 0; font-size: 12px; color: {{c.muted}}">Inline file text, unified diffs, images and cached webpages.</p>
142
+ </div>
143
+
144
+ <section style="{{s.node}} left: 48px; top: 524px; width: 400px; height: 176px">
145
+ <div style="{{s.head}}">
146
+ <svg width="16" height="16" viewBox="0 0 24 24" style="flex-shrink: 0; color: {{c.muted}}; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><rect x="3.5" y="5" width="17" height="14" rx="2"></rect><path d="M3.5 9h17"></path></svg>
147
+ <span style="{{s.title}}">Model Context Protocol — Resources</span>
148
+ <button aria-label="Expand (Enter)" style="{{s.expand}}"><svg width="13" height="13" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round"><path d="M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7"></path></svg></button>
149
+ <button aria-label="Add to context (P)" style="{{s.pinOff}}"><svg width="10" height="10" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round"><path d="M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20"></path></svg></button>
150
+ </div>
151
+ <div style="padding: 10px 14px; display: flex; flex-direction: column; gap: 8px">
152
+ <div style="display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 6px; background: {{c.warnA}}; color: {{c.warn}}; font-size: 12px; font-weight: 500"><svg width="14" height="14" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round"><path d="M12 4l9 16H3zM12 10v4M12 17v.5"></path></svg>Showing cached copy — live fetch failed</div>
153
+ <div style="font-size: 13px; font-weight: 600">Resources</div>
154
+ <p style="margin: 0; font-size: 12px; line-height: 1.6; color: {{c.soft}}">Servers expose data and content that clients can read and use as context for model interactions.</p>
155
+ </div>
156
+ </section>
157
+
158
+ <section style="{{s.node}} left: 480px; top: 524px; width: 340px; height: 176px">
159
+ <div style="{{s.head}}">
160
+ <svg width="16" height="16" viewBox="0 0 24 24" style="flex-shrink: 0; color: {{c.muted}}; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><path d="M7 3.5h7l4 4V20.5H6V3.5zM14 3.5V8h4"></path></svg>
161
+ <span style="{{s.title}}">node-sizes.ts</span>
162
+ <span style="font-size: 11px; color: {{c.dim}}">src/shared</span>
163
+ <button aria-label="Expand (Enter)" style="{{s.expand}}"><svg width="13" height="13" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round"><path d="M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7"></path></svg></button>
164
+ <button aria-label="Add to context (P)" style="{{s.pinOff}}"><svg width="10" height="10" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round"><path d="M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20"></path></svg></button>
165
+ </div>
166
+ <div style="flex: 1; padding: 10px 14px; background: {{c.codeBg}}; font-family: 'IBM Plex Mono', monospace; font-size: 12px; line-height: 1.6; color: {{c.soft}}; white-space: pre">export const NODE_MIN = { width: 180, height: 96 };
167
+
168
+ export function clampSize(size) {
169
+ return {
170
+ width: Math.max(size.width, NODE_MIN.width),
171
+ height: Math.max(size.height, NODE_MIN.height),</div>
172
+ </section>
173
+
174
+ <section style="{{s.node}} left: 852px; top: 524px; width: 420px; height: 176px">
175
+ <div style="{{s.head}}">
176
+ <svg width="16" height="16" viewBox="0 0 24 24" style="flex-shrink: 0; color: {{c.muted}}; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round"><rect x="4" y="3" width="16" height="18" rx="2"></rect><path d="M12 6.5v6M9 9.5h6M9 17h6"></path></svg>
177
+ <span style="{{s.title}}">Readability floor — 2 files</span>
178
+ <span style="font-size: 11px; color: {{c.ok}}">+2</span><span style="font-size: 11px; color: {{c.danger}}">−2</span>
179
+ <button aria-label="Expand (Enter)" style="{{s.expand}}"><svg width="13" height="13" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round"><path d="M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7"></path></svg></button>
180
+ <button aria-label="Add to context (P)" style="{{s.pinOff}}"><svg width="10" height="10" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round"><path d="M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20"></path></svg></button>
181
+ </div>
182
+ <div style="flex: 1; padding: 8px 0; background: {{c.codeBg}}; font-family: 'IBM Plex Mono', monospace; font-size: 12px; line-height: 1.7">
183
+ <div style="padding: 0 14px; color: {{c.dim}}">@@ src/client/theme/global.css</div>
184
+ <div style="padding: 0 14px; background: {{c.dangerA}}; color: {{c.danger}}">- font-size: 10px;</div>
185
+ <div style="padding: 0 14px; background: {{c.okA}}; color: {{c.ok}}">+ font-size: var(--fs-meta);</div>
186
+ <div style="padding: 0 14px; background: {{c.dangerA}}; color: {{c.danger}}">- border-radius: 12px 12px 8px 8px;</div>
187
+ <div style="padding: 0 14px; background: {{c.okA}}; color: {{c.ok}}">+ border-radius: var(--r-node);</div>
188
+ </div>
189
+ </section>
190
+
191
+ <button style="position: absolute; right: 16px; top: 16px; display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 8px 0 12px; border-radius: 999px; border: 1px solid {{c.line}}; background: {{c.panel}}; box-shadow: {{c.e2}}; color: {{c.soft}}; font-family: inherit; font-size: 12px; font-weight: 500">Updates<span style="min-width: 18px; height: 18px; padding: 0 5px; box-sizing: border-box; border-radius: 999px; background: {{c.accent}}; color: {{c.onAccent}}; font-size: 11px; font-weight: 600; display: flex; align-items: center; justify-content: center">1</span></button>
192
+
193
+ <div style="position: absolute; left: 594px; bottom: 20px; display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 6px 0 12px; border-radius: 999px; border: 1px solid {{c.accentRing}}; background: {{c.panel}}; box-shadow: {{c.e2}}; font-size: 12px; font-weight: 500; color: {{c.accent}}">
194
+ <svg width="14" height="14" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round"><path d="M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20"></path></svg>
195
+ 4 in context
196
+ <button aria-label="Clear all context pins" style="width: 22px; height: 22px; border: 0; border-radius: 999px; background: {{c.accentA}}; color: {{c.accent}}; display: flex; align-items: center; justify-content: center; padding: 0"><svg width="12" height="12" viewBox="0 0 24 24" style="fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round"><path d="M7 7l10 10M17 7L7 17"></path></svg></button>
197
+ </div>
198
+
199
+ <div style="position: absolute; right: 16px; bottom: 16px; width: 200px; height: 130px; box-sizing: border-box; border-radius: 10px; border: 1px solid {{c.line}}; background: {{c.panel}}; box-shadow: {{c.e2}}; overflow: hidden">
200
+ <sc-for list="{{mini}}" as="m" hint-placeholder-count="12">
201
+ <div style="position: absolute; left: {{m.x}}px; top: {{m.y}}px; width: {{m.w}}px; height: {{m.h}}px; border-radius: 2px; background: {{m.fill}}"></div>
202
+ </sc-for>
203
+ <div style="position: absolute; left: 10px; top: 10px; width: 64px; height: 44px; border: 1.5px solid {{c.soft}}; border-radius: 3px"></div>
204
+ <span style="position: absolute; right: 8px; bottom: 6px; font-size: 11px; color: {{c.dim}}">100%</span>
205
+ </div>
206
+
207
+ </main>
208
+ </div>
209
+ </x-dc>
210
+ <script type="text/x-dc" data-dc-script data-props='{"theme":{"editor":"enum","options":["harbor","daylight"],"default":"harbor"},"$preview":{"width":1440,"height":900}}'>
211
+ class Component extends DCLogic {
212
+ renderVals() {
213
+ var themes = {
214
+ harbor: {
215
+ bg: '#081524', dot: 'rgba(142,163,189,0.14)', panel: '#0f1d31', panel2: '#13243b', line: '#1b2c44',
216
+ text: '#e6eef7', soft: '#b9c6d6', muted: '#8ea3bd', dim: '#6b7d94',
217
+ accent: '#4BBCFF', accentA: 'rgba(75,188,255,0.14)', accentRing: 'rgba(75,188,255,0.24)', onAccent: '#081524',
218
+ attn: '#B388FF', attnA: 'rgba(179,136,255,0.16)',
219
+ warn: '#f4c542', warnA: 'rgba(244,197,66,0.12)', ok: '#2fd07f', okA: 'rgba(47,208,127,0.10)',
220
+ danger: '#ff6a7f', dangerA: 'rgba(255,106,127,0.10)', codeBg: '#0b1828',
221
+ e1: '0 1px 2px rgba(0,0,0,0.4), 0 6px 20px rgba(0,0,0,0.24)', e2: '0 10px 30px rgba(0,0,0,0.45)',
222
+ mm: 'rgba(142,163,189,0.30)', bar: 'rgba(75,188,255,0.45)'
223
+ },
224
+ daylight: {
225
+ bg: '#F6F7F9', dot: 'rgba(11,23,38,0.12)', panel: '#FFFFFF', panel2: '#F2F4F7', line: '#DDE2E9',
226
+ text: '#0B1726', soft: '#3d4d63', muted: '#55657a', dim: '#6f7d90',
227
+ accent: '#1A7ABF', accentA: 'rgba(26,122,191,0.10)', accentRing: 'rgba(26,122,191,0.20)', onAccent: '#FFFFFF',
228
+ attn: '#7C4DDB', attnA: 'rgba(124,77,219,0.10)',
229
+ warn: '#94600A', warnA: 'rgba(214,150,30,0.14)', ok: '#1E7F51', okA: 'rgba(30,143,90,0.10)',
230
+ danger: '#B8344A', dangerA: 'rgba(201,58,79,0.08)', codeBg: '#F7F9FB',
231
+ e1: '0 1px 2px rgba(11,23,38,0.06), 0 4px 14px rgba(11,23,38,0.06)', e2: '0 10px 30px rgba(11,23,38,0.12)',
232
+ mm: 'rgba(11,23,38,0.14)', bar: 'rgba(26,122,191,0.35)'
233
+ }
234
+ };
235
+ var c = themes[this.props.theme] || themes.harbor;
236
+ var btnBase = 'display:flex;align-items:center;justify-content:center;border:0;padding:0;font-family:inherit;cursor:pointer;';
237
+ var s = {
238
+ rail: btnBase + 'width:36px;height:36px;border-radius:6px;background:transparent;color:' + c.muted + ';',
239
+ railOn: btnBase + 'width:36px;height:36px;border-radius:6px;background:' + c.accentA + ';color:' + c.accent + ';',
240
+ ghost: btnBase + 'height:30px;padding:0 6px;border-radius:6px;background:transparent;',
241
+ pill: btnBase + 'gap:8px;height:30px;padding:0 12px;border-radius:999px;border:1px solid ' + c.line + ';background:transparent;color:' + c.muted + ';font-size:12px;font-weight:500;',
242
+ btn: btnBase + 'height:30px;padding:0 12px;border-radius:6px;border:1px solid ' + c.line + ';background:' + c.panel2 + ';color:' + c.text + ';font-size:12px;font-weight:500;',
243
+ icon28: btnBase + 'width:28px;height:28px;border-radius:6px;background:transparent;color:' + c.muted + ';',
244
+ ibtn: btnBase + 'width:24px;height:24px;border-radius:6px;background:transparent;color:' + c.muted + ';',
245
+ ibtnOn: btnBase + 'width:24px;height:24px;border-radius:6px;background:' + c.panel2 + ';color:' + c.text + ';',
246
+ node: 'position:absolute;box-sizing:border-box;display:flex;flex-direction:column;overflow:hidden;background:' + c.panel + ';border:1px solid ' + c.line + ';border-radius:10px;box-shadow:' + c.e1 + ';',
247
+ nodePinned: 'position:absolute;box-sizing:border-box;display:flex;flex-direction:column;overflow:hidden;background:' + c.panel + ';border:1.5px solid ' + c.accent + ';border-radius:10px;box-shadow:0 0 0 3px ' + c.accentRing + ', ' + c.e1 + ';left:48px;top:88px;width:400px;height:340px;',
248
+ pinOff: btnBase + 'flex-shrink:0;width:18px;height:18px;box-sizing:border-box;border-radius:999px;border:1.5px solid ' + c.dim + ';background:transparent;color:' + c.soft + ';',
249
+ expand: btnBase + 'flex-shrink:0;width:22px;height:22px;border-radius:6px;background:transparent;color:' + c.soft + ';',
250
+ pinOn: 'flex-shrink:0;width:18px;height:18px;border-radius:999px;display:flex;align-items:center;justify-content:center;background:' + c.accent + ';color:' + c.onAccent + ';',
251
+ head: 'position:relative;display:flex;align-items:center;gap:8px;height:36px;flex-shrink:0;box-sizing:border-box;padding:0 8px 0 12px;border-bottom:1px solid ' + c.line + ';',
252
+ title: 'flex:1;min-width:0;font-size:12px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:' + c.text + ';',
253
+ trace: 'position:absolute;box-sizing:border-box;display:flex;align-items:center;gap:10px;padding:0 14px;background:' + c.panel + ';border:1px solid ' + c.line + ';border-radius:10px;box-shadow:' + c.e1 + ';',
254
+ edgeLabel: 'position:absolute;font-size:11px;line-height:20px;padding:0 8px;border-radius:999px;border:1px solid ' + c.line + ';background:' + c.panel2 + ';color:' + c.muted + ';',
255
+ th: 'padding:5px 10px;font-size:11px;font-weight:600;color:' + c.muted + ';background:' + c.panel2 + ';border-bottom:1px solid ' + c.line + ';',
256
+ td: 'padding:5px 10px;border-bottom:1px solid ' + c.line + ';color:' + c.text + ';',
257
+ tdm: 'padding:5px 10px;border-bottom:1px solid ' + c.line + ';color:' + c.muted + ';'
258
+ };
259
+ var heights = [92, 84, 118, 106, 128, 150];
260
+ var labels = ['W23', 'W24', 'W25', 'W26', 'W27', 'W28'];
261
+ var bars = heights.map(function (h, i) {
262
+ return { h: h, label: labels[i], fill: i === heights.length - 1 ? c.accent : c.bar };
263
+ });
264
+ var mini = [
265
+ { x: 10, y: 10, w: 22, h: 18, fill: c.accent },
266
+ { x: 36, y: 10, w: 18, h: 8, fill: c.mm }, { x: 36, y: 21, w: 18, h: 3, fill: c.mm }, { x: 36, y: 26, w: 18, h: 3, fill: c.mm },
267
+ { x: 58, y: 10, w: 22, h: 18, fill: c.mm },
268
+ { x: 10, y: 36, w: 22, h: 10, fill: c.mm }, { x: 36, y: 36, w: 18, h: 10, fill: c.mm }, { x: 58, y: 36, w: 22, h: 10, fill: c.mm },
269
+ { x: 92, y: 10, w: 26, h: 20, fill: c.mm }, { x: 122, y: 10, w: 26, h: 20, fill: c.mm }, { x: 152, y: 10, w: 26, h: 20, fill: c.mm },
270
+ { x: 92, y: 36, w: 26, h: 20, fill: c.mm }, { x: 122, y: 36, w: 26, h: 20, fill: c.mm }, { x: 152, y: 36, w: 26, h: 20, fill: c.mm },
271
+ { x: 10, y: 62, w: 22, h: 18, fill: c.mm }, { x: 36, y: 62, w: 22, h: 18, fill: c.mm }, { x: 62, y: 62, w: 22, h: 18, fill: c.mm },
272
+ { x: 92, y: 62, w: 26, h: 20, fill: c.mm }, { x: 122, y: 62, w: 26, h: 20, fill: c.mm }, { x: 152, y: 62, w: 26, h: 20, fill: c.mm },
273
+ { x: 10, y: 88, w: 50, h: 12, fill: c.mm }, { x: 92, y: 88, w: 26, h: 20, fill: c.mm }, { x: 122, y: 88, w: 26, h: 20, fill: c.mm }
274
+ ];
275
+ return { c: c, s: s, bars: bars, mini: mini };
276
+ }
277
+ }
278
+ </script>
279
+ </body>
280
+ </html>
@@ -0,0 +1,260 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Near a pin</title>
6
+ <script src="./support.js"></script>
7
+ </head>
8
+ <body>
9
+ <x-dc>
10
+ <helmet>
11
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&amp;family=IBM+Plex+Sans:wght@400;500;600&amp;display=swap">
12
+ <style>
13
+ body{margin:0}
14
+ </style>
15
+ </helmet>
16
+ <div style="width: 1440px; height: 2020px; box-sizing: border-box; padding: 44px 56px; background: #081524; color: #e6eef7; font-family: 'IBM Plex Sans', system-ui, sans-serif; font-size: 13px; line-height: 1.5; display: flex; flex-direction: column; gap: 28px">
17
+
18
+ <div>
19
+ <h1 style="margin: 0; font-size: 28px; font-weight: 600; letter-spacing: -0.015em">Near a pin</h1>
20
+ <p style="margin: 4px 0 0; font-size: 13px; color: #8ea3bd; max-width: 1100px">Each pinned node pulls up to five unpinned nodes whose centres are within 600 px into the agent's brief — each as its title and a short summary, with “near &lt;pin&gt;” as the reason, never its full content. They get their own, weaker mark: a dotted chip with the word “near”. The mark ships in wave 1 together with that brief change, so it claims exactly what the agent receives.</p>
21
+ </div>
22
+
23
+ <section style="display: grid; grid-template-columns: 860px minmax(0, 1fr); gap: 32px">
24
+ <div style="display: flex; flex-direction: column; gap: 8px">
25
+ <span style="{{s.label}}">1 · At rest</span>
26
+ <div style="{{s.scene}} height: 420px">
27
+ <sc-for list="{{rest}}" as="n" hint-placeholder-count="6">
28
+ <div style="{{n.box}}">
29
+ <div style="{{n.head}}"><svg width="14" height="14" viewBox="0 0 24 24" style="{{s.kind}}"><path d="{{i.note}}"></path></svg><span style="{{s.title}}">{{n.title}}</span>
30
+ <sc-if value="{{n.near}}" hint-placeholder-val="{{ false }}"><span style="{{s.chip}}"><svg width="11" height="11" viewBox="0 0 24 24" style="{{s.ring}}"><circle cx="12" cy="12" r="8"></circle><circle cx="12" cy="12" r="2.4" style="fill: currentColor; stroke: none"></circle></svg>{{n.nearText}}</span></sc-if>
31
+ <span style="{{s.expand}}"><svg width="12" height="12" viewBox="0 0 24 24" style="{{s.ic}}"><path d="{{i.expand}}"></path></svg></span>
32
+ <span style="{{n.pinStyle}}"><svg width="9" height="9" viewBox="0 0 24 24" style="{{s.ic2}}"><path d="{{i.pin}}"></path></svg></span>
33
+ </div>
34
+ <div style="padding: 7px 10px; font-size: 11px; color: #8ea3bd">{{n.meta}}</div>
35
+ </div>
36
+ </sc-for>
37
+ </div>
38
+ <span style="font-size: 12px; color: #8ea3bd">Two pins. Price page copy and Churn deep-dive are near Release runbook; Pricing notes is near both pins (“near 2”). Q3 risks is farther than 600 px, so it carries nothing.</span>
39
+ </div>
40
+
41
+ <div style="display: flex; flex-direction: column; gap: 12px">
42
+ <span style="{{s.label}}">The mark</span>
43
+ <div style="{{s.card}} gap: 12px">
44
+ <div style="display: flex; align-items: center; gap: 10px"><span style="{{s.chip}}"><svg width="11" height="11" viewBox="0 0 24 24" style="{{s.ring}}"><circle cx="12" cy="12" r="8"></circle><circle cx="12" cy="12" r="2.4" style="fill: currentColor; stroke: none"></circle></svg>near</span><span style="font-size: 12px; color: #b9c6d6">Dotted ring with a dot, the word “near”, a dotted pin-blue outline. In the header after the title, before expand and the pin.</span></div>
45
+ <div style="display: flex; align-items: center; gap: 10px"><span style="{{s.chip}}"><svg width="11" height="11" viewBox="0 0 24 24" style="{{s.ring}}"><circle cx="12" cy="12" r="8"></circle><circle cx="12" cy="12" r="2.4" style="fill: currentColor; stroke: none"></circle></svg>near 2</span><span style="font-size: 12px; color: #b9c6d6">Near more than one pin: the count. Hover lists the pins.</span></div>
46
+ <div style="height: 1px; background: #1b2c44"></div>
47
+ <sc-for list="{{compare}}" as="c" hint-placeholder-count="4">
48
+ <div style="display: grid; grid-template-columns: 110px 1fr; gap: 10px; font-size: 12px"><span style="font-weight: 600">{{c.k}}</span><span style="color: #b9c6d6">{{c.v}}</span></div>
49
+ </sc-for>
50
+ </div>
51
+ <div style="{{s.card}} gap: 6px">
52
+ <span style="font-size: 12px; font-weight: 600">What the agent gets (wave 1 brief)</span>
53
+ <span style="font-size: 12px; color: #b9c6d6">In the main brief, after the pinned cards: each near node's title and a short summary, nearest first, with the pin it is near as the reason. Never its full content — pin it for that.</span>
54
+ <div style="padding: 8px 10px; border-radius: 6px; background: #06111e; border: 1px solid #1b2c44; font-family: 'IBM Plex Mono', monospace; font-size: 11px; line-height: 1.6; color: #b9c6d6; white-space: pre-wrap">near “Release runbook” · 240 px
55
+ Price page copy — Draft copy for the Pro plan page: headline, three benefits, FAQ.</div>
56
+ </div>
57
+ </div>
58
+ </section>
59
+
60
+ <section style="display: grid; grid-template-columns: 860px minmax(0, 1fr); gap: 32px">
61
+ <div style="display: flex; flex-direction: column; gap: 8px">
62
+ <span style="{{s.label}}">2 · Which pin? Hover a pin to see its neighbours</span>
63
+ <div style="{{s.scene}} height: 420px">
64
+ <svg width="860" height="420" viewBox="0 0 860 420" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round">
65
+ <circle cx="425" cy="192" r="285" style="stroke: rgba(75,188,255,0.25); stroke-width: 1.5; stroke-dasharray: 3 6"></circle>
66
+ <path d="{{tether.a}}" style="stroke: #4BBCFF; stroke-width: 1.5; stroke-dasharray: 2 5"></path>
67
+ <path d="{{tether.b}}" style="stroke: #4BBCFF; stroke-width: 1.5; stroke-dasharray: 2 5"></path>
68
+ <path d="{{tether.c}}" style="stroke: #4BBCFF; stroke-width: 1.5; stroke-dasharray: 2 5"></path>
69
+ </svg>
70
+ <span style="position: absolute; left: 640px; top: 392px; font-size: 11px; color: rgba(75,188,255,0.7)">600 px from Release runbook</span>
71
+ <sc-for list="{{hover}}" as="n" hint-placeholder-count="6">
72
+ <div style="{{n.box}}">
73
+ <div style="{{n.head}}"><svg width="14" height="14" viewBox="0 0 24 24" style="{{s.kind}}"><path d="{{i.note}}"></path></svg><span style="{{s.title}}">{{n.title}}</span>
74
+ <sc-if value="{{n.near}}" hint-placeholder-val="{{ false }}"><span style="{{n.chipStyle}}"><svg width="11" height="11" viewBox="0 0 24 24" style="{{s.ring}}"><circle cx="12" cy="12" r="8"></circle><circle cx="12" cy="12" r="2.4" style="fill: currentColor; stroke: none"></circle></svg>{{n.nearText}}</span></sc-if>
75
+ <span style="{{s.expand}}"><svg width="12" height="12" viewBox="0 0 24 24" style="{{s.ic}}"><path d="{{i.expand}}"></path></svg></span>
76
+ <span style="{{n.pinStyle}}"><svg width="9" height="9" viewBox="0 0 24 24" style="{{s.ic2}}"><path d="{{i.pin}}"></path></svg></span>
77
+ </div>
78
+ <div style="padding: 7px 10px; font-size: 11px; color: #8ea3bd">{{n.meta}}</div>
79
+ </div>
80
+ </sc-for>
81
+ <sc-for list="{{nums}}" as="m" hint-placeholder-count="3"><span style="position: absolute; left: {{m.x}}px; top: {{m.y}}px; width: 20px; height: 20px; border-radius: 999px; background: #081524; border: 1px dotted #4BBCFF; color: #4BBCFF; font-size: 11px; font-weight: 600; text-align: center; line-height: 18px">{{m.n}}</span></sc-for>
82
+ </div>
83
+ <span style="font-size: 12px; color: #8ea3bd">Dotted tethers, numbered nearest first, and the 600 px radius while the pin is hovered or selected. Tethers are drawn in screen space, so they still join a pin and its neighbours at fit zoom. Other nodes are untouched.</span>
84
+ </div>
85
+
86
+ <div style="display: flex; flex-direction: column; gap: 12px">
87
+ <span style="{{s.label}}">Hover a near chip</span>
88
+ <div style="padding: 12px 14px; border-radius: 10px; border: 1px solid #2a4566; background: #13243b; box-shadow: 0 10px 30px rgba(0,0,0,0.55); display: flex; flex-direction: column; gap: 6px">
89
+ <span style="font-size: 12px; font-weight: 600">Near 2 pins</span>
90
+ <div style="display: flex; justify-content: space-between; font-size: 12px"><span>Release runbook</span><span style="font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: #8ea3bd">240 px</span></div>
91
+ <div style="display: flex; justify-content: space-between; font-size: 12px"><span>Readability floor</span><span style="font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: #8ea3bd">410 px</span></div>
92
+ <span style="font-size: 11px; color: #b9c6d6">The agent gets this node's title and a short summary, not its full content.</span>
93
+ <div style="display: flex; gap: 6px"><button style="height: 26px; padding: 0 10px; border: 0; border-radius: 6px; background: #4BBCFF; color: #081524; font-family: inherit; font-size: 11px; font-weight: 600">Pin to send content</button><button style="height: 26px; padding: 0 10px; border-radius: 6px; border: 1px solid #2a4566; background: transparent; color: #e6eef7; font-family: inherit; font-size: 11px">Show pins</button></div>
94
+ </div>
95
+ <span style="{{s.label}}">The context chip</span>
96
+ <div style="padding: 12px; border-radius: 12px; border: 1px solid #2a4566; background: #13243b; display: flex; flex-direction: column; gap: 6px">
97
+ <div style="display: flex; align-items: center; justify-content: space-between"><span style="font-size: 12px; font-weight: 600">In the agent's context</span><span style="font-size: 11px; color: #8ea3bd">2 cards · 3 near</span></div>
98
+ <span style="font-size: 11px; color: #8ea3bd">Pinned · full content</span>
99
+ <span style="font-size: 12px">Release runbook · Readability floor</span>
100
+ <span style="font-size: 11px; color: #8ea3bd">Near your pins · title and summary</span>
101
+ <span style="font-size: 12px; color: #b9c6d6">Price page copy · Churn deep-dive · Pricing notes</span>
102
+ </div>
103
+ </div>
104
+ </section>
105
+
106
+ <section style="display: flex; flex-direction: column; gap: 10px">
107
+ <span style="{{s.label}}">3 · The moment it changes</span>
108
+ <div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px">
109
+ <sc-for list="{{moments}}" as="mo" hint-placeholder-count="3">
110
+ <div style="display: flex; flex-direction: column; gap: 8px">
111
+ <div style="{{s.scene}} height: 190px">
112
+ <sc-if value="{{mo.ring}}" hint-placeholder-val="{{ false }}"><svg width="420" height="190" viewBox="0 0 420 190" style="position: absolute; left: 0; top: 0; fill: none"><circle cx="110" cy="95" r="150" style="stroke: rgba(75,188,255,0.35); stroke-width: 1.5; stroke-dasharray: 3 6"></circle></svg></sc-if>
113
+ <div style="{{s.pinnedBox}} left: 20px; top: 60px"><div style="{{s.pinnedHead}}"><span style="{{s.title}}">Release runbook</span><span style="{{s.pinOn}}"><svg width="9" height="9" viewBox="0 0 24 24" style="{{s.ic2}}"><path d="{{i.pin}}"></path></svg></span></div></div>
114
+ <div style="{{mo.box}}"><div style="{{s.plainHead}}"><span style="{{s.title}}">Price page copy</span><sc-if value="{{mo.chip}}" hint-placeholder-val="{{ false }}"><span style="{{mo.chipStyle}}"><svg width="11" height="11" viewBox="0 0 24 24" style="{{s.ring}}"><circle cx="12" cy="12" r="8"></circle><circle cx="12" cy="12" r="2.4" style="fill: currentColor; stroke: none"></circle></svg>near</span></sc-if></div></div>
115
+ </div>
116
+ <span style="font-size: 12px; font-weight: 600">{{mo.t}}</span>
117
+ <span style="font-size: 12px; color: #8ea3bd">{{mo.d}}</span>
118
+ <div style="display: flex; align-items: center; gap: 8px; padding: 7px 10px; border-radius: 8px; border: 1px solid #1b2c44; background: #0f1d31; font-size: 11px; color: #b9c6d6"><span style="width: 6px; height: 6px; border-radius: 999px; background: #4BBCFF; flex-shrink: 0"></span>{{mo.update}}</div>
119
+ </div>
120
+ </sc-for>
121
+ </div>
122
+ </section>
123
+
124
+ <section style="display: grid; grid-template-columns: minmax(0, 1fr) 640px; gap: 32px">
125
+ <div style="display: flex; flex-direction: column; gap: 10px">
126
+ <span style="{{s.label}}">4 · It survives the other states</span>
127
+ <div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px">
128
+ <sc-for list="{{combos}}" as="cb" hint-placeholder-count="6">
129
+ <div style="display: flex; flex-direction: column; gap: 6px">
130
+ <div style="position: relative; height: 104px; border-radius: 8px; background: #06111e">
131
+ <div style="{{cb.box}}">
132
+ <sc-if value="{{cb.bar}}" hint-placeholder-val="{{ false }}"><div style="position: absolute; left: 0; right: 0; top: 0; height: 2.5px; background: #B388FF"></div></sc-if>
133
+ <div style="{{cb.head}}"><span style="{{s.title}}">Price page copy</span>
134
+ <sc-if value="{{cb.near}}" hint-placeholder-val="{{ false }}"><span style="{{s.chip}}"><svg width="11" height="11" viewBox="0 0 24 24" style="{{s.ring}}"><circle cx="12" cy="12" r="8"></circle><circle cx="12" cy="12" r="2.4" style="fill: currentColor; stroke: none"></circle></svg>{{cb.nearText}}</span></sc-if>
135
+ <span style="{{cb.pinStyle}}"><svg width="9" height="9" viewBox="0 0 24 24" style="{{s.ic2}}"><path d="{{i.pin}}"></path></svg></span>
136
+ </div>
137
+ <div style="padding: 6px 10px; font-size: 11px; color: #8ea3bd">copy draft · v3</div>
138
+ </div>
139
+ <sc-if value="{{cb.handles}}" hint-placeholder-val="{{ false }}"><span style="{{s.h}} left: 7px; top: 7px"></span><span style="{{s.h}} right: 7px; top: 7px"></span><span style="{{s.h}} left: 7px; bottom: 7px"></span><span style="{{s.h}} right: 7px; bottom: 7px"></span></sc-if>
140
+ </div>
141
+ <span style="font-size: 12px; font-weight: 600">{{cb.t}}</span>
142
+ <span style="font-size: 11px; color: #8ea3bd">{{cb.d}}</span>
143
+ </div>
144
+ </sc-for>
145
+ </div>
146
+ </div>
147
+
148
+ <div style="display: flex; flex-direction: column; gap: 10px">
149
+ <span style="{{s.label}}">At 600 px — the narrow end</span>
150
+ <div style="position: relative; width: 600px; height: 360px; border-radius: 12px; border: 1px solid #2a4566; overflow: hidden; background-color: #081524; background-image: radial-gradient(rgba(142,163,189,0.14) 1px, transparent 1.2px); background-size: 24px 24px">
151
+ <svg width="600" height="360" viewBox="0 0 600 360" style="position: absolute; left: 0; top: 0; fill: none; stroke-linecap: round"><path d="M 300 108 L 160 196" style="stroke: #4BBCFF; stroke-width: 1.5; stroke-dasharray: 2 5"></path><path d="M 300 108 L 440 196" style="stroke: #4BBCFF; stroke-width: 1.5; stroke-dasharray: 2 5"></path></svg>
152
+ <div style="{{s.pinnedBox}} left: 190px; top: 24px; width: 220px"><div style="{{s.pinnedHead}}"><span style="{{s.title}}">Release runbook</span><span style="{{s.expand}}"><svg width="12" height="12" viewBox="0 0 24 24" style="{{s.ic}}"><path d="{{i.expand}}"></path></svg></span><span style="{{s.pinOn}}"><svg width="9" height="9" viewBox="0 0 24 24" style="{{s.ic2}}"><path d="{{i.pin}}"></path></svg></span></div><div style="padding: 7px 10px; font-size: 11px; color: #8ea3bd">pinned · hovered</div></div>
153
+ <div style="{{s.plainBox}} left: 24px; top: 196px; width: 270px"><div style="{{s.plainHead}}"><span style="{{s.title}}">Price page copy draft for Pro</span><span style="{{s.chip}}"><svg width="11" height="11" viewBox="0 0 24 24" style="{{s.ring}}"><circle cx="12" cy="12" r="8"></circle><circle cx="12" cy="12" r="2.4" style="fill: currentColor; stroke: none"></circle></svg>near</span><span style="{{s.pinOff}}"><svg width="9" height="9" viewBox="0 0 24 24" style="{{s.ic2}}"><path d="{{i.pin}}"></path></svg></span></div><div style="padding: 7px 10px; font-size: 11px; color: #8ea3bd">The title truncates first; the chip keeps its word.</div></div>
154
+ <div style="{{s.plainBox}} left: 306px; top: 196px; width: 270px"><div style="{{s.plainHead}}"><span style="{{s.title}}">Pricing notes</span><span style="{{s.chip}}"><svg width="11" height="11" viewBox="0 0 24 24" style="{{s.ring}}"><circle cx="12" cy="12" r="8"></circle><circle cx="12" cy="12" r="2.4" style="fill: currentColor; stroke: none"></circle></svg>near 2</span><span style="{{s.pinOff}}"><svg width="9" height="9" viewBox="0 0 24 24" style="{{s.ic2}}"><path d="{{i.pin}}"></path></svg></span></div><div style="padding: 7px 10px; font-size: 11px; color: #8ea3bd">near 2 pins</div></div>
155
+ <span style="position: absolute; left: 24px; bottom: 14px; display: flex; align-items: center; gap: 6px; height: 28px; padding: 0 12px; border-radius: 999px; border: 1px solid rgba(75,188,255,0.3); background: #0f1d31; color: #4BBCFF; font-size: 12px; font-weight: 500">2 in context · 3 near</span>
156
+ </div>
157
+ </div>
158
+ </section>
159
+
160
+ </div>
161
+ </x-dc>
162
+ <script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":1440,"height":2020}}'>
163
+ class Component extends DCLogic {
164
+ renderVals() {
165
+ var i = {
166
+ note: 'M6 5h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2zM8 10h8M8 14h5',
167
+ pin: 'M9 4h6l-.8 5.5 2.8 3H7l2.8-3zM12 12.5V20',
168
+ expand: 'M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7'
169
+ };
170
+ var pinOn = 'width:18px;height:18px;border-radius:999px;display:flex;align-items:center;justify-content:center;flex-shrink:0;background:#4BBCFF;color:#081524;';
171
+ var pinOff = 'width:18px;height:18px;box-sizing:border-box;border-radius:999px;display:flex;align-items:center;justify-content:center;flex-shrink:0;border:1.5px solid #6b7d94;color:#b9c6d6;';
172
+ var chip = 'display:flex;align-items:center;gap:4px;height:18px;padding:0 7px;border-radius:999px;border:1px dotted #4BBCFF;color:#7fcfff;font-size:11px;font-weight:500;flex-shrink:0;white-space:nowrap;';
173
+ var chipLit = chip + 'background:rgba(75,188,255,0.12);';
174
+ var chipPulse = chip + 'background:rgba(75,188,255,0.18);box-shadow:0 0 0 4px rgba(75,188,255,0.12);';
175
+ var chipFade = chip + 'opacity:0.35;';
176
+ var e1 = '0 1px 2px rgba(0,0,0,0.4),0 6px 20px rgba(0,0,0,0.24)';
177
+ var boxBase = 'position:absolute;box-sizing:border-box;overflow:hidden;border-radius:10px;background:#0f1d31;box-shadow:' + e1 + ';';
178
+ var headBase = 'display:flex;align-items:center;gap:6px;height:34px;padding:0 8px 0 10px;border-bottom:1px solid #1b2c44;';
179
+ var s = {
180
+ label: 'font-size:11px;font-weight:500;letter-spacing:0.06em;text-transform:uppercase;color:#6b7d94;',
181
+ scene: 'position:relative;border-radius:10px;border:1px solid #1b2c44;overflow:hidden;background-color:#081524;background-image:radial-gradient(rgba(142,163,189,0.14) 1px, transparent 1.2px);background-size:24px 24px;',
182
+ card: 'display:flex;flex-direction:column;padding:14px 16px;border-radius:10px;border:1px solid #1b2c44;background:#0b1828;',
183
+ kind: 'flex-shrink:0;color:#8ea3bd;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;',
184
+ title: 'flex:1;min-width:0;font-size:12px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;',
185
+ ring: 'flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-dasharray:2.2 2.6;',
186
+ ic: 'fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;',
187
+ ic2: 'fill:none;stroke:currentColor;stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round;',
188
+ expand: 'width:20px;height:20px;display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#b9c6d6;',
189
+ chip: chip, pinOn: pinOn, pinOff: pinOff,
190
+ pinnedBox: boxBase + 'width:180px;border:1.5px solid #4BBCFF;',
191
+ pinnedHead: headBase + 'background:rgba(75,188,255,0.10);',
192
+ plainBox: boxBase + 'border:1px solid #1b2c44;',
193
+ plainHead: headBase,
194
+ h: 'position:absolute;width:8px;height:8px;box-sizing:border-box;border-radius:2px;background:#0f1d31;border:1.5px solid #4BBCFF;'
195
+ };
196
+ function node(x, y, title, meta, kind, nearText, chipStyle) {
197
+ var pinned = kind === 'pin';
198
+ return {
199
+ title: title, meta: meta, near: !!nearText, nearText: nearText || '', chipStyle: chipStyle || chip,
200
+ box: boxBase + 'left:' + x + 'px;top:' + y + 'px;width:250px;height:84px;border:' + (pinned ? '1.5px solid #4BBCFF' : '1px solid #1b2c44') + ';',
201
+ head: headBase + (pinned ? 'background:rgba(75,188,255,0.10);' : ''),
202
+ pinStyle: pinned ? pinOn : pinOff
203
+ };
204
+ }
205
+ var rest = [
206
+ node(300, 150, 'Release runbook', 'pinned', 'pin'),
207
+ node(30, 40, 'Price page copy', 'near Release runbook', '', 'near'),
208
+ node(580, 40, 'Churn deep-dive', 'near Release runbook', '', 'near'),
209
+ node(40, 290, 'Pricing notes', 'near both pins', '', 'near 2'),
210
+ node(330, 300, 'Readability floor', 'pinned', 'pin'),
211
+ node(590, 300, 'Q3 risks', 'more than 600 px away', '')
212
+ ];
213
+ var hover = [
214
+ node(300, 150, 'Release runbook', 'pinned · hovered', 'pin'),
215
+ node(30, 40, 'Price page copy', 'near · 1st', '', 'near', chipLit),
216
+ node(580, 40, 'Churn deep-dive', 'near · 3rd', '', 'near', chipLit),
217
+ node(40, 290, 'Pricing notes', 'near · 2nd', '', 'near 2', chipLit),
218
+ node(330, 300, 'Readability floor', 'pinned', 'pin'),
219
+ node(590, 300, 'Q3 risks', 'not near', '')
220
+ ];
221
+ var tether = { a: 'M 425 192 L 155 124', b: 'M 425 192 L 705 124', c: 'M 425 192 L 165 290' };
222
+ var nums = [{ n: '1', x: 120, y: 128 }, { n: '3', x: 700, y: 128 }, { n: '2', x: 170, y: 262 }];
223
+ var compare = [
224
+ { k: 'Near', v: 'dotted chip in the header; the border does not change' },
225
+ { k: 'Pinned', v: 'solid 1.5 px border, tinted header, filled badge' },
226
+ { k: 'Selected', v: 'a ring with a gap outside the node, plus handles' },
227
+ { k: 'Agent editing', v: 'violet bar across the top' }
228
+ ];
229
+ var moments = [
230
+ { t: 'Dragging toward a pin', d: 'The nearest pin shows its 600 px radius while you drag; the chip previews “near” once the centre is inside.', ring: true, chip: true, chipStyle: chip + 'opacity:0.6;', update: 'Release runbook · 600 px',
231
+ box: boxBase + 'border:1px solid #1b2c44;left:220px;top:110px;width:180px;' },
232
+ { t: 'Dropped inside', d: 'The chip pulses once. One Updates entry names the node and the pin — no generic toast.', ring: false, chip: true, chipStyle: chipPulse, update: '“Price page copy” is now near “Release runbook” — the agent gets its title and summary.',
233
+ box: boxBase + 'border:1px solid #1b2c44;left:220px;top:110px;width:180px;' },
234
+ { t: 'Moved out', d: 'The chip fades out; the entry says the agent no longer sees it.', ring: false, chip: true, chipStyle: chipFade, update: '“Price page copy” left “Release runbook” — it is out of the agent’s brief.',
235
+ box: boxBase + 'border:1px solid #1b2c44;left:236px;top:18px;width:170px;' }
236
+ ];
237
+ function combo(t, d, opts) {
238
+ var sel = !!opts.sel, pinned = !!opts.pinned;
239
+ var shadow = sel ? '0 0 0 3px #06111e, 0 0 0 5px #4BBCFF, ' + e1 : e1;
240
+ return {
241
+ t: t, d: d, near: !!opts.near, nearText: opts.nearText || 'near', bar: !!opts.bar, handles: sel,
242
+ box: 'position:absolute;left:14px;top:14px;right:14px;bottom:14px;box-sizing:border-box;overflow:hidden;border-radius:10px;background:#0f1d31;box-shadow:' + shadow + ';border:' + (pinned ? '1.5px solid #4BBCFF' : '1px solid #1b2c44') + ';',
243
+ head: 'display:flex;align-items:center;gap:6px;height:32px;padding:0 8px 0 10px;border-bottom:1px solid #1b2c44;' + (pinned ? 'background:rgba(75,188,255,0.10);' : ''),
244
+ pinStyle: pinned ? pinOn : pinOff
245
+ };
246
+ }
247
+ var combos = [
248
+ combo('Near', 'The chip only.', { near: true }),
249
+ combo('Near + selected', 'The chip inside, the gap ring outside.', { near: true, sel: true }),
250
+ combo('Near + agent editing', 'The violet bar on top, the chip in the header.', { near: true, bar: true }),
251
+ combo('Near two pins', 'The count; hover lists both pins.', { near: true, nearText: 'near 2' }),
252
+ combo('Pinned', 'Never “near”: only unpinned nodes are neighbours. Pin it and the chip goes.', { pinned: true }),
253
+ combo('Pinned + agent editing', 'Pin styling and the violet bar; no chip.', { pinned: true, bar: true })
254
+ ];
255
+ return { s: s, i: i, rest: rest, hover: hover, tether: tether, nums: nums, compare: compare, moments: moments, combos: combos };
256
+ }
257
+ }
258
+ </script>
259
+ </body>
260
+ </html>