@oh-just-another/react-ui 0.61.0 → 0.63.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 (369) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/README.md +3 -3
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/color/color-palette.d.ts.map +1 -0
  5. package/dist/color/color-palette.js.map +1 -0
  6. package/dist/color/color-swatch-picker.d.ts.map +1 -0
  7. package/dist/{color-swatch-picker.js → color/color-swatch-picker.js} +4 -3
  8. package/dist/color/color-swatch-picker.js.map +1 -0
  9. package/dist/{constants.d.ts → core/constants.d.ts} +66 -14
  10. package/dist/core/constants.d.ts.map +1 -0
  11. package/dist/{constants.js → core/constants.js} +99 -14
  12. package/dist/core/constants.js.map +1 -0
  13. package/dist/core/context.d.ts.map +1 -0
  14. package/dist/core/context.js.map +1 -0
  15. package/dist/core/hooks.d.ts.map +1 -0
  16. package/dist/core/hooks.js.map +1 -0
  17. package/dist/core/portal-container.d.ts.map +1 -0
  18. package/dist/core/portal-container.js.map +1 -0
  19. package/dist/core/use-fullscreen.d.ts +14 -0
  20. package/dist/core/use-fullscreen.d.ts.map +1 -0
  21. package/dist/core/use-fullscreen.js +38 -0
  22. package/dist/core/use-fullscreen.js.map +1 -0
  23. package/dist/core/use-quiet-gesture.d.ts +11 -0
  24. package/dist/core/use-quiet-gesture.d.ts.map +1 -0
  25. package/dist/core/use-quiet-gesture.js +61 -0
  26. package/dist/core/use-quiet-gesture.js.map +1 -0
  27. package/dist/core/use-quiet-viewport.d.ts +10 -0
  28. package/dist/core/use-quiet-viewport.d.ts.map +1 -0
  29. package/dist/core/use-quiet-viewport.js +40 -0
  30. package/dist/core/use-quiet-viewport.js.map +1 -0
  31. package/dist/index.d.ts +55 -50
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +55 -50
  34. package/dist/index.js.map +1 -1
  35. package/dist/layout/diagram-bars.d.ts.map +1 -0
  36. package/dist/layout/diagram-bars.js.map +1 -0
  37. package/dist/layout/diagram-canvas.d.ts.map +1 -0
  38. package/dist/layout/diagram-canvas.js.map +1 -0
  39. package/dist/layout/diagram-root.d.ts.map +1 -0
  40. package/dist/{diagram-root.js → layout/diagram-root.js} +2 -2
  41. package/dist/layout/diagram-root.js.map +1 -0
  42. package/dist/{sidebar.d.ts → layout/sidebar.d.ts} +1 -0
  43. package/dist/layout/sidebar.d.ts.map +1 -0
  44. package/dist/layout/sidebar.js +38 -0
  45. package/dist/layout/sidebar.js.map +1 -0
  46. package/dist/layout/ui-layer.d.ts.map +1 -0
  47. package/dist/layout/ui-layer.js.map +1 -0
  48. package/dist/menus/command-palette.d.ts.map +1 -0
  49. package/dist/{command-palette.js → menus/command-palette.js} +2 -2
  50. package/dist/menus/command-palette.js.map +1 -0
  51. package/dist/menus/context-menu-controller.d.ts.map +1 -0
  52. package/dist/menus/context-menu-controller.js.map +1 -0
  53. package/dist/{context-menu.d.ts → menus/context-menu.d.ts} +12 -0
  54. package/dist/menus/context-menu.d.ts.map +1 -0
  55. package/dist/menus/context-menu.js +617 -0
  56. package/dist/menus/context-menu.js.map +1 -0
  57. package/dist/menus/link-drop-shape-menu.d.ts.map +1 -0
  58. package/dist/{link-drop-shape-menu.js → menus/link-drop-shape-menu.js} +4 -4
  59. package/dist/menus/link-drop-shape-menu.js.map +1 -0
  60. package/dist/{main-menu.d.ts → menus/main-menu.d.ts} +45 -2
  61. package/dist/menus/main-menu.d.ts.map +1 -0
  62. package/dist/menus/main-menu.js +260 -0
  63. package/dist/menus/main-menu.js.map +1 -0
  64. package/dist/overlays/file-drop-overlay.d.ts +15 -0
  65. package/dist/overlays/file-drop-overlay.d.ts.map +1 -0
  66. package/dist/overlays/file-drop-overlay.js +27 -0
  67. package/dist/overlays/file-drop-overlay.js.map +1 -0
  68. package/dist/overlays/frame-name-editor-overlay.d.ts.map +1 -0
  69. package/dist/{frame-name-editor-overlay.js → overlays/frame-name-editor-overlay.js} +1 -1
  70. package/dist/overlays/frame-name-editor-overlay.js.map +1 -0
  71. package/dist/overlays/help-button.d.ts.map +1 -0
  72. package/dist/{help-button.js → overlays/help-button.js} +3 -4
  73. package/dist/overlays/help-button.js.map +1 -0
  74. package/dist/overlays/help-dialog.d.ts.map +1 -0
  75. package/dist/{help-dialog.js → overlays/help-dialog.js} +4 -24
  76. package/dist/overlays/help-dialog.js.map +1 -0
  77. package/dist/overlays/link-badges.d.ts +14 -0
  78. package/dist/overlays/link-badges.d.ts.map +1 -0
  79. package/dist/overlays/link-badges.js +60 -0
  80. package/dist/overlays/link-badges.js.map +1 -0
  81. package/dist/overlays/link-caption-editor.d.ts.map +1 -0
  82. package/dist/{link-caption-editor.js → overlays/link-caption-editor.js} +3 -3
  83. package/dist/overlays/link-caption-editor.js.map +1 -0
  84. package/dist/overlays/link-hover-popup.d.ts.map +1 -0
  85. package/dist/{link-hover-popup.js → overlays/link-hover-popup.js} +5 -4
  86. package/dist/overlays/link-hover-popup.js.map +1 -0
  87. package/dist/overlays/merge-dialog.d.ts.map +1 -0
  88. package/dist/overlays/merge-dialog.js +39 -0
  89. package/dist/overlays/merge-dialog.js.map +1 -0
  90. package/dist/overlays/search-overlay.d.ts.map +1 -0
  91. package/dist/{search-overlay.js → overlays/search-overlay.js} +2 -2
  92. package/dist/overlays/search-overlay.js.map +1 -0
  93. package/dist/overlays/sticky-reactions.d.ts +2 -0
  94. package/dist/overlays/sticky-reactions.d.ts.map +1 -0
  95. package/dist/overlays/sticky-reactions.js +94 -0
  96. package/dist/overlays/sticky-reactions.js.map +1 -0
  97. package/dist/overlays/text-editor-overlay.d.ts.map +1 -0
  98. package/dist/{text-editor-overlay.js → overlays/text-editor-overlay.js} +37 -5
  99. package/dist/overlays/text-editor-overlay.js.map +1 -0
  100. package/dist/{comments-panel.d.ts → panels/comments-panel.d.ts} +4 -1
  101. package/dist/panels/comments-panel.d.ts.map +1 -0
  102. package/dist/panels/comments-panel.js +51 -0
  103. package/dist/panels/comments-panel.js.map +1 -0
  104. package/dist/panels/control-sets.d.ts +42 -0
  105. package/dist/panels/control-sets.d.ts.map +1 -0
  106. package/dist/panels/control-sets.js +63 -0
  107. package/dist/panels/control-sets.js.map +1 -0
  108. package/dist/panels/diff-panel.d.ts.map +1 -0
  109. package/dist/panels/diff-panel.js.map +1 -0
  110. package/dist/panels/drawing-panel.d.ts.map +1 -0
  111. package/dist/{drawing-panel.js → panels/drawing-panel.js} +3 -3
  112. package/dist/panels/drawing-panel.js.map +1 -0
  113. package/dist/panels/edge-style-panel.d.ts.map +1 -0
  114. package/dist/{edge-style-panel.js → panels/edge-style-panel.js} +1 -1
  115. package/dist/panels/edge-style-panel.js.map +1 -0
  116. package/dist/panels/frame-panel.d.ts.map +1 -0
  117. package/dist/{frame-panel.js → panels/frame-panel.js} +1 -1
  118. package/dist/panels/frame-panel.js.map +1 -0
  119. package/dist/{layer-panel.d.ts → panels/layer-panel.d.ts} +5 -1
  120. package/dist/panels/layer-panel.d.ts.map +1 -0
  121. package/dist/panels/layer-panel.js +52 -0
  122. package/dist/panels/layer-panel.js.map +1 -0
  123. package/dist/panels/library-panel.d.ts.map +1 -0
  124. package/dist/{library-panel.js → panels/library-panel.js} +4 -5
  125. package/dist/panels/library-panel.js.map +1 -0
  126. package/dist/panels/property-panel.d.ts.map +1 -0
  127. package/dist/panels/property-panel.js +1492 -0
  128. package/dist/panels/property-panel.js.map +1 -0
  129. package/dist/panels/selection-floating-panel.d.ts.map +1 -0
  130. package/dist/{selection-floating-panel.js → panels/selection-floating-panel.js} +24 -13
  131. package/dist/panels/selection-floating-panel.js.map +1 -0
  132. package/dist/panels/stats-panel.d.ts.map +1 -0
  133. package/dist/{stats-panel.js → panels/stats-panel.js} +1 -1
  134. package/dist/panels/stats-panel.js.map +1 -0
  135. package/dist/primitives/bottom-sheet.d.ts.map +1 -0
  136. package/dist/{bottom-sheet.js → primitives/bottom-sheet.js} +9 -22
  137. package/dist/primitives/bottom-sheet.js.map +1 -0
  138. package/dist/primitives/button-group.d.ts.map +1 -0
  139. package/dist/primitives/button-group.js.map +1 -0
  140. package/dist/primitives/css-var.d.ts +8 -0
  141. package/dist/primitives/css-var.d.ts.map +1 -0
  142. package/dist/primitives/css-var.js +11 -0
  143. package/dist/primitives/css-var.js.map +1 -0
  144. package/dist/primitives/float-panel.d.ts +35 -0
  145. package/dist/primitives/float-panel.d.ts.map +1 -0
  146. package/dist/primitives/float-panel.js +42 -0
  147. package/dist/primitives/float-panel.js.map +1 -0
  148. package/dist/primitives/icon-button.d.ts.map +1 -0
  149. package/dist/primitives/icon-button.js.map +1 -0
  150. package/dist/primitives/markdown.d.ts.map +1 -0
  151. package/dist/primitives/markdown.js.map +1 -0
  152. package/dist/primitives/modal.d.ts.map +1 -0
  153. package/dist/{modal.js → primitives/modal.js} +11 -9
  154. package/dist/primitives/modal.js.map +1 -0
  155. package/dist/{popover.d.ts → primitives/popover.d.ts} +1 -1
  156. package/dist/primitives/popover.d.ts.map +1 -0
  157. package/dist/{popover.js → primitives/popover.js} +7 -18
  158. package/dist/primitives/popover.js.map +1 -0
  159. package/dist/primitives/segmented-control.d.ts.map +1 -0
  160. package/dist/primitives/segmented-control.js.map +1 -0
  161. package/dist/primitives/slider.d.ts.map +1 -0
  162. package/dist/primitives/slider.js.map +1 -0
  163. package/dist/primitives/switch.d.ts +24 -0
  164. package/dist/primitives/switch.d.ts.map +1 -0
  165. package/dist/primitives/switch.js +17 -0
  166. package/dist/primitives/switch.js.map +1 -0
  167. package/dist/primitives/toast.d.ts.map +1 -0
  168. package/dist/{toast.js → primitives/toast.js} +12 -33
  169. package/dist/primitives/toast.js.map +1 -0
  170. package/dist/primitives/tooltip.d.ts.map +1 -0
  171. package/dist/{tooltip.js → primitives/tooltip.js} +3 -3
  172. package/dist/primitives/tooltip.js.map +1 -0
  173. package/dist/{palette.d.ts → toolbar/palette.d.ts} +6 -1
  174. package/dist/toolbar/palette.d.ts.map +1 -0
  175. package/dist/{palette.js → toolbar/palette.js} +39 -5
  176. package/dist/toolbar/palette.js.map +1 -0
  177. package/dist/{toolbar.d.ts → toolbar/toolbar.d.ts} +9 -0
  178. package/dist/toolbar/toolbar.d.ts.map +1 -0
  179. package/dist/{toolbar.js → toolbar/toolbar.js} +132 -62
  180. package/dist/toolbar/toolbar.js.map +1 -0
  181. package/dist/utils/format-time.d.ts.map +1 -0
  182. package/dist/utils/format-time.js.map +1 -0
  183. package/dist/utils/use-dismiss-timer.d.ts.map +1 -0
  184. package/dist/utils/use-dismiss-timer.js.map +1 -0
  185. package/dist/widgets/minimap.d.ts.map +1 -0
  186. package/dist/{minimap.js → widgets/minimap.js} +50 -36
  187. package/dist/widgets/minimap.js.map +1 -0
  188. package/dist/widgets/reset-to-content-button.d.ts +11 -0
  189. package/dist/widgets/reset-to-content-button.d.ts.map +1 -0
  190. package/dist/{reset-to-content-button.js → widgets/reset-to-content-button.js} +8 -9
  191. package/dist/widgets/reset-to-content-button.js.map +1 -0
  192. package/dist/widgets/versioning.d.ts.map +1 -0
  193. package/dist/{versioning.js → widgets/versioning.js} +3 -3
  194. package/dist/widgets/versioning.js.map +1 -0
  195. package/dist/widgets/zen-mode.d.ts.map +1 -0
  196. package/dist/widgets/zen-mode.js.map +1 -0
  197. package/package.json +9 -9
  198. package/src/styles.css +1596 -258
  199. package/dist/bottom-sheet.d.ts.map +0 -1
  200. package/dist/bottom-sheet.js.map +0 -1
  201. package/dist/button-group.d.ts.map +0 -1
  202. package/dist/button-group.js.map +0 -1
  203. package/dist/color-palette.d.ts.map +0 -1
  204. package/dist/color-palette.js.map +0 -1
  205. package/dist/color-swatch-picker.d.ts.map +0 -1
  206. package/dist/color-swatch-picker.js.map +0 -1
  207. package/dist/command-palette.d.ts.map +0 -1
  208. package/dist/command-palette.js.map +0 -1
  209. package/dist/comments-panel.d.ts.map +0 -1
  210. package/dist/comments-panel.js +0 -142
  211. package/dist/comments-panel.js.map +0 -1
  212. package/dist/constants.d.ts.map +0 -1
  213. package/dist/constants.js.map +0 -1
  214. package/dist/context-menu-controller.d.ts.map +0 -1
  215. package/dist/context-menu-controller.js.map +0 -1
  216. package/dist/context-menu.d.ts.map +0 -1
  217. package/dist/context-menu.js +0 -368
  218. package/dist/context-menu.js.map +0 -1
  219. package/dist/context.d.ts.map +0 -1
  220. package/dist/context.js.map +0 -1
  221. package/dist/diagram-bars.d.ts.map +0 -1
  222. package/dist/diagram-bars.js.map +0 -1
  223. package/dist/diagram-canvas.d.ts.map +0 -1
  224. package/dist/diagram-canvas.js.map +0 -1
  225. package/dist/diagram-root.d.ts.map +0 -1
  226. package/dist/diagram-root.js.map +0 -1
  227. package/dist/diff-panel.d.ts.map +0 -1
  228. package/dist/diff-panel.js.map +0 -1
  229. package/dist/drawing-panel.d.ts.map +0 -1
  230. package/dist/drawing-panel.js.map +0 -1
  231. package/dist/edge-style-panel.d.ts.map +0 -1
  232. package/dist/edge-style-panel.js.map +0 -1
  233. package/dist/format-time.d.ts.map +0 -1
  234. package/dist/format-time.js.map +0 -1
  235. package/dist/frame-name-editor-overlay.d.ts.map +0 -1
  236. package/dist/frame-name-editor-overlay.js.map +0 -1
  237. package/dist/frame-panel.d.ts.map +0 -1
  238. package/dist/frame-panel.js.map +0 -1
  239. package/dist/help-button.d.ts.map +0 -1
  240. package/dist/help-button.js.map +0 -1
  241. package/dist/help-dialog.d.ts.map +0 -1
  242. package/dist/help-dialog.js.map +0 -1
  243. package/dist/hooks.d.ts.map +0 -1
  244. package/dist/hooks.js.map +0 -1
  245. package/dist/icon-button.d.ts.map +0 -1
  246. package/dist/icon-button.js.map +0 -1
  247. package/dist/layer-panel.d.ts.map +0 -1
  248. package/dist/layer-panel.js +0 -117
  249. package/dist/layer-panel.js.map +0 -1
  250. package/dist/library-panel.d.ts.map +0 -1
  251. package/dist/library-panel.js.map +0 -1
  252. package/dist/link-caption-editor.d.ts.map +0 -1
  253. package/dist/link-caption-editor.js.map +0 -1
  254. package/dist/link-drop-shape-menu.d.ts.map +0 -1
  255. package/dist/link-drop-shape-menu.js.map +0 -1
  256. package/dist/link-hover-popup.d.ts.map +0 -1
  257. package/dist/link-hover-popup.js.map +0 -1
  258. package/dist/main-menu.d.ts.map +0 -1
  259. package/dist/main-menu.js +0 -249
  260. package/dist/main-menu.js.map +0 -1
  261. package/dist/markdown.d.ts.map +0 -1
  262. package/dist/markdown.js.map +0 -1
  263. package/dist/merge-dialog.d.ts.map +0 -1
  264. package/dist/merge-dialog.js +0 -50
  265. package/dist/merge-dialog.js.map +0 -1
  266. package/dist/minimap.d.ts.map +0 -1
  267. package/dist/minimap.js.map +0 -1
  268. package/dist/modal.d.ts.map +0 -1
  269. package/dist/modal.js.map +0 -1
  270. package/dist/palette.d.ts.map +0 -1
  271. package/dist/palette.js.map +0 -1
  272. package/dist/popover.d.ts.map +0 -1
  273. package/dist/popover.js.map +0 -1
  274. package/dist/portal-container.d.ts.map +0 -1
  275. package/dist/portal-container.js.map +0 -1
  276. package/dist/property-panel.d.ts.map +0 -1
  277. package/dist/property-panel.js +0 -917
  278. package/dist/property-panel.js.map +0 -1
  279. package/dist/reset-to-content-button.d.ts +0 -10
  280. package/dist/reset-to-content-button.d.ts.map +0 -1
  281. package/dist/reset-to-content-button.js.map +0 -1
  282. package/dist/search-overlay.d.ts.map +0 -1
  283. package/dist/search-overlay.js.map +0 -1
  284. package/dist/segmented-control.d.ts.map +0 -1
  285. package/dist/segmented-control.js.map +0 -1
  286. package/dist/selection-floating-panel.d.ts.map +0 -1
  287. package/dist/selection-floating-panel.js.map +0 -1
  288. package/dist/sidebar.d.ts.map +0 -1
  289. package/dist/sidebar.js +0 -68
  290. package/dist/sidebar.js.map +0 -1
  291. package/dist/slider.d.ts.map +0 -1
  292. package/dist/slider.js.map +0 -1
  293. package/dist/stats-panel.d.ts.map +0 -1
  294. package/dist/stats-panel.js.map +0 -1
  295. package/dist/text-editor-overlay.d.ts.map +0 -1
  296. package/dist/text-editor-overlay.js.map +0 -1
  297. package/dist/toast.d.ts.map +0 -1
  298. package/dist/toast.js.map +0 -1
  299. package/dist/toolbar.d.ts.map +0 -1
  300. package/dist/toolbar.js.map +0 -1
  301. package/dist/tooltip.d.ts.map +0 -1
  302. package/dist/tooltip.js.map +0 -1
  303. package/dist/ui-layer.d.ts.map +0 -1
  304. package/dist/ui-layer.js.map +0 -1
  305. package/dist/use-dismiss-timer.d.ts.map +0 -1
  306. package/dist/use-dismiss-timer.js.map +0 -1
  307. package/dist/versioning.d.ts.map +0 -1
  308. package/dist/versioning.js.map +0 -1
  309. package/dist/zen-mode.d.ts.map +0 -1
  310. package/dist/zen-mode.js.map +0 -1
  311. /package/dist/{color-palette.d.ts → color/color-palette.d.ts} +0 -0
  312. /package/dist/{color-palette.js → color/color-palette.js} +0 -0
  313. /package/dist/{color-swatch-picker.d.ts → color/color-swatch-picker.d.ts} +0 -0
  314. /package/dist/{context.d.ts → core/context.d.ts} +0 -0
  315. /package/dist/{context.js → core/context.js} +0 -0
  316. /package/dist/{hooks.d.ts → core/hooks.d.ts} +0 -0
  317. /package/dist/{hooks.js → core/hooks.js} +0 -0
  318. /package/dist/{portal-container.d.ts → core/portal-container.d.ts} +0 -0
  319. /package/dist/{portal-container.js → core/portal-container.js} +0 -0
  320. /package/dist/{diagram-bars.d.ts → layout/diagram-bars.d.ts} +0 -0
  321. /package/dist/{diagram-bars.js → layout/diagram-bars.js} +0 -0
  322. /package/dist/{diagram-canvas.d.ts → layout/diagram-canvas.d.ts} +0 -0
  323. /package/dist/{diagram-canvas.js → layout/diagram-canvas.js} +0 -0
  324. /package/dist/{diagram-root.d.ts → layout/diagram-root.d.ts} +0 -0
  325. /package/dist/{ui-layer.d.ts → layout/ui-layer.d.ts} +0 -0
  326. /package/dist/{ui-layer.js → layout/ui-layer.js} +0 -0
  327. /package/dist/{command-palette.d.ts → menus/command-palette.d.ts} +0 -0
  328. /package/dist/{context-menu-controller.d.ts → menus/context-menu-controller.d.ts} +0 -0
  329. /package/dist/{context-menu-controller.js → menus/context-menu-controller.js} +0 -0
  330. /package/dist/{link-drop-shape-menu.d.ts → menus/link-drop-shape-menu.d.ts} +0 -0
  331. /package/dist/{frame-name-editor-overlay.d.ts → overlays/frame-name-editor-overlay.d.ts} +0 -0
  332. /package/dist/{help-button.d.ts → overlays/help-button.d.ts} +0 -0
  333. /package/dist/{help-dialog.d.ts → overlays/help-dialog.d.ts} +0 -0
  334. /package/dist/{link-caption-editor.d.ts → overlays/link-caption-editor.d.ts} +0 -0
  335. /package/dist/{link-hover-popup.d.ts → overlays/link-hover-popup.d.ts} +0 -0
  336. /package/dist/{merge-dialog.d.ts → overlays/merge-dialog.d.ts} +0 -0
  337. /package/dist/{search-overlay.d.ts → overlays/search-overlay.d.ts} +0 -0
  338. /package/dist/{text-editor-overlay.d.ts → overlays/text-editor-overlay.d.ts} +0 -0
  339. /package/dist/{diff-panel.d.ts → panels/diff-panel.d.ts} +0 -0
  340. /package/dist/{diff-panel.js → panels/diff-panel.js} +0 -0
  341. /package/dist/{drawing-panel.d.ts → panels/drawing-panel.d.ts} +0 -0
  342. /package/dist/{edge-style-panel.d.ts → panels/edge-style-panel.d.ts} +0 -0
  343. /package/dist/{frame-panel.d.ts → panels/frame-panel.d.ts} +0 -0
  344. /package/dist/{library-panel.d.ts → panels/library-panel.d.ts} +0 -0
  345. /package/dist/{property-panel.d.ts → panels/property-panel.d.ts} +0 -0
  346. /package/dist/{selection-floating-panel.d.ts → panels/selection-floating-panel.d.ts} +0 -0
  347. /package/dist/{stats-panel.d.ts → panels/stats-panel.d.ts} +0 -0
  348. /package/dist/{bottom-sheet.d.ts → primitives/bottom-sheet.d.ts} +0 -0
  349. /package/dist/{button-group.d.ts → primitives/button-group.d.ts} +0 -0
  350. /package/dist/{button-group.js → primitives/button-group.js} +0 -0
  351. /package/dist/{icon-button.d.ts → primitives/icon-button.d.ts} +0 -0
  352. /package/dist/{icon-button.js → primitives/icon-button.js} +0 -0
  353. /package/dist/{markdown.d.ts → primitives/markdown.d.ts} +0 -0
  354. /package/dist/{markdown.js → primitives/markdown.js} +0 -0
  355. /package/dist/{modal.d.ts → primitives/modal.d.ts} +0 -0
  356. /package/dist/{segmented-control.d.ts → primitives/segmented-control.d.ts} +0 -0
  357. /package/dist/{segmented-control.js → primitives/segmented-control.js} +0 -0
  358. /package/dist/{slider.d.ts → primitives/slider.d.ts} +0 -0
  359. /package/dist/{slider.js → primitives/slider.js} +0 -0
  360. /package/dist/{toast.d.ts → primitives/toast.d.ts} +0 -0
  361. /package/dist/{tooltip.d.ts → primitives/tooltip.d.ts} +0 -0
  362. /package/dist/{format-time.d.ts → utils/format-time.d.ts} +0 -0
  363. /package/dist/{format-time.js → utils/format-time.js} +0 -0
  364. /package/dist/{use-dismiss-timer.d.ts → utils/use-dismiss-timer.d.ts} +0 -0
  365. /package/dist/{use-dismiss-timer.js → utils/use-dismiss-timer.js} +0 -0
  366. /package/dist/{minimap.d.ts → widgets/minimap.d.ts} +0 -0
  367. /package/dist/{versioning.d.ts → widgets/versioning.d.ts} +0 -0
  368. /package/dist/{zen-mode.d.ts → widgets/zen-mode.d.ts} +0 -0
  369. /package/dist/{zen-mode.js → widgets/zen-mode.js} +0 -0
