@forte-ui/react 1.0.0-alpha.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 (304) hide show
  1. package/README.md +240 -0
  2. package/dist/Accordion-9JunkjgY.js +111 -0
  3. package/dist/Alert-Cn_WUF3L.js +183 -0
  4. package/dist/AspectRatio-gSjpTVk-.js +39 -0
  5. package/dist/Avatar-BuitDluH.js +87 -0
  6. package/dist/Badge-sArNWMre.js +33 -0
  7. package/dist/Breadcrumb-Cq7tFtMX.js +170 -0
  8. package/dist/Button-AiyKnx5I.js +42 -0
  9. package/dist/ButtonGroup-C-CrwPXP.js +54 -0
  10. package/dist/Calendar-D7Q-QJ_e.js +503 -0
  11. package/dist/Checkbox-DfNbmOed.js +56 -0
  12. package/dist/Collapsible-D8UKiGip.js +86 -0
  13. package/dist/ColorPicker-B-eCI31W.js +612 -0
  14. package/dist/Combobox-D-BN-Tvp.js +302 -0
  15. package/dist/ContextMenu-D81uDaMG.js +44 -0
  16. package/dist/DatePicker-CfkMsaI-.js +192 -0
  17. package/dist/Dialog-_n8FpFs5.js +432 -0
  18. package/dist/Drawer-DKQF3OO7.js +158 -0
  19. package/dist/Field-FLFEO70D.js +58 -0
  20. package/dist/Fieldset-CYhh71Qt.js +28 -0
  21. package/dist/Form-DVPmW9XV.js +17 -0
  22. package/dist/Input-BgGWhO2q.js +18 -0
  23. package/dist/InputGroup-DsZyDXNn.js +89 -0
  24. package/dist/Menu-CKu9xE2h.js +261 -0
  25. package/dist/Menubar-Dax027Db.js +19 -0
  26. package/dist/NavList-DGvcIoJm.js +176 -0
  27. package/dist/NavigationMenu-BayQkUUb.js +209 -0
  28. package/dist/NumberField-P55SA8T7.js +191 -0
  29. package/dist/OTPField-CjHvBNSN.js +55 -0
  30. package/dist/Popover-BXhn2Wwt.js +142 -0
  31. package/dist/PreviewCard-Dnitrky0.js +99 -0
  32. package/dist/Progress-BlomDp-X.js +81 -0
  33. package/dist/ProgressCircle-j6XBl0fk.js +112 -0
  34. package/dist/Radio-BIcX4INJ.js +37 -0
  35. package/dist/Resizable-7nJJM97e.js +609 -0
  36. package/dist/ScrollArea-CBMGJ6hh.js +83 -0
  37. package/dist/Select-BP-zvdXm.js +237 -0
  38. package/dist/Separator-DewJBzaJ.js +21 -0
  39. package/dist/Skeleton-zr6ObCCq.js +79 -0
  40. package/dist/Slider-Bh8_cti1.js +104 -0
  41. package/dist/Spinner-BF0uD4hR.js +53 -0
  42. package/dist/Switch-OBewMMvM.js +39 -0
  43. package/dist/Tabs-LgkSbPSF.js +132 -0
  44. package/dist/Textarea-CqZJL41e.js +51 -0
  45. package/dist/Toast-BWayxAcd.js +304 -0
  46. package/dist/Toggle-BrhMnkF5.js +45 -0
  47. package/dist/Toolbar-OmOVCk3i.js +88 -0
  48. package/dist/Tooltip-CI4chsRw.js +101 -0
  49. package/dist/clsx-By2n9mTe.js +16 -0
  50. package/dist/cn.d.ts +8 -0
  51. package/dist/cn.js +11 -0
  52. package/dist/components/accordion/Accordion.d.ts +117 -0
  53. package/dist/components/accordion/Accordion.js +3 -0
  54. package/dist/components/accordion/index.d.ts +2 -0
  55. package/dist/components/accordion/index.js +2 -0
  56. package/dist/components/alert/Alert.d.ts +167 -0
  57. package/dist/components/alert/Alert.js +3 -0
  58. package/dist/components/alert/index.d.ts +2 -0
  59. package/dist/components/alert/index.js +2 -0
  60. package/dist/components/aspect-ratio/AspectRatio.d.ts +128 -0
  61. package/dist/components/aspect-ratio/AspectRatio.js +3 -0
  62. package/dist/components/aspect-ratio/index.d.ts +2 -0
  63. package/dist/components/aspect-ratio/index.js +2 -0
  64. package/dist/components/avatar/Avatar.d.ts +176 -0
  65. package/dist/components/avatar/Avatar.js +3 -0
  66. package/dist/components/avatar/index.d.ts +2 -0
  67. package/dist/components/avatar/index.js +2 -0
  68. package/dist/components/badge/Badge.d.ts +117 -0
  69. package/dist/components/badge/Badge.js +3 -0
  70. package/dist/components/badge/index.d.ts +2 -0
  71. package/dist/components/badge/index.js +2 -0
  72. package/dist/components/breadcrumb/Breadcrumb.d.ts +244 -0
  73. package/dist/components/breadcrumb/Breadcrumb.js +3 -0
  74. package/dist/components/breadcrumb/index.d.ts +2 -0
  75. package/dist/components/breadcrumb/index.js +2 -0
  76. package/dist/components/button/Button.d.ts +73 -0
  77. package/dist/components/button/Button.js +3 -0
  78. package/dist/components/button/index.d.ts +2 -0
  79. package/dist/components/button/index.js +2 -0
  80. package/dist/components/button-group/ButtonGroup.d.ts +113 -0
  81. package/dist/components/button-group/ButtonGroup.js +3 -0
  82. package/dist/components/button-group/index.d.ts +2 -0
  83. package/dist/components/button-group/index.js +2 -0
  84. package/dist/components/calendar/Calendar.d.ts +201 -0
  85. package/dist/components/calendar/Calendar.js +3 -0
  86. package/dist/components/calendar/index.d.ts +2 -0
  87. package/dist/components/calendar/index.js +2 -0
  88. package/dist/components/checkbox/Checkbox.d.ts +130 -0
  89. package/dist/components/checkbox/Checkbox.js +3 -0
  90. package/dist/components/checkbox/index.d.ts +2 -0
  91. package/dist/components/checkbox/index.js +2 -0
  92. package/dist/components/collapsible/Collapsible.d.ts +91 -0
  93. package/dist/components/collapsible/Collapsible.js +3 -0
  94. package/dist/components/collapsible/index.d.ts +2 -0
  95. package/dist/components/collapsible/index.js +2 -0
  96. package/dist/components/color-picker/ColorPicker.d.ts +553 -0
  97. package/dist/components/color-picker/ColorPicker.js +4 -0
  98. package/dist/components/color-picker/color.d.ts +102 -0
  99. package/dist/components/color-picker/color.js +249 -0
  100. package/dist/components/color-picker/index.d.ts +2 -0
  101. package/dist/components/color-picker/index.js +3 -0
  102. package/dist/components/combobox/Combobox.d.ts +553 -0
  103. package/dist/components/combobox/Combobox.js +3 -0
  104. package/dist/components/combobox/index.d.ts +2 -0
  105. package/dist/components/combobox/index.js +2 -0
  106. package/dist/components/context-menu/ContextMenu.d.ts +103 -0
  107. package/dist/components/context-menu/ContextMenu.js +3 -0
  108. package/dist/components/context-menu/index.d.ts +3 -0
  109. package/dist/components/context-menu/index.js +2 -0
  110. package/dist/components/date-picker/DatePicker.d.ts +268 -0
  111. package/dist/components/date-picker/DatePicker.js +3 -0
  112. package/dist/components/date-picker/index.d.ts +2 -0
  113. package/dist/components/date-picker/index.js +2 -0
  114. package/dist/components/dialog/Dialog.d.ts +567 -0
  115. package/dist/components/dialog/Dialog.js +3 -0
  116. package/dist/components/dialog/index.d.ts +2 -0
  117. package/dist/components/dialog/index.js +2 -0
  118. package/dist/components/drawer/Drawer.d.ts +351 -0
  119. package/dist/components/drawer/Drawer.js +3 -0
  120. package/dist/components/drawer/index.d.ts +2 -0
  121. package/dist/components/drawer/index.js +2 -0
  122. package/dist/components/field/Field.d.ts +170 -0
  123. package/dist/components/field/Field.js +3 -0
  124. package/dist/components/field/index.d.ts +2 -0
  125. package/dist/components/field/index.js +2 -0
  126. package/dist/components/fieldset/Fieldset.d.ts +60 -0
  127. package/dist/components/fieldset/Fieldset.js +3 -0
  128. package/dist/components/fieldset/index.d.ts +2 -0
  129. package/dist/components/fieldset/index.js +2 -0
  130. package/dist/components/form/Form.d.ts +76 -0
  131. package/dist/components/form/Form.js +3 -0
  132. package/dist/components/form/index.d.ts +2 -0
  133. package/dist/components/form/index.js +2 -0
  134. package/dist/components/input/Input.d.ts +67 -0
  135. package/dist/components/input/Input.js +3 -0
  136. package/dist/components/input/index.d.ts +2 -0
  137. package/dist/components/input/index.js +2 -0
  138. package/dist/components/input-group/InputGroup.d.ts +214 -0
  139. package/dist/components/input-group/InputGroup.js +3 -0
  140. package/dist/components/input-group/index.d.ts +2 -0
  141. package/dist/components/input-group/index.js +2 -0
  142. package/dist/components/menu/Menu.d.ts +587 -0
  143. package/dist/components/menu/Menu.js +3 -0
  144. package/dist/components/menu/index.d.ts +2 -0
  145. package/dist/components/menu/index.js +2 -0
  146. package/dist/components/menubar/Menubar.d.ts +104 -0
  147. package/dist/components/menubar/Menubar.js +3 -0
  148. package/dist/components/menubar/index.d.ts +2 -0
  149. package/dist/components/menubar/index.js +2 -0
  150. package/dist/components/nav-list/NavList.d.ts +290 -0
  151. package/dist/components/nav-list/NavList.js +3 -0
  152. package/dist/components/nav-list/index.d.ts +2 -0
  153. package/dist/components/nav-list/index.js +2 -0
  154. package/dist/components/navigation-menu/NavigationMenu.d.ts +483 -0
  155. package/dist/components/navigation-menu/NavigationMenu.js +3 -0
  156. package/dist/components/navigation-menu/index.d.ts +2 -0
  157. package/dist/components/navigation-menu/index.js +2 -0
  158. package/dist/components/number-field/NumberField.d.ts +303 -0
  159. package/dist/components/number-field/NumberField.js +3 -0
  160. package/dist/components/number-field/index.d.ts +2 -0
  161. package/dist/components/number-field/index.js +2 -0
  162. package/dist/components/otp-field/OTPField.d.ts +206 -0
  163. package/dist/components/otp-field/OTPField.js +3 -0
  164. package/dist/components/otp-field/index.d.ts +2 -0
  165. package/dist/components/otp-field/index.js +2 -0
  166. package/dist/components/popover/Popover.d.ts +394 -0
  167. package/dist/components/popover/Popover.js +3 -0
  168. package/dist/components/popover/index.d.ts +2 -0
  169. package/dist/components/popover/index.js +2 -0
  170. package/dist/components/preview-card/PreviewCard.d.ts +307 -0
  171. package/dist/components/preview-card/PreviewCard.js +3 -0
  172. package/dist/components/preview-card/index.d.ts +2 -0
  173. package/dist/components/preview-card/index.js +2 -0
  174. package/dist/components/progress/Progress.d.ts +156 -0
  175. package/dist/components/progress/Progress.js +3 -0
  176. package/dist/components/progress/ProgressCircle.d.ts +166 -0
  177. package/dist/components/progress/ProgressCircle.js +3 -0
  178. package/dist/components/progress/index.d.ts +4 -0
  179. package/dist/components/progress/index.js +3 -0
  180. package/dist/components/radio/Radio.d.ts +144 -0
  181. package/dist/components/radio/Radio.js +3 -0
  182. package/dist/components/radio/index.d.ts +2 -0
  183. package/dist/components/radio/index.js +2 -0
  184. package/dist/components/resizable/Resizable.d.ts +211 -0
  185. package/dist/components/resizable/Resizable.js +3 -0
  186. package/dist/components/resizable/index.d.ts +2 -0
  187. package/dist/components/resizable/index.js +2 -0
  188. package/dist/components/scroll-area/ScrollArea.d.ts +113 -0
  189. package/dist/components/scroll-area/ScrollArea.js +3 -0
  190. package/dist/components/scroll-area/index.d.ts +2 -0
  191. package/dist/components/scroll-area/index.js +2 -0
  192. package/dist/components/select/Select.d.ts +345 -0
  193. package/dist/components/select/Select.js +3 -0
  194. package/dist/components/select/index.d.ts +2 -0
  195. package/dist/components/select/index.js +2 -0
  196. package/dist/components/separator/Separator.d.ts +75 -0
  197. package/dist/components/separator/Separator.js +3 -0
  198. package/dist/components/separator/index.d.ts +2 -0
  199. package/dist/components/separator/index.js +2 -0
  200. package/dist/components/skeleton/Skeleton.d.ts +169 -0
  201. package/dist/components/skeleton/Skeleton.js +3 -0
  202. package/dist/components/skeleton/index.d.ts +2 -0
  203. package/dist/components/skeleton/index.js +2 -0
  204. package/dist/components/slider/Slider.d.ts +208 -0
  205. package/dist/components/slider/Slider.js +3 -0
  206. package/dist/components/slider/index.d.ts +2 -0
  207. package/dist/components/slider/index.js +2 -0
  208. package/dist/components/spinner/Spinner.d.ts +92 -0
  209. package/dist/components/spinner/Spinner.js +3 -0
  210. package/dist/components/spinner/index.d.ts +2 -0
  211. package/dist/components/spinner/index.js +2 -0
  212. package/dist/components/switch/Switch.d.ts +80 -0
  213. package/dist/components/switch/Switch.js +3 -0
  214. package/dist/components/switch/index.d.ts +2 -0
  215. package/dist/components/switch/index.js +2 -0
  216. package/dist/components/tabs/Tabs.d.ts +125 -0
  217. package/dist/components/tabs/Tabs.js +3 -0
  218. package/dist/components/tabs/index.d.ts +2 -0
  219. package/dist/components/tabs/index.js +2 -0
  220. package/dist/components/textarea/Textarea.d.ts +119 -0
  221. package/dist/components/textarea/Textarea.js +3 -0
  222. package/dist/components/textarea/index.d.ts +2 -0
  223. package/dist/components/textarea/index.js +2 -0
  224. package/dist/components/toast/Toast.d.ts +517 -0
  225. package/dist/components/toast/Toast.js +3 -0
  226. package/dist/components/toast/index.d.ts +2 -0
  227. package/dist/components/toast/index.js +2 -0
  228. package/dist/components/toggle/Toggle.d.ts +171 -0
  229. package/dist/components/toggle/Toggle.js +3 -0
  230. package/dist/components/toggle/index.d.ts +2 -0
  231. package/dist/components/toggle/index.js +2 -0
  232. package/dist/components/toolbar/Toolbar.d.ts +318 -0
  233. package/dist/components/toolbar/Toolbar.js +3 -0
  234. package/dist/components/toolbar/index.d.ts +2 -0
  235. package/dist/components/toolbar/index.js +2 -0
  236. package/dist/components/tooltip/Tooltip.d.ts +361 -0
  237. package/dist/components/tooltip/Tooltip.js +3 -0
  238. package/dist/components/tooltip/index.d.ts +2 -0
  239. package/dist/components/tooltip/index.js +2 -0
  240. package/dist/index.d.ts +92 -0
  241. package/dist/index.js +86 -0
  242. package/dist/styles/Accordion.css +1 -0
  243. package/dist/styles/Alert.css +1 -0
  244. package/dist/styles/AspectRatio.css +1 -0
  245. package/dist/styles/Avatar.css +1 -0
  246. package/dist/styles/Badge.css +1 -0
  247. package/dist/styles/Breadcrumb.css +1 -0
  248. package/dist/styles/Button.css +1 -0
  249. package/dist/styles/ButtonGroup.css +1 -0
  250. package/dist/styles/Calendar.css +1 -0
  251. package/dist/styles/Checkbox.css +1 -0
  252. package/dist/styles/Collapsible.css +1 -0
  253. package/dist/styles/ColorPicker.css +1 -0
  254. package/dist/styles/Combobox.css +1 -0
  255. package/dist/styles/ContextMenu.css +1 -0
  256. package/dist/styles/DatePicker.css +1 -0
  257. package/dist/styles/Dialog.css +1 -0
  258. package/dist/styles/Drawer.css +1 -0
  259. package/dist/styles/Field.css +1 -0
  260. package/dist/styles/Fieldset.css +1 -0
  261. package/dist/styles/Form.css +1 -0
  262. package/dist/styles/Input.css +1 -0
  263. package/dist/styles/InputGroup.css +1 -0
  264. package/dist/styles/Menu.css +1 -0
  265. package/dist/styles/Menubar.css +1 -0
  266. package/dist/styles/NavList.css +1 -0
  267. package/dist/styles/NavigationMenu.css +1 -0
  268. package/dist/styles/NumberField.css +1 -0
  269. package/dist/styles/OTPField.css +1 -0
  270. package/dist/styles/Popover.css +1 -0
  271. package/dist/styles/PreviewCard.css +1 -0
  272. package/dist/styles/Progress.css +1 -0
  273. package/dist/styles/ProgressCircle.css +1 -0
  274. package/dist/styles/Radio.css +1 -0
  275. package/dist/styles/Resizable.css +1 -0
  276. package/dist/styles/ScrollArea.css +1 -0
  277. package/dist/styles/Select.css +1 -0
  278. package/dist/styles/Separator.css +1 -0
  279. package/dist/styles/Skeleton.css +1 -0
  280. package/dist/styles/Slider.css +1 -0
  281. package/dist/styles/Spinner.css +1 -0
  282. package/dist/styles/Switch.css +1 -0
  283. package/dist/styles/Tabs.css +1 -0
  284. package/dist/styles/Textarea.css +1 -0
  285. package/dist/styles/Toast.css +1 -0
  286. package/dist/styles/Toggle.css +1 -0
  287. package/dist/styles/Toolbar.css +1 -0
  288. package/dist/styles/Tooltip.css +1 -0
  289. package/dist/styles/a11y.css +119 -0
  290. package/dist/styles/layers.css +39 -0
  291. package/dist/styles/motion.css +194 -0
  292. package/dist/styles/patterns.css +236 -0
  293. package/dist/styles/properties.css +62 -0
  294. package/dist/styles/reset.css +11 -0
  295. package/dist/styles/tailwind.css +281 -0
  296. package/dist/styles/theme.css +57 -0
  297. package/dist/styles/tokens.color.css +223 -0
  298. package/dist/styles/tokens.css +460 -0
  299. package/dist/tailwind-merge.d.ts +52 -0
  300. package/dist/tailwind-merge.js +52 -0
  301. package/docs-data/props.json +8047 -0
  302. package/docs-data/theming.json +9600 -0
  303. package/docs-data/tokens.json +4070 -0
  304. package/package.json +78 -0
