@bendyline/squisq-editor-react 1.3.0 → 1.5.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 (461) hide show
  1. package/dist/DocumentSettingsDialog.d.ts +26 -0
  2. package/dist/DocumentSettingsDialog.d.ts.map +1 -0
  3. package/dist/DocumentSettingsDialog.js +115 -0
  4. package/dist/DocumentSettingsDialog.js.map +1 -0
  5. package/dist/EditorContext.d.ts +248 -4
  6. package/dist/EditorContext.d.ts.map +1 -1
  7. package/dist/EditorContext.js +248 -10
  8. package/dist/EditorContext.js.map +1 -1
  9. package/dist/EditorShell.d.ts +184 -4
  10. package/dist/EditorShell.d.ts.map +1 -1
  11. package/dist/EditorShell.js +184 -12
  12. package/dist/EditorShell.js.map +1 -1
  13. package/dist/EmojiPicker.d.ts +50 -0
  14. package/dist/EmojiPicker.d.ts.map +1 -0
  15. package/dist/EmojiPicker.js +182 -0
  16. package/dist/EmojiPicker.js.map +1 -0
  17. package/dist/ImageEditor.d.ts +68 -0
  18. package/dist/ImageEditor.d.ts.map +1 -0
  19. package/dist/ImageEditor.js +166 -0
  20. package/dist/ImageEditor.js.map +1 -0
  21. package/dist/ImageNodeView.d.ts +13 -1
  22. package/dist/ImageNodeView.d.ts.map +1 -1
  23. package/dist/ImageNodeView.js +172 -19
  24. package/dist/ImageNodeView.js.map +1 -1
  25. package/dist/ImageViewer.d.ts +26 -0
  26. package/dist/ImageViewer.d.ts.map +1 -0
  27. package/dist/ImageViewer.js +119 -0
  28. package/dist/ImageViewer.js.map +1 -0
  29. package/dist/InlineIcon.d.ts +17 -0
  30. package/dist/InlineIcon.d.ts.map +1 -0
  31. package/dist/InlineIcon.js +72 -0
  32. package/dist/InlineIcon.js.map +1 -0
  33. package/dist/InlinePreviewGutter.d.ts +52 -0
  34. package/dist/InlinePreviewGutter.d.ts.map +1 -0
  35. package/dist/InlinePreviewGutter.js +397 -0
  36. package/dist/InlinePreviewGutter.js.map +1 -0
  37. package/dist/LinkDialog.d.ts +43 -0
  38. package/dist/LinkDialog.d.ts.map +1 -0
  39. package/dist/LinkDialog.js +102 -0
  40. package/dist/LinkDialog.js.map +1 -0
  41. package/dist/MediaBin.d.ts +12 -1
  42. package/dist/MediaBin.d.ts.map +1 -1
  43. package/dist/MediaBin.js +13 -3
  44. package/dist/MediaBin.js.map +1 -1
  45. package/dist/MentionExtension.js +10 -7
  46. package/dist/MentionExtension.js.map +1 -1
  47. package/dist/OutlinePanel.d.ts +17 -0
  48. package/dist/OutlinePanel.d.ts.map +1 -0
  49. package/dist/OutlinePanel.js +167 -0
  50. package/dist/OutlinePanel.js.map +1 -0
  51. package/dist/PlainHtmlPreview.d.ts +50 -0
  52. package/dist/PlainHtmlPreview.d.ts.map +1 -0
  53. package/dist/PlainHtmlPreview.js +155 -0
  54. package/dist/PlainHtmlPreview.js.map +1 -0
  55. package/dist/PreviewControls.d.ts +15 -1
  56. package/dist/PreviewControls.d.ts.map +1 -1
  57. package/dist/PreviewControls.js +75 -18
  58. package/dist/PreviewControls.js.map +1 -1
  59. package/dist/PreviewPanel.d.ts +11 -10
  60. package/dist/PreviewPanel.d.ts.map +1 -1
  61. package/dist/PreviewPanel.js +20 -17
  62. package/dist/PreviewPanel.js.map +1 -1
  63. package/dist/RawEditor.d.ts.map +1 -1
  64. package/dist/RawEditor.js +198 -4
  65. package/dist/RawEditor.js.map +1 -1
  66. package/dist/RecorderEntry.d.ts +24 -0
  67. package/dist/RecorderEntry.d.ts.map +1 -0
  68. package/dist/RecorderEntry.js +139 -0
  69. package/dist/RecorderEntry.js.map +1 -0
  70. package/dist/TemplateAnnotation.d.ts.map +1 -1
  71. package/dist/TemplateAnnotation.js +32 -6
  72. package/dist/TemplateAnnotation.js.map +1 -1
  73. package/dist/TemplatePicker.d.ts +53 -0
  74. package/dist/TemplatePicker.d.ts.map +1 -0
  75. package/dist/TemplatePicker.js +388 -0
  76. package/dist/TemplatePicker.js.map +1 -0
  77. package/dist/ThemeCustomizerPanel.d.ts +32 -0
  78. package/dist/ThemeCustomizerPanel.d.ts.map +1 -0
  79. package/dist/ThemeCustomizerPanel.js +256 -0
  80. package/dist/ThemeCustomizerPanel.js.map +1 -0
  81. package/dist/ThemePicker.d.ts +33 -0
  82. package/dist/ThemePicker.d.ts.map +1 -0
  83. package/dist/ThemePicker.js +148 -0
  84. package/dist/ThemePicker.js.map +1 -0
  85. package/dist/Toolbar.d.ts.map +1 -1
  86. package/dist/Toolbar.js +508 -33
  87. package/dist/Toolbar.js.map +1 -1
  88. package/dist/VersionHistoryPanel.d.ts +14 -0
  89. package/dist/VersionHistoryPanel.d.ts.map +1 -0
  90. package/dist/VersionHistoryPanel.js +147 -0
  91. package/dist/VersionHistoryPanel.js.map +1 -0
  92. package/dist/ViewMenuPanel.d.ts +13 -0
  93. package/dist/ViewMenuPanel.d.ts.map +1 -0
  94. package/dist/ViewMenuPanel.js +58 -0
  95. package/dist/ViewMenuPanel.js.map +1 -0
  96. package/dist/WysiwygEditor.d.ts.map +1 -1
  97. package/dist/WysiwygEditor.js +198 -9
  98. package/dist/WysiwygEditor.js.map +1 -1
  99. package/dist/__tests__/detectMarkdown.test.js +0 -14
  100. package/dist/__tests__/detectMarkdown.test.js.map +1 -1
  101. package/dist/__tests__/documentSettingsDialog.test.d.ts +2 -0
  102. package/dist/__tests__/documentSettingsDialog.test.d.ts.map +1 -0
  103. package/dist/__tests__/documentSettingsDialog.test.js +132 -0
  104. package/dist/__tests__/documentSettingsDialog.test.js.map +1 -0
  105. package/dist/__tests__/emojiPicker.test.d.ts +2 -0
  106. package/dist/__tests__/emojiPicker.test.d.ts.map +1 -0
  107. package/dist/__tests__/emojiPicker.test.js +111 -0
  108. package/dist/__tests__/emojiPicker.test.js.map +1 -0
  109. package/dist/__tests__/fileKind.test.js +13 -0
  110. package/dist/__tests__/fileKind.test.js.map +1 -1
  111. package/dist/__tests__/imageEditAffordance.test.d.ts +2 -0
  112. package/dist/__tests__/imageEditAffordance.test.d.ts.map +1 -0
  113. package/dist/__tests__/imageEditAffordance.test.js +188 -0
  114. package/dist/__tests__/imageEditAffordance.test.js.map +1 -0
  115. package/dist/__tests__/imageEditorShell.test.d.ts +2 -0
  116. package/dist/__tests__/imageEditorShell.test.d.ts.map +1 -0
  117. package/dist/__tests__/imageEditorShell.test.js +52 -0
  118. package/dist/__tests__/imageEditorShell.test.js.map +1 -0
  119. package/dist/__tests__/imageEditorState.test.d.ts +3 -0
  120. package/dist/__tests__/imageEditorState.test.d.ts.map +1 -0
  121. package/dist/__tests__/imageEditorState.test.js +148 -0
  122. package/dist/__tests__/imageEditorState.test.js.map +1 -0
  123. package/dist/__tests__/inlinePreviewGutter.test.d.ts +2 -0
  124. package/dist/__tests__/inlinePreviewGutter.test.d.ts.map +1 -0
  125. package/dist/__tests__/inlinePreviewGutter.test.js +51 -0
  126. package/dist/__tests__/inlinePreviewGutter.test.js.map +1 -0
  127. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.d.ts +2 -0
  128. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.d.ts.map +1 -0
  129. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.js +63 -0
  130. package/dist/__tests__/inlinePreviewGutterAllBlocks.test.js.map +1 -0
  131. package/dist/__tests__/jsonEditor.test.d.ts +2 -0
  132. package/dist/__tests__/jsonEditor.test.d.ts.map +1 -0
  133. package/dist/__tests__/jsonEditor.test.js +134 -0
  134. package/dist/__tests__/jsonEditor.test.js.map +1 -0
  135. package/dist/__tests__/layersPanel.test.d.ts +2 -0
  136. package/dist/__tests__/layersPanel.test.d.ts.map +1 -0
  137. package/dist/__tests__/layersPanel.test.js +84 -0
  138. package/dist/__tests__/layersPanel.test.js.map +1 -0
  139. package/dist/__tests__/linkDialogDocPicker.test.d.ts +7 -0
  140. package/dist/__tests__/linkDialogDocPicker.test.d.ts.map +1 -0
  141. package/dist/__tests__/linkDialogDocPicker.test.js +75 -0
  142. package/dist/__tests__/linkDialogDocPicker.test.js.map +1 -0
  143. package/dist/__tests__/mediaAttachmentFlow.test.d.ts +2 -0
  144. package/dist/__tests__/mediaAttachmentFlow.test.d.ts.map +1 -0
  145. package/dist/__tests__/mediaAttachmentFlow.test.js +99 -0
  146. package/dist/__tests__/mediaAttachmentFlow.test.js.map +1 -0
  147. package/dist/__tests__/outlinePanel.test.d.ts +2 -0
  148. package/dist/__tests__/outlinePanel.test.d.ts.map +1 -0
  149. package/dist/__tests__/outlinePanel.test.js +68 -0
  150. package/dist/__tests__/outlinePanel.test.js.map +1 -0
  151. package/dist/__tests__/plainHtmlPreview.test.d.ts +2 -0
  152. package/dist/__tests__/plainHtmlPreview.test.d.ts.map +1 -0
  153. package/dist/__tests__/plainHtmlPreview.test.js +87 -0
  154. package/dist/__tests__/plainHtmlPreview.test.js.map +1 -0
  155. package/dist/__tests__/propertiesPanel.test.d.ts +2 -0
  156. package/dist/__tests__/propertiesPanel.test.d.ts.map +1 -0
  157. package/dist/__tests__/propertiesPanel.test.js +64 -0
  158. package/dist/__tests__/propertiesPanel.test.js.map +1 -0
  159. package/dist/__tests__/recorderFormats.test.d.ts +2 -0
  160. package/dist/__tests__/recorderFormats.test.d.ts.map +1 -0
  161. package/dist/__tests__/recorderFormats.test.js +121 -0
  162. package/dist/__tests__/recorderFormats.test.js.map +1 -0
  163. package/dist/__tests__/recorderTimingJson.test.d.ts +2 -0
  164. package/dist/__tests__/recorderTimingJson.test.d.ts.map +1 -0
  165. package/dist/__tests__/recorderTimingJson.test.js +37 -0
  166. package/dist/__tests__/recorderTimingJson.test.js.map +1 -0
  167. package/dist/__tests__/templateAnnotationRoundTrip.test.d.ts +2 -0
  168. package/dist/__tests__/templateAnnotationRoundTrip.test.d.ts.map +1 -0
  169. package/dist/__tests__/templateAnnotationRoundTrip.test.js +31 -0
  170. package/dist/__tests__/templateAnnotationRoundTrip.test.js.map +1 -0
  171. package/dist/__tests__/tiptapBridge.test.js +26 -0
  172. package/dist/__tests__/tiptapBridge.test.js.map +1 -1
  173. package/dist/__tests__/tiptapImageRoundTrip.test.d.ts +2 -0
  174. package/dist/__tests__/tiptapImageRoundTrip.test.d.ts.map +1 -0
  175. package/dist/__tests__/tiptapImageRoundTrip.test.js +68 -0
  176. package/dist/__tests__/tiptapImageRoundTrip.test.js.map +1 -0
  177. package/dist/__tests__/useImageEditor.test.d.ts +2 -0
  178. package/dist/__tests__/useImageEditor.test.d.ts.map +1 -0
  179. package/dist/__tests__/useImageEditor.test.js +131 -0
  180. package/dist/__tests__/useImageEditor.test.js.map +1 -0
  181. package/dist/__tests__/useMediaRecorder.test.d.ts +2 -0
  182. package/dist/__tests__/useMediaRecorder.test.d.ts.map +1 -0
  183. package/dist/__tests__/useMediaRecorder.test.js +153 -0
  184. package/dist/__tests__/useMediaRecorder.test.js.map +1 -0
  185. package/dist/__tests__/versionHistory.test.d.ts +2 -0
  186. package/dist/__tests__/versionHistory.test.d.ts.map +1 -0
  187. package/dist/__tests__/versionHistory.test.js +124 -0
  188. package/dist/__tests__/versionHistory.test.js.map +1 -0
  189. package/dist/blockSlice.d.ts +24 -0
  190. package/dist/blockSlice.d.ts.map +1 -0
  191. package/dist/blockSlice.js +63 -0
  192. package/dist/blockSlice.js.map +1 -0
  193. package/dist/buildPreviewDoc.d.ts.map +1 -1
  194. package/dist/buildPreviewDoc.js +52 -2
  195. package/dist/buildPreviewDoc.js.map +1 -1
  196. package/dist/emojiData.d.ts +81 -0
  197. package/dist/emojiData.d.ts.map +1 -0
  198. package/dist/emojiData.js +1283 -0
  199. package/dist/emojiData.js.map +1 -0
  200. package/dist/fileKind.d.ts +6 -2
  201. package/dist/fileKind.d.ts.map +1 -1
  202. package/dist/fileKind.js +25 -4
  203. package/dist/fileKind.js.map +1 -1
  204. package/dist/hooks/useFileDrop.d.ts.map +1 -1
  205. package/dist/hooks/useFileDrop.js +40 -4
  206. package/dist/hooks/useFileDrop.js.map +1 -1
  207. package/dist/imageEditor/CanvasSurface.d.ts +31 -0
  208. package/dist/imageEditor/CanvasSurface.d.ts.map +1 -0
  209. package/dist/imageEditor/CanvasSurface.js +264 -0
  210. package/dist/imageEditor/CanvasSurface.js.map +1 -0
  211. package/dist/imageEditor/ImageVersionHistoryDropdown.d.ts +39 -0
  212. package/dist/imageEditor/ImageVersionHistoryDropdown.d.ts.map +1 -0
  213. package/dist/imageEditor/ImageVersionHistoryDropdown.js +283 -0
  214. package/dist/imageEditor/ImageVersionHistoryDropdown.js.map +1 -0
  215. package/dist/imageEditor/LayersPanel.d.ts +14 -0
  216. package/dist/imageEditor/LayersPanel.d.ts.map +1 -0
  217. package/dist/imageEditor/LayersPanel.js +43 -0
  218. package/dist/imageEditor/LayersPanel.js.map +1 -0
  219. package/dist/imageEditor/PropertiesPanel.d.ts +14 -0
  220. package/dist/imageEditor/PropertiesPanel.d.ts.map +1 -0
  221. package/dist/imageEditor/PropertiesPanel.js +97 -0
  222. package/dist/imageEditor/PropertiesPanel.js.map +1 -0
  223. package/dist/imageEditor/Toolbar.d.ts +30 -0
  224. package/dist/imageEditor/Toolbar.d.ts.map +1 -0
  225. package/dist/imageEditor/Toolbar.js +108 -0
  226. package/dist/imageEditor/Toolbar.js.map +1 -0
  227. package/dist/imageEditor/icons.d.ts +24 -0
  228. package/dist/imageEditor/icons.d.ts.map +1 -0
  229. package/dist/imageEditor/icons.js +45 -0
  230. package/dist/imageEditor/icons.js.map +1 -0
  231. package/dist/imageEditor/layers/EditorImageLayer.d.ts +16 -0
  232. package/dist/imageEditor/layers/EditorImageLayer.d.ts.map +1 -0
  233. package/dist/imageEditor/layers/EditorImageLayer.js +37 -0
  234. package/dist/imageEditor/layers/EditorImageLayer.js.map +1 -0
  235. package/dist/imageEditor/layers/EditorShapeLayer.d.ts +15 -0
  236. package/dist/imageEditor/layers/EditorShapeLayer.d.ts.map +1 -0
  237. package/dist/imageEditor/layers/EditorShapeLayer.js +20 -0
  238. package/dist/imageEditor/layers/EditorShapeLayer.js.map +1 -0
  239. package/dist/imageEditor/layers/EditorTextLayer.d.ts +18 -0
  240. package/dist/imageEditor/layers/EditorTextLayer.d.ts.map +1 -0
  241. package/dist/imageEditor/layers/EditorTextLayer.js +13 -0
  242. package/dist/imageEditor/layers/EditorTextLayer.js.map +1 -0
  243. package/dist/imageEditor/layers/SelectionHandles.d.ts +17 -0
  244. package/dist/imageEditor/layers/SelectionHandles.d.ts.map +1 -0
  245. package/dist/imageEditor/layers/SelectionHandles.js +19 -0
  246. package/dist/imageEditor/layers/SelectionHandles.js.map +1 -0
  247. package/dist/imageEditor/state.d.ts +76 -0
  248. package/dist/imageEditor/state.d.ts.map +1 -0
  249. package/dist/imageEditor/state.js +87 -0
  250. package/dist/imageEditor/state.js.map +1 -0
  251. package/dist/imageEditor/useImageEditor.d.ts +53 -0
  252. package/dist/imageEditor/useImageEditor.d.ts.map +1 -0
  253. package/dist/imageEditor/useImageEditor.js +244 -0
  254. package/dist/imageEditor/useImageEditor.js.map +1 -0
  255. package/dist/imageEditor/useImageEditorTokens.d.ts +16 -0
  256. package/dist/imageEditor/useImageEditorTokens.d.ts.map +1 -0
  257. package/dist/imageEditor/useImageEditorTokens.js +45 -0
  258. package/dist/imageEditor/useImageEditorTokens.js.map +1 -0
  259. package/dist/index.d.ts +48 -1
  260. package/dist/index.d.ts.map +1 -1
  261. package/dist/index.js +36 -0
  262. package/dist/index.js.map +1 -1
  263. package/dist/jsonEditor/EmbeddedRichTextField.d.ts +15 -0
  264. package/dist/jsonEditor/EmbeddedRichTextField.d.ts.map +1 -0
  265. package/dist/jsonEditor/EmbeddedRichTextField.js +74 -0
  266. package/dist/jsonEditor/EmbeddedRichTextField.js.map +1 -0
  267. package/dist/jsonEditor/JsonEditor.d.ts +36 -0
  268. package/dist/jsonEditor/JsonEditor.d.ts.map +1 -0
  269. package/dist/jsonEditor/JsonEditor.js +15 -0
  270. package/dist/jsonEditor/JsonEditor.js.map +1 -0
  271. package/dist/jsonEditor/JsonEditorContext.d.ts +28 -0
  272. package/dist/jsonEditor/JsonEditorContext.d.ts.map +1 -0
  273. package/dist/jsonEditor/JsonEditorContext.js +41 -0
  274. package/dist/jsonEditor/JsonEditorContext.js.map +1 -0
  275. package/dist/jsonEditor/RenderNode.d.ts +16 -0
  276. package/dist/jsonEditor/RenderNode.d.ts.map +1 -0
  277. package/dist/jsonEditor/RenderNode.js +32 -0
  278. package/dist/jsonEditor/RenderNode.js.map +1 -0
  279. package/dist/jsonEditor/editors.d.ts +36 -0
  280. package/dist/jsonEditor/editors.d.ts.map +1 -0
  281. package/dist/jsonEditor/editors.js +347 -0
  282. package/dist/jsonEditor/editors.js.map +1 -0
  283. package/dist/jsonEditor/index.d.ts +3 -0
  284. package/dist/jsonEditor/index.d.ts.map +1 -0
  285. package/dist/jsonEditor/index.js +2 -0
  286. package/dist/jsonEditor/index.js.map +1 -0
  287. package/dist/jsonEditor/useJsonEditorTokens.d.ts +13 -0
  288. package/dist/jsonEditor/useJsonEditorTokens.d.ts.map +1 -0
  289. package/dist/jsonEditor/useJsonEditorTokens.js +38 -0
  290. package/dist/jsonEditor/useJsonEditorTokens.js.map +1 -0
  291. package/dist/recorder/RecorderButton.d.ts +31 -0
  292. package/dist/recorder/RecorderButton.d.ts.map +1 -0
  293. package/dist/recorder/RecorderButton.js +24 -0
  294. package/dist/recorder/RecorderButton.js.map +1 -0
  295. package/dist/recorder/RecorderModal.d.ts +59 -0
  296. package/dist/recorder/RecorderModal.d.ts.map +1 -0
  297. package/dist/recorder/RecorderModal.js +333 -0
  298. package/dist/recorder/RecorderModal.js.map +1 -0
  299. package/dist/recorder/RecorderPanel.d.ts +25 -0
  300. package/dist/recorder/RecorderPanel.d.ts.map +1 -0
  301. package/dist/recorder/RecorderPanel.js +30 -0
  302. package/dist/recorder/RecorderPanel.js.map +1 -0
  303. package/dist/recorder/formats.d.ts +51 -0
  304. package/dist/recorder/formats.d.ts.map +1 -0
  305. package/dist/recorder/formats.js +144 -0
  306. package/dist/recorder/formats.js.map +1 -0
  307. package/dist/recorder/hooks/useMediaRecorder.d.ts +90 -0
  308. package/dist/recorder/hooks/useMediaRecorder.d.ts.map +1 -0
  309. package/dist/recorder/hooks/useMediaRecorder.js +277 -0
  310. package/dist/recorder/hooks/useMediaRecorder.js.map +1 -0
  311. package/dist/recorder/hooks/useStreamPreview.d.ts +22 -0
  312. package/dist/recorder/hooks/useStreamPreview.d.ts.map +1 -0
  313. package/dist/recorder/hooks/useStreamPreview.js +44 -0
  314. package/dist/recorder/hooks/useStreamPreview.js.map +1 -0
  315. package/dist/recorder/sources/cameraStream.d.ts +22 -0
  316. package/dist/recorder/sources/cameraStream.d.ts.map +1 -0
  317. package/dist/recorder/sources/cameraStream.js +24 -0
  318. package/dist/recorder/sources/cameraStream.js.map +1 -0
  319. package/dist/recorder/sources/micStream.d.ts +15 -0
  320. package/dist/recorder/sources/micStream.d.ts.map +1 -0
  321. package/dist/recorder/sources/micStream.js +24 -0
  322. package/dist/recorder/sources/micStream.js.map +1 -0
  323. package/dist/recorder/sources/screenStream.d.ts +53 -0
  324. package/dist/recorder/sources/screenStream.d.ts.map +1 -0
  325. package/dist/recorder/sources/screenStream.js +114 -0
  326. package/dist/recorder/sources/screenStream.js.map +1 -0
  327. package/dist/recorder/timingJson.d.ts +51 -0
  328. package/dist/recorder/timingJson.d.ts.map +1 -0
  329. package/dist/recorder/timingJson.js +42 -0
  330. package/dist/recorder/timingJson.js.map +1 -0
  331. package/dist/tiptap/TiptapAudio.d.ts +26 -0
  332. package/dist/tiptap/TiptapAudio.d.ts.map +1 -0
  333. package/dist/tiptap/TiptapAudio.js +58 -0
  334. package/dist/tiptap/TiptapAudio.js.map +1 -0
  335. package/dist/tiptap/TiptapVideo.d.ts +30 -0
  336. package/dist/tiptap/TiptapVideo.d.ts.map +1 -0
  337. package/dist/tiptap/TiptapVideo.js +66 -0
  338. package/dist/tiptap/TiptapVideo.js.map +1 -0
  339. package/dist/tiptap/useResolvedMediaSrc.d.ts +2 -0
  340. package/dist/tiptap/useResolvedMediaSrc.d.ts.map +1 -0
  341. package/dist/tiptap/useResolvedMediaSrc.js +42 -0
  342. package/dist/tiptap/useResolvedMediaSrc.js.map +1 -0
  343. package/dist/tiptapBridge.d.ts.map +1 -1
  344. package/dist/tiptapBridge.js +210 -16
  345. package/dist/tiptapBridge.js.map +1 -1
  346. package/dist/useHeadingLayout.d.ts +54 -0
  347. package/dist/useHeadingLayout.d.ts.map +1 -0
  348. package/dist/useHeadingLayout.js +260 -0
  349. package/dist/useHeadingLayout.js.map +1 -0
  350. package/dist/utils/collectInlineFontAwesomeCss.d.ts +21 -0
  351. package/dist/utils/collectInlineFontAwesomeCss.d.ts.map +1 -0
  352. package/dist/utils/collectInlineFontAwesomeCss.js +68 -0
  353. package/dist/utils/collectInlineFontAwesomeCss.js.map +1 -0
  354. package/dist/utils/dropUtils.d.ts +21 -2
  355. package/dist/utils/dropUtils.d.ts.map +1 -1
  356. package/dist/utils/dropUtils.js +43 -4
  357. package/dist/utils/dropUtils.js.map +1 -1
  358. package/dist/utils/normalizeMalformedAssetUrl.d.ts +15 -0
  359. package/dist/utils/normalizeMalformedAssetUrl.d.ts.map +1 -0
  360. package/dist/utils/normalizeMalformedAssetUrl.js +27 -0
  361. package/dist/utils/normalizeMalformedAssetUrl.js.map +1 -0
  362. package/package.json +8 -5
  363. package/src/DocumentSettingsDialog.tsx +266 -0
  364. package/src/EditorContext.tsx +534 -10
  365. package/src/EditorShell.tsx +691 -63
  366. package/src/EmojiPicker.tsx +332 -0
  367. package/src/ImageEditor.tsx +327 -0
  368. package/src/ImageNodeView.tsx +222 -21
  369. package/src/ImageViewer.tsx +221 -0
  370. package/src/InlineIcon.ts +84 -0
  371. package/src/InlinePreviewGutter.tsx +582 -0
  372. package/src/LinkDialog.tsx +276 -0
  373. package/src/MediaBin.tsx +22 -3
  374. package/src/MentionExtension.tsx +10 -7
  375. package/src/OutlinePanel.tsx +295 -0
  376. package/src/PlainHtmlPreview.tsx +211 -0
  377. package/src/PreviewControls.tsx +130 -24
  378. package/src/PreviewPanel.tsx +38 -21
  379. package/src/RawEditor.tsx +215 -4
  380. package/src/RecorderEntry.tsx +164 -0
  381. package/src/TemplateAnnotation.ts +32 -6
  382. package/src/TemplatePicker.tsx +818 -0
  383. package/src/ThemeCustomizerPanel.tsx +595 -0
  384. package/src/ThemePicker.tsx +319 -0
  385. package/src/Toolbar.tsx +708 -111
  386. package/src/VersionHistoryPanel.tsx +329 -0
  387. package/src/ViewMenuPanel.tsx +188 -0
  388. package/src/WysiwygEditor.tsx +229 -9
  389. package/src/__tests__/detectMarkdown.test.ts +0 -15
  390. package/src/__tests__/documentSettingsDialog.test.tsx +147 -0
  391. package/src/__tests__/emojiPicker.test.tsx +133 -0
  392. package/src/__tests__/fileKind.test.ts +16 -0
  393. package/src/__tests__/imageEditAffordance.test.tsx +268 -0
  394. package/src/__tests__/imageEditorShell.test.tsx +57 -0
  395. package/src/__tests__/imageEditorState.test.ts +171 -0
  396. package/src/__tests__/inlinePreviewGutter.test.tsx +62 -0
  397. package/src/__tests__/inlinePreviewGutterAllBlocks.test.tsx +103 -0
  398. package/src/__tests__/jsonEditor.test.tsx +168 -0
  399. package/src/__tests__/layersPanel.test.tsx +97 -0
  400. package/src/__tests__/linkDialogDocPicker.test.tsx +137 -0
  401. package/src/__tests__/mediaAttachmentFlow.test.ts +110 -0
  402. package/src/__tests__/outlinePanel.test.tsx +79 -0
  403. package/src/__tests__/plainHtmlPreview.test.tsx +107 -0
  404. package/src/__tests__/propertiesPanel.test.tsx +69 -0
  405. package/src/__tests__/recorderFormats.test.ts +146 -0
  406. package/src/__tests__/recorderTimingJson.test.ts +41 -0
  407. package/src/__tests__/templateAnnotationRoundTrip.test.ts +34 -0
  408. package/src/__tests__/tiptapBridge.test.ts +29 -0
  409. package/src/__tests__/tiptapImageRoundTrip.test.ts +73 -0
  410. package/src/__tests__/useImageEditor.test.tsx +159 -0
  411. package/src/__tests__/useMediaRecorder.test.ts +186 -0
  412. package/src/__tests__/versionHistory.test.tsx +197 -0
  413. package/src/blockSlice.ts +75 -0
  414. package/src/buildPreviewDoc.ts +61 -6
  415. package/src/emojiData.ts +1337 -0
  416. package/src/fileKind.ts +30 -6
  417. package/src/hooks/useFileDrop.ts +40 -4
  418. package/src/imageEditor/CanvasSurface.tsx +402 -0
  419. package/src/imageEditor/ImageVersionHistoryDropdown.tsx +396 -0
  420. package/src/imageEditor/LayersPanel.tsx +143 -0
  421. package/src/imageEditor/PropertiesPanel.tsx +428 -0
  422. package/src/imageEditor/Toolbar.tsx +242 -0
  423. package/src/imageEditor/icons.tsx +144 -0
  424. package/src/imageEditor/image-editor.css +450 -0
  425. package/src/imageEditor/layers/EditorImageLayer.tsx +45 -0
  426. package/src/imageEditor/layers/EditorShapeLayer.tsx +62 -0
  427. package/src/imageEditor/layers/EditorTextLayer.tsx +45 -0
  428. package/src/imageEditor/layers/SelectionHandles.tsx +86 -0
  429. package/src/imageEditor/state.ts +153 -0
  430. package/src/imageEditor/useImageEditor.ts +328 -0
  431. package/src/imageEditor/useImageEditorTokens.ts +70 -0
  432. package/src/index.ts +82 -0
  433. package/src/jsonEditor/EmbeddedRichTextField.tsx +81 -0
  434. package/src/jsonEditor/JsonEditor.tsx +81 -0
  435. package/src/jsonEditor/JsonEditorContext.tsx +75 -0
  436. package/src/jsonEditor/RenderNode.tsx +66 -0
  437. package/src/jsonEditor/editors.tsx +678 -0
  438. package/src/jsonEditor/index.ts +2 -0
  439. package/src/jsonEditor/json-editor.css +463 -0
  440. package/src/jsonEditor/useJsonEditorTokens.ts +63 -0
  441. package/src/recorder/RecorderButton.tsx +72 -0
  442. package/src/recorder/RecorderModal.tsx +596 -0
  443. package/src/recorder/RecorderPanel.tsx +93 -0
  444. package/src/recorder/formats.ts +159 -0
  445. package/src/recorder/hooks/useMediaRecorder.ts +378 -0
  446. package/src/recorder/hooks/useStreamPreview.ts +47 -0
  447. package/src/recorder/sources/cameraStream.ts +32 -0
  448. package/src/recorder/sources/micStream.ts +25 -0
  449. package/src/recorder/sources/screenStream.ts +162 -0
  450. package/src/recorder/timingJson.ts +66 -0
  451. package/src/styles/editor.css +2490 -51
  452. package/src/styles/image-edit-affordance.css +201 -0
  453. package/src/styles/index.css +10 -0
  454. package/src/tiptap/TiptapAudio.tsx +86 -0
  455. package/src/tiptap/TiptapVideo.tsx +119 -0
  456. package/src/tiptap/useResolvedMediaSrc.ts +47 -0
  457. package/src/tiptapBridge.ts +227 -22
  458. package/src/useHeadingLayout.ts +294 -0
  459. package/src/utils/collectInlineFontAwesomeCss.ts +69 -0
  460. package/src/utils/dropUtils.ts +54 -6
  461. package/src/utils/normalizeMalformedAssetUrl.ts +22 -0
