@oh-just-another/react-ui 0.60.0 → 0.62.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 (365) hide show
  1. package/CHANGELOG.md +137 -0
  2. package/README.md +3 -3
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/{color-palette.d.ts → color/color-palette.d.ts} +5 -0
  5. package/dist/color/color-palette.d.ts.map +1 -0
  6. package/dist/{color-palette.js → color/color-palette.js} +5 -0
  7. package/dist/color/color-palette.js.map +1 -0
  8. package/dist/color/color-swatch-picker.d.ts.map +1 -0
  9. package/dist/{color-swatch-picker.js → color/color-swatch-picker.js} +8 -17
  10. package/dist/color/color-swatch-picker.js.map +1 -0
  11. package/dist/{constants.d.ts → core/constants.d.ts} +70 -21
  12. package/dist/core/constants.d.ts.map +1 -0
  13. package/dist/{constants.js → core/constants.js} +104 -16
  14. package/dist/core/constants.js.map +1 -0
  15. package/dist/core/context.d.ts.map +1 -0
  16. package/dist/core/context.js.map +1 -0
  17. package/dist/core/hooks.d.ts.map +1 -0
  18. package/dist/core/hooks.js.map +1 -0
  19. package/dist/core/portal-container.d.ts.map +1 -0
  20. package/dist/core/portal-container.js.map +1 -0
  21. package/dist/core/use-fullscreen.d.ts +14 -0
  22. package/dist/core/use-fullscreen.d.ts.map +1 -0
  23. package/dist/core/use-fullscreen.js +38 -0
  24. package/dist/core/use-fullscreen.js.map +1 -0
  25. package/dist/core/use-quiet-gesture.d.ts +11 -0
  26. package/dist/core/use-quiet-gesture.d.ts.map +1 -0
  27. package/dist/core/use-quiet-gesture.js +61 -0
  28. package/dist/core/use-quiet-gesture.js.map +1 -0
  29. package/dist/core/use-quiet-viewport.d.ts +10 -0
  30. package/dist/core/use-quiet-viewport.d.ts.map +1 -0
  31. package/dist/core/use-quiet-viewport.js +40 -0
  32. package/dist/core/use-quiet-viewport.js.map +1 -0
  33. package/dist/index.d.ts +55 -50
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +55 -50
  36. package/dist/index.js.map +1 -1
  37. package/dist/layout/diagram-bars.d.ts.map +1 -0
  38. package/dist/layout/diagram-bars.js.map +1 -0
  39. package/dist/layout/diagram-canvas.d.ts.map +1 -0
  40. package/dist/layout/diagram-canvas.js.map +1 -0
  41. package/dist/layout/diagram-root.d.ts.map +1 -0
  42. package/dist/{diagram-root.js → layout/diagram-root.js} +2 -2
  43. package/dist/layout/diagram-root.js.map +1 -0
  44. package/dist/{sidebar.d.ts → layout/sidebar.d.ts} +1 -0
  45. package/dist/layout/sidebar.d.ts.map +1 -0
  46. package/dist/layout/sidebar.js +38 -0
  47. package/dist/layout/sidebar.js.map +1 -0
  48. package/dist/layout/ui-layer.d.ts.map +1 -0
  49. package/dist/layout/ui-layer.js.map +1 -0
  50. package/dist/menus/command-palette.d.ts.map +1 -0
  51. package/dist/{command-palette.js → menus/command-palette.js} +3 -3
  52. package/dist/menus/command-palette.js.map +1 -0
  53. package/dist/menus/context-menu-controller.d.ts.map +1 -0
  54. package/dist/menus/context-menu-controller.js.map +1 -0
  55. package/dist/{context-menu.d.ts → menus/context-menu.d.ts} +12 -0
  56. package/dist/menus/context-menu.d.ts.map +1 -0
  57. package/dist/menus/context-menu.js +617 -0
  58. package/dist/menus/context-menu.js.map +1 -0
  59. package/dist/menus/link-drop-shape-menu.d.ts.map +1 -0
  60. package/dist/{link-drop-shape-menu.js → menus/link-drop-shape-menu.js} +4 -4
  61. package/dist/menus/link-drop-shape-menu.js.map +1 -0
  62. package/dist/{main-menu.d.ts → menus/main-menu.d.ts} +45 -2
  63. package/dist/menus/main-menu.d.ts.map +1 -0
  64. package/dist/menus/main-menu.js +260 -0
  65. package/dist/menus/main-menu.js.map +1 -0
  66. package/dist/overlays/file-drop-overlay.d.ts +15 -0
  67. package/dist/overlays/file-drop-overlay.d.ts.map +1 -0
  68. package/dist/overlays/file-drop-overlay.js +27 -0
  69. package/dist/overlays/file-drop-overlay.js.map +1 -0
  70. package/dist/overlays/frame-name-editor-overlay.d.ts.map +1 -0
  71. package/dist/{frame-name-editor-overlay.js → overlays/frame-name-editor-overlay.js} +1 -1
  72. package/dist/overlays/frame-name-editor-overlay.js.map +1 -0
  73. package/dist/overlays/help-button.d.ts.map +1 -0
  74. package/dist/{help-button.js → overlays/help-button.js} +3 -4
  75. package/dist/overlays/help-button.js.map +1 -0
  76. package/dist/overlays/help-dialog.d.ts.map +1 -0
  77. package/dist/{help-dialog.js → overlays/help-dialog.js} +4 -24
  78. package/dist/overlays/help-dialog.js.map +1 -0
  79. package/dist/overlays/link-badges.d.ts +14 -0
  80. package/dist/overlays/link-badges.d.ts.map +1 -0
  81. package/dist/overlays/link-badges.js +60 -0
  82. package/dist/overlays/link-badges.js.map +1 -0
  83. package/dist/overlays/link-caption-editor.d.ts.map +1 -0
  84. package/dist/{link-caption-editor.js → overlays/link-caption-editor.js} +3 -3
  85. package/dist/overlays/link-caption-editor.js.map +1 -0
  86. package/dist/overlays/link-hover-popup.d.ts.map +1 -0
  87. package/dist/{link-hover-popup.js → overlays/link-hover-popup.js} +5 -4
  88. package/dist/overlays/link-hover-popup.js.map +1 -0
  89. package/dist/overlays/merge-dialog.d.ts.map +1 -0
  90. package/dist/overlays/merge-dialog.js +39 -0
  91. package/dist/overlays/merge-dialog.js.map +1 -0
  92. package/dist/overlays/search-overlay.d.ts.map +1 -0
  93. package/dist/{search-overlay.js → overlays/search-overlay.js} +2 -2
  94. package/dist/overlays/search-overlay.js.map +1 -0
  95. package/dist/overlays/sticky-reactions.d.ts +2 -0
  96. package/dist/overlays/sticky-reactions.d.ts.map +1 -0
  97. package/dist/overlays/sticky-reactions.js +94 -0
  98. package/dist/overlays/sticky-reactions.js.map +1 -0
  99. package/dist/overlays/text-editor-overlay.d.ts.map +1 -0
  100. package/dist/{text-editor-overlay.js → overlays/text-editor-overlay.js} +37 -5
  101. package/dist/overlays/text-editor-overlay.js.map +1 -0
  102. package/dist/{comments-panel.d.ts → panels/comments-panel.d.ts} +4 -1
  103. package/dist/panels/comments-panel.d.ts.map +1 -0
  104. package/dist/panels/comments-panel.js +51 -0
  105. package/dist/panels/comments-panel.js.map +1 -0
  106. package/dist/panels/diff-panel.d.ts.map +1 -0
  107. package/dist/panels/diff-panel.js.map +1 -0
  108. package/dist/panels/drawing-panel.d.ts.map +1 -0
  109. package/dist/{drawing-panel.js → panels/drawing-panel.js} +3 -3
  110. package/dist/panels/drawing-panel.js.map +1 -0
  111. package/dist/panels/edge-style-panel.d.ts.map +1 -0
  112. package/dist/{edge-style-panel.js → panels/edge-style-panel.js} +1 -1
  113. package/dist/panels/edge-style-panel.js.map +1 -0
  114. package/dist/panels/frame-panel.d.ts.map +1 -0
  115. package/dist/{frame-panel.js → panels/frame-panel.js} +1 -1
  116. package/dist/panels/frame-panel.js.map +1 -0
  117. package/dist/{layer-panel.d.ts → panels/layer-panel.d.ts} +5 -1
  118. package/dist/panels/layer-panel.d.ts.map +1 -0
  119. package/dist/panels/layer-panel.js +52 -0
  120. package/dist/panels/layer-panel.js.map +1 -0
  121. package/dist/panels/library-panel.d.ts.map +1 -0
  122. package/dist/{library-panel.js → panels/library-panel.js} +4 -5
  123. package/dist/panels/library-panel.js.map +1 -0
  124. package/dist/panels/property-panel.d.ts.map +1 -0
  125. package/dist/panels/property-panel.js +1397 -0
  126. package/dist/panels/property-panel.js.map +1 -0
  127. package/dist/panels/selection-floating-panel.d.ts.map +1 -0
  128. package/dist/{selection-floating-panel.js → panels/selection-floating-panel.js} +24 -13
  129. package/dist/panels/selection-floating-panel.js.map +1 -0
  130. package/dist/panels/stats-panel.d.ts.map +1 -0
  131. package/dist/{stats-panel.js → panels/stats-panel.js} +1 -1
  132. package/dist/panels/stats-panel.js.map +1 -0
  133. package/dist/primitives/bottom-sheet.d.ts.map +1 -0
  134. package/dist/{bottom-sheet.js → primitives/bottom-sheet.js} +9 -22
  135. package/dist/primitives/bottom-sheet.js.map +1 -0
  136. package/dist/primitives/button-group.d.ts.map +1 -0
  137. package/dist/primitives/button-group.js.map +1 -0
  138. package/dist/primitives/css-var.d.ts +8 -0
  139. package/dist/primitives/css-var.d.ts.map +1 -0
  140. package/dist/primitives/css-var.js +11 -0
  141. package/dist/primitives/css-var.js.map +1 -0
  142. package/dist/primitives/float-panel.d.ts +35 -0
  143. package/dist/primitives/float-panel.d.ts.map +1 -0
  144. package/dist/primitives/float-panel.js +42 -0
  145. package/dist/primitives/float-panel.js.map +1 -0
  146. package/dist/primitives/icon-button.d.ts.map +1 -0
  147. package/dist/primitives/icon-button.js.map +1 -0
  148. package/dist/primitives/markdown.d.ts.map +1 -0
  149. package/dist/primitives/markdown.js.map +1 -0
  150. package/dist/primitives/modal.d.ts.map +1 -0
  151. package/dist/{modal.js → primitives/modal.js} +11 -9
  152. package/dist/primitives/modal.js.map +1 -0
  153. package/dist/{popover.d.ts → primitives/popover.d.ts} +1 -1
  154. package/dist/primitives/popover.d.ts.map +1 -0
  155. package/dist/{popover.js → primitives/popover.js} +7 -18
  156. package/dist/primitives/popover.js.map +1 -0
  157. package/dist/primitives/segmented-control.d.ts.map +1 -0
  158. package/dist/primitives/segmented-control.js.map +1 -0
  159. package/dist/primitives/slider.d.ts.map +1 -0
  160. package/dist/primitives/slider.js.map +1 -0
  161. package/dist/primitives/switch.d.ts +24 -0
  162. package/dist/primitives/switch.d.ts.map +1 -0
  163. package/dist/primitives/switch.js +17 -0
  164. package/dist/primitives/switch.js.map +1 -0
  165. package/dist/primitives/toast.d.ts.map +1 -0
  166. package/dist/{toast.js → primitives/toast.js} +12 -33
  167. package/dist/primitives/toast.js.map +1 -0
  168. package/dist/primitives/tooltip.d.ts.map +1 -0
  169. package/dist/{tooltip.js → primitives/tooltip.js} +3 -3
  170. package/dist/primitives/tooltip.js.map +1 -0
  171. package/dist/{palette.d.ts → toolbar/palette.d.ts} +6 -1
  172. package/dist/toolbar/palette.d.ts.map +1 -0
  173. package/dist/{palette.js → toolbar/palette.js} +39 -5
  174. package/dist/toolbar/palette.js.map +1 -0
  175. package/dist/{toolbar.d.ts → toolbar/toolbar.d.ts} +9 -0
  176. package/dist/toolbar/toolbar.d.ts.map +1 -0
  177. package/dist/{toolbar.js → toolbar/toolbar.js} +132 -62
  178. package/dist/toolbar/toolbar.js.map +1 -0
  179. package/dist/utils/format-time.d.ts.map +1 -0
  180. package/dist/utils/format-time.js.map +1 -0
  181. package/dist/utils/use-dismiss-timer.d.ts.map +1 -0
  182. package/dist/utils/use-dismiss-timer.js.map +1 -0
  183. package/dist/widgets/minimap.d.ts.map +1 -0
  184. package/dist/{minimap.js → widgets/minimap.js} +50 -36
  185. package/dist/widgets/minimap.js.map +1 -0
  186. package/dist/widgets/reset-to-content-button.d.ts +11 -0
  187. package/dist/widgets/reset-to-content-button.d.ts.map +1 -0
  188. package/dist/{reset-to-content-button.js → widgets/reset-to-content-button.js} +8 -9
  189. package/dist/widgets/reset-to-content-button.js.map +1 -0
  190. package/dist/widgets/versioning.d.ts.map +1 -0
  191. package/dist/{versioning.js → widgets/versioning.js} +4 -4
  192. package/dist/widgets/versioning.js.map +1 -0
  193. package/dist/widgets/zen-mode.d.ts.map +1 -0
  194. package/dist/widgets/zen-mode.js.map +1 -0
  195. package/package.json +9 -9
  196. package/src/styles.css +1622 -287
  197. package/dist/bottom-sheet.d.ts.map +0 -1
  198. package/dist/bottom-sheet.js.map +0 -1
  199. package/dist/button-group.d.ts.map +0 -1
  200. package/dist/button-group.js.map +0 -1
  201. package/dist/color-palette.d.ts.map +0 -1
  202. package/dist/color-palette.js.map +0 -1
  203. package/dist/color-swatch-picker.d.ts.map +0 -1
  204. package/dist/color-swatch-picker.js.map +0 -1
  205. package/dist/command-palette.d.ts.map +0 -1
  206. package/dist/command-palette.js.map +0 -1
  207. package/dist/comments-panel.d.ts.map +0 -1
  208. package/dist/comments-panel.js +0 -142
  209. package/dist/comments-panel.js.map +0 -1
  210. package/dist/constants.d.ts.map +0 -1
  211. package/dist/constants.js.map +0 -1
  212. package/dist/context-menu-controller.d.ts.map +0 -1
  213. package/dist/context-menu-controller.js.map +0 -1
  214. package/dist/context-menu.d.ts.map +0 -1
  215. package/dist/context-menu.js +0 -368
  216. package/dist/context-menu.js.map +0 -1
  217. package/dist/context.d.ts.map +0 -1
  218. package/dist/context.js.map +0 -1
  219. package/dist/diagram-bars.d.ts.map +0 -1
  220. package/dist/diagram-bars.js.map +0 -1
  221. package/dist/diagram-canvas.d.ts.map +0 -1
  222. package/dist/diagram-canvas.js.map +0 -1
  223. package/dist/diagram-root.d.ts.map +0 -1
  224. package/dist/diagram-root.js.map +0 -1
  225. package/dist/diff-panel.d.ts.map +0 -1
  226. package/dist/diff-panel.js.map +0 -1
  227. package/dist/drawing-panel.d.ts.map +0 -1
  228. package/dist/drawing-panel.js.map +0 -1
  229. package/dist/edge-style-panel.d.ts.map +0 -1
  230. package/dist/edge-style-panel.js.map +0 -1
  231. package/dist/format-time.d.ts.map +0 -1
  232. package/dist/format-time.js.map +0 -1
  233. package/dist/frame-name-editor-overlay.d.ts.map +0 -1
  234. package/dist/frame-name-editor-overlay.js.map +0 -1
  235. package/dist/frame-panel.d.ts.map +0 -1
  236. package/dist/frame-panel.js.map +0 -1
  237. package/dist/help-button.d.ts.map +0 -1
  238. package/dist/help-button.js.map +0 -1
  239. package/dist/help-dialog.d.ts.map +0 -1
  240. package/dist/help-dialog.js.map +0 -1
  241. package/dist/hooks.d.ts.map +0 -1
  242. package/dist/hooks.js.map +0 -1
  243. package/dist/icon-button.d.ts.map +0 -1
  244. package/dist/icon-button.js.map +0 -1
  245. package/dist/layer-panel.d.ts.map +0 -1
  246. package/dist/layer-panel.js +0 -117
  247. package/dist/layer-panel.js.map +0 -1
  248. package/dist/library-panel.d.ts.map +0 -1
  249. package/dist/library-panel.js.map +0 -1
  250. package/dist/link-caption-editor.d.ts.map +0 -1
  251. package/dist/link-caption-editor.js.map +0 -1
  252. package/dist/link-drop-shape-menu.d.ts.map +0 -1
  253. package/dist/link-drop-shape-menu.js.map +0 -1
  254. package/dist/link-hover-popup.d.ts.map +0 -1
  255. package/dist/link-hover-popup.js.map +0 -1
  256. package/dist/main-menu.d.ts.map +0 -1
  257. package/dist/main-menu.js +0 -249
  258. package/dist/main-menu.js.map +0 -1
  259. package/dist/markdown.d.ts.map +0 -1
  260. package/dist/markdown.js.map +0 -1
  261. package/dist/merge-dialog.d.ts.map +0 -1
  262. package/dist/merge-dialog.js +0 -50
  263. package/dist/merge-dialog.js.map +0 -1
  264. package/dist/minimap.d.ts.map +0 -1
  265. package/dist/minimap.js.map +0 -1
  266. package/dist/modal.d.ts.map +0 -1
  267. package/dist/modal.js.map +0 -1
  268. package/dist/palette.d.ts.map +0 -1
  269. package/dist/palette.js.map +0 -1
  270. package/dist/popover.d.ts.map +0 -1
  271. package/dist/popover.js.map +0 -1
  272. package/dist/portal-container.d.ts.map +0 -1
  273. package/dist/portal-container.js.map +0 -1
  274. package/dist/property-panel.d.ts.map +0 -1
  275. package/dist/property-panel.js +0 -917
  276. package/dist/property-panel.js.map +0 -1
  277. package/dist/reset-to-content-button.d.ts +0 -10
  278. package/dist/reset-to-content-button.d.ts.map +0 -1
  279. package/dist/reset-to-content-button.js.map +0 -1
  280. package/dist/search-overlay.d.ts.map +0 -1
  281. package/dist/search-overlay.js.map +0 -1
  282. package/dist/segmented-control.d.ts.map +0 -1
  283. package/dist/segmented-control.js.map +0 -1
  284. package/dist/selection-floating-panel.d.ts.map +0 -1
  285. package/dist/selection-floating-panel.js.map +0 -1
  286. package/dist/sidebar.d.ts.map +0 -1
  287. package/dist/sidebar.js +0 -68
  288. package/dist/sidebar.js.map +0 -1
  289. package/dist/slider.d.ts.map +0 -1
  290. package/dist/slider.js.map +0 -1
  291. package/dist/stats-panel.d.ts.map +0 -1
  292. package/dist/stats-panel.js.map +0 -1
  293. package/dist/text-editor-overlay.d.ts.map +0 -1
  294. package/dist/text-editor-overlay.js.map +0 -1
  295. package/dist/toast.d.ts.map +0 -1
  296. package/dist/toast.js.map +0 -1
  297. package/dist/toolbar.d.ts.map +0 -1
  298. package/dist/toolbar.js.map +0 -1
  299. package/dist/tooltip.d.ts.map +0 -1
  300. package/dist/tooltip.js.map +0 -1
  301. package/dist/ui-layer.d.ts.map +0 -1
  302. package/dist/ui-layer.js.map +0 -1
  303. package/dist/use-dismiss-timer.d.ts.map +0 -1
  304. package/dist/use-dismiss-timer.js.map +0 -1
  305. package/dist/versioning.d.ts.map +0 -1
  306. package/dist/versioning.js.map +0 -1
  307. package/dist/zen-mode.d.ts.map +0 -1
  308. package/dist/zen-mode.js.map +0 -1
  309. /package/dist/{color-swatch-picker.d.ts → color/color-swatch-picker.d.ts} +0 -0
  310. /package/dist/{context.d.ts → core/context.d.ts} +0 -0
  311. /package/dist/{context.js → core/context.js} +0 -0
  312. /package/dist/{hooks.d.ts → core/hooks.d.ts} +0 -0
  313. /package/dist/{hooks.js → core/hooks.js} +0 -0
  314. /package/dist/{portal-container.d.ts → core/portal-container.d.ts} +0 -0
  315. /package/dist/{portal-container.js → core/portal-container.js} +0 -0
  316. /package/dist/{diagram-bars.d.ts → layout/diagram-bars.d.ts} +0 -0
  317. /package/dist/{diagram-bars.js → layout/diagram-bars.js} +0 -0
  318. /package/dist/{diagram-canvas.d.ts → layout/diagram-canvas.d.ts} +0 -0
  319. /package/dist/{diagram-canvas.js → layout/diagram-canvas.js} +0 -0
  320. /package/dist/{diagram-root.d.ts → layout/diagram-root.d.ts} +0 -0
  321. /package/dist/{ui-layer.d.ts → layout/ui-layer.d.ts} +0 -0
  322. /package/dist/{ui-layer.js → layout/ui-layer.js} +0 -0
  323. /package/dist/{command-palette.d.ts → menus/command-palette.d.ts} +0 -0
  324. /package/dist/{context-menu-controller.d.ts → menus/context-menu-controller.d.ts} +0 -0
  325. /package/dist/{context-menu-controller.js → menus/context-menu-controller.js} +0 -0
  326. /package/dist/{link-drop-shape-menu.d.ts → menus/link-drop-shape-menu.d.ts} +0 -0
  327. /package/dist/{frame-name-editor-overlay.d.ts → overlays/frame-name-editor-overlay.d.ts} +0 -0
  328. /package/dist/{help-button.d.ts → overlays/help-button.d.ts} +0 -0
  329. /package/dist/{help-dialog.d.ts → overlays/help-dialog.d.ts} +0 -0
  330. /package/dist/{link-caption-editor.d.ts → overlays/link-caption-editor.d.ts} +0 -0
  331. /package/dist/{link-hover-popup.d.ts → overlays/link-hover-popup.d.ts} +0 -0
  332. /package/dist/{merge-dialog.d.ts → overlays/merge-dialog.d.ts} +0 -0
  333. /package/dist/{search-overlay.d.ts → overlays/search-overlay.d.ts} +0 -0
  334. /package/dist/{text-editor-overlay.d.ts → overlays/text-editor-overlay.d.ts} +0 -0
  335. /package/dist/{diff-panel.d.ts → panels/diff-panel.d.ts} +0 -0
  336. /package/dist/{diff-panel.js → panels/diff-panel.js} +0 -0
  337. /package/dist/{drawing-panel.d.ts → panels/drawing-panel.d.ts} +0 -0
  338. /package/dist/{edge-style-panel.d.ts → panels/edge-style-panel.d.ts} +0 -0
  339. /package/dist/{frame-panel.d.ts → panels/frame-panel.d.ts} +0 -0
  340. /package/dist/{library-panel.d.ts → panels/library-panel.d.ts} +0 -0
  341. /package/dist/{property-panel.d.ts → panels/property-panel.d.ts} +0 -0
  342. /package/dist/{selection-floating-panel.d.ts → panels/selection-floating-panel.d.ts} +0 -0
  343. /package/dist/{stats-panel.d.ts → panels/stats-panel.d.ts} +0 -0
  344. /package/dist/{bottom-sheet.d.ts → primitives/bottom-sheet.d.ts} +0 -0
  345. /package/dist/{button-group.d.ts → primitives/button-group.d.ts} +0 -0
  346. /package/dist/{button-group.js → primitives/button-group.js} +0 -0
  347. /package/dist/{icon-button.d.ts → primitives/icon-button.d.ts} +0 -0
  348. /package/dist/{icon-button.js → primitives/icon-button.js} +0 -0
  349. /package/dist/{markdown.d.ts → primitives/markdown.d.ts} +0 -0
  350. /package/dist/{markdown.js → primitives/markdown.js} +0 -0
  351. /package/dist/{modal.d.ts → primitives/modal.d.ts} +0 -0
  352. /package/dist/{segmented-control.d.ts → primitives/segmented-control.d.ts} +0 -0
  353. /package/dist/{segmented-control.js → primitives/segmented-control.js} +0 -0
  354. /package/dist/{slider.d.ts → primitives/slider.d.ts} +0 -0
  355. /package/dist/{slider.js → primitives/slider.js} +0 -0
  356. /package/dist/{toast.d.ts → primitives/toast.d.ts} +0 -0
  357. /package/dist/{tooltip.d.ts → primitives/tooltip.d.ts} +0 -0
  358. /package/dist/{format-time.d.ts → utils/format-time.d.ts} +0 -0
  359. /package/dist/{format-time.js → utils/format-time.js} +0 -0
  360. /package/dist/{use-dismiss-timer.d.ts → utils/use-dismiss-timer.d.ts} +0 -0
  361. /package/dist/{use-dismiss-timer.js → utils/use-dismiss-timer.js} +0 -0
  362. /package/dist/{minimap.d.ts → widgets/minimap.d.ts} +0 -0
  363. /package/dist/{versioning.d.ts → widgets/versioning.d.ts} +0 -0
  364. /package/dist/{zen-mode.d.ts → widgets/zen-mode.d.ts} +0 -0
  365. /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
  /**
@@ -79,11 +206,15 @@
79
206
  :root {
80
207
  /* All values mirror UI_SURFACE.dark + UI_ACCENT.dark from
81
208
  `@oh-just-another/tokens`. */
