@bendyline/squisq-editor-react 1.6.2 → 2.0.1

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 (218) hide show
  1. package/README.md +12 -3
  2. package/dist/index.d.ts +1275 -183
  3. package/dist/index.js +20345 -12777
  4. package/dist/index.js.map +1 -1
  5. package/dist/monaco.d.ts +1 -0
  6. package/dist/monaco.js +4 -0
  7. package/dist/monaco.js.map +1 -0
  8. package/dist/styles/index.css +1607 -241
  9. package/package.json +9 -5
  10. package/src/BlockPropertiesPopover.tsx +30 -15
  11. package/src/DocumentSettingsDialog.tsx +39 -33
  12. package/src/EditorContext.tsx +199 -42
  13. package/src/EditorShell.tsx +349 -261
  14. package/src/ImageEditor.tsx +22 -1
  15. package/src/InlinePreviewGutter.tsx +16 -8
  16. package/src/MediaBin.tsx +107 -14
  17. package/src/OutlinePanel.tsx +202 -7
  18. package/src/PlainHtmlPreview.tsx +40 -1
  19. package/src/PreviewControls.tsx +362 -89
  20. package/src/PreviewPanel.tsx +312 -78
  21. package/src/RawEditor.tsx +13 -2
  22. package/src/RecorderEntry.tsx +2 -0
  23. package/src/StatusBar.tsx +5 -2
  24. package/src/TemplateAnnotation.ts +12 -3
  25. package/src/TemplatePicker.tsx +75 -21
  26. package/src/ThemeCustomizerPanel.tsx +8 -0
  27. package/src/ThemePicker.tsx +10 -5
  28. package/src/TimelineBlockPreview.tsx +1 -1
  29. package/src/Toolbar.tsx +357 -51
  30. package/src/TransitionPicker.tsx +36 -4
  31. package/src/ViewMenuPanel.tsx +12 -14
  32. package/src/WysiwygEditor.tsx +124 -91
  33. package/src/__tests__/blockPropertiesPopoverTheme.test.tsx +33 -0
  34. package/src/__tests__/blockTagActivity.test.ts +183 -0
  35. package/src/__tests__/buildDocumentPreviewMarkdown.test.ts +75 -0
  36. package/src/__tests__/buildPreviewDocContent.test.ts +48 -0
  37. package/src/__tests__/buildPreviewDocTransition.test.ts +21 -1
  38. package/src/__tests__/canvasSurfaceTextEditing.test.tsx +60 -0
  39. package/src/__tests__/codeContextSectionView.test.tsx +8 -6
  40. package/src/__tests__/customLayoutManagerTheme.test.tsx +34 -0
  41. package/src/__tests__/documentSettingsDialog.test.tsx +51 -1
  42. package/src/__tests__/editorScrollHandoff.test.tsx +102 -0
  43. package/src/__tests__/editorScrollSync.test.ts +65 -0
  44. package/src/__tests__/editorShellProps.test.tsx +123 -1
  45. package/src/__tests__/emojiPicker.test.tsx +2 -42
  46. package/src/__tests__/headingTransition.test.ts +0 -12
  47. package/src/__tests__/imageEditAffordance.test.tsx +5 -1
  48. package/src/__tests__/imageEditModalContract.test.tsx +119 -0
  49. package/src/__tests__/imageEditorShell.test.tsx +15 -1
  50. package/src/__tests__/jsonEditor.test.tsx +56 -1
  51. package/src/__tests__/layersPanel.test.tsx +75 -5
  52. package/src/__tests__/majorApiTypes.test.ts +26 -0
  53. package/src/__tests__/mediaAttachmentFlow.test.ts +2 -2
  54. package/src/__tests__/mediaBinDrop.test.tsx +90 -0
  55. package/src/__tests__/narrationSave.test.ts +148 -0
  56. package/src/__tests__/outlinePanel.test.tsx +93 -3
  57. package/src/__tests__/outlineSource.test.ts +217 -0
  58. package/src/__tests__/plainHtmlPreview.test.tsx +17 -1
  59. package/src/__tests__/presentationMode.test.tsx +290 -0
  60. package/src/__tests__/previewControls.test.tsx +382 -5
  61. package/src/__tests__/previewPanelAudioFailure.test.tsx +46 -0
  62. package/src/__tests__/previewPanelPresentation.test.tsx +126 -0
  63. package/src/__tests__/previewPanelTransforms.test.tsx +117 -0
  64. package/src/__tests__/rawEditorModelIsolation.test.ts +19 -0
  65. package/src/__tests__/recorderTheme.test.tsx +42 -0
  66. package/src/__tests__/resolveBlockVisual.test.ts +43 -0
  67. package/src/__tests__/selectionConversions.test.ts +80 -0
  68. package/src/__tests__/statusBar.test.tsx +27 -0
  69. package/src/__tests__/teleprompter.test.tsx +190 -0
  70. package/src/__tests__/templateAnnotationRoundTrip.test.ts +26 -0
  71. package/src/__tests__/templatePickerPortal.test.tsx +62 -0
  72. package/src/__tests__/tiptapBridge.test.ts +71 -7
  73. package/src/__tests__/tiptapCodeBlockRoundTrip.test.ts +109 -0
  74. package/src/__tests__/tiptapImageRoundTrip.test.ts +1 -1
  75. package/src/__tests__/toolbarSelectionConversion.test.tsx +164 -0
  76. package/src/__tests__/transformStyleId.test.ts +13 -0
  77. package/src/__tests__/useImageEditor.test.tsx +67 -0
  78. package/src/__tests__/useMediaRecorder.test.ts +75 -0
  79. package/src/__tests__/viewMenuPanel.test.tsx +130 -0
  80. package/src/__tests__/wysiwygImageUpload.test.ts +69 -0
  81. package/src/__tests__/wysiwygTemplateBadgeFocus.test.tsx +56 -0
  82. package/src/asciiDiagram/AsciiDiagramExtension.ts +343 -0
  83. package/src/asciiDiagram/AsciiDiagramWidget.tsx +254 -0
  84. package/src/asciiDiagram/RepairableDiagramExtension.ts +200 -0
  85. package/src/asciiDiagram/__tests__/AsciiDiagramExtension.test.ts +145 -0
  86. package/src/asciiDiagram/__tests__/RepairableDiagramExtension.test.ts +159 -0
  87. package/src/asciiDiagram/__tests__/asciiDiagramCommands.test.ts +284 -0
  88. package/src/asciiDiagram/__tests__/asciiDiagramOps.test.ts +114 -0
  89. package/src/asciiDiagram/__tests__/asciiPaste.test.ts +43 -0
  90. package/src/asciiDiagram/asciiDiagramCommands.ts +174 -0
  91. package/src/asciiDiagram/asciiDiagramData.ts +149 -0
  92. package/src/asciiDiagram/asciiDiagramOps.ts +238 -0
  93. package/src/asciiDiagram/asciiPaste.ts +19 -0
  94. package/src/blockTagActivity.ts +233 -0
  95. package/src/buildDocumentPreviewMarkdown.ts +168 -0
  96. package/src/buildPreviewDoc.ts +19 -12
  97. package/src/codeContext/types.ts +1 -1
  98. package/src/customTemplates/CustomLayoutManager.tsx +3 -2
  99. package/src/customTemplates/CustomTemplateContext.tsx +6 -0
  100. package/src/customTemplates/TemplateDesigner.tsx +7 -4
  101. package/src/customTemplates/__tests__/library.test.ts +8 -0
  102. package/src/customTemplates/__tests__/useMemoryLayerAdapter.test.ts +13 -0
  103. package/src/customTemplates/designer.css +158 -99
  104. package/src/customTemplates/library.ts +16 -3
  105. package/src/customTemplates/useMemoryLayerAdapter.ts +7 -1
  106. package/src/customThemes/CustomThemeContext.tsx +6 -0
  107. package/src/customThemes/CustomThemeDialog.tsx +35 -5
  108. package/src/customThemes/ImportThemeSection.tsx +178 -0
  109. package/src/customThemes/__tests__/customThemeLibrary.test.ts +9 -0
  110. package/src/customThemes/__tests__/importThemeSection.test.tsx +192 -0
  111. package/src/customThemes/customThemeLibrary.ts +7 -4
  112. package/src/customThemes/index.ts +7 -1
  113. package/src/customThemes/themeDraft.ts +23 -7
  114. package/src/diagram/DiagramCanvas.tsx +25 -6
  115. package/src/diagram/types.ts +35 -0
  116. package/src/editorScrollSync.ts +73 -0
  117. package/src/emojiData.ts +3 -23
  118. package/src/frontmatterSettings.ts +23 -0
  119. package/src/headingTransition.ts +0 -15
  120. package/src/imageEditor/CanvasSurface.tsx +29 -23
  121. package/src/imageEditor/LayersPanel.tsx +78 -3
  122. package/src/imageEditor/Toolbar.tsx +5 -1
  123. package/src/imageEditor/icons.tsx +4 -0
  124. package/src/imageEditor/image-editor.css +75 -0
  125. package/src/imageEditor/layers/SelectionHandles.tsx +1 -1
  126. package/src/imageEditor/useImageEditor.ts +71 -14
  127. package/src/index.ts +198 -20
  128. package/src/jsonEditor/JsonEditorContext.tsx +12 -6
  129. package/src/jsonEditor/RenderNode.tsx +24 -3
  130. package/src/jsonEditor/editors.tsx +86 -19
  131. package/src/mediaEntries.ts +12 -0
  132. package/src/monaco.ts +35 -0
  133. package/src/monacoWorkers.ts +89 -0
  134. package/src/outlineSource.ts +171 -0
  135. package/src/presentation/PresentationMode.tsx +596 -0
  136. package/src/rawEditorIsolation.ts +18 -0
  137. package/src/recorder/RecorderButton.tsx +9 -1
  138. package/src/recorder/RecorderModal.tsx +84 -41
  139. package/src/recorder/RecorderPanel.tsx +9 -1
  140. package/src/recorder/hooks/useMediaRecorder.ts +97 -53
  141. package/src/resolveBlockVisual.ts +10 -4
  142. package/src/scene/Scene.tsx +48 -18
  143. package/src/scene/SceneBlockExtension.ts +17 -10
  144. package/src/scene/SceneBlockWidget.tsx +5 -1
  145. package/src/scene/SceneViewport.tsx +7 -3
  146. package/src/scene/ShapePalette.tsx +17 -2
  147. package/src/scene/__tests__/DiagramAdapter.test.ts +86 -0
  148. package/src/scene/__tests__/SceneBlockExtension.test.ts +33 -0
  149. package/src/scene/__tests__/sceneIsolation.test.tsx +119 -0
  150. package/src/scene/adapters/DiagramAdapter.ts +12 -101
  151. package/src/scene/adapters/DrawingAdapter.ts +6 -1
  152. package/src/scene/adapters/LayoutAdapter.ts +3 -0
  153. package/src/scene/commands/SceneCommand.ts +17 -3
  154. package/src/scene/index.ts +1 -6
  155. package/src/scene/layers/DiagramEdges.tsx +21 -7
  156. package/src/scene/layers/edgeGeometry.ts +9 -1
  157. package/src/scene/layers/nodeCard.tsx +27 -8
  158. package/src/scene/scene.css +5 -2
  159. package/src/scene/text/SceneTextOverlay.tsx +5 -5
  160. package/src/scene/text/sceneTextChannel.ts +26 -20
  161. package/src/scene/text/sceneTextConfig.ts +4 -0
  162. package/src/scene/tools/ConnectTool.ts +13 -4
  163. package/src/scene/tools/SceneTool.ts +8 -0
  164. package/src/scene/tools/SelectTool.ts +39 -23
  165. package/src/scene/tools/ShapeTool.ts +2 -3
  166. package/src/selectionConversions.ts +155 -0
  167. package/src/styles/ascii-diagram.css +79 -0
  168. package/src/styles/ascii-timeline.css +596 -0
  169. package/src/styles/editor.css +736 -120
  170. package/src/styles/index.css +3 -0
  171. package/src/styles/tree-view.css +189 -0
  172. package/src/teleprompter/TeleprompterControls.tsx +218 -0
  173. package/src/teleprompter/TeleprompterSelfView.tsx +22 -0
  174. package/src/teleprompter/TeleprompterSurface.tsx +267 -0
  175. package/src/teleprompter/TeleprompterView.tsx +338 -0
  176. package/src/teleprompter/canvasRenderer.ts +161 -0
  177. package/src/teleprompter/floatingWindow.ts +352 -0
  178. package/src/teleprompter/index.ts +61 -0
  179. package/src/teleprompter/pcmWorklet.ts +62 -0
  180. package/src/teleprompter/recording/insertPreamble.ts +80 -0
  181. package/src/teleprompter/recording/narrationSave.ts +134 -0
  182. package/src/teleprompter/recording/useNarrationRecorder.ts +367 -0
  183. package/src/teleprompter/scrollModel.ts +85 -0
  184. package/src/teleprompter/teleprompterTheme.ts +303 -0
  185. package/src/teleprompter/types.ts +38 -0
  186. package/src/teleprompter/useFloatingWindow.ts +74 -0
  187. package/src/teleprompter/useMicAnalysis.ts +211 -0
  188. package/src/teleprompter/useTeleprompter.ts +421 -0
  189. package/src/templateContentPreviewResolver.ts +12 -5
  190. package/src/timeline/TimelineEditorWidget.tsx +861 -0
  191. package/src/timeline/TimelineViewExtension.ts +252 -0
  192. package/src/timeline/__tests__/TimelineEditorWidget.test.tsx +414 -0
  193. package/src/timeline/__tests__/TimelineViewExtension.test.ts +163 -0
  194. package/src/timeline/__tests__/timelineCommands.test.ts +359 -0
  195. package/src/timeline/__tests__/timelineOps.test.ts +277 -0
  196. package/src/timeline/__tests__/timelinePaste.test.ts +34 -0
  197. package/src/timeline/timelineCommands.ts +421 -0
  198. package/src/timeline/timelineData.ts +54 -0
  199. package/src/timeline/timelineOps.ts +381 -0
  200. package/src/timeline/timelinePaste.ts +8 -0
  201. package/src/tiptapBridge.ts +47 -21
  202. package/src/transformStyleId.ts +17 -0
  203. package/src/treeview/TreeOutlineWidget.tsx +390 -0
  204. package/src/treeview/TreeViewExtension.ts +250 -0
  205. package/src/treeview/__tests__/TreeOutlineWidget.test.tsx +156 -0
  206. package/src/treeview/__tests__/TreeViewExtension.test.ts +122 -0
  207. package/src/treeview/__tests__/treeOps.test.ts +177 -0
  208. package/src/treeview/__tests__/treePaste.test.ts +40 -0
  209. package/src/treeview/__tests__/treeViewCommands.test.ts +179 -0
  210. package/src/treeview/treeOps.ts +231 -0
  211. package/src/treeview/treePaste.ts +13 -0
  212. package/src/treeview/treeViewCommands.ts +99 -0
  213. package/src/treeview/treeViewData.ts +41 -0
  214. package/src/useMonacoLoader.ts +11 -34
  215. package/src/wysiwygImageUpload.ts +113 -0
  216. package/src/diagram/DiagramExtension.ts +0 -209
  217. package/src/diagram/DiagramWidget.tsx +0 -272
  218. package/src/diagram/useDiagramData.ts +0 -126