@@ -0,0 +1,223 @@
1
+ /**
2
+ * GENERATED FILE — do not edit by hand.
3
+ * Source of truth: packages/react/scripts/ramp.mjs
4
+ * Regenerate with: pnpm --filter @forte-ui/react tokens
5
+ */
6
+
7
+ @layer forte.tokens {
8
+ /* -----------------------------------------------------------------------
9
+ * Layer 0 — fallback for engines without relative colour syntax.
10
+ * Hue cannot be extracted without it, so we mix toward white/black instead.
11
+ * Degraded but coherent, and it keeps a brand seed recognisable.
12
+ * --------------------------------------------------------------------- */
13
+ :root,
14
+ .forte-theme,
15
+ [data-forte-theme] {
16
+ --forte-accent-1: color-mix(in oklab, var(--forte-accent-seed) 3%, white);
17
+ --forte-accent-2: color-mix(in oklab, var(--forte-accent-seed) 6%, white);
18
+ --forte-accent-3: color-mix(in oklab, var(--forte-accent-seed) 12%, white);
19
+ --forte-accent-4: color-mix(in oklab, var(--forte-accent-seed) 18%, white);
20
+ --forte-accent-5: color-mix(in oklab, var(--forte-accent-seed) 25%, white);
21
+ --forte-accent-6: color-mix(in oklab, var(--forte-accent-seed) 33%, white);
22
+ --forte-accent-7: color-mix(in oklab, var(--forte-accent-seed) 45%, white);
23
+ --forte-accent-8: color-mix(in oklab, var(--forte-accent-seed) 62%, white);
24
+ --forte-accent-9: var(--forte-accent-seed);
25
+ --forte-accent-10: color-mix(in oklab, var(--forte-accent-seed) 92%, black);
26
+ --forte-accent-11: color-mix(in oklab, var(--forte-accent-seed) 65%, black);
27
+ --forte-accent-12: color-mix(in oklab, var(--forte-accent-seed) 30%, black);
28
+ }
29
+
30
+ @media (prefers-color-scheme: dark) {
31
+ :root,
32
+ .forte-theme,
33
+ [data-forte-theme] {
34
+ --forte-accent-1: color-mix(in oklab, var(--forte-accent-seed) 8%, #0a0a0b);
35
+ --forte-accent-2: color-mix(in oklab, var(--forte-accent-seed) 12%, #0a0a0b);
36
+ --forte-accent-3: color-mix(in oklab, var(--forte-accent-seed) 22%, #0a0a0b);
37
+ --forte-accent-4: color-mix(in oklab, var(--forte-accent-seed) 30%, #0a0a0b);
38
+ --forte-accent-5: color-mix(in oklab, var(--forte-accent-seed) 38%, #0a0a0b);
39
+ --forte-accent-6: color-mix(in oklab, var(--forte-accent-seed) 48%, #0a0a0b);
40
+ --forte-accent-7: color-mix(in oklab, var(--forte-accent-seed) 62%, #0a0a0b);
41
+ --forte-accent-8: color-mix(in oklab, var(--forte-accent-seed) 80%, #0a0a0b);
42
+ --forte-accent-10: color-mix(in oklab, var(--forte-accent-seed) 88%, white);
43
+ --forte-accent-11: color-mix(in oklab, var(--forte-accent-seed) 55%, white);
44
+ --forte-accent-12: color-mix(in oklab, var(--forte-accent-seed) 22%, white);
45
+ }
46
+ }
47
+ :root,
48
+ .forte-theme,
49
+ [data-forte-theme] {
50
+ --forte-secondary-1: color-mix(in oklab, var(--forte-secondary-seed) 3%, white);
51
+ --forte-secondary-2: color-mix(in oklab, var(--forte-secondary-seed) 6%, white);
52
+ --forte-secondary-3: color-mix(in oklab, var(--forte-secondary-seed) 12%, white);
53
+ --forte-secondary-4: color-mix(in oklab, var(--forte-secondary-seed) 18%, white);
54
+ --forte-secondary-5: color-mix(in oklab, var(--forte-secondary-seed) 25%, white);
55
+ --forte-secondary-6: color-mix(in oklab, var(--forte-secondary-seed) 33%, white);
56
+ --forte-secondary-7: color-mix(in oklab, var(--forte-secondary-seed) 45%, white);
57
+ --forte-secondary-8: color-mix(in oklab, var(--forte-secondary-seed) 62%, white);
58
+ --forte-secondary-9: var(--forte-secondary-seed);
59
+ --forte-secondary-10: color-mix(in oklab, var(--forte-secondary-seed) 92%, black);
60
+ --forte-secondary-11: color-mix(in oklab, var(--forte-secondary-seed) 65%, black);
61
+ --forte-secondary-12: color-mix(in oklab, var(--forte-secondary-seed) 30%, black);
62
+ }
63
+
64
+ @media (prefers-color-scheme: dark) {
65
+ :root,
66
+ .forte-theme,
67
+ [data-forte-theme] {
68
+ --forte-secondary-1: color-mix(in oklab, var(--forte-secondary-seed) 8%, #0a0a0b);
69
+ --forte-secondary-2: color-mix(in oklab, var(--forte-secondary-seed) 12%, #0a0a0b);
70
+ --forte-secondary-3: color-mix(in oklab, var(--forte-secondary-seed) 22%, #0a0a0b);
71
+ --forte-secondary-4: color-mix(in oklab, var(--forte-secondary-seed) 30%, #0a0a0b);
72
+ --forte-secondary-5: color-mix(in oklab, var(--forte-secondary-seed) 38%, #0a0a0b);
73
+ --forte-secondary-6: color-mix(in oklab, var(--forte-secondary-seed) 48%, #0a0a0b);
74
+ --forte-secondary-7: color-mix(in oklab, var(--forte-secondary-seed) 62%, #0a0a0b);
75
+ --forte-secondary-8: color-mix(in oklab, var(--forte-secondary-seed) 80%, #0a0a0b);
76
+ --forte-secondary-10: color-mix(in oklab, var(--forte-secondary-seed) 88%, white);
77
+ --forte-secondary-11: color-mix(in oklab, var(--forte-secondary-seed) 55%, white);
78
+ --forte-secondary-12: color-mix(in oklab, var(--forte-secondary-seed) 22%, white);
79
+ }
80
+ }
81
+ :root,
82
+ .forte-theme,
83
+ [data-forte-theme] {
84
+ --forte-gray-1: light-dark(oklch(0.994 0 0), oklch(0.178 0 0));
85
+ --forte-gray-2: light-dark(oklch(0.982 0 0), oklch(0.213 0 0));
86
+ --forte-gray-3: light-dark(oklch(0.957 0 0), oklch(0.252 0 0));
87
+ --forte-gray-4: light-dark(oklch(0.935 0 0), oklch(0.284 0 0));
88
+ --forte-gray-5: light-dark(oklch(0.914 0 0), oklch(0.314 0 0));
89
+ --forte-gray-6: light-dark(oklch(0.891 0 0), oklch(0.350 0 0));
90
+ --forte-gray-7: light-dark(oklch(0.858 0 0), oklch(0.401 0 0));
91
+ --forte-gray-8: light-dark(oklch(0.797 0 0), oklch(0.487 0 0));
92
+ --forte-gray-9: light-dark(oklch(0.646 0 0), oklch(0.537 0 0));
93
+ --forte-gray-10: light-dark(oklch(0.610 0 0), oklch(0.585 0 0));
94
+ --forte-gray-11: light-dark(oklch(0.503 0 0), oklch(0.770 0 0));
95
+ --forte-gray-12: light-dark(oklch(0.242 0 0), oklch(0.949 0 0));
96
+ }
97
+
98
+ /* -----------------------------------------------------------------------
99
+ * Layer 1 — the real ramps.
100
+ * The @supports test uses a LITERAL colour on purpose: a test containing
101
+ * var() reports true unconditionally and would never guard anything.
102
+ * light-dark() needs no separate guard — relative colour syntax shipped
103
+ * later than light-dark() in every engine, so passing this test implies it.
104
+ * --------------------------------------------------------------------- */
105
+ @supports (color: oklch(from red l c h)) {
106
+ :root,
107
+ .forte-theme,
108
+ [data-forte-theme] {
109
+ --forte-accent-1: light-dark(
110
+ oklch(from var(--forte-accent-seed) 0.993 min(0.010, calc(c * 0.04)) h),
111
+ oklch(from var(--forte-accent-seed) 0.178 min(0.018, calc(c * 0.10)) h));
112
+ --forte-accent-2: light-dark(
113
+ oklch(from var(--forte-accent-seed) 0.978 min(0.022, calc(c * 0.09)) h),
114
+ oklch(from var(--forte-accent-seed) 0.213 min(0.028, calc(c * 0.14)) h));
115
+ --forte-accent-3: light-dark(
116
+ oklch(from var(--forte-accent-seed) 0.954 min(0.043, calc(c * 0.17)) h),
117
+ oklch(from var(--forte-accent-seed) 0.271 min(0.060, calc(c * 0.32)) h));
118
+ --forte-accent-4: light-dark(
119
+ oklch(from var(--forte-accent-seed) 0.930 min(0.062, calc(c * 0.25)) h),
120
+ oklch(from var(--forte-accent-seed) 0.313 min(0.084, calc(c * 0.45)) h));
121
+ --forte-accent-5: light-dark(
122
+ oklch(from var(--forte-accent-seed) 0.899 min(0.078, calc(c * 0.33)) h),
123
+ oklch(from var(--forte-accent-seed) 0.363 min(0.098, calc(c * 0.53)) h));
124
+ --forte-accent-6: light-dark(
125
+ oklch(from var(--forte-accent-seed) 0.860 min(0.092, calc(c * 0.42)) h),
126
+ oklch(from var(--forte-accent-seed) 0.424 min(0.104, calc(c * 0.56)) h));
127
+ --forte-accent-7: light-dark(
128
+ oklch(from var(--forte-accent-seed) 0.810 min(0.110, calc(c * 0.52)) h),
129
+ oklch(from var(--forte-accent-seed) 0.503 min(0.112, calc(c * 0.60)) h));
130
+ --forte-accent-8: light-dark(
131
+ oklch(from var(--forte-accent-seed) 0.745 min(0.140, calc(c * 0.66)) h),
132
+ oklch(from var(--forte-accent-seed) 0.606 min(0.130, calc(c * 0.70)) h));
133
+ --forte-accent-9: var(--forte-accent-seed);
134
+ --forte-accent-10: light-dark(
135
+ oklch(from var(--forte-accent-seed) clamp(0.30, calc(l - 0.035), 0.95) c h),
136
+ oklch(from var(--forte-accent-seed) clamp(0.30, calc(l + 0.05), 0.93) min(0.17, calc(c * 0.90)) h));
137
+ --forte-accent-11: light-dark(
138
+ oklch(from var(--forte-accent-seed) clamp(0.32, calc(l - 0.09), 0.490) min(0.15, calc(c * 0.80)) h),
139
+ oklch(from var(--forte-accent-seed) clamp(0.76, calc(l + 0.16), 0.92) min(0.14, calc(c * 0.72)) h));
140
+ --forte-accent-12: light-dark(
141
+ oklch(from var(--forte-accent-seed) clamp(0.20, calc(l * 0.5), 0.34) min(0.09, calc(c * 0.50)) h),
142
+ oklch(from var(--forte-accent-seed) clamp(0.88, calc(l + 0.28), 0.96) min(0.065, calc(c * 0.34)) h));
143
+ }
144
+ :root,
145
+ .forte-theme,
146
+ [data-forte-theme] {
147
+ --forte-secondary-1: light-dark(
148
+ oklch(from var(--forte-secondary-seed) 0.993 min(0.010, calc(c * 0.04)) h),
149
+ oklch(from var(--forte-secondary-seed) 0.178 min(0.018, calc(c * 0.10)) h));
150
+ --forte-secondary-2: light-dark(
151
+ oklch(from var(--forte-secondary-seed) 0.978 min(0.022, calc(c * 0.09)) h),
152
+ oklch(from var(--forte-secondary-seed) 0.213 min(0.028, calc(c * 0.14)) h));
153
+ --forte-secondary-3: light-dark(
154
+ oklch(from var(--forte-secondary-seed) 0.954 min(0.043, calc(c * 0.17)) h),
155
+ oklch(from var(--forte-secondary-seed) 0.271 min(0.060, calc(c * 0.32)) h));
156
+ --forte-secondary-4: light-dark(
157
+ oklch(from var(--forte-secondary-seed) 0.930 min(0.062, calc(c * 0.25)) h),
158
+ oklch(from var(--forte-secondary-seed) 0.313 min(0.084, calc(c * 0.45)) h));
159
+ --forte-secondary-5: light-dark(
160
+ oklch(from var(--forte-secondary-seed) 0.899 min(0.078, calc(c * 0.33)) h),
161
+ oklch(from var(--forte-secondary-seed) 0.363 min(0.098, calc(c * 0.53)) h));
162
+ --forte-secondary-6: light-dark(
163
+ oklch(from var(--forte-secondary-seed) 0.860 min(0.092, calc(c * 0.42)) h),
164
+ oklch(from var(--forte-secondary-seed) 0.424 min(0.104, calc(c * 0.56)) h));
165
+ --forte-secondary-7: light-dark(
166
+ oklch(from var(--forte-secondary-seed) 0.810 min(0.110, calc(c * 0.52)) h),
167
+ oklch(from var(--forte-secondary-seed) 0.503 min(0.112, calc(c * 0.60)) h));
168
+ --forte-secondary-8: light-dark(
169
+ oklch(from var(--forte-secondary-seed) 0.745 min(0.140, calc(c * 0.66)) h),
170
+ oklch(from var(--forte-secondary-seed) 0.606 min(0.130, calc(c * 0.70)) h));
171
+ --forte-secondary-9: var(--forte-secondary-seed);
172
+ --forte-secondary-10: light-dark(
173
+ oklch(from var(--forte-secondary-seed) clamp(0.30, calc(l - 0.035), 0.95) c h),
174
+ oklch(from var(--forte-secondary-seed) clamp(0.30, calc(l + 0.05), 0.93) min(0.17, calc(c * 0.90)) h));
175
+ --forte-secondary-11: light-dark(
176
+ oklch(from var(--forte-secondary-seed) clamp(0.32, calc(l - 0.09), 0.490) min(0.15, calc(c * 0.80)) h),
177
+ oklch(from var(--forte-secondary-seed) clamp(0.76, calc(l + 0.16), 0.92) min(0.14, calc(c * 0.72)) h));
178
+ --forte-secondary-12: light-dark(
179
+ oklch(from var(--forte-secondary-seed) clamp(0.20, calc(l * 0.5), 0.34) min(0.09, calc(c * 0.50)) h),
180
+ oklch(from var(--forte-secondary-seed) clamp(0.88, calc(l + 0.28), 0.96) min(0.065, calc(c * 0.34)) h));
181
+ }
182
+ :root,
183
+ .forte-theme,
184
+ [data-forte-theme] {
185
+ --forte-gray-1: light-dark(
186
+ oklch(from var(--forte-accent-seed) 0.994 min(calc(0.002 * var(--forte-neutral-tint)), calc(c * 0.02)) h),
187
+ oklch(from var(--forte-accent-seed) 0.178 min(calc(0.004 * var(--forte-neutral-tint)), calc(c * 0.03)) h));
188
+ --forte-gray-2: light-dark(
189
+ oklch(from var(--forte-accent-seed) 0.982 min(calc(0.004 * var(--forte-neutral-tint)), calc(c * 0.03)) h),
190
+ oklch(from var(--forte-accent-seed) 0.213 min(calc(0.006 * var(--forte-neutral-tint)), calc(c * 0.04)) h));
191
+ --forte-gray-3: light-dark(
192
+ oklch(from var(--forte-accent-seed) 0.957 min(calc(0.006 * var(--forte-neutral-tint)), calc(c * 0.04)) h),
193
+ oklch(from var(--forte-accent-seed) 0.252 min(calc(0.009 * var(--forte-neutral-tint)), calc(c * 0.05)) h));
194
+ --forte-gray-4: light-dark(
195
+ oklch(from var(--forte-accent-seed) 0.935 min(calc(0.008 * var(--forte-neutral-tint)), calc(c * 0.05)) h),
196
+ oklch(from var(--forte-accent-seed) 0.284 min(calc(0.011 * var(--forte-neutral-tint)), calc(c * 0.06)) h));
197
+ --forte-gray-5: light-dark(
198
+ oklch(from var(--forte-accent-seed) 0.914 min(calc(0.009 * var(--forte-neutral-tint)), calc(c * 0.05)) h),
199
+ oklch(from var(--forte-accent-seed) 0.314 min(calc(0.012 * var(--forte-neutral-tint)), calc(c * 0.06)) h));
200
+ --forte-gray-6: light-dark(
201
+ oklch(from var(--forte-accent-seed) 0.891 min(calc(0.01 * var(--forte-neutral-tint)), calc(c * 0.06)) h),
202
+ oklch(from var(--forte-accent-seed) 0.350 min(calc(0.013 * var(--forte-neutral-tint)), calc(c * 0.07)) h));
203
+ --forte-gray-7: light-dark(
204
+ oklch(from var(--forte-accent-seed) 0.858 min(calc(0.011 * var(--forte-neutral-tint)), calc(c * 0.06)) h),
205
+ oklch(from var(--forte-accent-seed) 0.401 min(calc(0.014 * var(--forte-neutral-tint)), calc(c * 0.07)) h));
206
+ --forte-gray-8: light-dark(
207
+ oklch(from var(--forte-accent-seed) 0.797 min(calc(0.012 * var(--forte-neutral-tint)), calc(c * 0.07)) h),
208
+ oklch(from var(--forte-accent-seed) 0.487 min(calc(0.014 * var(--forte-neutral-tint)), calc(c * 0.07)) h));
209
+ --forte-gray-9: light-dark(
210
+ oklch(from var(--forte-accent-seed) 0.646 min(calc(0.01 * var(--forte-neutral-tint)), calc(c * 0.06)) h),
211
+ oklch(from var(--forte-accent-seed) 0.537 min(calc(0.012 * var(--forte-neutral-tint)), calc(c * 0.06)) h));
212
+ --forte-gray-10: light-dark(
213
+ oklch(from var(--forte-accent-seed) 0.610 min(calc(0.008 * var(--forte-neutral-tint)), calc(c * 0.05)) h),
214
+ oklch(from var(--forte-accent-seed) 0.585 min(calc(0.01 * var(--forte-neutral-tint)), calc(c * 0.05)) h));
215
+ --forte-gray-11: light-dark(
216
+ oklch(from var(--forte-accent-seed) 0.503 min(calc(0.006 * var(--forte-neutral-tint)), calc(c * 0.04)) h),
217
+ oklch(from var(--forte-accent-seed) 0.770 min(calc(0.007 * var(--forte-neutral-tint)), calc(c * 0.04)) h));
218
+ --forte-gray-12: light-dark(
219
+ oklch(from var(--forte-accent-seed) 0.242 min(calc(0.004 * var(--forte-neutral-tint)), calc(c * 0.03)) h),
220
+ oklch(from var(--forte-accent-seed) 0.949 min(calc(0.005 * var(--forte-neutral-tint)), calc(c * 0.03)) h));
221
+ }
222
+ }
223
+ }
@@ -0,0 +1,460 @@
1
+ /**
2
+ * forte-ui semantic tokens, geometry, and motion.
3
+ * The colour *ramps* are generated — see tokens.color.css / scripts/ramp.mjs.
4
+ *
5
+ * Most blocks here are declared on `:root, .forte-theme, [data-forte-theme]`, not
6
+ * on `:root` alone. That repetition is load-bearing: a `var()` inside an
7
+ * unregistered custom property is substituted at the element where the
8
+ * property is DECLARED, so a subtree that only overrides `--forte-accent-seed`
9
+ * would keep the root's already-resolved values. Restating the derivations on
10
+ * the scope selectors is what makes per-subtree theming work at all.
11
+ *
12
+ * The exception is the radius and density defaults, which sit on `:root`
13
+ * alone — they are what the `data-forte-*` presets rewrite, so restating them on
14
+ * every scope would have each scope shadow a preset inherited from an
15
+ * ancestor. See the comment above that block; motion.css does the same.
16
+ */
17
+ @layer forte.tokens {
18
+ :root {
19
+ color-scheme: light dark;
20
+ }
21
+
22
+ /* ------------------------------------------------------------------------
23
+ * Direction
24
+ *
25
+ * `--forte-direction` is the sign of the inline axis, for the handful of
26
+ * places that must move something with `translate`/`transform`, which have
27
+ * no logical form and always run along the physical x axis. A component
28
+ * multiplies its own positive travel by it; nothing else here needs to know
29
+ * about direction, because every other placement uses logical properties.
30
+ *
31
+ * Keyed on the `dir` ATTRIBUTE, and deliberately not on `:dir()`: with this
32
+ * package's CSS targets, `:dir()` is lowered at build time into a list of
33
+ * `:lang()` selectors, which follows the document *language* rather than the
34
+ * `dir` attribute — so the rule would quietly stop matching in the published
35
+ * stylesheet while still working in source.
36
+ *
37
+ * Both directions are declared, and the value is inherited rather than read
38
+ * off an ancestor selector, so the NEAREST `dir` ancestor wins: an LTR
39
+ * island inside an RTL page gets 1 back, at any nesting depth.
40
+ * --------------------------------------------------------------------- */
41
+ [dir="ltr"] {
42
+ --forte-direction: 1;
43
+ }
44
+
45
+ [dir="rtl"] {
46
+ --forte-direction: -1;
47
+ }
48
+
49
+ /* Forcing a mode opts out of the OS preference. */
50
+ [data-theme="light"] {
51
+ color-scheme: light;
52
+ }
53
+
54
+ [data-theme="dark"] {
55
+ color-scheme: dark;
56
+ }
57
+
58
+ /* ------------------------------------------------------------------------
59
+ * Status colours. Fixed hues — a brand seed must not be able to make an
60
+ * error message look reassuring.
61
+ * --------------------------------------------------------------------- */
62
+ :root,
63
+ .forte-theme,
64
+ [data-forte-theme] {
65
+ --forte-danger-2: light-dark(oklch(0.974 0.014 17), oklch(0.220 0.035 17));
66
+ --forte-danger-3: light-dark(oklch(0.944 0.033 17), oklch(0.272 0.061 17));
67
+ --forte-danger-7: light-dark(oklch(0.808 0.098 17), oklch(0.480 0.128 17));
68
+ --forte-danger-9: oklch(0.552 0.211 24);
69
+ --forte-danger-10: light-dark(oklch(0.512 0.208 24), oklch(0.606 0.204 24));
70
+ --forte-danger-11: light-dark(oklch(0.485 0.196 24), oklch(0.760 0.140 20));
71
+
72
+ --forte-success-2: light-dark(oklch(0.976 0.017 155), oklch(0.216 0.032 155));
73
+ --forte-success-3: light-dark(oklch(0.946 0.042 155), oklch(0.268 0.054 155));
74
+ --forte-success-7: light-dark(oklch(0.810 0.100 155), oklch(0.470 0.110 155));
75
+ --forte-success-9: oklch(0.545 0.148 152);
76
+ --forte-success-11: light-dark(oklch(0.475 0.128 152), oklch(0.792 0.135 152));
77
+
78
+ --forte-warning-2: light-dark(oklch(0.980 0.024 85), oklch(0.222 0.034 85));
79
+ --forte-warning-3: light-dark(oklch(0.955 0.058 85), oklch(0.276 0.056 85));
80
+ /* Lighter than its own `-9`, which reads backwards until you remember
81
+ * that amber's 9 sits at 0.812 — step 7 has to stay above it or the ramp
82
+ * inverts. It is the faintest of the four `-7` edges against white
83
+ * (1.6:1, where danger manages 1.9) and that is the hue, not a mistake:
84
+ * a warning chip carries its meaning in the label, never in the border
85
+ * alone. */
86
+ --forte-warning-7: light-dark(oklch(0.855 0.110 85), oklch(0.500 0.095 85));
87
+ --forte-warning-9: oklch(0.812 0.163 82);
88
+ --forte-warning-11: light-dark(oklch(0.520 0.118 60), oklch(0.840 0.140 85));
89
+
90
+ /* Blue runs out of sRGB gamut earlier than the other three hues do, so
91
+ * steps 2 and 3 carry visibly less chroma than their danger and success
92
+ * counterparts rather than the same number clipped: the browser clips
93
+ * naively instead of gamut-mapping, and a clipped near-white shifts
94
+ * lightness as well as saturation. `--forte-info-11` on `--forte-info-3`
95
+ * still measures 5.12:1 light / 7.78:1 dark. */
96
+ --forte-info-2: light-dark(oklch(0.975 0.012 250), oklch(0.218 0.038 250));
97
+ --forte-info-3: light-dark(oklch(0.945 0.026 250), oklch(0.272 0.065 250));
98
+ --forte-info-7: light-dark(oklch(0.800 0.090 250), oklch(0.478 0.130 250));
99
+ /* Step 9 sat at 0.588 for as long as nothing painted text on it. `Badge`
100
+ * does — a solid `tone="info"` chip — and white measured 4.09:1 there, an
101
+ * AA failure. Black clears it (4.77:1), but nobody ships black on azure,
102
+ * so the fill moved instead: 0.550 puts white at 4.78:1 and lands info
103
+ * between its own siblings (danger 0.552, success 0.545) rather than as an
104
+ * outlier above them. `Alert` reads only the tints above and is unaffected.
105
+ * check-contrast.mjs asserts the pair, which is what stops a future nudge
106
+ * from undoing this. */
107
+ --forte-info-9: oklch(0.550 0.158 250);
108
+ --forte-info-11: light-dark(oklch(0.500 0.140 250), oklch(0.790 0.110 250));
109
+ }
110
+
111
+ /* Baseline for engines that reach neither @supports block below. Declared
112
+ * first on purpose: equal-specificity declarations are won by the LAST one,
113
+ * so a fallback placed after the @supports blocks would silently defeat
114
+ * them. Order is the mechanism here. */
115
+ :root,
116
+ .forte-theme,
117
+ [data-forte-theme] {
118
+ --forte-color-on-primary: oklch(0.995 0 0);
119
+ --forte-color-on-secondary: oklch(0.995 0 0);
120
+ }
121
+
122
+ /* ------------------------------------------------------------------------
123
+ * Auto-contrast text on a solid fill.
124
+ *
125
+ * The white/black crossover is NOT a constant lightness. It rises for
126
+ * pinks and purples and falls for greens, because OKLCH lightness weights
127
+ * the channels differently from WCAG relative luminance. A first-order hue
128
+ * term tracks it closely enough that this fallback clears AA on its own:
129
+ * measured worst case 4.50:1 across 119,108 in-gamut seeds, against a
130
+ * theoretical optimum of 4.58:1. Coefficients are fitted — keep them in
131
+ * sync with scripts/check-contrast.mjs, which enforces them.
132
+ *
133
+ * `clamp(0, (threshold - l) * 1000, 1)` is a branch: lighter-than-threshold
134
+ * collapses to 0 (black), darker to 1 (white). Chroma is forced to 0 so the
135
+ * result is a true neutral rather than a tinted off-white.
136
+ * --------------------------------------------------------------------- */
137
+ @supports (color: oklch(from red l c h)) {
138
+ :root,
139
+ .forte-theme,
140
+ [data-forte-theme] {
141
+ --forte-on-threshold: 0.5675;
142
+ --forte-on-hue-cos: 0.13;
143
+ --forte-on-hue-sin: -0.03;
144
+
145
+ --forte-color-on-primary: oklch(
146
+ from var(--forte-accent-9)
147
+ clamp(0, calc((var(--forte-on-threshold)
148
+ + c * (var(--forte-on-hue-cos) * cos(h * 1deg)
149
+ + var(--forte-on-hue-sin) * sin(h * 1deg))
150
+ - l) * 1000), 1)
151
+ 0 h
152
+ );
153
+ --forte-color-on-secondary: oklch(
154
+ from var(--forte-secondary-9)
155
+ clamp(0, calc((var(--forte-on-threshold)
156
+ + c * (var(--forte-on-hue-cos) * cos(h * 1deg)
157
+ + var(--forte-on-hue-sin) * sin(h * 1deg))
158
+ - l) * 1000), 1)
159
+ 0 h
160
+ );
161
+ }
162
+ }
163
+
164
+ /* contrast-color() judges the actually-painted, gamut-mapped colour rather
165
+ * than the specified lightness, so it stays correct even for seeds the
166
+ * fitted threshold can only approximate. Layered second so it wins where
167
+ * supported. */
168
+ @supports (color: contrast-color(red)) {
169
+ :root,
170
+ .forte-theme,
171
+ [data-forte-theme] {
172
+ --forte-color-on-primary: contrast-color(var(--forte-accent-9));
173
+ --forte-color-on-secondary: contrast-color(var(--forte-secondary-9));
174
+ }
175
+ }
176
+
177
+ /* ------------------------------------------------------------------------
178
+ * Semantic aliases — what components actually consume.
179
+ * --------------------------------------------------------------------- */
180
+ :root,
181
+ .forte-theme,
182
+ [data-forte-theme] {
183
+ /* Surfaces */
184
+ --forte-color-background: var(--forte-gray-1);
185
+ --forte-color-panel: var(--forte-gray-2);
186
+ --forte-color-panel-hover: var(--forte-gray-3);
187
+ --forte-color-panel-active: var(--forte-gray-4);
188
+ --forte-color-overlay: var(--forte-gray-1);
189
+
190
+ /* Text */
191
+ --forte-color-foreground: var(--forte-gray-12);
192
+ --forte-color-foreground-muted: var(--forte-gray-11);
193
+ /* 3.73:1 — passes SC 1.4.11 for non-text, FAILS 1.4.3 for body copy.
194
+ * Icons and decoration only. `prefers-contrast: more` promotes it. */
195
+ --forte-color-foreground-subtle: var(--forte-gray-10);
196
+
197
+ /* Borders */
198
+ --forte-color-border: var(--forte-gray-7);
199
+ --forte-color-border-muted: var(--forte-gray-6);
200
+ --forte-color-border-strong: var(--forte-gray-8);
201
+
202
+ /* Primary */
203
+ --forte-color-primary: var(--forte-accent-9);
204
+ --forte-color-primary-hover: var(--forte-accent-10);
205
+ --forte-color-primary-active: var(--forte-accent-11);
206
+ --forte-color-primary-soft: var(--forte-accent-3);
207
+ --forte-color-primary-soft-hover: var(--forte-accent-4);
208
+ --forte-color-primary-soft-active: var(--forte-accent-5);
209
+ --forte-color-primary-text: var(--forte-accent-11);
210
+ --forte-color-primary-border: var(--forte-accent-7);
211
+
212
+ /* Secondary */
213
+ --forte-color-secondary: var(--forte-secondary-9);
214
+ --forte-color-secondary-hover: var(--forte-secondary-10);
215
+ --forte-color-secondary-active: var(--forte-secondary-11);
216
+ --forte-color-secondary-soft: var(--forte-secondary-3);
217
+ --forte-color-secondary-soft-hover: var(--forte-secondary-4);
218
+ --forte-color-secondary-soft-active: var(--forte-secondary-5);
219
+ --forte-color-secondary-text: var(--forte-secondary-11);
220
+ --forte-color-secondary-border: var(--forte-secondary-7);
221
+
222
+ /* Status */
223
+ --forte-color-danger: var(--forte-danger-9);
224
+ --forte-color-danger-hover: var(--forte-danger-10);
225
+ --forte-color-danger-text: var(--forte-danger-11);
226
+ --forte-color-danger-soft: var(--forte-danger-3);
227
+ --forte-color-danger-border: var(--forte-danger-7);
228
+ --forte-color-on-danger: oklch(0.995 0 0);
229
+ --forte-color-success: var(--forte-success-9);
230
+ --forte-color-success-text: var(--forte-success-11);
231
+ --forte-color-success-soft: var(--forte-success-3);
232
+ --forte-color-success-border: var(--forte-success-7);
233
+ --forte-color-warning: var(--forte-warning-9);
234
+ --forte-color-warning-text: var(--forte-warning-11);
235
+ --forte-color-warning-soft: var(--forte-warning-3);
236
+ --forte-color-warning-border: var(--forte-warning-7);
237
+ --forte-color-info: var(--forte-info-9);
238
+ --forte-color-info-text: var(--forte-info-11);
239
+ --forte-color-info-soft: var(--forte-info-3);
240
+ --forte-color-info-border: var(--forte-info-7);
241
+
242
+ /* Text on a solid status fill. Literals, not the auto-contrast expression
243
+ * the brand tones use: those hues are fixed above, so the answer is known
244
+ * at author time and there is nothing for `contrast-color()` to decide.
245
+ *
246
+ * The two are not the same colour, and that is the point of having them.
247
+ * `--forte-warning-9` is a light amber — white on it measures 1.82:1, a
248
+ * failure a component guessing "solid fill means white text" would ship
249
+ * silently. `--forte-success-9` sits almost exactly on the white/black
250
+ * crossover: 4.54:1 white against 4.56:1 black, so it clears AA either way
251
+ * and by very little. check-contrast.mjs asserts all four pairs, which is
252
+ * what stops a future nudge to a status hue from quietly breaking one.
253
+ *
254
+ * `--forte-color-on-info` is the newest of the four and the note that used
255
+ * to stand here said to add it "with a matching assertion the day
256
+ * something needs it". `Badge` needed it. The assertion is in place, and
257
+ * so is the other half of that day's work: `--forte-info-9` moved down to
258
+ * 0.550 so the answer could be white — see the note on the ramp above. */
259
+ --forte-color-on-success: oklch(0.995 0 0);
260
+ --forte-color-on-warning: oklch(0.145 0 0);
261
+ --forte-color-on-info: oklch(0.995 0 0);
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Geometry: spacing, radius, density, typography, elevation.
267
+ */
268
+ @layer forte.tokens {
269
+ :root,
270
+ .forte-theme,
271
+ [data-forte-theme] {
272
+ /* Spacing (4px base) */
273
+ --forte-space-1: 0.25rem;
274
+ --forte-space-2: 0.5rem;
275
+ --forte-space-3: 0.75rem;
276
+ --forte-space-4: 1rem;
277
+ --forte-space-5: 1.5rem;
278
+ --forte-space-6: 2rem;
279
+ --forte-space-7: 2.5rem;
280
+ --forte-space-8: 3rem;
281
+
282
+ /* Typography */
283
+ --forte-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
284
+ "Helvetica Neue", Arial, sans-serif;
285
+ --forte-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
286
+ "Liberation Mono", monospace;
287
+
288
+ --forte-font-size-1: 0.75rem;
289
+ --forte-font-size-2: 0.875rem;
290
+ --forte-font-size-3: 1rem;
291
+ --forte-font-size-4: 1.125rem;
292
+ --forte-font-size-5: 1.25rem;
293
+ --forte-font-size-6: 1.5rem;
294
+
295
+ --forte-font-weight-normal: 400;
296
+ --forte-font-weight-medium: 500;
297
+ --forte-font-weight-semibold: 600;
298
+ --forte-font-weight-bold: 700;
299
+
300
+ --forte-line-height-tight: 1.2;
301
+ --forte-line-height-normal: 1.5;
302
+
303
+ --forte-letter-spacing-tight: -0.01em;
304
+ --forte-letter-spacing-normal: 0em;
305
+
306
+ /* Elevation. Every shadow is forced to `none` under forced-colors, so a
307
+ * shadow may never be the only thing separating a surface from the page —
308
+ * floating surfaces also carry `.forte-hc-surface`. */
309
+ --forte-shadow-1: 0 1px 2px 0 light-dark(oklch(0 0 0 / 0.05), oklch(0 0 0 / 0.4));
310
+ --forte-shadow-2:
311
+ 0 1px 3px 0 light-dark(oklch(0 0 0 / 0.1), oklch(0 0 0 / 0.5)),
312
+ 0 1px 2px -1px light-dark(oklch(0 0 0 / 0.1), oklch(0 0 0 / 0.5));
313
+ --forte-shadow-3:
314
+ 0 4px 6px -1px light-dark(oklch(0 0 0 / 0.1), oklch(0 0 0 / 0.5)),
315
+ 0 2px 4px -2px light-dark(oklch(0 0 0 / 0.1), oklch(0 0 0 / 0.5));
316
+ --forte-shadow-4:
317
+ 0 12px 24px -6px light-dark(oklch(0 0 0 / 0.12), oklch(0 0 0 / 0.6)),
318
+ 0 4px 8px -4px light-dark(oklch(0 0 0 / 0.1), oklch(0 0 0 / 0.5));
319
+
320
+ /* Scrims and glass */
321
+ --forte-scrim-color: light-dark(oklch(0 0 0 / 0.45), oklch(0 0 0 / 0.65));
322
+ --forte-scrim-blur: 4px;
323
+ --forte-glass-alpha: 0.72;
324
+
325
+ /* Hit targets — SC 2.5.8 (AA) and 2.5.5 (AAA) */
326
+ --forte-target-min: 24px;
327
+ --forte-target-comfortable: 44px;
328
+ }
329
+
330
+ /* ------------------------------------------------------------------------
331
+ * Radius and density defaults, on `:root` ALONE.
332
+ *
333
+ * Everything above is restated on `.forte-theme` / `[data-forte-theme]` because
334
+ * it is DERIVED from a seed a scope can override, and a `var()` inside an
335
+ * unregistered custom property is substituted where it is declared. These
336
+ * two groups are different: they are the values the `data-forte-radius` and
337
+ * `data-forte-density` presets below rewrite. Restating them on the scope
338
+ * selectors would mean every theme scope re-declares the DEFAULTS on top of
339
+ * a preset inherited from an ancestor — `.forte-theme` (0,1,0) and
340
+ * `[data-forte-radius="pill"]` (0,1,0) tie on specificity, and the scope wins
341
+ * because it matches the nearer element. A docs demo frame inside a page
342
+ * themed to `pill` would silently snap back to the default radius.
343
+ *
344
+ * So: inheritance carries a preset into a scope, and a scope that wants its
345
+ * own geometry says so with its own `data-forte-radius` / `data-forte-density`,
346
+ * which then wins on the blocks below. The cost is that overriding a raw
347
+ * `--forte-space-*` or `--forte-radius-*` on a subtree no longer re-derives the
348
+ * semantic values — that is what the presets are for.
349
+ * --------------------------------------------------------------------- */
350
+ :root {
351
+ /* Radius scale */
352
+ --forte-radius-1: 0.125rem;
353
+ --forte-radius-2: 0.25rem;
354
+ --forte-radius-3: 0.375rem;
355
+ --forte-radius-4: 0.5rem;
356
+ --forte-radius-5: 0.75rem;
357
+ --forte-radius-6: 1rem;
358
+ --forte-radius-full: 9999px;
359
+
360
+ /* Semantic radius — what components consume, so a preset can retarget
361
+ * the whole library by rewriting three values instead of seven. */
362
+ --forte-radius-control: var(--forte-radius-4);
363
+ --forte-radius-surface: var(--forte-radius-5);
364
+ --forte-radius-pill: var(--forte-radius-full);
365
+
366
+ /* Density: control metrics. Comfortable is the default. */
367
+ --forte-control-h-sm: 1.75rem;
368
+ --forte-control-h-md: 2.25rem;
369
+ --forte-control-h-lg: 2.75rem;
370
+ --forte-control-px-sm: var(--forte-space-3);
371
+ --forte-control-px-md: var(--forte-space-4);
372
+ --forte-control-px-lg: var(--forte-space-5);
373
+ --forte-control-gap: var(--forte-space-2);
374
+ --forte-surface-p: var(--forte-space-5);
375
+ --forte-list-item-py: var(--forte-space-2);
376
+ }
377
+
378
+ /* Radius presets. Discrete literals rather than a calc() multiplier: an
379
+ * unregistered property containing var() freezes at its declaring element,
380
+ * so `calc(8px * var(--forte-radius-factor))` on :root would never re-derive
381
+ * inside a scoped subtree. There are only three presets — literals are both
382
+ * simpler and correct.
383
+ *
384
+ * Each preset restates the WHOLE scale, the way every state block in
385
+ * motion.css does, so a preset is a complete statement rather than a patch
386
+ * on whatever it inherited. `none` zeroes the scale itself, so a nested
387
+ * `soft` that only re-pointed `--forte-radius-control` at `--forte-radius-5`
388
+ * would resolve it against its ancestor's zero and stay square. */
389
+ /* `0px` and not `0`, and the unit is load-bearing. A bare `0` in a custom
390
+ * property is a <number>, and a math function may not mix a number with a
391
+ * length: `min(var(--forte-radius-surface), 12px)` becomes invalid at
392
+ * computed-value time under this preset, taking every value derived from it
393
+ * down with it. On `border-radius` itself the two are identical, so the
394
+ * breakage only ever showed up one derivation later — which is exactly the
395
+ * kind of silent var() failure that is hard to find. */
396
+ [data-forte-radius="none"] {
397
+ --forte-radius-1: 0px;
398
+ --forte-radius-2: 0px;
399
+ --forte-radius-3: 0px;
400
+ --forte-radius-4: 0px;
401
+ --forte-radius-5: 0px;
402
+ --forte-radius-6: 0px;
403
+ --forte-radius-full: 0px;
404
+ --forte-radius-control: 0px;
405
+ --forte-radius-surface: 0px;
406
+ --forte-radius-pill: 0px;
407
+ }
408
+
409
+ [data-forte-radius="soft"] {
410
+ --forte-radius-1: 0.125rem;
411
+ --forte-radius-2: 0.25rem;
412
+ --forte-radius-3: 0.375rem;
413
+ --forte-radius-4: 0.5rem;
414
+ --forte-radius-5: 0.75rem;
415
+ --forte-radius-6: 1rem;
416
+ --forte-radius-full: 9999px;
417
+ --forte-radius-control: var(--forte-radius-5);
418
+ --forte-radius-surface: var(--forte-radius-6);
419
+ --forte-radius-pill: var(--forte-radius-full);
420
+ }
421
+
422
+ [data-forte-radius="pill"] {
423
+ --forte-radius-1: 0.125rem;
424
+ --forte-radius-2: 0.25rem;
425
+ --forte-radius-3: 0.375rem;
426
+ --forte-radius-4: 0.5rem;
427
+ --forte-radius-5: 0.75rem;
428
+ --forte-radius-6: 1rem;
429
+ --forte-radius-full: 9999px;
430
+ --forte-radius-control: var(--forte-radius-full);
431
+ --forte-radius-surface: var(--forte-radius-6);
432
+ --forte-radius-pill: var(--forte-radius-full);
433
+ }
434
+
435
+ /* Density presets. `compact` `sm` lands at exactly 24px — the SC 2.5.8
436
+ * floor. Do not add a denser preset. */
437
+ [data-forte-density="compact"] {
438
+ --forte-control-h-sm: 1.5rem;
439
+ --forte-control-h-md: 1.875rem;
440
+ --forte-control-h-lg: 2.25rem;
441
+ --forte-control-px-sm: var(--forte-space-2);
442
+ --forte-control-px-md: var(--forte-space-3);
443
+ --forte-control-px-lg: var(--forte-space-4);
444
+ --forte-control-gap: var(--forte-space-1);
445
+ --forte-surface-p: var(--forte-space-4);
446
+ --forte-list-item-py: var(--forte-space-1);
447
+ }
448
+
449
+ [data-forte-density="spacious"] {
450
+ --forte-control-h-sm: 2.25rem;
451
+ --forte-control-h-md: 2.75rem;
452
+ --forte-control-h-lg: 3.25rem;
453
+ --forte-control-px-sm: var(--forte-space-4);
454
+ --forte-control-px-md: var(--forte-space-5);
455
+ --forte-control-px-lg: var(--forte-space-6);
456
+ --forte-control-gap: var(--forte-space-3);
457
+ --forte-surface-p: var(--forte-space-6);
458
+ --forte-list-item-py: var(--forte-space-3);
459
+ }
460
+ }