package/src/styles.css CHANGED
@@ -19,48 +19,175 @@
19
19
  * value in `packages/tokens/src/colors.ts`.
20
20
  */
21
21
 
22
+ /* ================================================================== */
23
+ /* DESIGN TOKENS */
24
+ /* Every component reads its colours, sizes and rhythm through these */
25
+ /* custom properties. They are grouped by TYPE; hosts override any of */
26
+ /* them in their own stylesheet. Theme-dependent groups (colour, */
27
+ /* elevation) are re-declared per theme scope below; the rest are */
28
+ /* theme-neutral and live here only. */
29
+ /* ================================================================== */
22
30
  :root {
23
- /* --- Surfaces (from UI_SURFACE.light) --- */
24
- --du-canvas-bg: #f5f5f5; /* UI_SURFACE.light.canvas */
25
- --du-ui-bg: rgba(255, 255, 255, 0.95); /* UI_SURFACE.light.bg */
26
- --du-ui-bg-solid: #ffffff; /* UI_SURFACE.light.bgSolid */
27
- --du-ui-border: rgba(0, 0, 0, 0.08); /* UI_SURFACE.light.border */
28
- --du-ui-shadow: 0 1px 4px rgba(0, 0, 0, 0.08), 0 4px 12px rgba(0, 0, 0, 0.04);
29
-
30
- /* --- Text (from UI_SURFACE.light) --- */
31
- --du-text: #1a1a1a; /* UI_SURFACE.light.text */
32
- --du-text-muted: #6b6b6b; /* UI_SURFACE.light.textMuted */
31
+ /* ---- Colour · surfaces (UI_SURFACE.light in @oh-just-another/tokens) ---- */
32
+ --du-canvas-bg: #f5f5f5; /* paper under the scene — NOT themed (see dark note) */
33
+ --du-ui-bg: #ffffff; /* chrome surface (bars, groups) opaque */
34
+ --du-ui-bg-solid: #ffffff; /* same surface; kept for hosts that override one */
35
+ --du-ui-border: rgba(0, 0, 0, 0.08); /* hairline on every chrome edge */
36
+ --du-hover-overlay: rgba(0, 0, 0, 0.05); /* hover wash on flat controls */
37
+ --du-scrim: rgba(0, 0, 0, 0.55); /* backdrop behind modals / sheets */
38
+
39
+ /* ---- Colour · text ---- */
40
+ --du-text: #1a1a1a;
41
+ --du-text-muted: #6b6b6b; /* captions, shortcuts, group titles */
33
42
  --du-text-on-accent: #ffffff;
34
43
 
35
- /* --- Accent (from UI_ACCENT.light — Radix iris) --- */
36
- --du-accent: #5b5bd6; /* UI_ACCENT.light.accent (iris.iris9) */
37
- --du-accent-hover: #5151cd; /* UI_ACCENT.light.accentHover (iris.iris10) */
38
- --du-danger: #e54d2e; /* UI_ACCENT.light.danger (tomato.tomato9) */
39
-
40
- /* --- Selected (tonal, modern-style) --- */
41
- /* Active toolbar / icon buttons get a *muted* tonal fill so they
42
- read as "this state is selected" without hijacking the eye like
43
- a saturated accent fill would. The icon switches to the accent
44
- hue, the background stays close to the surface. */
45
- --du-selected-bg: #e6e7ff; /* UI_ACCENT.light.selectedBg (iris.iris4) */
46
- --du-selected-fg: #5753c6; /* UI_ACCENT.light.selectedFg (iris.iris11) */
47
-
48
- /* --- Sizing --- */
49
- --du-radius: 10px;
50
- --du-radius-sm: 6px;
51
- --du-radius-lg: 14px;
52
- --du-button-size: 36px;
53
- --du-button-size-sm: 32px;
54
- --du-icon-size: 18px;
55
- --du-gap: 8px;
56
- --du-gap-sm: 4px;
57
- --du-pad: 8px;
58
- --du-pad-sm: 4px;
59
- --du-hover-overlay: rgba(0, 0, 0, 0.05);
60
- --du-bar-inset: 12px;
44
+ /* ---- Colour · accent (UI_ACCENT.light — Radix iris) ---- */
45
+ --du-accent: #5b5bd6; /* iris9 — focus rings, active glyphs, links */
46
+ --du-accent-hover: #5151cd; /* iris10 */
47
+ --du-danger: #e54d2e; /* tomato9 */
48
+ --du-success: #30a46c; /* grass9 */
49
+ --du-warning: #ffc53d; /* amber9 */
50
+ /* Selected state is TONAL: a muted iris wash + iris text, never a
51
+ saturated fill, so a pressed tool doesn't hijack the eye. */
52
+ --du-selected-bg: #e6e7ff; /* iris4 */
53
+ --du-selected-fg: #5753c6; /* iris11 */
54
+
55
+ /* ---- Colour · inverse (tooltip) ---- */
56
+ --du-tooltip-bg: var(--du-text);
57
+ --du-tooltip-fg: var(--du-ui-bg-solid);
58
+
59
+ /* ---- Elevation — ONE level for every floating chrome surface
60
+ (toolbars, groups, menus, popovers, panels, minimap), a heavier one
61
+ for dialogs that sit on a scrim. Tinted with the text colour. ---- */
62
+ --du-ui-shadow: 0 2px 8px rgba(34, 36, 40, 0.12), 0 0 12px rgba(34, 36, 40, 0.04);
63
+ --du-modal-shadow: 0 8px 32px rgba(34, 36, 40, 0.24);
64
+
65
+ /* ---- Radius — three steps: items inside a group (4), toolbars /
66
+ dropdowns / popovers (8), panels / dialogs (12); pills are round. ---- */
67
+ --du-radius-sm: 4px;
68
+ --du-radius: 8px;
69
+ --du-radius-lg: 12px;
70
+ --du-radius-round: 999px;
71
+
72
+ /* ---- Chrome rhythm — ONE size and ONE inset shared by toolbars and
73
+ menus: a toolbar button, a menu row (Shapes and lines, context / main
74
+ / zoom menus) and a panel list row are all `--du-control-size` tall;
75
+ the padding around a toolbar's button column and around a menu's rows
76
+ is `--du-chrome-pad`. Change these two to rescale every bar and menu
77
+ together. ---- */
78
+ --du-control-size: 40px;
79
+ --du-chrome-pad: 4px;
80
+
81
+ /* ---- Spacing — 4-px grid. `--du-gap` / `--du-pad` are the working
82
+ defaults for chrome (8 = between controls / inside a surface,
83
+ 4 = inside a group / between grouped items). ---- */
84
+ --du-space-xs: 2px;
85
+ --du-space-sm: 4px;
86
+ --du-space-md: 8px;
87
+ --du-space-lg: 12px;
88
+ --du-space-xl: 16px;
89
+ --du-space-2xl: 24px;
90
+ --du-gap: var(--du-space-md);
91
+ --du-gap-sm: var(--du-space-sm);
92
+ --du-pad: var(--du-space-md);
93
+ --du-pad-sm: var(--du-chrome-pad); /* inset of a button group / dock */
94
+
95
+ /* ---- Sizing · controls ---- */
96
+ --du-button-size: var(--du-control-size); /* toolbar icon button / bar height driver */
97
+ --du-button-size-sm: var(--du-control-size); /* grouped / panel buttons — same 40 (alias) */
98
+ --du-touch-size: 44px; /* minimum tap target on coarse pointers */
99
+ --du-icon-size: 24px; /* toolbar glyph — lucide's native grid, crisp strokes */
100
+ --du-icon-size-sm: 20px; /* in-row glyph (menus, panels) — a step below controls */
101
+ --du-input-h: 36px; /* text / search inputs */
102
+ --du-control-h: 28px; /* small inline controls (number input, swatch fill) */
103
+ --du-swatch-size: 32px; /* colour cell (fill grows from 28 → 32 on hover) */
104
+ --du-switch-w: 30px;
105
+ --du-switch-h: 18px;
106
+ --du-key-h: 24px; /* <kbd> pill in the help dialog */
107
+ --du-checkbox-size: 16px; /* native checkbox in property rows */
108
+ --du-input-icon-size: 12px; /* glyph inside a text input (search) */
109
+ --du-divider-h: var(--du-icon-size); /* vertical separator inside a toolbar row */
110
+
111
+ /* ---- Typography — system stack; 14 body, 12 captions, 10 micro caps. ---- */
112
+ --du-font-family:
113
+ system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
114
+ --du-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
115
+ --du-font-size-xs: 10px;
116
+ --du-font-size-sm: 12px;
117
+ --du-font-size: 14px;
118
+ --du-font-size-lg: 16px;
119
+ --du-font-weight: 400;
120
+ --du-font-weight-strong: 600;
121
+ --du-line-height: 20px;
122
+ --du-caps-tracking: 0.5px; /* letter-spacing of uppercase captions */
123
+
124
+ /* ---- Layout — where the static chrome sits ---- */
125
+ --du-bar-inset: 12px; /* canvas edge → top / bottom bars, side panels, minimap */
126
+ --du-dock-inset: 10px; /* canvas edge → the vertical tool dock */
127
+ --du-flyout-gap: 10px; /* a bar → the menu / flyout that opens from it */
128
+ --du-submenu-gap: 6px; /* parent menu column → nested menu */
129
+ /* Height of a bar = group padding + button + padding + border. */
130
+ --du-bar-height: calc(var(--du-button-size) + 2 * var(--du-pad-sm) + 2px);
131
+ /* Top edge of anything docked under the top bar / above the bottom bar. */
132
+ --du-bar-clear: calc(var(--du-bar-inset) + var(--du-bar-height) + var(--du-gap));
133
+ --du-side-panel-w: 240px;
134
+ --du-brand-h: 24px; /* logo artwork height inside the 40-px brand cell */
135
+ --du-sidebar-w: 280px; /* host-composed <Sidebar> */
136
+ --du-thread-w: 280px; /* comment thread popover */
137
+ --du-panel-row-h: var(--du-control-size); /* list row inside a panel (layers, comments) */
138
+
139
+ /* ---- Menus — one system for the context menu, main / zoom menus, the
140
+ Shapes and lines flyout and list rows inside popovers. ---- */
141
+ --du-menu-pad: var(--du-chrome-pad); /* inset around the rows = toolbar group inset */
142
+ --du-menu-min-w: 240px;
143
+ --du-menu-radius: var(--du-radius);
144
+ --du-menu-row-h: var(--du-control-size); /* = toolbar button height */
145
+ --du-menu-row-pad-x: var(--du-space-xl);
146
+ --du-menu-row-radius: var(--du-radius-sm);
147
+ --du-menu-gutter: 24px; /* icon / check column, same width everywhere */
148
+ --du-menu-gap: var(--du-space-md); /* gutter ↔ label */
149
+ --du-menu-font: var(--du-font-size);
150
+ --du-menu-shortcut-font: var(--du-font-size-sm);
151
+ --du-menu-sep: var(--du-space-md); /* separator / group-title vertical rhythm */
152
+
153
+ /* ---- Popovers (property controls) ---- */
154
+ --du-popover-pad: var(--du-pad);
155
+ --du-popover-min-w: 120px;
156
+ --du-popover-max-w: 320px;
157
+
158
+ /* ---- Modals / dialogs ---- */
159
+ --du-modal-pad-y: var(--du-space-xl);
160
+ --du-modal-pad-x: 20px;
161
+ --du-modal-gap: var(--du-space-lg);
162
+ --du-modal-radius: var(--du-radius-lg);
163
+ --du-modal-max-w: 560px;
164
+ --du-modal-margin: 32px; /* kept clear on each side of the viewport */
165
+
166
+ /* ---- Toasts ---- */
167
+ --du-toast-inset: var(--du-space-xl);
168
+ --du-toast-min-w: 240px;
169
+ --du-toast-max-w: 360px;
170
+
171
+ /* ---- Tooltip ---- */
172
+ --du-tooltip-max-w: 260px;
173
+
174
+ /* ---- z-index scale (one place; chrome inside the UI layer stacks in
175
+ its own context, dialogs / toasts / tooltips portal to body) ---- */
61
176
  --du-z-canvas: 1;
62
- --du-z-ui: 100;
63
- --du-z-modal: 1000;
177
+ --du-z-ui: 100; /* UI layer (bars, docks, panels) + bottom sheets */
178
+ --du-z-link-chrome: 1380; /* sticky reactions, link badges / popups */
179
+ --du-z-floating: 1500; /* selection floating toolbar */
180
+ --du-z-popover: 1600; /* popovers, drop menus, caption editor */
181
+ --du-z-drop-overlay: 1650; /* file-drop hint — over panels and popovers, under menus */
182
+ --du-z-context-menu: 1700; /* above every toolbar, panel and popover */
183
+ --du-z-modal: 1800; /* dialogs — above all floating chrome */
184
+ --du-z-toast: 1900; /* above dialogs */
185
+ --du-z-tooltip: 10000; /* always on top */
186
+
187
+ /* ---- Motion ---- */
188
+ --du-motion-fast: 0.12s ease; /* hover / state changes */
189
+ --du-motion-press: 0.05s ease; /* press scale */
190
+ --du-motion-sheet: 0.18s ease; /* bottom-sheet height snap */
64
191
  }