82
- --du-canvas-bg: #121212; /* UI_SURFACE.dark.canvas */
83
- --du-ui-bg: rgba(35, 35, 35, 0.95); /* UI_SURFACE.dark.bg */
209
+ /* The canvas is NOT themed (user content is authored against light
210
+ paper); dark mode darkens the chrome only. UI_SURFACE.dark.canvas. */
211
+ --du-canvas-bg: #f5f5f5;
212
+ --du-ui-bg: #252525; /* UI_SURFACE.dark.bg */
84
213
  --du-ui-bg-solid: #252525; /* UI_SURFACE.dark.bgSolid */
85
214
  --du-ui-border: rgba(255, 255, 255, 0.08); /* UI_SURFACE.dark.border */
86
- --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);
87
218
  --du-text: #e8e8e8; /* UI_SURFACE.dark.text */
88
219
  --du-text-muted: #9a9a9a; /* UI_SURFACE.dark.textMuted */
89
220
  --du-accent: #5b5bd6; /* UI_ACCENT.dark.accent (irisDark.iris9) */
@@ -100,10 +231,12 @@
100
231
  up the light palette under all conditions. Mirrors
101
232
  UI_SURFACE.light + UI_ACCENT.light. */
102
233
  --du-canvas-bg: #f5f5f5;
