@markdstage/markdstage 2.5.1 → 3.0.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.
package/README.md CHANGED
@@ -16,8 +16,8 @@ exported PDF, or hybrid editable PowerPoint deck.
16
16
  ## Install
17
17
 
18
18
  ```console
19
- npx @markdstage/markdstage presentation slides.md
20
19
  npx @markdstage/markdstage present slides.md
20
+ npx @markdstage/markdstage preview slides.md
21
21
  npm install --global @markdstage/markdstage
22
22
  ```
23
23
 
@@ -31,8 +31,8 @@ npm install --global .\markdstage-markdstage-<version>.tgz
31
31
  ## Commands
32
32
 
33
33
  ```console
34
- markdstage presentation slides.md
35
- markdstage present slides.md --watch
34
+ markdstage present slides.md
35
+ markdstage preview slides.md --watch
36
36
  markdstage validate slides.md --json
37
37
  markdstage inspect slides.md --json
38
38
  markdstage capture slides.md --pages 2,4
@@ -45,8 +45,8 @@ markdstage skill install --target claude
45
45
 
46
46
  | Command | Description |
47
47
  | --- | --- |
48
- | `presentation` | Opens the presenter view with the current slide, next-slide preview, speaker notes, and navigation. Select **Start presentation** to open the synchronized audience-facing window; select **End presentation** to close it. `--watch` reloads on save, and `--no-open` serves the presenter URL without launching a browser. |
49
- | `present` | Serves the deck on loopback and opens the MarkdStage presenter window: navigation, presenter view, next-slide preview, speaker notes, overview, custom themes, Mermaid, Architecture DSL, and local assets. `--watch` reloads on save while preserving the current slide, keeps the last valid deck when a save is broken, and enables Architecture editing. Without `--watch`, the source is read-only. `--no-open` serves the deck only. |
48
+ | `present` | Opens the presenter view with the current slide, next-slide preview, speaker notes, and navigation. Select **Start presentation** to open the synchronized audience-facing window; select **End presentation** to close it. `--watch` reloads on save, and `--no-open` serves the presenter URL without launching a browser. |
49
+ | `preview` | Serves the deck on loopback and opens the MarkdStage preview: navigation, presenter view, next-slide preview, speaker notes, overview, custom themes, Mermaid, Architecture DSL, and local assets. `--watch` reloads on save while preserving the current slide, keeps the last valid deck when a save is broken, and enables Architecture editing. Without `--watch`, the source is read-only. `--no-open` serves the deck only. |
50
50
  | `validate` | Checks deck structure, Architecture DSL blocks, themes, and theme paths. |
51
51
  | `inspect` | Reports the same compact 1280x720 clipping diagnostics as the canvas `inspect_layout` action. `--slide <n>` limits it to one page, `--all` includes slides that fit, `--fail-on-issues` exits with code 5. |
52
52
  | `capture` | Writes 1280x720 PNG files. Without `--pages` only the slides reported as clipped are captured. |
@@ -60,7 +60,7 @@ Global options: `--workspace <dir>`, `--theme <name>`, `--theme-file <path>`,
60
60
 
61
61
  ## Architecture editing
62
62
 
63
- Run `markdstage present slides.md --watch` for the live authoring workflow. The
63
+ Run `markdstage preview slides.md --watch` for the live authoring workflow. The
64
64
  browser starts in viewing mode. Select the pencil control to move Architecture
65
65
  elements; those placement changes are saved atomically to the matching
66
66
  `architecture` fence. Select **Advanced edit** to add, update, duplicate,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markdstage/markdstage",
3
- "version": "2.5.1",
3
+ "version": "3.0.0",
4
4
  "description": "Present, validate, inspect, capture, and export MarkdStage Markdown decks from the command line — no Copilot canvas required.",
5
5
  "license": "MIT",
6
6
  "author": "runceel",
package/shared/README.md CHANGED
@@ -78,11 +78,12 @@ The themed slide is displayed and updates automatically
78
78
  presenter, and PDF output.
79
79
  - The **canvas renderer** owns the compact navigation controls, shape editing,
80
80
  the slide list, and current position. **More controls > Shape editing**
81
- toggles the same placement mode as `edit_architecture`. For Markdown loaded
82
- with **More controls > Open Markdown**, **Advanced editing** opens
83
- the dedicated `architecture-editor` canvas. The agent only opens the deck and
84
- does not run an `ask_user` loop. Margin clicks are installed only in normal
85
- canvas and presenter modes, never print mode. `goto_slide` remains available
81
+ opens the dedicated `architecture-editor` canvas directly for Markdown loaded
82
+ with **More controls > Open Markdown**; slides with multiple diagrams first
83
+ show a diagram picker. Decks without a source association retain the
84
+ lightweight placement mode. The agent only opens the deck and does not run an
85
+ `ask_user` loop. Margin clicks are installed only in normal canvas and
86
+ presenter modes, never print mode. `goto_slide` remains available
86
87
  for an explicit page request from chat.
87
88
  - **PDF Export is available from More controls > Export PDF.** When
88
89
  `sourceName` is passed
@@ -206,10 +207,31 @@ When the extension detects a presentation-related prompt, it adds a short hint
206
207
  to use `markdstage_guide` at most once per session. No hint is added after the
207
208
  tool has already been called, and session-end cleanup removes the state.
208
209
 
209
- ### Slide fragment format
210
+ ### Markdown file syntax
210
211
 
211
- Each element in open / `load_deck` `slides` is one Markdown string. It may start
212
- with front matter delimited by `---`, followed by GFM-compatible content.
212
+ A Markdown file represents the complete deck. At the top level, a line containing
213
+ only `---` after a blank line separates slides. A leading `---` block is file
214
+ front matter, and `---` inside a fenced code block is not a separator.
215
+
216
+ Use only the top-level `---` syntax for slide boundaries. Custom markers such as
217
+ `<!-- slide -->` are not slide separators and must not be used.
218
+
219
+ Do not place a top-level HTML comment immediately before a slide separator. End
220
+ the comment, leave a blank line, and then write `---`; without the blank line,
221
+ the separator may not be recognized as a slide boundary.
222
+
223
+ To have MarkdStage read and split a workspace Markdown file, use **More controls >
224
+ Open Markdown**. This file-loading workflow is separate from the Canvas API.
225
+
226
+ ### Canvas API `slides` array
227
+
228
+ For canvas `open` and `load_deck`, each element of the `slides` array is exactly
229
+ one slide. The caller must read, split, or generate the deck before invoking the
230
+ Canvas API. Do not pass a complete multi-slide Markdown file as one array element
231
+ and expect its `---` lines to be split.
232
+
233
+ Each array element is one Markdown string. It may start with front matter
234
+ delimited by `---`, followed by GFM-compatible content.
213
235
 
214
236
  | Front matter | Purpose |
215
237
  | --- | --- |
@@ -244,14 +266,6 @@ First explain the **prerequisites**.
244
266
  -->
245
267
  ```