65
192
 
66
193
  /**
@@ -82,10 +209,12 @@
82
209
  /* The canvas is NOT themed (user content is authored against light
83
210
  paper); dark mode darkens the chrome only. UI_SURFACE.dark.canvas. */
84
211
  --du-canvas-bg: #f5f5f5;
85
- --du-ui-bg: rgba(35, 35, 35, 0.95); /* UI_SURFACE.dark.bg */
212
+ --du-ui-bg: #252525; /* UI_SURFACE.dark.bg */
86
213
  --du-ui-bg-solid: #252525; /* UI_SURFACE.dark.bgSolid */
87
214
  --du-ui-border: rgba(255, 255, 255, 0.08); /* UI_SURFACE.dark.border */
88
- --du-ui-shadow: 0 1px 4px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.3);
215
+ --du-ui-shadow: 0 2px 8px rgba(0, 0, 0, 0.45), 0 0 12px rgba(0, 0, 0, 0.25);
216
+ --du-modal-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
217
+ --du-scrim: rgba(0, 0, 0, 0.65);
89
218
  --du-text: #e8e8e8; /* UI_SURFACE.dark.text */
90
219
  --du-text-muted: #9a9a9a; /* UI_SURFACE.dark.textMuted */
91
220
  --du-accent: #5b5bd6; /* UI_ACCENT.dark.accent (irisDark.iris9) */
@@ -102,10 +231,12 @@
102
231
  up the light palette under all conditions. Mirrors
103
232
  UI_SURFACE.light + UI_ACCENT.light. */
104
233
  --du-canvas-bg: #f5f5f5;
105
- --du-ui-bg: rgba(255, 255, 255, 0.95);
234
+ --du-ui-bg: #ffffff;
106
235
  --du-ui-bg-solid: #ffffff;
107
236
  --du-ui-border: rgba(0, 0, 0, 0.08);
108
- --du-ui-shadow: 0 1px 4px rgba(0, 0, 0, 0.08), 0 4px 12px rgba(0, 0, 0, 0.04);
237
+ --du-ui-shadow: 0 2px 8px rgba(34, 36, 40, 0.12), 0 0 12px rgba(34, 36, 40, 0.04);
238
+ --du-modal-shadow: 0 8px 32px rgba(34, 36, 40, 0.24);
239
+ --du-scrim: rgba(0, 0, 0, 0.55);
109
240
  --du-text: #1a1a1a;
110
241
  --du-text-muted: #6b6b6b;
111
242
  --du-accent: #5b5bd6; /* iris.iris9 */
@@ -116,8 +247,8 @@
116
247
  }
117
248
 
118
249
  /* ------------------------------------------------------------------ */
119
- /* Legacy variable aliases — kept so the older components (MainMenu, */
120
- /* ContextMenu, Modal, HelpDialog) that read `var(--panel)` / */
250
+ /* Legacy variable aliases (DEPRECATED prefer `--du-*`). Kept so */
251
+ /* hosts and older components that read `var(--panel)` / */
121
252
  /* `var(--text)` / `var(--button-bg)` etc. still pick up the active */
122
253
  /* theme without being rewritten to the `--du-*` namespace. */
123
254
  /* */
@@ -159,17 +290,21 @@
159
290
  --toolbar-bg: var(--du-ui-bg-solid);
160
291
  --cursor-bg: var(--du-selected-bg);
161
292
  --code-bg: var(--du-ui-bg-solid);
162
- --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
293
+ --font-mono: var(--du-font-mono);
294
+ --panel-fg: var(--du-text);
295
+ --du-accent-strong: var(--du-accent-hover);
163
296
  }
164
297
 
165
298
  [data-theme="dark"] {
166
299
  /* Mirrors UI_SURFACE.dark + UI_ACCENT.dark from `@oh-just-another/tokens`. */
167
300
  /* Canvas stays light — see the note in the media-query block above. */
168
301
  --du-canvas-bg: #f5f5f5;
169
- --du-ui-bg: rgba(35, 35, 35, 0.95);
302
+ --du-ui-bg: #252525;
170
303
  --du-ui-bg-solid: #252525;
171
304
  --du-ui-border: rgba(255, 255, 255, 0.08);
172
- --du-ui-shadow: 0 1px 4px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.3);
305
+ --du-ui-shadow: 0 2px 8px rgba(0, 0, 0, 0.45), 0 0 12px rgba(0, 0, 0, 0.25);
306
+ --du-modal-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
307
+ --du-scrim: rgba(0, 0, 0, 0.65);
173
308
  --du-text: #e8e8e8;
174
309
  --du-text-muted: #9a9a9a;
175
310
  --du-accent: #5b5bd6; /* irisDark.iris9 */
@@ -180,19 +315,16 @@
180
315
  }
181
316
 
182
317
  /* ------------------------------------------------------------------ */
183
- /* Canvas surface focus ring. The surface is `tabIndex=0` so keyboard */
184
- /* users can land on it, but it also takes focus on a pointer press */
185
- /* (so shortcuts work right after a click). Gate the ring on */
186
- /* `:focus-visible` so it shows ONLY for keyboard focus — a mouse click */
187
- /* never draws an input-like outline. Class+pseudo specificity (0,2,0) */
188
- /* beats a host's `*:focus { outline: none }`. */
318
+ /* Canvas surface: `tabIndex=0` so it can hold focus (shortcuts work */
319
+ /* right after a click / Tab), but it never draws a focus ring the */
320
+ /* selection chrome on the canvas is the focus indication. Programmatic */
321
+ /* re-focus after a click makes browsers match `:focus-visible`, so */
322
+ /* that state is silenced too. */
189
323
  /* ------------------------------------------------------------------ */
190
- .du-canvas-surface {
191
- outline: none;
192
- }
324
+ .du-canvas-surface,
325
+ .du-canvas-surface:focus,
193
326
  .du-canvas-surface:focus-visible {
194
- outline: 2px solid var(--du-accent);
195
- outline-offset: -2px;
327
+ outline: none;
196
328
  }
197
329
 
198
330
  /* ------------------------------------------------------------------ */
@@ -265,13 +397,14 @@
265
397
  border: 1px solid var(--du-ui-border);
266
398
  border-radius: var(--du-radius);
267
399
  cursor: pointer;
268
- font-size: 14px;
400
+ font-family: var(--du-font-family);
401
+ font-size: var(--du-font-size);
269
402
  line-height: 1;
270
403
  box-shadow: var(--du-ui-shadow);
271
404
  transition:
272
- background 0.12s ease,
273
- color 0.12s ease,
274
- transform 0.05s ease;
405
+ background var(--du-motion-fast),
406
+ color var(--du-motion-fast),
407
+ transform var(--du-motion-press);
275
408
  padding: 0;
276
409
  outline: none;
277
410
  user-select: none;
@@ -292,7 +425,7 @@
292
425
 
293
426
  .du-icon-button:focus-visible {
294
427
  outline: 2px solid var(--du-accent);
295
- outline-offset: 2px;
428
+ outline-offset: var(--du-space-xs);
296
429
  }
297
430
 
298
431
  .du-icon-button[aria-pressed="true"],
@@ -312,7 +445,7 @@
312
445
  .du-icon-button-sm {
313
446
  width: var(--du-button-size-sm);
314
447
  height: var(--du-button-size-sm);
315
- font-size: 12px;
448
+ font-size: var(--du-font-size-sm);
316
449
  }
317
450
 
318
451
  /**
@@ -355,6 +488,22 @@
355
488
  be able to render outside the group's bounds. */
356
489
  }
357
490
 
491
+ /* Items inside a toolbar group take the item radius (4); the group itself
492
+ keeps the toolbar radius (8). */
493
+ .du-button-group > .du-icon-button,
494
+ .du-button-group > .du-shapes-wrap > .du-icon-button {
495
+ border-radius: var(--du-radius-sm);
496
+ }
497
+
498
+ /* Inside a popover the group is a plain segmented row: the popover
499
+ already provides the surface, so no nested card chrome. */
500
+ .du-popover .du-button-group {
501
+ padding: 0;
502
+ background: transparent;
503
+ border: 0;
504
+ box-shadow: none;
505
+ }
506
+
358
507
  /* Vertical variant — the left creation dock. Stacks buttons in a
359
508
  column; dividers (rendered inline by <Toolbar>) become horizontal. */
360
509
  .du-button-group-vertical {
@@ -362,7 +511,8 @@
362
511
  align-items: stretch;
363
512
  }
364
513
 