@@ -29,6 +29,13 @@
29
29
  flex-shrink: 0;
30
30
  }
31
31
 
32
+ .squisq-editor-header--image {
33
+ display: flex;
34
+ align-items: center;
35
+ gap: 8px;
36
+ padding: 6px 8px;
37
+ }
38
+
32
39
  .squisq-editor-content {
33
40
  flex: 1;
34
41
  overflow: hidden;
@@ -61,7 +68,11 @@
61
68
  }
62
69
 
63
70
  .squisq-view-tab {
64
- padding: 6px 16px;
71
+ /* Asymmetric vertical padding pushes the label down toward the
72
+ underline so it reads as a tab indicator rather than a label
73
+ floating above a separate line. Underline (`border-bottom: 2px`)
74
+ stays at the very bottom of the tab; text shifts ~3px lower. */
75
+ padding: 11px 16px 3px;
65
76
  min-width: 72px;
66
77
  text-align: center;
67
78
  border: none;
@@ -108,7 +119,20 @@
108
119
  background: #ffffff;
109
120
  border-right: 1px solid rgba(0, 0, 0, 0.12);
110
121
  align-self: stretch;
111
- align-items: center;
122
+ /* Bottom-align so the active-tab underline lands flush with the
123
+ toolbar's lower edge — the underline-as-tab-indicator pattern
124
+ reads as "tab", not "floating button in the middle of a bar". */
125
+ align-items: flex-end;
126
+ box-sizing: border-box;
127
+ }
128
+
129
+ /* When the outline pane is visible, anchor the toolbar's view-tabs section
130
+ * to the outline pane's width so their right-edge dividers line up
131
+ * vertically — otherwise the view-tabs border and the outline's right edge
132
+ * sit at different X positions and the chrome looks misaligned. */
133
+ .squisq-editor-shell[data-outline-visible='true'] .squisq-toolbar-view-tabs {
134
+ flex-shrink: 0;
135
+ min-width: var(--squisq-outline-width, 240px);
112
136
  }