@@ -131,6 +131,216 @@
131
131
  box-sizing: border-box;
132
132
  }
133
133
 
134
+ .squisq-toolbar-view-tab-wrap {
135
+ display: flex;
136
+ align-items: flex-end;
137
+ align-self: stretch;
138
+ }
139
+
140
+ /* The Use tab owns the primary preview-mode chooser. Keeping the arrow in the
141
+ tab cluster makes mode selection available before entering Use and frees the
142
+ preview toolbar for format/theme/output settings. */
143
+ .squisq-toolbar-use-tab {
144
+ border-bottom: 2px solid transparent;
145
+ }
146
+
147
+ .squisq-toolbar-use-tab > .squisq-toolbar-view-tab {
148
+ padding-right: 4px;
149
+ padding-bottom: 4px;
150
+ border-bottom: 0;
151
+ }
152
+
153
+ .squisq-toolbar-use-tab--active {
154
+ border-bottom-color: #2563eb;
155
+ }
156
+
157
+ .squisq-use-mode-trigger {
158
+ align-self: stretch;
159
+ display: inline-flex;
160
+ align-items: flex-end;
161
+ justify-content: center;
162
+ width: 20px;
163
+ padding: 0 6px 9px 0;
164
+ border: 0;
165
+ background: transparent;
166
+ color: #4b5563;
167
+ cursor: pointer;
168
+ box-sizing: content-box;
169
+ }
170
+
171
+ .squisq-use-mode-trigger > svg {
172
+ display: block;
173
+ transform: translateY(-1px);
174
+ }
175
+
176
+ .squisq-use-mode-trigger:hover,
177
+ .squisq-use-mode-trigger--open {
178
+ color: #111827;
179
+ }
180
+
181
+ .squisq-toolbar-use-tab--active .squisq-use-mode-trigger {
182
+ color: #1d4ed8;
183
+ }
184
+
185
+ .squisq-use-mode-menu {
186
+ position: fixed;
187
+ z-index: 120;
188
+ width: min(340px, calc(100vw - 16px));
189
+ padding: 6px;
190
+ border: 1px solid #d1d5db;
191
+ border-radius: 10px;
192
+ background: #ffffff;
193
+ box-shadow:
194
+ 0 12px 32px rgba(15, 23, 42, 0.2),
195
+ 0 2px 6px rgba(15, 23, 42, 0.08);
196
+ box-sizing: border-box;
197
+ font-family:
198
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
199
+ animation: squisq-use-mode-menu-in 0.12s ease-out;
200
+ }
201
+
202
+ .squisq-use-mode-menu-item {
203
+ display: flex;
204
+ align-items: center;
205
+ gap: 10px;
206
+ width: 100%;
207
+ min-height: 52px;
208
+ padding: 7px 9px;
209
+ border: 0;
210
+ border-radius: 7px;
211
+ background: transparent;
212
+ color: #374151;
213
+ font: inherit;
214
+ text-align: left;
215
+ cursor: pointer;
216
+ transition:
217
+ background 0.12s ease,
218
+ color 0.12s ease;
219
+ }
220
+
221
+ .squisq-use-mode-menu-item:hover,
222
+ .squisq-use-mode-menu-item:focus-visible {
223
+ outline: none;
224
+ background: #f3f4f6;
225
+ color: #111827;
226
+ }
227
+
228
+ .squisq-use-mode-menu-item--selected {
229
+ background: #eff6ff;
230
+ color: #1d4ed8;
231
+ }
232
+
233
+ .squisq-use-mode-menu-icon {
234
+ display: inline-flex;
235
+ align-items: center;
236
+ justify-content: center;
237
+ width: 32px;
238
+ height: 32px;
239
+ flex: 0 0 32px;
240
+ border-radius: 8px;
241
+ background: #f1f5f9;
242
+ color: #64748b;
243
+ font-size: 14px;
244
+ }
245
+
246
+ .squisq-use-mode-menu-item--selected .squisq-use-mode-menu-icon {
247
+ background: #dbeafe;
248
+ color: #2563eb;
249
+ }
250
+
251
+ .squisq-use-mode-menu-copy {
252
+ display: flex;
253
+ flex: 1 1 auto;
254
+ min-width: 0;
255
+ flex-direction: column;
256
+ gap: 2px;
257
+ }
258
+
259
+ .squisq-use-mode-menu-label {
260
+ color: inherit;
261
+ font-size: 12.5px;
262
+ font-weight: 650;
263
+ line-height: 1.2;
264
+ }
265
+
266
+ .squisq-use-mode-menu-summary {
267
+ overflow: hidden;
268
+ color: #6b7280;
269
+ font-size: 11.5px;
270
+ font-weight: 400;
271
+ line-height: 1.3;
272
+ text-overflow: ellipsis;
273
+ white-space: nowrap;
274
+ }
275
+
276
+ .squisq-use-mode-menu-check {
277
+ display: inline-flex;
278
+ align-items: center;
279
+ justify-content: center;
280
+ width: 16px;
281
+ flex: 0 0 16px;
282
+ color: #2563eb;
283
+ font-size: 11px;
284
+ text-align: center;
285
+ }
286
+
287
+ @keyframes squisq-use-mode-menu-in {
288
+ from {
289
+ opacity: 0;
290
+ transform: translateY(-3px) scale(0.99);
291
+ }
292
+ to {
293
+ opacity: 1;
294
+ transform: translateY(0) scale(1);
295
+ }
296
+ }
297
+
298
+ @media (prefers-reduced-motion: reduce) {
299
+ .squisq-use-mode-menu {
300
+ animation: none;
301
+ }
302
+ }
303
+
304
+ .squisq-use-mode-menu[data-theme='dark'] {
305
+ border-color: #4b5563;
306
+ background: #1f2937;
307
+ }
308
+
309
+ .squisq-use-mode-menu[data-theme='dark'] .squisq-use-mode-menu-item {
310
+ color: #d1d5db;
311
+ }
312
+
313
+ .squisq-use-mode-menu[data-theme='dark'] .squisq-use-mode-menu-item:hover,
314
+ .squisq-use-mode-menu[data-theme='dark'] .squisq-use-mode-menu-item:focus-visible {
315
+ background: #374151;
316
+ color: #f9fafb;
317
+ }
318
+
319
+ .squisq-use-mode-menu[data-theme='dark'] .squisq-use-mode-menu-item--selected {
320
+ background: #172f4f;
321
+ color: #93c5fd;
322
+ }
323
+
324
+ .squisq-use-mode-menu[data-theme='dark'] .squisq-use-mode-menu-icon {
325
+ background: #334155;
326
+ color: #cbd5e1;
327
+ }
328
+
329
+ .squisq-use-mode-menu[data-theme='dark']
330
+ .squisq-use-mode-menu-item--selected
331
+ .squisq-use-mode-menu-icon {
332
+ background: #1e4976;
333
+ color: #bfdbfe;
334
+ }
335
+
336
+ .squisq-use-mode-menu[data-theme='dark'] .squisq-use-mode-menu-summary {
337
+ color: #94a3b8;
338
+ }
339
+
340
+ .squisq-use-mode-menu[data-theme='dark'] .squisq-use-mode-menu-check {
341
+ color: #93c5fd;
342
+ }
343
+
134
344
  /* When the outline pane is visible, anchor the toolbar's view-tabs section
135
345
  * to the outline pane's width so their right-edge dividers line up
136
346
  * vertically — otherwise the view-tabs border and the outline's right edge
@@ -435,6 +645,19 @@
435
645
  z-index: 100;
436
646
  min-width: 200px;
437
647
  padding: 4px 0;
648
+ /* This menu is portaled to <body>, outside the editor shell that normally
649
+ supplies the UX font. Keep its unbuttoned content (notably the header)
650
+ on the same sans-serif UI stack instead of inheriting the host page font. */
651
+ font-family: var(
652
+ --squisq-ux-font,
653
+ -apple-system,
654
+ BlinkMacSystemFont,
655
+ 'Segoe UI',
656
+ 'Noto Sans',
657
+ Helvetica,
658
+ Arial,
659
+ sans-serif
660
+ );
438
661
  background: #fff;