103
- --du-ui-bg: rgba(255, 255, 255, 0.95);
234
+ --du-ui-bg: #ffffff;
104
235
  --du-ui-bg-solid: #ffffff;
105
236
  --du-ui-border: rgba(0, 0, 0, 0.08);
106
- --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);
107
240
  --du-text: #1a1a1a;
108
241
  --du-text-muted: #6b6b6b;
109
242
  --du-accent: #5b5bd6; /* iris.iris9 */
@@ -114,8 +247,8 @@
114
247
  }
115
248
 
116
249
  /* ------------------------------------------------------------------ */
117
- /* Legacy variable aliases — kept so the older components (MainMenu, */
118
- /* 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)` / */
119
252
  /* `var(--text)` / `var(--button-bg)` etc. still pick up the active */
120
253
  /* theme without being rewritten to the `--du-*` namespace. */
121
254
  /* */
@@ -157,16 +290,21 @@
157
290
  --toolbar-bg: var(--du-ui-bg-solid);
158
291
  --cursor-bg: var(--du-selected-bg);
159
292
  --code-bg: var(--du-ui-bg-solid);
160
- --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);
161
296
  }
162
297
 
163
298
  [data-theme="dark"] {
164
299
  /* Mirrors UI_SURFACE.dark + UI_ACCENT.dark from `@oh-just-another/tokens`. */
165
- --du-canvas-bg: #121212;
166
- --du-ui-bg: rgba(35, 35, 35, 0.95);
300
+ /* Canvas stays light — see the note in the media-query block above. */
301
+ --du-canvas-bg: #f5f5f5;
302
+ --du-ui-bg: #252525;
167
303
  --du-ui-bg-solid: #252525;
168
304
  --du-ui-border: rgba(255, 255, 255, 0.08);
169
- --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);
170
308
  --du-text: #e8e8e8;
