@1agh/maude 0.39.1 → 0.41.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 (137) hide show
  1. package/README.md +1 -1
  2. package/apps/studio/ai-banner.tsx +2 -2
  3. package/apps/studio/annotations-context-toolbar.tsx +44 -1
  4. package/apps/studio/annotations-layer.tsx +306 -5
  5. package/apps/studio/annotations-model.ts +107 -6
  6. package/apps/studio/api.ts +1316 -67
  7. package/apps/studio/artboard-marquee.tsx +1 -1
  8. package/apps/studio/bin/_canvas-rects-playwright.mjs +55 -0
  9. package/apps/studio/bin/_canvas-rects-static.mjs +166 -0
  10. package/apps/studio/bin/_fetch-asset.mjs +556 -0
  11. package/apps/studio/bin/_html-playwright.mjs +9 -1
  12. package/apps/studio/bin/_pdf-playwright.mjs +8 -1
  13. package/apps/studio/bin/_png-playwright.mjs +8 -1
  14. package/apps/studio/bin/_pw-launch.mjs +54 -0
  15. package/apps/studio/bin/_svg-playwright.mjs +8 -1
  16. package/apps/studio/bin/_video-playwright.mjs +452 -0
  17. package/apps/studio/bin/annotate.mjs +576 -34
  18. package/apps/studio/bin/canvas-rects.sh +152 -0
  19. package/apps/studio/bin/fetch-asset.sh +34 -0
  20. package/apps/studio/bin/prep.sh +8 -1
  21. package/apps/studio/bin/read-annotations.mjs +138 -7
  22. package/apps/studio/bin/smoke.sh +42 -6
  23. package/apps/studio/build.ts +21 -0
  24. package/apps/studio/canvas-comment-mount.tsx +138 -4
  25. package/apps/studio/canvas-edit.ts +2625 -111
  26. package/apps/studio/canvas-lib.tsx +238 -2
  27. package/apps/studio/canvas-list-watch.ts +6 -2
  28. package/apps/studio/canvas-shell.tsx +514 -20
  29. package/apps/studio/client/app.jsx +2480 -52
  30. package/apps/studio/client/comments-overlay.css +130 -126
  31. package/apps/studio/client/github.js +15 -0
  32. package/apps/studio/client/panels/TimelinePanel.jsx +860 -0
  33. package/apps/studio/client/panels/timeline-parse.js +229 -0
  34. package/apps/studio/client/panels/timeline-snap.js +55 -0
  35. package/apps/studio/client/styles/3-shell-maude.css +155 -0
  36. package/apps/studio/comments-overlay.tsx +148 -41
  37. package/apps/studio/config.schema.json +14 -0
  38. package/apps/studio/context-menu.tsx +16 -6
  39. package/apps/studio/context.ts +113 -1
  40. package/apps/studio/contextual-toolbar.tsx +262 -4
  41. package/apps/studio/cursors-overlay.tsx +4 -4
  42. package/apps/studio/dist/client.bundle.js +89 -17
  43. package/apps/studio/dist/comment-mount.js +59 -1
  44. package/apps/studio/dist/runtime/.min-sizes.json +11 -1
  45. package/apps/studio/dist/runtime/@remotion_media.js +491 -0
  46. package/apps/studio/dist/runtime/@remotion_player.js +56 -0
  47. package/apps/studio/dist/runtime/@remotion_transitions.js +300 -0
  48. package/apps/studio/dist/runtime/@remotion_transitions_clock-wipe.js +1 -0
  49. package/apps/studio/dist/runtime/@remotion_transitions_fade.js +1 -0
  50. package/apps/studio/dist/runtime/@remotion_transitions_flip.js +1 -0
  51. package/apps/studio/dist/runtime/@remotion_transitions_none.js +1 -0
  52. package/apps/studio/dist/runtime/@remotion_transitions_slide.js +1 -0
  53. package/apps/studio/dist/runtime/@remotion_transitions_wipe.js +1 -0
  54. package/apps/studio/dist/runtime/REMOTION-LICENSE.md +28 -0
  55. package/apps/studio/dist/runtime/remotion.js +42 -0
  56. package/apps/studio/dist/styles.css +1 -1
  57. package/apps/studio/dom-selection.ts +127 -1
  58. package/apps/studio/drag-state.ts +24 -0
  59. package/apps/studio/equal-spacing-detector.ts +205 -0
  60. package/apps/studio/export-dialog.tsx +1 -1
  61. package/apps/studio/exporters/_browser-bundles.ts +117 -0
  62. package/apps/studio/exporters/_runtime.ts +69 -0
  63. package/apps/studio/exporters/html.ts +4 -3
  64. package/apps/studio/exporters/index.ts +28 -2
  65. package/apps/studio/exporters/pdf.ts +4 -3
  66. package/apps/studio/exporters/png.ts +5 -3
  67. package/apps/studio/exporters/pptx.ts +6 -4
  68. package/apps/studio/exporters/svg.ts +9 -5
  69. package/apps/studio/exporters/video-encode-lib.ts +200 -0
  70. package/apps/studio/exporters/video-render-lib.ts +108 -0
  71. package/apps/studio/exporters/video.ts +184 -0
  72. package/apps/studio/history.ts +47 -1
  73. package/apps/studio/http.ts +758 -27
  74. package/apps/studio/input-router.tsx +19 -1
  75. package/apps/studio/marquee-overlay.tsx +1 -1
  76. package/apps/studio/measure-overlay.tsx +241 -0
  77. package/apps/studio/participants-chrome.tsx +3 -3
  78. package/apps/studio/runtime-bundle.ts +30 -0
  79. package/apps/studio/server.ts +34 -9
  80. package/apps/studio/sizing-mode.ts +117 -0
  81. package/apps/studio/spacing-handles.ts +166 -0
  82. package/apps/studio/test/annotate-write.test.ts +890 -0
  83. package/apps/studio/test/annotations-roundtrip.test.ts +47 -0
  84. package/apps/studio/test/camera-reveal.test.tsx +173 -0
  85. package/apps/studio/test/canvas-create-api.test.ts +76 -0
  86. package/apps/studio/test/canvas-edit.test.ts +140 -0
  87. package/apps/studio/test/canvas-list-watch.test.ts +49 -0
  88. package/apps/studio/test/canvas-media-drop.test.ts +30 -1
  89. package/apps/studio/test/canvas-origin-gate.test.ts +54 -0
  90. package/apps/studio/test/canvas-rects.test.ts +198 -0
  91. package/apps/studio/test/clip-addressing.test.ts +732 -0
  92. package/apps/studio/test/comments-overlay.test.ts +117 -0
  93. package/apps/studio/test/config-reload.test.ts +230 -0
  94. package/apps/studio/test/dns-rebinding-guard.test.ts +74 -0
  95. package/apps/studio/test/dom-selection.test.ts +130 -0
  96. package/apps/studio/test/edit-css-occurrence.test.ts +81 -0
  97. package/apps/studio/test/edit-persistence.test.ts +91 -0
  98. package/apps/studio/test/edit-scope-api.test.ts +115 -0
  99. package/apps/studio/test/element-resize.test.ts +136 -0
  100. package/apps/studio/test/element-structural-api.test.ts +360 -0
  101. package/apps/studio/test/element-structural-edit.test.ts +233 -0
  102. package/apps/studio/test/equal-spacing-detector.test.ts +165 -1
  103. package/apps/studio/test/exporters/runtime.test.ts +59 -0
  104. package/apps/studio/test/file-lock.test.ts +84 -0
  105. package/apps/studio/test/fixtures/video-comp-fixture.tsx +82 -0
  106. package/apps/studio/test/history-rollback.test.ts +26 -0
  107. package/apps/studio/test/knob-props-authored.test.ts +87 -0
  108. package/apps/studio/test/read-annotations.test.ts +154 -0
  109. package/apps/studio/test/sizing-mode.test.ts +102 -0
  110. package/apps/studio/test/spacing-handles.test.ts +138 -0
  111. package/apps/studio/test/specimen-select.test.ts +88 -0
  112. package/apps/studio/test/timeline-parse.test.ts +127 -0
  113. package/apps/studio/test/timeline-snap.test.ts +85 -0
  114. package/apps/studio/test/tool-palette-insert-anchor.test.ts +84 -0
  115. package/apps/studio/test/undo-sequence-byte-compare.test.ts +211 -0
  116. package/apps/studio/test/video-asset.test.ts +163 -0
  117. package/apps/studio/test/video-comp-fixture.test.ts +50 -0
  118. package/apps/studio/test/video-comp.test.ts +168 -0
  119. package/apps/studio/test/video-render-bridge.test.ts +149 -0
  120. package/apps/studio/tool-palette.tsx +122 -2
  121. package/apps/studio/undo-hud.tsx +2 -2
  122. package/apps/studio/use-annotation-resize.tsx +6 -3
  123. package/apps/studio/use-canvas-media-drop.tsx +66 -4
  124. package/apps/studio/use-element-resize.tsx +732 -0
  125. package/apps/studio/use-keyboard-discipline.tsx +205 -15
  126. package/apps/studio/use-selection-set.tsx +14 -0
  127. package/apps/studio/use-spacing-handles.tsx +388 -0
  128. package/apps/studio/video-comp.tsx +444 -0
  129. package/apps/studio/whats-new.json +55 -0
  130. package/apps/studio/ws.ts +5 -0
  131. package/cli/commands/design.mjs +6 -1
  132. package/cli/commands/design.test.mjs +49 -1
  133. package/cli/lib/fetch-asset.test.mjs +213 -0
  134. package/package.json +8 -8
  135. package/plugins/design/dependencies.json +10 -2
  136. package/plugins/design/templates/_shell.html +25 -2
  137. package/plugins/design/templates/design-system-inspiration/_MAPPING.md +1 -1