439
662
  border: 1px solid #e5e7eb;
440
663
  border-radius: 6px;
@@ -451,6 +674,12 @@
451
674
  user-select: none;
452
675
  }
453
676
 
677
+ .squisq-insert-menu-header--separated {
678
+ margin-top: 4px;
679
+ padding-top: 8px;
680
+ border-top: 1px solid #e5e7eb;
681
+ }
682
+
454
683
  /* Portaled outside squisq-editor-shell, so dark mode is applied via data-theme. */
455
684
  .squisq-insert-menu[data-theme='dark'] {
456
685
  background: #1f2937;
@@ -470,6 +699,10 @@
470
699
  color: #6b7280;
471
700
  }
472
701
 
702
+ .squisq-insert-menu[data-theme='dark'] .squisq-insert-menu-header--separated {
703
+ border-top-color: #374151;
704
+ }
705
+
473
706
  /* ─── Template Picker (toolbar) ──────────────────────── */
474
707
 
475
708
  .squisq-template-picker {
@@ -1385,7 +1618,7 @@
1385
1618
  border: 0;
1386
1619
  border-radius: 0;
1387
1620
  vertical-align: baseline;
1388
- transform: translateY(2px);
1621
+ transform: translate(3px, 0);
1389
1622
  user-select: none;
1390
1623
  line-height: 1;
1391
1624
  cursor: pointer;
@@ -1499,6 +1732,26 @@
1499
1732
  display: none;
1500
1733
  }