246
268
 
247
- Write local images as `![Alternative text](/assets/foo.png)` and pass the source
248
- Markdown's workspace-relative path as `sourceName`. Lookup tries adjacent
249
- `assets/` before workspace-root `assets/`. Architecture `icon` and `image.src`
250
- use `assets/foo.svg` without a leading slash and follow the same lookup order.
251
- `sourceName` supplies this resolution base only; it does not read or watch the
252
- Markdown file.
253
- Specifically, lookup checks `assets/` beside the Markdown before `assets/` at the workspace root.
254
-
255
269
  On a standard slide, the first H1/H2 is fixed in the top title area, so its
256
270
  position does not move with body length. Later headings remain in the body.
257
271
  Specialized `title`, `section`, and `backcover` layouts retain their own
@@ -286,6 +300,20 @@ layout: section
286
300
  ## Key GitHub Copilot features
287
301
  ```
288
302
 
303
+ ### `sourceName` role
304
+
305
+ `sourceName` is workspace-relative metadata used to resolve adjacent themes and
306
+ images and to derive output filenames. It does not read, parse, split, or watch
307
+ Markdown content. Passing `sourceName` does not load a deck; non-empty canvas
308
+ input must still include the complete `slides` array.
309
+
310
+ To have MarkdStage load a Markdown file, use **More controls > Open Markdown**.
311
+
312
+ Write local images as `![Alternative text](/assets/foo.png)`. With `sourceName`,
313
+ lookup tries `assets/` beside the Markdown before workspace-root `assets/`.
314
+ Architecture `icon` and `image.src` use `assets/foo.svg` without a leading slash
315
+ and follow the same lookup order.
316
+
289
317
  ### Choosing a theme
290
318
 
291
319
  Set the deck-wide `theme`; use `dark` when omitted.
@@ -374,7 +402,9 @@ When writing explicit JSON, `elements` is required by the JSON Schema.
374
402
  ````
375
403
 
376
404
  - A `node` has a unique `id`, multiline `text`, and shape `rect`,
377
- `rounded-rect`, or `ellipse`.
405
+ `rounded-rect`, `ellipse`, `diamond`, `triangle`, `hexagon`, or
406
+ `parallelogram`. These additive shape values remain Architecture DSL v1 and
407
+ export as native PowerPoint shapes.
378
408
  - `icon` is a built-in name or a path under an adjacent or workspace-root
379
409
  `assets/` folder. See [Icons](#icons).
380
410
  - An `image` places an `assets/` image as an independent element. `fit` is
@@ -407,7 +437,9 @@ When writing explicit JSON, `elements` is required by the JSON Schema.
407
437
  `opacity`, `dash`, and `cornerRadius`. Prefer theme tokens `accent`,
408
438
  `accentStrong`, `accentSoft`, `accentLine`, `surface`, `fg`, `muted`, `body`,
409
439
  `border`, and `bg`. Literal colors are limited to hex, white, black, and
410
- transparent.
440
+ transparent. Omit `dash` (or use an empty value) for a solid line, use
441
+ `"dash": "1 5"` for a dotted line, or provide another space-separated numeric
442
+ pattern such as `"10 6"` for dashed/custom output.
411
443
  - Invalid JSON, out-of-range numbers, duplicate IDs, unknown references, and
412
444
  unsupported elements, styles, or colors render an inline diagram error while
413
445
  preserving other slide content. DSL values never generate HTML, script, or
@@ -740,8 +772,8 @@ Architecture diagrams can be moved directly over the rendered result. For decks
740
772
  imported through **More controls > Open Markdown**, edits write back to the source `architecture` fence and
741
773
  survive re-import. Decks supplied directly through open / `load_deck` cannot be
742
774
  reversibly mapped to a source file, so they save only to canvas deck state.
743
- In the standalone CLI, `markdstage present slides.md --watch` enables the same
744
- source-backed editing workflow; `present` without `--watch` is read-only.
775
+ In the standalone CLI, `markdstage preview slides.md --watch` enables the same
776
+ source-backed editing workflow; `preview` without `--watch` is read-only.
745
777
 
746
778
  **Placement editing is a stable part of Architecture DSL v1.**
747
779
 
@@ -760,8 +792,8 @@ Enter mode with:
760
792
 
761
793
  | Method | Purpose |
762
794
  | --- | --- |
763
- | Canvas action `edit_architecture` with `{ "enabled": true }` | Normal agent-controlled operation |
764
- | Pencil control during CLI `present --watch` | User-controlled live authoring; the browser starts with editing off |
795
+ | Canvas action `edit_architecture` with `{ "enabled": true }` | Agent-controlled lightweight placement operation |
796
+ | **Shape editing** for a deck without a source association | User-controlled lightweight placement operation |
765
797
  | Renderer URL `?architectureEdit=1` | Local debugging |
766
798
 
767
799
  `reset` disables editing. The query parameter also updates server state through
@@ -777,7 +809,6 @@ from disabling a client-only mode or `POST /edit` returning an unexpected 409.
777
809
  | Undo | Toolbar **Undo** | Ctrl+Z |
778
810
  | Redo | Toolbar **Redo** | Ctrl+Shift+Z / Ctrl+Y |
779
811
  | Clear selection | Click outside the diagram | Escape |
780
- | Full editing | Toolbar **Advanced editing** | — |
781
812
 
782
813
  Every move redraws the complete diagram and reroutes connectors. A live status
783
814
  region announces results.
@@ -791,8 +822,21 @@ blocks.
791
822
 
792
823
  - Add, delete, duplicate, reorder, and reparent nodes, groups, images, and
793
824
  connectors.
794
- - Drag, resize, snap to grid, zoom, and pan. Scroll horizontally/vertically
795
- when the diagram exceeds the workspace, or pan with middle-drag / Space-drag.
825
+ - Add nodes from a bounded shape palette containing rectangles, ellipses,
826
+ diamonds, triangles, hexagons, and parallelograms.
827
+ - The primary toolbar keeps Undo, Redo, Shape, Save, and More visible. Secondary
828
+ add, edit, ordering, view, grid, and reload commands are grouped under
829
+ **More**.
830
+ - Drag and resize with live feedback, snap to grid, zoom, and pan. Drag blank
831
+ canvas space with the primary button to pan horizontally and vertically;
832
+ middle-drag and Space-drag remain available.
833
+ - **Elements** and **Properties** are collapsible. Medium windows use nonmodal
834
+ docks so the canvas remains selectable; narrow windows use lightweight
835
+ overlays without a blocking backdrop. Opening a panel moves keyboard focus
836
+ to its content, and each panel has a local close control.
837
+ - Empty Architecture blocks show a focused **Add first shape** action. Toolbar
838
+ additions start near the visible canvas center and move to an unoccupied
839
+ sibling position when necessary.
796
840
  - Context menus on elements, empty space, and tree items provide appropriate
797
841
  add, connect, duplicate, delete, front/back order, Undo/Redo, and Save
798
842
  commands. Group **Layout** menus offer `none`, `row`, `column`, `grid`, and
@@ -804,7 +848,7 @@ blocks.
804
848
  return with `ArrowLeft`, execute with Enter/Space, and close with Escape.
805
849
  - A typed inspector edits geometry, layout, style, icon, ports, routing,
806
850
  polyline points, canvas metadata, and other editable v1 fields.
807
- - Add a standalone **Image** from the toolbar or context menu. Node inspector
851
+ - Add a standalone **Image** from **More** or a context menu. Node inspector
808
852
  **Select image from assets/** uses the same picker. It searches
809
853
  Markdown-adjacent and workspace-root `assets/` in that order. Import SVG,
810
854
  PNG, WebP, JPG, or JPEG up to 10 MB into workspace-root `assets/`; collisions
@@ -817,8 +861,11 @@ blocks.
817
861
  - Saving reloads any MarkdStage canvas or watched CLI presentation showing the
818
862
  same Markdown while preserving the current page and theme.
819
863
 
820
- Source-backed decks imported through **More controls > Open Markdown** and CLI `present --watch` enable
821
- **Advanced editing**. Agents can open the editor canvas directly:
864
+ For a source-backed deck imported through **More controls > Open Markdown**,
865
+ **Shape editing** opens this editor directly. If the slide contains multiple
866
+ Architecture blocks, select one from the accessible picker first. CLI
867
+ `preview --watch` opens the same editor in a browser window. Agents can open
868
+ the editor canvas directly:
822
869
 
823
870
  ```json