365
- .du-button-group > .du-icon-button {
514
+ .du-button-group > .du-icon-button,
515
+ .du-button-group > .du-shapes-wrap > .du-icon-button {
366
516
  border: none;
367
517
  box-shadow: none;
368
518
  border-radius: var(--du-radius-sm);
@@ -372,7 +522,8 @@
372
522
  }
373
523
 
374
524
  /* Vertical dock buttons are square + centred (icon-only tools). */
375
- .du-button-group-vertical > .du-icon-button {
525
+ .du-button-group-vertical > .du-icon-button,
526
+ .du-button-group-vertical > .du-shapes-wrap > .du-icon-button {
376
527
  width: var(--du-button-size-sm) !important;
377
528
  min-width: var(--du-button-size-sm) !important;
378
529
  padding: 0 !important;
@@ -408,25 +559,31 @@
408
559
  .du-button-group-vertical::-webkit-scrollbar {
409
560
  display: none;
410
561
  }
411
- .du-button-group-vertical > .du-icon-button {
412
- width: 44px !important;
413
- min-width: 44px !important;
414
- height: 44px !important;
562
+ .du-button-group-vertical > .du-icon-button,
563
+ .du-button-group-vertical > .du-shapes-wrap > .du-icon-button {
564
+ width: var(--du-touch-size) !important;
565
+ min-width: var(--du-touch-size) !important;
566
+ height: var(--du-touch-size) !important;
415
567
  }
416
568
  }
417
569
 
418
- .du-button-group > .du-icon-button:hover:not(:disabled) {
570
+ .du-button-group > .du-icon-button:hover:not(:disabled),
571
+ .du-button-group > .du-shapes-wrap > .du-icon-button:hover:not(:disabled) {
419
572
  background: var(--du-hover-overlay);
420
573
  }
421
574
 
422
575
  .du-button-group > .du-icon-button[aria-pressed="true"],
423
- .du-button-group > .du-icon-button.is-active {
576
+ .du-button-group > .du-shapes-wrap > .du-icon-button[aria-pressed="true"],
577
+ .du-button-group > .du-icon-button.is-active,
578
+ .du-button-group > .du-shapes-wrap > .du-icon-button.is-active {
424
579
  background: var(--du-selected-bg);
425
580
  color: var(--du-selected-fg);
426
581
  }
427
582
 
428
583
  .du-button-group > .du-icon-button[aria-pressed="true"]:hover:not(:disabled),
429
- .du-button-group > .du-icon-button.is-active:hover:not(:disabled) {
584
+ .du-button-group > .du-shapes-wrap > .du-icon-button[aria-pressed="true"]:hover:not(:disabled),
585
+ .du-button-group > .du-icon-button.is-active:hover:not(:disabled),
586
+ .du-button-group > .du-shapes-wrap > .du-icon-button.is-active:hover:not(:disabled) {
430
587
  background: color-mix(in srgb, var(--du-selected-bg) 90%, var(--du-text) 10%);
431
588
  }
432
589
 
@@ -437,13 +594,13 @@
437
594
  /* ------------------------------------------------------------------ */
438
595
  .du-side-panel {
439
596
  position: absolute;
440
- top: calc(var(--du-bar-inset) + var(--du-button-size) + var(--du-gap));
441
- bottom: calc(var(--du-bar-inset) + var(--du-button-size) + var(--du-gap));
442
- width: 240px;
597
+ top: var(--du-bar-clear);
598
+ bottom: var(--du-bar-clear);
599
+ width: var(--du-side-panel-w);
443
600
  background: var(--du-ui-bg);
444
601
  color: var(--du-text);
445
602
  border: 1px solid var(--du-ui-border);
446
- border-radius: var(--du-radius);
603
+ border-radius: var(--du-radius-lg);
447
604
  box-shadow: var(--du-ui-shadow);
448
605
  display: flex;
449
606
  flex-direction: column;
@@ -477,13 +634,13 @@
477
634
  .du-side-panel-header {
478
635
  display: flex;
479
636
  align-items: center;
480
- justify-content: flex-end;
637
+ justify-content: space-between;
481
638
  gap: var(--du-gap-sm);
482
639
  padding: var(--du-pad-sm) var(--du-pad-sm) var(--du-pad-sm) var(--du-pad);
483
- font-size: 12px;
484
- font-weight: 600;
640
+ font-size: var(--du-font-size-sm);
641
+ font-weight: var(--du-font-weight-strong);
485
642
  text-transform: uppercase;
486
- letter-spacing: 0.5px;
643
+ letter-spacing: var(--du-caps-tracking);
487
644
  color: var(--du-text-muted);
488
645
  }
489
646
 
@@ -492,6 +649,16 @@
492
649
  display: none;
493
650
  }
494
651
 
652
+ /* Panel title in the header's left slot (normal case, full text colour —
653
+ the header's uppercase muted styling is for action captions). */
654
+ .du-side-panel-title {
655
+ font-size: var(--du-font-size);
656
+ font-weight: 600;
657
+ color: var(--du-text);
658
+ text-transform: none;
659
+ letter-spacing: normal;
660
+ }
661
+
495
662
  /* Auto-height variant — content hugs its natural height instead
496
663
  of stretching from top to bottom of the canvas area. Used by
497
664
  the Properties panel so it shrinks to whatever the inspector
@@ -499,7 +666,7 @@
499
666
  so its long grid can scroll. */
500
667
  .du-side-panel-auto-height {
501
668
  bottom: auto;
502
- max-height: calc(100% - 2 * var(--du-bar-inset) - 2 * var(--du-button-size) - 2 * var(--du-gap));
669
+ max-height: calc(100% - 2 * var(--du-bar-clear));
503
670
  }
504
671
 
505
672
  .du-side-panel-body {
@@ -516,6 +683,335 @@
516
683
  padding: 0;
517
684
  }
518
685
 
686
+ /* Static variant — a card the host lays out itself (LayerPanel,
687
+ CommentsPanel inside a <Sidebar> or any flex column). Same chrome, no
688
+ absolute positioning; stretches to the host's height. */
689
+ .du-side-panel-static {
690
+ position: static;
691
+ top: auto;
692
+ bottom: auto;
693
+ min-height: 0;
694
+ max-height: 100%;
695
+ }
696
+
697
+ /* ------------------------------------------------------------------ */
698
+ /* Panel lists — rows inside a side panel share the menu-row rhythm */
699
+ /* (40-px rows, hover wash, tonal selected state). */
700
+ /* ------------------------------------------------------------------ */
701
+ .du-panel-list {
702
+ display: flex;
703
+ flex-direction: column;
704
+ padding: var(--du-pad-sm);
705
+ }
706
+
707
+ .du-panel-row {
708
+ all: unset;
709
+ display: flex;
710
+ align-items: center;
711
+ gap: var(--du-gap-sm);
712
+ box-sizing: border-box;
713
+ width: 100%;
714
+ min-height: var(--du-panel-row-h);
715
+ padding: 0 var(--du-pad-sm) 0 var(--du-pad);
716
+ border-radius: var(--du-radius-sm);
717
+ font-family: var(--du-font-family);
718
+ font-size: var(--du-font-size);
719
+ line-height: var(--du-line-height);
720
+ color: var(--du-text);
721
+ cursor: pointer;
722
+ }
723
+
724
+ .du-panel-row:hover {
725
+ background: var(--du-hover-overlay);
726
+ }
727
+
728
+ .du-panel-row.is-active {
729
+ background: var(--du-selected-bg);
730
+ color: var(--du-selected-fg);
731
+ }
732
+
733
+ .du-panel-row.is-muted {
734
+ opacity: 0.55;
735
+ }
736
+
737
+ .du-panel-row:focus-visible {
738
+ outline: 2px solid var(--du-accent);
739
+ outline-offset: -2px;
740
+ }
741
+
742
+ /* Two-line row (comments): meta line + preview, both left-aligned. */
743
+ .du-panel-row-stack {
744
+ flex-direction: column;
745
+ align-items: stretch;
746
+ justify-content: center;
747
+ gap: 0;
748
+ padding: var(--du-pad-sm) var(--du-pad);
749
+ text-align: left;
750
+ }
751
+
752
+ .du-panel-row-label {
753
+ flex: 1;
754
+ min-width: 0;
755
+ overflow: hidden;
756
+ text-overflow: ellipsis;
757
+ white-space: nowrap;
758
+ }
759
+
760
+ .du-panel-row-label.is-muted {
761
+ color: var(--du-text-muted);
762
+ }
763
+
764
+ .du-panel-row.is-active .du-panel-row-label.is-muted {
765
+ color: inherit;
766
+ }
767
+
768
+ .du-panel-row-meta {
769
+ display: flex;
770
+ gap: var(--du-gap-sm);
771
+ font-size: var(--du-font-size-sm);
772
+ color: var(--du-text-muted);
773
+ }
774
+
775
+ .du-panel-row-meta > strong {
776
+ color: var(--du-text);
777
+ font-weight: var(--du-font-weight-strong);
778
+ }
779
+
780
+ .du-panel-row.is-active .du-panel-row-meta,
781
+ .du-panel-row.is-active .du-panel-row-meta > strong {
782
+ color: inherit;
783
+ }
784
+
785
+ .du-panel-row-meta-end {
786
+ margin-left: auto;
787
+ }
788
+
789
+ .du-panel-empty {
790
+ padding: var(--du-space-xl) var(--du-pad);
791
+ font-size: var(--du-font-size-sm);
792
+ line-height: var(--du-line-height);
793
+ color: var(--du-text-muted);
794
+ }
795
+
796
+ /* Inline text input inside a panel row / form. */
797
+ .du-panel-input {
798
+ flex: 1;
799
+ min-width: 0;
800
+ height: var(--du-input-h);
801
+ box-sizing: border-box;
802
+ padding: 0 var(--du-space-md);
803
+ font: inherit;
804
+ font-family: var(--du-font-family);
805
+ font-size: var(--du-font-size-sm);
806
+ color: var(--du-text);
807
+ background: var(--du-ui-bg-solid);
808
+ border: 1px solid var(--du-ui-border);
809
+ border-radius: var(--du-radius-sm);
810
+ outline: none;
811
+ }
812
+
813
+ .du-panel-input::placeholder {
814
+ color: var(--du-text-muted);
815
+ }
816
+
817
+ .du-panel-input:focus {
818
+ border-color: var(--du-accent);
819
+ }
820
+
821
+ /* Muted flat icon button (hidden / unlocked layer toggles). */
822
+ .du-icon-button-flat.is-muted {
823
+ opacity: 0.4;
824
+ }
825
+
826
+ .du-icon-button-flat.is-muted:hover:not(:disabled) {
827
+ opacity: 1;
828
+ }
829
+
830
+ /* ------------------------------------------------------------------ */
831
+ /* Text button — small labelled action (dialog footers, thread header, */
832
+ /* sidebar tabs). `is-active` = tonal selected; `-primary` = accent. */
833
+ /* ------------------------------------------------------------------ */
834
+ .du-button {
835
+ display: inline-flex;
836
+ align-items: center;
837
+ justify-content: center;
838
+ gap: var(--du-gap-sm);
839
+ height: var(--du-button-size-sm);
840
+ padding: 0 var(--du-space-lg);
841
+ font-family: var(--du-font-family);
842
+ font-size: var(--du-font-size);
843
+ font-weight: var(--du-font-weight);
844
+ line-height: 1;
845
+ color: var(--du-text);
846
+ background: var(--du-ui-bg-solid);
847
+ border: 1px solid var(--du-ui-border);
848
+ border-radius: var(--du-radius-sm);
849
+ cursor: pointer;
850
+ white-space: nowrap;
851
+ transition:
852
+ background var(--du-motion-fast),
853
+ color var(--du-motion-fast);
854
+ }
855
+
856
+ .du-button:hover:not(:disabled) {
857
+ background: var(--du-hover-overlay);
858
+ }
859
+
860
+ .du-button:disabled {
861
+ cursor: not-allowed;
862
+ opacity: 0.4;
863
+ }
864
+
865
+ .du-button.is-active {
866
+ background: var(--du-selected-bg);
867
+ color: var(--du-selected-fg);
868
+ border-color: transparent;
869
+ }
870
+
871
+ .du-button-primary {
872
+ background: var(--du-accent);
873
+ color: var(--du-text-on-accent);
874
+ border-color: transparent;
875
+ }
876
+
877
+ .du-button-primary:hover:not(:disabled) {
878
+ background: var(--du-accent-hover);
879
+ }
880
+
881
+ .du-button:focus-visible {
882
+ outline: 2px solid var(--du-accent);
883
+ outline-offset: var(--du-space-xs);
884
+ }
885
+
886
+ /* ------------------------------------------------------------------ */
887
+ /* Sidebar — host-composed docked column with tabs (see <Sidebar>). */
888
+ /* ------------------------------------------------------------------ */
889
+ .du-sidebar {
890
+ display: flex;
891
+ flex-direction: column;
892
+ width: var(--du-sidebar-w);
893
+ min-height: 0;
894
+ font-family: var(--du-font-family);
895
+ font-size: var(--du-font-size);
896
+ color: var(--du-text);
897
+ background: var(--du-ui-bg-solid);
898
+ }
899
+
900
+ .du-sidebar-right {
901
+ border-left: 1px solid var(--du-ui-border);
902
+ }
903
+
904
+ .du-sidebar-left {
905
+ border-right: 1px solid var(--du-ui-border);
906
+ }
907
+
908
+ .du-sidebar-header {
909
+ padding: var(--du-space-lg) var(--du-space-xl);
910
+ font-size: var(--du-font-size);
911
+ font-weight: var(--du-font-weight-strong);
912
+ line-height: var(--du-line-height);
913
+ border-bottom: 1px solid var(--du-ui-border);
914
+ }
915
+
916
+ .du-sidebar-tabs {
917
+ display: flex;
918
+ gap: var(--du-gap-sm);
919
+ padding: var(--du-pad);
920
+ border-bottom: 1px solid var(--du-ui-border);
921
+ }
922
+
923
+ .du-sidebar-body {
924
+ flex: 1 1 auto;
925
+ min-height: 0;
926
+ overflow-y: auto;
927
+ padding: var(--du-pad);
928
+ }
929
+
930
+ .du-sidebar-section {
931
+ padding: var(--du-pad) var(--du-space-lg);
932
+ border-bottom: 1px solid var(--du-ui-border);
933
+ }
934
+
935
+ /* ------------------------------------------------------------------ */
936
+ /* Comment thread popover — floating card top-right of the canvas. */
937
+ /* ------------------------------------------------------------------ */
938
+ .du-thread {
939
+ position: absolute;
940
+ top: var(--du-bar-inset);
941
+ right: var(--du-bar-inset);
942
+ z-index: var(--du-z-popover);
943
+ display: flex;
944
+ flex-direction: column;
945
+ width: var(--du-thread-w);
946
+ max-height: 70vh;
947
+ font-family: var(--du-font-family);
948
+ font-size: var(--du-font-size);
949
+ line-height: var(--du-line-height);
950
+ color: var(--du-text);
951
+ background: var(--du-ui-bg-solid);
952
+ border: 1px solid var(--du-ui-border);
953
+ border-radius: var(--du-radius-lg);
954
+ box-shadow: var(--du-ui-shadow);
955
+ }
956
+
957
+ .du-thread-header {
958
+ display: flex;
959
+ align-items: center;
960
+ gap: var(--du-gap-sm);
961
+ padding: var(--du-pad-sm) var(--du-pad-sm) var(--du-pad-sm) var(--du-pad);
962
+ border-bottom: 1px solid var(--du-ui-border);
963
+ }
964
+
965
+ .du-thread-status {
966
+ flex: 1;
967
+ font-size: var(--du-font-size-sm);
968
+ color: var(--du-text-muted);
969
+ }
970
+
971
+ .du-thread-body {
972
+ flex: 1;
973
+ overflow-y: auto;
974
+ padding: var(--du-pad);
975
+ }
976
+
977
+ .du-thread-item {
978
+ position: relative;
979
+ padding-right: var(--du-button-size-sm);
980
+ margin-bottom: var(--du-space-lg);
981
+ }
982
+
983
+ .du-thread-item:last-child {
984
+ margin-bottom: 0;
985
+ }
986
+
987
+ .du-thread-item-remove {
988
+ position: absolute;
989
+ top: 0;
990
+ right: 0;
991
+ }
992
+
993
+ .du-thread-item-meta {
994
+ margin-bottom: var(--du-space-xs);
995
+ font-size: var(--du-font-size-sm);
996
+ color: var(--du-text-muted);
997
+ }
998
+
999
+ .du-thread-item-meta > strong {
1000
+ color: var(--du-text);
1001
+ font-weight: var(--du-font-weight-strong);
1002
+ }
1003
+
1004
+ .du-thread-item-body {
1005
+ white-space: pre-wrap;
1006
+ }
1007
+
1008
+ .du-thread-form {
1009
+ display: flex;
1010
+ gap: var(--du-gap-sm);
1011
+ padding: var(--du-pad);
1012
+ border-top: 1px solid var(--du-ui-border);
1013
+ }
1014
+
519
1015
  /* ------------------------------------------------------------------ */
520
1016
  /* Palette (template library content) — sectioned grid of icon tiles. */
521
1017
  /* No per-tile borders, no per-section dividers — visual structure */
@@ -536,8 +1032,9 @@
536
1032
  flex-direction: column;
537
1033
  }
538
1034
 
1035
+ /* Sections sit inside the same inset a menu panel gives its rows. */
539
1036
  .du-palette-section {
540
- padding: 0 var(--du-pad) var(--du-pad-sm);
1037
+ padding: 0 var(--du-menu-pad);
541
1038
  }
542
1039
 
543
1040
  .du-palette-category {
@@ -545,12 +1042,13 @@
545
1042
  background: transparent;
546
1043
  color: var(--du-text-muted);
547
1044
  border: none;
548
- padding: 10px 0 6px;
1045
+ /* Same rhythm as `.du-menu-group-title`. */
1046
+ padding: var(--du-menu-sep) var(--du-menu-row-pad-x) var(--du-space-xs);
549
1047
  font: inherit;
550
- font-size: 11px;
551
- font-weight: 600;
1048
+ font-size: var(--du-menu-shortcut-font);
1049
+ font-weight: var(--du-font-weight-strong);
552
1050
  text-transform: uppercase;
553
- letter-spacing: 0.5px;
1051
+ letter-spacing: var(--du-caps-tracking);
554
1052
  text-align: left;
555
1053
  cursor: pointer;
556
1054
  display: flex;
@@ -579,14 +1077,12 @@
579
1077
  padding: 0;
580
1078
  }
581
1079
 
582
- /* Compact list layout (modern-style templates panel) — single column of
583
- icon + name rows. Denser than the grid; the label reads left-aligned
584
- beside a small icon. */
1080
+ /* List layout (templates panel) — single column of icon + name rows in
1081
+ the shared menu-row rhythm (`--du-panel-row-h`, `--du-menu-row-pad-x`). */
585
1082
  .du-palette-list {
586
1083
  display: flex;
587
1084
  flex-direction: column;
588
- gap: 2px;
589
- padding: 0 var(--du-pad) var(--du-pad-sm);
1085
+ padding: 0 var(--du-menu-pad);
590
1086
  }
591
1087
  .du-palette-section > .du-palette-list {
592
1088
  padding: 0;
@@ -596,15 +1092,17 @@
596
1092
  align-items: center;
597
1093
  justify-content: flex-start;
598
1094
  aspect-ratio: auto;
599
- gap: 8px;
600
- padding: 5px 8px;
1095
+ gap: var(--du-menu-gap);
1096
+ min-height: var(--du-panel-row-h);
1097
+ padding: 0 var(--du-menu-row-pad-x);
1098
+ border-radius: var(--du-menu-row-radius);
601
1099
  text-align: left;
602
- font-size: 12px;
603
- line-height: 1.2;
1100
+ font-size: var(--du-menu-font);
1101
+ line-height: var(--du-line-height);
604
1102
  }
605
1103
  .du-palette-list .du-palette-item-icon {
606
- width: 20px !important;
607
- height: 20px !important;
1104
+ width: var(--du-icon-size) !important;
1105
+ height: var(--du-icon-size) !important;
608
1106
  flex: 0 0 auto;
609
1107
  }
610
1108
  .du-palette-list .du-palette-item-label {
@@ -615,9 +1113,9 @@
615
1113
  }
616
1114
 
617
1115
  .du-palette-empty {
618
- padding: 24px 12px;
1116
+ padding: var(--du-space-2xl) var(--du-space-lg);
619
1117
  text-align: center;
620
- font-size: 12px;
1118
+ font-size: var(--du-font-size-sm);
621
1119
  color: var(--du-text-muted);
622
1120
  }
623
1121
 
@@ -626,18 +1124,18 @@
626
1124
  flex-direction: column;
627
1125
  align-items: center;
628
1126
  justify-content: center;
629
- gap: 4px;
1127
+ gap: var(--du-space-sm);
630
1128
  aspect-ratio: 1;
631
- padding: 6px 4px;
1129
+ padding: var(--du-space-sm);
632
1130
  background: transparent;
633
1131
  color: var(--du-text);
634
1132
  border: none;
635
1133
  border-radius: var(--du-radius-sm);
636
1134
  cursor: grab;
637
1135
  text-align: center;
638
- font-size: 10px;
1136
+ font-size: var(--du-font-size-xs);
639
1137
  line-height: 1.1;
640
- transition: background 0.12s ease;
1138
+ transition: background var(--du-motion-fast);
641
1139
  }
642
1140
 
643
1141
  .du-palette-item:hover {
@@ -679,24 +1177,24 @@
679
1177
  .du-prop-panel {
680
1178
  display: flex;
681
1179
  flex-direction: column;
682
- gap: 16px;
683
- padding: 4px 0;
1180
+ gap: var(--du-space-xl);
1181
+ padding: var(--du-space-sm) 0;
684
1182
  color: var(--du-text);
685
- font-size: 12px;
1183
+ font-size: var(--du-font-size-sm);
686
1184
  }
687
1185
 
688
1186
  .du-prop-section {
689
1187
  display: flex;
690
1188
  flex-direction: column;
691
- gap: 6px;
1189
+ gap: var(--du-space-sm);
692
1190
  }
693
1191
 
694
1192
  .du-prop-section-label {
695
1193
  margin: 0;
696
- font-size: 10px;
697
- font-weight: 600;
1194
+ font-size: var(--du-font-size-xs);
1195
+ font-weight: var(--du-font-weight-strong);
698
1196
  text-transform: uppercase;
699
- letter-spacing: 0.5px;
1197
+ letter-spacing: var(--du-caps-tracking);
700
1198
  color: var(--du-text-muted);
701
1199
  }
702
1200
 
@@ -708,15 +1206,15 @@
708
1206
  }
709
1207
 
710
1208
  .du-prop-row-label {
711
- font-size: 11px;
1209
+ font-size: var(--du-font-size-sm);
712
1210
  color: var(--du-text-muted);
713
- min-width: 48px;
1211
+ min-width: 48px; /* label column of a prop row */
714
1212
  }
715
1213
 
716
1214
  .du-prop-empty {
717
1215
  font-style: italic;
718
1216
  color: var(--du-text-muted);
719
- font-size: 12px;
1217
+ font-size: var(--du-font-size-sm);
720
1218
  }
721
1219
 
722
1220
  /* modern-style flat segmented control inside the panel:
@@ -727,7 +1225,7 @@
727
1225
  border: none;
728
1226
  box-shadow: none;
729
1227
  padding: 0;
730
- gap: 2px;
1228
+ gap: var(--du-space-xs);
731
1229
  }
732
1230
 
733
1231
  /* Tighter active state inside the panel (smaller buttons, same
@@ -742,16 +1240,16 @@
742
1240
  .du-prop-checkbox {
743
1241
  display: inline-flex;
744
1242
  align-items: center;
745
- gap: 6px;
1243
+ gap: var(--du-space-sm);
746
1244
  cursor: pointer;
747
- font-size: 12px;
1245
+ font-size: var(--du-font-size-sm);
748
1246
  color: var(--du-text);
749
1247
  user-select: none;
750
1248
  }
751
1249
 
752
1250
  .du-prop-checkbox input[type="checkbox"] {
753
- width: 14px;
754
- height: 14px;
1251
+ width: var(--du-checkbox-size);
1252
+ height: var(--du-checkbox-size);
755
1253
  margin: 0;
756
1254
  accent-color: var(--du-selected-fg);
757
1255
  cursor: pointer;
@@ -766,14 +1264,14 @@
766
1264
  .du-swatch-grid {
767
1265
  display: inline-flex;
768
1266
  flex-wrap: wrap;
769
- gap: 4px;
770
- max-width: 232px; /* 8 cells (26 × 8 = 208) + 7 gaps × 4 = ~232 */
1267
+ gap: var(--du-space-sm);
1268
+ max-width: calc(8 * var(--du-swatch-size) + 7 * var(--du-space-sm)); /* 8 cells per row */
771
1269
  }
772
1270
 
773
1271
  .du-swatch {
774
1272
  position: relative;
775
- width: 26px;
776
- height: 26px;
1273
+ width: var(--du-swatch-size);
1274
+ height: var(--du-swatch-size);
777
1275
  padding: 0;
778
1276
  background: transparent;
779
1277
  border: none;
@@ -784,7 +1282,7 @@
784
1282
  justify-content: center;
785
1283
  /* Reserve the ring space so width never changes on selection. */
786
1284
  box-shadow: inset 0 0 0 0 transparent;
787
- transition: box-shadow 0.12s ease;
1285
+ transition: box-shadow var(--du-motion-fast);
788
1286
  /* Suppress the UA tap-highlight on iOS so the cell looks clean
789
1287
  while the user drags through swatches. */
790
1288
  -webkit-tap-highlight-color: transparent;
@@ -803,21 +1301,21 @@
803
1301
  display: inline-flex;
804
1302
  align-items: center;
805
1303
  justify-content: center;
806
- width: 24px;
807
- height: 24px;
1304
+ width: var(--du-control-h);
1305
+ height: var(--du-control-h);
808
1306
  border-radius: var(--du-radius-sm);
809
1307
  border: 1px solid var(--du-ui-border);
810
1308
  box-sizing: border-box;
811
1309
  transition:
812
- width 0.12s ease,
813
- height 0.12s ease,
814
- border-color 0.12s ease;
1310
+ width var(--du-motion-fast),
1311
+ height var(--du-motion-fast),
1312
+ border-color var(--du-motion-fast);
815
1313
  }
816
1314
 
817
1315
  .du-swatch:hover .du-swatch-fill,
818
1316
  .du-swatch:focus-visible .du-swatch-fill {
819
- width: 26px;
820
- height: 26px;
1317
+ width: var(--du-swatch-size);
1318
+ height: var(--du-swatch-size);
821
1319
  }
822
1320
 
823
1321
  /* Clear (×) + custom-picker (+) cells use the same chrome as a
@@ -842,12 +1340,526 @@
842
1340
  }
843
1341
 
844
1342
  /* ------------------------------------------------------------------ */
845
- /* Slider — themed native <input type=range> + value badge. */
846
1343
  /* ------------------------------------------------------------------ */
847
- .du-slider {
1344
+ /* Menu system — shared by the context menu, the main / zoom menus, */
1345
+ /* the Shapes and lines flyout and list rows inside popovers. All */
1346
+ /* metrics come from the `--du-menu-*` tokens. */
1347
+ /* ------------------------------------------------------------------ */
1348
+ .du-menu-panel {
1349
+ box-sizing: border-box;
1350
+ min-width: var(--du-menu-min-w);
1351
+ padding: var(--du-menu-pad);
1352
+ font-size: var(--du-menu-font);
1353
+ color: var(--menu-text);
1354
+ background: var(--menu-bg);
1355
+ border: 1px solid var(--menu-border);
1356
+ border-radius: var(--du-menu-radius);
1357
+ box-shadow: var(--du-ui-shadow);
1358
+ }
1359
+
1360
+ .du-menu-row {
1361
+ all: unset;
1362
+ box-sizing: border-box;
848
1363
  display: flex;
1364
+ gap: var(--du-menu-gap);
849
1365
  align-items: center;
850
- gap: 8px;
1366
+ justify-content: space-between;
1367
+ width: 100%;
1368
+ min-height: var(--du-menu-row-h);
1369
+ padding: 0 var(--du-menu-row-pad-x);
1370
+ font-size: var(--du-menu-font);
1371
+ color: var(--du-text);
1372
+ text-align: left;
1373
+ border-radius: var(--du-menu-row-radius);
1374
+ cursor: pointer;
1375
+ }
1376
+
1377
+ .du-menu-row:hover:not(:disabled),
1378
+ .du-menu-row.is-open {
1379
+ background: var(--du-hover-overlay);
1380
+ }
1381
+
1382
+ .du-menu-row.is-active {
1383
+ background: var(--du-selected-bg);
1384
+ }
1385
+
1386
+ .du-menu-row:disabled {
1387
+ cursor: not-allowed;
1388
+ opacity: 0.4;
1389
+ }
1390
+
1391
+ .du-menu-row:focus-visible {
1392
+ outline: 2px solid var(--du-accent);
1393
+ outline-offset: -2px;
1394
+ }
1395
+
1396
+ /* Label side: gutter + text. */
1397
+ .du-menu-row-main {
1398
+ display: inline-flex;
1399
+ gap: var(--du-menu-gap);
1400
+ align-items: center;
1401
+ min-width: 0;
1402
+ }
1403
+
1404
+ /* Leading gutter: icon, check mark or empty — labels align across rows. */
1405
+ .du-menu-gutter {
1406
+ display: inline-flex;
1407
+ flex: none;
1408
+ align-items: center;
1409
+ justify-content: center;
1410
+ width: var(--du-menu-gutter);
1411
+ color: var(--du-text-muted);
1412
+ }
1413
+
1414
+ .du-menu-gutter.is-accent {
1415
+ color: var(--du-accent);
1416
+ }
1417
+
1418
+ /* Trailing side: shortcut / chevron / control. */
1419
+ .du-menu-shortcut {
1420
+ margin-left: auto;
1421
+ font-size: var(--du-menu-shortcut-font);
1422
+ color: var(--du-text-muted);
1423
+ }
1424
+
1425
+ .du-menu-sep {
1426
+ margin: var(--du-menu-sep) 0;
1427
+ border: 0;
1428
+ border-top: 1px solid var(--menu-divider);
1429
+ }
1430
+
1431
+ .du-menu-group-title {
1432
+ padding: var(--du-menu-sep) var(--du-menu-row-pad-x) var(--du-space-xs);
1433
+ font-size: var(--du-menu-shortcut-font);
1434
+ letter-spacing: var(--du-caps-tracking);
1435
+ color: var(--du-text-muted);
1436
+ text-transform: uppercase;
1437
+ }
1438
+
1439
+ /* Nested panel of the main menu. The `::before` bridge covers the
1440
+ `--du-submenu-gap` strip (plus the parent's inset + border) so the
1441
+ pointer travelling from the parent row into the child never leaves the
1442
+ submenu wrapper — otherwise the gap would fire the delayed close. */
1443
+ .du-menu-submenu::before {
1444
+ content: "";
1445
+ position: absolute;
1446
+ top: 0;
1447
+ bottom: 0;
1448
+ right: 100%;
1449
+ width: calc(var(--du-menu-pad) + 1px + var(--du-submenu-gap));
1450
+ }
1451
+
1452
+ /* Modals share one padding / radius rhythm. */
1453
+ .du-modal-header {
1454
+ display: flex;
1455
+ gap: var(--du-modal-gap);
1456
+ align-items: center;
1457
+ justify-content: space-between;
1458
+ padding: var(--du-modal-pad-y) var(--du-modal-pad-x);
1459
+ border-bottom: 1px solid var(--du-ui-border);
1460
+ }
1461
+
1462
+ .du-modal-body {
1463
+ padding: var(--du-modal-pad-y) var(--du-modal-pad-x);
1464
+ overflow-y: auto;
1465
+ }
1466
+
1467
+ .du-modal-footer {
1468
+ display: flex;
1469
+ gap: var(--du-gap);
1470
+ justify-content: flex-end;
1471
+ padding: var(--du-modal-pad-y) var(--du-modal-pad-x);
1472
+ border-top: 1px solid var(--du-ui-border);
1473
+ }
1474
+
1475
+ .du-modal-title {
1476
+ margin: 0;
1477
+ font-size: var(--du-font-size-lg);
1478
+ font-weight: var(--du-font-weight-strong);
1479
+ line-height: var(--du-line-height);
1480
+ color: var(--du-text);
1481
+ }
1482
+
1483
+ .du-modal-subtitle {
1484
+ margin: var(--du-space-sm) 0 0;
1485
+ font-size: var(--du-font-size-sm);
1486
+ color: var(--du-text-muted);
1487
+ }
1488
+
1489
+ /* Flat close glyph in a modal header. */
1490
+ .du-modal-close {
1491
+ display: inline-flex;
1492
+ align-items: center;
1493
+ justify-content: center;
1494
+ padding: var(--du-space-sm);
1495
+ color: var(--du-text);
1496
+ background: transparent;
1497
+ border: none;
1498
+ border-radius: var(--du-radius-sm);
1499
+ cursor: pointer;
1500
+ }
1501
+
1502
+ .du-modal-close:hover {
1503
+ background: var(--du-hover-overlay);
1504
+ }
1505
+
1506
+ .du-modal-close:focus-visible {
1507
+ outline: 2px solid var(--du-accent);
1508
+ outline-offset: var(--du-space-xs);
1509
+ }
1510
+
1511
+ /* Merge dialog — one bordered card per conflict. */
1512
+ .du-merge-conflict {
1513
+ margin-bottom: var(--du-space-lg);
1514
+ padding: var(--du-space-md);
1515
+ border: 1px solid var(--du-ui-border);
1516
+ border-radius: var(--du-radius-sm);
1517
+ }
1518
+
1519
+ .du-merge-conflict-title {
1520
+ margin-bottom: var(--du-space-sm);
1521
+ font-size: var(--du-font-size-sm);
1522
+ color: var(--du-text-muted);
1523
+ }
1524
+
1525
+ .du-merge-conflict-picks {
1526
+ display: flex;
1527
+ gap: var(--du-gap);
1528
+ }
1529
+
1530
+ .du-merge-conflict-pick {
1531
+ display: flex;
1532
+ align-items: center;
1533
+ gap: var(--du-space-sm);
1534
+ font-size: var(--du-font-size-sm);
1535
+ }
1536
+
1537
+ /* ------------------------------------------------------------------ */
1538
+ /* Toast — top-right stack; the kind accent is the left border, set */
1539
+ /* inline by <ToastItem>. */
1540
+ /* ------------------------------------------------------------------ */
1541
+ .du-toast {
1542
+ display: flex;
1543
+ align-items: flex-start;
1544
+ gap: var(--du-space-lg);
1545
+ min-width: var(--du-toast-min-w);
1546
+ max-width: var(--du-toast-max-w);
1547
+ padding: var(--du-space-md) var(--du-space-lg);
1548
+ font-family: var(--du-font-family);
1549
+ font-size: var(--du-font-size);
1550
+ line-height: var(--du-line-height);
1551
+ color: var(--du-text);
1552
+ background: var(--du-ui-bg-solid);
1553
+ border: 1px solid var(--du-ui-border);
1554
+ border-radius: var(--du-radius);
1555
+ box-shadow: var(--du-ui-shadow);
1556
+ pointer-events: auto;
1557
+ }
1558
+
1559
+ .du-toast-message {
1560
+ flex: 1;
1561
+ }
1562
+
1563
+ .du-toast-dismiss {
1564
+ padding: 0;
1565
+ font-size: var(--du-font-size-lg);
1566
+ line-height: 1;
1567
+ color: var(--du-text-muted);
1568
+ background: transparent;
1569
+ border: none;
1570
+ cursor: pointer;
1571
+ }
1572
+
1573
+ .du-toast-dismiss:hover {
1574
+ color: var(--du-text);
1575
+ }
1576
+
1577
+ /* ------------------------------------------------------------------ */
1578
+ /* Bottom sheet — mobile dialog docked to the bottom edge. */
1579
+ /* ------------------------------------------------------------------ */
1580
+ .du-sheet-grip {
1581
+ display: flex;
1582
+ justify-content: center;
1583
+ padding: var(--du-space-md) 0;
1584
+ cursor: grab;
1585
+ touch-action: none;
1586
+ }
1587
+
1588
+ .du-sheet-grip-bar {
1589
+ display: block;
1590
+ width: 36px;
1591
+ height: var(--du-space-sm);
1592
+ border-radius: var(--du-radius-round);
1593
+ background: var(--du-text);
1594
+ opacity: 0.4;
1595
+ }
1596
+
1597
+ .du-sheet-body {
1598
+ flex: 1;
1599
+ overflow-y: auto;
1600
+ padding: 0 var(--du-space-lg) var(--du-space-lg);
1601
+ }
1602
+
1603
+ /* ------------------------------------------------------------------ */
1604
+ /* Static chrome docks — where the fixed toolbars live. */
1605
+ /* ------------------------------------------------------------------ */
1606
+ /* Brand cell at the start of the top-left bar: a 40-px cell holding the
1607
+ logo (or any host node), as wide as its content. Not interactive. */
1608
+ .du-button-group > .du-brand,
1609
+ .du-brand {
1610
+ width: auto;
1611
+ min-width: var(--du-button-size);
1612
+ padding: 0 var(--du-space-md);
1613
+ cursor: default;
1614
+ }
1615
+
1616
+ .du-brand:hover {
1617
+ background: transparent;
1618
+ }
1619
+
1620
+ .du-brand-logo {
1621
+ display: inline-flex;
1622
+ align-items: center;
1623
+ height: var(--du-brand-h);
1624
+ }
1625
+
1626
+ .du-brand-logo > svg {
1627
+ display: block;
1628
+ height: var(--du-brand-h);
1629
+ width: auto;
1630
+ }
1631
+
1632
+ /* Theme-matched artwork: light by default, dark under the dark theme —
1633
+ mirrors the token scopes (system preference, then explicit data-theme).
1634
+ Selectors keep the `.du-brand-logo > …` form so they outrank the base
1635
+ `> svg` rule above. */
1636
+ .du-brand-logo > .du-brand-logo-dark {
1637
+ display: none;
1638
+ }
1639
+
1640
+ @media (prefers-color-scheme: dark) {
1641
+ .du-brand-logo > .du-brand-logo-light {
1642
+ display: none;
1643
+ }
1644
+ .du-brand-logo > .du-brand-logo-dark {
1645
+ display: block;
1646
+ }
1647
+ }
1648
+
1649
+ [data-theme="light"] .du-brand-logo > .du-brand-logo-light {
1650
+ display: block;
1651
+ }
1652
+ [data-theme="light"] .du-brand-logo > .du-brand-logo-dark {
1653
+ display: none;
1654
+ }
1655
+ [data-theme="dark"] .du-brand-logo > .du-brand-logo-light {
1656
+ display: none;
1657
+ }
1658
+ [data-theme="dark"] .du-brand-logo > .du-brand-logo-dark {
1659
+ display: block;
1660
+ }
1661
+
1662
+ /* Zoom value trigger (opens the zoom menu) — flat, wide enough for "100%". */
1663
+ .du-zoom-trigger {
1664
+ min-width: 56px;
1665
+ padding: 0 var(--du-space-md);
1666
+ font-variant-numeric: tabular-nums;
1667
+ }
1668
+
1669
+ .du-zoom-readout {
1670
+ display: inline-block;
1671
+ min-width: var(--du-button-size);
1672
+ text-align: center;
1673
+ font-variant-numeric: tabular-nums;
1674
+ }
1675
+
1676
+ /* Standalone bottom-right zoom cluster (hosts without the bottom bar). */
1677
+ .du-zoom-floating {
1678
+ position: absolute;
1679
+ right: var(--du-bar-inset);
1680
+ bottom: var(--du-bar-inset);
1681
+ z-index: var(--du-z-ui);
1682
+ }
1683
+
1684
+ /* Hairline between button clusters inside a toolbar row / column. */
1685
+ .du-toolbar-divider {
1686
+ flex: none;
1687
+ width: 1px;
1688
+ height: var(--du-icon-size);
1689
+ margin: 0 var(--du-space-sm);
1690
+ background: var(--du-ui-border);
1691
+ }
1692
+
1693
+ .du-toolbar-divider.is-vertical {
1694
+ width: 100%;
1695
+ height: 1px;
1696
+ margin: var(--du-space-sm) 0;
1697
+ }
1698
+
1699
+ /* Minimap — bottom-right, stacked above the bottom bar. */
1700
+ .du-minimap-dock {
1701
+ position: absolute;
1702
+ right: var(--du-bar-inset);
1703
+ bottom: var(--du-bar-clear);
1704
+ z-index: var(--du-z-ui);
1705
+ overflow: hidden;
1706
+ background: var(--du-ui-bg-solid);
1707
+ border: 1px solid var(--du-ui-border);
1708
+ border-radius: var(--du-radius);
1709
+ box-shadow: var(--du-ui-shadow);
1710
+ }
1711
+
1712
+ /* Vertical tool dock — vertically centred with a WHOLE-pixel offset:
1713
+ a plain `translateY(-50%)` (or flex centring) lands on half pixels when
1714
+ the free space is odd, and every glyph in the dock renders blurry. */
1715
+ .du-dock {
1716
+ position: absolute;
1717
+ top: round(50%, 1px);
1718
+ z-index: var(--du-z-ui);
1719
+ translate: 0 round(-50%, 1px);
1720
+ }
1721
+
1722
+ /* ------------------------------------------------------------------ */
1723
+ /* File-drop overlay — shown while an OS file drag hovers the canvas. */
1724
+ /* Pointer-events none: the drop lands on the canvas handlers beneath. */
1725
+ /* ------------------------------------------------------------------ */
1726
+ .du-drop-overlay {
1727
+ position: absolute;
1728
+ inset: 0;
1729
+ z-index: var(--du-z-drop-overlay);
1730
+ pointer-events: none;
1731
+ background: color-mix(in srgb, var(--du-accent) 6%, transparent);
1732
+ }
1733
+
1734
+ .du-drop-overlay-frame {
1735
+ position: absolute;
1736
+ inset: var(--du-bar-inset);
1737
+ display: flex;
1738
+ align-items: center;
1739
+ justify-content: center;
1740
+ border: 2px dashed var(--du-accent);
1741
+ border-radius: var(--du-radius-lg);
1742
+ }
1743
+
1744
+ /* One card: the drop glyph + DROP on top, the accepted kinds listed
1745
+ beneath a hairline — no nested chips. */
1746
+ .du-drop-overlay-card {
1747
+ display: flex;
1748
+ flex-direction: column;
1749
+ align-items: stretch;
1750
+ min-width: 320px;
1751
+ max-width: min(560px, 80%);
1752
+ background: var(--du-ui-bg-solid);
1753
+ border: 1px solid var(--du-ui-border);
1754
+ border-radius: var(--du-radius-lg);
1755
+ box-shadow: var(--du-ui-shadow);
1756
+ overflow: hidden;
1757
+ }
1758
+
1759
+ .du-drop-overlay-center {
1760
+ display: flex;
1761
+ flex-direction: column;
1762
+ align-items: center;
1763
+ gap: var(--du-space-md);
1764
+ padding: var(--du-space-2xl) calc(2 * var(--du-space-2xl));
1765
+ color: var(--du-accent);
1766
+ }
1767
+
1768
+ .du-drop-overlay-label {
1769
+ font-family: var(--du-font-family);
1770
+ font-size: var(--du-font-size-lg);
1771
+ font-weight: var(--du-font-weight-strong);
1772
+ letter-spacing: 0.2em;
1773
+ text-transform: uppercase;
1774
+ }
1775
+
1776
+ .du-drop-overlay-types {
1777
+ display: flex;
1778
+ flex-direction: column;
1779
+ margin: 0;
1780
+ padding: var(--du-space-md) var(--du-space-xl);
1781
+ border-top: 1px solid var(--du-ui-border);
1782
+ list-style: none;
1783
+ }
1784
+
1785
+ .du-drop-type {
1786
+ display: flex;
1787
+ align-items: center;
1788
+ gap: var(--du-gap);
1789
+ min-height: var(--du-control-size);
1790
+ font-family: var(--du-font-family);
1791
+ font-size: var(--du-font-size);
1792
+ color: var(--du-text);
1793
+ }
1794
+
1795
+ .du-drop-type-label {
1796
+ font-weight: var(--du-font-weight-strong);
1797
+ white-space: nowrap;
1798
+ }
1799
+
1800
+ .du-drop-type-formats {
1801
+ font-size: var(--du-font-size-sm);
1802
+ color: var(--du-text-muted);
1803
+ }
1804
+
1805
+ /* Tool-options panel (brush / eraser) — top-right, under the top bar. */
1806
+ .du-tool-options-dock {
1807
+ position: absolute;
1808
+ top: var(--du-bar-clear);
1809
+ right: var(--du-bar-inset);
1810
+ z-index: var(--du-z-ui);
1811
+ }
1812
+
1813
+ /* Switch — pill toggle used for on/off settings inside menus. */
1814
+ .du-switch {
1815
+ position: relative;
1816
+ flex: none;
1817
+ width: var(--du-switch-w);
1818
+ height: var(--du-switch-h);
1819
+ padding: 0;
1820
+ background: var(--du-ui-border);
1821
+ border: 0;
1822
+ border-radius: var(--du-radius-round);
1823
+ cursor: pointer;
1824
+ transition: background var(--du-motion-fast);
1825
+ }
1826
+
1827
+ .du-switch.is-on {
1828
+ background: var(--du-accent);
1829
+ }
1830
+
1831
+ .du-switch:disabled {
1832
+ cursor: not-allowed;
1833
+ opacity: 0.4;
1834
+ }
1835
+
1836
+ .du-switch-knob {
1837
+ position: absolute;
1838
+ top: var(--du-space-xs);
1839
+ left: var(--du-space-xs);
1840
+ width: calc(var(--du-switch-h) - 2 * var(--du-space-xs));
1841
+ height: calc(var(--du-switch-h) - 2 * var(--du-space-xs));
1842
+ background: var(--du-text-on-accent);
1843
+ border-radius: 50%;
1844
+ box-shadow: var(--du-ui-shadow);
1845
+ transition: transform var(--du-motion-fast);
1846
+ }
1847
+
1848
+ .du-switch.is-on .du-switch-knob {
1849
+ transform: translateX(calc(var(--du-switch-w) - var(--du-switch-h)));
1850
+ }
1851
+
1852
+ .du-switch:focus-visible {
1853
+ outline: 2px solid var(--du-accent);
1854
+ outline-offset: 2px;
1855
+ }
1856
+
1857
+ /* Slider — themed native <input type=range> + value badge. */
1858
+ /* ------------------------------------------------------------------ */
1859
+ .du-slider {
1860
+ display: flex;
1861
+ align-items: center;
1862
+ gap: var(--du-space-md);
851
1863
  width: 100%;
852
1864
  }
853
1865
 
@@ -856,22 +1868,22 @@
856
1868
  -webkit-appearance: none;
857
1869
  appearance: none;
858
1870
  background: transparent;
859
- height: 18px;
1871
+ height: var(--du-switch-h);
860
1872
  margin: 0;
861
1873
  padding: 0;
862
1874
  cursor: pointer;
863
1875
  }
864
1876
 
865
1877
  .du-slider-track::-webkit-slider-runnable-track {
866
- height: 4px;
1878
+ height: var(--du-space-sm);
867
1879
  background: var(--du-selected-bg);
868
- border-radius: 2px;
1880
+ border-radius: var(--du-space-xs);
869
1881
  }
870
1882
 
871
1883
  .du-slider-track::-moz-range-track {
872
- height: 4px;
1884
+ height: var(--du-space-sm);
873
1885
  background: var(--du-selected-bg);
874
- border-radius: 2px;
1886
+ border-radius: var(--du-space-xs);
875
1887
  border: none;
876
1888
  }
877
1889
 
@@ -885,7 +1897,7 @@
885
1897
  border: 2px solid var(--du-ui-bg-solid);
886
1898
  margin-top: -5px;
887
1899
  cursor: grab;
888
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
1900
+ box-shadow: var(--du-ui-shadow);
889
1901
  }
890
1902
 
891
1903
  .du-slider-track::-moz-range-thumb {
@@ -895,7 +1907,7 @@
895
1907
  border-radius: 50%;
896
1908
  border: 2px solid var(--du-ui-bg-solid);
897
1909
  cursor: grab;
898
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
1910
+ box-shadow: var(--du-ui-shadow);
899
1911
  }
900
1912
 
901
1913
  .du-slider-track:focus {
@@ -908,10 +1920,10 @@
908
1920
  }
909
1921
 
910
1922
  .du-slider-value {
911
- min-width: 36px;
1923
+ min-width: 36px; /* "100%" */
912
1924
  text-align: right;
913
1925
  font-variant-numeric: tabular-nums;
914
- font-size: 11px;
1926
+ font-size: var(--du-font-size-sm);
915
1927
  color: var(--du-text-muted);
916
1928
  }
917
1929
 
@@ -920,15 +1932,15 @@
920
1932
  /* ------------------------------------------------------------------ */
921
1933
  .du-number-input {
922
1934
  width: 64px;
923
- height: 24px;
1935
+ height: var(--du-control-h);
924
1936
  box-sizing: border-box;
925
1937
  background: var(--du-ui-bg-solid);
926
1938
  color: var(--du-text);
927
1939
  border: 1px solid var(--du-ui-border);
928
1940
  border-radius: var(--du-radius-sm);
929
- padding: 0 6px;
1941
+ padding: 0 var(--du-space-sm);
930
1942
  font: inherit;
931
- font-size: 11px;
1943
+ font-size: var(--du-font-size-sm);
932
1944
  font-variant-numeric: tabular-nums;
933
1945
  outline: none;
934
1946
  }
@@ -940,21 +1952,21 @@
940
1952
  /* Search input row — sits between the header and the body. */
941
1953
  .du-side-panel-search {
942
1954
  position: relative;
943
- padding: var(--du-pad-sm) var(--du-pad);
944
- border-bottom: 1px solid var(--du-ui-border);
1955
+ padding: var(--du-pad-sm) var(--du-pad) var(--du-pad);
945
1956
  }
946
1957
 
947
1958
  .du-side-panel-search input[type="search"] {
948
1959
  width: 100%;
949
- height: 28px;
1960
+ height: var(--du-input-h);
950
1961
  box-sizing: border-box;
951
1962
  background: var(--du-ui-bg-solid);
952
1963
  color: var(--du-text);
953
1964
  border: 1px solid var(--du-ui-border);
954
1965
  border-radius: var(--du-radius-sm);
955
- padding: 0 8px 0 26px;
1966
+ padding: 0 var(--du-space-md) 0
1967
+ calc(var(--du-space-md) + var(--du-input-icon-size) + var(--du-space-sm));
956
1968
  font: inherit;
957
- font-size: 12px;
1969
+ font-size: var(--du-font-size-sm);
958
1970
  outline: none;
959
1971
  }
960
1972
 
@@ -968,7 +1980,7 @@
968
1980
 
969
1981
  .du-side-panel-search-icon {
970
1982
  position: absolute;
971
- left: calc(var(--du-pad) + 8px);
1983
+ left: calc(var(--du-pad) + var(--du-space-md));
972
1984
  top: 50%;
973
1985
  transform: translateY(-50%);
974
1986
  color: var(--du-text-muted);
@@ -982,20 +1994,21 @@
982
1994
  display: inline-flex;
983
1995
  align-items: center;
984
1996
  gap: var(--du-gap-sm);
985
- padding: 0 12px;
1997
+ padding: 0 var(--du-space-lg);
986
1998
  height: var(--du-button-size);
987
1999
  background: var(--du-ui-bg);
988
2000
  color: var(--du-text);
989
2001
  border: 1px solid var(--du-ui-border);
990
- border-radius: 999px;
2002
+ border-radius: var(--du-radius-round);
991
2003
  box-shadow: var(--du-ui-shadow);
992
2004
  cursor: pointer;
993
- font-size: 13px;
2005
+ font-family: var(--du-font-family);
2006
+ font-size: var(--du-font-size);
994
2007
  line-height: 1;
995
2008
  white-space: nowrap;
996
2009
  transition:
997
- background 0.15s ease,
998
- transform 0.05s ease;
2010
+ background var(--du-motion-fast),
2011
+ transform var(--du-motion-press);
999
2012
  }
1000
2013
 
1001
2014
  .du-pill-button:hover {
@@ -1011,16 +2024,16 @@
1011
2024
  /* Pointer-events-none so it never blocks hover on neighbour buttons. */
1012
2025
  /* ------------------------------------------------------------------ */
1013
2026
  .du-tooltip {
1014
- background: var(--du-text);
1015
- color: var(--du-ui-bg-solid);
1016
- padding: 4px 8px;
2027
+ background: var(--du-tooltip-bg);
2028
+ color: var(--du-tooltip-fg);
2029
+ padding: var(--du-space-sm) var(--du-space-md);
1017
2030
  border-radius: var(--du-radius-sm);
1018
- font-size: 12px;
2031
+ font-size: var(--du-font-size-sm);
1019
2032
  line-height: 1.4;
1020
2033
  white-space: nowrap;
1021
2034
  box-shadow: var(--du-ui-shadow);
1022
- font-family: inherit;
1023
- max-width: 260px;
2035
+ font-family: var(--du-font-family);
2036
+ max-width: var(--du-tooltip-max-w);
1024
2037
  }
1025
2038
 
1026
2039
  /* ------------------------------------------------------------------ */
@@ -1031,22 +2044,21 @@
1031
2044
  /* ------------------------------------------------------------------ */
1032
2045
  .du-help-islands {
1033
2046
  display: grid;
1034
- gap: 24px;
2047
+ gap: var(--du-space-2xl);
1035
2048
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
1036
2049
  }
1037
2050
 
1038
2051
  .du-help-island {
1039
2052
  display: flex;
1040
2053
  flex-direction: column;
1041
- gap: 8px;
2054
+ gap: var(--du-space-md);
1042
2055
  }
1043
2056
 
1044
2057
  .du-help-island-title {
1045
2058
  margin: 0;
1046
- font-size: 13px;
1047
- font-weight: 600;
2059
+ font-size: var(--du-font-size);
2060
+ font-weight: var(--du-font-weight-strong);
1048
2061
  color: var(--du-text);
1049
- letter-spacing: 0.2px;
1050
2062
  }
1051
2063
 
1052
2064
  .du-help-island-rows {
@@ -1059,9 +2071,10 @@
1059
2071
  display: flex;
1060
2072
  align-items: center;
1061
2073
  justify-content: space-between;
1062
- gap: 12px;
1063
- padding: 8px 12px;
1064
- font-size: 13px;
2074
+ gap: var(--du-space-lg);
2075
+ padding: var(--du-space-md) var(--du-space-lg);
2076
+ font-size: var(--du-font-size);
2077
+ line-height: var(--du-line-height);
1065
2078
  color: var(--du-text);
1066
2079
  border-bottom: 1px solid var(--du-ui-border);
1067
2080
  }
@@ -1078,38 +2091,38 @@
1078
2091
  .du-help-keys {
1079
2092
  display: inline-flex;
1080
2093
  align-items: center;
1081
- gap: 4px;
2094
+ gap: var(--du-space-sm);
1082
2095
  flex-shrink: 0;
1083
2096
  }
1084
2097
 
1085
2098
  .du-help-keys-separator {
1086
- font-size: 11px;
2099
+ font-size: var(--du-font-size-sm);
1087
2100
  color: var(--du-text-muted);
1088
- padding: 0 2px;
2101
+ padding: 0 var(--du-space-xs);
1089
2102
  }
1090
2103
 
1091
2104
  .du-help-key {
1092
2105
  display: inline-flex;
1093
2106
  align-items: center;
1094
2107
  justify-content: center;
1095
- min-width: 22px;
1096
- height: 22px;
1097
- padding: 0 6px;
2108
+ min-width: var(--du-key-h);
2109
+ height: var(--du-key-h);
2110
+ padding: 0 var(--du-space-sm);
1098
2111
  background: var(--du-selected-bg);
1099
2112
  color: var(--du-selected-fg);
1100
2113
  border-radius: var(--du-radius-sm);
1101
- font-family: inherit;
1102
- font-size: 11px;
1103
- font-weight: 600;
2114
+ font-family: var(--du-font-family);
2115
+ font-size: var(--du-font-size-sm);
2116
+ font-weight: var(--du-font-weight-strong);
1104
2117
  line-height: 1;
1105
2118
  white-space: nowrap;
1106
2119
  }
1107
2120
 
1108
2121
  .du-help-platform-badge {
1109
- font-size: 11px;
2122
+ font-size: var(--du-font-size-sm);
1110
2123
  color: var(--du-text-muted);
1111
2124
  text-transform: uppercase;
1112
- letter-spacing: 0.5px;
2125
+ letter-spacing: var(--du-caps-tracking);
1113
2126
  }
1114
2127
 
1115
2128
  /* ------------------------------------------------------------------ */
@@ -1134,9 +2147,9 @@
1134
2147
  border-radius: var(--du-radius);
1135
2148
  box-shadow: var(--du-ui-shadow);
1136
2149
  padding: var(--du-pad-sm);
1137
- font-size: 12px;
2150
+ font-size: var(--du-font-size-sm);
1138
2151
  color: var(--du-text);
1139
- max-width: calc(100vw - 32px);
2152
+ max-width: calc(100vw - 2 * var(--du-bar-inset));
1140
2153
  /* Allow horizontal scroll within the pill when too many controls
1141
2154
  are visible; `shift` middleware clamps the outer position but
1142
2155
  a panel wider than viewport still needs internal overflow. */
@@ -1154,13 +2167,11 @@
1154
2167
  right: 0;
1155
2168
  /* Sit ABOVE the bottom bar (zoom / help) + the home-indicator safe area
1156
2169
  so the two don't overlap. Mirrors the side-panel top offset. */
1157
- bottom: calc(
1158
- var(--du-bar-inset) + var(--du-button-size) + var(--du-gap) + env(safe-area-inset-bottom, 0px)
1159
- );
1160
- z-index: 1500;
2170
+ bottom: calc(var(--du-bar-clear) + env(safe-area-inset-bottom, 0px));
2171
+ z-index: var(--du-z-floating);
1161
2172
  display: flex;
1162
2173
  justify-content: center;
1163
- padding: 0 8px;
2174
+ padding: 0 var(--du-space-md);
1164
2175
  pointer-events: none;
1165
2176
  }
1166
2177
 
@@ -1171,10 +2182,10 @@
1171
2182
  flex-direction: column;
1172
2183
  align-items: stretch;
1173
2184
  width: 100%;
1174
- max-width: 560px;
2185
+ max-width: var(--du-modal-max-w);
1175
2186
  overflow: visible;
1176
- gap: 6px;
1177
- padding: 8px;
2187
+ gap: var(--du-space-sm);
2188
+ padding: var(--du-space-md);
1178
2189
  }
1179
2190
  .du-sel-mobile-row {
1180
2191
  display: flex;
@@ -1205,19 +2216,19 @@
1205
2216
  align-items: center;
1206
2217
  gap: var(--du-gap-sm);
1207
2218
  border-top: 1px solid var(--du-ui-border);
1208
- padding-top: 8px;
2219
+ padding-top: var(--du-space-md);
1209
2220
  }
1210
2221
  /* ≥44px touch targets on the mobile panel (Apple HIG). Standalone icon
1211
2222
  buttons + color triggers grow; grouped segmented buttons stay a touch
1212
2223
  smaller so wide controls (font-size S/M/L/XL) still fit one row. */
1213
2224
  .du-sel-panel-mobile .du-sel-icon-button,
1214
2225
  .du-sel-panel-mobile .du-sel-color-trigger {
1215
- width: 44px;
1216
- height: 44px;
2226
+ width: var(--du-touch-size);
2227
+ height: var(--du-touch-size);
1217
2228
  }
1218
2229
  .du-sel-panel-mobile .du-button-group > .du-icon-button {
1219
- width: 38px;
1220
- height: 38px;
2230
+ width: var(--du-control-size);
2231
+ height: var(--du-control-size);
1221
2232
  }
1222
2233
 
1223
2234
  /* Flat segmented controls inside the floating panel — no group
@@ -1228,7 +2239,7 @@
1228
2239
  border: none;
1229
2240
  box-shadow: none;
1230
2241
  padding: 0;
1231
- gap: 2px;
2242
+ gap: var(--du-space-xs);
1232
2243
  }
1233
2244
 
1234
2245
  .du-sel-panel .du-button-group > .du-icon-button {
@@ -1262,9 +2273,9 @@
1262
2273
 
1263
2274
  .du-sel-color-swatch {
1264
2275
  display: inline-block;
1265
- width: 18px;
1266
- height: 18px;
1267
- border-radius: 4px;
2276
+ width: var(--du-divider-h);
2277
+ height: var(--du-divider-h);
2278
+ border-radius: var(--du-radius-sm);
1268
2279
  border: 1px solid var(--du-ui-border);
1269
2280
  box-sizing: border-box;
1270
2281
  }
@@ -1310,13 +2321,13 @@
1310
2321
  justify-content: center;
1311
2322
  height: var(--du-button-size-sm);
1312
2323
  min-width: var(--du-button-size-sm);
1313
- padding: 0 8px;
2324
+ padding: 0 var(--du-space-md);
1314
2325
  background: transparent;
1315
2326
  border: none;
1316
2327
  border-radius: var(--du-radius-sm);
1317
2328
  cursor: pointer;
1318
2329
  color: var(--du-text);
1319
- font-size: 12px;
2330
+ font-size: var(--du-font-size-sm);
1320
2331
  font-variant-numeric: tabular-nums;
1321
2332
  }
1322
2333
 
@@ -1330,12 +2341,27 @@
1330
2341
  }
1331
2342
 
1332
2343
  /* Visual divider between inline groups (z-order, actions). */
1333
- .du-sel-divider {
2344
+ /* Control clusters of the selection panel. The separator is drawn by a
2345
+ group that has a NON-EMPTY group before it — so clusters whose controls
2346
+ all rendered nothing for this selection never leave a stray or doubled
2347
+ divider, and no divider ever sits at either end. */
2348
+ .du-sel-group {
2349
+ display: inline-flex;
2350
+ gap: var(--du-gap-sm);
2351
+ align-items: center;
2352
+ }
2353
+
2354
+ .du-sel-group:empty {
2355
+ display: none;
2356
+ }
2357
+
2358
+ .du-sel-group:not(:empty) ~ .du-sel-group:not(:empty)::before {
1334
2359
  display: inline-block;
1335
2360
  width: 1px;
1336
- height: 18px;
2361
+ height: var(--du-divider-h);
2362
+ margin: 0 var(--du-space-xs);
2363
+ content: "";
1337
2364
  background: var(--du-ui-border);
1338
- margin: 0 2px;
1339
2365
  }
1340
2366
 
1341
2367
  /* ------------------------------------------------------------------ */
@@ -1347,26 +2373,26 @@
1347
2373
  border: 1px solid var(--du-ui-border);
1348
2374
  border-radius: var(--du-radius);
1349
2375
  box-shadow: var(--du-ui-shadow);
1350
- padding: var(--du-pad);
1351
- font-size: 12px;
2376
+ padding: var(--du-popover-pad);
2377
+ font-size: var(--du-font-size-sm);
1352
2378
  color: var(--du-text);
1353
- min-width: 120px;
1354
- max-width: 320px;
2379
+ min-width: var(--du-popover-min-w);
2380
+ max-width: var(--du-popover-max-w);
1355
2381
  }
1356
2382
 
1357
2383
  .du-sel-popover-section {
1358
2384
  display: flex;
1359
2385
  flex-direction: column;
1360
- gap: 8px;
2386
+ gap: var(--du-space-md);
1361
2387
  min-width: 0;
1362
2388
  }
1363
2389
 
1364
2390
  .du-sel-popover-label {
1365
2391
  margin: 0;
1366
- font-size: 10px;
1367
- font-weight: 600;
2392
+ font-size: var(--du-font-size-xs);
2393
+ font-weight: var(--du-font-weight-strong);
1368
2394
  text-transform: uppercase;
1369
- letter-spacing: 0.5px;
2395
+ letter-spacing: var(--du-caps-tracking);
1370
2396
  color: var(--du-text-muted);
1371
2397
  }
1372
2398
 
@@ -1375,12 +2401,14 @@
1375
2401
  current value. */
1376
2402
  .du-sel-menu-row {
1377
2403
  all: unset;
1378
- display: block;
2404
+ display: flex;
2405
+ align-items: center;
1379
2406
  width: 100%;
2407
+ min-height: var(--du-menu-row-h);
1380
2408
  box-sizing: border-box;
1381
- padding: 6px 10px;
1382
- border-radius: 4px;
1383
- font-size: 13px;
2409
+ padding: 0 var(--du-menu-row-pad-x);
2410
+ border-radius: var(--du-menu-row-radius);
2411
+ font-size: var(--du-menu-font);
1384
2412
  color: var(--du-text);
1385
2413
  cursor: pointer;
1386
2414
  }
@@ -1398,12 +2426,12 @@
1398
2426
  width: 220px;
1399
2427
  max-width: 60vw;
1400
2428
  box-sizing: border-box;
1401
- padding: 6px 8px;
1402
- font-size: 13px;
2429
+ padding: var(--du-space-sm) var(--du-space-md);
2430
+ font-size: var(--du-font-size);
1403
2431
  color: var(--du-text);
1404
2432
  background: var(--du-ui-bg);
1405
2433
  border: 1px solid var(--du-ui-border);
1406
- border-radius: 4px;
2434
+ border-radius: var(--du-radius-sm);
1407
2435
  outline: none;
1408
2436
  }