1501
1734
 
1735
+ /* In active mode the selection and pointer classes are independent, so tags
1736
+ * can be visible on two heading-defined blocks at once. Gate both on the
1737
+ * ProseMirror focus class: the document keeps its selection after blur, but a
1738
+ * non-blinking caret should not leave that remembered block's tags behind. */
1739
+ .squisq-wysiwyg-container[data-block-tags='active'] .squisq-template-badge,
1740
+ .squisq-wysiwyg-container[data-block-tags='active'] .squisq-props-badge {
1741
+ display: none;
1742
+ }
1743
+
1744
+ .squisq-wysiwyg-container[data-block-tags='active']
1745
+ .squisq-wysiwyg-editor.ProseMirror-focused
1746
+ :is(.squisq-block-tags--selected, .squisq-block-tags--hovered)
1747
+ > .squisq-template-badge,
1748
+ .squisq-wysiwyg-container[data-block-tags='active']
1749
+ .squisq-wysiwyg-editor.ProseMirror-focused
1750
+ :is(.squisq-block-tags--selected, .squisq-block-tags--hovered)
1751
+ > .squisq-props-badge {
1752
+ display: inline-flex;
1753
+ }
1754
+
1502
1755
  /* ─── Block-properties badge (sibling of the template badge) ───────────
1503
1756
  The on-canvas entry point to the block-properties palette: a small
1504
1757
  sliders chip just after the template badge. Quiet by default like the
@@ -1521,6 +1774,7 @@
1521
1774
  border: 1px solid #d1d5db;
1522
1775
  border-radius: 10px;
1523
1776
  vertical-align: middle;
1777
+ transform: translate(3px, -2px);
1524
1778
  user-select: none;
1525
1779
  cursor: pointer;
1526
1780
  opacity: 0.5;
@@ -1532,11 +1786,12 @@
1532
1786
 
1533
1787
  /* Sliders glyph painted via CSS so the badge span stays empty in the DOM
1534
1788
  (see propsBadgeSpec — a real child could leak into serialized markdown).
1535
- `\f1de` is Font Awesome's "sliders"; the font is already loaded for the
1536
- editor's inline-icon glyph decorations. */
1789
+ `\f1de` is Font Awesome's "sliders"; use Font Awesome's own family
1790
+ variable so this follows the bundled major version instead of resolving
1791
+ against a stale hard-coded family name. */
1537
1792
  .squisq-props-badge::before {
1538
1793
  content: '\f1de';
1539
- font-family: 'Font Awesome 6 Free';
1794
+ font-family: var(--fa-family-classic, 'Font Awesome 7 Free');
1540
1795
  font-weight: 900;
1541
1796
  font-size: 10px;
1542
1797
  line-height: 1;
@@ -1546,9 +1801,9 @@
1546
1801
  it after the glyph — and reads as an active (not just affordance) chip. */
1547
1802
  .squisq-props-badge[data-props-summary] {
1548
1803
  opacity: 1;
1549
- color: #6d28d9;
1550
- background: #f5f3ff;
1551
- border-color: #c4b5fd;
1804
+ color: var(--squisq-block-props-accent, inherit);
1805
+ background: color-mix(in oklch, currentColor 12%, transparent);
1806
+ border-color: color-mix(in oklch, currentColor 35%, transparent);
1552
1807
  }
1553
1808
 
1554
1809
  .squisq-props-badge[data-props-summary]::after {
@@ -1565,13 +1820,39 @@
1565
1820
  .squisq-props-badge:hover,
1566
1821
  .squisq-props-badge:focus-visible {
1567
1822
  opacity: 1;
1568
- color: #6d28d9;
1569
- background: #ede9fe;
1570
- border-color: #c4b5fd;
1823
+ color: var(--squisq-block-props-accent, inherit);
1824
+ background: color-mix(in oklch, currentColor 16%, transparent);
1825
+ border-color: color-mix(in oklch, currentColor 42%, transparent);
1571
1826
  outline: none;
1572
1827
  }
1573
1828
 
1574
1829
  /* ─── Block-properties palette popover (portaled to <body>) ──────────── */
1830
+ :is(.squisq-block-props-popover, .squisq-transition-picker, .squisq-transition-flyout) {
1831
+ --squisq-block-props-surface: #ffffff;
1832
+ --squisq-block-props-surface-hover: #f3f4f6;
1833
+ --squisq-block-props-input: #ffffff;
1834
+ --squisq-block-props-text: #111827;
1835
+ --squisq-block-props-muted: #6b7280;
1836
+ --squisq-block-props-quiet: #9ca3af;
1837
+ --squisq-block-props-border: #d1d5db;
1838
+ --squisq-block-props-divider: #e5e7eb;
1839
+ }
1840
+
1841
+ :is(
1842
+ .squisq-block-props-popover,
1843
+ .squisq-transition-picker,
1844
+ .squisq-transition-flyout
1845
+ )[data-theme='dark'] {
1846
+ --squisq-block-props-surface: #1f2937;
1847
+ --squisq-block-props-surface-hover: #374151;
1848
+ --squisq-block-props-input: #111827;
1849
+ --squisq-block-props-text: #f9fafb;
1850
+ --squisq-block-props-muted: #d1d5db;
1851
+ --squisq-block-props-quiet: #9ca3af;
1852
+ --squisq-block-props-border: #4b5563;
1853
+ --squisq-block-props-divider: #374151;
1854
+ }
1855
+
1575
1856
  .squisq-block-props-popover {
1576
1857
  width: 280px;
1577
1858
  max-width: calc(100vw - 24px);
@@ -1579,8 +1860,9 @@
1579
1860
  display: flex;
1580
1861
  flex-direction: column;
1581
1862
  gap: 10px;
1582
- background: #fff;
1583
- border: 1px solid #e5e7eb;
1863
+ color: var(--squisq-block-props-text);
1864
+ background: var(--squisq-block-props-surface);
1865
+ border: 1px solid var(--squisq-block-props-divider);
1584
1866
  border-radius: 10px;
1585
1867
  box-shadow:
1586
1868
  0 8px 24px rgba(0, 0, 0, 0.12),
@@ -1597,7 +1879,7 @@
1597
1879
  .squisq-block-props-label {
1598
1880
  font-size: 11px;
1599
1881
  font-weight: 600;
1600
- color: #6b7280;
1882
+ color: var(--squisq-block-props-muted);
1601
1883
  flex-shrink: 0;
1602
1884
  }
1603
1885
 
@@ -1611,54 +1893,47 @@
1611
1893
  width: 72px;
1612
1894
  padding: 4px 6px;
1613
1895
  font-size: 12px;
1614
- color: #111827;
1615
- border: 1px solid #d1d5db;
1896
+ color: var(--squisq-block-props-text);
1897
+ background: var(--squisq-block-props-input);
1898
+ border: 1px solid var(--squisq-block-props-border);
1616
1899
  border-radius: 5px;
1617
1900
  outline: none;
1618
1901
  }
1619
1902
 
1620
1903
  .squisq-block-props-input:focus {
1621
- border-color: #6366f1;
1904
+ border-color: var(--squisq-block-props-accent, #6366f1);
1622
1905
  }
1623
1906
 
1624
1907
  .squisq-block-props-unit {
1625
1908
  font-size: 11px;
1626
- color: #9ca3af;
1909
+ color: var(--squisq-block-props-quiet);
1627
1910
  }
1628
1911
 
1629
1912
  /* Dark theme */
1630
- .squisq-editor-shell[data-theme='dark'] .squisq-props-badge {
1913
+ .squisq-editor-shell[data-theme='dark'] .squisq-props-badge:not([data-props-summary]) {
1631
1914
  border-color: #4b5563;
1632
1915
  color: #9ca3af;
1633
1916
  }
1634
1917
 
1635
1918
  .squisq-editor-shell[data-theme='dark'] .squisq-props-badge[data-props-summary] {
1636
- color: #ddd6fe;
1637
- background: #3730a3;
1638
- border-color: #6d5fd6;
1919
+ color: var(--squisq-block-props-accent, inherit);
1920
+ background: color-mix(in oklch, currentColor 24%, transparent);
1921
+ border-color: color-mix(in oklch, currentColor 52%, transparent);
1639
1922
  }
1640
1923
 
1641
1924
  .squisq-editor-shell[data-theme='dark'] .squisq-props-badge:hover,
1642
1925
  .squisq-editor-shell[data-theme='dark'] .squisq-props-badge:focus-visible {
1643
- color: #ede9fe;
1644
- background: #4c1d95;
1645
- border-color: #7c3aed;
1926
+ color: var(--squisq-block-props-accent, inherit);
1927
+ background: color-mix(in oklch, currentColor 28%, transparent);
1928
+ border-color: color-mix(in oklch, currentColor 58%, transparent);
1646
1929
  }
1647
1930
 
1648
- .squisq-editor-shell[data-theme='dark'] .squisq-block-props-popover {
1649
- background: #1f2937;
1650
- border-color: #374151;
1931
+ .squisq-block-props-popover[data-theme='dark'] {
1651
1932
  box-shadow:
1652
1933
  0 8px 24px rgba(0, 0, 0, 0.4),
1653
1934
  0 2px 6px rgba(0, 0, 0, 0.2);
1654
1935
  }
1655
1936
 
1656
- .squisq-editor-shell[data-theme='dark'] .squisq-block-props-input {
1657
- background: #111827;
1658
- color: #f9fafb;
1659
- border-color: #4b5563;
1660
- }
1661
-
1662
1937
  /* ─── Status Bar ─────────────────────────────────────── */
1663
1938
 
1664
1939
  .squisq-status-bar {
@@ -1771,10 +2046,14 @@
1771
2046
  }
1772
2047
  .squisq-wysiwyg-editor h2 {
1773
2048
  font-size: 1.5em;
1774
- margin: 0.65em 0 0.35em;
2049
+ margin: 0.8em 0 0.25em;
1775
2050
  }
1776
2051
  .squisq-wysiwyg-editor h3 {
1777
2052
  font-size: 1.17em;
2053
+ /* The inline template/property controls are 22–23px tall. Reserve their
2054
+ line-box height while they are hidden so active-mode hover does not make
2055
+ an H3 (and the content below it) jump by a pixel or two. */
2056
+ min-height: 26px;
1778
2057
  margin: 1.3em 0 0.3em;
1779
2058
  }
1780
2059
  .squisq-wysiwyg-editor h4 {
@@ -1800,7 +2079,7 @@
1800
2079
 
1801
2080
  .squisq-wysiwyg-editor p {
1802
2081
  margin: 0.5em 0;
1803
- line-height: 1.6;
2082
+ line-height: 1.7;
1804
2083
  }
1805
2084
 
1806
2085
  .squisq-wysiwyg-editor blockquote {
@@ -1810,6 +2089,13 @@
1810
2089
  color: var(--squisq-theme-text-muted, #6b7280);
1811
2090
  }
1812
2091
 
2092
+ /* Consecutive Markdown quote lines share one blockquote. Keep their Tiptap
2093
+ paragraphs visually line-adjacent instead of applying the normal prose
2094
+ paragraph gap between every authored `>` line. */
2095
+ .squisq-wysiwyg-editor blockquote > p {
2096
+ margin: 0;
2097
+ }
2098
+
1813
2099
  /* Inline `code` and `<pre>` blocks: the foreground / background draw from
1814
2100
  the active theme when the WYSIWYG container inherits theme colors
1815
2101
  (View menu → "Editor styling from theme: Fonts & colors"). The
@@ -1824,6 +2110,10 @@
1824
2110
  overflow-x: auto;
1825
2111
  font-size: 13px;
1826
2112
  line-height: 1.5;
2113
+ /* Explicit monospace: the container sets a themed sans body font, so
2114
+ UA defaults for <pre> are not reliable inside it. Column-aligned
2115
+ content (ASCII diagrams) depends on this. */
2116
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;
1827
2117
  }
1828
2118
 
1829
2119
  .squisq-wysiwyg-editor code {
@@ -1832,6 +2122,7 @@
1832
2122
  padding: 1px 4px;
1833
2123
  border-radius: 3px;
1834
2124
  font-size: 0.9em;
2125
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace;
1835
2126
  }
1836
2127
 
1837
2128
  .squisq-wysiwyg-editor pre code {
@@ -2163,6 +2454,54 @@
2163
2454
  cursor: pointer;
2164
2455
  }
2165
2456
 
2457
+ /* Presentation is a fixed split button after the adaptive Use controls, so
2458
+ it remains available even when individual preview settings overflow. */
2459
+ .squisq-presentation-control {
2460
+ display: inline-flex;
2461
+ align-items: center;
2462
+ flex: 0 0 auto;
2463
+ margin: 0 5px 0 3px;
2464
+ border: 1px solid var(--squisq-border, #d1d5db);
2465
+ border-radius: 5px;
2466
+ background: var(--squisq-input-bg, #fff);
2467
+ overflow: hidden;
2468
+ }
2469
+
2470
+ .squisq-presentation-control .squisq-presentation-start {
2471
+ width: 30px;
2472
+ border-radius: 0;
2473
+ }
2474
+
2475
+ .squisq-presentation-menu-trigger {
2476
+ align-self: stretch;
2477
+ display: inline-flex;
2478
+ align-items: center;
2479
+ justify-content: center;
2480
+ width: 18px;
2481
+ padding: 0;
2482
+ border: 0;
2483
+ border-left: 1px solid var(--squisq-border, #d1d5db);
2484
+ background: transparent;
2485
+ color: var(--squisq-text-muted, #6b7280);
2486
+ cursor: pointer;
2487
+ }
2488
+
2489
+ .squisq-presentation-menu-trigger:hover,
2490
+ .squisq-presentation-menu-trigger--open {
2491
+ background: rgba(107, 114, 128, 0.2);
2492
+ color: var(--squisq-text, #111827);
2493
+ }
2494
+
2495
+ .squisq-presentation-menu-item:disabled {
2496
+ cursor: not-allowed;
2497
+ opacity: 0.55;
2498
+ }
2499
+
2500
+ .squisq-presentation-menu-item:disabled:hover {
2501
+ background: transparent;
2502
+ color: inherit;
2503
+ }
2504
+
2166
2505
  /* Link color follows the active theme's primary when "Theme styling →
2167
2506
  Fonts & colors" is on, otherwise falls back to the historical blue.
2168
2507
  In both cases we blend toward the surface text color so the link
@@ -2223,6 +2562,136 @@
2223
2562
  color: #dc2626;
2224
2563
  }
2225
2564
 
2565
+ /* Bounded presentation keeps the host page intact while giving the entire
2566
+ EditorShell to the active Use surface. Browser fullscreen uses the same
2567
+ chrome suppression, then lets the Fullscreen API size the shell. */
2568
+ .squisq-editor-shell[data-presentation-mode='control'],
2569
+ .squisq-editor-shell[data-presentation-mode='fullscreen'] {
2570
+ position: relative;
2571
+ background: #000;
2572
+ }
2573
+
2574
+ .squisq-editor-shell[data-presentation-mode='control'] > .squisq-editor-header,
2575
+ .squisq-editor-shell[data-presentation-mode='fullscreen'] > .squisq-editor-header,
2576
+ .squisq-editor-shell[data-presentation-mode='control'] > .squisq-status-bar,
2577
+ .squisq-editor-shell[data-presentation-mode='fullscreen'] > .squisq-status-bar,
2578
+ .squisq-editor-shell[data-presentation-mode='control'] > .squisq-timeline,
2579
+ .squisq-editor-shell[data-presentation-mode='fullscreen'] > .squisq-timeline {
2580
+ display: none;
2581
+ }
2582
+
2583
+ .squisq-editor-shell[data-presentation-mode='control'] .squisq-media-bin,
2584
+ .squisq-editor-shell[data-presentation-mode='fullscreen'] .squisq-media-bin,
2585
+ .squisq-editor-shell[data-presentation-mode='control'] .squisq-custom-theme-pane,
2586
+ .squisq-editor-shell[data-presentation-mode='fullscreen'] .squisq-custom-theme-pane {
2587
+ display: none;
2588
+ }
2589
+
2590
+ .squisq-editor-shell[data-presentation-mode='control'] .squisq-preview-player,
2591
+ .squisq-editor-shell[data-presentation-mode='fullscreen'] .squisq-preview-player {
2592
+ padding: 0;
2593
+ background: #000;
2594
+ }
2595
+
2596
+ .squisq-editor-shell[data-presentation-mode='fullscreen']:fullscreen {
2597
+ width: 100vw !important;
2598
+ height: 100vh !important;
2599
+ min-width: 0 !important;
2600
+ min-height: 0 !important;
2601
+ max-width: none !important;
2602
+ max-height: none !important;
2603
+ }
2604
+
2605
+ .squisq-presentation-exit {
2606
+ position: absolute;
2607
+ z-index: 1001;
2608
+ top: 12px;
2609
+ right: 12px;
2610
+ display: inline-flex;
2611
+ align-items: center;
2612
+ gap: 7px;
2613
+ min-height: 34px;
2614
+ padding: 7px 11px;
2615
+ border: 1px solid rgba(255, 255, 255, 0.35);
2616
+ border-radius: 7px;
2617
+ background: rgba(15, 23, 42, 0.78);
2618
+ color: #fff;
2619
+ font: 600 12px/1 var(--squisq-ux-font, sans-serif);
2620
+ cursor: pointer;
2621
+ opacity: 0.72;
2622
+ backdrop-filter: blur(8px);
2623
+ transition:
2624
+ opacity 0.12s ease,
2625
+ background 0.12s ease;
2626
+ }
2627
+
2628
+ .squisq-presentation-exit:hover,
2629
+ .squisq-presentation-exit:focus-visible {
2630
+ outline: none;
2631
+ background: rgba(15, 23, 42, 0.94);
2632
+ opacity: 1;
2633
+ }
2634
+
2635
+ .squisq-presentation-window {
2636
+ width: 100%;
2637
+ height: 100%;
2638
+ display: flex;
2639
+ overflow: hidden;
2640
+ background: #000;
2641
+ }
2642
+
2643
+ .squisq-presentation-window-preview,
2644
+ .squisq-presentation-window-surface,
2645
+ .squisq-presentation-teleprompter {
2646
+ width: 100%;
2647
+ height: 100%;
2648
+ min-width: 0;
2649
+ min-height: 0;
2650
+ }
2651
+
2652
+ .squisq-presentation-window-preview {
2653
+ display: flex;
2654
+ }
2655
+
2656
+ .squisq-presentation-window-surface {
2657
+ padding: 0;
2658
+ background: #000;
2659
+ pointer-events: none;
2660
+ }
2661
+
2662
+ .squisq-presentation-teleprompter {
2663
+ display: flex;
2664
+ overflow: hidden;
2665
+ pointer-events: none;
2666
+ }
2667
+
2668
+ .squisq-presentation-connecting {
2669
+ color: rgba(255, 255, 255, 0.72);
2670
+ font: 500 14px/1.4 var(--squisq-ux-font, sans-serif);
2671
+ }
2672
+
2673
+ .squisq-presentation-error {
2674
+ position: fixed;
2675
+ z-index: 10000;
2676
+ top: 16px;
2677
+ left: 50%;
2678
+ max-width: min(420px, calc(100vw - 32px));
2679
+ padding: 10px 14px;
2680
+ border: 1px solid #fecaca;
2681
+ border-radius: 8px;
2682
+ background: #fff1f2;
2683
+ color: #991b1b;
2684
+ box-shadow: 0 10px 30px rgba(15, 23, 42, 0.2);
2685
+ font: 500 13px/1.4 var(--squisq-ux-font, sans-serif);
2686
+ transform: translateX(-50%);
2687
+ }
2688
+
2689
+ .squisq-presentation-error[data-theme='dark'] {
2690
+ border-color: #7f1d1d;
2691
+ background: #3f151b;
2692
+ color: #fecdd3;
2693
+ }
2694
+
2226
2695
  /* ─── CSS custom properties ──────────────────────────── */
2227
2696
 
2228
2697
  .squisq-editor-shell {
@@ -2295,6 +2764,20 @@
2295
2764
  border-bottom-color: #60a5fa;
2296
2765
  }
2297
2766
 
2767
+ .squisq-editor-shell[data-theme='dark'] .squisq-toolbar-use-tab--active {
2768
+ border-bottom-color: #60a5fa;
2769
+ }
2770
+
2771
+ .squisq-editor-shell[data-theme='dark'] .squisq-use-mode-trigger {
2772
+ color: #d1d5db;
2773
+ }
2774
+
2775
+ .squisq-editor-shell[data-theme='dark'] .squisq-use-mode-trigger:hover,
2776
+ .squisq-editor-shell[data-theme='dark'] .squisq-use-mode-trigger--open,
2777
+ .squisq-editor-shell[data-theme='dark'] .squisq-toolbar-use-tab--active .squisq-use-mode-trigger {
2778
+ color: #93c5fd;
2779
+ }
2780
+
2298
2781
  .squisq-editor-shell[data-theme='dark'] .squisq-toolbar-button {
2299
2782
  color: #d1d5db;
2300
2783
  }
@@ -2708,6 +3191,7 @@
2708
3191
  /* ─── Media Bin ──────────────────────────────────────── */
2709
3192
 
2710
3193
  .squisq-media-bin {
3194
+ position: relative;
2711
3195
  width: 220px;
2712
3196
  border-left: 1px solid #e5e7eb;
2713
3197
  background: #f9fafb;
@@ -2717,6 +3201,46 @@
2717
3201
  overflow: hidden;
2718
3202
  }
2719
3203
 
3204
+ .squisq-media-bin-drop-target {
3205
+ position: absolute;
3206
+ inset: 6px;
3207
+ z-index: 5;
3208
+ display: flex;
3209
+ flex-direction: column;
3210
+ align-items: center;
3211
+ justify-content: center;
3212
+ gap: 4px;
3213
+ border: 2px dashed #2563eb;
3214
+ border-radius: 6px;
3215
+ background: rgba(239, 246, 255, 0.96);
3216
+ color: #1d4ed8;
3217
+ font-size: 12px;
3218
+ text-align: center;
3219
+ pointer-events: none;
3220
+ }
3221
+
3222
+ .squisq-media-bin-drop-target-icon {
3223
+ display: flex;
3224
+ align-items: center;
3225
+ justify-content: center;
3226
+ width: 28px;
3227
+ height: 28px;
3228
+ border-radius: 999px;
3229
+ background: #2563eb;
3230
+ color: #fff;
3231
+ font-size: 22px;
3232
+ font-weight: 400;
3233
+ line-height: 1;
3234
+ }
3235
+
3236
+ .squisq-media-bin-drop-target strong {
3237
+ font-size: 13px;
3238
+ }
3239
+
3240
+ .squisq-media-bin-drop-target span:last-child {
3241
+ color: #64748b;
3242
+ }
3243
+
2720
3244
  .squisq-media-bin-header {
2721
3245
  display: flex;
2722
3246
  align-items: center;
@@ -2904,6 +3428,21 @@
2904
3428
  border-left-color: #374151;
2905
3429
  }
2906
3430
 
3431
+ .squisq-media-bin--dark .squisq-media-bin-drop-target,
3432
+ .squisq-editor-shell[data-theme='dark'] .squisq-media-bin .squisq-media-bin-drop-target {
3433
+ border-color: #60a5fa;
3434
+ background: rgba(15, 23, 42, 0.96);
3435
+ color: #bfdbfe;
3436
+ }
3437
+
3438
+ .squisq-media-bin--dark .squisq-media-bin-drop-target span:last-child,
3439
+ .squisq-editor-shell[data-theme='dark']
3440
+ .squisq-media-bin
3441
+ .squisq-media-bin-drop-target
3442
+ span:last-child {
3443
+ color: #94a3b8;
3444
+ }
3445
+
2907
3446
  .squisq-media-bin--dark .squisq-media-bin-header,
2908
3447
  .squisq-editor-shell[data-theme='dark'] .squisq-media-bin .squisq-media-bin-header {
2909
3448
  border-bottom-color: #374151;
@@ -3991,6 +4530,69 @@
3991
4530
  background: #1d4ed8;
3992
4531
  }
3993
4532
 
4533
+ /* "Import from file" affordance (shared by the customizer popover + designer pane) */
4534
+ .squisq-theme-import {
4535
+ display: flex;
4536
+ flex-direction: column;
4537
+ gap: 6px;
4538
+ }
4539
+
4540
+ .squisq-theme-import-drop {
4541
+ display: flex;
4542
+ align-items: center;
4543
+ gap: 8px;
4544
+ padding: 8px;
4545
+ border: 1px dashed var(--squisq-border, #d1d5db);
4546
+ border-radius: 6px;
4547
+ background: var(--squisq-input-bg, #f9fafb);
4548
+ }
4549
+
4550
+ .squisq-theme-import-drop--active {
4551
+ border-color: #2563eb;
4552
+ background: rgba(37, 99, 235, 0.08);
4553
+ }
4554
+
4555
+ .squisq-theme-import-drop--busy {
4556
+ opacity: 0.7;
4557
+ pointer-events: none;
4558
+ }
4559
+
4560
+ .squisq-theme-import-hint {
4561
+ font-size: 11px;
4562
+ color: var(--squisq-text-muted, #6b7280);
4563
+ }
4564
+
4565
+ .squisq-theme-import-status {
4566
+ font-size: 11px;
4567
+ color: var(--squisq-text-muted, #6b7280);
4568
+ }
4569
+
4570
+ .squisq-theme-import-error {
4571
+ font-size: 11px;
4572
+ color: #dc2626;
4573
+ }
4574
+
4575
+ .squisq-theme-import-warnings {
4576
+ margin: 0;
4577
+ padding-left: 16px;
4578
+ font-size: 11px;
4579
+ color: var(--squisq-text-muted, #6b7280);
4580
+ }
4581
+
4582
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-import-drop {
4583
+ border-color: #374151;
4584
+ background: #111827;
4585
+ }
4586
+
4587
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-import-drop--active {
4588
+ border-color: #3b82f6;
4589
+ background: rgba(59, 130, 246, 0.12);
4590
+ }
4591
+
4592
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-import-error {
4593
+ color: #f87171;
4594
+ }
4595
+
3994
4596
  .squisq-editor-shell[data-theme='dark'] .squisq-theme-customizer-popover {
3995
4597
  background: #1f2937;
3996
4598
  border-color: #374151;
@@ -4803,6 +5405,7 @@
4803
5405
  }
4804
5406
 
4805
5407
  .squisq-outline-item {
5408
+ position: relative;
4806
5409
  margin: 0;
4807
5410
  }
4808
5411
 
@@ -4827,6 +5430,56 @@
4827
5430
  background: #f3f4f6;
4828
5431
  }
4829
5432
 
5433
+ .squisq-outline-row[draggable='true'] {
5434
+ cursor: grab;
5435
+ }
5436
+
5437
+ .squisq-outline-row[draggable='true']:active {
5438
+ cursor: grabbing;
5439
+ }
5440
+
5441
+ .squisq-outline-drag-handle {
5442
+ display: inline-flex;
5443
+ align-items: center;
5444
+ justify-content: center;
5445
+ flex: 0 0 8px;
5446
+ color: currentColor;
5447
+ opacity: 0.35;
5448
+ transition: opacity 0.1s ease;
5449
+ }
5450
+
5451
+ .squisq-outline-row:hover .squisq-outline-drag-handle,
5452
+ .squisq-outline-row:focus-visible .squisq-outline-drag-handle {
5453
+ opacity: 0.75;
5454
+ }
5455
+
5456
+ .squisq-outline-item--dragging {
5457
+ opacity: 0.42;
5458
+ }
5459
+
5460
+ .squisq-outline-item--drop-before > .squisq-outline-row-wrap::before,
5461
+ .squisq-outline-item--drop-after::after {
5462
+ content: '';
5463
+ position: absolute;
5464
+ z-index: 2;
5465
+ left: 4px;
5466
+ right: 4px;
5467
+ height: 2px;
5468
+ border-radius: 999px;
5469
+ background: var(--squisq-outline-accent, #4338ca);
5470
+ pointer-events: none;
5471
+ }
5472
+
5473
+ .squisq-outline-item--drop-before > .squisq-outline-row-wrap::before {
5474
+ top: -1px;
5475
+ }
5476
+
5477
+ /* The after marker belongs to the whole tree item so a parent section's
5478
+ insertion boundary appears below its complete nested subtree. */
5479
+ .squisq-outline-item--drop-after::after {
5480
+ bottom: -1px;
5481
+ }
5482
+
4830
5483
  .squisq-outline-row-text {
4831
5484
  overflow: hidden;
4832
5485
  text-overflow: ellipsis;
@@ -4997,10 +5650,7 @@
4997
5650
  color: #d1d5db;
4998
5651
  }
4999
5652
 
5000
- /* Dark-mode rebind for all preview-gutter custom properties. Individual
5001
- rules below remain as no-ops kept for back-compat with any host CSS
5002
- that may still target them — the variable redefinition is the single
5003
- source of truth going forward. */
5653
+ /* Dark-mode rebind for all preview-gutter custom properties. */
5004
5654
  .squisq-editor-shell[data-theme='dark'] {
5005
5655
  --squisq-preview-accent: #818cf8;
5006
5656
  --squisq-preview-accent-muted: #475569;
@@ -5016,10 +5666,6 @@
5016
5666
  --squisq-preview-empty-text: #94a3b8;
5017
5667
  }
5018
5668
 
5019
- .squisq-editor-shell[data-theme='dark'] .squisq-inline-preview-gutter {
5020
- background: var(--squisq-preview-gutter-bg);
5021
- }
5022
-
5023
5669
  .squisq-editor-shell[data-theme='dark'] .squisq-outline-empty {
5024
5670
  color: #94a3b8;
5025
5671
  }
@@ -5891,9 +6537,9 @@
5891
6537
  padding: 3px 8px;
5892
6538
  font-size: 12px;
5893
6539
  font-weight: 500;
5894
- color: #374151;
5895
- background: #fff;
5896
- border: 1px solid #d1d5db;
6540
+ color: var(--squisq-block-props-text);
6541
+ background: var(--squisq-block-props-surface);
6542
+ border: 1px solid var(--squisq-block-props-border);
5897
6543
  border-radius: 5px;
5898
6544
  cursor: pointer;
5899
6545
  white-space: nowrap;
@@ -5903,23 +6549,23 @@
5903
6549
  }
5904
6550
 
5905
6551
  .squisq-transition-picker-trigger:hover {
5906
- background: #f3f4f6;
5907
- border-color: #9ca3af;
6552
+ background: var(--squisq-block-props-surface-hover);
6553
+ border-color: var(--squisq-block-props-quiet);
5908
6554
  }
5909
6555
 
5910
6556
  .squisq-transition-picker-trigger--open {
5911
- background: #f3f4f6;
5912
- border-color: #6366f1;
5913
- outline: 2px solid rgba(99, 102, 241, 0.25);
6557
+ background: var(--squisq-block-props-surface-hover);
6558
+ border-color: var(--squisq-block-props-accent, #6366f1);
6559
+ outline: 2px solid color-mix(in oklch, var(--squisq-block-props-accent, #6366f1) 25%, transparent);
5914
6560
  outline-offset: -1px;
5915
6561
  }
5916
6562
 
5917
6563
  .squisq-transition-picker-trigger-label {
5918
- color: #6b7280;
6564
+ color: var(--squisq-block-props-muted);
5919
6565
  }
5920
6566
 
5921
6567
  .squisq-transition-picker-trigger-value {
5922
- color: #111827;
6568
+ color: var(--squisq-block-props-text);
5923
6569
  font-weight: 400;
5924
6570
  max-width: 110px;
5925
6571
  overflow: hidden;
@@ -5927,7 +6573,7 @@
5927
6573
  }
5928
6574
 
5929
6575
  .squisq-transition-picker-trigger svg {
5930
- color: #9ca3af;
6576
+ color: var(--squisq-block-props-quiet);
5931
6577
  flex-shrink: 0;
5932
6578
  }
5933
6579
 
@@ -5946,8 +6592,9 @@
5946
6592
  max-width: calc(100vw - 24px);
5947
6593
  display: flex;
5948
6594
  flex-direction: column;
5949
- background: #fff;
5950
- border: 1px solid #e5e7eb;
6595
+ color: var(--squisq-block-props-text);
6596
+ background: var(--squisq-block-props-surface);
6597
+ border: 1px solid var(--squisq-block-props-divider);
5951
6598
  border-radius: 10px;
5952
6599
  box-shadow:
5953
6600
  0 8px 24px rgba(0, 0, 0, 0.12),
@@ -5957,21 +6604,22 @@
5957
6604
 
5958
6605
  .squisq-transition-flyout-search {
5959
6606
  padding: 8px;
5960
- border-bottom: 1px solid #f0f0f0;
6607
+ border-bottom: 1px solid var(--squisq-block-props-divider);
5961
6608
  }
5962
6609
 
5963
6610
  .squisq-transition-flyout-search-input {
5964
6611
  width: 100%;
5965
6612
  padding: 6px 8px;
5966
6613
  font-size: 13px;
5967
- color: #111827;
5968
- border: 1px solid #d1d5db;
6614
+ color: var(--squisq-block-props-text);
6615
+ background: var(--squisq-block-props-input);
6616
+ border: 1px solid var(--squisq-block-props-border);
5969
6617
  border-radius: 6px;
5970
6618
  outline: none;
5971
6619
  }
5972
6620
 
5973
6621
  .squisq-transition-flyout-search-input:focus {
5974
- border-color: #6366f1;
6622
+ border-color: var(--squisq-block-props-accent, #6366f1);
5975
6623
  }
5976
6624
 
5977
6625
  .squisq-transition-flyout-list {
@@ -5993,7 +6641,7 @@
5993
6641
  font-weight: 600;
5994
6642
  letter-spacing: 0.04em;
5995
6643
  text-transform: uppercase;
5996
- color: #9ca3af;
6644
+ color: var(--squisq-block-props-quiet);
5997
6645
  }
5998
6646
 
5999
6647
  .squisq-transition-flyout-grid {
@@ -6008,9 +6656,9 @@
6008
6656
  text-align: left;
6009
6657
  padding: 6px 8px;
6010
6658
  font-size: 12px;
6011
- color: #374151;
6012
- background: #fff;
6013
- border: 1px solid #e5e7eb;
6659
+ color: var(--squisq-block-props-text);
6660
+ background: var(--squisq-block-props-surface);
6661
+ border: 1px solid var(--squisq-block-props-divider);
6014
6662
  border-radius: 6px;
6015
6663
  cursor: pointer;
6016
6664
  white-space: nowrap;
@@ -6019,14 +6667,14 @@
6019
6667
  }
6020
6668
 
6021
6669
  .squisq-transition-option:hover {
6022
- background: #f3f4f6;
6023
- border-color: #d1d5db;
6670
+ background: var(--squisq-block-props-surface-hover);
6671
+ border-color: var(--squisq-block-props-border);
6024
6672
  }
6025
6673
 
6026
6674
  .squisq-transition-option--selected {
6027
- background: #eef2ff;
6028
- border-color: #6366f1;
6029
- color: #4338ca;
6675
+ color: var(--squisq-block-props-accent, #4338ca);
6676
+ background: color-mix(in oklch, var(--squisq-block-props-accent, #6366f1) 14%, transparent);
6677
+ border-color: var(--squisq-block-props-accent, #6366f1);
6030
6678
  font-weight: 600;
6031
6679
  }
6032
6680
 
@@ -6055,13 +6703,13 @@
6055
6703
  .squisq-transition-flyout-empty {
6056
6704
  padding: 12px 8px;
6057
6705
  font-size: 12px;
6058
- color: #9ca3af;
6706
+ color: var(--squisq-block-props-quiet);
6059
6707
  text-align: center;
6060
6708
  }
6061
6709
 
6062
6710
  /* Direction + duration controls, shown below the list once a type is set. */
6063
6711
  .squisq-transition-flyout-controls {
6064
- border-top: 1px solid #f0f0f0;
6712
+ border-top: 1px solid var(--squisq-block-props-divider);
6065
6713
  padding: 10px 12px;
6066
6714
  display: flex;
6067
6715
  flex-direction: column;
@@ -6078,7 +6726,7 @@
6078
6726
  .squisq-transition-flyout-control-label {
6079
6727
  font-size: 11px;
6080
6728
  font-weight: 600;
6081
- color: #6b7280;
6729
+ color: var(--squisq-block-props-muted);
6082
6730
  }
6083
6731
 
6084
6732
  .squisq-transition-direction-row {
@@ -6089,21 +6737,21 @@
6089
6737
  .squisq-transition-direction-button {
6090
6738
  padding: 4px 8px;
6091
6739
  font-size: 11px;
6092
- color: #374151;
6093
- background: #fff;
6094
- border: 1px solid #d1d5db;
6740
+ color: var(--squisq-block-props-text);
6741
+ background: var(--squisq-block-props-surface);
6742
+ border: 1px solid var(--squisq-block-props-border);
6095
6743
  border-radius: 5px;
6096
6744
  cursor: pointer;
6097
6745
  }
6098
6746
 
6099
6747
  .squisq-transition-direction-button:hover {
6100
- background: #f3f4f6;
6748
+ background: var(--squisq-block-props-surface-hover);
6101
6749
  }
6102
6750
 
6103
6751
  .squisq-transition-direction-button--selected {
6104
- background: #eef2ff;
6105
- border-color: #6366f1;
6106
- color: #4338ca;
6752
+ color: var(--squisq-block-props-accent, #4338ca);
6753
+ background: color-mix(in oklch, var(--squisq-block-props-accent, #6366f1) 14%, transparent);
6754
+ border-color: var(--squisq-block-props-accent, #6366f1);
6107
6755
  font-weight: 600;
6108
6756
  }
6109
6757
 
@@ -6117,19 +6765,20 @@
6117
6765
  width: 64px;
6118
6766
  padding: 4px 6px;
6119
6767
  font-size: 12px;
6120
- color: #111827;
6121
- border: 1px solid #d1d5db;
6768
+ color: var(--squisq-block-props-text);
6769
+ background: var(--squisq-block-props-input);
6770
+ border: 1px solid var(--squisq-block-props-border);
6122
6771
  border-radius: 5px;
6123
6772
  outline: none;
6124
6773
  }
6125
6774
 
6126
6775
  .squisq-transition-duration-input:focus {
6127
- border-color: #6366f1;
6776
+ border-color: var(--squisq-block-props-accent, #6366f1);
6128
6777
  }
6129
6778
 
6130
6779
  .squisq-transition-duration-unit {
6131
6780
  font-size: 11px;
6132
- color: #9ca3af;
6781
+ color: var(--squisq-block-props-quiet);
6133
6782
  }
6134
6783
 
6135
6784
  /* Dark theme */
@@ -6146,50 +6795,17 @@
6146
6795
 
6147
6796
  .squisq-editor-shell[data-theme='dark'] .squisq-transition-picker-trigger--open {
6148
6797
  background: #374151;
6149
- border-color: #818cf8;
6798
+ border-color: var(--squisq-block-props-accent, #818cf8);
6150
6799
  }
6151
6800
 
6152
6801
  .squisq-editor-shell[data-theme='dark'] .squisq-transition-picker-trigger-value {
6153
6802
  color: #f9fafb;
6154
6803
  }
6155
6804
 
6156
- /* Dark styling for the portaled flyout keyed off the editor shell the same
6157
- way the template gallery popover is (see `.squisq-template-gallery` above). */
6158
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-flyout {
6159
- background: #1f2937;
6160
- border-color: #374151;
6805
+ /* Portaled to <body>, so the flyout's own data-theme is the reliable dark-mode
6806
+ boundary. Child colors come from the local surface tokens above. */
6807
+ .squisq-transition-flyout[data-theme='dark'] {
6161
6808
  box-shadow:
6162
6809
  0 8px 24px rgba(0, 0, 0, 0.4),
6163
6810
  0 2px 6px rgba(0, 0, 0, 0.2);
6164
6811
  }
6165
-
6166
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-flyout-search,
6167
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-flyout-controls {
6168
- border-color: #374151;
6169
- }
6170
-
6171
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-flyout-search-input,
6172
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-duration-input {
6173
- background: #111827;
6174
- color: #f9fafb;
6175
- border-color: #4b5563;
6176
- }
6177
-
6178
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-option,
6179
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-direction-button {
6180
- background: #1f2937;
6181
- color: #e5e7eb;
6182
- border-color: #4b5563;
6183
- }
6184
-
6185
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-option:hover,
6186
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-direction-button:hover {
6187
- background: #374151;
6188
- }
6189
-
6190
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-option--selected,
6191
- .squisq-editor-shell[data-theme='dark'] .squisq-transition-direction-button--selected {
6192
- background: #3730a3;
6193
- border-color: #818cf8;
6194
- color: #e0e7ff;
6195
- }