171
309
  --du-text-muted: #9a9a9a;
172
310
  --du-accent: #5b5bd6; /* irisDark.iris9 */
@@ -177,19 +315,16 @@
177
315
  }
178
316
 
179
317
  /* ------------------------------------------------------------------ */
180
- /* Canvas surface focus ring. The surface is `tabIndex=0` so keyboard */
181
- /* users can land on it, but it also takes focus on a pointer press */
182
- /* (so shortcuts work right after a click). Gate the ring on */
183
- /* `:focus-visible` so it shows ONLY for keyboard focus — a mouse click */
184
- /* never draws an input-like outline. Class+pseudo specificity (0,2,0) */
185
- /* 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. */
186
323
  /* ------------------------------------------------------------------ */
187
- .du-canvas-surface {
188
- outline: none;
189
- }
324
+ .du-canvas-surface,
325
+ .du-canvas-surface:focus,
190
326
  .du-canvas-surface:focus-visible {
191
- outline: 2px solid var(--du-accent);
192
- outline-offset: -2px;
327
+ outline: none;
193
328
  }
194
329
 
195
330
  /* ------------------------------------------------------------------ */
@@ -262,13 +397,14 @@
262
397
  border: 1px solid var(--du-ui-border);
263
398
  border-radius: var(--du-radius);
264
399
  cursor: pointer;
265
- font-size: 14px;
400
+ font-family: var(--du-font-family);
401
+ font-size: var(--du-font-size);
266
402
  line-height: 1;
267
403
  box-shadow: var(--du-ui-shadow);
268
404
  transition:
269
- background 0.12s ease,
270
- color 0.12s ease,
271
- transform 0.05s ease;
405
+ background var(--du-motion-fast),
406
+ color var(--du-motion-fast),
407
+ transform var(--du-motion-press);
272
408
  padding: 0;
273
409
  outline: none;
274
410
  user-select: none;
@@ -289,7 +425,7 @@
289
425
 
290
426
  .du-icon-button:focus-visible {
291
427
  outline: 2px solid var(--du-accent);
292
- outline-offset: 2px;
428
+ outline-offset: var(--du-space-xs);
293
429
  }
294
430
 
295
431
  .du-icon-button[aria-pressed="true"],
@@ -309,7 +445,7 @@
309
445
  .du-icon-button-sm {
310
446
  width: var(--du-button-size-sm);
311
447
  height: var(--du-button-size-sm);
312
- font-size: 12px;
448
+ font-size: var(--du-font-size-sm);
313
449
  }
314
450
 
315
451
  /**
@@ -352,6 +488,22 @@
352
488
  be able to render outside the group's bounds. */
353
489
  }
354
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
+
355
507
  /* Vertical variant — the left creation dock. Stacks buttons in a
356
508
  column; dividers (rendered inline by <Toolbar>) become horizontal. */
357
509
  .du-button-group-vertical {
@@ -359,7 +511,8 @@
359
511
  align-items: stretch;
360
512
  }
361
513
 
362
- .du-button-group > .du-icon-button {
514
+ .du-button-group > .du-icon-button,
515
+ .du-button-group > .du-shapes-wrap > .du-icon-button {
363
516
  border: none;
364
517
  box-shadow: none;
365
518
  border-radius: var(--du-radius-sm);
@@ -369,7 +522,8 @@
369
522
  }
370
523
 
371
524
  /* Vertical dock buttons are square + centred (icon-only tools). */
372
- .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 {
373
527
  width: var(--du-button-size-sm) !important;
374
528
  min-width: var(--du-button-size-sm) !important;
375
529
  padding: 0 !important;
@@ -405,25 +559,31 @@
405
559
  .du-button-group-vertical::-webkit-scrollbar {
406
560
  display: none;
407
561
  }
408
- .du-button-group-vertical > .du-icon-button {
409
- width: 44px !important;
410
- min-width: 44px !important;
411
- 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;
412
567
  }
413
568
  }
414
569
 
415
- .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) {
416
572
  background: var(--du-hover-overlay);
417
573
  }
418
574
 
419
575
  .du-button-group > .du-icon-button[aria-pressed="true"],
420
- .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 {
421
579
  background: var(--du-selected-bg);
422
580
  color: var(--du-selected-fg);
423
581
  }
424
582
 
425
583
  .du-button-group > .du-icon-button[aria-pressed="true"]:hover:not(:disabled),
426
- .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) {
427
587
  background: color-mix(in srgb, var(--du-selected-bg) 90%, var(--du-text) 10%);
428
588
  }
429
589
 
@@ -434,13 +594,13 @@
434
594
  /* ------------------------------------------------------------------ */
435
595
  .du-side-panel {
436
596
  position: absolute;
437
- top: calc(var(--du-bar-inset) + var(--du-button-size) + var(--du-gap));
438
- bottom: calc(var(--du-bar-inset) + var(--du-button-size) + var(--du-gap));
439
- width: 240px;
597
+ top: var(--du-bar-clear);
598
+ bottom: var(--du-bar-clear);
599
+ width: var(--du-side-panel-w);
440
600
  background: var(--du-ui-bg);
441
601
  color: var(--du-text);
442
602
  border: 1px solid var(--du-ui-border);
443
- border-radius: var(--du-radius);
603
+ border-radius: var(--du-radius-lg);
444
604
  box-shadow: var(--du-ui-shadow);
445
605
  display: flex;
446
606
  flex-direction: column;
@@ -474,13 +634,13 @@
474
634
  .du-side-panel-header {
475
635
  display: flex;
476
636
  align-items: center;
477
- justify-content: flex-end;
637
+ justify-content: space-between;
478
638
  gap: var(--du-gap-sm);
479
639
  padding: var(--du-pad-sm) var(--du-pad-sm) var(--du-pad-sm) var(--du-pad);
480
- font-size: 12px;
481
- font-weight: 600;
640
+ font-size: var(--du-font-size-sm);
641
+ font-weight: var(--du-font-weight-strong);
482
642
  text-transform: uppercase;
483
- letter-spacing: 0.5px;
643
+ letter-spacing: var(--du-caps-tracking);
484
644
  color: var(--du-text-muted);
485
645
  }
486
646
 
@@ -489,6 +649,16 @@
489
649
  display: none;
490
650
  }
491
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
+
492
662
  /* Auto-height variant — content hugs its natural height instead
493
663
  of stretching from top to bottom of the canvas area. Used by
494
664
  the Properties panel so it shrinks to whatever the inspector
@@ -496,7 +666,7 @@
496
666
  so its long grid can scroll. */
497
667
  .du-side-panel-auto-height {
498
668
  bottom: auto;
499
- 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));
500
670
  }
501
671
 
502
672
  .du-side-panel-body {
@@ -513,6 +683,335 @@
513
683
  padding: 0;
514
684
  }
515
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
+
516
1015
  /* ------------------------------------------------------------------ */
517
1016
  /* Palette (template library content) — sectioned grid of icon tiles. */
518
1017
  /* No per-tile borders, no per-section dividers — visual structure */
@@ -533,8 +1032,9 @@
533
1032
  flex-direction: column;
534
1033
  }
535
1034
 
1035
+ /* Sections sit inside the same inset a menu panel gives its rows. */
536
1036
  .du-palette-section {
537
- padding: 0 var(--du-pad) var(--du-pad-sm);
1037
+ padding: 0 var(--du-menu-pad);
538
1038
  }
539
1039
 
540
1040
  .du-palette-category {
@@ -542,12 +1042,13 @@
542
1042
  background: transparent;
543
1043
  color: var(--du-text-muted);
544
1044
  border: none;
545
- 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);
546
1047
  font: inherit;
547
- font-size: 11px;
548
- font-weight: 600;
1048
+ font-size: var(--du-menu-shortcut-font);
1049
+ font-weight: var(--du-font-weight-strong);
549
1050
  text-transform: uppercase;
550
- letter-spacing: 0.5px;
1051
+ letter-spacing: var(--du-caps-tracking);
551
1052
  text-align: left;
552
1053
  cursor: pointer;
553
1054
  display: flex;
@@ -576,14 +1077,12 @@
576
1077
  padding: 0;
577
1078
  }
578
1079
 
579
- /* Compact list layout (modern-style templates panel) — single column of
580
- icon + name rows. Denser than the grid; the label reads left-aligned
581
- 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`). */
582
1082
  .du-palette-list {
583
1083
  display: flex;
584
1084
  flex-direction: column;
585
- gap: 2px;
586
- padding: 0 var(--du-pad) var(--du-pad-sm);
1085
+ padding: 0 var(--du-menu-pad);
587
1086
  }
588
1087
  .du-palette-section > .du-palette-list {
589
1088
  padding: 0;
@@ -593,15 +1092,17 @@
593
1092
  align-items: center;
594
1093
  justify-content: flex-start;
595
1094
  aspect-ratio: auto;
596
- gap: 8px;
597
- 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);
598
1099
  text-align: left;