1409
2437
 
@@ -1414,29 +2442,228 @@
1414
2442
 
1415
2443
  /* Hover link popup (chip above a linked element). */
1416
2444
  .du-link-popup {
1417
- z-index: 1400;
1418
- margin-top: -6px;
2445
+ z-index: var(--du-z-link-chrome);
2446
+ margin-top: calc(-1 * var(--du-space-sm));
2447
+ pointer-events: auto;
2448
+ }
2449
+
2450
+ /* Two-row alignment / list dropdowns: stacked segment rows. */
2451
+ .du-sel-align-rows {
2452
+ display: flex;
2453
+ flex-direction: column;
2454
+ gap: var(--du-space-sm);
2455
+ padding: var(--du-space-sm);
2456
+ }
2457
+
2458
+ .du-sel-align-rows-row {
2459
+ display: flex;
2460
+ gap: var(--du-space-sm);
2461
+ justify-content: center;
2462
+ }
2463
+
2464
+ /* Image file-name input in the toolbar row. */
2465
+ .du-sel-name-input {
2466
+ width: 140px;
2467
+ padding: var(--du-space-xs) var(--du-space-sm);
2468
+ font-family: var(--du-font-family);
2469
+ font-size: var(--du-font-size-sm);
2470
+ color: var(--du-text);
2471
+ background: transparent;
2472
+ border: 1px solid transparent;
2473
+ border-radius: var(--du-radius-sm);
2474
+ }
2475
+
2476
+ .du-sel-name-input:hover,
2477
+ .du-sel-name-input:focus {
2478
+ border-color: var(--menu-border);
2479
+ outline: none;
2480
+ }
2481
+
2482
+ /* Sticky Auto font-size toggle inside the size popover. */
2483
+ .du-sel-auto-size {
2484
+ width: auto;
2485
+ padding: var(--du-space-xs) var(--du-space-md);
2486
+ font-family: var(--du-font-family);
2487
+ font-size: var(--du-font-size-sm);
2488
+ font-weight: var(--du-font-weight-strong);
2489
+ }
2490
+
2491
+ /* Sticky size letters (S / M / L segments). */
2492
+ .du-sel-size-letter {
2493
+ font-family: var(--du-font-family);
2494
+ font-size: var(--du-font-size-sm);
2495
+ font-weight: var(--du-font-weight-strong);
2496
+ }
2497
+
2498
+ /* Emoji picker grid inside its popover. */
2499
+ .du-sel-emoji-grid {
2500
+ display: grid;
2501
+ grid-template-columns: repeat(5, var(--du-input-h));
2502
+ gap: var(--du-space-xs);
2503
+ padding: var(--du-space-sm);
2504
+ }
2505
+
2506
+ .du-sel-emoji-item {
2507
+ width: var(--du-input-h);
2508
+ height: var(--du-input-h);
2509
+ padding: 0;
2510
+ font-size: var(--du-font-size-lg);
2511
+ line-height: 1;
2512
+ background: transparent;
2513
+ border: 1px solid transparent;
2514
+ border-radius: var(--du-radius-sm);
2515
+ cursor: pointer;
2516
+ }
2517
+
2518
+ .du-sel-emoji-item:hover {
2519
+ border-color: var(--menu-border);
2520
+ }
2521
+
2522
+ /* Sticky tag pills in the tag popover. */
2523
+ .du-sel-tag-list {
2524
+ display: flex;
2525
+ flex-wrap: wrap;
2526
+ gap: var(--du-space-sm);
2527
+ margin-bottom: var(--du-space-sm);
2528
+ }
2529
+
2530
+ .du-sel-tag-pill {
2531
+ display: inline-flex;
2532
+ align-items: center;
2533
+ gap: var(--du-space-sm);
2534
+ padding: var(--du-space-xs) var(--du-space-md);
2535
+ font-family: var(--du-font-family);
2536
+ font-size: var(--du-font-size-sm);
2537
+ background: var(--menu-bg);
2538
+ border: 1px solid var(--menu-border);
2539
+ border-radius: var(--du-radius-round);
2540
+ }
2541
+
2542
+ .du-sel-tag-remove {
2543
+ padding: 0 var(--du-space-xs);
2544
+ font-size: var(--du-font-size-sm);
2545
+ line-height: 1;
2546
+ color: inherit;
2547
+ background: transparent;
2548
+ border: 0;
2549
+ cursor: pointer;
2550
+ }
2551
+
2552
+ /* Sticky reactions: pills are painted by the canvas renderer; the DOM
2553
+ only carries transparent click zones on the same rects plus the "+"
2554
+ button / picker anchor. */
2555
+ .du-sticky-reactions {
2556
+ position: fixed;
2557
+ z-index: var(--du-z-link-chrome);
2558
+ display: flex;
2559
+ align-items: center;
2560
+ pointer-events: auto;
2561
+ }
2562
+
2563
+ .du-sticky-reaction-hit {
2564
+ position: fixed;
2565
+ z-index: var(--du-z-link-chrome);
2566
+ padding: 0;
2567
+ background: transparent;
2568
+ border: 0;
2569
+ border-radius: var(--du-radius-round);
2570
+ cursor: pointer;
2571
+ }
2572
+
2573
+ .du-sticky-reaction-picker {
2574
+ position: absolute;
2575
+ bottom: var(--du-key-h);
2576
+ left: 0;
2577
+ display: grid;
2578
+ grid-template-columns: repeat(5, var(--du-input-h));
2579
+ gap: var(--du-space-xs);
2580
+ padding: var(--du-space-sm);
2581
+ background: var(--menu-bg);
2582
+ border: 1px solid var(--menu-border);
2583
+ border-radius: var(--du-radius);
2584
+ box-shadow: var(--du-ui-shadow);
2585
+ }
2586
+
2587
+ /* Border-group trigger: an outlined ring showing the stroke colour. */
2588
+ .du-sel-swatch-ring {
2589
+ background: transparent;
2590
+ border: 3px solid var(--menu-border); /* ring thickness = stroke preview */
2591
+ }
2592
+
2593
+ /* Frame size preset list inside its popover. */
2594
+ .du-sel-preset-list {
2595
+ display: grid;
2596
+ grid-template-columns: 1fr 1fr;
2597
+ gap: var(--du-space-sm);
2598
+ }
2599
+
2600
+ .du-sel-preset-item {
2601
+ padding: var(--du-space-sm) var(--du-space-md);
2602
+ font-family: var(--du-font-family);
2603
+ font-size: var(--du-font-size-sm);
2604
+ color: var(--du-text);
2605
+ background: transparent;
2606
+ border: 1px solid var(--menu-border);
2607
+ border-radius: var(--du-radius-sm);
2608
+ cursor: pointer;
2609
+ }
2610
+
2611
+ .du-sel-preset-item:hover {
2612
+ border-color: var(--du-accent);
2613
+ }
2614
+
2615
+ /* Alt-text textarea inside its popover. */
2616
+ .du-sel-alt-input {
2617
+ width: 200px;
2618
+ padding: var(--du-space-sm);
2619
+ font-family: var(--du-font-family);
2620
+ font-size: var(--du-font-size-sm);
2621
+ color: var(--du-text);
2622
+ background: transparent;
2623
+ border: 1px solid var(--menu-border);
2624
+ border-radius: var(--du-radius-sm);
2625
+ resize: vertical;
2626
+ }
2627
+
2628
+ /* Persistent link badge at an element's top-right corner. Slightly offset
2629
+ outward so it reads as attached to the shape without covering content. */
2630
+ .du-link-badge {
2631
+ z-index: var(--du-z-link-chrome);
2632
+ display: inline-flex;
2633
+ align-items: center;
2634
+ justify-content: center;
2635
+ width: var(--du-divider-h);
2636
+ height: var(--du-divider-h);
2637
+ padding: 0;
2638
+ color: var(--du-accent);
2639
+ background: var(--menu-bg);
2640
+ border: 1px solid var(--menu-border);
2641
+ border-radius: 50%;
2642
+ box-shadow: var(--du-ui-shadow);
2643
+ transform: translate(-40%, -60%);
2644
+ cursor: pointer;
1419
2645
  pointer-events: auto;
1420
2646
  }