113
137
 
114
138
  .squisq-toolbar-actions {
@@ -121,7 +145,12 @@
121
145
  }
122
146
 
123
147
  .squisq-toolbar-view-tab {
124
- padding: 4px 14px;
148
+ /* Top padding is asymmetric — bumped 4px above the bottom — so the
149
+ label sits more vertically centered alongside the neighboring
150
+ toolbar buttons rather than floating up against the toolbar's
151
+ top edge. The 2px `border-bottom` remains the active-tab
152
+ underline at the tab's lower edge. */
153
+ padding: 8px 14px 4px;
125
154
  border: none;
126
155
  background: transparent;
127
156
  color: #4b5563;
@@ -348,6 +377,7 @@
348
377
  white-space: nowrap;
349
378
  }
350
379
 
380
+ /* Keep for overflow-menu compact=true usage */
351
381
  .squisq-template-picker-select {
352
382
  font-size: 12px;
353
383
  padding: 2px 6px;
@@ -364,6 +394,258 @@
364
394
  outline-offset: -1px;
365
395
  }
366
396
 
397
+ /* ─── Template Gallery Popover ───────────────────────── */
398
+
399
+ .squisq-template-picker-popover-host {
400
+ position: relative;
401
+ }
402
+
403
+ .squisq-template-picker-trigger {
404
+ display: inline-flex;
405
+ align-items: center;
406
+ gap: 5px;
407
+ padding: 3px 8px 3px 6px;
408
+ font-size: 12px;
409
+ font-weight: 500;
410
+ color: #374151;
411
+ background: #fff;
412
+ border: 1px solid #d1d5db;
413
+ border-radius: 5px;
414
+ cursor: pointer;
415
+ white-space: nowrap;
416
+ transition:
417
+ background 0.1s,
418
+ border-color 0.1s;
419
+ }
420
+
421
+ .squisq-template-picker-trigger:hover {
422
+ background: #f3f4f6;
423
+ border-color: #9ca3af;
424
+ }
425
+
426
+ .squisq-template-picker-trigger--open {
427
+ background: #f3f4f6;
428
+ border-color: #6366f1;
429
+ outline: 2px solid rgba(99, 102, 241, 0.25);
430
+ outline-offset: -1px;
431
+ }
432
+
433
+ .squisq-template-picker-trigger-label {
434
+ color: #6b7280;
435
+ }
436
+
437
+ /* Mini thumbnail of the current template's wireframe inside the trigger.
438
+ The underlying SVGs are 56×40; we shrink them via width/height so the
439
+ trigger button stays compact next to other toolbar controls. */
440
+ .squisq-template-picker-trigger-thumb {
441
+ display: inline-flex;
442
+ align-items: center;
443
+ justify-content: center;
444
+ flex-shrink: 0;
445
+ border: 1px solid #e5e7eb;
446
+ border-radius: 3px;
447
+ background: #fff;
448
+ padding: 1px;
449
+ line-height: 0;
450
+ }
451
+ .squisq-template-picker-trigger-thumb svg {
452
+ width: 24px;
453
+ height: 17px;
454
+ display: block;
455
+ }
456
+
457
+ /* When the toolbar is width-constrained, drop the "Block:" label so the
458
+ thumbnail + name + caret can fit. The toolbar root sets
459
+ container-type: inline-size + container-name: squisq-toolbar. */
460
+ @container squisq-toolbar (max-width: 900px) {
461
+ .squisq-template-picker-trigger-label {
462
+ display: none;
463
+ }
464
+ }
465
+
466
+ .squisq-template-picker-trigger-value {
467
+ color: #111827;
468
+ font-weight: 400;
469
+ max-width: 120px;
470
+ overflow: hidden;
471
+ text-overflow: ellipsis;
472
+ }
473
+
474
+ .squisq-template-picker-trigger-caret {
475
+ color: #9ca3af;
476
+ flex-shrink: 0;
477
+ }
478
+
479
+ /* The gallery popover panel — rendered in a portal with fixed positioning */
480
+ .squisq-template-gallery {
481
+ width: 420px;
482
+ max-width: calc(100vw - 24px);
483
+ max-height: 480px;
484
+ overflow-y: auto;
485
+ background: #fff;
486
+ border: 1px solid #e5e7eb;
487
+ border-radius: 10px;
488
+ box-shadow:
489
+ 0 8px 24px rgba(0, 0, 0, 0.12),
490
+ 0 2px 6px rgba(0, 0, 0, 0.06);
491
+ padding: 8px;
492
+ animation: squisq-gallery-appear 0.12s ease-out;
493
+ }
494
+
495
+ @keyframes squisq-gallery-appear {
496
+ from {
497
+ opacity: 0;
498
+ transform: translateY(-4px);
499
+ }
500
+ to {
501
+ opacity: 1;
502
+ transform: translateY(0);
503
+ }
504
+ }
505
+
506
+ /* "— none —" row at the top */
507
+ .squisq-template-gallery-none {
508
+ display: flex;
509
+ align-items: center;
510
+ gap: 10px;
511
+ width: 100%;
512
+ padding: 6px 10px;
513
+ border: 1px solid transparent;
514
+ border-radius: 7px;
515
+ background: none;
516
+ cursor: pointer;
517
+ text-align: left;
518
+ margin-bottom: 6px;
519
+ transition: background 0.1s;
520
+ }
521
+
522
+ .squisq-template-gallery-none:hover {
523
+ background: #f9fafb;
524
+ }
525
+
526
+ .squisq-template-gallery-none.squisq-template-gallery-card--selected {
527
+ background: #eef2ff;
528
+ border-color: #c7d2fe;
529
+ }
530
+
531
+ .squisq-template-gallery-none-label {
532
+ font-size: 12px;
533
+ font-weight: 600;
534
+ color: #6b7280;
535
+ white-space: nowrap;
536
+ }
537
+
538
+ .squisq-template-gallery-none-desc {
539
+ font-size: 11px;
540
+ color: #9ca3af;
541
+ }
542
+
543
+ /* Grid of template cards */
544
+ .squisq-template-gallery-grid {
545
+ display: grid;
546
+ grid-template-columns: 1fr 1fr;
547
+ gap: 6px;
548
+ }
549
+
550
+ @media (min-width: 900px) {
551
+ .squisq-template-gallery {
552
+ width: 780px;
553
+ max-height: 880px;
554
+ }
555
+
556
+ .squisq-template-gallery-grid {
557
+ grid-template-columns: 1fr 1fr 1fr 1fr;
558
+ }
559
+ }
560
+
561
+ /* Individual template card */
562
+ .squisq-template-gallery-card {
563
+ display: flex;
564
+ align-items: flex-start;
565
+ gap: 10px;
566
+ padding: 8px 10px;
567
+ border: 1px solid #e5e7eb;
568
+ border-radius: 7px;
569
+ background: none;
570
+ cursor: pointer;
571
+ text-align: left;
572
+ transition:
573
+ background 0.1s,
574
+ border-color 0.1s,
575
+ box-shadow 0.1s;
576
+ }
577
+
578
+ .squisq-template-gallery-card:hover {
579
+ background: #f9fafb;
580
+ border-color: #a5b4fc;
581
+ box-shadow: 0 1px 4px rgba(99, 102, 241, 0.1);
582
+ }
583
+
584
+ .squisq-template-gallery-card--selected {
585
+ background: #eef2ff;
586
+ border-color: #6366f1;
587
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15);
588
+ }
589
+
590
+ .squisq-template-gallery-card-icon {
591
+ flex-shrink: 0;
592
+ border-radius: 4px;
593
+ overflow: hidden;
594
+ background: #f8fafc;
595
+ border: 1px solid #e5e7eb;
596
+ line-height: 0;
597
+ }
598
+
599
+ .squisq-template-picker-icon {
600
+ display: block;
601
+ }
602
+
603
+ .squisq-template-gallery-card-body {
604
+ display: flex;
605
+ flex-direction: column;
606
+ gap: 3px;
607
+ min-width: 0;
608
+ }
609
+
610
+ .squisq-template-gallery-card-name {
611
+ font-size: 12px;
612
+ font-weight: 600;
613
+ color: #111827;
614
+ line-height: 1.3;
615
+ }
616
+
617
+ .squisq-template-gallery-card-desc {
618
+ font-size: 11px;
619
+ color: #6b7280;
620
+ line-height: 1.4;
621
+ }
622
+
623
+ /* Recommended / All templates segmentation */
624
+ .squisq-template-gallery-section + .squisq-template-gallery-section {
625
+ margin-top: 14px;
626
+ padding-top: 10px;
627
+ border-top: 1px solid #e5e7eb;
628
+ }
629
+
630
+ .squisq-template-gallery-section-title {
631
+ margin: 4px 4px 8px;
632
+ font-size: 10px;
633
+ font-weight: 700;
634
+ color: #6b7280;
635
+ text-transform: uppercase;
636
+ letter-spacing: 0.06em;
637
+ }
638
+
639
+ .squisq-editor-shell[data-theme='dark']
640
+ .squisq-template-gallery-section
641
+ + .squisq-template-gallery-section {
642
+ border-top-color: #374151;
643
+ }
644
+
645
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery-section-title {
646
+ color: #9ca3af;
647
+ }
648
+
367
649
  /* ─── Tooltip (portal) ────────────────────────────────── */
368
650
 