599
- font-size: 12px;
600
- line-height: 1.2;
1100
+ font-size: var(--du-menu-font);
1101
+ line-height: var(--du-line-height);
601
1102
  }
602
1103
  .du-palette-list .du-palette-item-icon {
603
- width: 20px !important;
604
- height: 20px !important;
1104
+ width: var(--du-icon-size) !important;
1105
+ height: var(--du-icon-size) !important;
605
1106
  flex: 0 0 auto;
606
1107
  }
607
1108
  .du-palette-list .du-palette-item-label {
@@ -612,9 +1113,9 @@
612
1113
  }
613
1114
 
614
1115
  .du-palette-empty {
615
- padding: 24px 12px;
1116
+ padding: var(--du-space-2xl) var(--du-space-lg);
616
1117
  text-align: center;
617
- font-size: 12px;
1118
+ font-size: var(--du-font-size-sm);
618
1119
  color: var(--du-text-muted);
619
1120
  }
620
1121
 
@@ -623,18 +1124,18 @@
623
1124
  flex-direction: column;
624
1125
  align-items: center;
625
1126
  justify-content: center;
626
- gap: 4px;
1127
+ gap: var(--du-space-sm);
627
1128
  aspect-ratio: 1;
628
- padding: 6px 4px;
1129
+ padding: var(--du-space-sm);
629
1130
  background: transparent;
630
1131
  color: var(--du-text);
631
1132
  border: none;
632
1133
  border-radius: var(--du-radius-sm);
633
1134
  cursor: grab;
634
1135
  text-align: center;
635
- font-size: 10px;
1136
+ font-size: var(--du-font-size-xs);
636
1137
  line-height: 1.1;
637
- transition: background 0.12s ease;
1138
+ transition: background var(--du-motion-fast);
638
1139
  }
639
1140
 
640
1141
  .du-palette-item:hover {
@@ -676,24 +1177,24 @@
676
1177
  .du-prop-panel {
677
1178
  display: flex;
678
1179
  flex-direction: column;
679
- gap: 16px;
680
- padding: 4px 0;
1180
+ gap: var(--du-space-xl);
1181
+ padding: var(--du-space-sm) 0;
681
1182
  color: var(--du-text);
682
- font-size: 12px;
1183
+ font-size: var(--du-font-size-sm);
683
1184
  }
684
1185
 
685
1186
  .du-prop-section {
686
1187
  display: flex;
687
1188
  flex-direction: column;
688
- gap: 6px;
1189
+ gap: var(--du-space-sm);
689
1190
  }
690
1191
 
691
1192
  .du-prop-section-label {
692
1193
  margin: 0;
693
- font-size: 10px;
694
- font-weight: 600;
1194
+ font-size: var(--du-font-size-xs);
1195
+ font-weight: var(--du-font-weight-strong);
695
1196
  text-transform: uppercase;
696
- letter-spacing: 0.5px;
1197
+ letter-spacing: var(--du-caps-tracking);
697
1198
  color: var(--du-text-muted);
698
1199
  }
699
1200
 
@@ -705,15 +1206,15 @@
705
1206
  }
706
1207
 
707
1208
  .du-prop-row-label {
708
- font-size: 11px;
1209
+ font-size: var(--du-font-size-sm);
709
1210
  color: var(--du-text-muted);
710
- min-width: 48px;
1211
+ min-width: 48px; /* label column of a prop row */
711
1212
  }
712
1213
 
713
1214
  .du-prop-empty {
714
1215
  font-style: italic;
715
1216
  color: var(--du-text-muted);
716
- font-size: 12px;
1217
+ font-size: var(--du-font-size-sm);
717
1218
  }
718
1219
 
719
1220
  /* modern-style flat segmented control inside the panel:
@@ -724,7 +1225,7 @@
724
1225
  border: none;
725
1226
  box-shadow: none;
726
1227
  padding: 0;
727
- gap: 2px;
1228
+ gap: var(--du-space-xs);
728
1229
  }
729
1230
 
730
1231
  /* Tighter active state inside the panel (smaller buttons, same
@@ -739,16 +1240,16 @@
739
1240
  .du-prop-checkbox {
740
1241
  display: inline-flex;
741
1242
  align-items: center;
742
- gap: 6px;
1243
+ gap: var(--du-space-sm);
743
1244
  cursor: pointer;
744
- font-size: 12px;
1245
+ font-size: var(--du-font-size-sm);
745
1246
  color: var(--du-text);
746
1247
  user-select: none;
747
1248
  }
748
1249
 
749
1250
  .du-prop-checkbox input[type="checkbox"] {
750
- width: 14px;
751
- height: 14px;
1251
+ width: var(--du-checkbox-size);
1252
+ height: var(--du-checkbox-size);
752
1253
  margin: 0;
753
1254
  accent-color: var(--du-selected-fg);
754
1255
  cursor: pointer;
@@ -763,14 +1264,14 @@
763
1264
  .du-swatch-grid {
764
1265
  display: inline-flex;
765
1266
  flex-wrap: wrap;
766
- gap: 4px;
767
- 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 */
768
1269
  }
769
1270
 
770
1271
  .du-swatch {
771
1272
  position: relative;
772
- width: 26px;
773
- height: 26px;
1273
+ width: var(--du-swatch-size);
1274
+ height: var(--du-swatch-size);
774
1275
  padding: 0;
775
1276
  background: transparent;
776
1277
  border: none;
@@ -781,7 +1282,7 @@
781
1282
  justify-content: center;
782
1283
  /* Reserve the ring space so width never changes on selection. */
783
1284
  box-shadow: inset 0 0 0 0 transparent;
784
- transition: box-shadow 0.12s ease;
1285
+ transition: box-shadow var(--du-motion-fast);
785
1286
  /* Suppress the UA tap-highlight on iOS so the cell looks clean
786
1287
  while the user drags through swatches. */
787
1288
  -webkit-tap-highlight-color: transparent;
@@ -800,21 +1301,21 @@
800
1301
  display: inline-flex;
801
1302
  align-items: center;
802
1303
  justify-content: center;
803
- width: 24px;
804
- height: 24px;
1304
+ width: var(--du-control-h);
1305
+ height: var(--du-control-h);
805
1306
  border-radius: var(--du-radius-sm);
806
1307
  border: 1px solid var(--du-ui-border);
807
1308
  box-sizing: border-box;
808
1309
  transition:
809
- width 0.12s ease,
810
- height 0.12s ease,
811
- border-color 0.12s ease;
1310
+ width var(--du-motion-fast),
1311
+ height var(--du-motion-fast),
1312
+ border-color var(--du-motion-fast);
812
1313
  }
813
1314
 
814
1315
  .du-swatch:hover .du-swatch-fill,
815
1316
  .du-swatch:focus-visible .du-swatch-fill {
816
- width: 26px;
817
- height: 26px;
1317
+ width: var(--du-swatch-size);
1318
+ height: var(--du-swatch-size);
818
1319
  }
819
1320
 
820
1321
  /* Clear (×) + custom-picker (+) cells use the same chrome as a
@@ -839,36 +1340,550 @@
839
1340
  }
840
1341
 
841
1342
  /* ------------------------------------------------------------------ */
842
- /* Slider — themed native <input type=range> + value badge. */
843
1343
  /* ------------------------------------------------------------------ */
844
- .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;
845
1363
  display: flex;
1364
+ gap: var(--du-menu-gap);
846
1365
  align-items: center;
847
- gap: 8px;
1366
+ justify-content: space-between;
848
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;
849
1375
  }
850
1376
 
851
- .du-slider-track {
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);
1863
+ width: 100%;
1864
+ }
1865
+
1866
+ .du-slider-track {
852
1867
  flex: 1;
853
1868
  -webkit-appearance: none;
854
1869
  appearance: none;
855
1870
  background: transparent;
856
- height: 18px;
1871
+ height: var(--du-switch-h);
857
1872
  margin: 0;
858
1873
  padding: 0;
859
1874
  cursor: pointer;
860
1875
  }
861
1876
 
862
1877
  .du-slider-track::-webkit-slider-runnable-track {
863
- height: 4px;
1878
+ height: var(--du-space-sm);
864
1879
  background: var(--du-selected-bg);
865
- border-radius: 2px;
1880
+ border-radius: var(--du-space-xs);
866
1881
  }
867
1882
 
868
1883
  .du-slider-track::-moz-range-track {
869
- height: 4px;
1884
+ height: var(--du-space-sm);
870
1885
  background: var(--du-selected-bg);
871
- border-radius: 2px;
1886
+ border-radius: var(--du-space-xs);
872
1887
  border: none;
873
1888
  }
874
1889
 
@@ -882,7 +1897,7 @@
882
1897
  border: 2px solid var(--du-ui-bg-solid);
883
1898
  margin-top: -5px;
884
1899
  cursor: grab;
885
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
1900
+ box-shadow: var(--du-ui-shadow);
886
1901
  }
887
1902
 
888
1903
  .du-slider-track::-moz-range-thumb {
@@ -892,7 +1907,7 @@
892
1907
  border-radius: 50%;
893
1908
  border: 2px solid var(--du-ui-bg-solid);
894
1909
  cursor: grab;
895
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
1910
+ box-shadow: var(--du-ui-shadow);
896
1911
  }
897
1912
 
898
1913
  .du-slider-track:focus {
@@ -905,10 +1920,10 @@
905
1920
  }
906
1921
 