1421
2647
 
2648
+ .du-link-badge:hover {
2649
+ color: var(--du-accent-strong, var(--du-accent));
2650
+ border-color: var(--du-accent);
2651
+ }
2652
+
1422
2653
  .du-link-popup-url {
1423
2654
  display: inline-flex;
1424
2655
  align-items: center;
1425
- gap: 6px;
2656
+ gap: var(--du-space-sm);
1426
2657
  max-width: 280px;
1427
- padding: 4px 8px;
1428
- font:
1429
- 12px system-ui,
1430
- -apple-system,
1431
- Segoe UI,
1432
- Roboto,
1433
- sans-serif;
2658
+ padding: var(--du-space-sm) var(--du-space-md);
2659
+ font-family: var(--du-font-family);
2660
+ font-size: var(--du-font-size-sm);
1434
2661
  color: var(--du-accent);
1435
2662
  text-decoration: none;
1436
2663
  background: var(--menu-bg);
1437
2664
  border: 1px solid var(--menu-border);
1438
- border-radius: 6px;
1439
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
2665
+ border-radius: var(--du-radius);
2666
+ box-shadow: var(--du-ui-shadow);
1440
2667
  cursor: pointer;
1441
2668
  }
1442
2669
 
@@ -1455,18 +2682,18 @@
1455
2682
  .du-arrowhead-grid {
1456
2683
  display: grid;
1457
2684
  grid-template-columns: repeat(4, 1fr);
1458
- gap: 2px;
1459
- margin-top: 4px;
2685
+ gap: var(--du-space-xs);
2686
+ margin-top: var(--du-space-sm);
1460
2687
  }