369
651
  .squisq-tooltip {
@@ -395,11 +677,12 @@
395
677
  .squisq-template-badge {
396
678
  display: inline-flex;
397
679
  align-items: center;
680
+ gap: 4px;
398
681
  margin-left: 8px;
399
- padding: 1px 7px;
682
+ padding: 1px 6px 1px 8px;
400
683
  font-size: 11px;
401
684
  font-weight: 600;
402
- font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
685
+ font-family: inherit;
403
686
  color: #6d28d9;
404
687
  background: #ede9fe;
405
688
  border: 1px solid #c4b5fd;
@@ -407,10 +690,64 @@
407
690
  vertical-align: middle;
408
691
  user-select: none;
409
692
  line-height: 1.6;
693
+ cursor: pointer;
694
+ transition:
695
+ background 0.15s ease,
696
+ border-color 0.15s ease;
697
+ }
698
+
699
+ .squisq-template-badge:hover,
700
+ .squisq-template-badge:focus-visible {
701
+ background: #ddd6fe;
702
+ border-color: #a78bfa;
703
+ outline: none;
704
+ }
705
+
706
+ .squisq-template-badge::before {
707
+ content: attr(data-template-label);
410
708
  }
411
709
 
412
710
  .squisq-template-badge::after {
413
- content: attr(data-template);
711
+ content: '▾';
712
+ font-size: 9px;
713
+ line-height: 1;
714
+ opacity: 0.7;
715
+ }
716
+
717
+ /* Empty variant — subtle affordance on plain headings that opens the
718
+ * template picker. Quiet by default, brightens when the heading is
719
+ * hovered, fully styled on direct hover/focus. */
720
+ .squisq-template-badge.squisq-template-badge--empty {
721
+ color: #94a3b8;
722
+ background: transparent;
723
+ border-color: #d1d5db;
724
+ border-style: dashed;
725
+ opacity: 0.5;
726
+ }
727
+
728
+ .squisq-template-badge.squisq-template-badge--empty::before {
729
+ content: 'Block';
730
+ font-weight: 500;
731
+ }
732
+
733
+ :is(h1, h2, h3, h4, h5, h6):hover > .squisq-template-badge--empty {
734
+ opacity: 0.9;
735
+ }
736
+
737
+ .squisq-template-badge.squisq-template-badge--empty:hover,
738
+ .squisq-template-badge.squisq-template-badge--empty:focus-visible {
739
+ opacity: 1;
740
+ color: #6d28d9;
741
+ background: #ede9fe;
742
+ border-color: #c4b5fd;
743
+ border-style: solid;
744
+ }
745
+
746
+ /* Hide block-template chips when the View menu toggles them off. The
747
+ * underlying `data-template` heading attribute is untouched — only the
748
+ * inline visual affordance disappears. */
749
+ .squisq-wysiwyg-container[data-block-tags='hidden'] .squisq-template-badge {
750
+ display: none;
414
751
  }
415
752
 
416
753
  /* ─── Status Bar ─────────────────────────────────────── */
@@ -459,8 +796,61 @@
459
796
  margin: 0 auto;
460
797
  outline: none;
461
798
  min-height: 100%;
462
- background: #fff;
799
+ /* When the WYSIWYG container is set to inherit theme colors (View menu →
800
+ "Theme styling: Fonts & colors"), --squisq-theme-bg / --squisq-theme-text
801
+ are populated from the active Squisq theme. Otherwise the editor falls
802
+ back to its default light surface. */
803
+ color: var(--squisq-theme-text, #1f2937);
804
+ background: var(--squisq-theme-bg, #fff);
463
805
  box-shadow: 0 2px 14px rgba(0, 0, 0, 0.12);
806
+ /* Body font follows the active squisq theme when one is selected; the
807
+ fallback inherits from the host page when it isn't. */
808
+ font-family: var(--squisq-theme-body-font, inherit);
809
+ /* Explicit caret color so the blinking insertion point stays visible
810
+ even when an ancestor (e.g. a DocBlocks shell with the OS in dark
811
+ mode) inherits a near-white color into the editor. Without this
812
+ `caret-color: auto` follows the inherited `color`, which can end up
813
+ white-on-white in the WYSIWYG surface. */
814
+ caret-color: var(--squisq-theme-text, #1f2937);
815
+ /* Custom I-beam mouse cursor so the pointer stays visible on the
816
+ editor's white surface even when the OS is configured to render
817
+ cursors in white (Windows lets users do this). The SVG draws a
818
+ dark I-beam with a thin white halo so it reads on both light and
819
+ dark editor backgrounds. Hotspot is the centerline (8,11). The
820
+ final `text` keyword is the fallback when the URL fails to load. */
821
+ cursor:
822
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='22' viewBox='0 0 16 22'><g fill='none' stroke-linecap='round'><path d='M5 3 L11 3 M5 19 L11 19 M8 3 L8 19' stroke='white' stroke-width='3.2'/><path d='M5 3 L11 3 M5 19 L11 19 M8 3 L8 19' stroke='%231f2937' stroke-width='1.4'/></g></svg>")
823
+ 8 11,
824
+ text;
825
+ }
826
+
827
+ /* ── Drop cursor (I-beam) ─────────────────────────────────────
828
+ ProseMirror's Dropcursor extension (bundled with StarterKit) renders
829
+ a horizontal bar at the prospective drop position when an image or
830
+ any other node is being dragged inside the document. The default
831
+ styling is a 1px black line that's easy to miss against body text,
832
+ so we beef it up to a 3px accent-coloured bar with rounded ends. */
833
+ .squisq-wysiwyg-editor .prosemirror-dropcursor-block,
834
+ .squisq-wysiwyg-editor .prosemirror-dropcursor-inline {
835
+ background: var(--squisq-editor-accent, #4a9eff) !important;
836
+ border-radius: 2px;
837
+ }
838
+ .squisq-wysiwyg-editor .prosemirror-dropcursor-block {
839
+ height: 3px !important;
840
+ }
841
+ .squisq-wysiwyg-editor .prosemirror-dropcursor-inline {
842
+ width: 3px !important;
843
+ }
844
+
845
+ .squisq-wysiwyg-editor h1,
846
+ .squisq-wysiwyg-editor h2,
847
+ .squisq-wysiwyg-editor h3,
848
+ .squisq-wysiwyg-editor h4,
849
+ .squisq-wysiwyg-editor h5,
850
+ .squisq-wysiwyg-editor h6 {
851
+ /* Headings pick up the theme's titleFont; fall through to body when
852
+ no theme is active. */
853
+ font-family: var(--squisq-theme-title-font, var(--squisq-theme-body-font, inherit));
464
854
  }
465
855
 
466
856
  .squisq-wysiwyg-editor h1 {
@@ -494,15 +884,21 @@
494
884
  }
495
885
 
496
886
  .squisq-wysiwyg-editor blockquote {
497
- border-left: 3px solid #d1d5db;
887
+ border-left: 3px solid var(--squisq-theme-text-muted, #d1d5db);
498
888
  padding-left: 16px;
499
889
  margin: 0.5em 0;
500
- color: #6b7280;
890
+ color: var(--squisq-theme-text-muted, #6b7280);
501
891
  }
502
892
 
893
+ /* Inline `code` and `<pre>` blocks: the foreground / background draw from
894
+ the active theme when the WYSIWYG container inherits theme colors
895
+ (View menu → "Editor styling from theme: Fonts & colors"). The
896
+ fallbacks preserve the historical light-mode look when no theme is
897
+ active. Dark-mode overrides below adapt the same fallbacks for the
898
+ editor's own dark chrome. */
503
899
  .squisq-wysiwyg-editor pre {
504
- background: #1e293b;
505
- color: #e2e8f0;
900
+ background: var(--squisq-theme-bg-muted, #1e293b);
901
+ color: var(--squisq-theme-text, #e2e8f0);
506
902
  padding: 12px 16px;
507
903
  border-radius: 6px;
508
904
  overflow-x: auto;
@@ -511,7 +907,8 @@
511
907
  }
512
908
 
513
909
  .squisq-wysiwyg-editor code {
514
- background: #f1f5f9;
910
+ background: var(--squisq-theme-bg-muted, #f1f5f9);
911
+ color: var(--squisq-theme-text, inherit);
515
912
  padding: 1px 4px;
516
913
  border-radius: 3px;
517
914
  font-size: 0.9em;
@@ -681,9 +1078,22 @@
681
1078
  min-width: 0;
682
1079
  }
683
1080
 
1081
+ /* Link color follows the active theme's primary when "Theme styling →
1082
+ Fonts & colors" is on, otherwise falls back to the historical blue.
1083
+ In both cases we blend toward the surface text color so the link
1084
+ reads cleanly against the background — some themes (Gezellig) pick a
1085
+ mid-tone primary that's nearly invisible on a dark page when used
1086
+ neat. The fallback `--squisq-theme-text: #1f2937` matches the
1087
+ default editor chrome. */
684
1088
  .squisq-wysiwyg-editor a {
685
- color: #2563eb;
1089
+ color: color-mix(
1090
+ in srgb,
1091
+ var(--squisq-theme-primary, #2563eb) 65%,
1092
+ var(--squisq-theme-text, #1f2937)
1093
+ );
686
1094
  text-decoration: underline;
1095
+ text-decoration-thickness: 1px;
1096
+ text-underline-offset: 2px;
687
1097
  }
688
1098
 
689
1099
  /* Tiptap placeholder */
@@ -865,69 +1275,171 @@
865
1275
  border-color: #4b5563;
866
1276
  }
867
1277
 
868
- /* Template badge (dark) */
869
- .squisq-editor-shell[data-theme='dark'] .squisq-template-badge {
870
- color: #a78bfa;
871
- background: #2e1065;
872
- border-color: #6d28d9;
1278
+ /* Template Gallery Popover (dark) */
1279
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-picker-trigger {
1280
+ background: #1f2937;
1281
+ color: #e5e7eb;
1282
+ border-color: #4b5563;
873
1283
  }
874
1284
 
875
- /* Status Bar */
876
- .squisq-editor-shell[data-theme='dark'] .squisq-status-bar {
877
- border-top-color: #374151;
878
- background: #1f2937;
879
- color: #9ca3af;
1285
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-picker-trigger:hover {
1286
+ background: #374151;
1287
+ border-color: #6b7280;
880
1288
  }
881
1289
 
882
- .squisq-editor-shell[data-theme='dark'] .squisq-status-ok {
883
- color: #34d399;
1290
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-picker-trigger--open {
1291
+ background: #374151;
1292
+ border-color: #818cf8;
884
1293
  }
885
1294
 
886
- .squisq-editor-shell[data-theme='dark'] .squisq-status-error {
887
- color: #f87171;
1295
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-picker-trigger-label {
1296
+ color: #9ca3af;
888
1297
  }
889
1298
 
890
- .squisq-editor-shell[data-theme='dark'] .squisq-status-parsing {
891
- color: #fbbf24;
1299
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-picker-trigger-value {
1300
+ color: #f9fafb;
892
1301
  }
893
1302
 
894
- /* WYSIWYG Editor */
895
- .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-container {
896
- background: #0f1219;
1303
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery {
1304
+ background: #1f2937;
1305
+ border-color: #374151;
1306
+ box-shadow:
1307
+ 0 8px 24px rgba(0, 0, 0, 0.4),
1308
+ 0 2px 6px rgba(0, 0, 0, 0.2);
897
1309
  }
898
1310
 
899
- .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor {
900
- color: #e5e7eb;
901
- background: #111827;
902
- box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
1311
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery-none:hover {
1312
+ background: #374151;
903
1313
  }
904
1314
 
905
- .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor blockquote {
906
- border-left-color: #4b5563;
1315
+ .squisq-editor-shell[data-theme='dark']
1316
+ .squisq-template-gallery-none.squisq-template-gallery-card--selected {
1317
+ background: #1e1b4b;
1318
+ border-color: #4338ca;
1319
+ }
1320
+
1321
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery-none-label {
907
1322
  color: #9ca3af;
908
1323
  }
909
1324
 
910
- .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor pre {
911
- background: #0f172a;
912
- color: #e2e8f0;
1325
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery-none-desc {
1326
+ color: #6b7280;
913
1327
  }
914
1328
 
915
- .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor code {
1329
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery-card {
1330
+ border-color: #374151;
1331
+ }
1332
+
1333
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery-card:hover {
916
1334
  background: #374151;
917
- color: #e5e7eb;
1335
+ border-color: #6366f1;
918
1336
  }
919
1337
 
920
- .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor pre code {
921
- background: none;
1338
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery-card--selected {
1339
+ background: #1e1b4b;
1340
+ border-color: #818cf8;
1341
+ box-shadow: 0 0 0 2px rgba(129, 140, 248, 0.2);
922
1342
  }
923
1343
 
924
- .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor hr {
925
- border-top-color: #374151;
1344
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery-card-icon {
1345
+ background: #111827;
1346
+ border-color: #374151;
926
1347
  }
927
1348
 
928
- .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor th,
929
- .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor td {
930
- border-color: #4b5563;
1349
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery-card-name {
1350
+ color: #f3f4f6;
1351
+ }
1352
+
1353
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-gallery-card-desc {
1354
+ color: #9ca3af;
1355
+ }
1356
+
1357
+ /* Template badge (dark) */
1358
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-badge {
1359
+ color: #a78bfa;
1360
+ background: #2e1065;
1361
+ border-color: #6d28d9;
1362
+ }
1363
+
1364
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-badge.squisq-template-badge--empty {
1365
+ color: #64748b;
1366
+ background: transparent;
1367
+ border-color: #374151;
1368
+ border-style: dashed;
1369
+ }
1370
+
1371
+ .squisq-editor-shell[data-theme='dark'] .squisq-template-badge.squisq-template-badge--empty:hover,
1372
+ .squisq-editor-shell[data-theme='dark']
1373
+ .squisq-template-badge.squisq-template-badge--empty:focus-visible {
1374
+ color: #c4b5fd;
1375
+ background: #2e1065;
1376
+ border-color: #6d28d9;
1377
+ border-style: solid;
1378
+ }
1379
+
1380
+ /* Status Bar */
1381
+ .squisq-editor-shell[data-theme='dark'] .squisq-status-bar {
1382
+ border-top-color: #374151;
1383
+ background: #1f2937;
1384
+ color: #9ca3af;
1385
+ }
1386
+
1387
+ .squisq-editor-shell[data-theme='dark'] .squisq-status-ok {
1388
+ color: #34d399;
1389
+ }
1390
+
1391
+ .squisq-editor-shell[data-theme='dark'] .squisq-status-error {
1392
+ color: #f87171;
1393
+ }
1394
+
1395
+ .squisq-editor-shell[data-theme='dark'] .squisq-status-parsing {
1396
+ color: #fbbf24;
1397
+ }
1398
+
1399
+ /* WYSIWYG Editor */
1400
+ .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-container {
1401
+ background: #0f1219;
1402
+ }
1403
+
1404
+ .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor {
1405
+ color: #e5e7eb;
1406
+ background: #111827;
1407
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
1408
+ caret-color: #e5e7eb;
1409
+ /* Light-stroked I-beam for the dark editor surface — same shape as
1410
+ the light-mode cursor but inverted colors so it contrasts on dark. */
1411
+ cursor:
1412
+ url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='22' viewBox='0 0 16 22'><g fill='none' stroke-linecap='round'><path d='M5 3 L11 3 M5 19 L11 19 M8 3 L8 19' stroke='%23111827' stroke-width='3.2'/><path d='M5 3 L11 3 M5 19 L11 19 M8 3 L8 19' stroke='%23e5e7eb' stroke-width='1.4'/></g></svg>")
1413
+ 8 11,
1414
+ text;
1415
+ }
1416
+
1417
+ .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor blockquote {
1418
+ border-left-color: #4b5563;
1419
+ color: #9ca3af;
1420
+ }
1421
+
1422
+ .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor pre {
1423
+ background: var(--squisq-theme-bg-muted, #0f172a);
1424
+ color: var(--squisq-theme-text, #e2e8f0);
1425
+ }
1426
+
1427
+ .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor code {
1428
+ background: var(--squisq-theme-bg-muted, #374151);
1429
+ color: var(--squisq-theme-text, #e5e7eb);
1430
+ }
1431
+
1432
+ .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor pre code {
1433
+ background: none;
1434
+ }
1435
+
1436
+ .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor hr {
1437
+ border-top-color: #374151;
1438
+ }
1439
+
1440
+ .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor th,
1441
+ .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor td {
1442
+ border-color: #4b5563;
931
1443
  }
932
1444
 
933
1445
  .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor th {
@@ -956,7 +1468,16 @@
956
1468
  }
957
1469
 
958
1470
  .squisq-editor-shell[data-theme='dark'] .squisq-wysiwyg-editor a {
959
- color: #60a5fa;
1471
+ /* Dark-chrome fallback: when no theme is providing
1472
+ --squisq-theme-primary, blend the dark-chrome blue with the dark-
1473
+ chrome text color so the link still has enough lift. Themed
1474
+ surfaces (Fonts & colors) override this via the rule above using
1475
+ their own primary, so we don't need a separate dark-themed mix. */
1476
+ color: color-mix(
1477
+ in srgb,
1478
+ var(--squisq-theme-primary, #60a5fa) 65%,
1479
+ var(--squisq-theme-text, #e5e7eb)
1480
+ );
960
1481
  }
961
1482
 
962
1483
  .squisq-editor-shell[data-theme='dark']
@@ -1435,3 +1956,1921 @@
1435
1956
  color: rgba(255, 255, 255, 0.6);
1436
1957
  }
1437
1958
  }
1959
+
1960
+ /* ─── Image Viewer ───────────────────────────────────── */
1961
+
1962
+ .squisq-image-viewer {
1963
+ display: flex;
1964
+ flex-direction: column;
1965
+ width: 100%;
1966
+ height: 100%;
1967
+ background: #f3f4f6;
1968
+ /* Subtle checkerboard so transparent PNGs are visible without dominating
1969
+ the chrome. Anchored to the stage element below. */
1970
+ }
1971
+
1972
+ .squisq-image-viewer-stage {
1973
+ flex: 1;
1974
+ position: relative;
1975
+ overflow: hidden;
1976
+ display: flex;
1977
+ align-items: center;
1978
+ justify-content: center;
1979
+ background-color: #f3f4f6;
1980
+ background-image:
1981
+ linear-gradient(45deg, #e5e7eb 25%, transparent 25%),
1982
+ linear-gradient(-45deg, #e5e7eb 25%, transparent 25%),
1983
+ linear-gradient(45deg, transparent 75%, #e5e7eb 75%),
1984
+ linear-gradient(-45deg, transparent 75%, #e5e7eb 75%);
1985
+ background-size: 16px 16px;
1986
+ background-position:
1987
+ 0 0,
1988
+ 0 8px,
1989
+ 8px -8px,
1990
+ -8px 0;
1991
+ user-select: none;
1992
+ }
1993
+
1994
+ .squisq-image-viewer-img {
1995
+ display: block;
1996
+ max-width: 100%;
1997
+ max-height: 100%;
1998
+ image-rendering: auto;
1999
+ pointer-events: none;
2000
+ }
2001
+
2002
+ .squisq-image-viewer-error {
2003
+ color: #b91c1c;
2004
+ font-size: 13px;
2005
+ }
2006
+
2007
+ .squisq-image-viewer-toolbar {
2008
+ position: absolute;
2009
+ top: 8px;
2010
+ right: 8px;
2011
+ display: flex;
2012
+ gap: 2px;
2013
+ padding: 2px;
2014
+ border-radius: 6px;
2015
+ background: rgba(255, 255, 255, 0.92);
2016
+ border: 1px solid rgba(0, 0, 0, 0.08);
2017
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
2018
+ }
2019
+
2020
+ .squisq-image-viewer-btn {
2021
+ appearance: none;
2022
+ border: none;
2023
+ background: transparent;
2024
+ padding: 4px 8px;
2025
+ border-radius: 4px;
2026
+ cursor: pointer;
2027
+ font-size: 12px;
2028
+ color: #1f2937;
2029
+ min-width: 28px;
2030
+ }
2031
+
2032
+ .squisq-image-viewer-btn:hover {
2033
+ background: rgba(0, 0, 0, 0.06);
2034
+ }
2035
+
2036
+ .squisq-image-viewer-btn[aria-pressed='true'] {
2037
+ background: rgba(88, 101, 242, 0.15);
2038
+ color: #4338ca;
2039
+ }
2040
+
2041
+ .squisq-image-viewer-status {
2042
+ display: flex;
2043
+ justify-content: space-between;
2044
+ gap: 12px;
2045
+ padding: 4px 10px;
2046
+ font-size: 11px;
2047
+ color: #6b7280;
2048
+ background: #f9fafb;
2049
+ border-top: 1px solid #e5e7eb;
2050
+ }
2051
+
2052
+ .squisq-image-viewer--dark {
2053
+ background: #111827;
2054
+ }
2055
+
2056
+ .squisq-image-viewer--dark .squisq-image-viewer-stage {
2057
+ background-color: #111827;
2058
+ background-image:
2059
+ linear-gradient(45deg, #1f2937 25%, transparent 25%),
2060
+ linear-gradient(-45deg, #1f2937 25%, transparent 25%),
2061
+ linear-gradient(45deg, transparent 75%, #1f2937 75%),
2062
+ linear-gradient(-45deg, transparent 75%, #1f2937 75%);
2063
+ }
2064
+
2065
+ .squisq-image-viewer--dark .squisq-image-viewer-toolbar {
2066
+ background: rgba(31, 41, 55, 0.92);
2067
+ border-color: rgba(255, 255, 255, 0.12);
2068
+ }
2069
+
2070
+ .squisq-image-viewer--dark .squisq-image-viewer-btn {
2071
+ color: #e5e7eb;
2072
+ }
2073
+
2074
+ .squisq-image-viewer--dark .squisq-image-viewer-btn:hover {
2075
+ background: rgba(255, 255, 255, 0.08);
2076
+ }
2077
+
2078
+ .squisq-image-viewer--dark .squisq-image-viewer-btn[aria-pressed='true'] {
2079
+ background: rgba(128, 140, 255, 0.22);
2080
+ color: #c7d2fe;
2081
+ }
2082
+
2083
+ .squisq-image-viewer--dark .squisq-image-viewer-status {
2084
+ color: #9ca3af;
2085
+ background: #0b1020;
2086
+ border-top-color: rgba(255, 255, 255, 0.08);
2087
+ }
2088
+
2089
+ /* ─── Version History ────────────────────────────────── */
2090
+
2091
+ .squisq-version-history {
2092
+ position: relative;
2093
+ flex-shrink: 0;
2094
+ margin-left: 2px;
2095
+ }
2096
+
2097
+ .squisq-version-history-popover {
2098
+ position: absolute;
2099
+ top: 100%;
2100
+ right: 0;
2101
+ z-index: 90;
2102
+ min-width: 280px;
2103
+ max-width: 360px;
2104
+ margin-top: 4px;
2105
+ padding: 8px 0;
2106
+ background: var(--squisq-bg, #fff);
2107
+ border: 1px solid var(--squisq-border, #e5e7eb);
2108
+ border-radius: 6px;
2109
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
2110
+ color: var(--squisq-text, #1f2937);
2111
+ }
2112
+
2113
+ /* When a snapshot is selected, the popover expands and lays out the diff
2114
+ to the left of the version list. The diff column flexes; the list
2115
+ column stays a fixed width so the times/sizes don't reflow. */
2116
+ .squisq-version-history-popover--with-diff {
2117
+ display: flex;
2118
+ flex-direction: row;
2119
+ align-items: stretch;
2120
+ width: min(960px, 90vw);
2121
+ min-width: 720px;
2122
+ max-width: none;
2123
+ padding: 0;
2124
+ }
2125
+
2126
+ .squisq-version-history-popover--with-diff .squisq-version-history-list-pane {
2127
+ width: 280px;
2128
+ flex-shrink: 0;
2129
+ border-left: 1px solid var(--squisq-border, #e5e7eb);
2130
+ padding: 8px 0;
2131
+ overflow-y: auto;
2132
+ max-height: 480px;
2133
+ }
2134
+
2135
+ .squisq-version-history-diff {
2136
+ flex: 1 1 auto;
2137
+ display: flex;
2138
+ flex-direction: column;
2139
+ min-width: 0;
2140
+ }
2141
+
2142
+ .squisq-version-history-diff-header {
2143
+ display: flex;
2144
+ justify-content: space-between;
2145
+ gap: 8px;
2146
+ padding: 8px 12px;
2147
+ border-bottom: 1px solid var(--squisq-border, #e5e7eb);
2148
+ font-size: 11px;
2149
+ color: var(--squisq-text-muted, #6b7280);
2150
+ text-transform: uppercase;
2151
+ letter-spacing: 0.04em;
2152
+ }
2153
+
2154
+ .squisq-version-history-diff-label strong {
2155
+ color: var(--squisq-text, #1f2937);
2156
+ font-weight: 600;
2157
+ margin-right: 6px;
2158
+ text-transform: none;
2159
+ letter-spacing: 0;
2160
+ }
2161
+
2162
+ .squisq-version-history-diff-body {
2163
+ flex: 1 1 auto;
2164
+ height: 480px;
2165
+ min-height: 0;
2166
+ }
2167
+
2168
+ .squisq-version-history-header {
2169
+ display: flex;
2170
+ align-items: center;
2171
+ gap: 8px;
2172
+ padding: 4px 12px 8px 12px;
2173
+ border-bottom: 1px solid var(--squisq-border, #e5e7eb);
2174
+ }
2175
+
2176
+ .squisq-version-history-title {
2177
+ font-size: 13px;
2178
+ font-weight: 600;
2179
+ }
2180
+
2181
+ .squisq-version-history-error {
2182
+ padding: 8px 12px;
2183
+ font-size: 12px;
2184
+ color: #b91c1c;
2185
+ background: #fef2f2;
2186
+ }
2187
+
2188
+ .squisq-version-history-empty {
2189
+ padding: 16px 12px;
2190
+ font-size: 12px;
2191
+ color: var(--squisq-text-muted, #6b7280);
2192
+ text-align: center;
2193
+ }
2194
+
2195
+ .squisq-version-history-list {
2196
+ list-style: none;
2197
+ margin: 0;
2198
+ padding: 0;
2199
+ max-height: 320px;
2200
+ overflow-y: auto;
2201
+ }
2202
+
2203
+ .squisq-version-history-row {
2204
+ display: grid;
2205
+ grid-template-columns: 1fr auto;
2206
+ align-items: center;
2207
+ gap: 8px;
2208
+ padding: 0 12px;
2209
+ font-size: 12px;
2210
+ }
2211
+
2212
+ .squisq-version-history-row:hover {
2213
+ background: var(--squisq-row-hover, #f3f4f6);
2214
+ }
2215
+
2216
+ .squisq-version-history-row--selected {
2217
+ background: var(--squisq-row-hover, #e5edff);
2218
+ }
2219
+
2220
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-row--selected {
2221
+ background: #2a3a52;
2222
+ }
2223
+
2224
+ /* The synthetic "Current" row at the top represents the live editor
2225
+ draft. It's clickable (selecting it deselects any snapshot, hiding the
2226
+ diff) and gets a subtle separator below it so it reads apart from the
2227
+ list of saved snapshots. */
2228
+ .squisq-version-history-row--current {
2229
+ border-bottom: 1px solid var(--squisq-border, #e5e7eb);
2230
+ margin-bottom: 4px;
2231
+ padding-bottom: 2px;
2232
+ }
2233
+
2234
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-row--current {
2235
+ border-color: #374151;
2236
+ }
2237
+
2238
+ .squisq-version-history-row-select {
2239
+ display: flex;
2240
+ align-items: center;
2241
+ gap: 8px;
2242
+ background: none;
2243
+ border: none;
2244
+ padding: 6px 0;
2245
+ margin: 0;
2246
+ font: inherit;
2247
+ color: inherit;
2248
+ text-align: left;
2249
+ cursor: pointer;
2250
+ }
2251
+
2252
+ .squisq-version-history-row__time {
2253
+ font-variant-numeric: tabular-nums;
2254
+ }
2255
+
2256
+ .squisq-version-history-row__size {
2257
+ color: var(--squisq-text-muted, #6b7280);
2258
+ font-variant-numeric: tabular-nums;
2259
+ }
2260
+
2261
+ .squisq-version-history-row__actions {
2262
+ display: flex;
2263
+ gap: 8px;
2264
+ padding: 6px 0;
2265
+ }
2266
+
2267
+ .squisq-version-history-link {
2268
+ border: none;
2269
+ background: transparent;
2270
+ padding: 0;
2271
+ color: #2563eb;
2272
+ font: inherit;
2273
+ cursor: pointer;
2274
+ }
2275
+
2276
+ .squisq-version-history-link:hover {
2277
+ text-decoration: underline;
2278
+ }
2279
+
2280
+ .squisq-version-history-link--primary {
2281
+ color: #b91c1c;
2282
+ font-weight: 600;
2283
+ }
2284
+
2285
+ .squisq-version-history-confirm {
2286
+ grid-column: 1 / -1;
2287
+ display: flex;
2288
+ flex-direction: column;
2289
+ gap: 6px;
2290
+ padding: 8px;
2291
+ margin-top: 6px;
2292
+ background: var(--squisq-row-hover, #f3f4f6);
2293
+ border-radius: 4px;
2294
+ font-size: 12px;
2295
+ }
2296
+
2297
+ .squisq-version-history-confirm-actions {
2298
+ display: flex;
2299
+ justify-content: flex-end;
2300
+ gap: 12px;
2301
+ }
2302
+
2303
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-popover {
2304
+ background: #1f2937;
2305
+ border-color: #374151;
2306
+ color: #d1d5db;
2307
+ }
2308
+
2309
+ .squisq-editor-shell[data-theme='dark']
2310
+ .squisq-version-history-popover--with-diff
2311
+ .squisq-version-history-list-pane {
2312
+ border-color: #374151;
2313
+ }
2314
+
2315
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-diff-header {
2316
+ border-color: #374151;
2317
+ }
2318
+
2319
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-diff-label strong {
2320
+ color: #d1d5db;
2321
+ }
2322
+
2323
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-header {
2324
+ border-color: #374151;
2325
+ }
2326
+
2327
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-row:hover {
2328
+ background: #374151;
2329
+ }
2330
+
2331
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-row__size {
2332
+ color: #9ca3af;
2333
+ }
2334
+
2335
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-confirm {
2336
+ background: #111827;
2337
+ }
2338
+
2339
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-error {
2340
+ background: rgba(239, 68, 68, 0.1);
2341
+ color: #fca5a5;
2342
+ }
2343
+
2344
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-link {
2345
+ color: #93c5fd;
2346
+ }
2347
+
2348
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-link--primary {
2349
+ color: #fca5a5;
2350
+ }
2351
+
2352
+ .squisq-editor-shell[data-theme='dark'] .squisq-version-history-preview {
2353
+ background: #0b1020;
2354
+ border-color: #374151;
2355
+ }
2356
+
2357
+ /* ─── View Menu ─────────────────────────────────────────────────── */
2358
+
2359
+ .squisq-view-menu {
2360
+ position: relative;
2361
+ flex-shrink: 0;
2362
+ margin-left: 2px;
2363
+ }
2364
+
2365
+ .squisq-view-menu-popover {
2366
+ position: absolute;
2367
+ top: 100%;
2368
+ right: 0;
2369
+ z-index: 90;
2370
+ min-width: 200px;
2371
+ margin-top: 4px;
2372
+ padding: 6px 0;
2373
+ background: var(--squisq-bg, #fff);
2374
+ border: 1px solid var(--squisq-border, #e5e7eb);
2375
+ border-radius: 6px;
2376
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
2377
+ color: var(--squisq-text, #1f2937);
2378
+ }
2379
+
2380
+ .squisq-view-menu-row {
2381
+ display: flex;
2382
+ align-items: center;
2383
+ gap: 8px;
2384
+ padding: 6px 12px;
2385
+ font-size: 13px;
2386
+ cursor: pointer;
2387
+ user-select: none;
2388
+ }
2389
+
2390
+ .squisq-view-menu-row:hover {
2391
+ background: var(--squisq-row-hover, #f3f4f6);
2392
+ }
2393
+
2394
+ .squisq-view-menu-checkbox {
2395
+ margin: 0;
2396
+ cursor: pointer;
2397
+ }
2398
+
2399
+ .squisq-view-menu-label {
2400
+ flex: 1;
2401
+ }
2402
+
2403
+ .squisq-view-menu-row--select {
2404
+ flex-direction: column;
2405
+ align-items: stretch;
2406
+ gap: 4px;
2407
+ cursor: default;
2408
+ }
2409
+
2410
+ .squisq-view-menu-row--select:hover {
2411
+ background: transparent;
2412
+ }
2413
+
2414
+ .squisq-view-menu-row--select .squisq-view-menu-label {
2415
+ font-size: 11px;
2416
+ color: var(--squisq-text-muted, #6b7280);
2417
+ text-transform: uppercase;
2418
+ letter-spacing: 0.04em;
2419
+ }
2420
+
2421
+ .squisq-view-menu-select {
2422
+ width: 100%;
2423
+ padding: 4px 8px;
2424
+ font: inherit;
2425
+ font-size: 13px;
2426
+ background: var(--squisq-input-bg, #fff);
2427
+ color: var(--squisq-text, #1f2937);
2428
+ border: 1px solid var(--squisq-border, #d1d5db);
2429
+ border-radius: 4px;
2430
+ cursor: pointer;
2431
+ }
2432
+
2433
+ /* Radio-group variant of --select: same uppercase caption header, but the
2434
+ options render as stacked radio rows instead of a native <select>. */
2435
+ .squisq-view-menu-row--radios {
2436
+ flex-direction: column;
2437
+ align-items: stretch;
2438
+ gap: 2px;
2439
+ cursor: default;
2440
+ }
2441
+
2442
+ .squisq-view-menu-row--radios:hover {
2443
+ background: transparent;
2444
+ }
2445
+
2446
+ .squisq-view-menu-row--radios > .squisq-view-menu-label {
2447
+ font-size: 11px;
2448
+ color: var(--squisq-text-muted, #6b7280);
2449
+ text-transform: uppercase;
2450
+ letter-spacing: 0.04em;
2451
+ margin-bottom: 2px;
2452
+ }
2453
+
2454
+ .squisq-view-menu-radio-row {
2455
+ display: flex;
2456
+ align-items: center;
2457
+ gap: 8px;
2458
+ padding: 4px 4px;
2459
+ font-size: 13px;
2460
+ cursor: pointer;
2461
+ border-radius: 4px;
2462
+ user-select: none;
2463
+ }
2464
+
2465
+ .squisq-view-menu-radio-row:hover {
2466
+ background: var(--squisq-row-hover, #f3f4f6);
2467
+ }
2468
+
2469
+ .squisq-view-menu-radio {
2470
+ margin: 0;
2471
+ cursor: pointer;
2472
+ }
2473
+
2474
+ .squisq-view-menu-radio-label {
2475
+ flex: 1;
2476
+ }
2477
+
2478
+ .squisq-view-menu-separator {
2479
+ height: 1px;
2480
+ background: var(--squisq-border, #e5e7eb);
2481
+ margin: 6px 0;
2482
+ }
2483
+
2484
+ .squisq-editor-shell[data-theme='dark'] .squisq-view-menu-popover {
2485
+ background: #1f2937;
2486
+ border-color: #374151;
2487
+ color: #d1d5db;
2488
+ }
2489
+
2490
+ .squisq-editor-shell[data-theme='dark'] .squisq-view-menu-row:hover {
2491
+ background: #374151;
2492
+ }
2493
+
2494
+ .squisq-editor-shell[data-theme='dark'] .squisq-view-menu-row--select:hover {
2495
+ background: transparent;
2496
+ }
2497
+
2498
+ .squisq-editor-shell[data-theme='dark'] .squisq-view-menu-row--radios:hover {
2499
+ background: transparent;
2500
+ }
2501
+
2502
+ .squisq-editor-shell[data-theme='dark'] .squisq-view-menu-radio-row:hover {
2503
+ background: #374151;
2504
+ }
2505
+
2506
+ .squisq-editor-shell[data-theme='dark'] .squisq-view-menu-select {
2507
+ background: #111827;
2508
+ border-color: #374151;
2509
+ color: #e5e7eb;
2510
+ }
2511
+
2512
+ .squisq-editor-shell[data-theme='dark'] .squisq-view-menu-separator {
2513
+ background: #374151;
2514
+ }
2515
+
2516
+ /* ─── Theme Customizer ──────────────────────────────────────────── */
2517
+
2518
+ .squisq-theme-customizer {
2519
+ position: relative;
2520
+ flex-shrink: 0;
2521
+ margin-left: 2px;
2522
+ }
2523
+
2524
+ .squisq-theme-customizer-popover {
2525
+ position: absolute;
2526
+ top: 100%;
2527
+ right: 0;
2528
+ z-index: 90;
2529
+ width: 360px;
2530
+ max-width: 95vw;
2531
+ margin-top: 4px;
2532
+ background: var(--squisq-bg, #fff);
2533
+ border: 1px solid var(--squisq-border, #e5e7eb);
2534
+ border-radius: 6px;
2535
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
2536
+ color: var(--squisq-text, #1f2937);
2537
+ }
2538
+
2539
+ .squisq-theme-customizer-header {
2540
+ display: flex;
2541
+ align-items: center;
2542
+ padding: 10px 12px;
2543
+ border-bottom: 1px solid var(--squisq-border, #e5e7eb);
2544
+ }
2545
+
2546
+ .squisq-theme-customizer-title {
2547
+ font-size: 13px;
2548
+ font-weight: 600;
2549
+ }
2550
+
2551
+ .squisq-theme-customizer-body {
2552
+ max-height: 70vh;
2553
+ overflow-y: auto;
2554
+ padding: 8px 0;
2555
+ }
2556
+
2557
+ .squisq-theme-customizer-section {
2558
+ padding: 8px 12px;
2559
+ }
2560
+
2561
+ .squisq-theme-customizer-section + .squisq-theme-customizer-section {
2562
+ border-top: 1px solid var(--squisq-border, #f3f4f6);
2563
+ }
2564
+
2565
+ .squisq-theme-customizer-section-title {
2566
+ font-size: 11px;
2567
+ font-weight: 600;
2568
+ text-transform: uppercase;
2569
+ letter-spacing: 0.04em;
2570
+ color: var(--squisq-text-muted, #6b7280);
2571
+ margin-bottom: 6px;
2572
+ }
2573
+
2574
+ .squisq-theme-customizer-section-hint {
2575
+ font-size: 11px;
2576
+ color: var(--squisq-text-muted, #6b7280);
2577
+ margin-bottom: 8px;
2578
+ }
2579
+
2580
+ .squisq-theme-customizer-section-body {
2581
+ display: flex;
2582
+ flex-direction: column;
2583
+ gap: 6px;
2584
+ }
2585
+
2586
+ .squisq-theme-customizer-row {
2587
+ display: grid;
2588
+ grid-template-columns: 88px auto 1fr;
2589
+ align-items: center;
2590
+ gap: 8px;
2591
+ font-size: 12px;
2592
+ }
2593
+
2594
+ .squisq-theme-customizer-row--font {
2595
+ grid-template-columns: 88px 1fr;
2596
+ flex-wrap: wrap;
2597
+ }
2598
+
2599
+ .squisq-theme-customizer-row--font > input,
2600
+ .squisq-theme-customizer-row--font > select:not(:first-of-type) {
2601
+ grid-column: 2 / -1;
2602
+ margin-top: 4px;
2603
+ }
2604
+
2605
+ .squisq-theme-customizer-row-label {
2606
+ font-weight: 500;
2607
+ color: var(--squisq-text, #1f2937);
2608
+ }
2609
+
2610
+ .squisq-theme-customizer-color {
2611
+ width: 28px;
2612
+ height: 24px;
2613
+ padding: 0;
2614
+ border: 1px solid var(--squisq-border, #e5e7eb);
2615
+ border-radius: 4px;
2616
+ background: transparent;
2617
+ cursor: pointer;
2618
+ }
2619
+
2620
+ .squisq-theme-customizer-input {
2621
+ width: 100%;
2622
+ padding: 4px 6px;
2623
+ border: 1px solid var(--squisq-border, #e5e7eb);
2624
+ border-radius: 4px;
2625
+ background: var(--squisq-input-bg, #fff);
2626
+ font: inherit;
2627
+ font-size: 12px;
2628
+ color: inherit;
2629
+ }
2630
+
2631
+ .squisq-theme-customizer-input--hex {
2632
+ font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
2633
+ }
2634
+
2635
+ .squisq-theme-customizer-scale {
2636
+ display: flex;
2637
+ gap: 4px;
2638
+ margin-top: 6px;
2639
+ margin-left: 96px;
2640
+ }
2641
+
2642
+ .squisq-theme-customizer-swatch {
2643
+ width: 24px;
2644
+ height: 16px;
2645
+ border-radius: 3px;
2646
+ border: 1px solid rgba(0, 0, 0, 0.1);
2647
+ display: inline-block;
2648
+ }
2649
+
2650
+ .squisq-theme-customizer-footer {
2651
+ display: flex;
2652
+ justify-content: flex-end;
2653
+ gap: 8px;
2654
+ padding: 10px 12px;
2655
+ border-top: 1px solid var(--squisq-border, #e5e7eb);
2656
+ }
2657
+
2658
+ .squisq-theme-customizer-button {
2659
+ padding: 4px 10px;
2660
+ border: 1px solid var(--squisq-border, #e5e7eb);
2661
+ border-radius: 4px;
2662
+ background: var(--squisq-input-bg, #f9fafb);
2663
+ font: inherit;
2664
+ font-size: 12px;
2665
+ color: inherit;
2666
+ cursor: pointer;
2667
+ }
2668
+
2669
+ .squisq-theme-customizer-button:hover {
2670
+ background: var(--squisq-row-hover, #f3f4f6);
2671
+ }
2672
+
2673
+ .squisq-theme-customizer-button--primary {
2674
+ background: #2563eb;
2675
+ border-color: #2563eb;
2676
+ color: #fff;
2677
+ }
2678
+
2679
+ .squisq-theme-customizer-button--primary:hover {
2680
+ background: #1d4ed8;
2681
+ }
2682
+
2683
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-customizer-popover {
2684
+ background: #1f2937;
2685
+ border-color: #374151;
2686
+ color: #d1d5db;
2687
+ }
2688
+
2689
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-customizer-header,
2690
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-customizer-footer {
2691
+ border-color: #374151;
2692
+ }
2693
+
2694
+ .squisq-editor-shell[data-theme='dark']
2695
+ .squisq-theme-customizer-section
2696
+ + .squisq-theme-customizer-section {
2697
+ border-color: #374151;
2698
+ }
2699
+
2700
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-customizer-input {
2701
+ background: #111827;
2702
+ border-color: #374151;
2703
+ color: #d1d5db;
2704
+ }
2705
+
2706
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-customizer-button {
2707
+ background: #111827;
2708
+ border-color: #374151;
2709
+ color: #d1d5db;
2710
+ }
2711
+
2712
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-customizer-button:hover {
2713
+ background: #374151;
2714
+ }
2715
+
2716
+ /* ─── Inline Preview Gutter ─────────────────────────────────────── */
2717
+
2718
+ /* Wrapper around the active editor + gutters — a flex row inside the
2719
+ editor body. Used by both WYSIWYG and Markdown views. Panes (outline
2720
+ on the left, card-preview gutter on the right) are flex children with
2721
+ fixed widths so the editor naturally shrinks to fit the remaining
2722
+ space; nothing overlaps even when the editor (Monaco or Tiptap) fills
2723
+ the wrapper edge-to-edge by default. */
2724
+ .squisq-editor-with-gutter {
2725
+ display: flex;
2726
+ flex-direction: row;
2727
+ align-items: stretch;
2728
+ width: 100%;
2729
+ height: 100%;
2730
+ min-height: 0;
2731
+ position: relative;
2732
+ container-type: inline-size;
2733
+ container-name: squisq-editor-body;
2734
+ }
2735
+
2736
+ .squisq-editor-with-gutter > .squisq-wysiwyg-container,
2737
+ .squisq-editor-with-gutter > .squisq-wysiwyg-pane,
2738
+ .squisq-editor-with-gutter > .squisq-raw-editor-container {
2739
+ flex: 1 1 auto;
2740
+ min-width: 0;
2741
+ min-height: 0;
2742
+ }
2743
+
2744
+ /* Frame the white code area inside Monaco. The outline + inline-preview
2745
+ panes and Monaco's gutter / overview ruler all share the same beige
2746
+ "desk" color.
2747
+
2748
+ The breathing room between the seam and the first character is faked
2749
+ in two layers:
2750
+
2751
+ 1. RawEditor.tsx sets `lineDecorationsWidth: 22` — 12 more than
2752
+ Monaco's default (10) — which widens the gutter on the right.
2753
+ Monaco's own coordinate math accounts for it, so cursor /
2754
+ hit-testing / selections all stay aligned with the rendered text.
2755
+
2756
+ 2. The right 12px of `.margin` is painted with the canvas background
2757
+ via `.margin::before`, and the seam (`.margin::after`) is moved
2758
+ inward to `right: 12px` so it sits between the real gutter and the
2759
+ fake-canvas strip. From the outside the gutter looks the same
2760
+ width it always did and the breathing room appears to live inside
2761
+ the canvas. */
2762
+ .squisq-raw-editor-container .monaco-editor .margin {
2763
+ position: relative;
2764
+ }
2765
+
2766
+ .squisq-raw-editor-container .monaco-editor .margin::before {
2767
+ content: '';
2768
+ position: absolute;
2769
+ top: 0;
2770
+ right: 0;
2771
+ width: 12px;
2772
+ height: 100%;
2773
+ background: #ffffff;
2774
+ pointer-events: none;
2775
+ z-index: 5;
2776
+ }
2777
+
2778
+ .squisq-raw-editor-container .monaco-editor .margin::after {
2779
+ content: '';
2780
+ position: absolute;
2781
+ top: 0;
2782
+ right: 12px;
2783
+ width: 1px;
2784
+ height: 100%;
2785
+ background: #b0a99a;
2786
+ pointer-events: none;
2787
+ z-index: 10;
2788
+ }
2789
+
2790
+ .squisq-editor-shell[data-theme='dark']
2791
+ .squisq-raw-editor-container
2792
+ .monaco-editor
2793
+ .margin::before {
2794
+ background: #1e1e1e;
2795
+ }
2796
+
2797
+ .squisq-editor-shell[data-theme='dark'] .squisq-raw-editor-container .monaco-editor .margin::after {
2798
+ background: #2a3144;
2799
+ }
2800
+
2801
+ /* The outline pane and the inline-preview gutter are flex children too —
2802
+ each holds a fixed width and the editor takes the remainder. */
2803
+ .squisq-editor-with-gutter > .squisq-outline,
2804
+ .squisq-editor-with-gutter > .squisq-inline-preview-gutter {
2805
+ flex: 0 0 auto;
2806
+ min-height: 0;
2807
+ }
2808
+
2809
+ /* All gutter chrome is parameterized through CSS custom properties so
2810
+ hosts can re-theme without overriding individual rules. Defaults
2811
+ below match the original light-mode values; the dark-mode block
2812
+ further down rebinds them. Hosts override at any selector level
2813
+ (e.g. `.db-shell[data-theme='dark'] .squisq-editor-shell { ... }`). */
2814
+ .squisq-editor-shell {
2815
+ --squisq-preview-accent: #6366f1;
2816
+ --squisq-preview-accent-muted: #94a3b8;
2817
+ --squisq-preview-gutter-bg: #dcd8d0;
2818
+ --squisq-preview-card-bg: #ffffff;
2819
+ --squisq-preview-card-border: #e5e7eb;
2820
+ --squisq-preview-card-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
2821
+ --squisq-preview-card-title: #111827;
2822
+ --squisq-preview-card-svg-bg: #f1f5f9;
2823
+ --squisq-preview-dot-halo: #ffffff;
2824
+ --squisq-preview-empty-bg: #ffffff;
2825
+ --squisq-preview-empty-border: #d1d5db;
2826
+ --squisq-preview-empty-text: #6b7280;
2827
+ }
2828
+
2829
+ .squisq-inline-preview-gutter {
2830
+ /* Tinted to match the WYSIWYG container's "desk" color so this pane
2831
+ reads as part of the same surrounding chrome the Monaco gutter
2832
+ blends into on the other side of the canvas. */
2833
+ padding: 0;
2834
+ background: var(--squisq-preview-gutter-bg);
2835
+ border: none;
2836
+ box-sizing: border-box;
2837
+ font-family: inherit;
2838
+ }
2839
+
2840
+ .squisq-inline-preview-empty {
2841
+ position: absolute;
2842
+ top: 12px;
2843
+ left: 12px;
2844
+ right: 12px;
2845
+ color: var(--squisq-preview-empty-text);
2846
+ font-size: 12px;
2847
+ line-height: 1.4;
2848
+ padding: 12px;
2849
+ text-align: center;
2850
+ border: 1px dashed var(--squisq-preview-empty-border);
2851
+ border-radius: 8px;
2852
+ background: var(--squisq-preview-empty-bg);
2853
+ }
2854
+
2855
+ .squisq-inline-preview-empty p {
2856
+ margin: 0;
2857
+ }
2858
+
2859
+ .squisq-inline-preview-card {
2860
+ display: flex;
2861
+ flex-direction: column;
2862
+ gap: 6px;
2863
+ padding: 8px;
2864
+ background: var(--squisq-preview-card-bg);
2865
+ border: 1px solid var(--squisq-preview-card-border);
2866
+ border-radius: 8px;
2867
+ box-shadow: var(--squisq-preview-card-shadow);
2868
+ transition: top 120ms ease-out;
2869
+ }
2870
+
2871
+ .squisq-inline-preview-card-label {
2872
+ display: flex;
2873
+ flex-direction: row;
2874
+ align-items: baseline;
2875
+ gap: 6px;
2876
+ font-size: 12px;
2877
+ line-height: 1.3;
2878
+ white-space: nowrap;
2879
+ overflow: hidden;
2880
+ }
2881
+
2882
+ .squisq-inline-preview-card-template {
2883
+ font-weight: 600;
2884
+ color: var(--squisq-preview-accent);
2885
+ flex-shrink: 0;
2886
+ }
2887
+
2888
+ .squisq-inline-preview-card-sep {
2889
+ color: var(--squisq-preview-accent-muted);
2890
+ flex-shrink: 0;
2891
+ }
2892
+
2893
+ .squisq-inline-preview-card-title {
2894
+ color: var(--squisq-preview-card-title);
2895
+ font-weight: 500;
2896
+ overflow: hidden;
2897
+ text-overflow: ellipsis;
2898
+ }
2899
+
2900
+ .squisq-inline-preview-card-svg {
2901
+ width: 100%;
2902
+ overflow: hidden;
2903
+ border-radius: 4px;
2904
+ background: var(--squisq-preview-card-svg-bg);
2905
+ }
2906
+
2907
+ /* Vertical bracket line showing each block's editor extent. Lives in the
2908
+ connector strip, anchored to its right edge so the cards sit
2909
+ immediately to its right. The diagonal connector bridges from the
2910
+ vertical line to its card at the heading row. */
2911
+ .squisq-inline-preview-extent {
2912
+ width: 4px;
2913
+ background: var(--squisq-preview-accent);
2914
+ border-radius: 2px;
2915
+ transition:
2916
+ top 120ms ease-out,
2917
+ height 120ms ease-out;
2918
+ }
2919
+
2920
+ /* Untagged blocks get a thinner, lower-contrast bar — they still surface
2921
+ the block's structural reach but recede behind the strong accent bars
2922
+ that pair with cards. */
2923
+ .squisq-inline-preview-extent--untagged {
2924
+ width: 3px;
2925
+ background: var(--squisq-preview-accent-muted);
2926
+ border-radius: 1.5px;
2927
+ }
2928
+
2929
+ /* Diagonal connector SVG colors — the JSX uses inline `stroke`/`fill`
2930
+ presentation attributes so the geometry stays self-contained, but
2931
+ those attributes are weaker than CSS rules and are overridden here
2932
+ so all preview accents flow through the same custom property. */
2933
+ .squisq-inline-preview-connector-svg line {
2934
+ stroke: var(--squisq-preview-accent);
2935
+ }
2936
+ .squisq-inline-preview-connector-svg circle {
2937
+ fill: var(--squisq-preview-accent);
2938
+ stroke: var(--squisq-preview-dot-halo);
2939
+ }
2940
+
2941
+ /* Diagonal connector SVG — drawn directly via <line>/<circle> elements
2942
+ in InlinePreviewGutter; CSS is intentionally minimal so the JSX
2943
+ coordinates remain the source of truth. */
2944
+ .squisq-inline-preview-connector-svg line,
2945
+ .squisq-inline-preview-connector-svg circle {
2946
+ transition:
2947
+ cx 120ms ease-out,
2948
+ cy 120ms ease-out,
2949
+ x1 120ms ease-out,
2950
+ y1 120ms ease-out,
2951
+ x2 120ms ease-out,
2952
+ y2 120ms ease-out;
2953
+ }
2954
+
2955
+ /* Auto-hide the gutter (and its connector strip) when the editor body is
2956
+ too narrow to host both surfaces comfortably. */
2957
+ @container squisq-editor-body (max-width: 720px) {
2958
+ .squisq-inline-preview-gutter,
2959
+ .squisq-inline-preview-connectors,
2960
+ .squisq-outline {
2961
+ display: none;
2962
+ }
2963
+ }
2964
+
2965
+ /* ─── Outline pane ─────────────────────────────────────────────────
2966
+ Left-side companion to the inline preview gutter — a hierarchical
2967
+ tree of the document's headings. Sits as a flex child inside
2968
+ `.squisq-editor-with-gutter`; the editor takes whatever space remains. */
2969
+
2970
+ .squisq-outline {
2971
+ padding: 12px 8px;
2972
+ background: #dcd8d0;
2973
+ font-size: 13px;
2974
+ color: #1f2937;
2975
+ box-sizing: border-box;
2976
+ overflow-y: auto;
2977
+ }
2978
+
2979
+ .squisq-outline-empty {
2980
+ padding: 16px 12px;
2981
+ font-size: 12px;
2982
+ color: #6b7280;
2983
+ text-align: center;
2984
+ }
2985
+
2986
+ .squisq-outline-tree {
2987
+ list-style: none;
2988
+ margin: 0;
2989
+ padding: 0;
2990
+ }
2991
+
2992
+ .squisq-outline-item {
2993
+ margin: 0;
2994
+ }
2995
+
2996
+ .squisq-outline-row {
2997
+ display: flex;
2998
+ align-items: center;
2999
+ gap: 6px;
3000
+ width: 100%;
3001
+ padding: 4px 6px;
3002
+ border: none;
3003
+ background: transparent;
3004
+ text-align: left;
3005
+ font: inherit;
3006
+ color: inherit;
3007
+ cursor: pointer;
3008
+ border-radius: 4px;
3009
+ white-space: nowrap;
3010
+ overflow: hidden;
3011
+ }
3012
+
3013
+ .squisq-outline-row:hover {
3014
+ background: #f3f4f6;
3015
+ }
3016
+
3017
+ .squisq-outline-row-text {
3018
+ overflow: hidden;
3019
+ text-overflow: ellipsis;
3020
+ flex: 1;
3021
+ min-width: 0;
3022
+ }
3023
+
3024
+ /* Depth-based indent. The outermost level still pays a small base
3025
+ inset so all rows visually align inside the pane. */
3026
+ .squisq-outline-row--depth-1 {
3027
+ padding-left: 6px;
3028
+ font-weight: 600;
3029
+ }
3030
+ .squisq-outline-row--depth-2 {
3031
+ padding-left: 18px;
3032
+ font-weight: 500;
3033
+ }
3034
+ .squisq-outline-row--depth-3 {
3035
+ padding-left: 30px;
3036
+ }
3037
+ .squisq-outline-row--depth-4 {
3038
+ padding-left: 42px;
3039
+ color: #475569;
3040
+ }
3041
+ .squisq-outline-row--depth-5 {
3042
+ padding-left: 54px;
3043
+ font-size: 12px;
3044
+ color: #475569;
3045
+ }
3046
+ .squisq-outline-row--depth-6 {
3047
+ padding-left: 66px;
3048
+ font-size: 12px;
3049
+ color: #64748b;
3050
+ }
3051
+
3052
+ /* Template-name chip + current-row highlight inherit the active document
3053
+ * theme's accent via `--squisq-outline-accent` (injected by OutlinePanel
3054
+ * from `previewSettings.activeTheme.colors.primary`). Without a theme
3055
+ * mounted the fallback purple matches the original styling. Soft bg /
3056
+ * border tints are derived from the accent via `color-mix` so any
3057
+ * theme color produces a balanced, low-contrast surface. */
3058
+ .squisq-outline-template-chip {
3059
+ flex-shrink: 0;
3060
+ padding: 1px 6px;
3061
+ font-size: 10px;
3062
+ font-weight: 600;
3063
+ color: var(--squisq-outline-accent, #6d28d9);
3064
+ background: color-mix(in oklch, var(--squisq-outline-accent, #6d28d9) 12%, transparent);
3065
+ border: 1px solid color-mix(in oklch, var(--squisq-outline-accent, #6d28d9) 35%, transparent);
3066
+ border-radius: 8px;
3067
+ line-height: 1.4;
3068
+ }
3069
+
3070
+ .squisq-outline-row--current {
3071
+ background: color-mix(in oklch, var(--squisq-outline-accent, #4338ca) 14%, transparent);
3072
+ color: var(--squisq-outline-accent, #4338ca);
3073
+ }
3074
+
3075
+ /* ── Hover-revealed promote / demote arrows ─────────────────────
3076
+ * The wrap is the row-level flex container. Arrows sit absolutely on
3077
+ * the right edge so they overlay the template chip without causing
3078
+ * layout shift on hover. Their background fills the row's hover tint
3079
+ * so the chip behind them isn't visible while the buttons are active. */
3080
+ .squisq-outline-row-wrap {
3081
+ position: relative;
3082
+ display: flex;
3083
+ align-items: stretch;
3084
+ }
3085
+
3086
+ .squisq-outline-row-wrap .squisq-outline-row {
3087
+ flex: 1;
3088
+ min-width: 0;
3089
+ }
3090
+
3091
+ .squisq-outline-row-actions {
3092
+ position: absolute;
3093
+ top: 50%;
3094
+ right: 2px;
3095
+ transform: translateY(-50%);
3096
+ display: flex;
3097
+ gap: 1px;
3098
+ padding: 1px 2px;
3099
+ border-radius: 4px;
3100
+ opacity: 0;
3101
+ pointer-events: none;
3102
+ background: #f3f4f6;
3103
+ transition: opacity 0.1s ease;
3104
+ }
3105
+
3106
+ .squisq-outline-row-wrap:hover .squisq-outline-row-actions,
3107
+ .squisq-outline-row-wrap:focus-within .squisq-outline-row-actions {
3108
+ opacity: 1;
3109
+ pointer-events: auto;
3110
+ }
3111
+
3112
+ /* When the row is the active one, the actions tint matches the
3113
+ * accent-tinted row background so they blend into the highlight. */
3114
+ .squisq-outline-row-wrap:has(.squisq-outline-row--current) .squisq-outline-row-actions {
3115
+ background: color-mix(in oklch, var(--squisq-outline-accent, #4338ca) 14%, #f3f4f6);
3116
+ }
3117
+
3118
+ /* Keep the row's hover fill while the cursor is on the arrows, since
3119
+ * `:hover` on `.squisq-outline-row` won't match when the pointer leaves
3120
+ * the button onto a sibling. */
3121
+ .squisq-outline-row-wrap:hover .squisq-outline-row:not(.squisq-outline-row--current) {
3122
+ background: #f3f4f6;
3123
+ }
3124
+
3125
+ .squisq-outline-row-arrow {
3126
+ width: 18px;
3127
+ height: 18px;
3128
+ display: flex;
3129
+ align-items: center;
3130
+ justify-content: center;
3131
+ background: transparent;
3132
+ border: none;
3133
+ border-radius: 3px;
3134
+ padding: 0;
3135
+ cursor: pointer;
3136
+ color: #6b7280;
3137
+ transition:
3138
+ background 0.1s ease,
3139
+ color 0.1s ease;
3140
+ }
3141
+
3142
+ .squisq-outline-row-arrow:hover:not(:disabled) {
3143
+ background: rgba(0, 0, 0, 0.08);
3144
+ color: #111827;
3145
+ }
3146
+
3147
+ .squisq-outline-row-arrow:focus-visible {
3148
+ outline: 2px solid var(--squisq-outline-accent, #4338ca);
3149
+ outline-offset: 1px;
3150
+ }
3151
+
3152
+ .squisq-outline-row-arrow:disabled {
3153
+ opacity: 0.3;
3154
+ cursor: default;
3155
+ }
3156
+
3157
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline-row-actions {
3158
+ background: #1f2937;
3159
+ }
3160
+
3161
+ .squisq-editor-shell[data-theme='dark']
3162
+ .squisq-outline-row-wrap:has(.squisq-outline-row--current)
3163
+ .squisq-outline-row-actions {
3164
+ background: color-mix(in oklch, var(--squisq-outline-accent, #4338ca) 32%, #1f2937);
3165
+ }
3166
+
3167
+ .squisq-editor-shell[data-theme='dark']
3168
+ .squisq-outline-row-wrap:hover
3169
+ .squisq-outline-row:not(.squisq-outline-row--current) {
3170
+ background: #1f2937;
3171
+ }
3172
+
3173
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline-row-arrow {
3174
+ color: #9ca3af;
3175
+ }
3176
+
3177
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline-row-arrow:hover:not(:disabled) {
3178
+ background: rgba(255, 255, 255, 0.08);
3179
+ color: #f9fafb;
3180
+ }
3181
+
3182
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline {
3183
+ background: #0f1219;
3184
+ color: #d1d5db;
3185
+ }
3186
+
3187
+ /* Dark-mode rebind for all preview-gutter custom properties. Individual
3188
+ rules below remain as no-ops kept for back-compat with any host CSS
3189
+ that may still target them — the variable redefinition is the single
3190
+ source of truth going forward. */
3191
+ .squisq-editor-shell[data-theme='dark'] {
3192
+ --squisq-preview-accent: #818cf8;
3193
+ --squisq-preview-accent-muted: #475569;
3194
+ --squisq-preview-gutter-bg: #0f1219;
3195
+ --squisq-preview-card-bg: #111827;
3196
+ --squisq-preview-card-border: #1f2937;
3197
+ --squisq-preview-card-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
3198
+ --squisq-preview-card-title: #e5e7eb;
3199
+ --squisq-preview-card-svg-bg: #1e293b;
3200
+ --squisq-preview-dot-halo: #0f172a;
3201
+ --squisq-preview-empty-bg: #111827;
3202
+ --squisq-preview-empty-border: #374151;
3203
+ --squisq-preview-empty-text: #94a3b8;
3204
+ }
3205
+
3206
+ .squisq-editor-shell[data-theme='dark'] .squisq-inline-preview-gutter {
3207
+ background: var(--squisq-preview-gutter-bg);
3208
+ }
3209
+
3210
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline-empty {
3211
+ color: #94a3b8;
3212
+ }
3213
+
3214
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline-row:hover {
3215
+ background: #1f2937;
3216
+ }
3217
+
3218
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline-row--depth-4,
3219
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline-row--depth-5 {
3220
+ color: #94a3b8;
3221
+ }
3222
+
3223
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline-row--depth-6 {
3224
+ color: #6b7280;
3225
+ }
3226
+
3227
+ /* Dark mode keeps the same accent inheritance — but mixes the tint
3228
+ * toward a higher saturation since transparent overlays on a dark
3229
+ * surface read as much weaker than on light. Text color is lifted
3230
+ * toward white so the accent stays legible against dark chrome. */
3231
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline-template-chip {
3232
+ color: color-mix(in oklch, var(--squisq-outline-accent, #6d28d9) 55%, #ffffff);
3233
+ background: color-mix(in oklch, var(--squisq-outline-accent, #6d28d9) 30%, transparent);
3234
+ border-color: color-mix(in oklch, var(--squisq-outline-accent, #6d28d9) 55%, transparent);
3235
+ }
3236
+
3237
+ .squisq-editor-shell[data-theme='dark'] .squisq-outline-row--current {
3238
+ background: color-mix(in oklch, var(--squisq-outline-accent, #4338ca) 32%, transparent);
3239
+ color: color-mix(in oklch, var(--squisq-outline-accent, #4338ca) 55%, #ffffff);
3240
+ }
3241
+
3242
+ /* (Dark-mode preview-gutter chrome flows through the custom-property
3243
+ redefinition above. Individual color rules removed — the base
3244
+ .squisq-inline-preview-* selectors already pull from the same vars
3245
+ that the dark block rebinds.) */
3246
+
3247
+ /* ── Link Dialog ─────────────────────────────────────────────── */
3248
+
3249
+ .squisq-link-dialog-overlay {
3250
+ position: fixed;
3251
+ inset: 0;
3252
+ z-index: 200;
3253
+ display: flex;
3254
+ align-items: center;
3255
+ justify-content: center;
3256
+ background: rgba(0, 0, 0, 0.45);
3257
+ padding: 16px;
3258
+ }
3259
+
3260
+ .squisq-link-dialog {
3261
+ width: 100%;
3262
+ max-width: 440px;
3263
+ background: var(--squisq-bg, #fff);
3264
+ color: var(--squisq-text, #1f2937);
3265
+ border: 1px solid var(--squisq-border, #e5e7eb);
3266
+ border-radius: 8px;
3267
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
3268
+ display: flex;
3269
+ flex-direction: column;
3270
+ }
3271
+
3272
+ .squisq-link-dialog-header {
3273
+ display: flex;
3274
+ align-items: center;
3275
+ justify-content: space-between;
3276
+ padding: 12px 16px;
3277
+ border-bottom: 1px solid var(--squisq-border, #e5e7eb);
3278
+ }
3279
+
3280
+ .squisq-link-dialog-title {
3281
+ margin: 0;
3282
+ font-size: 14px;
3283
+ font-weight: 600;
3284
+ }
3285
+
3286
+ .squisq-link-dialog-close {
3287
+ background: none;
3288
+ border: none;
3289
+ font-size: 20px;
3290
+ line-height: 1;
3291
+ cursor: pointer;
3292
+ color: var(--squisq-text-muted, #6b7280);
3293
+ padding: 0 4px;
3294
+ }
3295
+
3296
+ .squisq-link-dialog-close:hover {
3297
+ color: var(--squisq-text, #1f2937);
3298
+ }
3299
+
3300
+ .squisq-link-dialog-body {
3301
+ padding: 16px;
3302
+ display: flex;
3303
+ flex-direction: column;
3304
+ gap: 12px;
3305
+ }
3306
+
3307
+ .squisq-link-dialog-field {
3308
+ display: flex;
3309
+ flex-direction: column;
3310
+ gap: 4px;
3311
+ }
3312
+
3313
+ .squisq-link-dialog-label {
3314
+ font-size: 12px;
3315
+ font-weight: 500;
3316
+ color: var(--squisq-text-muted, #6b7280);
3317
+ }
3318
+
3319
+ .squisq-link-dialog-input {
3320
+ width: 100%;
3321
+ padding: 6px 10px;
3322
+ font: inherit;
3323
+ font-size: 13px;
3324
+ background: var(--squisq-bg, #fff);
3325
+ color: var(--squisq-text, #1f2937);
3326
+ border: 1px solid var(--squisq-border, #d1d5db);
3327
+ border-radius: 4px;
3328
+ outline: none;
3329
+ box-sizing: border-box;
3330
+ }
3331
+
3332
+ .squisq-link-dialog-input:focus {
3333
+ border-color: #3b82f6;
3334
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
3335
+ }
3336
+
3337
+ .squisq-link-dialog-footer {
3338
+ display: flex;
3339
+ justify-content: flex-end;
3340
+ gap: 8px;
3341
+ padding: 12px 16px;
3342
+ border-top: 1px solid var(--squisq-border, #e5e7eb);
3343
+ }
3344
+
3345
+ .squisq-link-dialog-btn {
3346
+ padding: 6px 14px;
3347
+ font: inherit;
3348
+ font-size: 13px;
3349
+ border-radius: 4px;
3350
+ border: 1px solid transparent;
3351
+ cursor: pointer;
3352
+ }
3353
+
3354
+ .squisq-link-dialog-btn--secondary {
3355
+ background: transparent;
3356
+ color: var(--squisq-text, #1f2937);
3357
+ border-color: var(--squisq-border, #d1d5db);
3358
+ }
3359
+
3360
+ .squisq-link-dialog-btn--secondary:hover {
3361
+ background: var(--squisq-bg, #f3f4f6);
3362
+ }
3363
+
3364
+ .squisq-link-dialog-btn--primary {
3365
+ background: #3b82f6;
3366
+ color: #fff;
3367
+ border-color: #3b82f6;
3368
+ }
3369
+
3370
+ .squisq-link-dialog-btn--primary:hover {
3371
+ background: #2563eb;
3372
+ border-color: #2563eb;
3373
+ }
3374
+
3375
+ /* ─── Document-link picker (LinkDialog) ──────────────────
3376
+ Surfaced when EditorShell receives a `documentLinkProvider` —
3377
+ the dialog grows a "Browse documents" tab that lists workspace
3378
+ neighbors so authors can pick a link target without typing the
3379
+ relative path by hand. */
3380
+
3381
+ .squisq-link-dialog-tabs {
3382
+ display: flex;
3383
+ gap: 2px;
3384
+ margin-bottom: 12px;
3385
+ border-bottom: 1px solid #e5e7eb;
3386
+ }
3387
+
3388
+ .squisq-link-dialog-tab {
3389
+ flex: 1;
3390
+ padding: 8px 12px;
3391
+ background: transparent;
3392
+ border: none;
3393
+ border-bottom: 2px solid transparent;
3394
+ font-size: 13px;
3395
+ font-weight: 500;
3396
+ color: #6b7280;
3397
+ cursor: pointer;
3398
+ }
3399
+
3400
+ .squisq-link-dialog-tab:hover {
3401
+ color: #1f2937;
3402
+ }
3403
+
3404
+ .squisq-link-dialog-tab--active {
3405
+ color: #1f2937;
3406
+ border-bottom-color: #3b82f6;
3407
+ }
3408
+
3409
+ .squisq-link-dialog-doc-picker {
3410
+ display: flex;
3411
+ flex-direction: column;
3412
+ gap: 6px;
3413
+ min-height: 0;
3414
+ }
3415
+
3416
+ .squisq-link-dialog-doc-list {
3417
+ max-height: 240px;
3418
+ overflow-y: auto;
3419
+ border: 1px solid #e5e7eb;
3420
+ border-radius: 4px;
3421
+ background: #fff;
3422
+ }
3423
+
3424
+ .squisq-link-dialog-doc-empty {
3425
+ padding: 16px 12px;
3426
+ text-align: center;
3427
+ color: #9ca3af;
3428
+ font-size: 13px;
3429
+ }
3430
+
3431
+ .squisq-link-dialog-doc-item {
3432
+ display: grid;
3433
+ grid-template-columns: 1fr auto;
3434
+ grid-template-areas:
3435
+ 'label path'
3436
+ 'desc desc';
3437
+ gap: 2px 12px;
3438
+ width: 100%;
3439
+ padding: 8px 12px;
3440
+ background: transparent;
3441
+ border: none;
3442
+ border-bottom: 1px solid #f3f4f6;
3443
+ text-align: left;
3444
+ font-family: inherit;
3445
+ cursor: pointer;
3446
+ }
3447
+
3448
+ .squisq-link-dialog-doc-item:last-child {
3449
+ border-bottom: none;
3450
+ }
3451
+
3452
+ .squisq-link-dialog-doc-item:hover {
3453
+ background: #f3f4f6;
3454
+ }
3455
+
3456
+ .squisq-link-dialog-doc-item--selected {
3457
+ background: #eff6ff;
3458
+ }
3459
+
3460
+ .squisq-link-dialog-doc-item-label {
3461
+ grid-area: label;
3462
+ font-size: 13px;
3463
+ font-weight: 500;
3464
+ color: #1f2937;
3465
+ overflow: hidden;
3466
+ text-overflow: ellipsis;
3467
+ white-space: nowrap;
3468
+ }
3469
+
3470
+ .squisq-link-dialog-doc-item-path {
3471
+ grid-area: path;
3472
+ font-size: 11px;
3473
+ color: #6b7280;
3474
+ font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
3475
+ }
3476
+
3477
+ .squisq-link-dialog-doc-item-desc {
3478
+ grid-area: desc;
3479
+ font-size: 11px;
3480
+ color: #9ca3af;
3481
+ }
3482
+
3483
+ .squisq-link-dialog-doc-current {
3484
+ font-size: 11px;
3485
+ color: #6b7280;
3486
+ padding: 4px 6px;
3487
+ }
3488
+
3489
+ .squisq-link-dialog-doc-current code {
3490
+ font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
3491
+ font-size: 11px;
3492
+ color: #1f2937;
3493
+ background: #f3f4f6;
3494
+ padding: 1px 4px;
3495
+ border-radius: 3px;
3496
+ }
3497
+
3498
+ /* ─── FontAwesome glyph decorations (Monaco) ─────────────
3499
+ Used by RawEditor to render the actual FA glyph as a Monaco
3500
+ `before:` content decoration adjacent to each `{[icon]}` source
3501
+ span. Per-family font-weight/font-family is necessary because the
3502
+ Free tier ships three distinct fonts (Brands, Solid, Regular). */
3503
+
3504
+ /* `inlineClassName` on Monaco's `before:` content decoration is
3505
+ applied to the wrapper around the injected glyph character. We
3506
+ render the codepoint via the appropriate FontAwesome font for the
3507
+ icon's family. */
3508
+ .fa-glyph-decoration-brands {
3509
+ font-family: 'Font Awesome 6 Brands' !important;
3510
+ font-weight: 400 !important;
3511
+ color: var(--squisq-fg, inherit);
3512
+ padding-right: 2px;
3513
+ font-style: normal !important;
3514
+ }
3515
+
3516
+ .fa-glyph-decoration-solid {
3517
+ font-family: 'Font Awesome 6 Free' !important;
3518
+ font-weight: 900 !important;
3519
+ color: var(--squisq-fg, inherit);
3520
+ padding-right: 2px;
3521
+ font-style: normal !important;
3522
+ }
3523
+
3524
+ .fa-glyph-decoration-regular {
3525
+ font-family: 'Font Awesome 6 Free' !important;
3526
+ font-weight: 400 !important;
3527
+ color: var(--squisq-fg, inherit);
3528
+ padding-right: 2px;
3529
+ font-style: normal !important;
3530
+ }
3531
+
3532
+ /* Monaco's suggest widget — when a completion item's `label.label`
3533
+ starts with a FontAwesome codepoint (we set this in RawEditor for
3534
+ icon suggestions), use FA fonts as fallbacks so the glyph renders
3535
+ instead of the empty ``-style placeholder square. Brand and
3536
+ Free fonts are listed in order; the browser picks whichever has
3537
+ the codepoint. font-weight 900 covers solid icons; brand icons
3538
+ shipping under their own font don't care about weight. Regular FA
3539
+ icons (weight 400) will fall through to the default and render
3540
+ as a placeholder — an acceptable trade since regular is the
3541
+ smallest tier in the Free catalog. */
3542
+ .monaco-editor .suggest-widget .monaco-list-row .label-name {
3543
+ /* Real fonts first (used for the icon-name characters), then FA
3544
+ fonts as fallbacks (used for the leading codepoint character).
3545
+ `inherit` is illegal inside a comma-separated font-family list
3546
+ — the browser drops the whole declaration if it appears there —
3547
+ so we spell out the system stack explicitly. */
3548
+ font-family:
3549
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, system-ui,
3550
+ 'Font Awesome 6 Brands', 'Font Awesome 6 Free', sans-serif;
3551
+ }
3552
+
3553
+ /* ─── Theme picker (popover with themed previews) ─────── */
3554
+
3555
+ .squisq-theme-picker-trigger {
3556
+ display: inline-flex;
3557
+ align-items: center;
3558
+ gap: 6px;
3559
+ padding: 2px 6px 2px 4px;
3560
+ border: 1px solid var(--squisq-border, #d1d5db);
3561
+ border-radius: 4px;
3562
+ background: var(--squisq-input-bg, #fff);
3563
+ color: var(--squisq-text, #1f2937);
3564
+ cursor: pointer;
3565
+ font: inherit;
3566
+ font-size: 12px;
3567
+ max-width: 220px;
3568
+ }
3569
+
3570
+ .squisq-theme-picker-trigger:hover {
3571
+ border-color: var(--squisq-text-muted, #9ca3af);
3572
+ }
3573
+
3574
+ .squisq-theme-picker-trigger--open {
3575
+ border-color: #3b82f6;
3576
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.18);
3577
+ }
3578
+
3579
+ .squisq-theme-picker-trigger--full {
3580
+ width: 100%;
3581
+ max-width: none;
3582
+ padding: 4px 8px 4px 4px;
3583
+ font-size: 13px;
3584
+ }
3585
+
3586
+ .squisq-theme-picker-caret {
3587
+ flex-shrink: 0;
3588
+ color: var(--squisq-text-muted, #6b7280);
3589
+ }
3590
+
3591
+ .squisq-theme-picker-name-chip {
3592
+ display: inline-block;
3593
+ padding: 2px 8px;
3594
+ border-radius: 4px;
3595
+ border: 1px solid transparent;
3596
+ font-size: 12px;
3597
+ font-weight: 500;
3598
+ line-height: 1.3;
3599
+ white-space: nowrap;
3600
+ overflow: hidden;
3601
+ text-overflow: ellipsis;
3602
+ }
3603
+
3604
+ .squisq-theme-picker-name-chip--trigger {
3605
+ flex: 1;
3606
+ min-width: 0;
3607
+ }
3608
+
3609
+ .squisq-theme-picker-name-chip--default {
3610
+ background: var(--squisq-bg, #fff) !important;
3611
+ color: var(--squisq-text, #1f2937) !important;
3612
+ border-color: var(--squisq-border, #d1d5db) !important;
3613
+ font-family: inherit !important;
3614
+ font-style: italic;
3615
+ }
3616
+
3617
+ .squisq-theme-picker-swatches {
3618
+ display: inline-flex;
3619
+ gap: 3px;
3620
+ flex-shrink: 0;
3621
+ }
3622
+
3623
+ .squisq-theme-picker-swatch {
3624
+ display: inline-block;
3625
+ width: 12px;
3626
+ height: 12px;
3627
+ border-radius: 2px;
3628
+ border: 1px solid rgba(0, 0, 0, 0.12);
3629
+ }
3630
+
3631
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-picker-swatch {
3632
+ border-color: rgba(255, 255, 255, 0.18);
3633
+ }
3634
+
3635
+ /* Popover */
3636
+ .squisq-theme-picker-popover {
3637
+ max-height: min(70vh, 520px);
3638
+ overflow-y: auto;
3639
+ background: var(--squisq-bg, #fff);
3640
+ color: var(--squisq-text, #1f2937);
3641
+ border: 1px solid var(--squisq-border, #e5e7eb);
3642
+ border-radius: 8px;
3643
+ box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
3644
+ padding: 6px;
3645
+ display: flex;
3646
+ flex-direction: column;
3647
+ gap: 2px;
3648
+ animation: squisq-theme-picker-appear 0.12s ease-out;
3649
+ }
3650
+
3651
+ @keyframes squisq-theme-picker-appear {
3652
+ from {
3653
+ opacity: 0;
3654
+ transform: translateY(-4px);
3655
+ }
3656
+ to {
3657
+ opacity: 1;
3658
+ transform: translateY(0);
3659
+ }
3660
+ }
3661
+
3662
+ .squisq-theme-picker-row {
3663
+ display: flex;
3664
+ align-items: center;
3665
+ gap: 10px;
3666
+ padding: 8px;
3667
+ border-radius: 6px;
3668
+ background: transparent;
3669
+ border: 1px solid transparent;
3670
+ cursor: pointer;
3671
+ text-align: left;
3672
+ width: 100%;
3673
+ font: inherit;
3674
+ }
3675
+
3676
+ .squisq-theme-picker-row:hover {
3677
+ background: var(--squisq-row-hover, #f3f4f6);
3678
+ }
3679
+
3680
+ .squisq-theme-picker-row--selected {
3681
+ background: #eef2ff;
3682
+ border-color: #c7d2fe;
3683
+ }
3684
+
3685
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-picker-row:hover {
3686
+ background: #374151;
3687
+ }
3688
+
3689
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-picker-row--selected {
3690
+ background: rgba(99, 102, 241, 0.2);
3691
+ border-color: rgba(165, 180, 252, 0.4);
3692
+ }
3693
+
3694
+ .squisq-theme-picker-row .squisq-theme-picker-name-chip {
3695
+ flex-shrink: 0;
3696
+ min-width: 110px;
3697
+ text-align: center;
3698
+ padding: 6px 10px;
3699
+ font-size: 13px;
3700
+ }
3701
+
3702
+ .squisq-theme-picker-row-meta {
3703
+ display: flex;
3704
+ flex-direction: column;
3705
+ gap: 4px;
3706
+ min-width: 0;
3707
+ flex: 1;
3708
+ }
3709
+
3710
+ .squisq-theme-picker-row-name {
3711
+ font-size: 12px;
3712
+ font-weight: 600;
3713
+ color: var(--squisq-text, #1f2937);
3714
+ }
3715
+
3716
+ .squisq-theme-picker-row-desc {
3717
+ font-size: 11px;
3718
+ color: var(--squisq-text-muted, #6b7280);
3719
+ line-height: 1.35;
3720
+ display: -webkit-box;
3721
+ -webkit-line-clamp: 2;
3722
+ -webkit-box-orient: vertical;
3723
+ overflow: hidden;
3724
+ }
3725
+
3726
+ /* Dark editor-shell variants for the trigger / popover */
3727
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-picker-trigger {
3728
+ background: #111827;
3729
+ border-color: #374151;
3730
+ color: #e5e7eb;
3731
+ }
3732
+
3733
+ .squisq-editor-shell[data-theme='dark'] .squisq-theme-picker-popover {
3734
+ background: #1f2937;
3735
+ border-color: #374151;
3736
+ color: #e5e7eb;
3737
+ }
3738
+
3739
+ /* ─── Document settings dialog ───────────────────────── */
3740
+
3741
+ .squisq-doc-settings-overlay {
3742
+ position: fixed;
3743
+ inset: 0;
3744
+ z-index: 200;
3745
+ display: flex;
3746
+ align-items: center;
3747
+ justify-content: center;
3748
+ background: rgba(0, 0, 0, 0.45);
3749
+ padding: 16px;
3750
+ }
3751
+
3752
+ .squisq-doc-settings-dialog {
3753
+ width: 100%;
3754
+ max-width: 440px;
3755
+ background: var(--squisq-bg, #fff);
3756
+ color: var(--squisq-text, #1f2937);
3757
+ border: 1px solid var(--squisq-border, #e5e7eb);
3758
+ border-radius: 8px;
3759
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
3760
+ display: flex;
3761
+ flex-direction: column;
3762
+ }
3763
+
3764
+ .squisq-doc-settings-header {
3765
+ display: flex;
3766
+ align-items: center;
3767
+ justify-content: space-between;
3768
+ padding: 12px 16px;
3769
+ border-bottom: 1px solid var(--squisq-border, #e5e7eb);
3770
+ }
3771
+
3772
+ .squisq-doc-settings-title {
3773
+ margin: 0;
3774
+ font-size: 14px;
3775
+ font-weight: 600;
3776
+ }
3777
+
3778
+ .squisq-doc-settings-close {
3779
+ background: none;
3780
+ border: none;
3781
+ font-size: 20px;
3782
+ line-height: 1;
3783
+ cursor: pointer;
3784
+ color: var(--squisq-text-muted, #6b7280);
3785
+ padding: 0 4px;
3786
+ }
3787
+
3788
+ .squisq-doc-settings-close:hover {
3789
+ color: var(--squisq-text, #1f2937);
3790
+ }
3791
+
3792
+ .squisq-doc-settings-body {
3793
+ padding: 16px;
3794
+ display: flex;
3795
+ flex-direction: column;
3796
+ gap: 14px;
3797
+ }
3798
+
3799
+ .squisq-doc-settings-field {
3800
+ display: flex;
3801
+ flex-direction: column;
3802
+ gap: 4px;
3803
+ }
3804
+
3805
+ .squisq-doc-settings-label {
3806
+ font-size: 12px;
3807
+ font-weight: 500;
3808
+ color: var(--squisq-text-muted, #6b7280);
3809
+ }
3810
+
3811
+ .squisq-doc-settings-input {
3812
+ width: 100%;
3813
+ padding: 6px 10px;
3814
+ font: inherit;
3815
+ font-size: 13px;
3816
+ background: var(--squisq-bg, #fff);
3817
+ color: var(--squisq-text, #1f2937);
3818
+ border: 1px solid var(--squisq-border, #d1d5db);
3819
+ border-radius: 4px;
3820
+ outline: none;
3821
+ box-sizing: border-box;
3822
+ }
3823
+
3824
+ .squisq-doc-settings-input:focus {
3825
+ border-color: #3b82f6;
3826
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
3827
+ }
3828
+
3829
+ .squisq-doc-settings-hint {
3830
+ font-size: 11px;
3831
+ color: var(--squisq-text-muted, #6b7280);
3832
+ line-height: 1.4;
3833
+ }
3834
+
3835
+ .squisq-doc-settings-hint strong {
3836
+ color: var(--squisq-text, #1f2937);
3837
+ font-weight: 600;
3838
+ }
3839
+
3840
+ .squisq-doc-settings-footer {
3841
+ display: flex;
3842
+ justify-content: flex-end;
3843
+ gap: 8px;
3844
+ padding: 12px 16px;
3845
+ border-top: 1px solid var(--squisq-border, #e5e7eb);
3846
+ }
3847
+
3848
+ .squisq-doc-settings-btn {
3849
+ padding: 6px 14px;
3850
+ font: inherit;
3851
+ font-size: 13px;
3852
+ border-radius: 4px;
3853
+ border: 1px solid transparent;
3854
+ cursor: pointer;
3855
+ }
3856
+
3857
+ .squisq-doc-settings-btn--secondary {
3858
+ background: transparent;
3859
+ color: var(--squisq-text, #1f2937);
3860
+ border-color: var(--squisq-border, #d1d5db);
3861
+ }
3862
+
3863
+ .squisq-doc-settings-btn--secondary:hover {
3864
+ background: var(--squisq-bg, #f3f4f6);
3865
+ }
3866
+
3867
+ .squisq-doc-settings-btn--primary {
3868
+ background: #3b82f6;
3869
+ color: #fff;
3870
+ border-color: #3b82f6;
3871
+ }
3872
+
3873
+ .squisq-doc-settings-btn--primary:hover {
3874
+ background: #2563eb;
3875
+ border-color: #2563eb;
3876
+ }