907
1922
  .du-slider-value {
908
- min-width: 36px;
1923
+ min-width: 36px; /* "100%" */
909
1924
  text-align: right;
910
1925
  font-variant-numeric: tabular-nums;
911
- font-size: 11px;
1926
+ font-size: var(--du-font-size-sm);
912
1927
  color: var(--du-text-muted);
913
1928
  }
914
1929
 
@@ -917,15 +1932,15 @@
917
1932
  /* ------------------------------------------------------------------ */
918
1933
  .du-number-input {
919
1934
  width: 64px;
920
- height: 24px;
1935
+ height: var(--du-control-h);
921
1936
  box-sizing: border-box;
922
1937
  background: var(--du-ui-bg-solid);
923
1938
  color: var(--du-text);
924
1939
  border: 1px solid var(--du-ui-border);
925
1940
  border-radius: var(--du-radius-sm);
926
- padding: 0 6px;
1941
+ padding: 0 var(--du-space-sm);
927
1942
  font: inherit;
928
- font-size: 11px;
1943
+ font-size: var(--du-font-size-sm);
929
1944
  font-variant-numeric: tabular-nums;
930
1945
  outline: none;
931
1946
  }
@@ -937,21 +1952,21 @@
937
1952
  /* Search input row — sits between the header and the body. */
938
1953
  .du-side-panel-search {
939
1954
  position: relative;
940
- padding: var(--du-pad-sm) var(--du-pad);
941
- border-bottom: 1px solid var(--du-ui-border);
1955
+ padding: var(--du-pad-sm) var(--du-pad) var(--du-pad);
942
1956
  }
943
1957
 
944
1958
  .du-side-panel-search input[type="search"] {
945
1959
  width: 100%;
946
- height: 28px;
1960
+ height: var(--du-input-h);
947
1961
  box-sizing: border-box;
948
1962
  background: var(--du-ui-bg-solid);
949
1963
  color: var(--du-text);
950
1964
  border: 1px solid var(--du-ui-border);
951
1965
  border-radius: var(--du-radius-sm);
952
- 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));
953
1968
  font: inherit;
954
- font-size: 12px;
1969
+ font-size: var(--du-font-size-sm);
955
1970
  outline: none;
956
1971
  }
957
1972
 
@@ -965,7 +1980,7 @@
965
1980
 
966
1981
  .du-side-panel-search-icon {
967
1982
  position: absolute;
968
- left: calc(var(--du-pad) + 8px);
1983
+ left: calc(var(--du-pad) + var(--du-space-md));
969
1984
  top: 50%;
970
1985
  transform: translateY(-50%);
971
1986
  color: var(--du-text-muted);
@@ -979,20 +1994,21 @@
979
1994
  display: inline-flex;
980
1995
  align-items: center;
981
1996
  gap: var(--du-gap-sm);
982
- padding: 0 12px;
1997
+ padding: 0 var(--du-space-lg);
983
1998
  height: var(--du-button-size);
984
1999
  background: var(--du-ui-bg);
985
2000
  color: var(--du-text);
986
2001
  border: 1px solid var(--du-ui-border);
987
- border-radius: 999px;
2002
+ border-radius: var(--du-radius-round);
988
2003
  box-shadow: var(--du-ui-shadow);
989
2004
  cursor: pointer;
990
- font-size: 13px;
2005
+ font-family: var(--du-font-family);
2006
+ font-size: var(--du-font-size);
991
2007
  line-height: 1;
992
2008
  white-space: nowrap;
993
2009
  transition:
994
- background 0.15s ease,
995
- transform 0.05s ease;
2010
+ background var(--du-motion-fast),
2011
+ transform var(--du-motion-press);
996
2012
  }
997
2013
 
998
2014
  .du-pill-button:hover {
@@ -1008,16 +2024,16 @@
1008
2024
  /* Pointer-events-none so it never blocks hover on neighbour buttons. */
1009
2025
  /* ------------------------------------------------------------------ */
1010
2026
  .du-tooltip {
1011
- background: var(--du-text);
1012
- color: var(--du-ui-bg-solid);
1013
- 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);
1014
2030
  border-radius: var(--du-radius-sm);
1015
- font-size: 12px;
2031
+ font-size: var(--du-font-size-sm);
1016
2032
  line-height: 1.4;
1017
2033
  white-space: nowrap;
1018
2034
  box-shadow: var(--du-ui-shadow);
1019
- font-family: inherit;
1020
- max-width: 260px;
2035
+ font-family: var(--du-font-family);
2036
+ max-width: var(--du-tooltip-max-w);
1021
2037
  }
1022
2038
 
1023
2039
  /* ------------------------------------------------------------------ */
@@ -1028,22 +2044,21 @@
1028
2044
  /* ------------------------------------------------------------------ */
1029
2045
  .du-help-islands {
1030
2046
  display: grid;
1031
- gap: 24px;
2047
+ gap: var(--du-space-2xl);
1032
2048
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
1033
2049
  }
1034
2050
 
1035
2051
  .du-help-island {
1036
2052
  display: flex;
1037
2053
  flex-direction: column;
1038
- gap: 8px;
2054
+ gap: var(--du-space-md);
1039
2055
  }
1040
2056
 
1041
2057
  .du-help-island-title {
1042
2058
  margin: 0;
1043
- font-size: 13px;
1044
- font-weight: 600;
2059
+ font-size: var(--du-font-size);
2060
+ font-weight: var(--du-font-weight-strong);
1045
2061
  color: var(--du-text);
1046
- letter-spacing: 0.2px;
1047
2062
  }
1048
2063
 
1049
2064
  .du-help-island-rows {
@@ -1056,9 +2071,10 @@
1056
2071
  display: flex;
1057
2072
  align-items: center;
1058
2073
  justify-content: space-between;
1059
- gap: 12px;
1060
- padding: 8px 12px;
1061
- 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);
1062
2078
  color: var(--du-text);
1063
2079
  border-bottom: 1px solid var(--du-ui-border);
1064
2080
  }
@@ -1075,38 +2091,38 @@
1075
2091
  .du-help-keys {
1076
2092
  display: inline-flex;
1077
2093
  align-items: center;
1078
- gap: 4px;
2094
+ gap: var(--du-space-sm);
1079
2095
  flex-shrink: 0;
1080
2096
  }
1081
2097
 
1082
2098
  .du-help-keys-separator {
1083
- font-size: 11px;
2099
+ font-size: var(--du-font-size-sm);
1084
2100
  color: var(--du-text-muted);
1085
- padding: 0 2px;
2101
+ padding: 0 var(--du-space-xs);
1086
2102
  }
1087
2103
 
1088
2104
  .du-help-key {
1089
2105
  display: inline-flex;
1090
2106
  align-items: center;
1091
2107
  justify-content: center;
1092
- min-width: 22px;
1093
- height: 22px;
1094
- padding: 0 6px;
2108
+ min-width: var(--du-key-h);
2109
+ height: var(--du-key-h);
2110
+ padding: 0 var(--du-space-sm);
1095
2111
  background: var(--du-selected-bg);
1096
2112
  color: var(--du-selected-fg);
1097
2113
  border-radius: var(--du-radius-sm);
1098
- font-family: inherit;
1099
- font-size: 11px;
1100
- 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);
1101
2117
  line-height: 1;
1102
2118
  white-space: nowrap;
1103
2119
  }
1104
2120
 
1105
2121
  .du-help-platform-badge {
1106
- font-size: 11px;
2122
+ font-size: var(--du-font-size-sm);
1107
2123
  color: var(--du-text-muted);
1108
2124
  text-transform: uppercase;
1109
- letter-spacing: 0.5px;
2125
+ letter-spacing: var(--du-caps-tracking);
1110
2126
  }
1111
2127
 
1112
2128
  /* ------------------------------------------------------------------ */
@@ -1131,9 +2147,9 @@
1131
2147
  border-radius: var(--du-radius);
1132
2148
  box-shadow: var(--du-ui-shadow);
1133
2149
  padding: var(--du-pad-sm);
1134
- font-size: 12px;
2150
+ font-size: var(--du-font-size-sm);
1135
2151
  color: var(--du-text);
1136
- max-width: calc(100vw - 32px);
2152
+ max-width: calc(100vw - 2 * var(--du-bar-inset));
1137
2153
  /* Allow horizontal scroll within the pill when too many controls
1138
2154
  are visible; `shift` middleware clamps the outer position but
1139
2155
  a panel wider than viewport still needs internal overflow. */
@@ -1151,13 +2167,11 @@
1151
2167
  right: 0;
1152
2168
  /* Sit ABOVE the bottom bar (zoom / help) + the home-indicator safe area
1153
2169
  so the two don't overlap. Mirrors the side-panel top offset. */
1154
- bottom: calc(
1155
- var(--du-bar-inset) + var(--du-button-size) + var(--du-gap) + env(safe-area-inset-bottom, 0px)
1156
- );
1157
- z-index: 1500;
2170
+ bottom: calc(var(--du-bar-clear) + env(safe-area-inset-bottom, 0px));
2171
+ z-index: var(--du-z-floating);
1158
2172
  display: flex;
1159
2173
  justify-content: center;
1160
- padding: 0 8px;
2174
+ padding: 0 var(--du-space-md);
1161
2175
  pointer-events: none;
1162
2176
  }
1163
2177
 
@@ -1168,10 +2182,10 @@
1168
2182
  flex-direction: column;
1169
2183
  align-items: stretch;
1170
2184
  width: 100%;
1171
- max-width: 560px;
2185
+ max-width: var(--du-modal-max-w);
1172
2186
  overflow: visible;
1173
- gap: 6px;
1174
- padding: 8px;
2187
+ gap: var(--du-space-sm);
2188
+ padding: var(--du-space-md);
1175
2189
  }