1461
2688
  .du-arrowhead-option {
1462
2689
  display: inline-flex;
1463
2690
  align-items: center;
1464
2691
  justify-content: center;
1465
- min-width: 30px;
1466
- height: 26px;
1467
- padding: 2px;
2692
+ min-width: var(--du-swatch-size);
2693
+ height: var(--du-swatch-size);
2694
+ padding: var(--du-space-xs);
1468
2695
  border: 1px solid transparent;
1469
- border-radius: 6px;
2696
+ border-radius: var(--du-radius-sm);
1470
2697
  background: transparent;
1471
2698
  cursor: pointer;
1472
2699
  color: var(--du-text);
@@ -1478,24 +2705,24 @@
1478
2705
  border-color: var(--du-accent);
1479
2706
  }
1480
2707
  .du-arrowhead-none {
1481
- font-size: 13px;
2708
+ font-size: var(--du-font-size);
1482
2709
  opacity: 0.6;
1483
2710
  }
1484
2711
  .du-arrowhead-erd-label {
1485
- font-size: 9px;
2712
+ font-size: var(--du-font-size-xs);
1486
2713
  line-height: 1.05;
1487
2714
  text-align: center;
1488
2715
  }
1489
2716
  .du-arrowhead-erd-toggle {
1490
- margin-top: 6px;
2717
+ margin-top: var(--du-space-sm);
1491
2718
  width: 100%;
1492
2719
  text-align: left;
1493
2720
  border: none;
1494
2721
  background: transparent;
1495
2722
  cursor: pointer;
1496
- font-size: 11px;
2723
+ font-size: var(--du-font-size-sm);
1497
2724
  color: var(--du-text-muted);
1498
- padding: 2px 0;
2725
+ padding: var(--du-space-xs) 0;
1499
2726
  }
