@weasel-js/ui 1.8.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/dist/chunks/{ActionBar-xA73vzzF.js → ActionBar-CfXS7-9f.js} +2 -2
  2. package/dist/chunks/{ActionBar-xA73vzzF.js.map → ActionBar-CfXS7-9f.js.map} +1 -1
  3. package/dist/chunks/{Badge-jYQjrTKc.js → Badge-4ShpqA0h.js} +2 -2
  4. package/dist/chunks/{Badge-jYQjrTKc.js.map → Badge-4ShpqA0h.js.map} +1 -1
  5. package/dist/chunks/{Badge-CTc9Lkwn.js → Badge-qkV9EqKs.js} +6 -2
  6. package/dist/chunks/Badge-qkV9EqKs.js.map +1 -0
  7. package/dist/chunks/{Button-XB-T75YL.js → Button-CQA-K1g9.js} +17 -17
  8. package/dist/chunks/Button-CQA-K1g9.js.map +1 -0
  9. package/dist/chunks/Button-KF-qSGtA.js +11 -0
  10. package/dist/chunks/Button-KF-qSGtA.js.map +1 -0
  11. package/dist/chunks/{ButtonBar-CIMKPPRS.js → ButtonBar-B-cYuoem.js} +10 -4
  12. package/dist/chunks/ButtonBar-B-cYuoem.js.map +1 -0
  13. package/dist/chunks/{Callout-DpTO3fkb.js → Callout-VyYDIP7w.js} +18 -18
  14. package/dist/chunks/Callout-VyYDIP7w.js.map +1 -0
  15. package/dist/chunks/{CloseButton-wb7Or5Eg.js → CloseButton-CKarkTT9.js} +3 -3
  16. package/dist/chunks/{CloseButton-wb7Or5Eg.js.map → CloseButton-CKarkTT9.js.map} +1 -1
  17. package/dist/chunks/{Code-AsKpgnv6.js → Code-ChwKP1V0.js} +8 -2
  18. package/dist/chunks/Code-ChwKP1V0.js.map +1 -0
  19. package/dist/chunks/{ColorModeControl-DET6Itwq.js → ColorModeControl-CH9PmDlT.js} +6 -6
  20. package/dist/chunks/{ColorModeControl-DET6Itwq.js.map → ColorModeControl-CH9PmDlT.js.map} +1 -1
  21. package/dist/chunks/{ComboBox-DKln_mOd.js → ComboBox-BMj_IKBj.js} +4 -4
  22. package/dist/chunks/ComboBox-BMj_IKBj.js.map +1 -0
  23. package/dist/chunks/{DataGrid-B6IS9vUk.js → DataGrid-CjiVKoaA.js} +2 -2
  24. package/dist/chunks/{DataGrid-B6IS9vUk.js.map → DataGrid-CjiVKoaA.js.map} +1 -1
  25. package/dist/chunks/{Dialog-h-5MeYpu.js → Dialog-Du4POZ52.js} +5 -5
  26. package/dist/chunks/Dialog-Du4POZ52.js.map +1 -0
  27. package/dist/chunks/{DragGhost-BeYDJyLZ.js → DragGhost-_IpuN_xM.js} +2 -2
  28. package/dist/chunks/{DragGhost-BeYDJyLZ.js.map → DragGhost-_IpuN_xM.js.map} +1 -1
  29. package/dist/chunks/{FallthroughDiagram-CS1IhQaU.js → FallthroughDiagram-Cn6QLWKA.js} +9 -9
  30. package/dist/chunks/{FallthroughDiagram-CS1IhQaU.js.map → FallthroughDiagram-Cn6QLWKA.js.map} +1 -1
  31. package/dist/chunks/{FillStrokeSwatch-C4h3rUFM.js → FillStrokeSwatch-BkUhlpQL.js} +2 -2
  32. package/dist/chunks/{FillStrokeSwatch-C4h3rUFM.js.map → FillStrokeSwatch-BkUhlpQL.js.map} +1 -1
  33. package/dist/chunks/{FontFamilySelect-DEvMXyZd.js → FontFamilySelect-CXN7O2-p.js} +2 -2
  34. package/dist/chunks/{FontFamilySelect-DEvMXyZd.js.map → FontFamilySelect-CXN7O2-p.js.map} +1 -1
  35. package/dist/chunks/{FontWeightSelect-BLQ_LMJF.js → FontWeightSelect-BBuJGe_2.js} +2 -2
  36. package/dist/chunks/{FontWeightSelect-BLQ_LMJF.js.map → FontWeightSelect-BBuJGe_2.js.map} +1 -1
  37. package/dist/chunks/{GestureRoute-BXESrHI0.js → GestureRoute-BqHUrGeQ.js} +13 -13
  38. package/dist/chunks/{GestureRoute-BXESrHI0.js.map → GestureRoute-BqHUrGeQ.js.map} +1 -1
  39. package/dist/chunks/{GradientEditor-vz771M-N.js → GradientEditor-DX4sb1Hf.js} +3 -3
  40. package/dist/chunks/{GradientEditor-vz771M-N.js.map → GradientEditor-DX4sb1Hf.js.map} +1 -1
  41. package/dist/chunks/{Icon-DPRUIo3G.js → Icon-BfqYtAX5.js} +30 -1
  42. package/dist/chunks/Icon-BfqYtAX5.js.map +1 -0
  43. package/dist/chunks/{ItemList-CRu9y7hL.js → ItemList-nbakLf3N.js} +32 -32
  44. package/dist/chunks/ItemList-nbakLf3N.js.map +1 -0
  45. package/dist/chunks/{Jog-TE6QI9i1.js → Jog-BU0xuM3G.js} +6 -6
  46. package/dist/chunks/{Jog-TE6QI9i1.js.map → Jog-BU0xuM3G.js.map} +1 -1
  47. package/dist/chunks/{Keycaps-C-FJyG8k.js → Keycaps-CM-gOj0e.js} +8 -2
  48. package/dist/chunks/Keycaps-CM-gOj0e.js.map +1 -0
  49. package/dist/chunks/LayerList-vfAoImxX.js +432 -0
  50. package/dist/chunks/LayerList-vfAoImxX.js.map +1 -0
  51. package/dist/chunks/{ListEditor-DGtwj99m.js → ListEditor-BAKs47bN.js} +3 -3
  52. package/dist/chunks/{ListEditor-DGtwj99m.js.map → ListEditor-BAKs47bN.js.map} +1 -1
  53. package/dist/chunks/{MenuButton-TAFg88Lp.js → MenuButton-CJGdhwGr.js} +5 -5
  54. package/dist/chunks/MenuButton-CJGdhwGr.js.map +1 -0
  55. package/dist/chunks/{MeshEditor-8CRsu-Td.js → MeshEditor-rhf7cXfG.js} +2 -2
  56. package/dist/chunks/{MeshEditor-8CRsu-Td.js.map → MeshEditor-rhf7cXfG.js.map} +1 -1
  57. package/dist/chunks/{OptionsBar-DeTAjVb7.js → OptionsBar-DyTXbev-.js} +9 -3
  58. package/dist/chunks/OptionsBar-DyTXbev-.js.map +1 -0
  59. package/dist/chunks/{PaintField-DX4uYlF9.js → PaintField--GbF8sL7.js} +7 -7
  60. package/dist/chunks/PaintField--GbF8sL7.js.map +1 -0
  61. package/dist/chunks/{PaintInput-CWyOJXUM.js → PaintInput-DSS5IjXn.js} +5 -5
  62. package/dist/chunks/{PaintInput-CWyOJXUM.js.map → PaintInput-DSS5IjXn.js.map} +1 -1
  63. package/dist/chunks/{PatternPicker-0j51aDJ3.js → PatternPicker-82DCUvUk.js} +2 -2
  64. package/dist/chunks/{PatternPicker-0j51aDJ3.js.map → PatternPicker-82DCUvUk.js.map} +1 -1
  65. package/dist/chunks/{Powerline-6wIFmDik.js → Powerline-CogJv9VU.js} +2 -2
  66. package/dist/chunks/{Powerline-6wIFmDik.js.map → Powerline-CogJv9VU.js.map} +1 -1
  67. package/dist/chunks/{Prefs-gbjYqvSD.js → Prefs-BSSKOvPa.js} +41 -41
  68. package/dist/chunks/Prefs-BSSKOvPa.js.map +1 -0
  69. package/dist/chunks/{Properties-BbNuMiic.js → Properties-DteSVEWs.js} +4 -4
  70. package/dist/chunks/{Properties-BbNuMiic.js.map → Properties-DteSVEWs.js.map} +1 -1
  71. package/dist/chunks/{PropertyField-CWUtNK1w.js → PropertyField-CLbUOynA.js} +67 -67
  72. package/dist/chunks/PropertyField-CLbUOynA.js.map +1 -0
  73. package/dist/chunks/{Select-ouV8O6cp.js → Select-BhHwjNsb.js} +13 -13
  74. package/dist/chunks/Select-BhHwjNsb.js.map +1 -0
  75. package/dist/chunks/{SelectionPanel-BpUqP75b.js → SelectionPanel-B6HinSdB.js} +2 -2
  76. package/dist/chunks/{SelectionPanel-BpUqP75b.js.map → SelectionPanel-B6HinSdB.js.map} +1 -1
  77. package/dist/chunks/{SidebarPanel--dJ-k9-V.js → SidebarPanel-P3a8tIIj.js} +2 -2
  78. package/dist/chunks/{SidebarPanel--dJ-k9-V.js.map → SidebarPanel-P3a8tIIj.js.map} +1 -1
  79. package/dist/chunks/{StatusBar-BEOfOX0D.js → StatusBar-DEh7J2Gj.js} +14 -9
  80. package/dist/chunks/StatusBar-DEh7J2Gj.js.map +1 -0
  81. package/dist/chunks/{SwatchStrip-BY6A511W.js → SwatchStrip-D7YNn_p0.js} +2 -2
  82. package/dist/chunks/{SwatchStrip-BY6A511W.js.map → SwatchStrip-D7YNn_p0.js.map} +1 -1
  83. package/dist/chunks/{ThemeSwitcher-tnATkIo1.js → ThemeSwitcher-BJWP1l87.js} +6 -6
  84. package/dist/chunks/{ThemeSwitcher-tnATkIo1.js.map → ThemeSwitcher-BJWP1l87.js.map} +1 -1
  85. package/dist/chunks/{Timeline-FlLUm8nd.js → Timeline-CisRg82u.js} +2 -2
  86. package/dist/chunks/{Timeline-FlLUm8nd.js.map → Timeline-CisRg82u.js.map} +1 -1
  87. package/dist/chunks/{Toast-CuHkT0x0.js → Toast-DhkU9Z0b.js} +3 -3
  88. package/dist/chunks/{Toast-CuHkT0x0.js.map → Toast-DhkU9Z0b.js.map} +1 -1
  89. package/dist/chunks/ToggleBar-CRc2k89_.js +10 -0
  90. package/dist/chunks/ToggleBar-CRc2k89_.js.map +1 -0
  91. package/dist/chunks/{ToggleBar-BZ4Gk1IU.js → ToggleBar-CfYbMK3x.js} +9 -9
  92. package/dist/chunks/ToggleBar-CfYbMK3x.js.map +1 -0
  93. package/dist/chunks/{TokenPanel-DongdiZM.js → TokenPanel-cL37E39j.js} +5 -5
  94. package/dist/chunks/{TokenPanel-DongdiZM.js.map → TokenPanel-cL37E39j.js.map} +1 -1
  95. package/dist/chunks/{ToolButton-BURp4YIO.js → ToolButton-Bo7WH1wt.js} +2 -2
  96. package/dist/chunks/{ToolButton-BURp4YIO.js.map → ToolButton-Bo7WH1wt.js.map} +1 -1
  97. package/dist/chunks/{ToolOptionsBar-wTPJFfOn.js → ToolOptionsBar-DmhzrOmd.js} +2 -2
  98. package/dist/chunks/{ToolOptionsBar-wTPJFfOn.js.map → ToolOptionsBar-DmhzrOmd.js.map} +1 -1
  99. package/dist/chunks/{ToolPalette-DKDFWOX-.js → ToolPalette-BTD84k9C.js} +2 -2
  100. package/dist/chunks/{ToolPalette-DKDFWOX-.js.map → ToolPalette-BTD84k9C.js.map} +1 -1
  101. package/dist/chunks/{Tooltip-C6eFCYxw.js → Tooltip-DljsPEQG.js} +4 -4
  102. package/dist/chunks/Tooltip-DljsPEQG.js.map +1 -0
  103. package/dist/chunks/Tree-B_PW6K-W.js +215 -0
  104. package/dist/chunks/Tree-B_PW6K-W.js.map +1 -0
  105. package/dist/chunks/{icons-CofIOTiI.js → icons-B_fPKEis.js} +52 -43
  106. package/dist/chunks/icons-B_fPKEis.js.map +1 -0
  107. package/dist/chunks/{model-qQj8Ny9w.js → model-Ca0f95r0.js} +5 -5
  108. package/dist/chunks/{model-qQj8Ny9w.js.map → model-Ca0f95r0.js.map} +1 -1
  109. package/dist/chunks/{portalHost-CE70wLzo.js → portalHost-RUQPxIoW.js} +3 -2
  110. package/dist/chunks/{portalHost-CE70wLzo.js.map → portalHost-RUQPxIoW.js.map} +1 -1
  111. package/dist/chunks/{prefField-CCm_nzlM.js → prefField-DPPbAmRR.js} +3 -3
  112. package/dist/chunks/{prefField-CCm_nzlM.js.map → prefField-DPPbAmRR.js.map} +1 -1
  113. package/dist/chunks/{segmentTooltip-CGxCOWNz.js → segmentTooltip-8VBPNgEc.js} +2 -2
  114. package/dist/chunks/{segmentTooltip-CGxCOWNz.js.map → segmentTooltip-8VBPNgEc.js.map} +1 -1
  115. package/dist/chunks/segmentedControl.module-62qjNWJk.js +11 -0
  116. package/dist/chunks/{segmentedControl.module-BzGXUL5G.js.map → segmentedControl.module-62qjNWJk.js.map} +1 -1
  117. package/dist/chunks/{useReorderDragList-CStYKjHl.js → useReorderDragList-DnqqvRGK.js} +38 -30
  118. package/dist/chunks/useReorderDragList-DnqqvRGK.js.map +1 -0
  119. package/dist/components/ActionBar/index.js +1 -1
  120. package/dist/components/Badge/index.d.ts +1 -0
  121. package/dist/components/Badge/index.d.ts.map +1 -1
  122. package/dist/components/Badge/index.js +3 -3
  123. package/dist/components/Badge/variantIcons.d.ts +5 -0
  124. package/dist/components/Badge/variantIcons.d.ts.map +1 -0
  125. package/dist/components/Button/index.d.ts +1 -0
  126. package/dist/components/Button/index.d.ts.map +1 -1
  127. package/dist/components/Button/index.js +3 -2
  128. package/dist/components/Button/variantIcons.d.ts +5 -0
  129. package/dist/components/Button/variantIcons.d.ts.map +1 -0
  130. package/dist/components/ButtonBar/index.d.ts +1 -0
  131. package/dist/components/ButtonBar/index.d.ts.map +1 -1
  132. package/dist/components/ButtonBar/index.js +2 -2
  133. package/dist/components/ButtonBar/variantIcons.d.ts +5 -0
  134. package/dist/components/ButtonBar/variantIcons.d.ts.map +1 -0
  135. package/dist/components/Callout/Callout.d.ts.map +1 -1
  136. package/dist/components/Callout/index.js +1 -1
  137. package/dist/components/CloseButton/index.js +1 -1
  138. package/dist/components/Code/index.d.ts +1 -0
  139. package/dist/components/Code/index.d.ts.map +1 -1
  140. package/dist/components/Code/index.js +2 -2
  141. package/dist/components/Code/variantIcons.d.ts +5 -0
  142. package/dist/components/Code/variantIcons.d.ts.map +1 -0
  143. package/dist/components/ColorModeControl/index.js +1 -1
  144. package/dist/components/ComboBox/ComboBox.d.ts.map +1 -1
  145. package/dist/components/ComboBox/index.js +1 -1
  146. package/dist/components/DataGrid/index.js +1 -1
  147. package/dist/components/Dialog/Dialog.d.ts.map +1 -1
  148. package/dist/components/Dialog/index.js +1 -1
  149. package/dist/components/DragGhost/index.js +1 -1
  150. package/dist/components/FallthroughDiagram/index.js +1 -1
  151. package/dist/components/FillStrokeSwatch/index.js +1 -1
  152. package/dist/components/FontFamilySelect/index.js +1 -1
  153. package/dist/components/FontWeightSelect/index.js +1 -1
  154. package/dist/components/GestureRoute/index.js +1 -1
  155. package/dist/components/GradientEditor/index.js +1 -1
  156. package/dist/components/ItemList/index.js +1 -1
  157. package/dist/components/Jog/index.js +1 -1
  158. package/dist/components/Keycaps/index.d.ts +1 -0
  159. package/dist/components/Keycaps/index.d.ts.map +1 -1
  160. package/dist/components/Keycaps/index.js +2 -2
  161. package/dist/components/Keycaps/variantIcons.d.ts +5 -0
  162. package/dist/components/Keycaps/variantIcons.d.ts.map +1 -0
  163. package/dist/components/LayerList/LayerList.d.ts.map +1 -1
  164. package/dist/components/LayerList/index.js +1 -1
  165. package/dist/components/ListEditor/index.js +1 -1
  166. package/dist/components/MenuButton/MenuButton.d.ts.map +1 -1
  167. package/dist/components/MenuButton/index.js +1 -1
  168. package/dist/components/MeshEditor/index.js +1 -1
  169. package/dist/components/OptionsBar/index.d.ts +1 -0
  170. package/dist/components/OptionsBar/index.d.ts.map +1 -1
  171. package/dist/components/OptionsBar/index.js +2 -2
  172. package/dist/components/OptionsBar/variantIcons.d.ts +5 -0
  173. package/dist/components/OptionsBar/variantIcons.d.ts.map +1 -0
  174. package/dist/components/PaintField/PaintField.d.ts.map +1 -1
  175. package/dist/components/PaintField/index.js +1 -1
  176. package/dist/components/PaintInput/index.js +1 -1
  177. package/dist/components/PatternPicker/index.js +1 -1
  178. package/dist/components/Powerline/index.js +2 -2
  179. package/dist/components/Prefs/index.js +2 -2
  180. package/dist/components/Properties/index.js +2 -2
  181. package/dist/components/Select/Select.d.ts.map +1 -1
  182. package/dist/components/Select/index.js +1 -1
  183. package/dist/components/SelectionPanel/index.js +2 -2
  184. package/dist/components/SidebarPanel/index.js +1 -1
  185. package/dist/components/StatusBar/StatusBar.d.ts +2 -0
  186. package/dist/components/StatusBar/StatusBar.d.ts.map +1 -1
  187. package/dist/components/StatusBar/index.js +1 -1
  188. package/dist/components/SwatchStrip/index.js +1 -1
  189. package/dist/components/ThemeSwitcher/index.js +1 -1
  190. package/dist/components/Timeline/index.js +1 -1
  191. package/dist/components/Toast/index.js +1 -1
  192. package/dist/components/ToggleBar/index.d.ts +1 -0
  193. package/dist/components/ToggleBar/index.d.ts.map +1 -1
  194. package/dist/components/ToggleBar/index.js +3 -2
  195. package/dist/components/ToggleBar/variantIcons.d.ts +5 -0
  196. package/dist/components/ToggleBar/variantIcons.d.ts.map +1 -0
  197. package/dist/components/TokenPanel/index.js +1 -1
  198. package/dist/components/ToolButton/index.js +1 -1
  199. package/dist/components/ToolOptionsBar/index.js +1 -1
  200. package/dist/components/ToolPalette/index.js +1 -1
  201. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
  202. package/dist/components/Tooltip/index.js +1 -1
  203. package/dist/components/Tree/Tree.d.ts +1 -1
  204. package/dist/components/Tree/Tree.d.ts.map +1 -1
  205. package/dist/components/Tree/index.js +1 -1
  206. package/dist/icons/index.d.ts +6 -0
  207. package/dist/icons/index.d.ts.map +1 -1
  208. package/dist/icons/paths.d.ts +12 -0
  209. package/dist/icons/paths.d.ts.map +1 -1
  210. package/dist/index.js +100 -98
  211. package/dist/index.js.map +1 -1
  212. package/dist/overlays/portalHost.d.ts +10 -4
  213. package/dist/overlays/portalHost.d.ts.map +1 -1
  214. package/dist/style.css +1 -1
  215. package/dist/useReorderDragList.d.ts +3 -0
  216. package/dist/useReorderDragList.d.ts.map +1 -1
  217. package/package.json +10 -9
  218. package/dist/chunks/Badge-CTc9Lkwn.js.map +0 -1
  219. package/dist/chunks/Button-XB-T75YL.js.map +0 -1
  220. package/dist/chunks/ButtonBar-CIMKPPRS.js.map +0 -1
  221. package/dist/chunks/Callout-DpTO3fkb.js.map +0 -1
  222. package/dist/chunks/Code-AsKpgnv6.js.map +0 -1
  223. package/dist/chunks/ComboBox-DKln_mOd.js.map +0 -1
  224. package/dist/chunks/Dialog-h-5MeYpu.js.map +0 -1
  225. package/dist/chunks/Icon-DPRUIo3G.js.map +0 -1
  226. package/dist/chunks/ItemList-CRu9y7hL.js.map +0 -1
  227. package/dist/chunks/Keycaps-C-FJyG8k.js.map +0 -1
  228. package/dist/chunks/LayerList-BXTAjK-4.js +0 -421
  229. package/dist/chunks/LayerList-BXTAjK-4.js.map +0 -1
  230. package/dist/chunks/MenuButton-TAFg88Lp.js.map +0 -1
  231. package/dist/chunks/OptionsBar-DeTAjVb7.js.map +0 -1
  232. package/dist/chunks/PaintField-DX4uYlF9.js.map +0 -1
  233. package/dist/chunks/Prefs-gbjYqvSD.js.map +0 -1
  234. package/dist/chunks/PropertyField-CWUtNK1w.js.map +0 -1
  235. package/dist/chunks/Select-ouV8O6cp.js.map +0 -1
  236. package/dist/chunks/StatusBar-BEOfOX0D.js.map +0 -1
  237. package/dist/chunks/ToggleBar-BZ4Gk1IU.js.map +0 -1
  238. package/dist/chunks/Tooltip-C6eFCYxw.js.map +0 -1
  239. package/dist/chunks/Tree-hzIbj2q1.js +0 -203
  240. package/dist/chunks/Tree-hzIbj2q1.js.map +0 -1
  241. package/dist/chunks/icons-CofIOTiI.js.map +0 -1
  242. package/dist/chunks/interactiveTarget-BNZmTow2.js +0 -24
  243. package/dist/chunks/interactiveTarget-BNZmTow2.js.map +0 -1
  244. package/dist/chunks/segmentedControl.module-BzGXUL5G.js +0 -11
  245. package/dist/chunks/useReorderDragList-CStYKjHl.js.map +0 -1
  246. package/dist/interactiveTarget.d.ts +0 -9
  247. package/dist/interactiveTarget.d.ts.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"MenuButton-TAFg88Lp.js","names":["RACButton","f","s","RACPopover","RACMenu","listbox","RACMenuItem","useOverlayPortal","TriggerTooltip","segmentTooltipContent","field_module_default","listbox_module_default","MenuButton_module_default","MenuButton","ariaLabel","portalContainer","MenuTrigger","anchor","isDisabled","Button","className","label","Popover","portalProps","Menu","onAction","key","items","MenuItem","item"],"sources":["../../src/components/MenuButton/MenuButton.module.css","../../src/components/MenuButton/MenuButton.tsx"],"sourcesContent":[".trigger {\n display: inline-flex;\n flex: none;\n align-items: center;\n gap: var(--wzl-space-3);\n padding: 0 var(--wzl-space-3) 0 var(--wzl-space-5);\n white-space: nowrap;\n cursor: pointer;\n}\n\n.label {\n color: var(--wzl-fg-subtle);\n}\n\n.chevron {\n width: 10px;\n height: 10px;\n color: var(--wzl-fg-muted);\n flex: 0 0 auto;\n}\n\n.popover {\n min-width: var(--trigger-width);\n max-height: inherit;\n outline: none;\n}\n\n.item {\n display: flex;\n align-items: center;\n padding: var(--wzl-space-2) var(--wzl-space-4);\n border-radius: var(--wzl-radius-sm);\n cursor: pointer;\n color: var(--wzl-fg);\n white-space: nowrap;\n outline: none;\n}\n\n.item[data-focused] {\n background: var(--wzl-surface-hover);\n}\n\n.item[data-disabled] {\n opacity: 0.4;\n cursor: not-allowed;\n}\n","import type { ReactNode } from 'react';\nimport {\n Button as RACButton,\n Menu as RACMenu,\n MenuItem as RACMenuItem,\n MenuTrigger,\n Popover as RACPopover,\n} from 'react-aria-components';\nimport { useOverlayPortal, type OverlayPortalProps } from '../../overlays/portalHost';\nimport f from '../field.module.css';\nimport listbox from '../listbox.module.css';\nimport s from './MenuButton.module.css';\nimport { TriggerTooltip, segmentTooltipContent, type SegmentTooltipFields } from '../segmentTooltip';\n\n/** One row in a {@link MenuButton}'s list. */\nexport type MenuButtonItem<T extends string = string> = {\n value: T;\n label: ReactNode;\n isDisabled?: boolean;\n /** Plain-text form of `label`, for type-to-select and screen readers. A\n * string label supplies this itself. */\n textValue?: string;\n};\n\n/** Props for {@link MenuButton}. */\nexport type MenuButtonProps<T extends string = string> = {\n /** What the button says. It never changes to show a chosen row. */\n label: ReactNode;\n items: ReadonlyArray<MenuButtonItem<T>>;\n /** Fired with the value of the row chosen. */\n onAction: (value: T) => void;\n isDisabled?: boolean;\n className?: string;\n 'aria-label'?: string;\n} & SegmentTooltipFields & OverlayPortalProps;\n\n/**\n * A button that opens a list and acts on the row chosen — \"Add trial…\",\n * \"Load…\". Unlike a {@link Select} it holds no value, so it sizes to its own\n * label rather than to its widest row.\n *\n * `shortcut` adds a kit tooltip reading `Name (⌘N)`, named by `aria-label` or\n * a string `label`, as `Button` does; `tooltip` replaces that text.\n */\nexport function MenuButton<T extends string = string>({\n label,\n items,\n onAction,\n isDisabled,\n className,\n 'aria-label': ariaLabel,\n portalContainer,\n shortcut,\n tooltip,\n}: MenuButtonProps<T>) {\n const { anchor, portalProps } = useOverlayPortal(portalContainer);\n return (\n <MenuTrigger>\n {anchor}\n <TriggerTooltip\n content={segmentTooltipContent({ tooltip, shortcut, ariaLabel, label })}\n disabled={isDisabled}\n >\n <RACButton\n className={[f.frame, s.trigger, className].filter(Boolean).join(' ')}\n isDisabled={isDisabled}\n aria-label={ariaLabel}\n >\n <span className={s.label}>{label}</span>\n <svg className={s.chevron} viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M2 4 L5 7 L8 4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </RACButton>\n </TriggerTooltip>\n {/* `data-weasel-overlay`: see Select — the list renders in a portal,\n outside the subtree the trigger sits in. */}\n <RACPopover className={s.popover} data-weasel-overlay=\"\" {...portalProps}>\n <RACMenu className={`${listbox.surface} ${listbox.list}`} onAction={(key) => onAction(key as T)}>\n {items.map((item) => (\n <RACMenuItem\n key={item.value}\n id={item.value}\n className={s.item}\n isDisabled={item.isDisabled}\n textValue={item.textValue ?? (typeof item.label === 'string' ? item.label : undefined)}\n >\n {item.label}\n </RACMenuItem>\n ))}\n </RACMenu>\n </RACPopover>\n </MenuTrigger>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AC4CA,SAAgBa,EAAsC,EACpD,UACA,UACA,aACA,eACA,cACA,cAAcC,GACd,oBACA,aACA,cACqB;CACrB,IAAM,EAAE,WAAQ,mBAAgBP,EAAiBQ,CAAe;CAChE,OACE,kBAACC,GAAD,EAAA,UAAA;EACGC;EACD,kBAACT,GAAD;GACE,SAASC,EAAsB;IAAE;IAAS;IAAU;IAAW;GAAM,CAAC;GACtE,UAAUS;GAEV,UAAA,kBAAClB,GAAD;IACE,WAAW;KAACC,EAAE;KAAOC,EAAE;KAASkB;IAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;IACvD;IACZ,cAAYN;IAHd,UAAA,CAKE,kBAAC,QAAD;KAAM,WAAWZ,EAAE;KAAQ,UAAAmB;IAAY,CAAA,GACvC,kBAAC,OAAD;KAAK,WAAWnB,EAAE;KAAS,SAAQ;KAAY,eAAY;KACzD,UAAA,kBAAC,QAAD;MAAM,GAAE;MAAiB,MAAK;MAAO,QAAO;MAAe,aAAY;MAAM,eAAc;MAAQ,gBAAe;KAAS,CAAA;IACxH,CAAA,CACI;;EACG,CAAA;EAGhB,kBAACC,GAAD;GAAY,WAAWD,EAAE;GAAS,uBAAoB;GAAG,GAAIqB;GAC3D,UAAA,kBAACnB,GAAD;IAAS,WAAW,GAAGC,EAAQ,QAAQ,GAAGA,EAAQ;IAAQ,WAAW,MAAQoB,EAASC,CAAQ;IAC3F,UAAAC,EAAM,KAAK,MACV,kBAACrB,GAAD;KAEE,IAAIuB,EAAK;KACT,WAAW3B,EAAE;KACb,YAAY2B,EAAK;KACjB,WAAWA,EAAK,cAAc,OAAOA,EAAK,SAAU,WAAWA,EAAK,QAAQ,KAAA;KAE3E,UAAAA,EAAK;IACK,GAPNA,EAAK,KAOC,CACd;GACM,CAAA;EACC,CAAA;CACD,EAAA,CAAA;AAEjB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"OptionsBar-DeTAjVb7.js","names":["s","useRovingTabIndex","OptionsBar","props","toggle","item","items","index","roving","segmentedControl_module_default","style","height","rootCls","size","variant","className","ariaLabel","cls","i"],"sources":["../../src/components/OptionsBar/OptionsBar.tsx"],"sourcesContent":["import { type CSSProperties, type ReactElement, type ReactNode } from 'react';\nimport s from '../segmentedControl.module.css';\nimport { useRovingTabIndex } from '../../useRovingTabIndex';\n\n/**\n * One segment of an {@link OptionsBar}. Unlike `ToggleBar`, each item carries\n * its own selected state and its own `onChange`.\n */\nexport type OptionsBarItem<V extends string | number = string> = {\n value: V;\n label?: ReactNode;\n ariaLabel?: string;\n disabled?: boolean;\n selected: boolean;\n onChange: (next: boolean) => void;\n};\n\n/** Segment height and type scale for an {@link OptionsBar}. */\nexport type OptionsBarSize = 'sm' | 'md';\n/** Visual treatment of an {@link OptionsBar}. */\nexport type OptionsBarVariant = 'default' | 'minimal';\n\n/** Props for {@link OptionsBar}. */\nexport type OptionsBarProps<V extends string | number = string> = {\n items: readonly OptionsBarItem<V>[];\n ariaLabel?: string;\n className?: string;\n height?: number;\n /** Size variant. `sm` is ~60% of the default height with reduced padding\n * and font size — sized for dense surfaces like lab control panels. */\n size?: OptionsBarSize;\n /** Visual variant. `minimal` strips the pill track and glass treatment;\n * selection becomes a flat accent. For dense diagnostic surfaces. */\n variant?: OptionsBarVariant;\n};\n\n/**\n * Segmented strip of independent on/off options, each owning its own state.\n * Use it when the segments are unrelated booleans; use `ToggleBar` when they\n * are values of one setting.\n */\nexport function OptionsBar<V extends string | number = string>(props: OptionsBarProps<V>): ReactElement {\n const { items, ariaLabel, className, height, size, variant } = props;\n\n const toggle = (index: number) => {\n const item = items[index];\n if (item.disabled) return;\n item.onChange(!item.selected);\n };\n\n const roving = useRovingTabIndex({ itemSelector: `.${s.segment}`, onActivate: toggle });\n\n const style: CSSProperties | undefined = height !== undefined\n ? ({ ['--tb-h' as string]: `${height}px` } as CSSProperties)\n : undefined;\n\n const rootCls = [\n s.root,\n size && s[`size_${size}`],\n variant && s[`variant_${variant}`],\n className,\n ].filter(Boolean).join(' ');\n\n return (\n <div\n ref={roving.rootRef}\n onKeyDown={roving.onKeyDown}\n className={rootCls}\n role=\"group\"\n aria-label={ariaLabel}\n style={style}\n >\n {items.map((item, i) => {\n const cls = `${s.segment}${item.selected ? ` ${s.segmentSelected}` : ''}`;\n return (\n <button\n key={item.value}\n type=\"button\"\n aria-pressed={item.selected}\n aria-label={item.ariaLabel}\n disabled={item.disabled}\n className={cls}\n onClick={() => toggle(i)}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;AAyCA,SAAgBE,EAA+C,GAAyC;CACtG,IAAM,EAAE,UAAO,cAAW,cAAW,WAAQ,SAAM,eAAYC,GAEzDC,KAAU,MAAkB;EAChC,IAAMC,IAAOC,EAAMC;EACnB,AAAIF,EAAK,YACTA,EAAK,SAAS,CAACA,EAAK,QAAQ;CAC9B,GAEMG,IAASP,EAAkB;EAAE,cAAc,IAAID,EAAE;EAAW,YAAYI;CAAO,CAAC,GAEhFM,IAAmCC,MAAW,KAAA,IAEhD,KAAA,IADC,EAAG,UAAqB,GAAGA,EAAO,IAAI,GAGrCC,IAAU;EACdZ,EAAE;EACFa,KAAQb,EAAE,QAAQa;EAClBC,KAAWd,EAAE,WAAWc;EACxBC;CACF,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAE1B,OACE,kBAAC,OAAD;EACE,KAAKP,EAAO;EACZ,WAAWA,EAAO;EAClB,WAAWI;EACX,MAAK;EACL,cAAYI;EACL;EAEN,UAAAV,EAAM,KAAK,GAAM,MAAM;GACtB,IAAMW,IAAM,GAAGjB,EAAE,UAAUK,EAAK,WAAW,IAAIL,EAAE,oBAAoB;GACrE,OACE,kBAAC,UAAD;IAEE,MAAK;IACL,gBAAcK,EAAK;IACnB,cAAYA,EAAK;IACjB,UAAUA,EAAK;IACf,WAAWY;IACX,eAAeb,EAAOc,CAAC;IAEtB,UAAAb,EAAK;GACA,GATDA,EAAK,KASJ;EAEZ,CAAC;CACE,CAAA;AAET"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"PaintField-DX4uYlF9.js","names":["RACButton","s","RACPopover","RACDialog","listbox","useOverlayPortal","paintPreviewCss","PaintInput","PaintField_module_default","kindLabel","mixed","paint","label","PaintField","props","ariaLabel","portalContainer","preview","value","usePaintKind","DialogTrigger","anchor","Button","className","unset","Popover","portalProps","Dialog","listbox_module_default"],"sources":["../../src/components/PaintField/PaintField.module.css","../../src/components/PaintField/PaintField.tsx"],"sourcesContent":[".trigger {\n display: inline-flex;\n align-items: center;\n gap: var(--wzl-space-3);\n inline-size: 100%;\n min-inline-size: 0;\n padding: 1px var(--wzl-space-3) 1px 1px;\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n background: var(--wzl-surface);\n color: var(--wzl-fg);\n font-family: var(--wzl-font-ui);\n font-size: var(--wzl-font-size-sm);\n cursor: pointer;\n}\n\n.trigger[data-unset] {\n opacity: 0.6;\n}\n\n.trigger[data-focus-visible] {\n outline: none;\n border-color: var(--wzl-focus-ring);\n box-shadow: 0 0 0 1px var(--wzl-focus-ring);\n}\n\n.swatch {\n /* A paint preview at a fixed 26:18 aspect, not a control box. */\n inline-size: 26px;\n block-size: 18px; /* not-a-control */\n flex: 0 0 auto;\n border-radius: calc(var(--wzl-radius-sm) - var(--wzl-border-w));\n /* Checker under the paint, so a translucent one reads as translucent. */\n background-color: var(--wzl-surface-raised);\n box-shadow: inset 0 0 0 1px var(--wzl-border);\n}\n\n/* No paint to show: the checker stands in rather than an invented color. */\n.swatch[data-empty],\n.trigger[data-mixed] .swatch {\n background: repeating-conic-gradient(\n var(--wzl-checker-a) 0% 25%,\n var(--wzl-checker-b) 0% 50%\n )\n 50% / var(--wzl-checker-size) var(--wzl-checker-size);\n}\n\n.label {\n flex: 1 1 auto;\n min-inline-size: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: start;\n}\n\n.popover {\n outline: none;\n}\n\n.body {\n inline-size: 240px;\n padding: var(--wzl-space-4);\n}\n","import { type ReactElement } from 'react';\nimport {\n Button as RACButton,\n Dialog as RACDialog,\n DialogTrigger,\n Popover as RACPopover,\n} from 'react-aria-components';\nimport { usePaintKind, type FillStyle, type PaintKind } from '@weasel-js/core';\nimport { useOverlayPortal, type OverlayPortalProps } from '../../overlays/portalHost';\nimport { paintPreviewCss } from '../../paintPreview';\nimport { PaintInput } from '../PaintInput';\nimport listbox from '../listbox.module.css';\nimport s from './PaintField.module.css';\n\n/** Props for {@link PaintField}. `onInput` fires throughout a gesture inside\n * the popover and `onChange` once at its end. */\nexport interface PaintFieldProps extends OverlayPortalProps {\n /** The paint being edited. `null` is an explicit \"no paint\"; `undefined` is\n * no value to show. */\n value: FillStyle | null | undefined;\n /** Indeterminate presentation: the trigger says \"Mixed\" and the editor\n * lights no kind. */\n mixed?: boolean;\n /** Dim the trigger — a value is in effect but was never chosen. */\n unset?: boolean;\n /** Restrict the editor's kind bar. Default: every registered kind. */\n kinds?: readonly PaintKind[];\n /** Offer \"None\" in the editor. Default `true`. */\n allowNone?: boolean;\n onInput?: (next: FillStyle | null) => void;\n onChange: (next: FillStyle | null) => void;\n /** Names the paint this field edits — `Fill`, `Color`. */\n 'aria-label'?: string;\n className?: string;\n}\n\n/** What the trigger says it is holding. */\nfunction kindLabel(paint: FillStyle | null | undefined, mixed: boolean, label: string | undefined): string {\n if (mixed) return 'Mixed';\n if (paint === null) return 'None';\n if (paint === undefined) return '—';\n return label ?? (paint.fill ?? 'solid');\n}\n\n/**\n * A whole `FillStyle` in one control slot: a swatch that says which kind it\n * holds, and a popover holding {@link PaintInput}.\n *\n * `PaintInput` itself is a kind bar over a body — six segments and a stop\n * editor — which a property row's control column cannot hold. This is the\n * shape for a narrow slot, and the difference that matters is fidelity: a\n * `ColorField` in that slot reads a gradient's first stop and writes a solid\n * back, so touching the control loses the paint.\n */\nexport function PaintField(props: PaintFieldProps): ReactElement {\n const {\n value, mixed = false, unset = false, kinds, allowNone = true,\n onInput, onChange, className, portalContainer,\n } = props;\n const ariaLabel = props['aria-label'];\n const { anchor, portalProps } = useOverlayPortal(portalContainer);\n const preview = mixed ? undefined : paintPreviewCss(value);\n const label = usePaintKind(value?.fill)?.label;\n\n return (\n <DialogTrigger>\n {anchor}\n <RACButton\n className={[s.trigger, className].filter(Boolean).join(' ')}\n aria-label={ariaLabel}\n {...(unset ? { 'data-unset': '' } : {})}\n {...(mixed ? { 'data-mixed': '' } : {})}\n >\n <span\n className={s.swatch}\n aria-hidden=\"true\"\n {...(preview ? { style: { background: preview } } : { 'data-empty': '' })}\n />\n <span className={s.label}>{kindLabel(value, mixed, label)}</span>\n </RACButton>\n {/* `data-weasel-overlay`: see Select — the popover renders in a portal,\n outside the subtree the trigger sits in. */}\n <RACPopover className={s.popover} data-weasel-overlay=\"\" {...portalProps}>\n <RACDialog className={`${listbox.surface} ${s.body}`} aria-label={ariaLabel ? `${ariaLabel} editor` : 'Paint editor'}>\n <PaintInput\n value={value}\n mixed={mixed}\n unset={unset}\n kinds={kinds}\n allowNone={allowNone}\n onInput={onInput}\n onChange={onChange}\n aria-label={ariaLabel}\n />\n </RACDialog>\n </RACPopover>\n </DialogTrigger>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;ACqCA,SAASS,EAAU,GAAqC,GAAgB,GAAmC;CAIzG,OAHIC,IAAc,UACdC,MAAU,OAAa,SACvBA,MAAU,KAAA,IAAkB,MACzBC,KAAUD,EAAM,QAAQ;AACjC;AAYA,SAAgBE,EAAW,GAAsC;CAC/D,IAAM,EACJ,UAAO,WAAQ,IAAO,WAAQ,IAAO,UAAO,eAAY,IACxD,YAAS,aAAU,cAAW,uBAC5BC,GACEC,IAAYD,EAAM,eAClB,EAAE,WAAQ,mBAAgBT,EAAiBW,CAAe,GAC1DC,IAAUP,IAAQ,KAAA,IAAYJ,EAAgBY,CAAK,GACnDN,IAAQO,EAAaD,GAAO,IAAI,CAAC,EAAE;CAEzC,OACE,kBAACE,GAAD,EAAA,UAAA;EACGC;EACD,kBAACrB,GAAD;GACE,WAAW,CAACC,EAAE,SAASsB,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;GAC1D,cAAYR;GACZ,GAAKS,IAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;GACrC,GAAKd,IAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;GAJvC,UAAA,CAME,kBAAC,QAAD;IACE,WAAWT,EAAE;IACb,eAAY;IACZ,GAAKgB,IAAU,EAAE,OAAO,EAAE,YAAYA,EAAQ,EAAE,IAAI,EAAE,cAAc,GAAG;GACxE,CAAA,GACD,kBAAC,QAAD;IAAM,WAAWhB,EAAE;IAAQ,UAAAQ,EAAUS,GAAOR,GAAOE,CAAK;GAAQ,CAAA,CACvD;;EAGX,kBAACV,GAAD;GAAY,WAAWD,EAAE;GAAS,uBAAoB;GAAG,GAAIyB;GAC3D,UAAA,kBAACvB,GAAD;IAAW,WAAW,GAAGC,EAAQ,QAAQ,GAAGH,EAAE;IAAQ,cAAYc,IAAY,GAAGA,EAAU,WAAW;IACpG,UAAA,kBAACR,GAAD;KACS;KACA;KACA;KACA;KACI;KACF;KACC;KACV,cAAYQ;IACb,CAAA;GACQ,CAAA;EACD,CAAA;CACC,EAAA,CAAA;AAEnB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Prefs-gbjYqvSD.js","names":["_Fragment","s","s","s","s","s","Dialog","PropertyRow","PropertyControl","Input","useRovingTabIndex","filterPrefSubtree","prefValueAtPath","isPrefLeaf","visiblePrefSubtree","prefFieldProps","pickActiveSection","active","offsets","top","slack","id","SETTLE_MS","useScrollSpy","options","setActive","useState","heldRef","useRef","timerRef","releaseRef","key","ids","measure","useCallback","root","rootRef","rootTop","el","scrollTo","release","prefersReducedMotion","useEffect","Prefs_module_default","PrefRow","stored","ctx","path","inherited","toggles","onAutoChange","setAuto","next","renderCtx","pref","v","custom","control","renderBuiltin","Fragment","ObjectLeaf","field","settledOnly","held","value","objectRows","out","child","children","inner","base","PrefsPane","props","leaves","group","entry","groups","childPath","className","scrollRef","leaf","PaneSection","Heading","depth","p","PrefsRail","activate","item","items","index","onOpen","onScrollTo","roving","i","section","ariaLabel","header","open","inView","current","showCounts","PrefsForm","query","setQuery","useMemo","visible","schema","showHidden","filterable","layout","RailLayout","NoMatches","GroupBody","prefRailItems","uncontrolled","setUncontrolled","subPages","requested","hasLeaves","paneGroup","spy","setOpen","whole","opensTop","leavesOf","filterField","onClearFilter","rootName","node","cursor","seg","onClear","PrefsDialog","form","rail","title","dialogClassName","headerExtra"],"sources":["../../src/useScrollSpy.ts","../../src/components/Prefs/Prefs.module.css","../../src/components/Prefs/PrefsRow.tsx","../../src/components/Prefs/PrefsPane.tsx","../../src/components/Prefs/PrefsRail.tsx","../../src/components/Prefs/PrefsForm.tsx","../../src/components/Prefs/PrefsDialog.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState, type RefObject } from 'react';\n\n/** One observed section: its id and its top edge, in the container's\n * coordinates (its `getBoundingClientRect().top` less the container's). */\nexport interface SectionOffset {\n id: string;\n top: number;\n}\n\n/**\n * The section a reader is looking at: the last one whose top edge has passed\n * the container's, within `slack` of it so a heading flush with the top counts\n * as arrived. Null until one has — the settings above the first section belong\n * to the group itself, and marking a section the reader has not reached yet\n * points them at the wrong place.\n *\n * Offsets arrive in document order and are not re-sorted — a caller reading\n * them off the DOM already has them that way, and sorting would hide a\n * measurement that came back wrong.\n */\nexport function pickActiveSection(\n offsets: readonly SectionOffset[],\n slack = 8,\n): string | null {\n let active: string | null = null;\n for (const { id, top } of offsets) {\n if (top - slack > 0) break;\n active = id;\n }\n return active;\n}\n\n/** Options for {@link useScrollSpy}. */\nexport interface UseScrollSpyOptions {\n /** The scrolling element holding the sections. */\n rootRef: RefObject<HTMLElement | null>;\n /** Section element ids, in document order. */\n ids: readonly string[];\n /** Pixels of tolerance at the container's top edge. */\n slack?: number;\n}\n\n/** What {@link useScrollSpy} returns. */\nexport interface ScrollSpy {\n /** Id of the section in view, or null before anything is measured. */\n active: string | null;\n /**\n * Scroll `id` to the container's top and hold that answer until the scroll\n * settles. Without the hold, the scroll the click causes is observed on its\n * way past every intervening section and the rail flickers through them.\n */\n scrollTo: (id: string) => void;\n}\n\n/** How long to keep a programmatic scroll's answer when `scrollend` never\n * arrives — Safari and Firefox have not shipped it. Comfortably longer than a\n * smooth scroll, short enough that a reader who then scrolls by hand is not\n * left looking at a stale highlight. */\nconst SETTLE_MS = 700;\n\n/**\n * Which of a scrolling container's sections is in view, for a navigation rail\n * that follows the reader. Positions are read on the container's own `scroll`\n * event — already throttled to the frame by the browser — rather than through\n * `IntersectionObserver`, so the decision stays a pure function of measured\n * offsets ({@link pickActiveSection}) and is testable apart from the DOM.\n */\nexport function useScrollSpy(options: UseScrollSpyOptions): ScrollSpy {\n const { rootRef, ids, slack } = options;\n const [active, setActive] = useState<string | null>(null);\n // Set while a programmatic scroll runs: what to report, instead of what the\n // moving container would say.\n const heldRef = useRef<string | null>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const releaseRef = useRef<(() => void) | null>(null);\n const key = ids.join('\\u0000');\n\n const measure = useCallback((): void => {\n const root = rootRef.current;\n if (!root) return;\n if (heldRef.current !== null) {\n setActive(heldRef.current);\n return;\n }\n const rootTop = root.getBoundingClientRect().top;\n const offsets: SectionOffset[] = [];\n for (const id of ids) {\n const el = root.querySelector<HTMLElement>(`[data-spy-section=\"${CSS.escape(id)}\"]`);\n if (el) offsets.push({ id, top: el.getBoundingClientRect().top - rootTop });\n }\n setActive(pickActiveSection(offsets, slack));\n // `ids` is compared by content through `key`: a caller deriving the array\n // each render would otherwise resubscribe on every one.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [rootRef, key, slack]);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n measure();\n root.addEventListener('scroll', measure, { passive: true });\n return () => root.removeEventListener('scroll', measure);\n }, [rootRef, measure]);\n\n const scrollTo = useCallback((id: string): void => {\n const root = rootRef.current;\n if (!root) return;\n const el = root.querySelector<HTMLElement>(`[data-spy-section=\"${CSS.escape(id)}\"]`);\n heldRef.current = id;\n setActive(id);\n const release = (): void => {\n heldRef.current = null;\n root.removeEventListener('scrollend', release);\n measure();\n };\n // A scroll interrupted by the next one would otherwise leave its\n // `scrollend` listener behind to fire against a later scroll.\n releaseRef.current?.();\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n releaseRef.current = release;\n timerRef.current = setTimeout(release, SETTLE_MS);\n root.addEventListener('scrollend', release);\n if (!el) return;\n const top = el.getBoundingClientRect().top - root.getBoundingClientRect().top + root.scrollTop;\n root.scrollTo?.({ top, behavior: prefersReducedMotion() ? 'auto' : 'smooth' });\n }, [rootRef, measure]);\n\n useEffect(() => () => {\n if (timerRef.current !== null) clearTimeout(timerRef.current);\n releaseRef.current?.();\n }, []);\n\n return { active, scrollTo };\n}\n\nfunction prefersReducedMotion(): boolean {\n return typeof matchMedia === 'function'\n && matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n","/* Ported from WeaselDraw's wd-prefs-* rules (apps/draw/src/app.css),\n * generalized onto theme tokens. Column width is overridable via\n * --wzl-prefs-column-width at any ancestor scope. */\n\n.columns {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: var(--wzl-space-6);\n overflow-y: auto;\n padding-right: var(--wzl-space-2);\n}\n\n.column {\n flex: 0 0 var(--wzl-prefs-column-width, 300px);\n width: var(--wzl-prefs-column-width, 300px);\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-4);\n}\n\n.panel {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-4);\n padding: var(--wzl-space-5);\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n --wzl-input-surface: var(--wzl-surface);\n}\n\n.subpanel {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-3);\n margin-top: var(--wzl-space-3);\n padding: var(--wzl-space-4) var(--wzl-space-4) var(--wzl-space-4) var(--wzl-space-5);\n background: var(--wzl-surface-sunken);\n border-left: 2px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n --wzl-input-surface: var(--wzl-surface);\n}\n\n.groupHeader {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-1);\n padding-bottom: var(--wzl-space-2);\n border-bottom: 1px solid var(--wzl-border);\n}\n\n.subpanel .groupHeader {\n border-bottom: none;\n padding-bottom: var(--wzl-space-1);\n}\n\n.groupTitle {\n margin: 0;\n font-size: var(--wzl-font-size-sm);\n font-weight: var(--wzl-font-weight-bold);\n color: var(--wzl-fg);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wider));\n text-transform: var(--wzl-params-label-case, uppercase);\n}\n\n.groupDesc {\n margin: 0;\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg-subtle);\n line-height: 1.35;\n}\n\n.rows {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-3);\n}\n\n/* A leaf's row is a PropertyRow, inline; this only sets the form's type. */\n.row {\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg);\n cursor: default;\n}\n\n/* Control slot — fixed width so the label can take the rest of the row.\n * Kit form controls render as block-level flex columns that fill it. */\n.rowControl {\n flex: 0 0 110px;\n min-width: 0;\n display: flex;\n align-items: center;\n}\n\n.unrenderable {\n font-family: var(--wzl-font-mono);\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg-subtle);\n}\n\n/* PrefsDialog header row: title text + optional headerExtra chrome. */\n.titleRow {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-6);\n flex: 1;\n min-width: 0;\n}\n\n.titleRow > span:first-child {\n flex: 1;\n min-width: 0;\n}\n\n/* An object leaf renders its fields as its own rows. */\n.objectLeaf {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-3);\n inline-size: 100%;\n}\n\n/* Outranks the PropertyRow it styles, which is a flex row. */\n.objectLeaf .objectRow {\n display: grid;\n grid-template-columns: 96px 1fr;\n gap: var(--wzl-space-4);\n align-items: center;\n}\n\n.objectGroup {\n margin: var(--wzl-space-2) 0 0;\n font-size: var(--wzl-font-size-xs);\n font-weight: var(--wzl-font-weight-bold);\n text-transform: var(--wzl-params-label-case, uppercase);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wide));\n opacity: 0.55;\n}\n\n/* ---------------------------------------------------------------------------\n * Rail layout. The rail is the only chrome: no panels, because the surface\n * the form sits on already has a border and a card inside it restates one.\n * Width is overridable via --wzl-prefs-rail-width at any ancestor scope.\n * ------------------------------------------------------------------------ */\n\n.columnsLayout {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-4);\n min-height: 0;\n}\n\n.railLayout {\n display: flex;\n flex-direction: row;\n align-items: stretch;\n min-height: 0;\n block-size: 100%;\n /* The pane scrolls, not the layout: a rail that scrolled away with the\n settings would be useless exactly when it is needed. */\n overflow: hidden;\n}\n\n/* What `PrefsDialog` hands `Dialog` for its body in rail layout: the pane\n inside does the scrolling and the rail meets the dialog's own edges. */\n.railBody {\n padding: 0;\n overflow: hidden;\n /* The modal sets only `max-height`, so the layout's `block-size: 100%`\n resolves against nothing and the pane grows to fit every row. As a flex\n item the layout takes the body's flexed height, which the cap does bound. */\n display: flex;\n flex-direction: column;\n /* A settled height: without one the dialog grows and shrinks as the reader\n moves between a two-row group and a twenty-row one, and the rail entry\n they are aiming at moves while they aim at it. */\n min-block-size: min(60vh, 420px);\n /* Same reason across: a filter that narrows the schema to two rows should\n not pull the dialog's edges in around them. */\n min-inline-size: min(760px, 90vw);\n}\n\n.railBody > .railLayout {\n flex: 1 1 auto;\n}\n\n.rail {\n /* Never more than two fifths of the box: at its full width in a narrow\n container the rail takes the space the settings need and leaves a pane\n too thin to hold a row. The clamp belongs on the flex basis — an\n `inline-size` here is simply ignored, which is what made a first attempt\n at this look right and do nothing. */\n flex: 0 1 min(var(--wzl-prefs-rail-width, 216px), 40%);\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-2);\n padding: var(--wzl-space-3) var(--wzl-space-2);\n background: var(--wzl-surface-sunken);\n border-right: 1px solid var(--wzl-border);\n overflow-y: auto;\n /* The rail is itself sunken, so a field taking the default surface would be\n the same color as the rail behind it. */\n --wzl-input-surface: var(--wzl-surface);\n}\n\n.railList {\n display: flex;\n flex-direction: column;\n gap: 1px;\n}\n\n.railItem {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-2);\n padding: var(--wzl-space-2) var(--wzl-space-3);\n border: none;\n border-radius: var(--wzl-radius-sm);\n background: none;\n color: var(--wzl-fg);\n font: inherit;\n font-size: var(--wzl-font-size-sm);\n text-align: start;\n cursor: default;\n}\n\n.railItem:hover {\n background: var(--wzl-surface-raised);\n}\n\n.railItem:focus-visible {\n outline: 2px solid var(--wzl-focus-ring);\n outline-offset: -2px;\n}\n\n.railSub {\n padding-left: var(--wzl-space-7);\n}\n\n.railSub:not(.railOpen, .railInView) .railName {\n color: var(--wzl-fg-muted);\n}\n\n.railOpen,\n.railOpen:hover {\n background: var(--wzl-accent);\n color: var(--wzl-fg-on-accent);\n}\n\n.railInView {\n box-shadow: inset 2px 0 0 var(--wzl-accent);\n}\n\n.railName {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Last in the row: a count that changes as the reader types would otherwise\n shove the name on every keystroke. */\n.railCount {\n composes: numeric from '@weasel-js/theme/numeric.module.css';\n margin-left: auto;\n font-size: var(--wzl-font-size-xs);\n opacity: 0.6;\n}\n\n.pane {\n flex: 1;\n min-width: 0;\n overflow-y: auto;\n padding: var(--wzl-space-5) var(--wzl-space-6);\n}\n\n.paneHead {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-1);\n margin-bottom: var(--wzl-space-5);\n}\n\n.paneTitle {\n margin: 0;\n font-size: var(--wzl-font-size-lg);\n font-weight: var(--wzl-font-weight-medium);\n color: var(--wzl-fg);\n}\n\n.paneDesc {\n margin: 0;\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg-subtle);\n line-height: 1.35;\n}\n\n.paneSection {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-3);\n margin-top: var(--wzl-space-6);\n}\n\n.paneSubsection {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-2);\n margin-top: var(--wzl-space-4);\n padding-left: var(--wzl-space-4);\n border-left: 2px solid var(--wzl-border);\n}\n\n.sectionTitle {\n position: sticky;\n /* Sticky offsets are measured from the scrollport's edge, not from inside\n the pane's padding, so this is 0 and the heading's own padding is what\n keeps the text off the edge. */\n top: 0;\n z-index: 1;\n margin: 0;\n padding: var(--wzl-space-3) 0 var(--wzl-space-2);\n background: var(--wzl-surface);\n border-bottom: 1px solid var(--wzl-border);\n font-size: var(--wzl-font-size-sm);\n font-weight: var(--wzl-font-weight-bold);\n color: var(--wzl-fg-subtle);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wider));\n text-transform: var(--wzl-params-label-case, uppercase);\n}\n\n.subsectionTitle {\n margin: 0;\n font-size: var(--wzl-font-size-xs);\n font-weight: var(--wzl-font-weight-bold);\n color: var(--wzl-fg-subtle);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wide));\n text-transform: var(--wzl-params-label-case, uppercase);\n}\n\n/* In the rail layout a row is a grid, so the control track grows with the\n pane instead of holding at the columns layout's fixed slot. */\n.railLayout .row {\n display: grid;\n /* The control track is capped rather than taking the rest: a number field\n as wide as the pane reads as a text area, and every row's control starts\n at the same x either way. */\n grid-template-columns:\n minmax(140px, var(--wzl-params-label-width, 240px))\n minmax(180px, 260px);\n align-items: center;\n}\n\n.railLayout .rowControl {\n flex: 1 1 auto;\n}\n\n.filter {\n padding: 0 var(--wzl-space-1) var(--wzl-space-2);\n}\n\n.noMatches {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: var(--wzl-space-3);\n padding: var(--wzl-space-6) 0;\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg-subtle);\n}\n\n.noMatches p {\n margin: 0;\n}\n\n.clearFilter {\n padding: var(--wzl-space-1) var(--wzl-space-3);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n background: var(--wzl-surface-raised);\n color: var(--wzl-fg);\n font: inherit;\n font-size: var(--wzl-font-size-sm);\n}\n","import { type ReactNode } from 'react';\nimport { PropertyControl } from '../Properties/PropertyField';\nimport { PropertyRow } from '../Properties/PropertyPanel';\nimport { prefFieldProps } from './prefField';\nimport {\n isPrefLeaf,\n prefValueAtPath,\n type PrefGroup,\n type PrefLeaf,\n type PrefObject,\n} from './schema';\nimport s from './Prefs.module.css';\n\n/** What a {@link PrefRenderer} is given for the leaf it is rendering. */\nexport interface PrefRenderContext {\n /** Dotted path of the leaf within the schema root. */\n path: string;\n /** The schema node. App renderers narrow this to their own kind shape. */\n pref: PrefLeaf;\n /** Current value — `values` at `path`, falling back to `pref.default`. */\n value: unknown;\n setValue: (value: unknown) => void;\n /** Whether this leaf is currently auto — not pinned, computed by the owner. */\n auto: boolean;\n /** Toggle this leaf's auto state. */\n setAuto: (next: boolean) => void;\n}\n\n/**\n * Renders the control cell for one preference leaf. Returning `null`\n * collapses the row.\n */\nexport type PrefRenderer = (ctx: PrefRenderContext) => ReactNode;\n\nexport interface WalkCtx {\n values: unknown;\n onChange: (path: string, value: unknown) => void;\n renderers?: Record<string, PrefRenderer>;\n auto?: ReadonlySet<string>;\n onAutoChange?: (path: string, next: boolean) => void;\n inheritHint?: (path: string) => string | undefined;\n canInherit?: (path: string) => boolean;\n}\n\nexport function PrefRow({ ctx, path, pref }: { ctx: WalkCtx; path: string; pref: PrefLeaf }) {\n const stored = prefValueAtPath(ctx.values, path);\n const inherited = ctx.auto?.has(path) ?? false;\n const { onAutoChange } = ctx;\n const toggles = onAutoChange !== undefined && (ctx.canInherit?.(path) ?? true);\n const setAuto = (next: boolean): void => {\n if (toggles) onAutoChange(path, next);\n };\n const renderCtx: PrefRenderContext = {\n path,\n pref,\n value: stored !== undefined ? stored : pref.default,\n setValue: (v) => ctx.onChange(path, v),\n auto: inherited,\n setAuto,\n };\n\n const custom = ctx.renderers?.[pref.kind];\n const control = custom ? custom(renderCtx) : renderBuiltin(renderCtx);\n if (custom && control === null) return null;\n\n // `block` leaves own their chrome (embedded editors with their own\n // header) — no label/tooltip row.\n if (pref.block) return <>{control}</>;\n\n return (\n <PropertyRow\n label={pref.name}\n description={pref.description}\n layout=\"inline\"\n className={s.row}\n // The owner passes an inherited leaf's value already resolved, so the\n // control keeps drawing it; editing it pins, through `onChange`.\n auto={inherited}\n autoControl=\"dimmed\"\n onAutoChange={toggles ? setAuto : undefined}\n hint={inherited ? ctx.inheritHint?.(path) : undefined}\n >\n <span className={s.rowControl}>{control}</span>\n </PropertyRow>\n );\n}\n\nfunction renderBuiltin(\n ctx: PrefRenderContext,\n // The object a nested leaf is a field of — what an enum `encoding` and a\n // font's weight and slant read against. Undefined for a top-level leaf.\n siblings?: Record<string, unknown>,\n): ReactNode {\n const { pref, value, setValue } = ctx;\n if (pref.kind === 'object') return <ObjectLeaf ctx={ctx} />;\n const field = prefFieldProps(pref, { value, siblings, setValue });\n if (field === null) {\n // App-defined kind with no `renderers` entry: labeled placeholder, not a\n // crash — a missing wiring should be visible and recoverable.\n return <span className={s.unrenderable}>({pref.kind}: no renderer)</span>;\n }\n switch (field.kind) {\n // A form stores what was settled on: a number once it is entered, a color\n // once its gesture ends.\n case 'number':\n return (\n <PropertyControl\n {...field}\n name={pref.name}\n onInput={settledOnly}\n steppers={field.accepts === undefined}\n />\n );\n case 'color':\n return <PropertyControl {...field} name={pref.name} onInput={settledOnly} />;\n default:\n return <PropertyControl {...field} name={pref.name} />;\n }\n}\n\nconst settledOnly = (): void => {};\n\n/** One value with its fields hanging off it: each field renders its own\n * control and commits the parent object whole. */\nfunction ObjectLeaf({ ctx }: { ctx: PrefRenderContext }) {\n const pref = ctx.pref as PrefObject;\n const { value, setValue } = ctx;\n const held = typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n const objectRows = (children: Record<string, PrefLeaf | PrefGroup>): ReactNode[] => {\n const out: ReactNode[] = [];\n for (const [key, child] of Object.entries(children)) {\n if (!isPrefLeaf(child)) {\n const inner = objectRows(child.children);\n if (inner.length === 0) continue;\n out.push(<h4 key={`group:${key}`} className={s.objectGroup}>{child.name}</h4>, ...inner);\n continue;\n }\n out.push(\n <PropertyRow\n key={key}\n label={child.name}\n layout=\"inline\"\n className={s.objectRow}\n >\n <span className={s.rowControl}>\n {renderBuiltin({\n path: `${ctx.path}.${key}`,\n pref: child,\n value: held?.[key],\n setValue: (v) => {\n const base = held ?? pref.fromScalar?.(value) ?? {};\n setValue({ ...base, [key]: v });\n },\n // A field is not pinned on its own — it shares the state of\n // the object leaf it hangs off.\n auto: ctx.auto,\n setAuto: ctx.setAuto,\n }, held)}\n </span>\n </PropertyRow>,\n );\n }\n return out;\n };\n return <div className={s.objectLeaf}>{objectRows(pref.children)}</div>;\n}\n","import { type RefObject } from 'react';\nimport { isPrefLeaf, type PrefGroup, type PrefLeaf } from './schema';\nimport { PrefRow, type WalkCtx } from './PrefsRow';\nimport s from './Prefs.module.css';\n\n/** Props for {@link PrefsPane}. */\nexport interface PrefsPaneProps {\n ctx: WalkCtx;\n /** The open group, or a synthetic one holding the root's loose leaves. */\n group: PrefGroup;\n /** Dotted path of `group`. Empty for the loose-leaf pane. */\n path: string;\n /** The pane's scroll container, for the rail's scroll spy. */\n scrollRef: RefObject<HTMLDivElement | null>;\n className?: string;\n}\n\n/**\n * One rail section's settings: the group's own leaves, then one headed\n * section per nested group.\n *\n * Nothing here draws a panel. The rail is the layout's structure, and a card\n * inside a dialog that already has a border only restates it — the columns\n * layout's sunken panels are what this is the alternative to.\n */\nexport function PrefsPane(props: PrefsPaneProps) {\n const { ctx, group, path, scrollRef, className } = props;\n const leaves = Object.entries(group.children).filter(\n (entry): entry is [string, PrefLeaf] => isPrefLeaf(entry[1]),\n );\n const groups = Object.entries(group.children).filter(\n (entry): entry is [string, PrefGroup] => !isPrefLeaf(entry[1]),\n );\n const childPath = (key: string): string => (path === '' ? key : `${path}.${key}`);\n\n return (\n <div className={[s.pane, className].filter(Boolean).join(' ')} ref={scrollRef}>\n <div className={s.paneHead}>\n <h3 className={s.paneTitle}>{group.name}</h3>\n {group.description !== undefined && (\n <p className={s.paneDesc}>{group.description}</p>\n )}\n </div>\n {leaves.length > 0 && (\n <div className={s.rows}>\n {leaves.map(([key, leaf]) => (\n <PrefRow key={key} ctx={ctx} path={childPath(key)} pref={leaf} />\n ))}\n </div>\n )}\n {groups.map(([key, child]) => (\n <PaneSection\n key={key}\n ctx={ctx}\n group={child}\n path={childPath(key)}\n depth={0}\n />\n ))}\n </div>\n );\n}\n\n/**\n * A nested group inside a pane. Depth 0 sections are the ones the rail links\n * to and carry `data-spy-section`; deeper ones indent and are reached only by\n * scrolling, which is what keeps the rail two levels deep whatever the schema\n * does.\n */\nfunction PaneSection({ ctx, group, path, depth }: {\n ctx: WalkCtx;\n group: PrefGroup;\n path: string;\n depth: number;\n}) {\n const Heading = depth === 0 ? 'h4' : 'h5';\n return (\n <section\n className={depth === 0 ? s.paneSection : s.paneSubsection}\n data-spy-section={depth === 0 ? path : undefined}\n aria-label={group.name}\n >\n <Heading className={depth === 0 ? s.sectionTitle : s.subsectionTitle}>\n {group.name}\n </Heading>\n {group.description !== undefined && (\n <p className={s.paneDesc}>{group.description}</p>\n )}\n <div className={s.rows}>\n {Object.entries(group.children).map(([key, child]) => {\n const p = `${path}.${key}`;\n return isPrefLeaf(child) ? (\n <PrefRow key={key} ctx={ctx} path={p} pref={child} />\n ) : (\n <PaneSection key={key} ctx={ctx} group={child} path={p} depth={depth + 1} />\n );\n })}\n </div>\n </section>\n );\n}\n","import type { ReactNode } from 'react';\nimport { useRovingTabIndex } from '../../useRovingTabIndex';\nimport type { PrefRailItem } from './schema';\nimport s from './Prefs.module.css';\n\n/** Props for {@link PrefsRail}. */\nexport interface PrefsRailProps {\n items: readonly PrefRailItem[];\n /** Path of the open group: depth 0, or depth 1 under `subPages`. */\n section: string;\n /** Path of the depth-1 group in view, from the pane's scroll spy. */\n current: string | null;\n /** A depth-0 entry was chosen: open its pane. */\n onOpen: (path: string) => void;\n /** A depth-1 entry was chosen: scroll the open pane to it, or, under\n * `subPages`, open it. */\n onScrollTo: (path: string) => void;\n /** Accessible name for the rail's landmark. */\n ariaLabel: string;\n /** Rendered above the list — the filter field, when there is one. */\n header?: ReactNode;\n /** Show each entry's match count. Only meaningful while filtering. */\n showCounts?: boolean;\n}\n\n/**\n * The rail beside a `PrefsForm` pane: depth-0 groups, each followed by the\n * depth-1 groups that scroll within it.\n *\n * A list of buttons rather than a tablist, because only half of these entries\n * switch anything — the nested ones scroll the pane the selected entry already\n * opened, and a tab that does not own a panel has no honest role. The open\n * group is `aria-current=\"page\"`; the nested group in view is\n * `aria-current=\"location\"`.\n */\nexport function PrefsRail(props: PrefsRailProps) {\n const { items, section, current, onOpen, onScrollTo, ariaLabel, header, showCounts } = props;\n const activate = (index: number): void => {\n const item = items[index];\n if (!item) return;\n if (item.depth === 0) onOpen(item.path);\n else onScrollTo(item.path);\n };\n const roving = useRovingTabIndex<HTMLDivElement>({\n itemSelector: `.${s.railItem}`,\n tabStopIndex: Math.max(0, items.findIndex((i) => i.path === section)),\n });\n\n return (\n <nav className={s.rail} aria-label={ariaLabel}>\n {header}\n <div className={s.railList} ref={roving.rootRef} onKeyDown={roving.onKeyDown}>\n {items.map((item, index) => {\n const open = item.path === section;\n const inView = item.depth === 1 && item.path === current;\n return (\n <button\n key={item.path === '' ? '\\u0000root' : item.path}\n type=\"button\"\n className={[s.railItem, item.depth === 1 && s.railSub, open && s.railOpen, inView && s.railInView]\n .filter(Boolean)\n .join(' ')}\n aria-current={open ? 'page' : inView ? 'location' : undefined}\n onClick={() => activate(index)}\n >\n <span className={s.railName}>{item.name}</span>\n {showCounts ? <span className={s.railCount}>{item.matches}</span> : null}\n </button>\n );\n })}\n </div>\n </nav>\n );\n}\n","import { useMemo, useRef, useState, type ReactNode } from 'react';\nimport { Input } from '../Input';\nimport { useScrollSpy } from '../../useScrollSpy';\nimport {\n filterPrefSubtree,\n isPrefLeaf,\n prefRailItems,\n visiblePrefSubtree,\n type PrefGroup,\n} from './schema';\nimport { PrefRow, type PrefRenderer, type WalkCtx } from './PrefsRow';\nimport { PrefsPane } from './PrefsPane';\nimport { PrefsRail } from './PrefsRail';\nimport s from './Prefs.module.css';\n\nexport type { PrefRenderer, PrefRenderContext } from './PrefsRow';\n\n/** How a {@link PrefsForm} lays its groups out. */\nexport type PrefsLayout = 'columns' | 'rail';\n\n/** Props for {@link PrefsForm}. */\nexport interface PrefsFormProps {\n /** Root of the schema tree. Core `ToolPrefGroup`s assign structurally. */\n schema: PrefGroup;\n /** Nested value tree (shape mirrors the schema). Sparse is fine —\n * missing leaves fall back to their schema `default`. */\n values?: unknown;\n /** Change callback with the leaf's dotted path. Values apply live;\n * there is no dirty/commit state. */\n onChange: (path: string, value: unknown) => void;\n /**\n * Per-kind renderers for app-defined kinds. Entries also override the\n * built-in kinds when keys collide. A renderer owns the control cell\n * (the label/tooltip row chrome stays with the form, unless the leaf\n * sets `block`); returning `null` collapses the row entirely. Unknown\n * kinds with no renderer show a labeled placeholder instead of\n * crashing.\n */\n renderers?: Record<string, PrefRenderer>;\n /** Reveal `hidden` leaves (dev tooling). Default false. */\n showHidden?: boolean;\n /**\n * `'columns'` (the default) wraps each top-level group into its own panel\n * column. `'rail'` puts a two-level navigation rail beside one group's\n * settings at a time — what a dialog-sized surface wants, since columns\n * overflow sideways once there are more than two.\n */\n layout?: PrefsLayout;\n /** Show a filter field that narrows the form to matching leaves. */\n filterable?: boolean;\n /** Rail layout: path of the open top-level group. Controlled. */\n section?: string;\n /** Rail layout: path of the group open before the reader picks one.\n * Defaults to the first in the schema. */\n defaultSection?: string;\n onSectionChange?: (path: string) => void;\n /**\n * Rail layout: a nested entry opens a page of its own group instead of\n * scrolling the open one to it, and a top-level entry's page holds only its\n * own leaves (or opens its first nested entry when it has none). For a\n * top-level group whose subgroups are long enough that one page of all of\n * them reads as a wall. Default false.\n */\n subPages?: boolean;\n /** Dotted paths whose leaves currently inherit: each still draws its control,\n * dimmed, showing the value in `values` — pass it already resolved. Editing\n * it calls `onChange` as usual, which is the owner's cue to pin it. */\n auto?: ReadonlySet<string>;\n /** Given, a leaf's label toggles whether it inherits: `next` true unpins it,\n * false pins it at the value it shows. Leaves `canInherit` refuses keep a\n * plain label. */\n onAutoChange?: (path: string, next: boolean) => void;\n /** Which leaves can inherit, and so get a label toggle. Default: every leaf,\n * once `onAutoChange` is given. */\n canInherit?: (path: string) => boolean;\n /** Small text after an inherited leaf's label, e.g. `() => 'from Defaults'`.\n * Default: none. */\n inheritHint?: (path: string) => string | undefined;\n className?: string;\n}\n\n/**\n * Schema-driven preferences form. Leaves render as label + control rows;\n * how the groups around them are arranged is `layout`'s to say — columns of\n * panels, or a navigation rail beside one group at a time.\n *\n * Storage-agnostic: pair with `PrefsDialog` for the modal composition, and\n * persist however the app likes via `onChange`.\n */\nexport function PrefsForm(props: PrefsFormProps) {\n const {\n schema,\n values,\n onChange,\n renderers,\n showHidden = false,\n layout = 'columns',\n filterable = false,\n auto,\n onAutoChange,\n canInherit,\n inheritHint,\n className,\n } = props;\n const [query, setQuery] = useState('');\n const root = useMemo(() => {\n const visible = visiblePrefSubtree(schema, showHidden);\n return visible === null ? null : filterPrefSubtree(visible, query);\n }, [schema, showHidden, query]);\n\n const ctx: WalkCtx = { values, onChange, renderers, auto, onAutoChange, canInherit, inheritHint };\n const field = filterable ? (\n <div className={s.filter}>\n <Input\n value={query}\n onChange={setQuery}\n aria-label={`Filter ${schema.name}`}\n placeholder=\"Filter settings\"\n />\n </div>\n ) : null;\n\n if (layout === 'rail') {\n return (\n <RailLayout\n {...props}\n root={root}\n ctx={ctx}\n query={query}\n filterField={field}\n onClearFilter={() => setQuery('')}\n />\n );\n }\n\n return (\n <div className={[s.columnsLayout, className].filter(Boolean).join(' ')}>\n {field}\n {root === null ? (\n <NoMatches query={query} onClear={() => setQuery('')} />\n ) : (\n <div className={s.columns}>\n {Object.entries(root.children).map(([key, child]) => (\n <div key={key} className={s.column}>\n {isPrefLeaf(child) ? (\n // Top-level leaves are unusual but legal — give each its own\n // column for symmetry with grouped siblings.\n <PrefRow ctx={ctx} path={key} pref={child} />\n ) : (\n <GroupBody ctx={ctx} group={child} path={key} depth={0} />\n )}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/** The rail layout's own state: which group is open, and where the pane is\n * scrolled to within it. Split out so the columns layout runs none of it. */\nfunction RailLayout(props: PrefsFormProps & {\n root: PrefGroup | null;\n ctx: WalkCtx;\n query: string;\n filterField: ReactNode;\n onClearFilter: () => void;\n}) {\n const { schema, root, ctx, query, filterField, onClearFilter, className } = props;\n const items = useMemo(() => (root === null ? [] : prefRailItems(root)), [root]);\n const [uncontrolled, setUncontrolled] = useState(\n () => props.defaultSection ?? '',\n );\n const subPages = props.subPages === true;\n const requested = props.section ?? uncontrolled;\n // A filter can take the open group out of the rail entirely, and a section\n // the schema never had can arrive from a consumer's stale state. Either way\n // the first surviving entry is what the reader should be looking at.\n let open = items.some((i) => i.path === requested && (i.depth === 0 || subPages))\n ? requested\n : (items.find((i) => i.depth === 0)?.path ?? '');\n if (subPages && root !== null && !hasLeaves(paneGroup(root, open, schema.name))) {\n open = items.find((i) => i.depth === 1 && i.section === open)?.path ?? open;\n }\n\n const scrollRef = useRef<HTMLDivElement | null>(null);\n const sectionIds = useMemo(\n () =>\n subPages\n ? []\n : items.filter((i) => i.depth === 1 && i.section === open).map((i) => i.path),\n [items, open, subPages],\n );\n const spy = useScrollSpy({ rootRef: scrollRef, ids: sectionIds });\n\n const setOpen = (path: string): void => {\n if (props.section === undefined) setUncontrolled(path);\n props.onSectionChange?.(path);\n // Optional-called: jsdom's elements have no `scrollTo`, and neither does\n // a pane that is not the scrolling box in some consumer's layout.\n scrollRef.current?.scrollTo?.({ top: 0 });\n };\n\n const whole = root === null ? null : paneGroup(root, open, schema.name);\n const opensTop = items.some((i) => i.path === open && i.depth === 0);\n const group = subPages && opensTop && whole !== null ? leavesOf(whole) : whole;\n\n return (\n <div className={[s.railLayout, className].filter(Boolean).join(' ')}>\n <PrefsRail\n items={items}\n section={open}\n current={subPages ? null : spy.active}\n onOpen={setOpen}\n onScrollTo={subPages ? setOpen : spy.scrollTo}\n ariaLabel={schema.name}\n header={filterField}\n showCounts={query.trim() !== ''}\n />\n {group === null ? (\n <div className={s.pane}>\n <NoMatches query={query} onClear={onClearFilter} />\n </div>\n ) : (\n <PrefsPane ctx={ctx} group={group} path={open} scrollRef={scrollRef} />\n )}\n </div>\n );\n}\n\n/**\n * The group a rail path opens. The empty path is the root's loose leaves,\n * which belong to no group of their own and are handed back as one named for\n * the schema — the rail lists them under the same name.\n */\nfunction paneGroup(root: PrefGroup, path: string, rootName: string): PrefGroup | null {\n if (path === '') {\n const children = Object.fromEntries(\n Object.entries(root.children).filter(([, child]) => isPrefLeaf(child)),\n );\n return Object.keys(children).length === 0\n ? null\n : { ...root, name: rootName, children };\n }\n let node: PrefGroup | undefined;\n let cursor = root;\n for (const seg of path.split('.')) {\n const next = cursor.children[seg];\n if (next === undefined || isPrefLeaf(next)) return null;\n node = next;\n cursor = next;\n }\n return node ?? null;\n}\n\n/** Whether a group holds any leaf directly, not counting its subgroups. */\nfunction hasLeaves(group: PrefGroup | null): boolean {\n return group !== null && Object.values(group.children).some(isPrefLeaf);\n}\n\n/** A group cut down to its direct leaves, for a page its subgroups each get their own of. */\nfunction leavesOf(group: PrefGroup): PrefGroup {\n return {\n ...group,\n children: Object.fromEntries(\n Object.entries(group.children).filter(([, child]) => isPrefLeaf(child)),\n ),\n };\n}\n\n/** What a filter matching nothing leaves behind. */\nfunction NoMatches({ query, onClear }: { query: string; onClear: () => void }) {\n return (\n <div className={s.noMatches}>\n <p>No settings match “{query.trim()}”.</p>\n <button type=\"button\" className={s.clearFilter} onClick={onClear}>\n Clear filter\n </button>\n </div>\n );\n}\n\nfunction GroupBody({ ctx, group, path, depth }: {\n ctx: WalkCtx;\n group: PrefGroup;\n path: string;\n depth: number;\n}) {\n return (\n <div className={depth === 0 ? s.panel : s.subpanel}>\n <div className={s.groupHeader}>\n <h3 className={s.groupTitle}>{group.name}</h3>\n {group.description !== undefined && (\n <p className={s.groupDesc}>{group.description}</p>\n )}\n </div>\n <div className={s.rows}>\n {Object.entries(group.children).map(([key, child]) => {\n const childPath = `${path}.${key}`;\n return isPrefLeaf(child) ? (\n <PrefRow key={key} ctx={ctx} path={childPath} pref={child} />\n ) : (\n <GroupBody key={key} ctx={ctx} group={child} path={childPath} depth={depth + 1} />\n );\n })}\n </div>\n </div>\n );\n}\n\n","import type { ReactNode } from 'react';\nimport { Dialog } from '../Dialog';\nimport { PrefsForm, type PrefsFormProps } from './PrefsForm';\nimport s from './Prefs.module.css';\n\n/**\n * Props for {@link PrefsDialog} — everything {@link PrefsForm} takes, plus\n * the dialog's own open state and chrome.\n */\nexport interface PrefsDialogProps extends PrefsFormProps {\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n /** Dialog heading. Defaults to the schema root's `name`. */\n title?: ReactNode;\n /** Extra chrome rendered at the end of the title row (e.g. a dev-mode\n * \"Show hidden\" switch). An action the reader acts on when they are done\n * — resetting, importing — belongs in `footer` instead, where a dialog's\n * actions live. */\n headerExtra?: ReactNode;\n /** Footer slot, passed through to `Dialog` — typically a reset or done\n * action. */\n footer?: ReactNode;\n /** Class applied to the dialog's modal box. */\n dialogClassName?: string;\n}\n\n/**\n * The kit's preferences dialog: `Dialog` + `PrefsForm`. Changes apply\n * live through `onChange` — there is no OK/Cancel staging. For custom\n * placement (sidebar, popover, inline page), compose `PrefsForm`\n * directly; this wrapper is intentionally thin.\n *\n * `layout=\"rail\"` is what a dialog usually wants: the default columns wrap\n * sideways past two groups, and this box is 900px at its widest.\n */\nexport function PrefsDialog(props: PrefsDialogProps) {\n const { isOpen, onOpenChange, title, headerExtra, footer, dialogClassName, ...form } = props;\n const rail = form.layout === 'rail';\n return (\n <Dialog\n isOpen={isOpen}\n onOpenChange={onOpenChange}\n aria-label={typeof title === 'string' ? title : form.schema.name}\n className={dialogClassName}\n footer={footer}\n bodyClassName={rail ? s.railBody : undefined}\n title={\n headerExtra !== undefined ? (\n <span className={s.titleRow}>\n <span>{title ?? form.schema.name}</span>\n {headerExtra}\n </span>\n ) : (\n title ?? form.schema.name\n )\n }\n >\n <PrefsForm {...form} />\n </Dialog>\n );\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"PropertyField-CWUtNK1w.js","names":["s","TooltipTrigger","Tooltip","SliderTrack","_Fragment","s","shared","_exhaustive","_Fragment","s","Switch","sharedCheckbox","Input","RadioGroup","Radio","Select","dlog","Tooltip$1","TooltipTrigger$1","useStance","range_module_default","ColorField","Select$1","FontFamilySelect","FontWeightSelect","Input$1","endlessAt","ToggleBar","labelForms","FitLabel","spinKey","UnitField","PaintInput","PaintField","RadioGroup$1","Radio$1","Switch$1","checkbox_module_default","Properties_module_default","DENSITY_CLASS","ALIGN_CLASS","propertyMetricClass","base","density","align","className","PanelNesting","createContext","PropertyPanel","nested","useContext","attrs","heading","title","selectable","stance","actions","PropertyList","forwardRef","pack","PropertySpan","PropertyNote","PropertyRow","variantClass","variant","intrinsic","resolved","layout","layoutClass","cls","span","auto","autoControl","trailing","readout","rowRef","useRef","labelRef","multiline","useMultiline","head","onAutoChange","AutoToggle","label","hint","description","PropertyHelp","tail","multi","group","children","setMultiline","useState","useLayoutEffect","row","enabled","observer","labelStyle","lineHeight","floor","labelWraps","tallChild","child","name","toggle","e","onChange","Focusable","useSliderDraft","draft","setDraft","p","onInput","next","SliderRow","control","boxedReadout","SliderReadout","SliderTrack$1","SliderCell","props","Fragment","useCommitListener","ref","latest","commit","useEffect","el","onCommit","unitSuffix","unit","ignore","NumberInput","known","isKnown","input","stepDisplay","decimal","step","sliderBounds","min","max","v","live","range","settle","raw","value","EditableReadout","text","format","n","qty","display","read","parseAs","typed","displayValue","fit","onTrack","PropertyField","field","id","useId","nameOf","controlClassName","shape","rowShape","rowClassName","ControlBody","PropertyControl","BooleanControl","StringControl","EnumControl","ColorControl","PaintControl","Dimmed","mixed","unset","on","box","useTextEdit","drafting","edit","placeholder","glyphTip","o","current","opt","lit","added","onClear","splitAlpha","eight","toHex8","getAlpha01","withAlpha","apart","split","alpha","route","hex","own","write","a","settled","withAlpha01","Editor"],"sources":["../../src/components/Properties/Properties.module.css","../../src/components/Properties/PropertyPanel.tsx","../../src/components/Properties/NumberControls.tsx","../../src/components/Properties/PropertyField.tsx"],"sourcesContent":["/* One stylesheet for the whole property-panel family. PropertyList, PropertyRow,\n PropertyGroup and Subpanel are styled together because the grid\n rules genuinely cross components — `.listPairs > .subpanel` and\n `.groupBody > :not(.rowColor)` name two components in one selector, and a CSS\n Module can only compose local names within its own file. */\n\n/* Authored against a border-box reset (labkit's `.lk-root *`). weasel-ui has no\n global reset, so the family restates it over its own subtrees. */\n.panel,\n.list,\n.row,\n.group,\n.subpanel,\n.panel *,\n.list *,\n.row *,\n.group *,\n.subpanel * {\n box-sizing: border-box;\n}\n\n/* A panel is chrome: a drag across it should move a slider, not paint a\n selection over its labels. What the family shows as a value stays copyable,\n and a field stays one — Safari carries `none` into an input's caret. */\n.panel,\n.list,\n.row,\n.group,\n.subpanel {\n -webkit-user-select: none;\n user-select: none;\n}\n\n/* Opted in with `selectable` (a debug panel's default): the whole family lets\n text select, reaching past each member's own `none`. */\n.panel[data-selectable='true'],\n.panel[data-selectable='true'] :is(.panel, .list, .row, .group, .subpanel, .card, .cardList) {\n -webkit-user-select: text;\n user-select: text;\n}\n\n.readout,\n.readoutInput,\n.row input:not([type='range']):not([type='checkbox']):not([type='radio']),\n.row textarea,\n.row [contenteditable] {\n -webkit-user-select: text;\n user-select: text;\n}\n\n/* ── Container metrics ──────────────────────────────────────────────\n Every spacing number the family lays out with is read from a `--wzl-prop-*`\n custom property with its own value as the fallback, so a consumer can move\n any of them from an ancestor without selector surgery. The `density` classes\n below set them in preset bundles; nothing in this file declares one, so an\n inherited value always reaches the use site. */\n\n.panel {\n background: var(--_s-fill);\n border: var(--_s-border-width) var(--_s-border-style) var(--_s-border-color);\n border-radius: var(--_s-radius);\n padding: var(--_s-pad);\n backdrop-filter: blur(var(--_s-blur));\n -webkit-backdrop-filter: blur(var(--_s-blur));\n}\n\n.panel[data-stance='preview'] {\n overflow: hidden;\n}\n\n\n.panelTitle {\n font-family: var(--_s-title-font);\n font-weight: var(--_s-title-weight);\n font-size: var(--_s-title-size);\n line-height: var(--wzl-leading-snug);\n letter-spacing: var(--_s-title-tracking);\n text-transform: var(--_s-title-case);\n color: var(--_s-title-color);\n padding: var(--_s-title-inset);\n margin: 0 0 var(--wzl-prop-panel-title-gap, 12px);\n}\n\n.panelHeader {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-4);\n margin: 0 0 var(--wzl-prop-panel-title-gap, 12px);\n}\n\n.panelHeader > .panelTitle {\n flex: 1 1 auto;\n min-width: 0;\n margin: 0;\n}\n\n.panelActions {\n display: flex;\n flex: none;\n align-items: center;\n gap: var(--wzl-space-2);\n margin-inline-start: auto;\n}\n\n/* Each panel resolves its slots into local names: the stance's own value,\n then — nested — the stance's nested value, falling back to the panel's base\n slot. The slots are @weasel-js/theme's STANCE_SLOTS. */\n/* BEGIN GENERATED stance rules: panel — `npm run gen:stances`, do not edit. */\n\n.panel {\n --wzl-tone: initial;\n}\n\n.panel {\n --_s-surface: var(--wzl-panel-surface);\n --_s-border-color: var(--wzl-panel-border-color);\n --_s-border-style: var(--wzl-panel-border-style);\n --_s-border-width: var(--wzl-panel-border-width);\n --_s-radius: var(--wzl-panel-radius);\n --_s-pad: var(--wzl-prop-panel-pad, var(--wzl-panel-pad));\n --_s-blur: var(--wzl-panel-blur);\n --_s-tone-mix: var(--wzl-panel-tone-mix);\n --_s-tone: var(--wzl-tone, var(--_s-surface));\n --_s-accent: var(--wzl-tone);\n --_s-title-font: var(--wzl-panel-title-font);\n --_s-title-weight: var(--wzl-panel-title-weight);\n --_s-title-size: var(--wzl-panel-title-size);\n --_s-title-case: var(--wzl-panel-title-case);\n --_s-title-tracking: var(--wzl-panel-title-tracking);\n --_s-title-color: var(--wzl-panel-title-color);\n --_s-title-inset: var(--wzl-panel-title-inset);\n}\n\n.panel[data-stance='scope'] {\n --_s-surface: var(--wzl-stance-scope-surface, var(--wzl-panel-surface));\n --_s-border-color: var(--wzl-stance-scope-border-color, var(--wzl-panel-border-color));\n --_s-border-style: var(--wzl-stance-scope-border-style, var(--wzl-panel-border-style));\n --_s-border-width: var(--wzl-stance-scope-border-width, var(--wzl-panel-border-width));\n --_s-radius: var(--wzl-stance-scope-radius, var(--wzl-panel-radius));\n --_s-pad: var(--wzl-stance-scope-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad)));\n --_s-blur: var(--wzl-stance-scope-blur, var(--wzl-panel-blur));\n --_s-tone-mix: var(--wzl-stance-scope-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-scope-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-scope-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-scope-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-scope-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-scope-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-scope-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-scope-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide)));\n --_s-title-color: var(--wzl-stance-scope-title-color, var(--wzl-fg-muted));\n --_s-title-inset: var(--wzl-stance-scope-title-inset, var(--wzl-panel-title-inset));\n}\n\n.panel[data-stance='scope'][data-nested] {\n --_s-surface: var(--wzl-stance-scope-nested-surface, var(--wzl-stance-scope-surface, var(--wzl-panel-surface)));\n --_s-border-color: var(--wzl-stance-scope-nested-border-color, var(--wzl-stance-scope-border-color, var(--wzl-panel-border-color)));\n --_s-border-style: var(--wzl-stance-scope-nested-border-style, var(--wzl-stance-scope-border-style, var(--wzl-panel-border-style)));\n --_s-border-width: var(--wzl-stance-scope-nested-border-width, var(--wzl-stance-scope-border-width, var(--wzl-panel-border-width)));\n --_s-radius: var(--wzl-stance-scope-nested-radius, var(--wzl-stance-scope-radius, var(--wzl-panel-radius)));\n --_s-pad: var(--wzl-stance-scope-nested-pad, var(--wzl-stance-scope-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad))));\n --_s-blur: var(--wzl-stance-scope-nested-blur, var(--wzl-stance-scope-blur, var(--wzl-panel-blur)));\n --_s-tone-mix: var(--wzl-stance-scope-nested-tone-mix, var(--wzl-stance-scope-tone-mix, var(--wzl-panel-tone-mix)));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-scope-nested-tone, var(--wzl-stance-scope-tone, var(--_s-surface))));\n --_s-accent: var(--wzl-stance-scope-nested-accent, var(--wzl-stance-scope-accent, var(--wzl-tone)));\n --_s-title-font: var(--wzl-stance-scope-nested-title-font, var(--wzl-stance-scope-title-font, var(--wzl-font-display)));\n --_s-title-weight: var(--wzl-stance-scope-nested-title-weight, var(--wzl-stance-scope-title-weight, var(--wzl-font-weight-light)));\n --_s-title-size: var(--wzl-stance-scope-nested-title-size, var(--wzl-stance-scope-title-size, var(--wzl-font-size-sm)));\n --_s-title-case: var(--wzl-stance-scope-nested-title-case, var(--wzl-stance-scope-title-case, var(--wzl-params-label-case, uppercase)));\n --_s-title-tracking: var(--wzl-stance-scope-nested-title-tracking, var(--wzl-stance-scope-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide))));\n --_s-title-color: var(--wzl-stance-scope-nested-title-color, var(--wzl-stance-scope-title-color, var(--wzl-fg-muted)));\n --_s-title-inset: var(--wzl-stance-scope-nested-title-inset, var(--wzl-stance-scope-title-inset, var(--wzl-panel-title-inset)));\n}\n\n.panel[data-stance='aside'] {\n --_s-surface: var(--wzl-stance-aside-surface, var(--wzl-panel-surface));\n --_s-border-color: var(--wzl-stance-aside-border-color, var(--wzl-panel-border-color));\n --_s-border-style: var(--wzl-stance-aside-border-style, var(--wzl-panel-border-style));\n --_s-border-width: var(--wzl-stance-aside-border-width, var(--wzl-panel-border-width));\n --_s-radius: var(--wzl-stance-aside-radius, var(--wzl-panel-radius));\n --_s-pad: var(--wzl-stance-aside-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad)));\n --_s-blur: var(--wzl-stance-aside-blur, var(--wzl-panel-blur));\n --_s-tone-mix: var(--wzl-stance-aside-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-aside-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-aside-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-aside-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-aside-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-aside-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-aside-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-aside-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide)));\n --_s-title-color: var(--wzl-stance-aside-title-color, var(--wzl-fg-muted));\n --_s-title-inset: var(--wzl-stance-aside-title-inset, var(--wzl-panel-title-inset));\n}\n\n.panel[data-stance='aside'][data-nested] {\n --_s-surface: var(--wzl-stance-aside-nested-surface, var(--wzl-stance-aside-surface, var(--wzl-panel-surface)));\n --_s-border-color: var(--wzl-stance-aside-nested-border-color, var(--wzl-stance-aside-border-color, var(--wzl-panel-border-color)));\n --_s-border-style: var(--wzl-stance-aside-nested-border-style, var(--wzl-stance-aside-border-style, var(--wzl-panel-border-style)));\n --_s-border-width: var(--wzl-stance-aside-nested-border-width, var(--wzl-stance-aside-border-width, var(--wzl-panel-border-width)));\n --_s-radius: var(--wzl-stance-aside-nested-radius, var(--wzl-stance-aside-radius, var(--wzl-panel-radius)));\n --_s-pad: var(--wzl-stance-aside-nested-pad, var(--wzl-stance-aside-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad))));\n --_s-blur: var(--wzl-stance-aside-nested-blur, var(--wzl-stance-aside-blur, var(--wzl-panel-blur)));\n --_s-tone-mix: var(--wzl-stance-aside-nested-tone-mix, var(--wzl-stance-aside-tone-mix, var(--wzl-panel-tone-mix)));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-aside-nested-tone, var(--wzl-stance-aside-tone, var(--_s-surface))));\n --_s-accent: var(--wzl-stance-aside-nested-accent, var(--wzl-stance-aside-accent, var(--wzl-tone)));\n --_s-title-font: var(--wzl-stance-aside-nested-title-font, var(--wzl-stance-aside-title-font, var(--wzl-font-display)));\n --_s-title-weight: var(--wzl-stance-aside-nested-title-weight, var(--wzl-stance-aside-title-weight, var(--wzl-font-weight-light)));\n --_s-title-size: var(--wzl-stance-aside-nested-title-size, var(--wzl-stance-aside-title-size, var(--wzl-font-size-sm)));\n --_s-title-case: var(--wzl-stance-aside-nested-title-case, var(--wzl-stance-aside-title-case, var(--wzl-params-label-case, uppercase)));\n --_s-title-tracking: var(--wzl-stance-aside-nested-title-tracking, var(--wzl-stance-aside-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide))));\n --_s-title-color: var(--wzl-stance-aside-nested-title-color, var(--wzl-stance-aside-title-color, var(--wzl-fg-muted)));\n --_s-title-inset: var(--wzl-stance-aside-nested-title-inset, var(--wzl-stance-aside-title-inset, var(--wzl-panel-title-inset)));\n}\n\n.panel[data-stance='advanced'] {\n --_s-surface: var(--wzl-stance-advanced-surface, var(--wzl-panel-surface));\n --_s-border-color: var(--wzl-stance-advanced-border-color, var(--wzl-panel-border-color));\n --_s-border-style: var(--wzl-stance-advanced-border-style, var(--wzl-panel-border-style));\n --_s-border-width: var(--wzl-stance-advanced-border-width, var(--wzl-panel-border-width));\n --_s-radius: var(--wzl-stance-advanced-radius, var(--wzl-panel-radius));\n --_s-pad: var(--wzl-stance-advanced-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad)));\n --_s-blur: var(--wzl-stance-advanced-blur, var(--wzl-panel-blur));\n --_s-tone-mix: var(--wzl-stance-advanced-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-advanced-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-advanced-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-advanced-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-advanced-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-advanced-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-advanced-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-advanced-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide)));\n --_s-title-color: var(--wzl-stance-advanced-title-color, var(--wzl-fg-muted));\n --_s-title-inset: var(--wzl-stance-advanced-title-inset, var(--wzl-panel-title-inset));\n}\n\n.panel[data-stance='advanced'][data-nested] {\n --_s-surface: var(--wzl-stance-advanced-nested-surface, var(--wzl-stance-advanced-surface, var(--wzl-panel-surface)));\n --_s-border-color: var(--wzl-stance-advanced-nested-border-color, var(--wzl-stance-advanced-border-color, var(--wzl-panel-border-color)));\n --_s-border-style: var(--wzl-stance-advanced-nested-border-style, var(--wzl-stance-advanced-border-style, var(--wzl-panel-border-style)));\n --_s-border-width: var(--wzl-stance-advanced-nested-border-width, var(--wzl-stance-advanced-border-width, var(--wzl-panel-border-width)));\n --_s-radius: var(--wzl-stance-advanced-nested-radius, var(--wzl-stance-advanced-radius, var(--wzl-panel-radius)));\n --_s-pad: var(--wzl-stance-advanced-nested-pad, var(--wzl-stance-advanced-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad))));\n --_s-blur: var(--wzl-stance-advanced-nested-blur, var(--wzl-stance-advanced-blur, var(--wzl-panel-blur)));\n --_s-tone-mix: var(--wzl-stance-advanced-nested-tone-mix, var(--wzl-stance-advanced-tone-mix, var(--wzl-panel-tone-mix)));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-advanced-nested-tone, var(--wzl-stance-advanced-tone, var(--_s-surface))));\n --_s-accent: var(--wzl-stance-advanced-nested-accent, var(--wzl-stance-advanced-accent, var(--wzl-tone)));\n --_s-title-font: var(--wzl-stance-advanced-nested-title-font, var(--wzl-stance-advanced-title-font, var(--wzl-font-display)));\n --_s-title-weight: var(--wzl-stance-advanced-nested-title-weight, var(--wzl-stance-advanced-title-weight, var(--wzl-font-weight-light)));\n --_s-title-size: var(--wzl-stance-advanced-nested-title-size, var(--wzl-stance-advanced-title-size, var(--wzl-font-size-sm)));\n --_s-title-case: var(--wzl-stance-advanced-nested-title-case, var(--wzl-stance-advanced-title-case, var(--wzl-params-label-case, uppercase)));\n --_s-title-tracking: var(--wzl-stance-advanced-nested-title-tracking, var(--wzl-stance-advanced-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide))));\n --_s-title-color: var(--wzl-stance-advanced-nested-title-color, var(--wzl-stance-advanced-title-color, var(--wzl-fg-muted)));\n --_s-title-inset: var(--wzl-stance-advanced-nested-title-inset, var(--wzl-stance-advanced-title-inset, var(--wzl-panel-title-inset)));\n}\n\n.panel[data-stance='debug'] {\n --_s-surface: var(--wzl-stance-debug-surface, var(--wzl-panel-surface));\n --_s-border-color: var(--wzl-stance-debug-border-color, var(--wzl-panel-border-color));\n --_s-border-style: var(--wzl-stance-debug-border-style, var(--wzl-panel-border-style));\n --_s-border-width: var(--wzl-stance-debug-border-width, var(--wzl-panel-border-width));\n --_s-radius: var(--wzl-stance-debug-radius, var(--wzl-panel-radius));\n --_s-pad: var(--wzl-stance-debug-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad)));\n --_s-blur: var(--wzl-stance-debug-blur, var(--wzl-panel-blur));\n --_s-tone-mix: var(--wzl-stance-debug-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-debug-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-debug-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-debug-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-debug-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-debug-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-debug-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-debug-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide)));\n --_s-title-color: var(--wzl-stance-debug-title-color, var(--wzl-fg-muted));\n --_s-title-inset: var(--wzl-stance-debug-title-inset, var(--wzl-panel-title-inset));\n}\n\n.panel[data-stance='debug'][data-nested] {\n --_s-surface: var(--wzl-stance-debug-nested-surface, var(--wzl-stance-debug-surface, var(--wzl-panel-surface)));\n --_s-border-color: var(--wzl-stance-debug-nested-border-color, var(--wzl-stance-debug-border-color, var(--wzl-panel-border-color)));\n --_s-border-style: var(--wzl-stance-debug-nested-border-style, var(--wzl-stance-debug-border-style, var(--wzl-panel-border-style)));\n --_s-border-width: var(--wzl-stance-debug-nested-border-width, var(--wzl-stance-debug-border-width, var(--wzl-panel-border-width)));\n --_s-radius: var(--wzl-stance-debug-nested-radius, var(--wzl-stance-debug-radius, var(--wzl-panel-radius)));\n --_s-pad: var(--wzl-stance-debug-nested-pad, var(--wzl-stance-debug-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad))));\n --_s-blur: var(--wzl-stance-debug-nested-blur, var(--wzl-stance-debug-blur, var(--wzl-panel-blur)));\n --_s-tone-mix: var(--wzl-stance-debug-nested-tone-mix, var(--wzl-stance-debug-tone-mix, var(--wzl-panel-tone-mix)));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-debug-nested-tone, var(--wzl-stance-debug-tone, var(--_s-surface))));\n --_s-accent: var(--wzl-stance-debug-nested-accent, var(--wzl-stance-debug-accent, var(--wzl-tone)));\n --_s-title-font: var(--wzl-stance-debug-nested-title-font, var(--wzl-stance-debug-title-font, var(--wzl-font-display)));\n --_s-title-weight: var(--wzl-stance-debug-nested-title-weight, var(--wzl-stance-debug-title-weight, var(--wzl-font-weight-light)));\n --_s-title-size: var(--wzl-stance-debug-nested-title-size, var(--wzl-stance-debug-title-size, var(--wzl-font-size-sm)));\n --_s-title-case: var(--wzl-stance-debug-nested-title-case, var(--wzl-stance-debug-title-case, var(--wzl-params-label-case, uppercase)));\n --_s-title-tracking: var(--wzl-stance-debug-nested-title-tracking, var(--wzl-stance-debug-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide))));\n --_s-title-color: var(--wzl-stance-debug-nested-title-color, var(--wzl-stance-debug-title-color, var(--wzl-fg-muted)));\n --_s-title-inset: var(--wzl-stance-debug-nested-title-inset, var(--wzl-stance-debug-title-inset, var(--wzl-panel-title-inset)));\n}\n\n.panel[data-stance='danger'] {\n --_s-surface: var(--wzl-stance-danger-surface, var(--wzl-panel-surface));\n --_s-border-color: var(--wzl-stance-danger-border-color, var(--wzl-panel-border-color));\n --_s-border-style: var(--wzl-stance-danger-border-style, var(--wzl-panel-border-style));\n --_s-border-width: var(--wzl-stance-danger-border-width, var(--wzl-panel-border-width));\n --_s-radius: var(--wzl-stance-danger-radius, var(--wzl-panel-radius));\n --_s-pad: var(--wzl-stance-danger-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad)));\n --_s-blur: var(--wzl-stance-danger-blur, var(--wzl-panel-blur));\n --_s-tone-mix: var(--wzl-stance-danger-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-danger-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-danger-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-danger-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-danger-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-danger-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-danger-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-danger-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide)));\n --_s-title-color: var(--wzl-stance-danger-title-color, var(--wzl-fg-muted));\n --_s-title-inset: var(--wzl-stance-danger-title-inset, var(--wzl-panel-title-inset));\n}\n\n.panel[data-stance='danger'][data-nested] {\n --_s-surface: var(--wzl-stance-danger-nested-surface, var(--wzl-stance-danger-surface, var(--wzl-panel-surface)));\n --_s-border-color: var(--wzl-stance-danger-nested-border-color, var(--wzl-stance-danger-border-color, var(--wzl-panel-border-color)));\n --_s-border-style: var(--wzl-stance-danger-nested-border-style, var(--wzl-stance-danger-border-style, var(--wzl-panel-border-style)));\n --_s-border-width: var(--wzl-stance-danger-nested-border-width, var(--wzl-stance-danger-border-width, var(--wzl-panel-border-width)));\n --_s-radius: var(--wzl-stance-danger-nested-radius, var(--wzl-stance-danger-radius, var(--wzl-panel-radius)));\n --_s-pad: var(--wzl-stance-danger-nested-pad, var(--wzl-stance-danger-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad))));\n --_s-blur: var(--wzl-stance-danger-nested-blur, var(--wzl-stance-danger-blur, var(--wzl-panel-blur)));\n --_s-tone-mix: var(--wzl-stance-danger-nested-tone-mix, var(--wzl-stance-danger-tone-mix, var(--wzl-panel-tone-mix)));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-danger-nested-tone, var(--wzl-stance-danger-tone, var(--_s-surface))));\n --_s-accent: var(--wzl-stance-danger-nested-accent, var(--wzl-stance-danger-accent, var(--wzl-tone)));\n --_s-title-font: var(--wzl-stance-danger-nested-title-font, var(--wzl-stance-danger-title-font, var(--wzl-font-display)));\n --_s-title-weight: var(--wzl-stance-danger-nested-title-weight, var(--wzl-stance-danger-title-weight, var(--wzl-font-weight-light)));\n --_s-title-size: var(--wzl-stance-danger-nested-title-size, var(--wzl-stance-danger-title-size, var(--wzl-font-size-sm)));\n --_s-title-case: var(--wzl-stance-danger-nested-title-case, var(--wzl-stance-danger-title-case, var(--wzl-params-label-case, uppercase)));\n --_s-title-tracking: var(--wzl-stance-danger-nested-title-tracking, var(--wzl-stance-danger-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide))));\n --_s-title-color: var(--wzl-stance-danger-nested-title-color, var(--wzl-stance-danger-title-color, var(--wzl-fg-muted)));\n --_s-title-inset: var(--wzl-stance-danger-nested-title-inset, var(--wzl-stance-danger-title-inset, var(--wzl-panel-title-inset)));\n}\n\n.panel[data-stance='notice'] {\n --_s-surface: var(--wzl-stance-notice-surface, var(--wzl-panel-surface));\n --_s-border-color: var(--wzl-stance-notice-border-color, var(--wzl-panel-border-color));\n --_s-border-style: var(--wzl-stance-notice-border-style, var(--wzl-panel-border-style));\n --_s-border-width: var(--wzl-stance-notice-border-width, var(--wzl-panel-border-width));\n --_s-radius: var(--wzl-stance-notice-radius, var(--wzl-panel-radius));\n --_s-pad: var(--wzl-stance-notice-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad)));\n --_s-blur: var(--wzl-stance-notice-blur, var(--wzl-panel-blur));\n --_s-tone-mix: var(--wzl-stance-notice-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-notice-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-notice-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-notice-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-notice-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-notice-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-notice-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-notice-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide)));\n --_s-title-color: var(--wzl-stance-notice-title-color, var(--wzl-fg-muted));\n --_s-title-inset: var(--wzl-stance-notice-title-inset, var(--wzl-panel-title-inset));\n}\n\n.panel[data-stance='notice'][data-nested] {\n --_s-surface: var(--wzl-stance-notice-nested-surface, var(--wzl-stance-notice-surface, var(--wzl-panel-surface)));\n --_s-border-color: var(--wzl-stance-notice-nested-border-color, var(--wzl-stance-notice-border-color, var(--wzl-panel-border-color)));\n --_s-border-style: var(--wzl-stance-notice-nested-border-style, var(--wzl-stance-notice-border-style, var(--wzl-panel-border-style)));\n --_s-border-width: var(--wzl-stance-notice-nested-border-width, var(--wzl-stance-notice-border-width, var(--wzl-panel-border-width)));\n --_s-radius: var(--wzl-stance-notice-nested-radius, var(--wzl-stance-notice-radius, var(--wzl-panel-radius)));\n --_s-pad: var(--wzl-stance-notice-nested-pad, var(--wzl-stance-notice-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad))));\n --_s-blur: var(--wzl-stance-notice-nested-blur, var(--wzl-stance-notice-blur, var(--wzl-panel-blur)));\n --_s-tone-mix: var(--wzl-stance-notice-nested-tone-mix, var(--wzl-stance-notice-tone-mix, var(--wzl-panel-tone-mix)));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-notice-nested-tone, var(--wzl-stance-notice-tone, var(--_s-surface))));\n --_s-accent: var(--wzl-stance-notice-nested-accent, var(--wzl-stance-notice-accent, var(--wzl-tone)));\n --_s-title-font: var(--wzl-stance-notice-nested-title-font, var(--wzl-stance-notice-title-font, var(--wzl-font-display)));\n --_s-title-weight: var(--wzl-stance-notice-nested-title-weight, var(--wzl-stance-notice-title-weight, var(--wzl-font-weight-light)));\n --_s-title-size: var(--wzl-stance-notice-nested-title-size, var(--wzl-stance-notice-title-size, var(--wzl-font-size-sm)));\n --_s-title-case: var(--wzl-stance-notice-nested-title-case, var(--wzl-stance-notice-title-case, var(--wzl-params-label-case, uppercase)));\n --_s-title-tracking: var(--wzl-stance-notice-nested-title-tracking, var(--wzl-stance-notice-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide))));\n --_s-title-color: var(--wzl-stance-notice-nested-title-color, var(--wzl-stance-notice-title-color, var(--wzl-fg-muted)));\n --_s-title-inset: var(--wzl-stance-notice-nested-title-inset, var(--wzl-stance-notice-title-inset, var(--wzl-panel-title-inset)));\n}\n\n.panel[data-stance='important'] {\n --_s-surface: var(--wzl-stance-important-surface, var(--wzl-panel-surface));\n --_s-border-color: var(--wzl-stance-important-border-color, var(--wzl-panel-border-color));\n --_s-border-style: var(--wzl-stance-important-border-style, var(--wzl-panel-border-style));\n --_s-border-width: var(--wzl-stance-important-border-width, var(--wzl-panel-border-width));\n --_s-radius: var(--wzl-stance-important-radius, var(--wzl-panel-radius));\n --_s-pad: var(--wzl-stance-important-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad)));\n --_s-blur: var(--wzl-stance-important-blur, var(--wzl-panel-blur));\n --_s-tone-mix: var(--wzl-stance-important-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-important-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-important-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-important-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-important-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-important-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-important-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-important-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide)));\n --_s-title-color: var(--wzl-stance-important-title-color, var(--wzl-fg-muted));\n --_s-title-inset: var(--wzl-stance-important-title-inset, var(--wzl-panel-title-inset));\n}\n\n.panel[data-stance='important'][data-nested] {\n --_s-surface: var(--wzl-stance-important-nested-surface, var(--wzl-stance-important-surface, var(--wzl-panel-surface)));\n --_s-border-color: var(--wzl-stance-important-nested-border-color, var(--wzl-stance-important-border-color, var(--wzl-panel-border-color)));\n --_s-border-style: var(--wzl-stance-important-nested-border-style, var(--wzl-stance-important-border-style, var(--wzl-panel-border-style)));\n --_s-border-width: var(--wzl-stance-important-nested-border-width, var(--wzl-stance-important-border-width, var(--wzl-panel-border-width)));\n --_s-radius: var(--wzl-stance-important-nested-radius, var(--wzl-stance-important-radius, var(--wzl-panel-radius)));\n --_s-pad: var(--wzl-stance-important-nested-pad, var(--wzl-stance-important-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad))));\n --_s-blur: var(--wzl-stance-important-nested-blur, var(--wzl-stance-important-blur, var(--wzl-panel-blur)));\n --_s-tone-mix: var(--wzl-stance-important-nested-tone-mix, var(--wzl-stance-important-tone-mix, var(--wzl-panel-tone-mix)));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-important-nested-tone, var(--wzl-stance-important-tone, var(--_s-surface))));\n --_s-accent: var(--wzl-stance-important-nested-accent, var(--wzl-stance-important-accent, var(--wzl-tone)));\n --_s-title-font: var(--wzl-stance-important-nested-title-font, var(--wzl-stance-important-title-font, var(--wzl-font-display)));\n --_s-title-weight: var(--wzl-stance-important-nested-title-weight, var(--wzl-stance-important-title-weight, var(--wzl-font-weight-light)));\n --_s-title-size: var(--wzl-stance-important-nested-title-size, var(--wzl-stance-important-title-size, var(--wzl-font-size-sm)));\n --_s-title-case: var(--wzl-stance-important-nested-title-case, var(--wzl-stance-important-title-case, var(--wzl-params-label-case, uppercase)));\n --_s-title-tracking: var(--wzl-stance-important-nested-title-tracking, var(--wzl-stance-important-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide))));\n --_s-title-color: var(--wzl-stance-important-nested-title-color, var(--wzl-stance-important-title-color, var(--wzl-fg-muted)));\n --_s-title-inset: var(--wzl-stance-important-nested-title-inset, var(--wzl-stance-important-title-inset, var(--wzl-panel-title-inset)));\n}\n\n.panel[data-stance='preview'] {\n --_s-surface: var(--wzl-stance-preview-surface, var(--wzl-panel-surface));\n --_s-border-color: var(--wzl-stance-preview-border-color, var(--wzl-panel-border-color));\n --_s-border-style: var(--wzl-stance-preview-border-style, var(--wzl-panel-border-style));\n --_s-border-width: var(--wzl-stance-preview-border-width, var(--wzl-panel-border-width));\n --_s-radius: var(--wzl-stance-preview-radius, var(--wzl-panel-radius));\n --_s-pad: var(--wzl-stance-preview-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad)));\n --_s-blur: var(--wzl-stance-preview-blur, var(--wzl-panel-blur));\n --_s-tone-mix: var(--wzl-stance-preview-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-preview-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-preview-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-preview-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-preview-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-preview-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-preview-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-preview-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide)));\n --_s-title-color: var(--wzl-stance-preview-title-color, var(--wzl-fg-muted));\n --_s-title-inset: var(--wzl-stance-preview-title-inset, var(--wzl-panel-title-inset));\n}\n\n.panel[data-stance='preview'][data-nested] {\n --_s-surface: var(--wzl-stance-preview-nested-surface, var(--wzl-stance-preview-surface, var(--wzl-panel-surface)));\n --_s-border-color: var(--wzl-stance-preview-nested-border-color, var(--wzl-stance-preview-border-color, var(--wzl-panel-border-color)));\n --_s-border-style: var(--wzl-stance-preview-nested-border-style, var(--wzl-stance-preview-border-style, var(--wzl-panel-border-style)));\n --_s-border-width: var(--wzl-stance-preview-nested-border-width, var(--wzl-stance-preview-border-width, var(--wzl-panel-border-width)));\n --_s-radius: var(--wzl-stance-preview-nested-radius, var(--wzl-stance-preview-radius, var(--wzl-panel-radius)));\n --_s-pad: var(--wzl-stance-preview-nested-pad, var(--wzl-stance-preview-pad, var(--wzl-prop-panel-pad, var(--wzl-panel-pad))));\n --_s-blur: var(--wzl-stance-preview-nested-blur, var(--wzl-stance-preview-blur, var(--wzl-panel-blur)));\n --_s-tone-mix: var(--wzl-stance-preview-nested-tone-mix, var(--wzl-stance-preview-tone-mix, var(--wzl-panel-tone-mix)));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-preview-nested-tone, var(--wzl-stance-preview-tone, var(--_s-surface))));\n --_s-accent: var(--wzl-stance-preview-nested-accent, var(--wzl-stance-preview-accent, var(--wzl-tone)));\n --_s-title-font: var(--wzl-stance-preview-nested-title-font, var(--wzl-stance-preview-title-font, var(--wzl-font-display)));\n --_s-title-weight: var(--wzl-stance-preview-nested-title-weight, var(--wzl-stance-preview-title-weight, var(--wzl-font-weight-light)));\n --_s-title-size: var(--wzl-stance-preview-nested-title-size, var(--wzl-stance-preview-title-size, var(--wzl-font-size-sm)));\n --_s-title-case: var(--wzl-stance-preview-nested-title-case, var(--wzl-stance-preview-title-case, var(--wzl-params-label-case, uppercase)));\n --_s-title-tracking: var(--wzl-stance-preview-nested-title-tracking, var(--wzl-stance-preview-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wide))));\n --_s-title-color: var(--wzl-stance-preview-nested-title-color, var(--wzl-stance-preview-title-color, var(--wzl-fg-muted)));\n --_s-title-inset: var(--wzl-stance-preview-nested-title-inset, var(--wzl-stance-preview-title-inset, var(--wzl-panel-title-inset)));\n}\n\n.panel {\n --_s-fill: var(--_s-surface);\n}\n\n.panel[data-tone],\n.panel[data-stance] {\n --_s-fill: color-mix(in oklab, var(--_s-tone) var(--_s-tone-mix), var(--_s-surface));\n}\n\n.panel[data-tone] {\n --wzl-surface-sunken: oklch(from var(--_s-fill) calc(l - 0.06) c h);\n}\n\n.panel[data-tone] {\n --wzl-accent: var(--_s-accent);\n --wzl-accent-base: var(--_s-accent);\n --wzl-accent-strong: color-mix(in oklab, var(--_s-accent) 70%, var(--wzl-fg));\n --wzl-accent-soft: color-mix(in oklab, var(--_s-accent) 45%, var(--wzl-surface));\n --wzl-accent-hover: var(--wzl-accent-strong);\n --wzl-accent-fg: var(--wzl-accent-strong);\n --wzl-focus-ring: var(--wzl-accent-strong);\n}\n\n/* END GENERATED stance rules: panel */\n\n.list {\n display: grid;\n grid-template-columns: 1fr 1fr;\n column-gap: var(--wzl-prop-column-gap, 16px);\n row-gap: var(--wzl-prop-row-gap, 4px);\n align-items: stretch;\n /* A property panel is dense: its fields are shorter and tighter than a\n standalone Input. Mapped here, on the container, so one declaration moves\n every field in the panel — and read from the container-level name so a\n density set further up is not shadowed by this declaration. */\n --wzl-field-h: var(--wzl-prop-field-h, var(--wzl-control-h-sm));\n --wzl-field-pad-x: var(--wzl-prop-field-pad-x, 6px);\n /* A kit `<Select>` in a row is a field like any other, and its trigger reads\n its height from a standalone control's token rather than the panel's. */\n --wzl-select-h: var(--wzl-field-h);\n}\n\n/* Default packing: only color rows pair, everything else spans full width.\n Scoped to NOT apply in pairs mode (otherwise this 0,2,0 selector beats the\n pairs override below, which is only 0,1,0). */\n.list:not(.listPairs) > :not(.rowColor) {\n grid-column: 1 / -1;\n}\n\n/* `pack=\"pairs\"` flips that: every row auto-places into the 2-col grid two\n per row, and explicit full-width children opt in via the span helper class. */\n.listPairs > * {\n min-width: 0;\n}\n\n.listPairs > .span,\n.listPairs > .subpanel,\n.listPairs > h3 {\n grid-column: 1 / -1;\n}\n\n/* `pack=\"one-up\"` gives every row the full width, color rows included — the\n one packing a palette can be built from. */\n.listOneUp > * {\n grid-column: 1 / -1;\n}\n\n/* ── density ────────────────────────────────────────────────────────\n Preset bundles for the container metrics above. Set on whichever container\n the consumer puts `density` on; every metric inherits down from there, so a\n panel sets the whole family and a single group can still differ. `normal`\n states its values rather than omitting them, so a group can go back to the\n default inside a tighter panel. */\n\n.densityTight {\n --wzl-prop-row-gap: 2px;\n --wzl-prop-subpanel-row-gap: 2px;\n --wzl-prop-column-gap: 8px;\n --wzl-prop-panel-pad: 10px 12px;\n --wzl-prop-panel-title-gap: 8px;\n --wzl-prop-group-pad: 4px 8px 6px;\n --wzl-prop-group-title-gap: 2px;\n --wzl-prop-field-h: 18px;\n --wzl-prop-field-pad-x: 5px;\n}\n\n.densityNormal {\n --wzl-prop-row-gap: 4px;\n --wzl-prop-subpanel-row-gap: 3px;\n --wzl-prop-column-gap: 16px;\n --wzl-prop-panel-pad: 14px 16px;\n --wzl-prop-panel-title-gap: 12px;\n --wzl-prop-group-pad: 6px 10px 8px;\n --wzl-prop-group-title-gap: 4px;\n --wzl-prop-field-h: 20px;\n --wzl-prop-field-pad-x: 6px;\n}\n\n.densityRoomy {\n --wzl-prop-row-gap: 8px;\n --wzl-prop-subpanel-row-gap: 7px;\n --wzl-prop-column-gap: 20px;\n --wzl-prop-panel-pad: 18px 20px;\n --wzl-prop-panel-title-gap: 16px;\n --wzl-prop-group-pad: 10px 14px 12px;\n --wzl-prop-group-title-gap: 6px;\n --wzl-prop-field-h: 24px;\n --wzl-prop-field-pad-x: 8px;\n}\n\n/* ── align ──────────────────────────────────────────────────────────\n Where an inline row's label and control sit on the row's cross axis.\n Inherits like density does, so a column of color rows lines its swatches up\n on one edge from a single declaration on the list.\n\n Two names, because a color row aligns twice: its items within their grid row,\n and the whole grid within the row's box. They agree except at `baseline`,\n which `align-content` does not take — there the grid goes to the top and the\n items find the label's baseline inside it.\n\n A row whose label and control are both one line of text reads a third:\n centering two runs of different sizes leaves their baselines apart, so there\n `center` means `baseline`. */\n\n.alignStart {\n --wzl-prop-row-align: start;\n --wzl-prop-row-align-content: start;\n --wzl-prop-row-align-text: start;\n}\n\n.alignCenter {\n --wzl-prop-row-align: center;\n --wzl-prop-row-align-content: center;\n --wzl-prop-row-align-text: baseline;\n}\n\n.alignEnd {\n --wzl-prop-row-align: end;\n --wzl-prop-row-align-content: end;\n --wzl-prop-row-align-text: end;\n}\n\n.alignBaseline {\n --wzl-prop-row-align: baseline;\n --wzl-prop-row-align-content: start;\n --wzl-prop-row-align-text: baseline;\n}\n\n/* ── Row ────────────────────────────────────────────────────────\n Default shape: label on top (with optional right-aligned readout),\n control below. */\n\n.row {\n display: flex;\n flex-direction: column;\n /* Every row stands on the same floor, whatever it holds. A switch is 16px, a\n range track 12 and a field 20, so a column of mixed rows sets its own line\n spacing row by row and reads as ragged — which is what a reader sees first,\n long before any one control's height. Taller content still grows the row;\n this only stops a short one from collapsing under the field it sits beside. */\n min-height: var(--wzl-prop-row-h, var(--wzl-field-h, var(--wzl-control-h)));\n /* No gap by default — controls sit flush under their label, matching\n speech-balloons `.field { gap: 0 }`. Slider rows pull tighter still\n via a negative margin on the label below. */\n gap: 0;\n min-width: 0;\n}\n\n/* Slider rows: pull the track up under the label so the row reads as one\n tight block rather than a label + a separate horizontal strip. Also\n bottom-align the track within the row so paired rows in a 2-col grid\n keep their tracks lined up even when one label wraps to two lines. */\n/* Stacked rows only: `:has()` carries its argument's specificity, so on an inline\n row this outranks `.rowInline`'s space-between and packs label and track to the\n right edge. */\n.row:not(.rowInline):has(> input[type='range']) {\n justify-content: flex-end;\n}\n\n.row:not(.rowInline):has(> input[type='range']) > .rowLabel {\n /* Baseline-align (not center) so the readout input doesn't inflate the\n label-group height past the text baseline. */\n align-items: baseline;\n gap: var(--wzl-space-2);\n margin-bottom: -4px;\n}\n\n.rowLabel {\n font-family: var(--wzl-font-display);\n font-weight: var(--wzl-font-weight-light);\n font-size: var(--wzl-font-size-sm);\n line-height: var(--wzl-leading-snug);\n color: var(--wzl-fg-muted);\n text-transform: var(--wzl-params-label-case, uppercase);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wide));\n display: flex;\n align-items: center;\n justify-content: var(--wzl-params-label-align, start);\n gap: var(--wzl-space-3);\n}\n\n/* A label track, only where a row runs label-beside-control: a stacked row's\n label already spans the row, and a width there would narrow it instead. */\n.rowInline > .rowLabel,\n.rowColor:not(.rowBlock) > .rowLabel,\n.rowCheckbox:not(.rowBlock) > .rowLabel {\n inline-size: var(--wzl-params-label-width, auto);\n}\n\n.readout {\n composes: numeric from '@weasel-js/theme/numeric.module.css';\n font-size: var(--wzl-font-size-sm);\n line-height: var(--wzl-leading-snug);\n font-style: normal;\n font-weight: var(--wzl-font-weight-medium);\n color: var(--wzl-accent-fg);\n margin-left: auto;\n}\n\n/*\n * An inline row's readout, which the row draws after the control rather than\n * beside the label: its width changes with the value, and anything after it on\n * the row would be shoved sideways on every update.\n */\n.readoutAfter {\n flex: 0 0 auto;\n margin-left: 0;\n}\n\n/* Bare readout text — the word a row shows while it is auto — carrying\n `.readoutInput`'s box, inside `.readoutGroup` just as the input is. The label\n is a baseline-aligned flex line, so anything taller above the baseline drags\n the whole line, label included, down with it: an input's border and padding\n did that for 3.5px on every pin toggle. Both states have to be the same box\n *and* the same nesting, because the group's own strut is 5px of the height. */\n.readoutText {\n composes: numeric from '@weasel-js/theme/numeric.module.css';\n display: inline-block;\n /* The input's content box, not its line-height: a text input's inner editor\n will not shrink to a line-height below the font's own content area, so it\n renders 16px of content where a span renders 11px. Stating the height on\n both and filling it here is what makes the two boxes agree. */\n height: var(--wzl-field-h, var(--wzl-control-h-sm));\n line-height: calc(var(--wzl-field-h, var(--wzl-control-h-sm)) - 4px);\n border: 1px solid transparent;\n padding: 1px 0;\n}\n\n/* ⓘ help affordance beside a row label. */\n.help {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.15em;\n height: 1.15em;\n padding: 0;\n border: 0;\n background: none;\n color: var(--wzl-fg-subtle);\n font: inherit;\n font-size: var(--wzl-font-size-sm);\n line-height: 1;\n letter-spacing: normal;\n cursor: help;\n border-radius: var(--wzl-radius-sm);\n}\n\n.help:hover {\n color: var(--wzl-fg);\n border-color: transparent;\n}\n\n.help:focus-visible {\n outline: 2px solid var(--wzl-focus-ring);\n outline-offset: 1px;\n color: var(--wzl-fg);\n}\n\n/* The pinned/auto affordance. Invisible at rest so a panel of thirty rows is\n not thirty dots; revealed by the row, and permanent once the row is auto. */\n/* The row's label is also its pin, so it says so when pointed at — the same\n dotted underline a compact `<Select>` puts under its value. */\n.autoToggle {\n cursor: pointer;\n border-radius: var(--wzl-radius-sm);\n}\n\n/* The same dotted line a compact `<Select>` draws under its value. Stated\n longhand: the shorthand's `auto` thickness takes the font's, which at label\n size closes the gaps and reads as a solid rule. The line takes the label's\n own color — a label is already muted, and a subtler line under it is a 1px\n dotted rule nobody can see. */\n.autoToggle:hover {\n text-decoration: underline;\n text-decoration-style: dotted;\n text-decoration-thickness: 1px;\n text-decoration-color: currentColor;\n text-underline-offset: 0.25em;\n}\n\n.autoToggle:focus-visible {\n outline: 2px solid var(--wzl-focus-ring);\n outline-offset: 2px;\n}\n\n/* Single always-rendered <input> styled to read as a text label until focused. */\n.readoutInput {\n composes: numeric from '@weasel-js/theme/numeric.module.css';\n font-size: inherit;\n font-style: inherit;\n font-weight: var(--wzl-font-weight-medium);\n /* Force leading-tight — the label parent inherits 1.2, which would make the\n input box ~3px taller than the speech-balloons reference. */\n line-height: var(--wzl-leading-tight);\n color: var(--wzl-accent-fg);\n background: transparent;\n border: 1px solid transparent;\n border-radius: var(--wzl-radius-sm);\n padding: 1px 0;\n margin: 0;\n /* Stated rather than left to the control's intrinsic size, which `.readoutText`\n cannot reproduce — see the note there. */\n height: var(--wzl-field-h, var(--wzl-control-h-sm));\n /* One width for every readout, so a column of sliders ends on one line; a range whose widest\n value (the fit, in digit-wide `ch`) will not fit it widens its own box. The box is\n border-box, so its border comes back on top, with half a `ch` for a glyph wider than a digit. */\n width: max(\n var(--wzl-property-readout-w, calc(4.5ch + 2px)),\n calc(var(--wzl-property-readout-fit, 0px) + 2px + 0.5ch)\n );\n text-align: right;\n cursor: text;\n outline: none;\n transition: background 80ms ease, border-color 80ms ease;\n -moz-appearance: textfield;\n}\n\n.readoutInput:hover {\n background: color-mix(in srgb, currentColor 8%, transparent);\n}\n\n.readoutInput:focus {\n background: var(--wzl-input-surface, var(--wzl-surface-sunken));\n border-color: var(--wzl-focus-ring);\n}\n\n.readoutInput::-webkit-inner-spin-button,\n.readoutInput::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n/* Inline-block (not flex) so the browser's native vertical-align for\n <sub>/<sup> still works inside — flex collapses baseline semantics\n and sinks superscripts onto the baseline. */\n.readoutGroup {\n display: inline-block;\n white-space: nowrap;\n}\n\n/* Word-style units (e.g. \"px\") read as a small dim suffix next to the digits. */\n.readoutUnit {\n color: var(--wzl-fg-muted);\n font-size: var(--wzl-font-size-2xs);\n line-height: var(--wzl-leading-tight);\n pointer-events: none;\n}\n\n/* An inline row's readout sits between the control and the next cell, so a unit\n beside it would take width from the track. It hangs below the digits instead,\n out of flow, so a row with a unit is the same size as one without. */\n.readoutAfter .readoutGroup {\n position: relative;\n}\n\n.readoutAfter .readoutUnit {\n position: absolute;\n top: 100%;\n right: 1px;\n margin-top: -4px;\n line-height: 1;\n text-transform: var(--wzl-params-label-case, uppercase);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wide));\n}\n\n/* A number and its unit, on one line, the field taking what the unit leaves. */\n.fieldUnitGroup {\n display: inline-flex;\n align-items: center;\n gap: var(--wzl-space-2);\n white-space: nowrap;\n min-width: 0;\n}\n\n.fieldUnitGroup > .numberField {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n/* Symbol units (e.g. `<sup>°</sup>`) lean on the browser's native super\n positioning in a readout. Just dim them to match — do NOT set\n line-height: 0, that would re-collapse the glyph onto the baseline. A flex\n item ignores `vertical-align`, so beside a field the glyph rides the top of\n the line instead. */\n.readoutGroup sup,\n.fieldUnitGroup sup {\n color: var(--wzl-fg-muted);\n font-size: var(--wzl-font-size-2xs);\n pointer-events: none;\n}\n\n.fieldUnitGroup > sup {\n align-self: flex-start;\n}\n\n/* ── Inline layout: label sits to the left of the control. ────── */\n.rowInline {\n flex-direction: row;\n align-items: var(--wzl-prop-row-align, center);\n /* Label on the left edge, field on the right: fields of different widths\n still line up as one rail down the column. */\n justify-content: space-between;\n gap: var(--wzl-space-3);\n}\n\n.rowInline .rowLabel {\n /* The label never gives: shrinking it breaks a name like `silhouette_width`\n mid-word, since it carries no break opportunity of its own. The field is\n what yields as the column narrows. */\n flex: 0 0 auto;\n}\n\n/* A row past one line — a textarea or list editor beside the label, or a label\n that wrapped — reads from the top: centering puts the label's first line\n halfway down the control, level with nothing. First baseline sets the label's\n first line on the control's first line of text, and a control with no text\n (a switch, a box) sits on that line the way it does in running text. Outranks\n `align` and the select row's text alignment, which place a one-line row.\n `data-multiline` is measured by the row. */\n.row.rowInline:has(textarea, [role='group'] > ul),\n.row.rowInline[data-multiline],\n.row.rowCheckbox:not(.rowBlock)[data-multiline] {\n align-items: first baseline;\n}\n\n.row.rowColor:not(.rowBlock)[data-multiline] > .rowLabel,\n.row.rowColor:not(.rowBlock)[data-multiline] > input[type='color'],\n.row.rowColor:not(.rowBlock)[data-multiline] > .colorField > :first-child {\n align-self: first baseline;\n}\n\n/* A textarea's baseline is its last line in some engines, so beside one the\n label goes to the top and steps down to the textarea's first line instead. */\n.rowInline:has(textarea) > .rowLabel {\n align-self: flex-start;\n padding-block-start: calc(var(--wzl-space-2) + 1px);\n}\n\n.rowInline > input,\n.rowInline > select,\n.rowInline > .toggleBar {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n/* Fields size to their content, not to the row they happen to sit in: a number\n is a handful of digits and a short string is a word. Stated as a width and\n not as a `min(100%, …)`, because an auto-width sidebar sizes to what its\n fields ask for and a percentage asks for an input's 20-character default.\n Only a field set in the row itself: a surface that wraps its control in a\n slot of its own sizes it there. */\n.row > .numberField,\n.row > .fieldUnitGroup > .numberField {\n flex: 0 1 auto;\n width: var(--wzl-prop-number-width, 9ch);\n max-width: 100%;\n}\n\n.row > .textField {\n width: var(--wzl-prop-text-width, 16ch);\n max-width: 100%;\n}\n\n/* The property rows' fields set their text at the weight the readouts use.\n The attribute outranks the field's own `font: inherit`. */\n.numberField input[type='text'],\n.textField input[type='text'] {\n font-weight: var(--wzl-font-weight-medium);\n}\n\n/* A select is as tall as the fields around it. */\n.select {\n --wzl-select-h: var(--wzl-field-h, var(--wzl-control-h));\n}\n\n/* Set directly in a property row, it drops its box and underlines its value:\n a dense row of settings reads its choices as words, and 10px of caret is a\n tenth of a short value's width. A surface that slots the control in a\n wrapper of its own — a prefs form, an inspector cell — keeps the box. */\n.row > .select {\n --wzl-select-bg: transparent;\n --wzl-select-border: 1px solid transparent;\n --wzl-select-pad: 0;\n --wzl-select-chevron: none;\n --wzl-select-underline: underline;\n --wzl-select-focus-border: transparent;\n --wzl-select-focus-shadow: none;\n --wzl-select-focus-outline: 1px solid var(--wzl-focus-ring);\n}\n\n/* The rules from here to the select are for a native input a caller hands a\n row directly; every field kind draws a kit field that brings its own frame,\n and sits deeper than a child. */\n.row > input[type='number']:not(.readoutInput) {\n width: var(--wzl-prop-number-width, 9ch);\n max-width: 100%;\n -moz-appearance: textfield;\n appearance: textfield;\n}\n\n.row > input[type='text']:not(.readoutInput) {\n width: var(--wzl-prop-text-width, 16ch);\n max-width: 100%;\n}\n\n/* An inline row stays on one line: the field gives up width to the label as the\n column narrows, down to a floor that still shows a value. */\n.rowInline > input:not(.readoutInput),\n.rowInline > .numberField,\n.rowInline > .fieldUnitGroup,\n.rowInline > .textField {\n flex: 0 1 auto;\n min-width: 4ch;\n}\n\n/* Inline, a select fills the space beside its label and sets its value against\n the chevron, like a native one handed to the row. */\n.rowInline > .select {\n flex: 1 1 auto;\n width: auto;\n min-width: 4ch;\n --wzl-select-align: right;\n}\n\n/* Two runs of text on one line read as one line or they read as broken, and\n centering two boxes is not aligning the text in them: a 13px label centered\n against a 15px value left the two baselines 1px apart, which is exactly the\n distance the eye reads as a mistake. Only the rows whose control is text — a\n checkbox or a swatch has no baseline of its own and would hang off the line\n instead. */\n.rowInline:has(> .select) {\n align-items: var(--wzl-prop-row-align-text, baseline);\n}\n\n/* A select sized to its longest option starts wherever that width leaves it, so\n a column of them scatters its values. Filling the row and setting the value\n against the chevron gives them one rail. */\n.rowInline > select {\n flex: 1 1 auto;\n min-width: 4ch;\n text-align: right;\n text-align-last: right;\n}\n\n.rowInline input[type='range'] {\n width: auto;\n}\n\n.row > input[type='text']:not(.readoutInput),\n.row > input[type='number'] {\n background: var(--wzl-input-surface, var(--wzl-surface-sunken));\n color: var(--wzl-fg);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n /* Height is stated rather than padded to, because the display face's line box\n is half again its font size — padding a field to size makes it 27px tall\n around 13px of text and no amount of trimming the padding fixes that. */\n height: var(--wzl-field-h, var(--wzl-control-h));\n padding: 0 var(--wzl-field-pad-x);\n font-family: var(--wzl-font-ui);\n font-weight: var(--wzl-font-weight-medium);\n font-size: var(--wzl-font-size);\n line-height: var(--wzl-leading-tight);\n}\n\n/* Numbers right-align so a column of them shares a decimal position; text does\n not, so this cannot live in the rule the two share. */\n.row > input[type='number'] {\n text-align: right;\n}\n\n/* Chrome reserves the spin-button gutter at the right edge whether or not the\n arrows are painted, so a right-aligned value stops ~20px short of its own\n border and the row reads as if something is missing from that space. The\n panel drives numbers by typing and dragging, never by the steppers.\n `.readoutInput` has always dropped them; this is the same removal for the\n typed field beside it. */\n.row > input[type='number']::-webkit-inner-spin-button,\n.row > input[type='number']::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n.row > input[type='text']:not(.readoutInput):focus,\n.row > input[type='number']:focus {\n outline: none;\n border-color: var(--wzl-focus-ring);\n box-shadow: 0 0 0 1px var(--wzl-focus-ring);\n}\n\n/* A dialog row's trigger reads as a field holding the value's summary, so a\n column of them lines up with the text fields around it. */\n.dialogTrigger {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-2);\n width: 100%;\n min-width: 4ch;\n height: var(--wzl-field-h, var(--wzl-control-h));\n padding: 0 var(--wzl-field-pad-x);\n background: var(--wzl-input-surface, var(--wzl-surface-sunken));\n color: var(--wzl-fg);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n font-family: var(--wzl-font-ui);\n font-weight: var(--wzl-font-weight-medium);\n font-size: var(--wzl-font-size);\n line-height: var(--wzl-leading-tight);\n text-align: start;\n cursor: pointer;\n}\n\n.rowInline > .dialogTrigger {\n flex: 1 1 auto;\n width: auto;\n}\n\n.dialogTrigger:hover {\n border-color: var(--wzl-border-strong);\n}\n\n.dialogTrigger:focus-visible {\n outline: none;\n border-color: var(--wzl-focus-ring);\n box-shadow: 0 0 0 1px var(--wzl-focus-ring);\n}\n\n.dialogSummary {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.dialogGlyph {\n flex: 0 0 auto;\n color: var(--wzl-fg-subtle);\n}\n\n/* A native select handed to a row renders borderless — chevron only,\n transparent background, no chrome. Keep the native arrow via appearance: auto\n so users still see something clickable. */\n.row > select {\n background: transparent;\n color: var(--wzl-fg);\n border: 0;\n border-radius: 0;\n height: var(--wzl-field-h, var(--wzl-control-h));\n padding: 0;\n font-family: var(--wzl-font-ui);\n font-weight: var(--wzl-font-weight-medium);\n font-size: var(--wzl-font-size);\n line-height: var(--wzl-leading-tight);\n cursor: pointer;\n}\n\n/* An outline rather than the boxed family's inset ring: a property-row select\n is borderless, so there is no border to recolour. */\n.row > select:focus {\n outline: 1px solid var(--wzl-focus-ring);\n outline-offset: 2px;\n}\n\n/* ── Color variant: label and swatch side-by-side, two per row in the grid.\n Switches to a 2-row grid when an alpha slider is rendered beneath. */\n/* `align-content: end` sinks the whole grid so a color row paired with a\n taller sibling keeps its alpha track on the neighbour's bottom edge. An\n explicit `align` overrides both that and the per-item alignment below, which\n is what a column of swatches read as a group needs. */\n.rowColor {\n display: grid;\n grid-template-columns: 1fr auto;\n grid-template-rows: auto;\n align-content: var(--wzl-prop-row-align-content, end);\n column-gap: var(--wzl-space-4);\n row-gap: 0;\n min-width: 0;\n}\n\n.rowColor .rowLabel {\n grid-column: 1;\n grid-row: 1;\n align-self: var(--wzl-prop-row-align, center);\n flex: initial;\n min-width: 0;\n}\n\n/* Padding: 0 is important — the native <input type=\"color\"> in some browsers (esp. Chrome) inflates beyond its\n declared box when given padding, which expands the grid row and pushes\n the paired slider track out of bottom alignment. */\n.rowColor > input[type='color'] {\n grid-column: 2;\n grid-row: 1;\n align-self: var(--wzl-prop-row-align, center);\n box-sizing: border-box;\n width: 36px;\n height: var(--wzl-control-h-xs);\n background: transparent;\n border: 0;\n border-radius: var(--wzl-radius-sm);\n padding: 0;\n cursor: pointer;\n flex-shrink: 0;\n}\n\n/* A color field set directly in the row gives its parts to the row's grid:\n the swatch beside the label, and the opacity track with its readout on a\n second row beneath. Nested in another wrapper, it keeps its own line. */\n.rowColor > .colorField {\n display: contents;\n}\n\n.rowColor > .colorField > :first-child {\n grid-column: 2;\n grid-row: 1;\n align-self: var(--wzl-prop-row-align, center);\n justify-self: end;\n}\n\n.rowColor > .colorField > input[type='range'] {\n grid-column: 1;\n grid-row: 2;\n}\n\n.rowColor > .colorField > :last-child:not(:first-child):not(input) {\n grid-column: 2;\n grid-row: 2;\n align-self: center;\n}\n\n/* `layout=\"block\"` stacks the color row: label, then swatch, then alpha. */\n.rowColor.rowBlock {\n grid-template-columns: 1fr;\n}\n\n.rowColor.rowBlock .rowLabel {\n grid-column: 1;\n grid-row: 1;\n}\n\n.rowColor.rowBlock > input[type='color'],\n.rowColor.rowBlock > .colorField > :first-child {\n grid-column: 1;\n grid-row: 2;\n justify-self: start;\n}\n\n.rowColor.rowBlock > .colorField > input[type='range'] {\n grid-row: 3;\n}\n\n/* A block row has one column, so the readout rides at the track's end. */\n.rowColor.rowBlock > .colorField > :last-child:not(:first-child):not(input) {\n grid-column: 1;\n grid-row: 3;\n justify-self: end;\n}\n\n/* ── Checkbox variant: label-first inline layout. */\n.rowCheckbox {\n flex-direction: row;\n align-items: var(--wzl-prop-row-align, center);\n /* Label on the leading edge and box on the trailing one, like every other\n inline row: a column of settings is read down its labels, and a box that\n leads its own row puts each label at a different indent. */\n justify-content: space-between;\n gap: var(--wzl-space-4);\n cursor: pointer;\n}\n\n.rowCheckbox > input[type='checkbox']:not([role='switch']) {\n accent-color: var(--wzl-accent);\n width: 14px;\n height: 14px;\n cursor: pointer;\n}\n\n/* `layout=\"block\"` stacks the checkbox row: label above, box beneath, both on\n the leading edge — a block row's cross axis is the horizontal one. */\n.rowCheckbox.rowBlock {\n flex-direction: column;\n align-items: var(--wzl-prop-row-align, start);\n}\n\n\n/* A state the control cannot draw itself: a switch has no indeterminate form,\n and nothing has an \"unset\" one. */\n.dimmed {\n opacity: 0.55;\n}\n\n/* A slider cell's readout, beside its track rather than in a row's label line.\n Doubled so a row laying its cells out evenly does not stretch it. */\n.cellReadout.cellReadout {\n flex: none;\n min-inline-size: 3ch;\n text-align: end;\n}\n\n.textarea {\n width: 100%;\n padding: var(--wzl-space-2) var(--wzl-space-4);\n background: var(--wzl-input-surface, var(--wzl-surface-sunken));\n color: var(--wzl-fg);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n font: inherit;\n font-size: var(--wzl-font-size-sm);\n resize: vertical;\n}\n\n/* ── Segmented toggle ─────────────────────────────────────────────\n A `ToggleBar`, filling the row the way a field does and standing at the\n row's field height rather than its own small size. */\n.row > .toggleBar {\n display: flex;\n width: 100%;\n height: var(--wzl-field-h, var(--wzl-control-h));\n}\n\n/* ── PropertyGroup ──────────────────────────────────────────────────\n Bordered, sunken section inside a list. */\n.group {\n grid-column: 1 / -1;\n background: var(--_s-fill);\n border: var(--_s-border-width) var(--_s-border-style) var(--_s-border-color);\n border-radius: var(--_s-radius);\n padding: var(--_s-pad);\n}\n\n/* A toned group is one of a list of like groups; its edge says which. */\n.group[data-tone] {\n border-left: 4px solid var(--wzl-tone);\n}\n\n.groupHeadRow {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-4);\n margin: 0 0 var(--wzl-prop-group-title-gap, 4px);\n}\n\n/* The row takes the title's bottom margin, so the handle and actions center on the title itself. */\n.groupHeadRow > .groupTitle {\n flex: 1 1 auto;\n min-width: 0;\n margin: 0;\n}\n\n.groupLeading,\n.groupActions {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--wzl-space-2);\n}\n\n/* BEGIN GENERATED stance rules: group — `npm run gen:stances`, do not edit. */\n\n.group {\n --wzl-tone: initial;\n}\n\n.group {\n --_s-surface: var(--wzl-surface-sunken);\n --_s-border-color: var(--wzl-border);\n --_s-border-style: solid;\n --_s-border-width: 0px;\n --_s-radius: var(--wzl-radius-md);\n --_s-pad: var(--wzl-prop-group-pad, 6px 10px 8px);\n --_s-tone-mix: var(--wzl-panel-tone-mix);\n --_s-tone: var(--wzl-tone, var(--_s-surface));\n --_s-accent: var(--wzl-tone);\n --_s-title-font: var(--wzl-font-display);\n --_s-title-weight: var(--wzl-font-weight-light);\n --_s-title-size: var(--wzl-font-size-sm);\n --_s-title-case: var(--wzl-params-label-case, uppercase);\n --_s-title-tracking: var(--wzl-params-label-tracking, var(--wzl-tracking-wider));\n --_s-title-color: var(--wzl-fg-subtle);\n}\n\n.group[data-stance='scope'] {\n --_s-surface: var(--wzl-stance-scope-surface, var(--wzl-surface-sunken));\n --_s-border-color: var(--wzl-stance-scope-border-color, var(--wzl-border));\n --_s-border-style: var(--wzl-stance-scope-border-style, solid);\n --_s-border-width: var(--wzl-stance-scope-border-width, 0px);\n --_s-radius: var(--wzl-stance-scope-radius, var(--wzl-radius-md));\n --_s-pad: var(--wzl-stance-scope-pad, var(--wzl-prop-group-pad, 6px 10px 8px));\n --_s-tone-mix: var(--wzl-stance-scope-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-scope-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-scope-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-scope-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-scope-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-scope-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-scope-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-scope-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-scope-title-color, var(--wzl-fg-subtle));\n}\n\n.group[data-stance='aside'] {\n --_s-surface: var(--wzl-stance-aside-surface, var(--wzl-surface-sunken));\n --_s-border-color: var(--wzl-stance-aside-border-color, var(--wzl-border));\n --_s-border-style: var(--wzl-stance-aside-border-style, solid);\n --_s-border-width: var(--wzl-stance-aside-border-width, 0px);\n --_s-radius: var(--wzl-stance-aside-radius, var(--wzl-radius-md));\n --_s-pad: var(--wzl-stance-aside-pad, var(--wzl-prop-group-pad, 6px 10px 8px));\n --_s-tone-mix: var(--wzl-stance-aside-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-aside-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-aside-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-aside-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-aside-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-aside-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-aside-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-aside-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-aside-title-color, var(--wzl-fg-subtle));\n}\n\n.group[data-stance='advanced'] {\n --_s-surface: var(--wzl-stance-advanced-surface, var(--wzl-surface-sunken));\n --_s-border-color: var(--wzl-stance-advanced-border-color, var(--wzl-border));\n --_s-border-style: var(--wzl-stance-advanced-border-style, solid);\n --_s-border-width: var(--wzl-stance-advanced-border-width, 0px);\n --_s-radius: var(--wzl-stance-advanced-radius, var(--wzl-radius-md));\n --_s-pad: var(--wzl-stance-advanced-pad, var(--wzl-prop-group-pad, 6px 10px 8px));\n --_s-tone-mix: var(--wzl-stance-advanced-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-advanced-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-advanced-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-advanced-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-advanced-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-advanced-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-advanced-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-advanced-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-advanced-title-color, var(--wzl-fg-subtle));\n}\n\n.group[data-stance='debug'] {\n --_s-surface: var(--wzl-stance-debug-surface, var(--wzl-surface-sunken));\n --_s-border-color: var(--wzl-stance-debug-border-color, var(--wzl-border));\n --_s-border-style: var(--wzl-stance-debug-border-style, solid);\n --_s-border-width: var(--wzl-stance-debug-border-width, 0px);\n --_s-radius: var(--wzl-stance-debug-radius, var(--wzl-radius-md));\n --_s-pad: var(--wzl-stance-debug-pad, var(--wzl-prop-group-pad, 6px 10px 8px));\n --_s-tone-mix: var(--wzl-stance-debug-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-debug-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-debug-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-debug-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-debug-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-debug-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-debug-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-debug-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-debug-title-color, var(--wzl-fg-subtle));\n}\n\n.group[data-stance='danger'] {\n --_s-surface: var(--wzl-stance-danger-surface, var(--wzl-surface-sunken));\n --_s-border-color: var(--wzl-stance-danger-border-color, var(--wzl-border));\n --_s-border-style: var(--wzl-stance-danger-border-style, solid);\n --_s-border-width: var(--wzl-stance-danger-border-width, 0px);\n --_s-radius: var(--wzl-stance-danger-radius, var(--wzl-radius-md));\n --_s-pad: var(--wzl-stance-danger-pad, var(--wzl-prop-group-pad, 6px 10px 8px));\n --_s-tone-mix: var(--wzl-stance-danger-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-danger-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-danger-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-danger-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-danger-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-danger-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-danger-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-danger-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-danger-title-color, var(--wzl-fg-subtle));\n}\n\n.group[data-stance='notice'] {\n --_s-surface: var(--wzl-stance-notice-surface, var(--wzl-surface-sunken));\n --_s-border-color: var(--wzl-stance-notice-border-color, var(--wzl-border));\n --_s-border-style: var(--wzl-stance-notice-border-style, solid);\n --_s-border-width: var(--wzl-stance-notice-border-width, 0px);\n --_s-radius: var(--wzl-stance-notice-radius, var(--wzl-radius-md));\n --_s-pad: var(--wzl-stance-notice-pad, var(--wzl-prop-group-pad, 6px 10px 8px));\n --_s-tone-mix: var(--wzl-stance-notice-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-notice-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-notice-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-notice-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-notice-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-notice-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-notice-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-notice-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-notice-title-color, var(--wzl-fg-subtle));\n}\n\n.group[data-stance='important'] {\n --_s-surface: var(--wzl-stance-important-surface, var(--wzl-surface-sunken));\n --_s-border-color: var(--wzl-stance-important-border-color, var(--wzl-border));\n --_s-border-style: var(--wzl-stance-important-border-style, solid);\n --_s-border-width: var(--wzl-stance-important-border-width, 0px);\n --_s-radius: var(--wzl-stance-important-radius, var(--wzl-radius-md));\n --_s-pad: var(--wzl-stance-important-pad, var(--wzl-prop-group-pad, 6px 10px 8px));\n --_s-tone-mix: var(--wzl-stance-important-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-important-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-important-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-important-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-important-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-important-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-important-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-important-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-important-title-color, var(--wzl-fg-subtle));\n}\n\n.group[data-stance='preview'] {\n --_s-surface: var(--wzl-stance-preview-surface, var(--wzl-surface-sunken));\n --_s-border-color: var(--wzl-stance-preview-border-color, var(--wzl-border));\n --_s-border-style: var(--wzl-stance-preview-border-style, solid);\n --_s-border-width: var(--wzl-stance-preview-border-width, 0px);\n --_s-radius: var(--wzl-stance-preview-radius, var(--wzl-radius-md));\n --_s-pad: var(--wzl-stance-preview-pad, var(--wzl-prop-group-pad, 6px 10px 8px));\n --_s-tone-mix: var(--wzl-stance-preview-tone-mix, var(--wzl-panel-tone-mix));\n --_s-tone: var(--wzl-tone, var(--wzl-stance-preview-tone, var(--_s-surface)));\n --_s-accent: var(--wzl-stance-preview-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-preview-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-preview-title-weight, var(--wzl-font-weight-light));\n --_s-title-size: var(--wzl-stance-preview-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-preview-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-preview-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-preview-title-color, var(--wzl-fg-subtle));\n}\n\n.group {\n --_s-fill: var(--_s-surface);\n}\n\n.group[data-tone],\n.group[data-stance] {\n --_s-fill: color-mix(in oklab, var(--_s-tone) var(--_s-tone-mix), var(--_s-surface));\n}\n\n.group[data-tone] {\n --wzl-accent: var(--_s-accent);\n --wzl-accent-base: var(--_s-accent);\n --wzl-accent-strong: color-mix(in oklab, var(--_s-accent) 70%, var(--wzl-fg));\n --wzl-accent-soft: color-mix(in oklab, var(--_s-accent) 45%, var(--wzl-surface));\n --wzl-accent-hover: var(--wzl-accent-strong);\n --wzl-accent-fg: var(--wzl-accent-strong);\n --wzl-focus-ring: var(--wzl-accent-strong);\n}\n\n/* END GENERATED stance rules: group */\n\n/* Group help text: spans the grid, sits above the rows it describes. */\n.note {\n grid-column: 1 / -1;\n margin: 0 0 var(--wzl-prop-group-title-gap, 4px);\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg-subtle);\n line-height: 1.35;\n}\n\n.groupTitle {\n display: grid;\n grid-template-columns: 1fr auto 1fr;\n align-items: center;\n gap: var(--wzl-space-4);\n margin: 0 0 var(--wzl-prop-group-title-gap, 4px);\n font-family: var(--_s-title-font);\n font-weight: var(--_s-title-weight);\n font-size: var(--_s-title-size);\n letter-spacing: var(--_s-title-tracking);\n text-transform: var(--_s-title-case);\n color: var(--_s-title-color);\n}\n\n.groupTitle hr {\n border: 0;\n border-top: 1px solid var(--_s-border-color);\n margin: 0;\n}\n\n/* The title between the rules. The twisty hangs off the text's leading edge,\n out of flow, so the text centers as though it were not there. */\n.groupTitleMid {\n position: relative;\n min-width: 0;\n}\n\n/* Being out of flow, the twisty would sit on the leading rule; the rule stops at its box instead. */\n.groupTitle:has(> .groupTitleMid > .groupTwisty) > hr:first-child {\n margin-inline-end: calc(\n var(--wzl-disclosure-target, var(--wzl-control-h-sm)) + var(--wzl-disclosure-gap, 4px) - var(--wzl-space-4)\n );\n}\n\n.groupTwisty {\n position: absolute;\n inset-inline-end: calc(100% + var(--wzl-disclosure-gap, 4px));\n top: 50%;\n translate: 0 -50%;\n}\n\n/* `hidden` on its own loses to the body's `display: grid` below. */\n.groupBody[hidden] {\n display: none;\n}\n\n.groupBody {\n display: grid;\n grid-template-columns: 1fr 1fr;\n column-gap: var(--wzl-prop-column-gap, 16px);\n row-gap: var(--wzl-prop-row-gap, 4px);\n /* Stretch so paired rows match in height — slider rows then bottom-align\n their tracks (via `margin-top: auto`) and stay lined up even when one\n sibling's label wraps to two lines. */\n align-items: stretch;\n}\n\n.group:not(.groupPairs) .groupBody > :not(.rowColor) {\n grid-column: 1 / -1;\n}\n\n.groupPairs .groupBody > * {\n grid-column: auto;\n}\n\n.groupPairs .groupBody > h3,\n.groupPairs .groupBody > .span {\n grid-column: 1 / -1;\n}\n\n.groupOneUp .groupBody > * {\n grid-column: 1 / -1;\n}\n\n/* ── Subpanel ────────────────────────────────────────────────────────\n Headered group of controls inside a list. The header is a typographic\n label flanked by a horizontal rule — no card chrome, just the divider. */\n.subpanel {\n display: grid;\n grid-template-columns: 1fr 1fr;\n column-gap: var(--wzl-prop-column-gap, 16px);\n row-gap: var(--wzl-prop-subpanel-row-gap, 3px);\n align-items: stretch;\n background: transparent;\n border: 0;\n padding: 0;\n margin: 0;\n}\n\n/* BEGIN GENERATED stance rules: subpanel — `npm run gen:stances`, do not edit. */\n\n.subpanel {\n --wzl-tone: initial;\n}\n\n.subpanel {\n --_s-border-color: var(--wzl-line-subtle);\n --_s-accent: var(--wzl-tone);\n --_s-title-font: var(--wzl-font-display);\n --_s-title-weight: var(--wzl-font-weight-medium);\n --_s-title-size: var(--wzl-font-size-sm);\n --_s-title-case: var(--wzl-params-label-case, uppercase);\n --_s-title-tracking: var(--wzl-params-label-tracking, var(--wzl-tracking-wider));\n --_s-title-color: var(--wzl-fg);\n}\n\n.subpanel[data-stance='scope'] {\n --_s-border-color: var(--wzl-stance-scope-border-color, var(--wzl-line-subtle));\n --_s-accent: var(--wzl-stance-scope-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-scope-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-scope-title-weight, var(--wzl-font-weight-medium));\n --_s-title-size: var(--wzl-stance-scope-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-scope-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-scope-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-scope-title-color, var(--wzl-fg));\n}\n\n.subpanel[data-stance='aside'] {\n --_s-border-color: var(--wzl-stance-aside-border-color, var(--wzl-line-subtle));\n --_s-accent: var(--wzl-stance-aside-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-aside-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-aside-title-weight, var(--wzl-font-weight-medium));\n --_s-title-size: var(--wzl-stance-aside-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-aside-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-aside-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-aside-title-color, var(--wzl-fg));\n}\n\n.subpanel[data-stance='advanced'] {\n --_s-border-color: var(--wzl-stance-advanced-border-color, var(--wzl-line-subtle));\n --_s-accent: var(--wzl-stance-advanced-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-advanced-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-advanced-title-weight, var(--wzl-font-weight-medium));\n --_s-title-size: var(--wzl-stance-advanced-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-advanced-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-advanced-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-advanced-title-color, var(--wzl-fg));\n}\n\n.subpanel[data-stance='debug'] {\n --_s-border-color: var(--wzl-stance-debug-border-color, var(--wzl-line-subtle));\n --_s-accent: var(--wzl-stance-debug-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-debug-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-debug-title-weight, var(--wzl-font-weight-medium));\n --_s-title-size: var(--wzl-stance-debug-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-debug-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-debug-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-debug-title-color, var(--wzl-fg));\n}\n\n.subpanel[data-stance='danger'] {\n --_s-border-color: var(--wzl-stance-danger-border-color, var(--wzl-line-subtle));\n --_s-accent: var(--wzl-stance-danger-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-danger-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-danger-title-weight, var(--wzl-font-weight-medium));\n --_s-title-size: var(--wzl-stance-danger-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-danger-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-danger-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-danger-title-color, var(--wzl-fg));\n}\n\n.subpanel[data-stance='notice'] {\n --_s-border-color: var(--wzl-stance-notice-border-color, var(--wzl-line-subtle));\n --_s-accent: var(--wzl-stance-notice-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-notice-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-notice-title-weight, var(--wzl-font-weight-medium));\n --_s-title-size: var(--wzl-stance-notice-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-notice-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-notice-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-notice-title-color, var(--wzl-fg));\n}\n\n.subpanel[data-stance='important'] {\n --_s-border-color: var(--wzl-stance-important-border-color, var(--wzl-line-subtle));\n --_s-accent: var(--wzl-stance-important-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-important-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-important-title-weight, var(--wzl-font-weight-medium));\n --_s-title-size: var(--wzl-stance-important-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-important-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-important-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-important-title-color, var(--wzl-fg));\n}\n\n.subpanel[data-stance='preview'] {\n --_s-border-color: var(--wzl-stance-preview-border-color, var(--wzl-line-subtle));\n --_s-accent: var(--wzl-stance-preview-accent, var(--wzl-tone));\n --_s-title-font: var(--wzl-stance-preview-title-font, var(--wzl-font-display));\n --_s-title-weight: var(--wzl-stance-preview-title-weight, var(--wzl-font-weight-medium));\n --_s-title-size: var(--wzl-stance-preview-title-size, var(--wzl-font-size-sm));\n --_s-title-case: var(--wzl-stance-preview-title-case, var(--wzl-params-label-case, uppercase));\n --_s-title-tracking: var(--wzl-stance-preview-title-tracking, var(--wzl-params-label-tracking, var(--wzl-tracking-wider)));\n --_s-title-color: var(--wzl-stance-preview-title-color, var(--wzl-fg));\n}\n\n.subpanel[data-tone] {\n --wzl-accent: var(--_s-accent);\n --wzl-accent-base: var(--_s-accent);\n --wzl-accent-strong: color-mix(in oklab, var(--_s-accent) 70%, var(--wzl-fg));\n --wzl-accent-soft: color-mix(in oklab, var(--_s-accent) 45%, var(--wzl-surface));\n --wzl-accent-hover: var(--wzl-accent-strong);\n --wzl-accent-fg: var(--wzl-accent-strong);\n --wzl-focus-ring: var(--wzl-accent-strong);\n}\n\n/* END GENERATED stance rules: subpanel */\n\n.subpanel > * {\n min-width: 0;\n}\n\n.subpanel > .subpanelTitle,\n.subpanel > .span {\n grid-column: 1 / -1;\n}\n\n.subpanelTitle {\n font-family: var(--_s-title-font);\n font-weight: var(--_s-title-weight);\n font-size: var(--_s-title-size);\n line-height: var(--wzl-leading-tight);\n color: var(--_s-title-color);\n text-transform: var(--_s-title-case);\n letter-spacing: var(--_s-title-tracking);\n margin: 0;\n padding: var(--wzl-space-3) 0 var(--wzl-space-2);\n display: flex;\n align-items: center;\n gap: var(--wzl-space-4);\n}\n\n.subpanelTitle > span {\n flex: 0 0 auto;\n}\n\n.subpanelTitle > hr {\n flex: 1 1 auto;\n border: 0;\n border-top: 1px solid var(--_s-border-color);\n margin: 0;\n}\n\n/* An auto row: the value is not pinned, and the row says only that. The\n control is hidden rather than removed, so the row keeps the height and the\n width it has while pinned and nothing below it moves on the toggle —\n `visibility` and not `opacity`, because a hidden control must also be out of\n reach of the pointer and the tab ring. The label and the readout are what\n stays: everything else in the row is the control. */\n.rowAuto > :not(.rowLabel):not(.readout) {\n visibility: hidden;\n}\n\n.rowAuto > .rowLabel {\n color: var(--wzl-fg-subtle);\n}\n\n/* An auto row that keeps drawing its control: the value is the one it inherits,\n drawn in the secondary accent so it reads as not chosen here. */\n.rowAutoInherited {\n composes: inherited from '@weasel-js/theme/inherited.module.css';\n}\n\n/* Where an inherited value comes from, after the label. */\n.rowHint {\n font-size: var(--wzl-font-size-2xs);\n color: var(--wzl-fg-subtle);\n white-space: nowrap;\n}\n\n/* A stacked row's readout sits inside the label and an inline row's sits after\n the control, so the label's case reached one and not the other: the same word\n read `AUTO` in one row and `auto` in the next. An auto row's readout is a\n word, not a number, so it takes the label recipe and both rows read alike. */\n.rowAuto .readout {\n font-size: var(--wzl-font-size-xs);\n color: var(--wzl-secondary-fg);\n text-transform: var(--wzl-params-label-case, uppercase);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wide));\n}\n","import {\n createContext,\n forwardRef,\n type ReactNode,\n type Ref,\n type RefObject,\n useContext,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { Focusable } from 'react-aria-components';\nimport { type StanceProps, useStance } from '../stance';\nimport { Tooltip, TooltipTrigger } from '../Tooltip';\nimport s from './Properties.module.css';\n\n/**\n * How much room a container gives its rows — gaps, padding, and field height,\n * moved together. Set on any container in the family; it reaches every\n * descendant, so an inner group can differ from the panel around it.\n */\nexport type PropertyDensity = 'tight' | 'normal' | 'roomy';\n\n/** Where an inline row's label and control sit on the row's cross axis. Set on\n * a container to line a whole column of them up. */\nexport type PropertyAlign = 'start' | 'center' | 'end' | 'baseline';\n\n/** Metric props every container in the family takes. Both reach descendants,\n * so the nearest container that states one wins. */\nexport interface PropertyMetricProps {\n /** Room the rows get. Unset inherits from an outer container, else `normal`. */\n density?: PropertyDensity;\n /**\n * Cross-axis alignment of an inline row's label and control. `baseline` sits\n * the control on the label's first-line baseline, which is what lines a\n * column of swatches up against labels of different heights. Unset keeps each\n * variant's own alignment — a color row centers its label and swatch and\n * sinks the pair to the row's bottom edge, which keeps a paired alpha track\n * level with its neighbour.\n */\n align?: PropertyAlign;\n}\n\nconst DENSITY_CLASS: Record<PropertyDensity, string> = {\n tight: s.densityTight,\n normal: s.densityNormal,\n roomy: s.densityRoomy,\n};\n\nconst ALIGN_CLASS: Record<PropertyAlign, string> = {\n start: s.alignStart,\n center: s.alignCenter,\n end: s.alignEnd,\n baseline: s.alignBaseline,\n};\n\n/** Joins a container's base class with its metric classes and the consumer's.\n * Exported for the family's other files, which share the same two props. */\nexport function propertyMetricClass(\n base: string,\n { density, align }: PropertyMetricProps,\n className?: string,\n): string {\n return [base, density && DENSITY_CLASS[density], align && ALIGN_CLASS[align], className]\n .filter(Boolean)\n .join(' ');\n}\n\n/** Props for `<PropertyPanel>`. */\nexport interface PropertyPanelProps extends PropertyMetricProps, StanceProps {\n title?: ReactNode;\n /** Controls on the trailing edge of the title row — a switch, a clear\n * button. They sit outside the heading, so they neither take its type nor\n * join its accessible name. */\n actions?: ReactNode;\n /**\n * Lets text inside the panel be selected and copied. A panel is chrome by\n * default, so a drag across it moves a slider rather than painting a\n * selection; a `debug` panel defaults to selectable, since what it shows —\n * ids, keys, traces — is there to be copied.\n */\n selectable?: boolean;\n children: ReactNode;\n className?: string;\n}\n\nconst PanelNesting = createContext(false);\n\n/**\n * A titled panel holding property rows — the sidebar container the rest of\n * this module's components fill.\n *\n * `stance` says what kind of content it holds and `tone` which of its peers it\n * is; the theme's `--wzl-panel-*` and `--wzl-stance-*` slots decide how each looks. A stanced\n * panel's title takes the row-label recipe rather than the display title.\n */\nexport function PropertyPanel({\n title,\n actions,\n selectable,\n children,\n className,\n density,\n align,\n stance,\n tone,\n}: PropertyPanelProps) {\n const nested = useContext(PanelNesting);\n const attrs = useStance({ stance, tone });\n const heading = title != null && <h2 className={s.panelTitle}>{title}</h2>;\n return (\n <div\n className={propertyMetricClass(s.panel, { density, align }, className)}\n {...attrs}\n data-nested={nested || undefined}\n data-selectable={(selectable ?? stance === 'debug') || undefined}\n >\n {actions != null ? (\n <div className={s.panelHeader}>\n {heading}\n <div className={s.panelActions}>{actions}</div>\n </div>\n ) : heading}\n <PanelNesting.Provider value>{children}</PanelNesting.Provider>\n </div>\n );\n}\n\n/** How a property list packs its rows into two columns. */\nexport type PropertyListPack = 'auto-color' | 'pairs' | 'one-up';\n\n/** Props for `<PropertyList>`. */\nexport interface PropertyListProps extends PropertyMetricProps {\n children: ReactNode;\n className?: string;\n /**\n * How rows pack into the 2-column grid.\n * - `'auto-color'` (default): only color rows pair side-by-side; everything\n * else spans the full width. Right for sparse top-level panels.\n * - `'pairs'`: every row auto-places into the 2-column grid two-per-row.\n * Headers and subpanels still span the full width; wrap any other\n * full-width child in `<PropertySpan>`. Right for dense effect bodies.\n * - `'one-up'`: every row spans the full width, color rows included. Right\n * for a palette — a column of swatches read as a group.\n */\n pack?: PropertyListPack;\n}\n\n/**\n * Grid container for PropertyRows. Use standalone for chrome-less layouts, or\n * nest inside <PropertyPanel/> for the standard glass card.\n */\nexport const PropertyList = forwardRef(function PropertyList(\n { children, className, pack = 'auto-color', density, align }: PropertyListProps,\n ref: Ref<HTMLDivElement>,\n) {\n const base = `${s.list}${pack === 'pairs' ? ` ${s.listPairs}` : pack === 'one-up' ? ` ${s.listOneUp}` : ''}`;\n return (\n <div ref={ref} className={propertyMetricClass(base, { density, align }, className)}>\n {children}\n </div>\n );\n});\n\n/** Props for `<PropertySpan>`. */\nexport interface PropertySpanProps {\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Wrapper that makes an arbitrary child span both columns of a\n * `<PropertyList pack=\"pairs\">`, a `<PropertyGroup pack=\"pairs\">` body, or a\n * `<Subpanel>`. `<PropertyRow span>` covers the row case; this covers\n * everything else a consumer puts in the grid.\n */\nexport function PropertySpan({ children, className }: PropertySpanProps) {\n return <div className={className ? `${s.span} ${className}` : s.span}>{children}</div>;\n}\n\n/** Props for `<PropertyNote>`. */\nexport interface PropertyNoteProps {\n children: ReactNode;\n className?: string;\n}\n\n/**\n * Muted paragraph that spans both columns of the grid — a group's help text,\n * sitting above the rows it describes rather than beside one of them.\n * `<PropertyRow description>` covers the per-row case.\n */\nexport function PropertyNote({ children, className }: PropertyNoteProps) {\n return <p className={className ? `${s.note} ${className}` : s.note}>{children}</p>;\n}\n\n/** Which control shape a row holds, which decides its intrinsic layout. */\nexport type PropertyRowVariant = 'default' | 'color' | 'checkbox';\n/** Whether a row's label sits above its control or beside it. */\nexport type PropertyRowLayout = 'block' | 'inline';\n\n/** Props for `<PropertyRow>`. */\nexport interface PropertyRowProps extends PropertyMetricProps {\n label: ReactNode;\n /** Right-aligned readout shown next to the label (e.g. current value). */\n readout?: ReactNode;\n /**\n * Help text for the row, shown in a tooltip off an ⓘ affordance beside the\n * label. Empty or absent renders no affordance.\n */\n description?: string;\n variant?: PropertyRowVariant;\n /**\n * Label position relative to the control. Unset takes the variant's own\n * orientation: `block` — label above control — for the default variant, and\n * `inline` for the color and checkbox variants, which read as a row.\n */\n layout?: PropertyRowLayout;\n /**\n * Take the full width of the enclosing grid. Only has an effect inside a\n * `<PropertyList pack=\"pairs\">` or a `<Subpanel>`; elsewhere rows are already\n * full width.\n */\n span?: boolean;\n children: ReactNode;\n htmlFor?: string;\n /** The control is a group of several (a segmented toggle), not one element.\n * The row then renders as a `<div>`: a `<label>` hands a click on its text to\n * its first control, which in a group means selecting the first option. Each\n * member has to carry its own name. */\n group?: boolean;\n className?: string;\n /** The row is auto: its value is not pinned and the owner computes it. The\n * control is hidden — its box kept, so the row does not resize — and the\n * row reads out the word instead. */\n auto?: boolean;\n /** Given, the row's label toggles `auto` when it is clicked. Omitted, the row\n * can show an auto state but not change it.\n *\n * The label then names that toggle, so a control passed as `children` has to\n * carry its own accessible name — every `<PropertyField>` does. */\n onAutoChange?: (next: boolean) => void;\n /** What an auto row does with its control. `'hidden'` (the default) keeps its\n * box and reads out the word instead; `'dimmed'` keeps drawing it, faded, for\n * an owner that passes the value the row inherits and pins on any edit. */\n autoControl?: 'hidden' | 'dimmed';\n /** Small muted text after the label — where an inherited value comes from. */\n hint?: ReactNode;\n}\n\n/** The label-plus-control frame `<PropertyField>` draws its rows in. Use it\n * directly for a control no field kind covers. */\nexport function PropertyRow({\n label,\n readout,\n description,\n variant = 'default',\n layout,\n span,\n children,\n htmlFor,\n group,\n className,\n density,\n align,\n auto,\n onAutoChange,\n autoControl = 'hidden',\n hint,\n}: PropertyRowProps) {\n const variantClass = variant === 'color' ? s.rowColor : variant === 'checkbox' ? s.rowCheckbox : '';\n // Each variant already lays out one way; a class is only needed for the\n // other one. The default variant stacks, so it needs `.rowInline`; color and\n // checkbox read as a row, so they need `.rowBlock`.\n const intrinsic: PropertyRowLayout = variant === 'default' ? 'block' : 'inline';\n const resolved = layout ?? intrinsic;\n const layoutClass =\n resolved === intrinsic ? '' : resolved === 'inline' ? s.rowInline : s.rowBlock;\n const cls = propertyMetricClass(\n [\n s.row,\n variantClass,\n layoutClass,\n span && s.span,\n auto && (autoControl === 'dimmed' ? s.rowAutoInherited : s.rowAuto),\n ]\n .filter(Boolean)\n .join(' '),\n { density, align },\n className,\n );\n // A stacked row reads label, readout, control down the column, so its readout\n // belongs on the label line. An inline row would put a value of changing width\n // in front of the control, which then moves under the pointer as it changes.\n const trailing = resolved === 'inline' && readout != null;\n const rowRef = useRef<HTMLElement | null>(null);\n const labelRef = useRef<HTMLSpanElement | null>(null);\n const multiline = useMultiline(rowRef, labelRef, resolved === 'inline');\n const head = (\n <span className={s.rowLabel} ref={labelRef}>\n {onAutoChange ? (\n <AutoToggle auto={auto ?? false} label={label} onChange={onAutoChange} />\n ) : (\n label\n )}\n {hint != null && <span className={s.rowHint}>{hint}</span>}\n {description ? <PropertyHelp label={label} description={description} /> : null}\n {readout != null && !trailing && <em className={s.readout}>{readout}</em>}\n </span>\n );\n const tail = trailing ? <em className={`${s.readout} ${s.readoutAfter}`}>{readout}</em> : null;\n const multi = multiline ? { 'data-multiline': '' } : {};\n return group ? (\n <div className={cls} ref={rowRef as RefObject<HTMLDivElement>} {...multi}>\n {head}\n {children}\n {tail}\n </div>\n ) : (\n <label\n className={cls}\n htmlFor={htmlFor}\n ref={rowRef as RefObject<HTMLLabelElement>}\n {...multi}\n >\n {head}\n {children}\n {tail}\n </label>\n );\n}\n\n/**\n * Whether an inline row runs past one line — its label wraps, or a child is\n * taller than a field. CSS can name the tall controls it knows (`:has()`), but\n * not a label that wrapped at this width, so the row measures. Never set\n * without layout, so jsdom always reads single-line.\n */\nfunction useMultiline(\n rowRef: RefObject<HTMLElement | null>,\n labelRef: RefObject<HTMLElement | null>,\n enabled: boolean,\n): boolean {\n const [multiline, setMultiline] = useState(false);\n useLayoutEffect(() => {\n const row = rowRef.current;\n const label = labelRef.current;\n if (!enabled || !row || !label || typeof ResizeObserver === 'undefined') {\n setMultiline(false);\n return;\n }\n const measure = (): void => {\n const labelStyle = getComputedStyle(label);\n const lineHeight =\n Number.parseFloat(labelStyle.lineHeight) ||\n Number.parseFloat(labelStyle.fontSize) * 1.2;\n const floor = Number.parseFloat(getComputedStyle(row).minHeight) || lineHeight;\n const labelWraps = label.getBoundingClientRect().height > lineHeight * 1.5;\n const tallChild = Array.from(row.children).some(\n (child) => child !== label && child.getBoundingClientRect().height > floor * 1.5,\n );\n setMultiline(labelWraps || tallChild);\n };\n const observer = new ResizeObserver(measure);\n observer.observe(row);\n observer.observe(label);\n for (const child of Array.from(row.children)) observer.observe(child);\n return () => observer.disconnect();\n }, [rowRef, labelRef, enabled]);\n return multiline;\n}\n\n/**\n * A row's label, doubling as the control for whether the row is auto: clicking\n * it hands the value back to whoever computes it, or takes it back.\n *\n * Pressed means pinned, to match the name — an auto row is the unpressed one.\n */\nfunction AutoToggle({\n auto,\n label,\n onChange,\n}: {\n auto: boolean;\n label: ReactNode;\n onChange: (next: boolean) => void;\n}) {\n const name = typeof label === 'string' ? label : 'this setting';\n const toggle = (e: { preventDefault: () => void; stopPropagation: () => void }) => {\n // The wrapping <label> would otherwise actuate the row's control.\n e.preventDefault();\n e.stopPropagation();\n onChange(!auto);\n };\n return (\n // A span, not a button: a <button> is a labelable element, so inside the\n // row's <label> it would take the row's name off the actual control.\n <span\n role=\"button\"\n tabIndex={0}\n className={s.autoToggle}\n aria-pressed={!auto}\n aria-label={`Pin ${name}`}\n onClick={toggle}\n onKeyDown={(e) => {\n // A native button gives Enter and Space for free; a span gives neither,\n // and Space would scroll the panel.\n if (e.key === 'Enter' || e.key === ' ') toggle(e);\n }}\n onMouseDown={(e) => e.stopPropagation()}\n >\n {label}\n </span>\n );\n}\n\n/** Props for `<PropertyHelp>`. */\nexport interface PropertyHelpProps {\n /** What the help is about; a string names the button `About <label>`. */\n label: ReactNode;\n description: string;\n}\n\n/** The ⓘ beside a row label that shows its `description` in a tooltip. Exported\n * for surfaces that draw a params label outside a `<PropertyRow>`. A tooltip\n * trigger has to be interactive to be keyboard-reachable, so this is a real\n * button. */\nexport function PropertyHelp({ label, description }: PropertyHelpProps) {\n const name = typeof label === 'string' ? label : 'this setting';\n return (\n <TooltipTrigger>\n <Focusable>\n <button\n type=\"button\"\n className={s.help}\n aria-label={`About ${name}`}\n onClick={(e) => {\n // The wrapping <label> would otherwise actuate the row's control.\n e.preventDefault();\n e.stopPropagation();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n >\n ⓘ\n </button>\n </Focusable>\n <Tooltip>{description}</Tooltip>\n </TooltipTrigger>\n );\n}\n","import {\n type ComponentProps,\n type CSSProperties,\n type ReactNode,\n type RefObject,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { decimal, parseAs, qty, type Display } from '@weasel-js/quantity';\nimport { dlog } from '../../dlog';\nimport { endlessAt } from '../../endless';\nimport { UnitField } from '../NumberField';\nimport { spinKey } from '../spin';\nimport shared from '../range.module.css';\nimport type { PropertyNumberFieldProps } from './PropertyField';\nimport { PropertyRow } from './PropertyPanel';\nimport s from './Properties.module.css';\n\n/**\n * A slider's props with its drag held locally. A caller taking settled values\n * only ignores `onInput`, so `value` stands still through the drag; without the\n * draft the controlled track snaps back on every move and commits from there.\n */\nfunction useSliderDraft(p: PropertyNumberFieldProps): PropertyNumberFieldProps {\n const [draft, setDraft] = useState<number>();\n const { onInput, onChange } = p;\n if (!onInput) return p;\n return {\n ...p,\n value: draft ?? p.value,\n onInput: (next) => {\n setDraft(next);\n onInput(next);\n },\n onChange: (next) => {\n setDraft(undefined);\n onChange(next);\n },\n };\n}\n\nexport function SliderRow({ row, readout, control }: {\n row: Omit<ComponentProps<typeof PropertyRow>, 'children'>;\n readout: ReactNode;\n control: PropertyNumberFieldProps;\n}) {\n const p = useSliderDraft(control);\n return (\n <PropertyRow {...row} readout={boxedReadout(readout) ?? <SliderReadout {...p} />}>\n <SliderTrack {...p} />\n </PropertyRow>\n );\n}\n\nexport function SliderCell(props: PropertyNumberFieldProps) {\n const p = useSliderDraft(props);\n return (\n <>\n <SliderTrack {...p} />\n <span className={s.cellReadout}>\n <SliderReadout {...p} />\n </span>\n </>\n );\n}\n\n/**\n * A ref for an input whose commit half has to come off a real listener.\n *\n * A native `range` input fires `input` through a drag and `change` once at\n * the end, but React's synthetic `onChange` sees only the first: its value\n * tracker drops the unchanged second. So a track offering the live/committed\n * split reads the live half from React and the committed half from here.\n * `commit` is `undefined` when the track has one callback, which then fires\n * continuously.\n */\nfunction useCommitListener(\n commit: ((raw: string) => void) | undefined,\n): RefObject<HTMLInputElement | null> {\n const ref = useRef<HTMLInputElement>(null);\n const latest = useRef(commit);\n useEffect(() => {\n latest.current = commit;\n });\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const onCommit = () => latest.current?.(el.value);\n el.addEventListener('change', onCommit);\n return () => el.removeEventListener('change', onCommit);\n }, []);\n return ref;\n}\n\nfunction unitSuffix(unit: ReactNode, className: string): ReactNode {\n if (unit == null) return null;\n return typeof unit === 'string' ? <span className={className}>{unit}</span> : unit;\n}\n\nexport const ignore = (): void => {};\n\nexport function NumberInput(p: PropertyNumberFieldProps) {\n const known = isKnown(p);\n const input = (\n <UnitField\n id={p.id}\n className={p.className ? `${s.numberField} ${p.className}` : s.numberField}\n value={known ? (p.value as number) : NaN}\n placeholder={p.mixed ? 'Mixed' : p.placeholder}\n minValue={p.min}\n maxValue={p.max}\n step={p.step}\n accepts={p.accepts}\n display={p.display}\n steppers={p.steppers}\n aria-label={p.name}\n // With one callback it is the live one: every keystroke and step reaches\n // it, and the commit on blur would only repeat the last of them.\n onInput={p.onInput ?? p.onChange}\n onChange={p.onInput ? p.onChange : ignore}\n />\n );\n if (p.unit == null || (known && !Number.isFinite(p.value))) return input;\n return (\n <span className={s.fieldUnitGroup}>\n {input}\n {unitSuffix(p.unit, s.readoutUnit)}\n </span>\n );\n}\n\n/** A value the field can show: a number, ±Infinity included, and not mixed. */\nfunction isKnown(p: PropertyNumberFieldProps): p is PropertyNumberFieldProps & { value: number } {\n return !p.mixed && typeof p.value === 'number' && !Number.isNaN(p.value);\n}\n\n/** The readout a slider shows when given no display: precision tracks `step`,\n * so integer steps show none, 0.1 one, 0.05 two. */\nexport function stepDisplay(step = 1): Display {\n return decimal({ places: step >= 1 ? 0 : Math.min(6, Math.max(0, Math.ceil(-Math.log10(step)))), grouping: false });\n}\n\n/** A slider's bounds, with the 0..100 fallback for an unbounded track, and\n * `settle`, which clamps a value onto the track and turns an endless end's\n * stop into ±Infinity. */\nfunction sliderBounds(p: PropertyNumberFieldProps): { min: number; max: number; step: number; settle: (v: number) => number } {\n const min = p.min ?? 0;\n const max = p.max ?? 100;\n const settle = (v: number) =>\n endlessAt(p.endless, 1) && v >= max ? Infinity\n : endlessAt(p.endless, -1) && v <= min ? -Infinity\n : Math.min(max, Math.max(min, v));\n return { min, max, step: p.step ?? 1, settle };\n}\n\nfunction SliderTrack(p: PropertyNumberFieldProps) {\n const { min, max, step, settle } = sliderBounds(p);\n const live = p.onInput ?? p.onChange;\n const commit = p.onInput ? p.onChange : undefined;\n const range = useCommitListener(commit && ((raw) => commit(settle(Number(raw)))));\n const known = isKnown(p);\n // The thumb clamps to the track; the readout beside it does not, so a value\n // past `max` is still reported as what it is.\n const value = known ? Math.min(Math.max(p.value as number, min), max) : min;\n return (\n // The shared skin with no fill: `InlineRange`'s filled-to-value track is its\n // own, and the property rows' 18% track is the one the kit converges on.\n <input\n ref={range}\n type=\"range\"\n id={p.id}\n className={p.className ? `${shared.range} ${p.className}` : shared.range}\n aria-label={p.name}\n // The readout is the keyboard's way in, and steps as the track would; a\n // tab stop here too would be two stops for one value.\n tabIndex={-1}\n min={min}\n max={max}\n step={step}\n value={value}\n disabled={p.mixed}\n onChange={(e) => {\n const v = settle(Number(e.target.value));\n dlog('property-panel', 'slider', { name: p.name, value: v });\n live(v);\n }}\n />\n );\n}\n\nfunction SliderReadout(p: PropertyNumberFieldProps) {\n const { min, max, step, settle } = sliderBounds(p);\n if (!isKnown(p)) return <>{boxedReadout('—')}</>;\n return (\n <EditableReadout\n name={p.name}\n value={p.value}\n min={min}\n max={max}\n step={step}\n settle={settle}\n display={p.display ?? stepDisplay(step)}\n format={p.format}\n unit={p.unit}\n onCommit={(next) => {\n p.onInput?.(next);\n p.onChange(next);\n }}\n />\n );\n}\n\n/**\n * A replacement readout in the box `EditableReadout` would have occupied.\n *\n * A row that can go auto swaps its editable readout for a word, and the label\n * is a flex line: an input is taller than bare text — a text input's inner\n * editor will not shrink to a line-height below the font's own content area —\n * so the swap moved the label's baseline, and the whole row with it. Only the\n * slider owns an `EditableReadout`, so only it needs this; giving every text\n * readout the box moves the rows that never had an input.\n */\nfunction boxedReadout(readout: ReactNode): ReactNode {\n if (typeof readout !== 'string' && typeof readout !== 'number') return readout;\n return (\n <span className={s.readoutGroup}>\n <span className={s.readoutText}>{readout}</span>\n </span>\n );\n}\n\ninterface EditableReadoutProps {\n name: string | undefined;\n value: number;\n min: number;\n max: number;\n step: number;\n /** Clamps onto the track, turning an endless end's stop into ±Infinity. */\n settle: (v: number) => number;\n display: Display;\n format?: (value: number) => ReactNode;\n unit?: ReactNode;\n onCommit: (next: number) => void;\n}\n\n/**\n * Readout that swaps to a number input on click, commits on Enter/blur,\n * cancels on Escape, and steps like the track beside it. Clicks are stopped so\n * a wrapping <label> doesn't forward focus to the slider thumb.\n */\nfunction EditableReadout({ name, value, min, max, step, settle, display, format, unit, onCommit }: EditableReadoutProps) {\n // Draft is non-null only while the input is focused; the live value mirrors\n // into the input otherwise.\n const [draft, setDraft] = useState<string | null>(null);\n const text = (n: number) => (format ? String(format(n)) : qty(n, display).text);\n const read = (typed: string) => parseAs(typed, display);\n const displayValue = draft !== null ? draft : text(value);\n // The widest value the range can show, which the stylesheet widens the box to fit.\n const fit = { '--wzl-property-readout-fit': `${Math.max(text(settle(min)).length, text(settle(max)).length)}ch` };\n // Where the value sits on the track: an endless end's ±Infinity at its stop.\n const onTrack = (v: number) => Math.min(max, Math.max(min, v));\n\n const commit = () => {\n if (draft !== null) {\n const n = read(draft);\n if (!Number.isNaN(n)) onCommit(settle(n));\n }\n setDraft(null);\n };\n\n return (\n <span className={s.readoutGroup}>\n <input\n type=\"text\"\n role=\"spinbutton\"\n aria-label={name}\n aria-valuenow={onTrack(value)}\n aria-valuetext={format ? text(value) : qty(value, display).spoken}\n aria-valuemin={min}\n aria-valuemax={max}\n inputMode=\"decimal\"\n className={s.readoutInput}\n style={fit as CSSProperties}\n value={displayValue}\n onFocus={(e) => {\n setDraft(text(value));\n e.currentTarget.select();\n }}\n onChange={(e) => setDraft(e.target.value.replace(/-/g, '−'))}\n onBlur={commit}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n e.currentTarget.focus();\n }}\n onMouseDown={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n commit();\n e.currentTarget.blur();\n } else if (e.key === 'Escape') {\n setDraft(null);\n e.currentTarget.blur();\n } else {\n const typed = draft === null ? value : read(draft);\n const next = spinKey(e.key, onTrack(Number.isNaN(typed) ? value : typed), { step, min, max });\n if (next === null) return;\n e.preventDefault();\n onCommit(settle(next));\n // A step is committed already; the box shows the value it comes back as.\n setDraft(null);\n }\n }}\n />\n {/* A word for infinity stands alone: `never`, not `never ms`. */}\n {Number.isFinite(value) && unitSuffix(unit, s.readoutUnit)}\n </span>\n );\n}\n","import {\n type ReactNode,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { getAlpha01, toHex8, withAlpha01, type FillStyle, type PaintKind } from '@weasel-js/core';\nimport { dlog } from '../../dlog';\nimport type { Display, UnitTable } from '@weasel-js/quantity';\nimport { ColorField } from '../ColorField';\nimport { FontFamilySelect } from '../FontFamilySelect';\nimport { FontWeightSelect } from '../FontWeightSelect';\nimport { Input } from '../Input';\nimport { PaintField } from '../PaintField';\nimport { PaintInput } from '../PaintInput';\nimport { Radio, RadioGroup } from '../RadioGroup';\nimport { Select } from '../Select';\nimport { Switch } from '../Switch';\nimport { FitLabel, labelForms } from '../FitLabel/FitLabel';\nimport { ToggleBar } from '../ToggleBar';\nimport sharedCheckbox from '../checkbox.module.css';\nimport {\n type PropertyMetricProps,\n PropertyRow,\n type PropertyRowLayout,\n type PropertyRowVariant,\n} from './PropertyPanel';\nimport s from './Properties.module.css';\nimport type { Endless } from '../../endless';\nimport { ignore, NumberInput, SliderCell, SliderRow } from './NumberControls';\n\n/** One choice of an enum field. */\nexport interface PropertyOption<T extends string> {\n value: T;\n /** The option's name. A string also names its segment for a screen reader. */\n label: ReactNode;\n /** Shorter forms of `label`, longest first. A segment too narrow for\n * `label` shows the longest that fits; `label` stays the accessible name.\n * A select has room for the label and leaves these out. */\n short?: readonly string[];\n /** A glyph a segment draws in place of any text form, with `label` as its\n * tooltip. A select draws it beside the label. */\n glyph?: ReactNode;\n /** Shown but not choosable: a value the control reports and cannot author. */\n disabled?: boolean;\n}\n\n/** Props every kind of field shares. */\ninterface FieldBase {\n /** The control's accessible name. A `<PropertyField>` takes it from a string\n * `label` when this is omitted. */\n name?: string;\n /** The sources the field reads disagree — a multi-selection whose nodes\n * differ. The control shows no value, in whatever form it has for that. */\n mixed?: boolean;\n /**\n * The sources agree on holding nothing: whatever is in effect comes from a\n * fallback further down. The control shows no chosen value rather than\n * inventing one, since the next edit would write the invention back.\n */\n unset?: boolean;\n /** Class on the control element itself. */\n className?: string;\n /** Id for the control element, for a `<label htmlFor>` outside it. */\n id?: string;\n}\n\n/** A boolean field. */\nexport interface PropertyBooleanFieldProps extends FieldBase {\n kind: 'boolean';\n /** `checkbox` (default), `switch`, or `toggle` — a one-segment pressable bar. */\n control?: 'checkbox' | 'switch' | 'toggle';\n /** Absent reads as off. */\n value: boolean | undefined;\n onChange: (next: boolean) => void;\n /** Shorter forms of `name`, longest first, for a `toggle` segment too\n * narrow for the whole name. */\n short?: readonly string[];\n /** A glyph a `toggle` segment draws in place of any text form. */\n glyph?: ReactNode;\n}\n\n/** A number field. */\nexport interface PropertyNumberFieldProps extends FieldBase {\n kind: 'number';\n /** `input` (default) for a typed number; `slider` for a track with an\n * editable readout, where the range matters more than the exact value. */\n control?: 'input' | 'slider';\n /** Absent reads as an empty field. */\n value: number | null | undefined;\n /**\n * The committed value. Given `onInput` as well, it fires once a drag ends,\n * or on blur, Enter or a step in a typed field; on its own it fires on every\n * move, keystroke and step. A caller wanting settled values only passes a\n * no-op `onInput`.\n */\n onChange: (next: number) => void;\n /** The live value, fired continuously. Pass it alongside `onChange` when the\n * write is expensive — cheap state here, the costly work there. */\n onInput?: (next: number) => void;\n /** A slider's track runs 0..100 where these are omitted. */\n min?: number;\n max?: number;\n step?: number;\n /** Which end stop of a slider stands for infinity: dragged there, it\n * reports `Infinity` (`-Infinity` at `min`), and a value of ±Infinity sits\n * there. The readout shows `display`'s word for it — `endless(unit('ms'),\n * 'never')` reads `never` — else `∞`, and drops `unit` beside it. */\n endless?: Endless;\n /**\n * Suffix after the value. A string becomes a dim word unit (`px`); pass JSX\n * like `<sup>°</sup>` for a symbol. Display only — the value stays a number.\n */\n unit?: ReactNode;\n /** Units a person may type into a typed field, each mapped to the factor\n * that turns it into the unit shown: `{ mm: 0.1, cm: 1 }`. */\n accepts?: Readonly<UnitTable>;\n /** How the value shows, is spoken, and reads back when typed —\n * `compact()` reads `2.00M`. A slider readout defaults to the value at\n * `step`'s precision. */\n display?: Display;\n /** A slider readout's text, for what no display expresses — a derived\n * value. Wins over `display`, and is spoken as shown. */\n format?: (value: number) => ReactNode;\n placeholder?: string;\n /** A typed field's up and down buttons. Default `false`: a dense panel\n * drives its numbers by typing, the arrow keys and the wheel. */\n steppers?: boolean;\n}\n\n/** A text field. */\nexport interface PropertyStringFieldProps extends FieldBase {\n kind: 'string';\n control?: 'input' | 'textarea';\n /** Absent reads as an empty field. */\n value: string | null | undefined;\n /**\n * The committed text. On its own it fires on every keystroke. Given\n * `onInput` as well, the field drafts: `onInput` gets each keystroke and\n * this fires once, on blur or Enter, and only if the text changed.\n */\n onChange: (next: string) => void;\n onInput?: (next: string) => void;\n placeholder?: string;\n maxLength?: number;\n}\n\n/** A choice among fixed options. */\nexport interface PropertyEnumFieldProps<T extends string = string> extends FieldBase {\n kind: 'enum';\n /**\n * `select` (default) is a dropdown. `radio` and `toggle` show every option\n * at once — a radio group lists them, and a toggle is a row of segments.\n */\n control?: 'select' | 'radio' | 'toggle';\n /** Absent, or not one of `options`, chooses nothing. */\n value: T | undefined;\n options: ReadonlyArray<PropertyOption<T>>;\n onChange: (next: T) => void;\n /**\n * Given, choosing nothing is a value of its own: a `toggle` lets the chosen\n * segment be clicked off, and calls this. Absent, a toggle always holds one.\n */\n onClear?: () => void;\n /** Shown while no option is chosen. Defaults to \"Choose option…\". */\n placeholder?: string;\n}\n\n/** A single color. */\nexport interface PropertyColorFieldProps extends FieldBase {\n kind: 'color';\n /** `#rrggbb`, or `#rrggbbaa` when `alpha` is `true`. */\n value: string | undefined;\n /**\n * The committed color. Given `onInput` as well, it fires once per gesture —\n * the picker closing, or the opacity track let go; on its own it fires on\n * every move. A caller wanting settled values only passes a no-op `onInput`.\n */\n onChange: (next: string) => void;\n onInput?: (next: string) => void;\n /**\n * Offer an opacity track. `true` keeps the alpha in `value` as `#rrggbbaa`;\n * a number is the 0..1 alpha held apart from it, reported through\n * `onAlphaChange` / `onAlphaInput`.\n */\n alpha?: boolean | number;\n onAlphaChange?: (next: number) => void;\n onAlphaInput?: (next: number) => void;\n /** Draw the opacity track inert, for a consumer that drops alpha. */\n alphaDisabled?: boolean;\n}\n\n/** A whole paint: a solid, a gradient, a pattern, or none. */\nexport interface PropertyPaintFieldProps extends FieldBase {\n kind: 'paint';\n /** `swatch` (default) opens the editor in a popover, for a narrow slot;\n * `inline` draws the kind bar and its editor in place. */\n control?: 'swatch' | 'inline';\n /** `null` is an explicit \"no paint\"; `undefined` is nothing to show. */\n value: FillStyle | null | undefined;\n onChange: (next: FillStyle | null) => void;\n onInput?: (next: FillStyle | null) => void;\n /** Offer \"None\". Default `true`. */\n allowNone?: boolean;\n /** Restrict the kinds offered. Default: every registered kind. */\n kinds?: readonly PaintKind[];\n}\n\n/** A font family, picked from the live font registry. */\nexport interface PropertyFontFamilyFieldProps extends FieldBase {\n kind: 'font-family';\n value: string | undefined;\n onChange: (next: string) => void;\n /** The weight and slant the family is drawn at, so the picker names the\n * variant that will actually paint. */\n weight?: number;\n fontStyle?: 'normal' | 'italic';\n}\n\n/** A font weight, picked from the weights its family has registered. */\nexport interface PropertyFontWeightFieldProps extends FieldBase {\n kind: 'font-weight';\n value: number | undefined;\n onChange: (next: number) => void;\n /** The family whose weights to offer. */\n family?: string;\n}\n\n/**\n * One field for {@link PropertyControl} and {@link PropertyField}, keyed by\n * `kind`.\n */\nexport type PropertyControlProps<T extends string = string> =\n | PropertyBooleanFieldProps\n | PropertyNumberFieldProps\n | PropertyStringFieldProps\n | PropertyEnumFieldProps<T>\n | PropertyColorFieldProps\n | PropertyPaintFieldProps\n | PropertyFontFamilyFieldProps\n | PropertyFontWeightFieldProps;\n\n/** The kinds a {@link PropertyControl} draws. */\nexport type PropertyFieldKind = PropertyControlProps['kind'];\n\n/** Row props {@link PropertyField} adds to the field it draws. */\nexport interface PropertyFieldRowProps extends PropertyMetricProps {\n label: ReactNode;\n /**\n * Text beside the label. On a slider it replaces the editable readout —\n * use it when the row is not showing a number a caller could type back,\n * such as an auto row's `auto`.\n */\n readout?: ReactNode;\n description?: string;\n layout?: PropertyRowLayout;\n /** Take the full width of the enclosing grid — see `<PropertyRow span>`. */\n span?: boolean;\n /** The row is auto — see `<PropertyRow auto>`. */\n auto?: boolean;\n /** Toggles `auto` from the row's label — see `<PropertyRow onAutoChange>`. */\n onAutoChange?: (next: boolean) => void;\n /** Class on the row. `controlClassName` reaches the control. */\n rowClassName?: string;\n controlClassName?: string;\n}\n\n/** Props for {@link PropertyField}: one field, and the row around it. */\nexport type PropertyFieldProps<T extends string = string> = PropertyFieldRowProps &\n DistributiveOmit<PropertyControlProps<T>, 'className' | 'id'>;\n\ntype DistributiveOmit<U, K extends PropertyKey> = U extends unknown ? Omit<U, K> : never;\n\n/**\n * A labeled settings row for one field, its control chosen by `kind` (and\n * `control`): `<PropertyField kind=\"number\" control=\"slider\" label=\"Blur\" …>`.\n *\n * The row is a {@link PropertyRow}; the control is the one\n * {@link PropertyControl} draws for the same props. Every schema-driven\n * settings surface in the kit — `ControlPanel`, `PrefsForm`, `SelectionPanel`\n * — draws its built-in kinds through that one mapping, so a kind's control\n * is decided once.\n *\n * Callbacks follow the field's shape: a discrete control (a box, a choice)\n * reports each pick; a continuous or typed one reports every change through\n * `onChange` alone, or splits them into live `onInput` and settled\n * `onChange` when given both. `mixed` and `unset` show a field whose sources\n * disagree, or agree on holding nothing.\n */\nexport function PropertyField<T extends string = string>(props: PropertyFieldProps<T>) {\n const {\n label,\n readout,\n description,\n layout,\n span,\n density,\n align,\n auto,\n onAutoChange,\n rowClassName,\n controlClassName,\n ...field\n } = props;\n const id = useId();\n // Internally a field's option type is erased to `string`: nothing below\n // reads it, and the caller's `onChange` still receives its own `T`.\n const control = {\n ...field,\n name: field.name ?? nameOf(label),\n className: controlClassName,\n id,\n } as unknown as PropertyControlProps;\n const shape = rowShape(control);\n\n const row = {\n label,\n description,\n layout,\n span,\n density,\n align,\n auto,\n onAutoChange,\n className: rowClassName,\n variant: shape.variant,\n group: shape.group,\n // The font pickers take no id; any other single control is named by the\n // row's `<label>` through this one.\n htmlFor: shape.group || control.kind === 'font-family' || control.kind === 'font-weight'\n ? undefined\n : id,\n };\n\n if (control.kind === 'number' && control.control === 'slider') {\n return <SliderRow row={row} readout={readout} control={control} />;\n }\n return (\n <PropertyRow {...row} readout={readout}>\n <ControlBody {...control} />\n </PropertyRow>\n );\n}\n\n/**\n * The control for one field, with no row around it — for a cell that shares\n * a row with others, or a surface that draws its own row. Keyed by `kind`\n * (and `control`), the same mapping {@link PropertyField} draws.\n *\n * A slider brings its readout beside the track. Several elements come back\n * as siblings rather than wrapped, so the surrounding row lays them out.\n */\nexport function PropertyControl<T extends string = string>(typed: PropertyControlProps<T>) {\n const props = typed as unknown as PropertyControlProps;\n if (props.kind === 'number' && props.control === 'slider') return <SliderCell {...props} />;\n return <ControlBody {...props} />;\n}\n\n/** How a row holds a field's control. */\nfunction rowShape(p: PropertyControlProps<string>): { variant: PropertyRowVariant; group: boolean } {\n switch (p.kind) {\n case 'boolean':\n // A switch renders its own <label>, and a segment is a button: neither\n // may sit inside the row's.\n return { variant: 'checkbox', group: p.control === 'switch' || p.control === 'toggle' };\n case 'enum':\n // A <label> hands a click on its text to its first control, which in a\n // group of options means choosing the first one.\n return { variant: 'default', group: p.control === 'radio' || p.control === 'toggle' };\n case 'color':\n return { variant: 'color', group: false };\n case 'paint':\n return { variant: 'default', group: true };\n default:\n return { variant: 'default', group: false };\n }\n}\n\nfunction ControlBody(props: PropertyControlProps) {\n switch (props.kind) {\n case 'boolean':\n return <BooleanControl {...props} />;\n case 'number':\n return <NumberInput {...props} />;\n case 'string':\n return <StringControl {...props} />;\n case 'enum':\n return <EnumControl {...props} />;\n case 'color':\n return <ColorControl {...props} />;\n case 'paint':\n return <PaintControl {...props} />;\n case 'font-family':\n return (\n <FontFamilySelect\n className={props.className}\n value={props.mixed ? undefined : props.value}\n mixed={props.mixed}\n onChange={props.onChange}\n weight={props.weight}\n fontStyle={props.fontStyle}\n aria-label={props.name}\n />\n );\n case 'font-weight':\n return (\n <FontWeightSelect\n className={props.className}\n value={props.mixed ? undefined : props.value}\n mixed={props.mixed}\n family={props.family}\n onChange={props.onChange}\n aria-label={props.name}\n />\n );\n default: {\n // Unreachable while every kind has an arm; a new kind without one is a\n // compile error here rather than an empty cell.\n const _exhaustive: never = props;\n throw new Error(`PropertyControl: no control for kind \"${(_exhaustive as { kind: string }).kind}\"`);\n }\n }\n}\n\n// ── Kinds ────────────────────────────────────────────────────────────────\n\n/** A cue for a state the control itself cannot draw: a switch has no\n * indeterminate form, and nothing has an \"unset\" one. */\nfunction Dimmed({ mixed, unset, children }: { mixed?: boolean; unset?: boolean; children: ReactNode }) {\n if (!mixed && !unset) return <>{children}</>;\n return (\n <span className={s.dimmed} title={mixed ? 'Mixed' : 'Not set'}>\n {children}\n </span>\n );\n}\n\nfunction BooleanControl(p: PropertyBooleanFieldProps) {\n const on = !p.mixed && p.value === true;\n const box = useRef<HTMLInputElement>(null);\n useEffect(() => {\n if (box.current) box.current.indeterminate = p.mixed === true;\n });\n if (p.control === 'toggle') {\n // Unselected already is how a toggle button says \"not set\", and dimming it\n // would read as disabled; mixed has a real ARIA form on one.\n const key = 'on';\n return (\n <ToggleBar<string>\n mode=\"multiple\"\n size=\"sm\"\n variant=\"flat\"\n className={p.className}\n ariaLabel={p.name}\n items={[{ value: key, label: p.glyph ?? <FitLabel forms={labelForms(p.name, p.short)} />, ariaLabel: p.name }]}\n value={on ? [key] : []}\n mixedValues={p.mixed ? [key] : []}\n onChange={(next) => p.onChange(next.includes(key))}\n />\n );\n }\n if (p.control === 'switch') {\n return (\n <Dimmed mixed={p.mixed} unset={p.unset}>\n <Switch className={p.className} isSelected={on} onChange={p.onChange} aria-label={p.name} />\n </Dimmed>\n );\n }\n // A native box rather than the kit's `Checkbox`: that one renders a `<label>`\n // of its own, which may not sit inside the row's, and without the row's the\n // label text would no longer toggle it.\n return (\n <Dimmed unset={p.unset}>\n <input\n ref={box}\n id={p.id}\n type=\"checkbox\"\n className={p.className ? `${sharedCheckbox.checkbox} ${p.className}` : sharedCheckbox.checkbox}\n aria-label={p.name}\n checked={on}\n onChange={(e) => p.onChange(e.target.checked)}\n />\n </Dimmed>\n );\n}\n\n/**\n * The text a field shows and how an edit to it lands. With `onInput` the\n * field drafts: the draft shows while it differs from `value`, and settles\n * through `onChange` on blur or Enter. Without it, every keystroke is the\n * value.\n */\nfunction useTextEdit(p: PropertyStringFieldProps) {\n const [draft, setDraft] = useState<string | null>(null);\n const value = p.mixed ? '' : (p.value ?? '');\n const drafting = p.onInput !== undefined;\n return {\n shown: draft ?? value,\n type: (next: string) => {\n if (!drafting) {\n p.onChange(next);\n return;\n }\n setDraft(next);\n p.onInput?.(next);\n },\n settle: () => {\n if (draft !== null && draft !== value) p.onChange(draft);\n setDraft(null);\n },\n };\n}\n\nfunction StringControl(p: PropertyStringFieldProps) {\n const edit = useTextEdit(p);\n const placeholder = p.mixed ? 'Mixed' : p.placeholder;\n if (p.control === 'textarea') {\n return (\n <textarea\n id={p.id}\n className={p.className ? `${s.textarea} ${p.className}` : s.textarea}\n aria-label={p.name}\n value={edit.shown}\n placeholder={placeholder}\n maxLength={p.maxLength}\n rows={3}\n onChange={(e) => edit.type(e.target.value)}\n onBlur={edit.settle}\n />\n );\n }\n return (\n <Input\n id={p.id}\n className={p.className ? `${s.textField} ${p.className}` : s.textField}\n value={edit.shown}\n placeholder={placeholder}\n maxLength={p.maxLength}\n aria-label={p.name}\n onChange={edit.type}\n onBlur={edit.settle}\n onKeyDown={(e) => {\n if (e.key === 'Enter') (e.target as HTMLElement).blur();\n }}\n />\n );\n}\n\n// A row's <label> text also holds the help button's ⓘ and any readout, so a\n// control takes its name from the string label, not from the <label> that\n// `for` points at it.\nfunction nameOf(label: ReactNode): string | undefined {\n return typeof label === 'string' ? label : undefined;\n}\n\n/** A segment drawing a glyph hides its label, so the label comes back as its tooltip. */\nfunction glyphTip(o: PropertyOption<string>): ReactNode {\n return o.glyph === undefined || o.glyph === null ? undefined : o.label;\n}\n\nfunction EnumControl(p: PropertyEnumFieldProps) {\n const chosen = !p.mixed && p.options.some((opt) => opt.value === p.value);\n const current = chosen ? (p.value as string) : null;\n\n if (p.control === 'radio') {\n return (\n <RadioGroup className={p.className} value={current} onChange={p.onChange} aria-label={p.name}>\n {p.options.map((o) => (\n <Radio key={o.value} value={o.value} isDisabled={o.disabled}>\n {o.label}\n </Radio>\n ))}\n </RadioGroup>\n );\n }\n if (p.control === 'toggle' && p.onClear) {\n // `multiple` for what `single` cannot give: a mixed state on each segment,\n // and arrow keys that move focus without choosing. At most one stays lit —\n // the segment just added wins, and adding none means the lit one was\n // clicked off.\n const { onClear } = p;\n const lit = current === null ? [] : [current];\n return (\n <ToggleBar<string>\n mode=\"multiple\"\n size=\"sm\"\n variant=\"flat\"\n className={p.className ? `${s.toggleBar} ${p.className}` : s.toggleBar}\n ariaLabel={p.name}\n items={p.options.map((o) => ({\n value: o.value,\n label: o.glyph ?? <FitLabel forms={labelForms(o.label, o.short)} />,\n ariaLabel: nameOf(o.label),\n tooltip: glyphTip(o),\n disabled: o.disabled,\n }))}\n value={lit}\n mixedValues={p.mixed ? p.options.map((o) => o.value) : []}\n onChange={(next) => {\n const added = next.find((v) => !lit.includes(v));\n if (added !== undefined) p.onChange(added);\n else onClear();\n }}\n />\n );\n }\n if (p.control === 'toggle') {\n return (\n <ToggleBar<string>\n size=\"sm\"\n variant=\"flat\"\n className={p.className ? `${s.toggleBar} ${p.className}` : s.toggleBar}\n ariaLabel={p.name}\n items={p.options.map((o) => ({\n value: o.value,\n label: o.glyph ?? <FitLabel forms={labelForms(o.label, o.short)} />,\n ariaLabel: nameOf(o.label),\n tooltip: glyphTip(o),\n disabled: o.disabled,\n }))}\n value={current}\n onChange={(next) => {\n if (next !== null) p.onChange(next);\n }}\n />\n );\n }\n return (\n <Select<string>\n className={p.className ? `${s.select} ${p.className}` : s.select}\n triggerId={p.id}\n aria-label={p.name}\n placeholder={p.mixed ? 'Mixed' : (p.placeholder ?? (p.unset ? '—' : 'Choose option…'))}\n selectedKey={current}\n options={p.options.map((o) => ({\n value: o.value,\n label: o.label,\n icon: o.glyph,\n isDisabled: o.disabled,\n }))}\n onSelectionChange={(v) => {\n dlog('property-panel', 'select', { name: p.name, value: v });\n p.onChange(v);\n }}\n />\n );\n}\n\n/** A hex color as the `#rrggbb` it paints and the 0..1 alpha beside it.\n * Anything unreadable is opaque black, which is what a swatch would show for\n * it anyway. */\nfunction splitAlpha(value: string | undefined): { rgb: string; alpha: number } {\n const eight = toHex8(value?.trim() ?? '');\n if (!/^#[0-9a-f]{8}$/i.test(eight)) return { rgb: '#000000', alpha: 1 };\n return { rgb: eight.slice(0, 7).toLowerCase(), alpha: getAlpha01(eight) };\n}\n\nfunction ColorControl(p: PropertyColorFieldProps) {\n const withAlpha = p.alpha !== undefined && p.alpha !== false;\n const apart = typeof p.alpha === 'number';\n const split = splitAlpha(p.value);\n const alpha = apart ? (p.alpha as number) : split.alpha;\n\n // `ColorField` holds alpha in the hex. One kept in a channel of its own goes\n // in with the color and comes back out of it, each half to its own callback.\n const route =\n (write: (hex: string) => void, own: ((a: number) => void) | undefined) => (hex: string) => {\n if (!apart) {\n write(hex);\n return;\n }\n const next = splitAlpha(hex);\n if (next.rgb !== split.rgb || !own) write(next.rgb);\n // Read back at the track's percent, which is all a hex byte can hold of it.\n const a = Math.round(next.alpha * 100) / 100;\n if (a !== Math.round(alpha * 100) / 100) own?.(a);\n };\n // As a number does: one callback is the live one, and the commit at the end\n // of a gesture would only repeat its last call.\n const drafting = p.onInput !== undefined || p.onAlphaInput !== undefined;\n const live = route(p.onInput ?? p.onChange, p.onAlphaInput ?? p.onAlphaChange);\n const settled = drafting ? route(p.onChange, p.onAlphaChange) : ignore;\n return (\n <ColorField\n id={p.id}\n className={p.className ? `${s.colorField} ${p.className}` : s.colorField}\n value={p.mixed ? undefined : withAlpha ? withAlpha01(split.rgb, alpha) : (p.value ?? '#000000')}\n mixed={p.mixed}\n alpha={withAlpha}\n alphaDisabled={p.alphaDisabled}\n onInput={live}\n onChange={settled}\n aria-label={p.name}\n />\n );\n}\n\nfunction PaintControl(p: PropertyPaintFieldProps) {\n const Editor = p.control === 'inline' ? PaintInput : PaintField;\n return (\n <Editor\n className={p.className}\n value={p.value}\n mixed={p.mixed}\n unset={p.unset}\n kinds={p.kinds}\n allowNone={p.allowNone}\n onChange={p.onChange}\n onInput={p.onInput}\n aria-label={p.name}\n />\n );\n}\n"],"mappings":"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"}