1176
2190
  .du-sel-mobile-row {
1177
2191
  display: flex;
@@ -1202,19 +2216,19 @@
1202
2216
  align-items: center;
1203
2217
  gap: var(--du-gap-sm);
1204
2218
  border-top: 1px solid var(--du-ui-border);
1205
- padding-top: 8px;
2219
+ padding-top: var(--du-space-md);
1206
2220
  }
1207
2221
  /* ≥44px touch targets on the mobile panel (Apple HIG). Standalone icon
1208
2222
  buttons + color triggers grow; grouped segmented buttons stay a touch
1209
2223
  smaller so wide controls (font-size S/M/L/XL) still fit one row. */
1210
2224
  .du-sel-panel-mobile .du-sel-icon-button,
1211
2225
  .du-sel-panel-mobile .du-sel-color-trigger {
1212
- width: 44px;
1213
- height: 44px;
2226
+ width: var(--du-touch-size);
2227
+ height: var(--du-touch-size);
1214
2228
  }
1215
2229
  .du-sel-panel-mobile .du-button-group > .du-icon-button {
1216
- width: 38px;
1217
- height: 38px;
2230
+ width: var(--du-control-size);
2231
+ height: var(--du-control-size);
1218
2232
  }
1219
2233
 
1220
2234
  /* Flat segmented controls inside the floating panel — no group
@@ -1225,7 +2239,7 @@
1225
2239
  border: none;
1226
2240
  box-shadow: none;
1227
2241
  padding: 0;
1228
- gap: 2px;
2242
+ gap: var(--du-space-xs);
1229
2243
  }
1230
2244
 
1231
2245
  .du-sel-panel .du-button-group > .du-icon-button {
@@ -1259,9 +2273,9 @@
1259
2273
 
1260
2274
  .du-sel-color-swatch {
1261
2275
  display: inline-block;
1262
- width: 18px;
1263
- height: 18px;
1264
- border-radius: 4px;
2276
+ width: var(--du-divider-h);
2277
+ height: var(--du-divider-h);
2278
+ border-radius: var(--du-radius-sm);
1265
2279
  border: 1px solid var(--du-ui-border);
1266
2280
  box-sizing: border-box;
1267
2281
  }
@@ -1291,8 +2305,8 @@
1291
2305
  `is-active` class had no visual, so toggles never reflected the
1292
2306
  selection's current style. */
1293
2307
  .du-sel-icon-button.is-active {
1294
- background: var(--du-accent-soft, rgba(80, 130, 255, 0.22));
1295
- color: var(--du-accent, #5082ff);
2308
+ background: var(--du-selected-bg);
2309
+ color: var(--du-selected-fg);
1296
2310
  }
1297
2311
 
1298
2312
  .du-sel-icon-button:focus-visible {
@@ -1307,13 +2321,13 @@
1307
2321
  justify-content: center;
1308
2322
  height: var(--du-button-size-sm);
1309
2323
  min-width: var(--du-button-size-sm);
1310
- padding: 0 8px;
2324
+ padding: 0 var(--du-space-md);
1311
2325
  background: transparent;
1312
2326
  border: none;
1313
2327
  border-radius: var(--du-radius-sm);
1314
2328
  cursor: pointer;
1315
2329
  color: var(--du-text);
1316
- font-size: 12px;
2330
+ font-size: var(--du-font-size-sm);
1317
2331
  font-variant-numeric: tabular-nums;
1318
2332
  }
1319
2333
 
@@ -1327,12 +2341,27 @@
1327
2341
  }
1328
2342
 
1329
2343
  /* Visual divider between inline groups (z-order, actions). */
1330
- .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 {
1331
2359
  display: inline-block;
1332
2360
  width: 1px;
1333
- height: 18px;
2361
+ height: var(--du-divider-h);
2362
+ margin: 0 var(--du-space-xs);
2363
+ content: "";
1334
2364
  background: var(--du-ui-border);
1335
- margin: 0 2px;
1336
2365
  }
1337
2366
 
1338
2367
  /* ------------------------------------------------------------------ */
@@ -1344,26 +2373,26 @@
1344
2373
  border: 1px solid var(--du-ui-border);
1345
2374
  border-radius: var(--du-radius);
1346
2375
  box-shadow: var(--du-ui-shadow);
1347
- padding: var(--du-pad);
1348
- font-size: 12px;
2376
+ padding: var(--du-popover-pad);
2377
+ font-size: var(--du-font-size-sm);
1349
2378
  color: var(--du-text);
1350
- min-width: 120px;
1351
- max-width: 320px;
2379
+ min-width: var(--du-popover-min-w);
2380
+ max-width: var(--du-popover-max-w);
1352
2381
  }
1353
2382
 
1354
2383
  .du-sel-popover-section {
1355
2384
  display: flex;
1356
2385
  flex-direction: column;
1357
- gap: 8px;
2386
+ gap: var(--du-space-md);
1358
2387
  min-width: 0;
1359
2388
  }
1360
2389
 
1361
2390
  .du-sel-popover-label {
1362
2391
  margin: 0;
1363
- font-size: 10px;
1364
- font-weight: 600;
2392
+ font-size: var(--du-font-size-xs);
2393
+ font-weight: var(--du-font-weight-strong);
1365
2394
  text-transform: uppercase;
1366
- letter-spacing: 0.5px;
2395
+ letter-spacing: var(--du-caps-tracking);
1367
2396
  color: var(--du-text-muted);
1368
2397
  }
1369
2398
 
@@ -1372,22 +2401,24 @@
1372
2401
  current value. */