@@ -4,9 +4,14 @@
4
4
  * world plane scales the entire layer (pins + composer + thread popover)
5
5
  * uniformly with the artboards.
6
6
  *
7
- * DS-token only. No raw hex literals, no glow shadows, no rounded > 4px, no
8
- * gradients. The design-system-guard subagent enforces this on PR keep edits
9
- * inside the token vocabulary.
7
+ * Maude-chrome tokens ONLY (`--maude-chrome-*` / `--maude-hud-*`, defined by
8
+ * canvas-shell.tsx's HUD_TOKENS_CSS) never the project DS's own `--bg-*` /
9
+ * `--fg-*` / `--accent*` names. This overlay is studio chrome, not canvas
10
+ * content: it must look identical across every project regardless of which
11
+ * design system is loaded, the same discipline already applied to the
12
+ * toolbar/halos/context-menu/export-dialog. Reusing the DS's own token names
13
+ * here was the bug — the composer/pins/thread re-skinned themselves to match
14
+ * whatever palette the open canvas happened to declare.
10
15
  */
11
16
 
12
17
  .cm-layer {
@@ -28,41 +33,41 @@
28
33
  height: 24px;
29
34
  padding: 0;
30
35
  margin: 0;
31
- background: var(--accent, #6f63ef);
32
- color: var(--accent-fg, #faf6ef);
33
- border: 1.5px solid var(--bg-0, #14131a);
34
- border-radius: var(--radius-sm, 5px) var(--radius-sm, 5px) var(--radius-sm, 5px) 2px;
35
- box-shadow: var(--shadow-md, 0 4px 14px rgba(0,0,0,0.3));
36
- font: 600 var(--type-xs, 11px) / 1 var(--font-mono, ui-monospace, monospace);
37
- letter-spacing: var(--tracking-wide, 0.04em);
36
+ background: var(--maude-hud-accent, #6f63ef);
37
+ color: var(--maude-hud-accent-fg, #faf6ef);
38
+ border: 1.5px solid var(--maude-chrome-bg-0, #14131a);
39
+ border-radius: 5px 5px 5px 2px;
40
+ box-shadow: 0 4px 14px var(--maude-chrome-shadow, rgba(0,0,0,0.3));
41
+ font: 600 11px / 1 var(--maude-chrome-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
42
+ letter-spacing: 0.04em;
38
43
  display: grid;
39
44
  place-items: center;
40
45
  cursor: pointer;
41
46
  pointer-events: auto;
42
47
  user-select: none;
43
- transition: background var(--dur-flip, 120ms) var(--ease-out, ease-out);
48
+ transition: background 120ms ease-out;
44
49
  will-change: transform;
45
50
  }
46
51
 
47
52
  .cm-pin:hover,
48
53
  .cm-pin[aria-expanded='true'] {
49
- background: var(--accent-hover, color-mix(in oklab, var(--accent, #d63b1f) 90%, white));
54
+ background: var(--maude-hud-accent-hover, color-mix(in oklab, var(--maude-hud-accent, #d63b1f) 90%, white));
50
55
  }
51
56
 
52
57
  .cm-pin:focus-visible {
53
58
  outline: none;
54
- box-shadow: var(--shadow-focus, 0 0 0 2px var(--accent, #d63b1f));
59
+ box-shadow: 0 0 0 2px var(--maude-hud-accent, #d63b1f);
55
60
  }
56
61
 
57
62
  .cm-pin[data-resolved='true'] {
58
- background: var(--bg-3, #1c1916);
59
- color: var(--fg-2, #6e6660);
63
+ background: var(--maude-chrome-bg-2, #1c1916);
64
+ color: var(--maude-chrome-fg-1, #6e6660);
60
65
  opacity: 0.6;
61
66
  }
62
67
 
63
68
  .cm-pin[data-focused='true'] {
64
69
  /* Subtle ring — DS hard-edges discipline: no glow, just a hairline outline. */
65
- outline: 1px solid var(--fg-0, #2a2520);
70
+ outline: 1px solid var(--maude-chrome-fg-0, #2a2520);
66
71
  outline-offset: 1px;
67
72
  }
68
73
 
@@ -70,34 +75,34 @@
70
75
  .cm-composer {
71
76
  position: absolute;
72
77
  width: 300px;
73
- background: var(--bg-1, #faf6ef);
74
- border: 1px solid var(--border-default, #3a352f);
75
- border-radius: var(--radius-sm, 2px);
76
- padding: var(--space-4, 12px);
77
- box-shadow: var(--shadow-md, 0 4px 14px rgba(0,0,0,0.22));
78
- font: var(--type-sm, 13px) / var(--lh-base, 1.5) var(--font-body, system-ui, sans-serif);
79
- color: var(--fg-0, #2a2520);
78
+ background: var(--maude-chrome-bg-1, #faf6ef);
79
+ border: 1px solid var(--maude-chrome-border, #3a352f);
80
+ border-radius: 2px;
81
+ padding: 12px;
82
+ box-shadow: 0 4px 14px var(--maude-chrome-shadow, rgba(0,0,0,0.22));
83
+ font: 13px / 1.5 system-ui, sans-serif;
84
+ color: var(--maude-chrome-fg-0, #2a2520);
80
85
  pointer-events: auto;
81
86
  z-index: 4;
82
87
  }
83
88
 
84
89
  .cm-composer__head {
85
- font-size: var(--type-xs, 11px);
86
- color: var(--fg-2, #6e6660);
87
- letter-spacing: var(--tracking-eyebrow, 0.08em);
90
+ font-size: 11px;
91
+ color: var(--maude-chrome-fg-1, #6e6660);
92
+ letter-spacing: 0.08em;
88
93
  text-transform: uppercase;
89
- margin: 0 0 var(--space-2, 4px) 0;
94
+ margin: 0 0 4px 0;
90
95
  display: flex;
91
96
  align-items: center;
92
- gap: var(--space-2, 4px);
97
+ gap: 4px;
93
98
  }
94
99
 
95
100
  .cm-composer__selector {
96
- color: var(--fg-1, #4a4540);
97
- background: var(--mono-cell-bg, color-mix(in oklab, var(--bg-1, #faf6ef) 80%, var(--accent, #d63b1f) 6%));
98
- padding: 0 var(--space-2, 4px);
99
- border: 1px solid var(--mono-rule, var(--border-subtle, #c8bfb4));
100
- font-size: var(--type-xs, 11px);
101
+ color: var(--maude-chrome-fg-0, #4a4540);
102
+ background: color-mix(in oklab, var(--maude-chrome-bg-1, #faf6ef) 80%, var(--maude-hud-accent, #d63b1f) 6%);
103
+ padding: 0 4px;
104
+ border: 1px solid var(--maude-chrome-border, #c8bfb4);
105
+ font-size: 11px;
101
106
  letter-spacing: 0;
102
107
  text-transform: none;
103
108
  }
@@ -106,53 +111,53 @@
106
111
  width: 100%;
107
112
  min-height: 72px;
108
113
  resize: vertical;
109
- background: var(--bg-0, #ffffff);
110
- color: var(--fg-0, #2a2520);
111
- border: 1px solid var(--border-default, #3a352f);
112
- border-radius: var(--radius-sm, 5px);
113
- padding: var(--space-3, 8px);
114
+ background: var(--maude-chrome-bg-0, #ffffff);
115
+ color: var(--maude-chrome-fg-0, #2a2520);
116
+ border: 1px solid var(--maude-chrome-border, #3a352f);
117
+ border-radius: 5px;
118
+ padding: 8px;
114
119
  font: inherit;
115
120
  box-sizing: border-box;
116
121
  }
117
122
 
118
123
  .cm-composer__textarea:focus-visible {
119
124
  outline: none;
120
- border-color: var(--accent, #d63b1f);
121
- box-shadow: var(--shadow-focus, 0 0 0 2px var(--accent, #d63b1f));
125
+ border-color: var(--maude-hud-accent, #d63b1f);
126
+ box-shadow: 0 0 0 2px var(--maude-hud-accent, #d63b1f);
122
127
  }
123
128
 
124
129
  .cm-composer__actions {
125
130
  display: flex;
126
- gap: var(--space-2, 4px);
131
+ gap: 4px;
127
132
  justify-content: flex-end;
128
- margin-top: var(--space-3, 8px);
133
+ margin-top: 8px;
129
134
  }
130
135
 
131
136
  .cm-btn {
132
- font: 500 var(--type-xs, 11px) / 1.4 var(--font-mono, ui-monospace, monospace);
133
- letter-spacing: var(--tracking-eyebrow, 0.08em);
137
+ font: 500 11px / 1.4 var(--maude-chrome-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
138
+ letter-spacing: 0.08em;
134
139
  text-transform: uppercase;
135
- padding: var(--space-2, 4px) var(--space-3, 8px);
136
- border: 1px solid var(--border-default, #3a352f);
137
- border-radius: var(--radius-sm, 5px);
140
+ padding: 4px 8px;
141
+ border: 1px solid var(--maude-chrome-border, #3a352f);
142
+ border-radius: 5px;
138
143
  cursor: pointer;
139
144
  background: transparent;
140
- color: var(--fg-0, #2a2520);
141
- transition: background var(--dur-flip, 120ms) var(--ease-out, ease-out);
145
+ color: var(--maude-chrome-fg-0, #2a2520);
146
+ transition: background 120ms ease-out;
142
147
  }
143
148
 
144
149
  .cm-btn:hover {
145
- background: var(--bg-2, color-mix(in oklab, var(--bg-1, #faf6ef) 80%, var(--fg-0, #2a2520) 6%));
150
+ background: var(--maude-chrome-bg-2, color-mix(in oklab, var(--maude-chrome-bg-1, #faf6ef) 80%, var(--maude-chrome-fg-0, #2a2520) 6%));
146
151
  }
147
152
 
148
153
  .cm-btn--primary {
149
- background: var(--accent, #d63b1f);
150
- color: var(--accent-fg, #faf6ef);
151
- border-color: var(--accent, #d63b1f);
154
+ background: var(--maude-hud-accent, #d63b1f);
155
+ color: var(--maude-hud-accent-fg, #faf6ef);
156
+ border-color: var(--maude-hud-accent, #d63b1f);
152
157
  }
153
158
 
154
159
  .cm-btn--primary:hover {
155
- background: var(--accent-hover, color-mix(in oklab, var(--accent, #d63b1f) 90%, white));
160
+ background: var(--maude-hud-accent-hover, color-mix(in oklab, var(--maude-hud-accent, #d63b1f) 90%, white));
156
161
  }
157
162
 
158
163
  .cm-btn:disabled {
@@ -162,7 +167,7 @@
162
167
 
163
168
  .cm-btn:focus-visible {
164
169
  outline: none;
165
- box-shadow: var(--shadow-focus, 0 0 0 2px var(--accent, #d63b1f));
170
+ box-shadow: 0 0 0 2px var(--maude-hud-accent, #d63b1f);
166
171
  }
167
172
 
168
173
  /* ─── Thread popover ──────────────────────────────────────────────────────── */
@@ -171,13 +176,13 @@
171
176
  width: 340px;
172
177
  max-height: 60vh;
173
178
  overflow: auto;
174
- background: var(--bg-2, color-mix(in oklab, var(--bg-1, #faf6ef) 80%, var(--fg-0, #2a2520) 6%));
175
- border: 1px solid var(--border-default, #3a352f);
176
- border-radius: var(--radius-sm, 2px);
177
- padding: var(--space-4, 12px);
178
- box-shadow: var(--shadow-md, 0 4px 14px rgba(0,0,0,0.22));
179
- font: var(--type-sm, 13px) / var(--lh-base, 1.5) var(--font-body, system-ui, sans-serif);
180
- color: var(--fg-0, #2a2520);
179
+ background: var(--maude-chrome-bg-2, color-mix(in oklab, var(--maude-chrome-bg-1, #faf6ef) 80%, var(--maude-chrome-fg-0, #2a2520) 6%));
180
+ border: 1px solid var(--maude-chrome-border, #3a352f);
181
+ border-radius: 2px;
182
+ padding: 12px;
183
+ box-shadow: 0 4px 14px var(--maude-chrome-shadow, rgba(0,0,0,0.22));
184
+ font: 13px / 1.5 system-ui, sans-serif;
185
+ color: var(--maude-chrome-fg-0, #2a2520);
181
186
  pointer-events: auto;
182
187
  z-index: 5;
183
188
  }
@@ -185,16 +190,16 @@
185
190
  .cm-thread__head {
186
191
  display: flex;
187
192
  flex-direction: column;
188
- gap: var(--space-2, 4px);
189
- padding-bottom: var(--space-3, 8px);
190
- border-bottom: 1px solid var(--border-default, #3a352f);
193
+ gap: 4px;
194
+ padding-bottom: 8px;
195
+ border-bottom: 1px solid var(--maude-chrome-border, #3a352f);
191
196
  }
192
197
 
193
198
  .cm-thread__head-row {
194
199
  display: flex;
195
200
  justify-content: flex-start;
196
201
  align-items: center;
197
- gap: var(--space-2, 4px);
202
+ gap: 4px;
198
203
  }
199
204
 
200
205
  /* Plan C P18 — pin/sequence badge in the thread popover header. */
@@ -205,51 +210,50 @@
205
210
  width: 18px;
206
211
  height: 18px;
207
212
  border-radius: 4px;
208
- background: var(--accent, #d63b1f);
209
- color: var(--accent-fg, #fff);
210
- font: 600 var(--type-xs, 11px) / 1 var(--font-mono, ui-monospace, monospace);
213
+ background: var(--maude-hud-accent, #d63b1f);
214
+ color: var(--maude-hud-accent-fg, #fff);
215
+ font: 600 11px / 1 var(--maude-chrome-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
211
216
  }
212
217
 
213
218
  .cm-thread__close {
214
219
  background: transparent;
215
- color: var(--fg-2, #6e6660);
216
- border: 1px solid var(--border-default, #3a352f);
217
- border-radius: var(--radius-sm, 5px);
218
- padding: 0 var(--space-2, 4px);
219
- font: 600 var(--type-xs, 11px) / 1.2 var(--font-mono, ui-monospace, monospace);
220
+ color: var(--maude-chrome-fg-1, #6e6660);
221
+ border: 1px solid var(--maude-chrome-border, #3a352f);
222
+ padding: 0 4px;
223
+ font: 600 11px / 1.2 var(--maude-chrome-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
220
224
  cursor: pointer;
221
225
  align-self: flex-start;
222
226
  margin-left: auto;
223
- transition: background var(--dur-flip, 120ms) var(--ease-out, ease-out);
227
+ transition: background 120ms ease-out;
224
228
  }
225
229
 
226
230
  .cm-thread__close:hover {
227
- background: var(--bg-3, #1c1916);
228
- color: var(--fg-0, #2a2520);
231
+ background: color-mix(in oklab, var(--maude-chrome-fg-0, #1c1917) 8%, transparent);
232
+ color: var(--maude-chrome-fg-0, #2a2520);
229
233
  }
230
234
 
231
235
  .cm-thread__close:focus-visible {
232
236
  outline: none;
233
- box-shadow: var(--shadow-focus, 0 0 0 2px var(--accent, #d63b1f));
237
+ box-shadow: 0 0 0 2px var(--maude-hud-accent, #d63b1f);
234
238
  }
235
239
 
236
240
  .cm-thread__author {
237
- color: var(--fg-0, #2a2520);
241
+ color: var(--maude-chrome-fg-0, #2a2520);
238
242
  font-weight: 600;
239
243
  }
240
244
 
241
245
  .cm-thread__time {
242
- color: var(--fg-2, #6e6660);
243
- font-size: var(--type-xs, 11px);
246
+ color: var(--maude-chrome-fg-1, #6e6660);
247
+ font-size: 11px;
244
248
  }
245
249
 
246
250
  .cm-thread__selector {
247
251
  display: inline-block;
248
- color: var(--fg-2, #6e6660);
249
- font-size: var(--type-xs, 11px);
250
- border: 1px solid var(--mono-rule, var(--border-subtle, #c8bfb4));
251
- padding: 0 var(--space-2, 4px);
252
- background: var(--mono-cell-bg, color-mix(in oklab, var(--bg-1, #faf6ef) 80%, var(--accent, #d63b1f) 6%));
252
+ color: var(--maude-chrome-fg-1, #6e6660);
253
+ font-size: 11px;
254
+ border: 1px solid var(--maude-chrome-border, #c8bfb4);
255
+ padding: 0 4px;
256
+ background: color-mix(in oklab, var(--maude-chrome-bg-1, #faf6ef) 80%, var(--maude-hud-accent, #d63b1f) 6%);
253
257
  align-self: flex-start;
254
258
  max-width: 100%;
255
259
  overflow: hidden;
@@ -258,7 +262,7 @@
258
262
  }
259
263
 
260
264
  .cm-thread__body {
261
- padding: var(--space-3, 8px) 0;
265
+ padding: 8px 0;
262
266
  white-space: pre-wrap;
263
267
  word-break: break-word;
264
268
  }
@@ -266,30 +270,30 @@
266
270
  .cm-thread__body strong,
267
271
  .cm-thread__reply-body strong {
268
272
  /* @mention tokens — bold, accent color. Inserted by `renderBodyWithMentions`. */
269
- color: var(--accent, #d63b1f);
273
+ color: var(--maude-hud-accent, #d63b1f);
270
274
  font-weight: 600;
271
275
  }
272
276
 
273
277
  .cm-thread__reply {
274
- padding: var(--space-3, 8px) 0;
275
- border-top: 1px solid var(--border-subtle, #c8bfb4);
278
+ padding: 8px 0;
279
+ border-top: 1px solid var(--maude-chrome-border, #c8bfb4);
276
280
  }
277
281
 
278
282
  .cm-thread__reply-head {
279
283
  display: flex;
280
284
  align-items: baseline;
281
- gap: var(--space-2, 4px);
282
- margin-bottom: var(--space-2, 4px);
285
+ gap: 4px;
286
+ margin-bottom: 4px;
283
287
  }
284
288
 
285
289
  .cm-thread__reply-author {
286
- color: var(--fg-1, #4a4540);
290
+ color: var(--maude-chrome-fg-0, #4a4540);
287
291
  font-weight: 600;
288
292
  }
289
293
 
290
294
  .cm-thread__reply-time {
291
- color: var(--fg-3, var(--fg-2, #6e6660));
292
- font-size: var(--type-xs, 11px);
295
+ color: var(--maude-chrome-fg-1, #6e6660);
296
+ font-size: 11px;
293
297
  }
294
298
 
295
299
  .cm-thread__reply-body {
@@ -298,68 +302,68 @@
298
302
  }
299
303
 
300
304
  .cm-thread__reply-form {
301
- padding-top: var(--space-3, 8px);
302
- border-top: 1px solid var(--border-default, #3a352f);
305
+ padding-top: 8px;
306
+ border-top: 1px solid var(--maude-chrome-border, #3a352f);
303
307
  display: flex;
304
308
  flex-direction: column;
305
- gap: var(--space-2, 4px);
309
+ gap: 4px;
306
310
  }
307
311
 
308
312
  .cm-thread__reply-textarea {
309
313
  width: 100%;
310
314
  min-height: 56px;
311
315
  resize: vertical;
312
- background: var(--bg-0, #ffffff);
313
- color: var(--fg-0, #2a2520);
314
- border: 1px solid var(--border-default, #3a352f);
315
- border-radius: var(--radius-sm, 5px);
316
- padding: var(--space-3, 8px);
316
+ background: var(--maude-chrome-bg-0, #ffffff);
317
+ color: var(--maude-chrome-fg-0, #2a2520);
318
+ border: 1px solid var(--maude-chrome-border, #3a352f);
319
+ border-radius: 5px;
320
+ padding: 8px;
317
321
  font: inherit;
318
322
  box-sizing: border-box;
319
323
  }
320
324
 
321
325
  .cm-thread__reply-textarea:focus-visible {
322
326
  outline: none;
323
- border-color: var(--accent, #d63b1f);
324
- box-shadow: var(--shadow-focus, 0 0 0 2px var(--accent, #d63b1f));
327
+ border-color: var(--maude-hud-accent, #d63b1f);
328
+ box-shadow: 0 0 0 2px var(--maude-hud-accent, #d63b1f);
325
329
  }
326
330
 
327
331
  .cm-thread__reply-actions {
328
332
  display: flex;
329
333
  justify-content: flex-end;
330
- gap: var(--space-2, 4px);
334
+ gap: 4px;
331
335
  }
332
336
 
333
337
  .cm-thread__actions {
334
338
  display: flex;
335
- gap: var(--space-2, 4px);
336
- padding-top: var(--space-3, 8px);
337
- margin-top: var(--space-3, 8px);
338
- border-top: 1px solid var(--border-default, #3a352f);
339
+ gap: 4px;
340
+ padding-top: 8px;
341
+ margin-top: 8px;
342
+ border-top: 1px solid var(--maude-chrome-border, #3a352f);
339
343
  }
340
344
 
341
345
  .cm-thread__actions .cm-btn--danger {
342
346
  margin-left: auto;
343
- color: var(--status-error, #c0392b);
344
- border-color: var(--status-error, #c0392b);
347
+ color: #c0392b;
348
+ border-color: #c0392b;
345
349
  }
346
350
 
347
351
  .cm-thread__actions .cm-btn--danger:hover {
348
- background: color-mix(in oklab, var(--status-error, #c0392b) 12%, transparent);
352
+ background: color-mix(in oklab, #c0392b 12%, transparent);
349
353
  }
350
354
 
351
355
  /* ─── @mention autocomplete ──────────────────────────────────────────────── */
352
356
  .cm-mention-popup {
353
357
  position: absolute;
354
- background: var(--bg-2, color-mix(in oklab, var(--bg-1, #faf6ef) 80%, var(--fg-0, #2a2520) 6%));
355
- border: 1px solid var(--border-default, #3a352f);
356
- border-radius: var(--radius-sm, 5px);
357
- font: var(--type-xs, 11px) / var(--lh-xs, 1.3) var(--font-mono, ui-monospace, monospace);
358
- color: var(--fg-0, #2a2520);
358
+ background: var(--maude-chrome-bg-2, color-mix(in oklab, var(--maude-chrome-bg-1, #faf6ef) 80%, var(--maude-chrome-fg-0, #2a2520) 6%));
359
+ border: 1px solid var(--maude-chrome-border, #3a352f);
360
+ border-radius: 5px;
361
+ font: 11px / 1.3 var(--maude-chrome-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
362
+ color: var(--maude-chrome-fg-0, #2a2520);
359
363
  max-height: 180px;
360
364
  min-width: 160px;
361
365
  overflow: auto;
362
- box-shadow: var(--shadow-md, 0 4px 14px rgba(0,0,0,0.22));
366
+ box-shadow: 0 4px 14px var(--maude-chrome-shadow, rgba(0,0,0,0.22));
363
367
  pointer-events: auto;
364
368
  z-index: 6;
365
369
  list-style: none;
@@ -368,16 +372,16 @@
368
372
  }
369
373
 
370
374
  .cm-mention-popup__item {
371
- padding: var(--space-2, 4px) var(--space-3, 8px);
375
+ padding: 4px 8px;
372
376
  cursor: pointer;
373
377
  display: flex;
374
378
  justify-content: space-between;
375
- gap: var(--space-3, 8px);
379
+ gap: 8px;
376
380
  }
377
381
 
378
382
  .cm-mention-popup__item[aria-selected='true'] {
379
- background: var(--accent, #d63b1f);
380
- color: var(--accent-fg, #faf6ef);
383
+ background: var(--maude-hud-accent, #d63b1f);
384
+ color: var(--maude-hud-accent-fg, #faf6ef);
381
385
  }
382
386
 
383
387
  .cm-mention-popup__name {
@@ -385,11 +389,11 @@
385
389
  }
386
390
 
387
391
  .cm-mention-popup__email {
388
- color: var(--fg-2, #6e6660);
389
- font-size: var(--type-xs, 11px);
392
+ color: var(--maude-chrome-fg-1, #6e6660);
393
+ font-size: 11px;
390
394
  }
391
395
 
392
396
  .cm-mention-popup__item[aria-selected='true'] .cm-mention-popup__email {
393
- color: var(--accent-fg, #faf6ef);
397
+ color: var(--maude-hud-accent-fg, #faf6ef);
394
398
  opacity: 0.85;
395
399
  }
@@ -87,6 +87,21 @@ export const appRecentProjects = () => invoke('app_recent_projects');
87
87
  export const pickDirectory = () => invoke('pick_directory');
88
88
  /** Switch the app to a local project folder (the freshly cloned copy). */
89
89
  export const openLocalProject = (path) => invoke('open_local_project', { path });
90
+ /**
91
+ * Native "Save As…" for an export — opens an OS save dialog seeded with
92
+ * `filename`, writes `bytes` (a plain number array from a Uint8Array) to the
93
+ * chosen path, and resolves to that path (or null if cancelled). Only callable in
94
+ * the native app; the browser build uses the `<a download>` blob instead.
95
+ */
96
+ export const saveExport = (filename, bytes) => invoke('save_export', { filename, bytes });
97
+
98
+ /**
99
+ * Native "open file" for media upload — the read counterpart to saveExport.
100
+ * WKWebView won't present the file panel for an HTML <input type=file>, so the
101
+ * AssetPicker uses this in the desktop app. Returns { name, bytes:[...] } or null
102
+ * (cancelled). Browser build uses the <input type=file> path instead.
103
+ */
104
+ export const pickMediaFile = () => invoke('pick_media_file');
90
105
 
91
106
  // ── Tauri shell: auto-update (Phase 32 / Task 1) ────────────────────────────────
92
107
  // The shell downloads + stages a newer build in the background and emits