1500
2727
  .du-arrowhead-erd-toggle:hover {
1501
2728
  color: var(--du-text);
@@ -1505,17 +2732,16 @@
1505
2732
  .du-link-caption-input {
1506
2733
  min-width: 60px;
1507
2734
  max-width: 220px;
1508
- padding: 2px 6px;
1509
- font:
1510
- 12px system-ui,
1511
- sans-serif;
2735
+ padding: var(--du-space-xs) var(--du-space-sm);
2736
+ font-family: var(--du-font-family);
2737
+ font-size: var(--du-font-size-sm);
1512
2738
  line-height: 1.25;
1513
2739
  text-align: center;
1514
2740
  color: var(--du-text);
1515
2741
  background: var(--du-ui-bg-solid);
1516
2742
  border: 1px solid var(--du-accent);
1517
- border-radius: 4px;
1518
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
2743
+ border-radius: var(--du-radius-sm);
2744
+ box-shadow: var(--du-ui-shadow);
1519
2745
  outline: none;
1520
2746
  resize: none;
1521
2747
  overflow: hidden;
@@ -1524,22 +2750,22 @@
1524
2750
  /* Mini shape-picker shown after a link is dropped on empty canvas. */
1525
2751
  .du-link-drop-menu {
1526
2752
  display: flex;
1527
- gap: 2px;
1528
- padding: 4px;
2753
+ gap: var(--du-space-xs);
2754
+ padding: var(--du-space-sm);
1529
2755
  background: var(--du-ui-bg-solid);
1530
2756
  border: 1px solid var(--du-ui-border);
1531
- border-radius: 8px;
1532
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
2757
+ border-radius: var(--du-radius);
2758
+ box-shadow: var(--du-ui-shadow);
1533
2759
  }
1534
2760
  .du-link-drop-item {
1535
2761
  display: inline-flex;
1536
2762
  align-items: center;
1537
2763
  justify-content: center;
1538
- width: 30px;
1539
- height: 30px;
1540
- padding: 4px;
2764
+ width: var(--du-button-size-sm);
2765
+ height: var(--du-button-size-sm);
2766
+ padding: var(--du-space-sm);
1541
2767
  border: none;
1542
- border-radius: 6px;
2768
+ border-radius: var(--du-radius-sm);
1543
2769
  background: transparent;
1544
2770
  cursor: pointer;
1545
2771
  color: var(--du-text);
@@ -1556,3 +2782,115 @@
1556
2782
  outline: 2px solid var(--du-accent);
1557
2783
  outline-offset: -2px;
1558
2784
  }
2785
+
2786
+ /* Mask picker tiles inside the image-mask popover. */
2787
+ .du-sel-mask-tiles {
2788
+ display: flex;
2789
+ gap: var(--du-space-sm);
2790
+ margin-bottom: var(--du-space-sm);
2791
+ }
2792
+
2793
+ /* Aspect-preset rows in the mask popover: icon + name, crop ratio
2794
+ right-aligned. */
2795
+ /* Arrange popover: one row of align / distribute action buttons. */
2796
+ .du-sel-arrange-row {
2797
+ display: flex;
2798
+ gap: var(--du-space-xs);
2799
+ }
2800
+
2801
+ .du-sel-mask-list {
2802
+ display: flex;
2803
+ flex-direction: column;
2804
+ margin-bottom: var(--du-space-sm);
2805
+ }
2806
+
2807
+ .du-sel-mask-row {
2808
+ display: flex;
2809
+ gap: var(--du-menu-gap);
2810
+ align-items: center;
2811
+ width: 100%;
2812
+ min-height: var(--du-menu-row-h);
2813
+ padding: 0 var(--du-menu-row-pad-x);
2814
+ font-size: var(--du-menu-font);
2815
+ color: var(--du-text);
2816
+ text-align: left;
2817
+ background: transparent;
2818
+ border: 0;
2819
+ border-radius: var(--du-menu-row-radius);
2820
+ cursor: pointer;
2821
+ }
2822
+
2823
+ .du-sel-mask-row:hover {
2824
+ background: var(--du-hover-overlay);
2825
+ }
2826
+
2827
+ .du-sel-mask-row.is-active {
2828
+ background: var(--du-selected-bg);
2829
+ }
2830
+
2831
+ .du-sel-mask-ratio {
2832
+ margin-left: auto;
2833
+ font-size: var(--du-menu-shortcut-font);
2834
+ color: var(--du-text-muted);
2835
+ }
2836
+
2837
+ /* "Shapes and lines" flyout beside the vertical toolbar. */
2838
+ .du-shapes-flyout {
2839
+ position: absolute;
2840
+ top: 0;
2841
+ /* The wrap sits inside the dock: clear its inset + border, then the gap. */
2842
+ left: calc(100% + var(--du-pad-sm) + 1px + var(--du-flyout-gap));
2843
+ z-index: var(--du-z-ui);
2844
+ display: flex;
2845
+ flex-direction: column;
2846
+ box-sizing: border-box;
2847
+ min-width: var(--du-menu-min-w);
2848
+ padding: var(--du-menu-pad);
2849
+ background: var(--menu-bg);
2850
+ border: 1px solid var(--menu-border);
2851
+ border-radius: var(--du-menu-radius);
2852
+ box-shadow: var(--du-ui-shadow);
2853
+ }
2854
+
2855
+ /* Rows use the shared menu metrics (see `.du-menu-row`). */
2856
+ .du-shapes-flyout-row {
2857
+ display: flex;
2858
+ gap: var(--du-menu-gap);
2859
+ align-items: center;
2860
+ width: 100%;
2861
+ min-height: var(--du-menu-row-h);
2862
+ padding: 0 var(--du-menu-row-pad-x);
2863
+ font-size: var(--du-menu-font);
2864
+ color: var(--du-text);
2865
+ text-align: left;
2866
+ background: transparent;
2867
+ border: 0;
2868
+ border-radius: var(--du-menu-row-radius);
2869
+ cursor: pointer;
2870
+ }
2871
+
2872
+ .du-shapes-flyout-row:hover {
2873
+ background: var(--du-hover-overlay);
2874
+ }
2875
+
2876
+ /* The armed tool (shape kind / line preset) — tonal selected, like menus. */
2877
+ .du-shapes-flyout-row.is-active {
2878
+ background: var(--du-selected-bg);
2879
+ color: var(--du-selected-fg);
2880
+ }
2881
+
2882
+ .du-shapes-flyout-row.is-active .du-shapes-flyout-hotkey {
2883
+ color: inherit;
2884
+ }
2885
+
2886
+ .du-shapes-flyout-hotkey {
2887
+ margin-left: auto;
2888
+ font-size: var(--du-menu-shortcut-font);
2889
+ color: var(--du-text-muted);
2890
+ }
2891
+
2892
+ .du-shapes-flyout-divider {
2893
+ margin: var(--du-menu-sep) 0;
2894
+ border: none;
2895
+ border-top: 1px solid var(--du-ui-border);
2896
+ }