1373
2402
  .du-sel-menu-row {
1374
2403
  all: unset;
1375
- display: block;
2404
+ display: flex;
2405
+ align-items: center;
1376
2406
  width: 100%;
2407
+ min-height: var(--du-menu-row-h);
1377
2408
  box-sizing: border-box;
1378
- padding: 6px 10px;
1379
- border-radius: 4px;
1380
- font-size: 13px;
1381
- color: var(--du-text, #ddd);
2409
+ padding: 0 var(--du-menu-row-pad-x);
2410
+ border-radius: var(--du-menu-row-radius);
2411
+ font-size: var(--du-menu-font);
2412
+ color: var(--du-text);
1382
2413
  cursor: pointer;
1383
2414
  }
1384
2415
 
1385
2416
  .du-sel-menu-row:hover {
1386
- background: var(--du-ui-hover, #2a2a2a);
2417
+ background: var(--du-hover-overlay);
1387
2418
  }
1388
2419
 
1389
2420
  .du-sel-menu-row.is-active {
1390
- background: var(--du-accent-soft, rgba(80, 130, 255, 0.2));
2421
+ background: var(--du-selected-bg);
1391
2422
  }
1392
2423
 
1393
2424
  /* URL field inside the element-link popover. */
@@ -1395,50 +2426,249 @@
1395
2426
  width: 220px;
1396
2427
  max-width: 60vw;
1397
2428
  box-sizing: border-box;
1398
- padding: 6px 8px;
1399
- font-size: 13px;
1400
- color: var(--du-text, #ddd);
1401
- background: var(--du-ui-bg, #1a1a1a);
1402
- border: 1px solid var(--du-ui-border, #333);
1403
- border-radius: 4px;
2429
+ padding: var(--du-space-sm) var(--du-space-md);
2430
+ font-size: var(--du-font-size);
2431
+ color: var(--du-text);
2432
+ background: var(--du-ui-bg);
2433
+ border: 1px solid var(--du-ui-border);
2434
+ border-radius: var(--du-radius-sm);
1404
2435
  outline: none;
1405
2436
  }
1406
2437
 
1407
2438
  .du-sel-link-input:focus-visible {
1408
- outline: 2px solid var(--du-accent, #5082ff);
2439
+ outline: 2px solid var(--du-accent);
1409
2440
  outline-offset: -1px;
1410
2441
  }
1411
2442
 
1412
2443
  /* Hover link popup (chip above a linked element). */
1413
2444
  .du-link-popup {
1414
- z-index: 1400;
1415
- 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;
1416
2560
  pointer-events: auto;
1417
2561
  }
1418
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;
2645
+ pointer-events: auto;
2646
+ }
2647
+
2648
+ .du-link-badge:hover {
2649
+ color: var(--du-accent-strong, var(--du-accent));
2650
+ border-color: var(--du-accent);
2651
+ }
2652
+
1419
2653
  .du-link-popup-url {
1420
2654
  display: inline-flex;
1421
2655
  align-items: center;
1422
- gap: 6px;
2656
+ gap: var(--du-space-sm);
1423
2657
  max-width: 280px;
1424
- padding: 4px 8px;
1425
- font:
1426
- 12px system-ui,
1427
- -apple-system,
1428
- Segoe UI,
1429
- Roboto,
1430
- sans-serif;
1431
- color: var(--du-accent, #5082ff);
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);
2661
+ color: var(--du-accent);
1432
2662
  text-decoration: none;
1433
- background: var(--menu-bg, #1a1a1a);
1434
- border: 1px solid var(--menu-border, #333);
1435
- border-radius: 6px;
1436
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
2663
+ background: var(--menu-bg);
2664
+ border: 1px solid var(--menu-border);
2665
+ border-radius: var(--du-radius);
2666
+ box-shadow: var(--du-ui-shadow);
1437
2667
  cursor: pointer;
1438
2668
  }
1439
2669
 
1440
2670
  .du-link-popup-url:hover {
1441
- background: var(--du-ui-hover, #2a2a2a);
2671
+ background: var(--du-hover-overlay);
1442
2672
  }
1443
2673
 
1444
2674
  .du-link-popup-text {
@@ -1452,67 +2682,66 @@
1452
2682
  .du-arrowhead-grid {
1453
2683
  display: grid;
1454
2684
  grid-template-columns: repeat(4, 1fr);
1455
- gap: 2px;
1456
- margin-top: 4px;
2685
+ gap: var(--du-space-xs);
2686
+ margin-top: var(--du-space-sm);
1457
2687
  }
1458
2688
  .du-arrowhead-option {
1459
2689
  display: inline-flex;
1460
2690
  align-items: center;
1461
2691
  justify-content: center;
1462
- min-width: 30px;
1463
- height: 26px;
1464
- padding: 2px;
2692
+ min-width: var(--du-swatch-size);
2693
+ height: var(--du-swatch-size);
2694
+ padding: var(--du-space-xs);
1465
2695
  border: 1px solid transparent;
1466
- border-radius: 6px;
2696
+ border-radius: var(--du-radius-sm);
1467
2697
  background: transparent;
1468
2698
  cursor: pointer;
1469
- color: var(--du-fg, #1c1c1e);
2699
+ color: var(--du-text);
1470
2700
  }
1471
2701
  .du-arrowhead-option:hover {
1472
- background: var(--du-hover, #f0f0f3);
2702
+ background: var(--du-hover-overlay);
1473
2703
  }
1474
2704
  .du-arrowhead-option--active {
1475
- border-color: var(--du-accent, #5082ff);
2705
+ border-color: var(--du-accent);
1476
2706
  }
1477
2707
  .du-arrowhead-none {
1478
- font-size: 13px;
2708
+ font-size: var(--du-font-size);
1479
2709
  opacity: 0.6;
1480
2710
  }
1481
2711
  .du-arrowhead-erd-label {
1482
- font-size: 9px;
2712
+ font-size: var(--du-font-size-xs);
1483
2713
  line-height: 1.05;
1484
2714
  text-align: center;
1485
2715
  }
1486
2716
  .du-arrowhead-erd-toggle {
1487
- margin-top: 6px;
2717
+ margin-top: var(--du-space-sm);
1488
2718
  width: 100%;
1489
2719
  text-align: left;
1490
2720
  border: none;
1491
2721
  background: transparent;
1492
2722
  cursor: pointer;
1493
- font-size: 11px;
1494
- color: var(--du-muted, #6b6b70);
1495
- padding: 2px 0;
2723
+ font-size: var(--du-font-size-sm);
2724
+ color: var(--du-text-muted);
2725
+ padding: var(--du-space-xs) 0;
1496
2726
  }
1497
2727
  .du-arrowhead-erd-toggle:hover {
1498
- color: var(--du-fg, #1c1c1e);
2728
+ color: var(--du-text);
1499
2729
  }
1500
2730
 
1501
2731
  /* Inline link caption editor (multiline textarea). */
1502
2732
  .du-link-caption-input {
1503
2733
  min-width: 60px;
1504
2734
  max-width: 220px;
1505
- padding: 2px 6px;
1506
- font:
1507
- 12px system-ui,
1508
- 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);
1509
2738
  line-height: 1.25;
1510
2739
  text-align: center;
1511
- color: var(--du-fg, #222);
1512
- background: var(--du-panel-bg, #fff);
1513
- border: 1px solid var(--du-accent, #5082ff);
1514
- border-radius: 4px;
1515
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
2740
+ color: var(--du-text);
2741
+ background: var(--du-ui-bg-solid);
2742
+ border: 1px solid var(--du-accent);
2743
+ border-radius: var(--du-radius-sm);
2744
+ box-shadow: var(--du-ui-shadow);
1516
2745
  outline: none;
1517
2746
  resize: none;
1518
2747
  overflow: hidden;
@@ -1521,28 +2750,28 @@
1521
2750
  /* Mini shape-picker shown after a link is dropped on empty canvas. */
1522
2751
  .du-link-drop-menu {
1523
2752
  display: flex;
1524
- gap: 2px;
1525
- padding: 4px;
1526
- background: var(--du-panel-bg, #fff);
1527
- border: 1px solid var(--du-border, #e3e3e6);
1528
- border-radius: 8px;
1529
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
2753
+ gap: var(--du-space-xs);
2754
+ padding: var(--du-space-sm);
2755
+ background: var(--du-ui-bg-solid);
2756
+ border: 1px solid var(--du-ui-border);
2757
+ border-radius: var(--du-radius);
2758
+ box-shadow: var(--du-ui-shadow);
1530
2759
  }
1531
2760
  .du-link-drop-item {
1532
2761
  display: inline-flex;
1533
2762
  align-items: center;
1534
2763
  justify-content: center;
1535
- width: 30px;
1536
- height: 30px;
1537
- padding: 4px;
2764
+ width: var(--du-button-size-sm);
2765
+ height: var(--du-button-size-sm);
2766
+ padding: var(--du-space-sm);
1538
2767
  border: none;
1539
- border-radius: 6px;
2768
+ border-radius: var(--du-radius-sm);
1540
2769
  background: transparent;
1541
2770
  cursor: pointer;
1542
- color: var(--du-fg, #1c1c1e);
2771
+ color: var(--du-text);
1543
2772
  }
1544
2773
  .du-link-drop-item:hover {
1545
- background: var(--du-hover, #f0f0f3);
2774
+ background: var(--du-hover-overlay);
1546
2775
  }
1547
2776
  .du-link-drop-item svg {
1548
2777
  width: 100%;
@@ -1550,6 +2779,112 @@
1550
2779
  }
1551
2780
 
1552
2781
  .du-sel-menu-row:focus-visible {
1553
- outline: 2px solid var(--du-accent, #5082ff);
2782
+ outline: 2px solid var(--du-accent);
1554
2783
  outline-offset: -2px;
1555
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
+ .du-sel-mask-list {
2796
+ display: flex;
2797
+ flex-direction: column;
2798
+ margin-bottom: var(--du-space-sm);
2799
+ }
2800
+
2801
+ .du-sel-mask-row {
2802
+ display: flex;
2803
+ gap: var(--du-menu-gap);
2804
+ align-items: center;
2805
+ width: 100%;
2806
+ min-height: var(--du-menu-row-h);
2807
+ padding: 0 var(--du-menu-row-pad-x);
2808
+ font-size: var(--du-menu-font);
2809
+ color: var(--du-text);
2810
+ text-align: left;
2811
+ background: transparent;
2812
+ border: 0;
2813
+ border-radius: var(--du-menu-row-radius);
2814
+ cursor: pointer;
2815
+ }
2816
+
2817
+ .du-sel-mask-row:hover {
2818
+ background: var(--du-hover-overlay);
2819
+ }
2820
+
2821
+ .du-sel-mask-row.is-active {
2822
+ background: var(--du-selected-bg);
2823
+ }
2824
+
2825
+ .du-sel-mask-ratio {
2826
+ margin-left: auto;
2827
+ font-size: var(--du-menu-shortcut-font);
2828
+ color: var(--du-text-muted);
2829
+ }
2830
+
2831
+ /* "Shapes and lines" flyout beside the vertical toolbar. */
2832
+ .du-shapes-flyout {
2833
+ position: absolute;
2834
+ top: 0;
2835
+ /* The wrap sits inside the dock: clear its inset + border, then the gap. */
2836
+ left: calc(100% + var(--du-pad-sm) + 1px + var(--du-flyout-gap));
2837
+ z-index: var(--du-z-ui);
2838
+ display: flex;
2839
+ flex-direction: column;
2840
+ box-sizing: border-box;
2841
+ min-width: var(--du-menu-min-w);
2842
+ padding: var(--du-menu-pad);
2843
+ background: var(--menu-bg);
2844
+ border: 1px solid var(--menu-border);
2845
+ border-radius: var(--du-menu-radius);
2846
+ box-shadow: var(--du-ui-shadow);
2847
+ }
2848
+
2849
+ /* Rows use the shared menu metrics (see `.du-menu-row`). */
2850
+ .du-shapes-flyout-row {
2851
+ display: flex;
2852
+ gap: var(--du-menu-gap);
2853
+ align-items: center;
2854
+ width: 100%;
2855
+ min-height: var(--du-menu-row-h);
2856
+ padding: 0 var(--du-menu-row-pad-x);
2857
+ font-size: var(--du-menu-font);
2858
+ color: var(--du-text);
2859
+ text-align: left;
2860
+ background: transparent;
2861
+ border: 0;
2862
+ border-radius: var(--du-menu-row-radius);
2863
+ cursor: pointer;
2864
+ }
2865
+
2866
+ .du-shapes-flyout-row:hover {
2867
+ background: var(--du-hover-overlay);
2868
+ }
2869
+
2870
+ /* The armed tool (shape kind / line preset) — tonal selected, like menus. */
2871
+ .du-shapes-flyout-row.is-active {
2872
+ background: var(--du-selected-bg);
2873
+ color: var(--du-selected-fg);
2874
+ }
2875
+
2876
+ .du-shapes-flyout-row.is-active .du-shapes-flyout-hotkey {
2877
+ color: inherit;
2878
+ }
2879
+
2880
+ .du-shapes-flyout-hotkey {
2881
+ margin-left: auto;
2882
+ font-size: var(--du-menu-shortcut-font);
2883
+ color: var(--du-text-muted);
2884
+ }
2885
+
2886
+ .du-shapes-flyout-divider {
2887
+ margin: var(--du-menu-sep) 0;
2888
+ border: none;
2889
+ border-top: 1px solid var(--du-ui-border);
2890
+ }