824
871
  {
@@ -7,6 +7,8 @@
7
7
  --editor-muted:#a8b0bd;
8
8
  --editor-accent:#67a7ff;
9
9
  --editor-accent-soft:#17365d;
10
+ --editor-brand:#ffb547;
11
+ --editor-brand-soft:#4a3519;
10
12
  --editor-danger:#ff8f8f;
11
13
  --editor-grid:rgba(255,255,255,.07);
12
14
  }
@@ -19,6 +21,8 @@
19
21
  --editor-muted:#606775;
20
22
  --editor-accent:#0f6cbd;
21
23
  --editor-accent-soft:#dcecff;
24
+ --editor-brand:#8a4f00;
25
+ --editor-brand-soft:#fff0d5;
22
26
  --editor-danger:#b3261e;
23
27
  --editor-grid:rgba(0,0,0,.08);
24
28
  }
@@ -27,34 +31,83 @@ html,body{height:100%;margin:0;overflow:hidden;}
27
31
  body{display:grid;grid-template-rows:auto minmax(0,1fr) auto;
28
32
  color:var(--editor-fg);background:var(--editor-panel);font:14px/1.4 "Segoe UI",sans-serif;}
29
33
  button,input,select,textarea{font:inherit;}
30
- button{min-height:30px;padding:4px 9px;border:1px solid var(--editor-border);
34
+ button{min-height:34px;padding:5px 10px;border:1px solid var(--editor-border);
31
35
  border-radius:6px;color:var(--editor-fg);background:var(--editor-panel-2);cursor:pointer;}
32
36
  button:hover:not(:disabled){border-color:var(--editor-accent);background:var(--editor-accent-soft);}
33
37
  button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{
34
38
  outline:2px solid var(--editor-accent);outline-offset:1px;}
35
39
  button:disabled{opacity:.42;cursor:default;}
36
- .editor-header{display:flex;align-items:center;gap:16px;padding:8px 12px;
40
+ .editor-header{position:relative;z-index:4;display:flex;align-items:center;gap:16px;padding:8px 12px;
37
41
  border-bottom:1px solid var(--editor-border);background:var(--editor-panel-2);}
38
42
  .editor-title{display:flex;align-items:center;gap:8px;min-width:230px;white-space:nowrap;}
43
+ .editor-title strong{font-size:15px;letter-spacing:-.01em;}
39
44
  .editor-title #sourceLabel{max-width:28vw;overflow:hidden;text-overflow:ellipsis;color:var(--editor-muted);}
40
- .dirty-badge{padding:2px 7px;border-radius:999px;color:#fff;background:#b26a00;font-size:12px;}
41
- .editor-actions{display:flex;align-items:center;gap:6px;min-width:0;overflow-x:auto;padding-bottom:2px;}
45
+ .dirty-badge{padding:2px 7px;border-radius:999px;color:#fff;background:#8a4f00;
46
+ font-size:12px;font-weight:600;}
47
+ .editor-panel-actions{display:flex;align-items:center;gap:6px;margin-left:auto;}
48
+ .editor-panel-actions button[aria-expanded="true"]{border-color:var(--editor-accent);background:var(--editor-accent-soft);}
49
+ .editor-actions{display:flex;align-items:center;gap:6px;min-width:0;}
42
50
  .toolbar-separator{width:1px;height:24px;background:var(--editor-border);flex:0 0 auto;}
43
- .save-button{font-weight:700;color:#fff;background:#0f6cbd;border-color:#0f6cbd;}
51
+ .shape-palette-host{position:relative;}
52
+ .shape-palette{position:fixed;z-index:30;display:grid;grid-template-columns:repeat(2,minmax(118px,1fr));
53
+ gap:6px;width:min(288px,calc(100vw - 24px));max-height:min(360px,calc(100vh - 24px));
54
+ padding:8px;overflow:auto;border:1px solid var(--editor-border);border-radius:12px;
55
+ background:var(--editor-panel-2);box-shadow:0 18px 45px rgba(0,0,0,.32);}
56
+ .shape-palette[hidden]{display:none;}
57
+ .shape-palette button{display:grid;grid-template-columns:32px minmax(0,1fr);align-items:center;
58
+ gap:8px;min-height:44px;padding:6px 8px;text-align:left;}
59
+ .shape-swatch{width:24px;height:20px;justify-self:center;border:2px solid currentColor;
60
+ background:color-mix(in srgb,var(--editor-accent) 18%,transparent);}
61
+ .shape-swatch[data-shape="rounded-rect"]{border-radius:7px;}
62
+ .shape-swatch[data-shape="ellipse"]{border-radius:50%;}
63
+ .shape-swatch[data-shape="diamond"]{width:18px;height:18px;transform:rotate(45deg);}
64
+ .shape-swatch[data-shape="triangle"]{border:0;clip-path:polygon(50% 0,100% 100%,0 100%);background:currentColor;}
65
+ .shape-swatch[data-shape="hexagon"]{border:0;clip-path:polygon(25% 0,75% 0,100% 50%,75% 100%,25% 100%,0 50%);
66
+ background:currentColor;}
67
+ .shape-swatch[data-shape="parallelogram"]{border:0;clip-path:polygon(18% 0,100% 0,82% 100%,0 100%);
68
+ background:currentColor;}
69
+ .save-button{font-weight:700;color:#17120a;background:var(--editor-brand);border-color:var(--editor-brand);}
70
+ .save-button:hover:not(:disabled){color:#17120a;background:color-mix(in srgb,var(--editor-brand) 86%,white);
71
+ border-color:color-mix(in srgb,var(--editor-brand) 86%,white);}
44
72
  .snap-toggle{display:flex;align-items:center;gap:4px;white-space:nowrap;color:var(--editor-muted);}
45
- .editor-layout{display:grid;grid-template-columns:230px minmax(0,1fr) 300px;min-height:0;}
46
- .editor-sidebar{min-height:0;overflow:auto;background:var(--editor-panel-2);}
47
- .editor-sidebar h2{position:sticky;top:0;z-index:2;margin:0;padding:10px 12px;
48
- border-bottom:1px solid var(--editor-border);background:var(--editor-panel-2);font-size:13px;}
73
+ .toolbar-more-host{position:relative;}
74
+ .toolbar-more-menu{position:fixed;z-index:35;display:grid;grid-template-columns:repeat(2,minmax(132px,1fr));
75
+ gap:10px;width:min(320px,calc(100vw - 16px));max-height:min(520px,calc(100vh - 16px));
76
+ padding:10px;overflow:auto;border:1px solid var(--editor-border);border-radius:10px;
77
+ background:var(--editor-panel-2);box-shadow:0 16px 34px rgba(0,0,0,.38);}
78
+ .toolbar-more-menu[hidden]{display:none;}
79
+ .toolbar-more-group{display:flex;flex-direction:column;gap:5px;min-width:0;}
80
+ .toolbar-more-label{padding:2px 4px;color:var(--editor-muted);font-size:11px;font-weight:700;
81
+ letter-spacing:.08em;text-transform:uppercase;}
82
+ .toolbar-more-menu button{width:100%;text-align:left;}
83
+ .toolbar-more-row{display:grid;grid-template-columns:repeat(3,1fr);gap:5px;}
84
+ .toolbar-more-row button{text-align:center;}
85
+ .toolbar-more-menu>.snap-toggle{min-height:34px;padding:5px 8px;border-radius:6px;background:var(--editor-panel);}
86
+ .toolbar-more-menu>button:last-child{grid-column:1/-1;}
87
+ .editor-layout{position:relative;z-index:1;display:grid;grid-template-columns:minmax(0,1fr);
88
+ min-height:0;overflow:hidden;}
89
+ body[data-elements-open="true"] .editor-layout{grid-template-columns:210px minmax(0,1fr);}
90
+ body[data-inspector-open="true"] .editor-layout{grid-template-columns:minmax(0,1fr) 300px;}
91
+ body[data-elements-open="true"][data-inspector-open="true"] .editor-layout{
92
+ grid-template-columns:210px minmax(0,1fr) 300px;}
93
+ .editor-sidebar{display:flex;flex-direction:column;min-height:0;overflow:auto;background:var(--editor-panel-2);}
94
+ body[data-elements-open="false"] .element-panel,
95
+ body[data-inspector-open="false"] .inspector-panel{display:none;}
96
+ .editor-sidebar-head{position:sticky;top:0;z-index:2;display:flex;align-items:center;
97
+ justify-content:space-between;min-height:42px;padding:4px 6px 4px 12px;
98
+ border-bottom:1px solid var(--editor-border);background:var(--editor-panel-2);}
99
+ .editor-sidebar h2{margin:0;font-size:14px;}
100
+ .editor-panel-close{min-width:34px;padding:0;font-size:18px;line-height:1;}
49
101
  .element-panel{border-right:1px solid var(--editor-border);}
50
102
  .inspector-panel{border-left:1px solid var(--editor-border);}
51
103
  .element-tree{padding:8px 0;}
52
- .tree-item{display:flex;align-items:center;gap:7px;width:100%;min-height:30px;padding:4px 10px;
104
+ .tree-item{display:flex;align-items:center;gap:7px;width:100%;min-height:34px;padding:5px 10px;
53
105
  border:0;border-radius:0;text-align:left;background:transparent;}
54
- .tree-item[aria-selected="true"]{background:var(--editor-accent-soft);color:var(--editor-accent);}
106
+ .tree-item[aria-selected="true"]{background:var(--editor-accent-soft);color:var(--editor-fg);}
107
+ .tree-item[aria-selected="true"] .tree-icon{color:inherit;}
55
108
  .tree-icon{width:18px;text-align:center;color:var(--editor-muted);}
56
109
  .tree-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
57
- .editor-viewport{position:relative;min-width:0;min-height:0;overflow:auto;
110
+ .editor-viewport{position:relative;min-width:0;min-height:0;overflow:auto;cursor:grab;
58
111
  background-color:#101217;
59
112
  background-image:linear-gradient(var(--editor-grid) 1px,transparent 1px),
60
113
  linear-gradient(90deg,var(--editor-grid) 1px,transparent 1px);
@@ -63,20 +116,36 @@ button:disabled{opacity:.42;cursor:default;}
63
116
  background-color:#e9edf3;}
64
117
  .canvas-surface{display:flex;align-items:flex-start;justify-content:center;width:max-content;min-width:100%;min-height:100%;
65
118
  padding:48px;transform-origin:top center;}
119
+ .editor-empty-state{align-self:center;display:grid;justify-items:center;gap:10px;width:min(420px,calc(100vw - 64px));
120
+ margin:auto;padding:36px 32px;text-align:center;color:var(--editor-fg);}
121
+ .editor-empty-state h2{margin:4px 0 0;font-size:24px;letter-spacing:-.025em;}
122
+ .editor-empty-state p{max-width:34ch;margin:0;color:var(--editor-muted);font-size:15px;}
123
+ .editor-empty-state small{color:var(--editor-muted);}
124
+ .empty-state-shape{width:64px;height:48px;border:3px solid var(--editor-accent);border-radius:12px;
125
+ background:var(--editor-accent-soft);box-shadow:8px 8px 0 color-mix(in srgb,var(--editor-brand) 72%,transparent);}
66
126
  .canvas-surface>.architecture-diagram{flex:0 0 auto;width:960px;margin:0;padding:18px;
67
127
  border:1px solid var(--editor-border);border-radius:10px;background:var(--surface);
68
128
  box-shadow:0 12px 36px rgba(0,0,0,.3);}
69
129
  .canvas-surface .architecture-svg{width:100%;max-height:none;overflow:visible;touch-action:none;}
70
130
  .canvas-surface [data-editor-ref]{cursor:pointer;outline:none;}
71
131
  .canvas-surface [data-editor-ref][data-editor-movable="true"]{cursor:grab;}
132
+ .editor-viewport.is-panning{cursor:grabbing;user-select:none;}
133
+ .editor-viewport.is-dragging [data-editor-ref]{pointer-events:none;}
134
+ .canvas-surface [data-editor-ref],.canvas-surface .editor-resize-handle{will-change:transform;}
135
+ .canvas-surface .editor-drag-target{filter:drop-shadow(0 12px 16px rgba(0,0,0,.28));opacity:.92;}
136
+ .canvas-surface .editor-settle{animation:editor-settle 150ms ease-out;transform-box:fill-box;
137
+ transform-origin:center;}
138
+ @keyframes editor-settle{from{opacity:.9;transform:scale(.985);}to{opacity:1;transform:scale(1);}}
72
139
  .canvas-surface [data-editor-selected="true"]>rect,
73
- .canvas-surface [data-editor-selected="true"]>ellipse{
74
- stroke:var(--editor-accent);stroke-width:7;filter:drop-shadow(0 0 7px var(--editor-accent));}
140
+ .canvas-surface [data-editor-selected="true"]>ellipse,
141
+ .canvas-surface [data-editor-selected="true"]>polygon{
142
+ stroke:var(--editor-accent);stroke-width:5;filter:drop-shadow(0 0 4px var(--editor-accent));}
75
143
  .canvas-surface [data-architecture-type="connector"][data-editor-selected="true"] path{
76
- stroke:var(--editor-accent);stroke-width:8;}
144
+ stroke:var(--editor-accent);stroke-width:6;}
77
145
  .editor-resize-handle{fill:var(--surface);stroke:var(--editor-accent);stroke-width:4;cursor:nwse-resize;}
78
146
  .editor-resize-handle[data-corner="ne"],.editor-resize-handle[data-corner="sw"]{cursor:nesw-resize;}
79
- .connector-source>rect,.connector-source>ellipse{stroke:#f9c74f!important;stroke-width:8!important;}
147
+ .connector-source>rect,.connector-source>ellipse,.connector-source>polygon{
148
+ stroke:#f9c74f!important;stroke-width:8!important;}
80
149
  .inspector{display:flex;flex-direction:column;gap:10px;padding:12px;}
81
150
  .inspector-section{display:grid;grid-template-columns:minmax(88px,1fr) minmax(0,1.35fr);
82
151
  gap:7px 10px;padding-bottom:11px;border-bottom:1px solid var(--editor-border);}
@@ -146,10 +215,37 @@ button:disabled{opacity:.42;cursor:default;}
146
215
  .asset-dialog-footer>span{min-width:0;color:var(--editor-muted);font-size:12px;}
147
216
  .asset-dialog-footer>span[data-kind="error"]{color:var(--editor-danger);font-weight:600;}
148
217
  .asset-dialog-footer>div{display:flex;gap:8px;}
149
- @media(max-width:900px){
150
- .editor-layout{grid-template-columns:180px minmax(0,1fr);}
151
- .inspector-panel{position:absolute;right:0;top:52px;bottom:28px;width:280px;z-index:5;
152
- box-shadow:-10px 0 24px rgba(0,0,0,.25);}
218
+ @media(max-width:1100px){
219
+ .editor-header{flex-wrap:wrap;gap:8px 12px;}
220
+ .editor-title{min-width:0;flex:1 1 260px;}
221
+ .editor-title #sourceLabel{max-width:min(48vw,420px);}
222
+ .editor-actions{margin-inline-start:auto;}
153
223
  .asset-dialog-body{grid-template-columns:minmax(0,1fr);}
154
224
  .asset-preview{display:none;}
155
225
  }
226
+ @media(max-width:620px){
227
+ .editor-header{gap:8px;padding:8px;}
228
+ .editor-title{flex-basis:100%;order:1;}
229
+ .editor-title #sourceLabel{max-width:32vw;}
230
+ .editor-panel-actions{order:2;margin:0;}
231
+ .editor-actions{order:3;margin-inline-start:auto;}
232
+ .editor-actions button,.editor-panel-actions button{min-height:40px;padding-inline:10px;}
233
+ .editor-layout{grid-template-columns:minmax(0,1fr)!important;}
234
+ .editor-sidebar{position:absolute;inset-block:0;z-index:12;width:min(340px,88vw);
235
+ visibility:hidden;box-shadow:0 16px 34px rgba(0,0,0,.34);
236
+ transition:transform 160ms ease-out,visibility 160ms;}
237
+ .element-panel{inset-inline-start:0;transform:translateX(-105%);}
238
+ .inspector-panel{inset-inline-end:0;transform:translateX(105%);}
239
+ body[data-elements-open="true"] .element-panel,
240
+ body[data-inspector-open="true"] .inspector-panel{display:flex;transform:translateX(0);visibility:visible;}
241
+ .shape-palette{grid-template-columns:1fr;width:min(220px,calc(100vw - 16px));}
242
+ .toolbar-more-menu{grid-template-columns:1fr;width:min(260px,calc(100vw - 16px));}
243
+ .toolbar-more-menu>button:last-child{grid-column:auto;}
244
+ }
245
+ @media(pointer:coarse){
246
+ button,.tree-item,.toolbar-more-menu>.snap-toggle{min-height:44px;}
247
+ }
248
+ @media(prefers-reduced-motion:reduce){
249
+ .editor-sidebar{transition:none;}
250
+ .canvas-surface .editor-settle{animation:none;}
251
+ }