zabi-components 8.0.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (456) hide show
  1. package/CHANGELOG.md +2935 -0
  2. package/README.md +243 -10
  3. package/THEME.md +162 -332
  4. package/THEMING.md +1419 -259
  5. package/dist/atoms/ActionPanel.svelte +15 -5
  6. package/dist/atoms/Avatar.svelte +120 -0
  7. package/dist/atoms/Avatar.svelte.d.ts +46 -0
  8. package/dist/atoms/Badge.svelte +71 -13
  9. package/dist/atoms/Badge.svelte.d.ts +8 -2
  10. package/dist/atoms/Block.svelte +74 -0
  11. package/dist/atoms/Block.svelte.d.ts +29 -0
  12. package/dist/atoms/Button.svelte +217 -30
  13. package/dist/atoms/Button.svelte.d.ts +33 -4
  14. package/dist/atoms/Card.svelte +182 -26
  15. package/dist/atoms/Card.svelte.d.ts +55 -3
  16. package/dist/atoms/CardHeader.svelte +16 -4
  17. package/dist/atoms/Checkbox.svelte +81 -21
  18. package/dist/atoms/Checkbox.svelte.d.ts +31 -2
  19. package/dist/atoms/Chip.svelte +351 -0
  20. package/dist/atoms/Chip.svelte.d.ts +57 -0
  21. package/dist/atoms/CodeBlock.svelte +20 -2
  22. package/dist/atoms/CodeBlock.svelte.d.ts +4 -0
  23. package/dist/atoms/CodeField.svelte +385 -0
  24. package/dist/atoms/CodeField.svelte.d.ts +61 -0
  25. package/dist/atoms/ColorPicker.svelte +260 -49
  26. package/dist/atoms/ColorPicker.svelte.d.ts +3 -0
  27. package/dist/atoms/Container.svelte +16 -8
  28. package/dist/atoms/DateField.svelte +145 -0
  29. package/dist/atoms/DateField.svelte.d.ts +81 -0
  30. package/dist/atoms/FieldMessages.svelte +69 -0
  31. package/dist/atoms/FieldMessages.svelte.d.ts +23 -0
  32. package/dist/atoms/FloatingActionButton.svelte +176 -0
  33. package/dist/atoms/FloatingActionButton.svelte.d.ts +51 -0
  34. package/dist/atoms/Heading.svelte +63 -5
  35. package/dist/atoms/Heading.svelte.d.ts +14 -0
  36. package/dist/atoms/IconButton.svelte +294 -26
  37. package/dist/atoms/IconButton.svelte.d.ts +62 -4
  38. package/dist/atoms/Input.svelte +259 -53
  39. package/dist/atoms/Input.svelte.d.ts +33 -2
  40. package/dist/atoms/List.svelte +5 -1
  41. package/dist/atoms/ListItem.svelte +70 -13
  42. package/dist/atoms/ListItem.svelte.d.ts +11 -0
  43. package/dist/atoms/PickerField.svelte +239 -0
  44. package/dist/atoms/PickerField.svelte.d.ts +67 -0
  45. package/dist/atoms/Progress.svelte +99 -19
  46. package/dist/atoms/Progress.svelte.d.ts +15 -1
  47. package/dist/atoms/Radio.svelte +51 -3
  48. package/dist/atoms/Radio.svelte.d.ts +30 -2
  49. package/dist/atoms/Rating.svelte +620 -0
  50. package/dist/atoms/Rating.svelte.d.ts +77 -0
  51. package/dist/atoms/Select.svelte +438 -98
  52. package/dist/atoms/Select.svelte.d.ts +61 -3
  53. package/dist/atoms/SelectionControl.svelte +193 -23
  54. package/dist/atoms/SelectionControl.svelte.d.ts +29 -3
  55. package/dist/atoms/Skeleton.svelte +114 -18
  56. package/dist/atoms/Skeleton.svelte.d.ts +30 -3
  57. package/dist/atoms/SkeletonGroup.svelte +43 -0
  58. package/dist/atoms/SkeletonGroup.svelte.d.ts +20 -0
  59. package/dist/atoms/Slider.svelte +344 -0
  60. package/dist/atoms/Slider.svelte.d.ts +40 -0
  61. package/dist/atoms/Sparkline.svelte +109 -0
  62. package/dist/atoms/Sparkline.svelte.d.ts +27 -0
  63. package/dist/atoms/SpeechBubble.svelte +187 -0
  64. package/dist/atoms/SpeechBubble.svelte.d.ts +33 -0
  65. package/dist/atoms/Spinner.svelte +57 -0
  66. package/dist/atoms/Spinner.svelte.d.ts +19 -0
  67. package/dist/atoms/Stat.svelte +72 -0
  68. package/dist/atoms/Stat.svelte.d.ts +19 -0
  69. package/dist/atoms/Table.svelte +151 -6
  70. package/dist/atoms/Table.svelte.d.ts +15 -3
  71. package/dist/atoms/TemporalField.svelte +472 -0
  72. package/dist/atoms/TemporalField.svelte.d.ts +48 -0
  73. package/dist/atoms/Text.svelte +23 -11
  74. package/dist/atoms/Text.svelte.d.ts +6 -3
  75. package/dist/atoms/Textarea.svelte +150 -44
  76. package/dist/atoms/Textarea.svelte.d.ts +35 -2
  77. package/dist/atoms/ThemeToggle.svelte +223 -44
  78. package/dist/atoms/ThemeToggle.svelte.d.ts +26 -3
  79. package/dist/atoms/TimeColumn.svelte +150 -0
  80. package/dist/atoms/TimeColumn.svelte.d.ts +25 -0
  81. package/dist/atoms/TimeField.svelte +151 -0
  82. package/dist/atoms/TimeField.svelte.d.ts +85 -0
  83. package/dist/atoms/Toast.svelte +22 -8
  84. package/dist/atoms/Toast.svelte.d.ts +2 -0
  85. package/dist/atoms/Toggle.svelte +98 -14
  86. package/dist/atoms/Toggle.svelte.d.ts +26 -2
  87. package/dist/atoms/Tooltip.svelte +528 -24
  88. package/dist/atoms/Tooltip.svelte.d.ts +18 -0
  89. package/dist/atoms/ZabiStringsProvider.svelte +45 -0
  90. package/dist/atoms/ZabiStringsProvider.svelte.d.ts +27 -0
  91. package/dist/atoms/index.d.ts +38 -0
  92. package/dist/atoms/index.js +29 -0
  93. package/dist/atoms/selection-control.styles.d.ts +47 -5
  94. package/dist/atoms/selection-control.styles.js +52 -10
  95. package/dist/components/atoms/index.d.ts +38 -0
  96. package/dist/components/atoms/index.d.ts.map +1 -1
  97. package/dist/components/atoms/selection-control.styles.d.ts +47 -5
  98. package/dist/components/atoms/selection-control.styles.d.ts.map +1 -1
  99. package/dist/components/index.d.ts +104 -2
  100. package/dist/components/index.d.ts.map +1 -1
  101. package/dist/components/map.d.ts +11 -0
  102. package/dist/components/map.d.ts.map +1 -0
  103. package/dist/components/molecules/index.d.ts +51 -0
  104. package/dist/components/molecules/index.d.ts.map +1 -1
  105. package/dist/components/molecules/toast-store.d.ts +83 -7
  106. package/dist/components/molecules/toast-store.d.ts.map +1 -1
  107. package/dist/components/organisms/index.d.ts +10 -0
  108. package/dist/components/organisms/index.d.ts.map +1 -1
  109. package/dist/components/types/variants.d.ts +24 -1
  110. package/dist/components/types/variants.d.ts.map +1 -1
  111. package/dist/components/util/app-shell.d.ts +79 -0
  112. package/dist/components/util/app-shell.d.ts.map +1 -0
  113. package/dist/components/util/avatar.d.ts +39 -0
  114. package/dist/components/util/avatar.d.ts.map +1 -0
  115. package/dist/components/util/bottom-sheet.d.ts +30 -0
  116. package/dist/components/util/bottom-sheet.d.ts.map +1 -0
  117. package/dist/components/util/bottom-tab-bar.d.ts +41 -0
  118. package/dist/components/util/bottom-tab-bar.d.ts.map +1 -0
  119. package/dist/components/util/calendar.d.ts +56 -0
  120. package/dist/components/util/calendar.d.ts.map +1 -0
  121. package/dist/components/util/chart.d.ts +140 -0
  122. package/dist/components/util/chart.d.ts.map +1 -0
  123. package/dist/components/util/chip.d.ts +66 -0
  124. package/dist/components/util/chip.d.ts.map +1 -0
  125. package/dist/components/util/cn.d.ts.map +1 -1
  126. package/dist/components/util/code-field.d.ts +63 -0
  127. package/dist/components/util/code-field.d.ts.map +1 -0
  128. package/dist/components/util/collapsible.d.ts +64 -0
  129. package/dist/components/util/collapsible.d.ts.map +1 -0
  130. package/dist/components/util/confirm-dialog.d.ts +12 -0
  131. package/dist/components/util/confirm-dialog.d.ts.map +1 -0
  132. package/dist/components/util/date.d.ts +96 -0
  133. package/dist/components/util/date.d.ts.map +1 -0
  134. package/dist/components/util/display-voice.d.ts +10 -0
  135. package/dist/components/util/display-voice.d.ts.map +1 -0
  136. package/dist/components/util/drawer.d.ts +13 -0
  137. package/dist/components/util/drawer.d.ts.map +1 -0
  138. package/dist/components/util/dropdown.d.ts +47 -0
  139. package/dist/components/util/dropdown.d.ts.map +1 -0
  140. package/dist/components/util/field-control.d.ts +30 -0
  141. package/dist/components/util/field-control.d.ts.map +1 -0
  142. package/dist/components/util/field.d.ts +45 -0
  143. package/dist/components/util/field.d.ts.map +1 -0
  144. package/dist/components/util/fit-in-viewport.d.ts +201 -0
  145. package/dist/components/util/fit-in-viewport.d.ts.map +1 -0
  146. package/dist/components/util/focus-utils.d.ts +77 -2
  147. package/dist/components/util/focus-utils.d.ts.map +1 -1
  148. package/dist/components/util/hydration.d.ts +45 -0
  149. package/dist/components/util/hydration.d.ts.map +1 -0
  150. package/dist/components/util/keyboard-inset.d.ts +18 -0
  151. package/dist/components/util/keyboard-inset.d.ts.map +1 -0
  152. package/dist/components/util/map-view.d.ts +144 -0
  153. package/dist/components/util/map-view.d.ts.map +1 -0
  154. package/dist/components/util/media-grid.d.ts +51 -0
  155. package/dist/components/util/media-grid.d.ts.map +1 -0
  156. package/dist/components/util/media.d.ts +6 -0
  157. package/dist/components/util/media.d.ts.map +1 -0
  158. package/dist/components/util/overlay-chrome.d.ts +53 -0
  159. package/dist/components/util/overlay-chrome.d.ts.map +1 -0
  160. package/dist/components/util/overlay.d.ts +72 -0
  161. package/dist/components/util/overlay.d.ts.map +1 -0
  162. package/dist/components/util/photo.d.ts +234 -0
  163. package/dist/components/util/photo.d.ts.map +1 -0
  164. package/dist/components/util/portal.d.ts +23 -0
  165. package/dist/components/util/portal.d.ts.map +1 -0
  166. package/dist/components/util/progress.d.ts +19 -0
  167. package/dist/components/util/progress.d.ts.map +1 -0
  168. package/dist/components/util/pull-to-refresh.d.ts +27 -0
  169. package/dist/components/util/pull-to-refresh.d.ts.map +1 -0
  170. package/dist/components/util/radio-keys.d.ts +25 -0
  171. package/dist/components/util/radio-keys.d.ts.map +1 -0
  172. package/dist/components/util/rating.d.ts +23 -0
  173. package/dist/components/util/rating.d.ts.map +1 -0
  174. package/dist/components/util/ready-made-strings.d.ts +77 -0
  175. package/dist/components/util/ready-made-strings.d.ts.map +1 -0
  176. package/dist/components/util/scroll-edge.d.ts +33 -0
  177. package/dist/components/util/scroll-edge.d.ts.map +1 -0
  178. package/dist/components/util/scroll-padding.d.ts +20 -0
  179. package/dist/components/util/scroll-padding.d.ts.map +1 -0
  180. package/dist/components/util/segmented-control.d.ts +16 -0
  181. package/dist/components/util/segmented-control.d.ts.map +1 -0
  182. package/dist/components/util/select.d.ts +41 -0
  183. package/dist/components/util/select.d.ts.map +1 -0
  184. package/dist/components/util/sheet-drag.d.ts +84 -0
  185. package/dist/components/util/sheet-drag.d.ts.map +1 -0
  186. package/dist/components/util/sidebar.d.ts +63 -0
  187. package/dist/components/util/sidebar.d.ts.map +1 -0
  188. package/dist/components/util/skeleton.d.ts +15 -0
  189. package/dist/components/util/skeleton.d.ts.map +1 -0
  190. package/dist/components/util/sliding-indicator.d.ts +25 -0
  191. package/dist/components/util/sliding-indicator.d.ts.map +1 -0
  192. package/dist/components/util/sortable-list.d.ts +65 -0
  193. package/dist/components/util/sortable-list.d.ts.map +1 -0
  194. package/dist/components/util/stepper.d.ts +40 -0
  195. package/dist/components/util/stepper.d.ts.map +1 -0
  196. package/dist/components/util/swipeable-list-item.d.ts +36 -0
  197. package/dist/components/util/swipeable-list-item.d.ts.map +1 -0
  198. package/dist/components/util/temporal-field.d.ts +89 -0
  199. package/dist/components/util/temporal-field.d.ts.map +1 -0
  200. package/dist/components/util/theme-mode.d.ts +80 -0
  201. package/dist/components/util/theme-mode.d.ts.map +1 -0
  202. package/dist/components/util/toaster.d.ts +133 -0
  203. package/dist/components/util/toaster.d.ts.map +1 -0
  204. package/dist/components/util/tone-surface.d.ts +34 -0
  205. package/dist/components/util/tone-surface.d.ts.map +1 -0
  206. package/dist/components/util/tooltip.d.ts +10 -0
  207. package/dist/components/util/tooltip.d.ts.map +1 -0
  208. package/dist/components/util/top-navbar.d.ts +35 -0
  209. package/dist/components/util/top-navbar.d.ts.map +1 -0
  210. package/dist/components/util/touch-target.d.ts +31 -0
  211. package/dist/components/util/touch-target.d.ts.map +1 -0
  212. package/dist/components/util/zabi-strings.d.ts +142 -0
  213. package/dist/components/util/zabi-strings.d.ts.map +1 -0
  214. package/dist/create-theme/cli.js +173 -0
  215. package/dist/create-theme/index.d.ts +190 -0
  216. package/dist/create-theme/index.js +1034 -0
  217. package/dist/create-theme/lib/ramp-math.js +128 -0
  218. package/dist/create-theme/lib/resolve.js +238 -0
  219. package/dist/create-theme/theme-data.js +2644 -0
  220. package/dist/index.d.ts +104 -2
  221. package/dist/index.js +75 -2
  222. package/dist/map.d.ts +10 -0
  223. package/dist/map.js +9 -0
  224. package/dist/molecules/Alert.svelte +63 -16
  225. package/dist/molecules/Alert.svelte.d.ts +14 -1
  226. package/dist/molecules/AppBar.svelte +674 -0
  227. package/dist/molecules/AppBar.svelte.d.ts +131 -0
  228. package/dist/molecules/AvatarGroup.svelte +116 -0
  229. package/dist/molecules/AvatarGroup.svelte.d.ts +40 -0
  230. package/dist/molecules/BarChart.svelte +381 -0
  231. package/dist/molecules/BarChart.svelte.d.ts +45 -0
  232. package/dist/molecules/BottomSheet.svelte +608 -0
  233. package/dist/molecules/BottomSheet.svelte.d.ts +109 -0
  234. package/dist/molecules/BottomTabBar.svelte +403 -0
  235. package/dist/molecules/BottomTabBar.svelte.d.ts +98 -0
  236. package/dist/molecules/Calendar.svelte +597 -0
  237. package/dist/molecules/Calendar.svelte.d.ts +72 -0
  238. package/dist/molecules/ChipGroup.svelte +325 -0
  239. package/dist/molecules/ChipGroup.svelte.d.ts +41 -0
  240. package/dist/molecules/Collapsible.svelte +347 -0
  241. package/dist/molecules/Collapsible.svelte.d.ts +61 -0
  242. package/dist/molecules/CollapsibleGroup.svelte +136 -0
  243. package/dist/molecules/CollapsibleGroup.svelte.d.ts +14 -0
  244. package/dist/molecules/ComponentDemo.svelte +16 -4
  245. package/dist/molecules/ComponentDemo.svelte.d.ts +3 -0
  246. package/dist/molecules/ConfirmDialog.svelte +257 -0
  247. package/dist/molecules/ConfirmDialog.svelte.d.ts +58 -0
  248. package/dist/molecules/ContactForm.svelte +34 -17
  249. package/dist/molecules/ContactForm.svelte.d.ts +8 -0
  250. package/dist/molecules/Drawer.svelte +415 -0
  251. package/dist/molecules/Drawer.svelte.d.ts +55 -0
  252. package/dist/molecules/Dropdown.svelte +517 -48
  253. package/dist/molecules/Dropdown.svelte.d.ts +47 -6
  254. package/dist/molecules/DropdownItem.svelte +122 -0
  255. package/dist/molecules/DropdownItem.svelte.d.ts +28 -0
  256. package/dist/molecules/EmptyState.svelte +55 -10
  257. package/dist/molecules/EmptyState.svelte.d.ts +8 -0
  258. package/dist/molecules/FormField.svelte +9 -1
  259. package/dist/molecules/FormField.svelte.d.ts +2 -0
  260. package/dist/molecules/Header.svelte +1 -1
  261. package/dist/molecules/ImageUpload.svelte +492 -69
  262. package/dist/molecules/ImageUpload.svelte.d.ts +82 -2
  263. package/dist/molecules/LineChart.svelte +459 -0
  264. package/dist/molecules/LineChart.svelte.d.ts +53 -0
  265. package/dist/molecules/MapView.svelte +565 -0
  266. package/dist/molecules/MapView.svelte.d.ts +88 -0
  267. package/dist/molecules/MediaGrid.svelte +527 -0
  268. package/dist/molecules/MediaGrid.svelte.d.ts +77 -0
  269. package/dist/molecules/Modal.svelte +293 -72
  270. package/dist/molecules/Modal.svelte.d.ts +51 -2
  271. package/dist/molecules/NavigationMenuContent.svelte +58 -1
  272. package/dist/molecules/NavigationMenuItem.svelte +0 -1
  273. package/dist/molecules/NavigationMenuLink.svelte +1 -1
  274. package/dist/molecules/NavigationMenuList.svelte +10 -3
  275. package/dist/molecules/NavigationMenuTrigger.svelte +2 -2
  276. package/dist/molecules/Page.svelte +32 -2
  277. package/dist/molecules/Page.svelte.d.ts +11 -0
  278. package/dist/molecules/PhotoGrid.svelte +523 -0
  279. package/dist/molecules/PhotoGrid.svelte.d.ts +73 -0
  280. package/dist/molecules/PhotoViewer.svelte +1213 -0
  281. package/dist/molecules/PhotoViewer.svelte.d.ts +74 -0
  282. package/dist/molecules/PieChart.svelte +421 -0
  283. package/dist/molecules/PieChart.svelte.d.ts +51 -0
  284. package/dist/molecules/PropsTable.svelte +22 -10
  285. package/dist/molecules/PropsTable.svelte.d.ts +3 -0
  286. package/dist/molecules/PullToRefresh.svelte +263 -0
  287. package/dist/molecules/PullToRefresh.svelte.d.ts +52 -0
  288. package/dist/molecules/RadioGroup.svelte +72 -18
  289. package/dist/molecules/RadioGroup.svelte.d.ts +19 -3
  290. package/dist/molecules/Section.svelte +1 -1
  291. package/dist/molecules/SegmentedControl.svelte +456 -0
  292. package/dist/molecules/SegmentedControl.svelte.d.ts +40 -0
  293. package/dist/molecules/SidebarBrandHeader.svelte +11 -1
  294. package/dist/molecules/SidebarBrandHeader.svelte.d.ts +3 -0
  295. package/dist/molecules/SidebarFooter.svelte +30 -7
  296. package/dist/molecules/SidebarFooter.svelte.d.ts +3 -0
  297. package/dist/molecules/SidebarNavSection.svelte +1 -1
  298. package/dist/molecules/SlideUp.svelte +220 -61
  299. package/dist/molecules/SlideUp.svelte.d.ts +26 -0
  300. package/dist/molecules/SortableList.svelte +633 -0
  301. package/dist/molecules/SortableList.svelte.d.ts +69 -0
  302. package/dist/molecules/Stepper.svelte +562 -0
  303. package/dist/molecules/Stepper.svelte.d.ts +39 -0
  304. package/dist/molecules/StickyActionBar.svelte +250 -0
  305. package/dist/molecules/StickyActionBar.svelte.d.ts +78 -0
  306. package/dist/molecules/SwipeableListItem.svelte +334 -0
  307. package/dist/molecules/SwipeableListItem.svelte.d.ts +54 -0
  308. package/dist/molecules/Tabs.svelte +310 -9
  309. package/dist/molecules/Tabs.svelte.d.ts +7 -0
  310. package/dist/molecules/Toaster.svelte +514 -5
  311. package/dist/molecules/Toaster.svelte.d.ts +153 -2
  312. package/dist/molecules/ToasterToast.svelte +495 -77
  313. package/dist/molecules/ToasterToast.svelte.d.ts +15 -0
  314. package/dist/molecules/UnsavedChangesBar.svelte +223 -0
  315. package/dist/molecules/UnsavedChangesBar.svelte.d.ts +43 -0
  316. package/dist/molecules/index.d.ts +51 -0
  317. package/dist/molecules/index.js +31 -0
  318. package/dist/molecules/toast-store.d.ts +83 -7
  319. package/dist/molecules/toast-store.js +25 -1
  320. package/dist/organisms/AppNavigation.svelte +440 -0
  321. package/dist/organisms/AppNavigation.svelte.d.ts +72 -0
  322. package/dist/organisms/AppShell.svelte +696 -0
  323. package/dist/organisms/AppShell.svelte.d.ts +157 -0
  324. package/dist/organisms/AppShellHeaderPart.svelte +163 -0
  325. package/dist/organisms/AppShellHeaderPart.svelte.d.ts +57 -0
  326. package/dist/organisms/SidebarAccountPanel.svelte +107 -12
  327. package/dist/organisms/SidebarAccountPanel.svelte.d.ts +19 -0
  328. package/dist/organisms/SidebarNavigation.svelte +111 -43
  329. package/dist/organisms/SidebarNavigation.svelte.d.ts +29 -1
  330. package/dist/organisms/SidebarPanel.svelte +34 -17
  331. package/dist/organisms/SidebarPanel.svelte.d.ts +1 -0
  332. package/dist/organisms/SidebarShell.svelte +164 -14
  333. package/dist/organisms/SidebarShell.svelte.d.ts +56 -2
  334. package/dist/organisms/TopNavbar.svelte +353 -39
  335. package/dist/organisms/TopNavbar.svelte.d.ts +47 -0
  336. package/dist/organisms/TopNavbarSheetContent.svelte +145 -0
  337. package/dist/organisms/TopNavbarSheetContent.svelte.d.ts +24 -0
  338. package/dist/organisms/index.d.ts +10 -0
  339. package/dist/organisms/index.js +7 -0
  340. package/dist/types/components.d.ts +21 -1
  341. package/dist/types/components.d.ts.map +1 -1
  342. package/dist/types/index.d.ts +1093 -26
  343. package/dist/types/index.d.ts.map +1 -1
  344. package/dist/types/variants.ts +28 -1
  345. package/dist/util/app-shell.d.ts +78 -0
  346. package/dist/util/app-shell.js +97 -0
  347. package/dist/util/avatar.d.ts +38 -0
  348. package/dist/util/avatar.js +52 -0
  349. package/dist/util/bottom-sheet.d.ts +29 -0
  350. package/dist/util/bottom-sheet.js +43 -0
  351. package/dist/util/bottom-tab-bar.d.ts +40 -0
  352. package/dist/util/bottom-tab-bar.js +54 -0
  353. package/dist/util/calendar.d.ts +55 -0
  354. package/dist/util/calendar.js +74 -0
  355. package/dist/util/chart.d.ts +139 -0
  356. package/dist/util/chart.js +305 -0
  357. package/dist/util/chip.d.ts +65 -0
  358. package/dist/util/chip.js +58 -0
  359. package/dist/util/cn.js +28 -2
  360. package/dist/util/code-field.d.ts +62 -0
  361. package/dist/util/code-field.js +112 -0
  362. package/dist/util/collapsible.d.ts +63 -0
  363. package/dist/util/collapsible.js +23 -0
  364. package/dist/util/confirm-dialog.d.ts +11 -0
  365. package/dist/util/confirm-dialog.js +2 -0
  366. package/dist/util/date.d.ts +95 -0
  367. package/dist/util/date.js +237 -0
  368. package/dist/util/display-voice.d.ts +9 -0
  369. package/dist/util/display-voice.js +9 -0
  370. package/dist/util/drawer.d.ts +12 -0
  371. package/dist/util/drawer.js +7 -0
  372. package/dist/util/dropdown.d.ts +46 -0
  373. package/dist/util/dropdown.js +21 -0
  374. package/dist/util/field-control.d.ts +29 -0
  375. package/dist/util/field-control.js +32 -0
  376. package/dist/util/field.d.ts +44 -0
  377. package/dist/util/field.js +38 -0
  378. package/dist/util/fit-in-viewport.d.ts +200 -0
  379. package/dist/util/fit-in-viewport.js +399 -0
  380. package/dist/util/focus-utils.d.ts +77 -2
  381. package/dist/util/focus-utils.js +186 -9
  382. package/dist/util/hydration.d.ts +44 -0
  383. package/dist/util/hydration.js +58 -0
  384. package/dist/util/keyboard-inset.d.ts +17 -0
  385. package/dist/util/keyboard-inset.js +53 -0
  386. package/dist/util/map-view.d.ts +143 -0
  387. package/dist/util/map-view.js +121 -0
  388. package/dist/util/media-grid.d.ts +50 -0
  389. package/dist/util/media-grid.js +81 -0
  390. package/dist/util/media.d.ts +5 -0
  391. package/dist/util/media.js +10 -0
  392. package/dist/util/overlay-chrome.d.ts +52 -0
  393. package/dist/util/overlay-chrome.js +56 -0
  394. package/dist/util/overlay.d.ts +71 -0
  395. package/dist/util/overlay.js +240 -0
  396. package/dist/util/photo.d.ts +233 -0
  397. package/dist/util/photo.js +209 -0
  398. package/dist/util/portal.d.ts +22 -0
  399. package/dist/util/portal.js +50 -0
  400. package/dist/util/progress.d.ts +18 -0
  401. package/dist/util/progress.js +17 -0
  402. package/dist/util/pull-to-refresh.d.ts +26 -0
  403. package/dist/util/pull-to-refresh.js +30 -0
  404. package/dist/util/radio-keys.d.ts +24 -0
  405. package/dist/util/radio-keys.js +49 -0
  406. package/dist/util/rating.d.ts +22 -0
  407. package/dist/util/rating.js +26 -0
  408. package/dist/util/ready-made-strings.d.ts +76 -0
  409. package/dist/util/ready-made-strings.js +67 -0
  410. package/dist/util/scroll-edge.d.ts +32 -0
  411. package/dist/util/scroll-edge.js +87 -0
  412. package/dist/util/scroll-padding.d.ts +19 -0
  413. package/dist/util/scroll-padding.js +44 -0
  414. package/dist/util/segmented-control.d.ts +15 -0
  415. package/dist/util/segmented-control.js +1 -0
  416. package/dist/util/select.d.ts +40 -0
  417. package/dist/util/select.js +63 -0
  418. package/dist/util/sheet-drag.d.ts +83 -0
  419. package/dist/util/sheet-drag.js +311 -0
  420. package/dist/util/sidebar.d.ts +62 -0
  421. package/dist/util/sidebar.js +38 -0
  422. package/dist/util/skeleton.d.ts +14 -0
  423. package/dist/util/skeleton.js +22 -0
  424. package/dist/util/sliding-indicator.d.ts +24 -0
  425. package/dist/util/sliding-indicator.js +44 -0
  426. package/dist/util/sortable-list.d.ts +64 -0
  427. package/dist/util/sortable-list.js +53 -0
  428. package/dist/util/stepper.d.ts +39 -0
  429. package/dist/util/stepper.js +38 -0
  430. package/dist/util/swipeable-list-item.d.ts +35 -0
  431. package/dist/util/swipeable-list-item.js +32 -0
  432. package/dist/util/temporal-field.d.ts +88 -0
  433. package/dist/util/temporal-field.js +136 -0
  434. package/dist/util/theme-mode.d.ts +79 -0
  435. package/dist/util/theme-mode.js +121 -0
  436. package/dist/util/toaster.d.ts +132 -0
  437. package/dist/util/toaster.js +130 -0
  438. package/dist/util/tone-surface.d.ts +33 -0
  439. package/dist/util/tone-surface.js +35 -0
  440. package/dist/util/tooltip.d.ts +9 -0
  441. package/dist/util/tooltip.js +18 -0
  442. package/dist/util/top-navbar.d.ts +34 -0
  443. package/dist/util/top-navbar.js +28 -0
  444. package/dist/util/touch-target.d.ts +30 -0
  445. package/dist/util/touch-target.js +30 -0
  446. package/dist/util/zabi-strings.d.ts +141 -0
  447. package/dist/util/zabi-strings.js +105 -0
  448. package/dist/zabi-components-colors.css +11 -2
  449. package/dist/zabi-components-theme-dark-only.css +870 -258
  450. package/dist/zabi-components-theme-dark.css +870 -258
  451. package/dist/zabi-components-theme-only.css +2419 -368
  452. package/dist/zabi-components-theme.css +2419 -368
  453. package/dist/zabi-components.css +6032 -711
  454. package/docs/lucide-icons.md +40 -17
  455. package/docs/theme-imports.md +81 -11
  456. package/package.json +45 -8
@@ -2,292 +2,904 @@
2
2
 
3
3
  /* Dark Mode Theme - CSS Custom Properties */
4
4
  /* Import this file after the main theme to enable dark mode support */
5
- .dark {
6
- /* Mirror @theme --zabi-base-* ramp (same physical hex; required for standalone dark import) */
7
- --zabi-base-50: #fafafa
8
- --zabi-base-75: #f7f7f7
9
- --zabi-base-100: #f4f4f5
10
- --zabi-base-150: #ececee
11
- --zabi-base-200: #e4e4e7
12
- --zabi-base-250: #dcdcdf
13
- --zabi-base-300: #d4d4d8
14
- --zabi-base-350: #babac1
15
- --zabi-base-400: #a1a1aa
16
- --zabi-base-450: #898992
17
- --zabi-base-500: #71717a
18
- --zabi-base-550: #61616a
19
- --zabi-base-600: #52525b
20
- --zabi-base-650: #484850
21
- --zabi-base-700: #3f3f46
22
- --zabi-base-750: #333338
23
- --zabi-base-800: #27272a
24
- --zabi-base-850: #1f1f22
25
- --zabi-base-900: #18181b
26
- --zabi-base-925: #101013
27
- --zabi-base-950: #09090b
28
- /* Mirror @theme --zabi-brand-* ramp (same physical hex; required for standalone dark import) */
29
- --zabi-brand-50: #f4f6ff
30
- --zabi-brand-100: #e9eeff
31
- --zabi-brand-200: #d3dcff
32
- --zabi-brand-300: #b5c6ff
33
- --zabi-brand-400: #92a9ff
34
- --zabi-brand-500: #6d87f1
35
- --zabi-brand-600: #4f68da
36
- --zabi-brand-700: #3c52ba
37
- --zabi-brand-800: #2b3e95
38
- --zabi-brand-900: #1c2c6d
39
- --zabi-brand-950: #111d49
5
+ [data-theme="light"] {
6
+ color-scheme: light;
7
+ }
8
+
9
+ [data-theme="dark"] {
10
+ color-scheme: dark;
11
+ }
12
+
13
+ [data-theme="auto"] {
14
+ color-scheme: light dark;
15
+ }
16
+
17
+ .dark,
18
+ [data-theme="dark"] {
40
19
  /* Brand Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
41
- --color-brand-50: var(--zabi-brand-950)
42
- --color-brand-100: var(--zabi-brand-900)
43
- --color-brand-200: var(--zabi-brand-800)
44
- --color-brand-300: var(--zabi-brand-700)
45
- --color-brand-400: var(--zabi-brand-600)
46
- --color-brand-500: var(--zabi-brand-500)
47
- --color-brand-600: var(--zabi-brand-400)
48
- --color-brand-700: var(--zabi-brand-300)
49
- --color-brand-800: var(--zabi-brand-200)
50
- --color-brand-900: var(--zabi-brand-100)
51
- --color-brand-950: var(--zabi-brand-50)
52
- /* Mirror @theme --zabi-citron-* ramp (same physical hex; required for standalone dark import) */
53
- --zabi-citron-50: #f6f7ef
54
- --zabi-citron-100: #edefdf
55
- --zabi-citron-200: #dcdfbf
56
- --zabi-citron-300: #c5ca95
57
- --zabi-citron-400: #aab063
58
- --zabi-citron-500: #8c9027
59
- --zabi-citron-600: #707400
60
- --zabi-citron-700: #5a5d00
61
- --zabi-citron-800: #454700
62
- --zabi-citron-900: #313200
63
- --zabi-citron-950: #202100
20
+ --color-brand-50: var(--zabi-brand-950);
21
+ --color-brand-100: var(--zabi-brand-900);
22
+ --color-brand-200: var(--zabi-brand-800);
23
+ --color-brand-300: var(--zabi-brand-700);
24
+ --color-brand-400: var(--zabi-brand-600);
25
+ --color-brand-500: var(--zabi-brand-500);
26
+ --color-brand-600: var(--zabi-brand-400);
27
+ --color-brand-700: var(--zabi-brand-300);
28
+ --color-brand-800: var(--zabi-brand-200);
29
+ --color-brand-900: var(--zabi-brand-100);
30
+ --color-brand-950: var(--zabi-brand-50);
64
31
  /* Citron Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
65
- --color-citron-50: var(--zabi-citron-950)
66
- --color-citron-100: var(--zabi-citron-900)
67
- --color-citron-200: var(--zabi-citron-800)
68
- --color-citron-300: var(--zabi-citron-700)
69
- --color-citron-400: var(--zabi-citron-600)
70
- --color-citron-500: var(--zabi-citron-500)
71
- --color-citron-600: var(--zabi-citron-400)
72
- --color-citron-700: var(--zabi-citron-300)
73
- --color-citron-800: var(--zabi-citron-200)
74
- --color-citron-900: var(--zabi-citron-100)
75
- --color-citron-950: var(--zabi-citron-50)
76
- /* Mirror @theme --zabi-pine-* ramp (same physical hex; required for standalone dark import) */
77
- --zabi-pine-50: #f0f8f5
78
- --zabi-pine-100: #e2f1eb
79
- --zabi-pine-200: #c5e4d7
80
- --zabi-pine-300: #9fd1bd
81
- --zabi-pine-400: #70ba9e
82
- --zabi-pine-500: #399c7a
83
- --zabi-pine-600: #00805e
84
- --zabi-pine-700: #00674a
85
- --zabi-pine-800: #004f37
86
- --zabi-pine-900: #003826
87
- --zabi-pine-950: #002518
32
+ --color-citron-50: var(--zabi-citron-950);
33
+ --color-citron-100: var(--zabi-citron-900);
34
+ --color-citron-200: var(--zabi-citron-800);
35
+ --color-citron-300: var(--zabi-citron-700);
36
+ --color-citron-400: var(--zabi-citron-600);
37
+ --color-citron-500: var(--zabi-citron-500);
38
+ --color-citron-600: var(--zabi-citron-400);
39
+ --color-citron-700: var(--zabi-citron-300);
40
+ --color-citron-800: var(--zabi-citron-200);
41
+ --color-citron-900: var(--zabi-citron-100);
42
+ --color-citron-950: var(--zabi-citron-50);
43
+ /* Accent Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
44
+ --color-accent-50: var(--zabi-accent-950);
45
+ --color-accent-100: var(--zabi-accent-900);
46
+ --color-accent-200: var(--zabi-accent-800);
47
+ --color-accent-300: var(--zabi-accent-700);
48
+ --color-accent-400: var(--zabi-accent-600);
49
+ --color-accent-500: var(--zabi-accent-500);
50
+ --color-accent-600: var(--zabi-accent-400);
51
+ --color-accent-700: var(--zabi-accent-300);
52
+ --color-accent-800: var(--zabi-accent-200);
53
+ --color-accent-900: var(--zabi-accent-100);
54
+ --color-accent-950: var(--zabi-accent-50);
88
55
  /* Pine Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
89
- --color-pine-50: var(--zabi-pine-950)
90
- --color-pine-100: var(--zabi-pine-900)
91
- --color-pine-200: var(--zabi-pine-800)
92
- --color-pine-300: var(--zabi-pine-700)
93
- --color-pine-400: var(--zabi-pine-600)
94
- --color-pine-500: var(--zabi-pine-500)
95
- --color-pine-600: var(--zabi-pine-400)
96
- --color-pine-700: var(--zabi-pine-300)
97
- --color-pine-800: var(--zabi-pine-200)
98
- --color-pine-900: var(--zabi-pine-100)
99
- --color-pine-950: var(--zabi-pine-50)
100
- /* Mirror @theme --zabi-iris-* ramp (same physical hex; required for standalone dark import) */
101
- --zabi-iris-50: #f6f6fd
102
- --zabi-iris-100: #ecedfb
103
- --zabi-iris-200: #dadbf6
104
- --zabi-iris-300: #c1c4ef
105
- --zabi-iris-400: #a5a7e2
106
- --zabi-iris-500: #8486cd
107
- --zabi-iris-600: #6969b4
108
- --zabi-iris-700: #535397
109
- --zabi-iris-800: #3f3f78
110
- --zabi-iris-900: #2c2c58
111
- --zabi-iris-950: #1d1d3a
56
+ --color-pine-50: var(--zabi-pine-950);
57
+ --color-pine-100: var(--zabi-pine-900);
58
+ --color-pine-200: var(--zabi-pine-800);
59
+ --color-pine-300: var(--zabi-pine-700);
60
+ --color-pine-400: var(--zabi-pine-600);
61
+ --color-pine-500: var(--zabi-pine-500);
62
+ --color-pine-600: var(--zabi-pine-400);
63
+ --color-pine-700: var(--zabi-pine-300);
64
+ --color-pine-800: var(--zabi-pine-200);
65
+ --color-pine-900: var(--zabi-pine-100);
66
+ --color-pine-950: var(--zabi-pine-50);
112
67
  /* Iris Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
113
- --color-iris-50: var(--zabi-iris-950)
114
- --color-iris-100: var(--zabi-iris-900)
115
- --color-iris-200: var(--zabi-iris-800)
116
- --color-iris-300: var(--zabi-iris-700)
117
- --color-iris-400: var(--zabi-iris-600)
118
- --color-iris-500: var(--zabi-iris-500)
119
- --color-iris-600: var(--zabi-iris-400)
120
- --color-iris-700: var(--zabi-iris-300)
121
- --color-iris-800: var(--zabi-iris-200)
122
- --color-iris-900: var(--zabi-iris-100)
123
- --color-iris-950: var(--zabi-iris-50)
124
- /* Mirror @theme --zabi-warning-* ramp (same physical hex; required for standalone dark import) */
125
- --zabi-warning-50: #fbf6ed
126
- --zabi-warning-100: #f7ecda
127
- --zabi-warning-200: #f1d9b6
128
- --zabi-warning-300: #e8bf87
129
- --zabi-warning-400: #db9e4c
130
- --zabi-warning-500: #c17b00
131
- --zabi-warning-600: #9e6000
132
- --zabi-warning-700: #824c00
133
- --zabi-warning-800: #663800
134
- --zabi-warning-900: #4b2600
135
- --zabi-warning-950: #341800
68
+ --color-iris-50: var(--zabi-iris-950);
69
+ --color-iris-100: var(--zabi-iris-900);
70
+ --color-iris-200: var(--zabi-iris-800);
71
+ --color-iris-300: var(--zabi-iris-700);
72
+ --color-iris-400: var(--zabi-iris-600);
73
+ --color-iris-500: var(--zabi-iris-500);
74
+ --color-iris-600: var(--zabi-iris-400);
75
+ --color-iris-700: var(--zabi-iris-300);
76
+ --color-iris-800: var(--zabi-iris-200);
77
+ --color-iris-900: var(--zabi-iris-100);
78
+ --color-iris-950: var(--zabi-iris-50);
136
79
  /* Warning Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
137
- --color-warning-50: var(--zabi-warning-950)
138
- --color-warning-100: var(--zabi-warning-900)
139
- --color-warning-200: var(--zabi-warning-800)
140
- --color-warning-300: var(--zabi-warning-700)
141
- --color-warning-400: var(--zabi-warning-600)
142
- --color-warning-500: var(--zabi-warning-500)
143
- --color-warning-600: var(--zabi-warning-400)
144
- --color-warning-700: var(--zabi-warning-300)
145
- --color-warning-800: var(--zabi-warning-200)
146
- --color-warning-900: var(--zabi-warning-100)
147
- --color-warning-950: var(--zabi-warning-50)
148
- /* Mirror @theme --zabi-error-* ramp (same physical hex; required for standalone dark import) */
149
- --zabi-error-50: #fff4f3
150
- --zabi-error-100: #ffe9e6
151
- --zabi-error-200: #ffd2cd
152
- --zabi-error-300: #ffb2ab
153
- --zabi-error-400: #ff877d
154
- --zabi-error-500: #ed564e
155
- --zabi-error-600: #d22828
156
- --zabi-error-700: #b20912
157
- --zabi-error-800: #8c0006
158
- --zabi-error-900: #660002
159
- --zabi-error-950: #460202
80
+ --color-warning-50: var(--zabi-warning-950);
81
+ --color-warning-100: var(--zabi-warning-900);
82
+ --color-warning-200: var(--zabi-warning-800);
83
+ --color-warning-300: var(--zabi-warning-700);
84
+ --color-warning-400: var(--zabi-warning-600);
85
+ --color-warning-500: var(--zabi-warning-500);
86
+ --color-warning-600: var(--zabi-warning-400);
87
+ --color-warning-700: var(--zabi-warning-300);
88
+ --color-warning-800: var(--zabi-warning-200);
89
+ --color-warning-900: var(--zabi-warning-100);
90
+ --color-warning-950: var(--zabi-warning-50);
160
91
  /* Error Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
161
- --color-error-50: var(--zabi-error-950)
162
- --color-error-100: var(--zabi-error-900)
163
- --color-error-200: var(--zabi-error-800)
164
- --color-error-300: var(--zabi-error-700)
165
- --color-error-400: var(--zabi-error-600)
166
- --color-error-500: var(--zabi-error-500)
167
- --color-error-600: var(--zabi-error-400)
168
- --color-error-700: var(--zabi-error-300)
169
- --color-error-800: var(--zabi-error-200)
170
- --color-error-900: var(--zabi-error-100)
171
- --color-error-950: var(--zabi-error-50)
92
+ --color-error-50: var(--zabi-error-950);
93
+ --color-error-100: var(--zabi-error-900);
94
+ --color-error-200: var(--zabi-error-800);
95
+ --color-error-300: var(--zabi-error-700);
96
+ --color-error-400: var(--zabi-error-600);
97
+ --color-error-500: var(--zabi-error-500);
98
+ --color-error-600: var(--zabi-error-400);
99
+ --color-error-700: var(--zabi-error-300);
100
+ --color-error-800: var(--zabi-error-200);
101
+ --color-error-900: var(--zabi-error-100);
102
+ --color-error-950: var(--zabi-error-50);
172
103
  /* Base Color Scale — semantic → physical mirror (1000 − step); 500 is fixed point */
173
- --color-base-50: #09090b
174
- --color-base-75: #101013
175
- --color-base-100: #18181b
176
- --color-base-150: #1f1f22
177
- --color-base-200: #27272a
178
- --color-base-250: #333338
179
- --color-base-300: #3f3f46
180
- --color-base-350: #484850
181
- --color-base-400: #52525b
182
- --color-base-450: #61616a
183
- --color-base-500: #71717a
184
- --color-base-550: #898992
185
- --color-base-600: #a1a1aa
186
- --color-base-650: #babac1
187
- --color-base-700: #d4d4d8
188
- --color-base-750: #dcdcdf
189
- --color-base-800: #e4e4e7
190
- --color-base-850: #ececee
191
- --color-base-900: #f4f4f5
192
- --color-base-925: #f7f7f7
193
- --color-base-950: #fafafa
104
+ --color-base-50: var(--zabi-base-950);
105
+ --color-base-75: var(--zabi-base-925);
106
+ --color-base-100: var(--zabi-base-900);
107
+ --color-base-150: var(--zabi-base-850);
108
+ --color-base-200: var(--zabi-base-800);
109
+ --color-base-250: var(--zabi-base-750);
110
+ --color-base-300: var(--zabi-base-700);
111
+ --color-base-350: var(--zabi-base-650);
112
+ --color-base-400: var(--zabi-base-600);
113
+ --color-base-450: var(--zabi-base-550);
114
+ --color-base-500: var(--zabi-base-500);
115
+ --color-base-550: var(--zabi-base-450);
116
+ --color-base-600: var(--zabi-base-400);
117
+ --color-base-650: var(--zabi-base-350);
118
+ --color-base-700: var(--zabi-base-300);
119
+ --color-base-750: var(--zabi-base-250);
120
+ --color-base-800: var(--zabi-base-200);
121
+ --color-base-850: var(--zabi-base-150);
122
+ --color-base-900: var(--zabi-base-100);
123
+ --color-base-925: var(--zabi-base-75);
124
+ --color-base-950: var(--zabi-base-50);
194
125
  /* Background Colors - No dark mode overrides needed, base colors are already inverted */
195
126
  /* Page Colors - No dark mode overrides needed, base colors are already inverted */
196
- /* Surface elevation — shadows don't read on dark, so each level steps up +6 OKLCH lightness
197
- * from the page background (L 21 → 27 → 33 → 39).
127
+ /* Surface elevation — shadows don't read on dark, so the surfaces carry it by tone, in two
128
+ * steps: page L 21.0, card L 24.1, elevated and overlay L 27.4 (D133/D134).
198
129
  *
199
130
  * GENERATED by scripts/generate-surfaces.js from tokens/surface-ladder.js — do not hand-edit.
200
- * Each level is #fafafa (the same light as the dark hover tint) washed over the page at
201
- * 6.4% / 13.1% / 19.7%, so every level is the one below it with more light on it. Baked to
202
- * opaque hex so the static checks can still resolve them and a modal stays opaque.
203
- * Enforced by scripts/check-surface-elevation.js (strictly increasing, 5–8 points). */
204
- --color-surface-base: #18181b
205
- --color-surface-raised: #262629
206
- --color-surface-elevated: #363638
207
- --color-surface-overlay: #454547
208
- --color-surface-overlay-hover: #52525b
131
+ * Every role is a plain step of the neutral ramp (--zabi-base-N), so hue and chroma are the
132
+ * ramp's own, and a --zabi-base-* override or a tinted neutral carries all of them. An overlay
133
+ * (sheet, menu, modal) is the same tone as elevated: it is told apart by its edge
134
+ * (--color-material-rim) and its shadow, not by being greyer. The hover on an overlay is one
135
+ * ramp step lighter; the inset is the page step, told apart by its 3:1 edge.
136
+ * With the default greys: #18181b / #1f1f22 / #27272a / #27272a, hover #333338, inset #18181b.
137
+ * Enforced by scripts/check-surface-elevation.js (ramp steps, never lighter downwards, at most
138
+ * two tone steps of 2–5 points, the overlay edge and the card edge). */
139
+ --color-surface-base: var(--zabi-base-900);
140
+ --color-surface-raised: var(--zabi-base-850);
141
+ --color-surface-elevated: var(--zabi-base-800);
142
+ --color-surface-overlay: var(--zabi-base-800);
143
+ --color-surface-overlay-hover: var(--zabi-base-750);
144
+ /* Inset — the page step, 3 points below the card (L 24.1). A field on the page is told apart
145
+ * by its 3:1 edge, as a white field on the near-white light page is. */
146
+ --color-surface-inset: var(--zabi-base-900);
147
+ /* Chrome and the bar tokens — restated so a light-only override of the page
148
+ * or the raised surface does not reach dark. */
149
+ --color-surface-chrome: var(--color-surface-base);
150
+ --color-bar: var(--color-surface-chrome);
151
+ --color-bar-border: color-mix(in srgb, var(--color-headline) 10%, transparent);
152
+ --color-bar-brand: var(--color-action-primary);
153
+ --color-tabbar-active: var(--color-nav-menu-active);
209
154
  /* Distinct from base, raised AND elevated — a neutral chip has no hue to
210
- * separate it, so it has to separate on lightness wherever it lands. */
211
- --color-neutral-subtle: var(--color-base-300)
212
- --color-border-overlay: var(--color-base-450)
155
+ * separate it, so it has to separate on lightness wherever it lands:
156
+ * base-300 is 1.70:1 on the page, 1.57:1 on the card, 1.43:1 on elevated. */
157
+ --color-neutral-subtle: var(--color-base-300);
158
+ --color-neutral-border: var(--color-base-200);
159
+ --color-border-overlay: var(--color-base-450);
213
160
  /* Background Colors */
214
- --color-background: var(--color-surface-base)
161
+ --color-background: var(--color-surface-base);
162
+ --color-background-tertiary: var(--color-base-100);
163
+ /* Page Colors — the dark page (base-100 here is --zabi-base-900, the same value as before) */
164
+ --color-page: var(--color-surface-base);
215
165
  /* Card Colors — aliases of the surface levels */
216
- --color-card: var(--color-surface-raised)
217
- --color-card-hover: var(--color-surface-elevated)
218
- --color-card-active: var(--color-surface-overlay)
219
- --color-card-elevated: var(--color-surface-elevated)
166
+ --color-card: var(--color-surface-raised);
167
+ --color-card-hover: var(--color-surface-elevated);
168
+ --color-card-active: var(--color-surface-overlay-hover);
169
+ --color-card-elevated: var(--color-surface-elevated);
170
+ /* Card tint, dark: the brand at 8% over the card (as the status tints of D136,
171
+ * which are 16%: here the field edge sets the ceiling, base-500 is 3.07:1 on
172
+ * this and 2.90:1 at 12%). 8% is #252733: 1.11:1 on the card and 1.20:1 on the
173
+ * page; headline 13.49, body 11.68, label and description 10.03, caption 7.68,
174
+ * link 8.81, ring 6.59:1. */
175
+ --color-card-tint: color-mix(in srgb, var(--zabi-brand-500) 8%, var(--color-surface-raised));
176
+ /* Card variant="flat", dark: a translucent step of the neutral ramp (base-50 at 7%), so a flat card
177
+ * is lighter than whatever it sits on, and a flat card inside a flat card is lighter again. Shadows
178
+ * do not carry layers on a dark page; alpha does. Hover and pressed are the same step at 11% and 15%.
179
+ * Restore the opaque fill: overrides: { dark: { '--color-card-flat': 'var(--color-card)' } }. */
180
+ --color-card-flat: color-mix(in srgb, var(--zabi-base-50) 7%, transparent);
181
+ --color-card-flat-hover: color-mix(in srgb, var(--zabi-base-50) 11%, transparent);
182
+ --color-card-flat-active: color-mix(in srgb, var(--zabi-base-50) 15%, transparent);
220
183
  /* Surfaces — numbered aliases of the surface levels */
221
- --color-surface-1: var(--color-surface-raised)
222
- --color-surface-2: var(--color-surface-elevated)
223
- --color-surface-3: var(--color-surface-overlay)
224
- --color-surface-4: var(--color-base-400)
184
+ --color-surface-1: var(--color-surface-raised);
185
+ --color-surface-2: var(--color-surface-elevated);
186
+ --color-surface-3: var(--color-surface-overlay);
187
+ --color-surface-4: var(--color-surface-overlay-hover);
225
188
  /*
226
- * Secondary text keeps ≥ 4.5:1 on every surface level, including overlays (L39).
227
- * Only base-650 and lighter pass on the overlay, so caption takes base-650 and description
228
- * moves one step up to base-700 to stay visibly stronger than caption.
189
+ * Secondary text keeps ≥ 4.5:1 on every surface level, including overlays (L27).
190
+ * Caption takes base-650 and description base-700 to stay visibly stronger than it.
229
191
  */
230
- --color-description: var(--color-base-700)
231
- --color-caption: var(--color-base-650)
192
+ --color-description: var(--color-base-700);
193
+ --color-caption: var(--color-base-650);
232
194
  /* Interaction fills — light tint on dark, mirroring the light-mode rule.
233
195
  * Alpha keeps these one step away from every surface level, which a fixed
234
196
  * ramp step cannot guarantee (base-100 in dark IS the page background). */
235
- --color-surface-hover: rgba(250, 250, 250, 0.08)
236
- --color-surface-active: rgba(250, 250, 250, 0.14)
197
+ --color-surface-hover: rgba(250, 250, 250, 0.08);
198
+ --color-surface-active: rgba(250, 250, 250, 0.14);
237
199
  /* Overlay Colors */
238
- --color-overlay: rgba(0, 0, 0, 0.7)
200
+ --color-overlay: rgba(0, 0, 0, 0.7);
239
201
  /* Input Colors
240
- * Dark fields are INSET: one step below the raised surface they sit on,
241
- * which is the dark-mode equivalent of a white field on a grey page. */
242
- --color-input: var(--color-base-150)
243
- --color-input-border: var(--color-base-300)
244
- --color-input-hover: var(--color-base-200)
245
- --color-input-focus: var(--color-base-150)
246
- --color-input-disabled: var(--color-base-100)
247
- --color-input-placeholder: var(--color-base-500)
202
+ * Dark fields are a translucent step of the neutral ramp (base-50 at 7%), the
203
+ * same idea as the flat card: a well one step LIGHTER than whatever it sits on,
204
+ * without a rule per surface. It was the page step (--color-surface-inset), so
205
+ * a dark form was told from the page by its 3:1 edge alone. 7% is 1.20:1 on
206
+ * the page (#28282b), 1.22:1 on a card (#2e2e31) and 1.23:1 on the overlay
207
+ * (#363639); hover 10% and pressed 15% (1.30:1 against the resting field on
208
+ * all three). The edge below stays 3:1 against the surface outside it.
209
+ * Restore the opaque field: overrides: { dark: {
210
+ * '--color-input': 'var(--color-surface-inset)', '--color-input-hover': 'var(--color-base-200)',
211
+ * '--color-input-focus': 'var(--color-base-150)',
212
+ * '--color-input-active': 'color-mix(in srgb, var(--zabi-base-50) 10%, var(--color-surface-inset))' } }. */
213
+ --color-input: color-mix(in srgb, var(--zabi-base-50) 7%, transparent);
214
+ /* What a field is inside a colour block (.on-brand, .on-accent, .on-fill): the translucent
215
+ * well would sit on the block's fill, which the theme's text is not set for, so the field
216
+ * takes these opaque steps there. */
217
+ --color-input-solid: var(--color-surface-inset);
218
+ --color-input-solid-hover: var(--color-base-200);
219
+ --color-input-solid-focus: var(--color-base-150);
220
+ --color-input-solid-active: color-mix(in srgb, var(--zabi-base-50) 10%, var(--color-surface-inset));
221
+ /* Restated here: the root value of a var() alias is resolved at :root. */
222
+ --color-progress-fill: var(--color-action-primary);
223
+ /* The field step is the page now, so the track takes its own: base-75
224
+ * (#101013), a well just below the page: 1.06:1 on the page, 1.14:1 on the
225
+ * card, 1.45:1 on the elevated surface. It was base-250 (#333338, 1.41:1 on
226
+ * the page). The fill is a mid step now (brand-600), and 3:1 on its rail
227
+ * needs a track this dark: 3.91:1 here with the default brand (2.59:1 on
228
+ * base-250, 2.94:1 for an amber brand on base-200). */
229
+ --color-progress-track: var(--color-base-75);
230
+ /* Restated: the root value of a var() alias is resolved at :root. The field
231
+ * edge, 3.67:1 on the page and 3.40:1 on the card. */
232
+ --color-progress-track-border: var(--color-input-border);
233
+ /* base-500 (the mirror's fixed point): 3.67:1 on the dark field and the page,
234
+ * 3.40:1 on the card, 3.08:1 on the elevated surface and the overlay.
235
+ * base-300 was 1.70, 1.57 and 1.43. */
236
+ --color-input-border: var(--color-base-500);
237
+ --color-input-border-hover: var(--color-input-border);
238
+ /* The decorative hairline (Card's default variant, list dividers). Quiet, like
239
+ * light's: base-250 is #333338, 1.41:1 on the page and 1.31:1 on the card
240
+ * (base-300 was 1.70 and 1.57, base-200 only 1.10 on the card). Restated: the
241
+ * root value of a var() alias is resolved at :root. -medium (2.29:1) and
242
+ * -strong (3.67:1) keep their order above it. */
243
+ --color-border: var(--color-base-250);
244
+ --color-border-weak: var(--color-base-250);
245
+ /* Toggle track, off. The thumb is the card (#1f1f22), so the track cannot
246
+ * be as dark as it. base-300 (#3f3f46) is 1.57:1 against the thumb, and the
247
+ * field edge gives the 3:1: 3.67:1 on the page, 3.40:1 on the card. */
248
+ --color-toggle-track: var(--color-base-300);
249
+ --color-toggle-track-hover: var(--color-base-350);
250
+ --color-toggle-track-active: var(--color-base-400);
251
+ --color-toggle-track-border: var(--color-input-border);
252
+ /* Toggle knob in dark: off, a light knob on the dark track (base-700, #d4d4d8:
253
+ * 7.07:1 resting, 5.23:1 pressed); on, as in light (the same 4.86:1 and up). */
254
+ --color-toggle-knob: var(--color-base-700);
255
+ --color-toggle-knob-checked: var(--color-action-primary-text);
256
+ /* Hover 10%: 1.10:1 above the resting well on the page, the card and the overlay, body 8.65:1
257
+ * or more and placeholder 4.68:1 or more on it. Was base-200. */
258
+ --color-input-hover: color-mix(in srgb, var(--zabi-base-50) 10%, transparent);
259
+ /* Pressed 15% of the light end of the ramp (unmirrored, --zabi-base-50): 1.30:1 against the
260
+ * resting well on the page (#3a3a3c), the card (#404042) and the overlay (#474749), 1.18:1
261
+ * past hover, body 7.34:1 or more, placeholder 4.54:1 on a card and 4.08:1 on the overlay,
262
+ * short of the border (2.35:1 or less). 14% is 1.254:1 on the default and under 1.25 on a tinted ramp. Was 10% into the page step (#2f2f31). */
263
+ --color-input-active: color-mix(in srgb, var(--zabi-base-50) 15%, transparent);
264
+ /* Focus is the resting well: the ring shows focus, and hover still reads on a focused field.
265
+ * Was base-150. */
266
+ --color-input-focus: color-mix(in srgb, var(--zabi-base-50) 7%, transparent);
267
+ /* The field is the page step now, so the disabled field goes one step below
268
+ * the page (base-75, #101013): 1.07:1 on the page, 1.16:1 on the card. */
269
+ --color-input-disabled: var(--color-base-75);
270
+ /* base-500 is the mirror's fixed point, the same grey as it was in light,
271
+ * and a dark field is a far lighter ground for it than a white one is dark:
272
+ * 3.40:1 at rest, 3.08:1 on hover, 2.60:1 pressed. base-600 mirrors to
273
+ * --zabi-base-400 (#a1a1aa): 6.41, 5.81 and 4.90. base-550 would be 4.74
274
+ * at rest but under 4.5 on hover. The value text is 2.0:1 stronger.
275
+ * The well is lighter now (a translucent step over the surface), and the
276
+ * pressed one over a card held base-400 to 4.04:1: so 40% of the next step
277
+ * toward the value (base-350, #babac1) is mixed in, #ababb3: 6.46, 5.89 and
278
+ * 4.98:1 at rest, hover and pressed on the page, 5.91, 5.37 and 4.54:1 on a
279
+ * card, 5.30, 4.82 and 4.08:1 on the overlay (pressed there is held to 4:1,
280
+ * see contrast-pairs.js), and 1.80:1 under the value (1.75 is the floor; 50%
281
+ * would be 1.75). Was base-600 (#a1a1aa). */
282
+ --color-input-placeholder: color-mix(in srgb, var(--zabi-base-350) 40%, var(--zabi-base-400));
248
283
  /* Text Colors - No dark mode overrides needed, base colors are already inverted */
249
- /* Border Colors - No dark mode overrides needed, base colors are already inverted */
250
- /* Focus Colors - No dark mode overrides needed, brand colors are already inverted */
284
+ /* Border Colors - the decorative edges need no override, base colors are
285
+ * already inverted. The control boundary does: base-500 is the mirror's
286
+ * fixed point (#71717a in both themes), and the dark surfaces above the card
287
+ * are too light for it (2.49:1 on elevated, 1.98:1 on the overlay). base-600
288
+ * mirrors to --zabi-base-400 (#a1a1aa): 3.73:1 on the overlay, the lightest
289
+ * surface, and more on every level below it. base-550 is 2.76:1 there. */
290
+ --color-control-border: var(--color-base-600);
291
+ /* Segmented control thumb — restated: the aliases resolve at :root, so without
292
+ * these dark would keep the light card colour. The track is a light tint over
293
+ * the page or a card (#2c2c2f / #333335), which the overlay tone now sits
294
+ * below, so the thumb takes base-400 (#52525b): 1.80:1 over the page track,
295
+ * 1.63:1 over the card track, headline text 7.03:1. */
296
+ --color-segment-thumb: var(--color-base-400);
297
+ --color-segment-thumb-text: var(--color-headline);
298
+ --color-segment-thumb-border: var(--color-control-border);
299
+ /* Focus Colors — the same steps as light, through the mirror: brand-600 is
300
+ * --zabi-brand-400 here, which is also the dark primary fill, so on a
301
+ * primary button the ring is separated by its offset gap exactly as in light.
302
+ * Dark used to stay one step back, on brand-500, the mirror's fixed point.
303
+ * That is 5.4:1 on the dark page but only 2.91:1 on the overlay, the
304
+ * lightest surface (2.78:1 for an amber brand), and a ring in a modal or a
305
+ * menu needs 3:1 too. Restated rather than left to inherit, so an app's
306
+ * light-only override of --color-focus does not reach dark. */
307
+ --color-focus: var(--color-brand-600);
308
+ --color-focus-weak: var(--color-brand-700);
309
+ --color-focus-medium: var(--color-brand-800);
310
+ --color-focus-strong: var(--color-brand-900);
311
+ /* The muted ring, for the same reason as the control boundary above: one
312
+ * step lighter than the fixed point, 3.73:1 on the overlay. */
313
+ --color-focus-ring-muted: var(--color-base-600);
251
314
  /* Primary Colors - No dark mode overrides needed, brand colors are already inverted */
252
315
  /* Secondary Colors - No dark mode overrides needed, base colors are already inverted */
253
- /* Success Colors — no overrides: @theme uses --color-pine-*; semantic pine resolves to mirrored physical ramp inside .dark */
254
- /* Warning Colors — no overrides: @theme uses --color-warning-* scale; it mirrors in .dark via --zabi-warning-* */
255
- /* Error Colors — no overrides: @theme uses --color-error-* scale; it mirrors in .dark via --zabi-error-* */
256
- /* Energetic Colors — no overrides: @theme uses --color-citron-*; citron mirrors in .dark via --zabi-citron-* */
316
+ /* Tinted fills and edges — the hue thinned into the card surface, not the
317
+ * mirrored step 100 / 200 (physical 900 / 800: deep, saturated, the loudest
318
+ * area on a dark screen). A tint here is a low-chroma tint of the card, and
319
+ * the hue is carried by the icon and the text. The mid step (500) is where
320
+ * the ramp's chroma peaks and the mirror's fixed point. The base is the card
321
+ * surface, so a badge or alert on a card is never darker than the card, and
322
+ * an app's override of the card surface carries through. The edge is the
323
+ * same mix, stronger. */
324
+ --color-success-subtle: color-mix(in srgb, var(--zabi-pine-500) 16%, var(--color-surface-raised));
325
+ --color-success-border: color-mix(in srgb, var(--zabi-pine-500) 36%, var(--color-surface-raised));
326
+ --color-warning-subtle: color-mix(in srgb, var(--zabi-warning-500) 16%, var(--color-surface-raised));
327
+ --color-warning-border: color-mix(in srgb, var(--zabi-warning-500) 36%, var(--color-surface-raised));
328
+ --color-error-subtle: color-mix(in srgb, var(--zabi-error-500) 16%, var(--color-surface-raised));
329
+ --color-error-border: color-mix(in srgb, var(--zabi-error-500) 36%, var(--color-surface-raised));
330
+ --color-energetic-subtle: color-mix(in srgb, var(--zabi-citron-500) 16%, var(--color-surface-raised));
331
+ --color-energetic-border: color-mix(in srgb, var(--zabi-citron-500) 36%, var(--color-surface-raised));
332
+ --color-accent-subtle: color-mix(in srgb, var(--zabi-accent-500) 16%, var(--color-surface-raised));
333
+ --color-accent-border: color-mix(in srgb, var(--zabi-accent-500) 36%, var(--color-surface-raised));
334
+ /* Label on a solid accent fill: the dark end of the ramp on its light end. */
335
+ --color-on-accent: var(--zabi-on-accent-dark);
336
+ --color-info-subtle: color-mix(in srgb, var(--zabi-iris-500) 16%, var(--color-surface-raised));
337
+ --color-info-border: color-mix(in srgb, var(--zabi-iris-500) 36%, var(--color-surface-raised));
257
338
  /* Neutral Colors — base-550 mirrors to L* 57, which is only 4.35:1 on a
258
339
  * raised surface. One step lighter clears AA on every dark surface level. */
259
- --color-neutral: var(--color-base-600)
260
- /* Info Colors — no overrides: @theme uses --color-iris-* (incl. --color-info-active); iris mirrors in .dark via --zabi-iris-* */
340
+ --color-neutral: var(--color-base-600);
341
+ /* Info Colors — no further overrides: @theme uses --color-iris-* (incl. --color-info-active); iris mirrors in .dark via --zabi-iris-* */
261
342
  /* ========================================
262
343
  ACTION COLORS - Dark Mode Overrides
263
344
  ======================================== */
264
- /* Primary Actions - Background adapts automatically via brand color inversion */
265
- /* 🎯 TO CHANGE bg-action-primary IN DARK MODE: Edit --zabi-brand-* physical ramp above (semantic --color-brand-* follows mirror) */
266
- /* Text color - the physical dark end of the brand ramp, on the physical
267
- * light end used as the dark-mode primary fill. 7.21:1. */
268
- --color-action-primary-text: var(--zabi-brand-950)
345
+ /* Primary Actions - the brand hue in dark too: the same physical steps as
346
+ * light (600 / 700 / 800), not the mirrored ones, which would be the pale
347
+ * 400 / 300 / 200. White on step 600 is 4.76 to 4.86:1 (every ramp is on one
348
+ * lightness curve); with the default brand the fill is 3.65:1 on the page,
349
+ * 3.39:1 on the card and 3.07:1 on the overlay (3:1 holds on all three, WCAG
350
+ * 1.4.11). Hover and pressed go darker, as in light.
351
+ * createTheme({ darkPrimary: 'mirror' }) writes the mirrored fills instead.
352
+ * 🎯 TO CHANGE bg-action-primary IN DARK MODE: override --color-action-primary under `dark`. */
353
+ --color-action-primary: var(--zabi-brand-600);
354
+ --color-action-primary-hover: var(--zabi-brand-700);
355
+ --color-action-primary-active: var(--zabi-brand-800);
356
+ /* "On brand" in dark: --zabi-on-brand-dark, which follows the light label (white). If an app
357
+ * moves the dark primary to a pale step, it sets the knob to a dark one.
358
+ * --color-action-primary-text is restated, as it always was here, so that an
359
+ * app's light-only override of it does not carry a different label onto the
360
+ * dark fill. */
361
+ --color-on-brand: var(--zabi-on-brand-dark);
362
+ --color-action-primary-text: var(--color-on-brand);
363
+ /* Pinned like the other tints: light moved these a step darker. */
364
+ --color-action-primary-subtle: var(--color-brand-100);
365
+ --color-action-primary-subtle-hover: var(--color-brand-200);
366
+ --color-action-primary-border: var(--color-brand-200);
367
+ /* Half a step past the dark hover fill, as in light. */
368
+ --color-action-primary-subtle-active: color-mix(in srgb, var(--color-brand-300) 50%, var(--color-brand-200));
269
369
  /* Secondary Actions - light alpha tint instead of the light-mode dark tint */
270
- --color-action-secondary: rgba(250, 250, 250, 0.09)
271
- --color-action-secondary-hover: rgba(250, 250, 250, 0.15)
272
- --color-action-secondary-active: rgba(250, 250, 250, 0.21)
273
- /* Disabled Actions - base-200 in dark is #27272a, still the quietest fill */
274
- /* Danger Actions — restated as aliases, not re-pointed.
275
- * These resolve through the mirrored --color-error-* scale, so dark danger
276
- * is the same step of the same ramp as light danger. They are repeated here
277
- * only because `zabi-components/theme-dark-only` has to stand alone as a
278
- * complete import (validate-theme.js enforces that). The raw hex this
279
- * replaced pinned dark danger brighter than light, which is why the
280
- * destructive action was the loudest element on a dark page. */
281
- --color-action-danger: var(--color-error-600)
282
- --color-action-danger-hover: var(--color-error-700)
283
- --color-action-danger-active: var(--color-error-800)
284
- --color-action-danger-subtle: var(--color-error-100)
285
- --color-action-danger-subtle-hover: var(--color-error-200)
286
- --color-action-danger-text: var(--color-error-50)
287
- /* Shadow Colors */
288
- --shadow-opacity: 0.3
289
- --shadow-sm: 0 1px 3px 0 rgb(var(--shadow-color) / var(--shadow-opacity)), 0 1px 2px -1px rgb(var(--shadow-color) / var(--shadow-opacity))
290
- --shadow-md: 0 4px 6px -1px rgb(var(--shadow-color) / var(--shadow-opacity)), 0 2px 4px -2px rgb(var(--shadow-color) / var(--shadow-opacity))
291
- --shadow-lg: 0 10px 15px -3px rgb(var(--shadow-color) / var(--shadow-opacity)), 0 4px 6px -4px rgb(var(--shadow-color) / var(--shadow-opacity))
292
- --shadow-xl: 0 20px 25px -5px rgb(var(--shadow-color) / var(--shadow-opacity)), 0 8px 10px -6px rgb(var(--shadow-color) / var(--shadow-opacity))
293
- }
370
+ --color-action-secondary: rgba(250, 250, 250, 0.09);
371
+ --color-action-secondary-hover: rgba(250, 250, 250, 0.15);
372
+ --color-action-secondary-active: rgba(250, 250, 250, 0.21);
373
+ /* Tonal Actions - the deep brand tint (brand-100 in dark is the deep end of
374
+ * the mirrored ramp) with a light brand label. Restated: the root values are
375
+ * var() aliases of roles that move in dark. Brand-800 is the light end of the
376
+ * mirrored ramp here: 9.48, 6.94 and 5.86:1 on the three fills. */
377
+ --color-action-tonal: var(--color-action-primary-subtle);
378
+ --color-action-tonal-hover: var(--color-action-primary-subtle-hover);
379
+ --color-action-tonal-active: color-mix(in srgb, var(--color-brand-300) 50%, var(--color-brand-200));
380
+ --color-action-tonal-text: var(--color-brand-800);
381
+ /* Chip, dark - its own steps, not the mirror of light. The ladder rises from
382
+ * the page (base-900, card base-850): rest base-750 is 1.41:1 on the page and
383
+ * 1.31:1 on the card, hover base-700 and pressed base-650 lighter again (1.70
384
+ * and 1.96 on the page). Headline is 11.43, 9.50 and 8.24:1 on the three.
385
+ * Restated, with the selected chip, because the root values are var() aliases. */
386
+ --color-chip: var(--zabi-base-750);
387
+ --color-chip-hover: var(--zabi-base-700);
388
+ --color-chip-active: var(--zabi-base-650);
389
+ --color-chip-text: var(--color-headline);
390
+ --color-chip-selected: var(--color-action-tonal);
391
+ --color-chip-selected-hover: var(--color-action-tonal-hover);
392
+ --color-chip-selected-active: var(--color-action-tonal-active);
393
+ --color-chip-selected-text: var(--color-action-tonal-text);
394
+ /* Outline Actions - the field edge, restated for the same reason. */
395
+ --color-action-outline-border: var(--color-input-border);
396
+ --color-action-outline-border-hover: var(--color-input-border-hover);
397
+ /* Disabled Actions - base-200 in dark is #27272a (the elevated tone), still
398
+ * the quietest fill, and the one the disabled label (base-500) reads on at 3.08:1.
399
+ * Pinned: light moved a step darker to stay visible on its darker page. */
400
+ --color-action-disabled: var(--color-base-200);
401
+ --color-action-disabled-border: var(--color-base-250);
402
+ /* Danger Actions — the same physical steps as light danger (600 / 700 / 800
403
+ * of --zabi-error-*) with the same label (step 50), so a destructive button
404
+ * is one red in both modes and shares the primary's veil. Physical, not
405
+ * through the mirror, which would be the pale 400 / 300 / 200. Restated
406
+ * because `zabi-components/theme-dark-only` has to stand alone as a complete
407
+ * import (validate-theme.js enforces that). The subtle tints are the thin mix below. */
408
+ --color-action-danger: var(--zabi-error-600);
409
+ --color-action-danger-hover: var(--zabi-error-700);
410
+ --color-action-danger-active: var(--zabi-error-800);
411
+ --color-action-danger-subtle: var(--color-error-subtle);
412
+ --color-action-danger-subtle-hover: color-mix(in srgb, var(--zabi-error-500) 20%, var(--color-surface-raised));
413
+ --color-action-danger-subtle-active: color-mix(in srgb, var(--zabi-error-500) 32%, var(--color-surface-raised));
414
+ --color-action-danger-text: var(--zabi-error-50);
415
+ /* Shadow Colors — black, not the light theme's ink tint. Much stronger than
416
+ * light (0.1 / 0.06): an overlay is the same tone as the elevated surface
417
+ * now, so a sheet (L 27.4) floats over a card (L 24.1) by its shadow and its
418
+ * edge, and the shadow has to carry it. */
419
+ --shadow-color: 0 0 0;
420
+ --shadow-opacity: 0.5;
421
+ --shadow-opacity-contact: 0.4;
422
+ --shadow-sm: 0 1px 2px 0 rgb(var(--shadow-color) / var(--shadow-opacity-contact)), 0 2px 6px -1px rgb(var(--shadow-color) / var(--shadow-opacity));
423
+ --shadow-md: 0 1px 3px 0 rgb(var(--shadow-color) / var(--shadow-opacity-contact)), 0 6px 14px -2px rgb(var(--shadow-color) / var(--shadow-opacity));
424
+ --shadow-lg: 0 1px 2px 0 rgb(var(--shadow-color) / var(--shadow-opacity-contact)), 0 10px 30px 0 rgb(var(--shadow-color) / var(--shadow-opacity));
425
+ --shadow-xl: 0 2px 4px 0 rgb(var(--shadow-color) / var(--shadow-opacity-contact)), 0 20px 50px -8px rgb(var(--shadow-color) / var(--shadow-opacity));
426
+ --shadow-material: 0 1px 2px 0 rgb(var(--shadow-color) / var(--shadow-opacity-contact)), 0 10px 30px 0 rgb(var(--shadow-color) / var(--shadow-opacity));
427
+ /* Materials — the alphas and the backdrop brightness differ (see @theme).
428
+ * The fills are not restated: they follow the surface tokens above. The
429
+ * filters are restated, because they hold a var() that resolves where it is
430
+ * declared; the fallbacks below are one class more specific than this rule
431
+ * and set them to none, so they still win in dark. */
432
+ --material-backdrop-brightness: 0.6;
433
+ --material-alpha-thin: 60%;
434
+ --material-alpha-regular: 68%;
435
+ --material-alpha-thick: 72%;
436
+ --material-filter-thin: blur(var(--material-blur-thin)) saturate(var(--material-saturate)) brightness(var(--material-backdrop-brightness));
437
+ --material-filter-regular: blur(var(--material-blur-regular)) saturate(var(--material-saturate)) brightness(var(--material-backdrop-brightness));
438
+ --material-filter-thick: blur(var(--material-blur-thick)) saturate(var(--material-saturate)) brightness(var(--material-backdrop-brightness));
439
+ --color-material-highlight: color-mix(in srgb, var(--zabi-base-50) 14%, transparent);
440
+ --color-material-rim: color-mix(in srgb, var(--zabi-base-50) 14%, transparent);
441
+ /* Gradients: the wash is quieter in dark (see @theme). The stops follow. */
442
+ --gradient-canvas-strength: 25%;
443
+ --gradient-control-top-strength: 0%;
444
+ --gradient-control-bottom-strength: 14%;
445
+ /* The accent's own strengths, no longer the shared ones: in dark its fill is
446
+ * the light step with a dark label, which a darkening veil would fail, so it
447
+ * keeps the lighter top and slight dark bottom it had (22 / 6). */
448
+ --gradient-control-accent-top-strength: 22%;
449
+ --gradient-control-accent-bottom-strength: 6%;
450
+ --shadow-control-highlight: inset 0 1px 0 color-mix(in srgb, var(--zabi-base-50) 25%, transparent);
451
+ /* Not a token: tells the browser the page is dark, so what it draws itself
452
+ * (date and time pickers, scrollbars, autofill, the caret of a native
453
+ * select) is dark too. It is the last declaration on purpose:
454
+ * scripts/sync-theme-tokens.js rewrites the ramp aliases at the top of this
455
+ * rule. The build publishes this rule under [data-theme="dark"] and, inside
456
+ * the dark media query, [data-theme="auto"], and every one of them carries
457
+ * it. Until 8.1 only the attributes set it and the class did not. */
458
+ color-scheme: dark;
459
+ }
460
+
461
+ /* The same declarations again, for data-theme="auto" when the system is dark. */
462
+ @media (prefers-color-scheme: dark) {
463
+ [data-theme="auto"] {
464
+ /* Brand Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
465
+ --color-brand-50: var(--zabi-brand-950);
466
+ --color-brand-100: var(--zabi-brand-900);
467
+ --color-brand-200: var(--zabi-brand-800);
468
+ --color-brand-300: var(--zabi-brand-700);
469
+ --color-brand-400: var(--zabi-brand-600);
470
+ --color-brand-500: var(--zabi-brand-500);
471
+ --color-brand-600: var(--zabi-brand-400);
472
+ --color-brand-700: var(--zabi-brand-300);
473
+ --color-brand-800: var(--zabi-brand-200);
474
+ --color-brand-900: var(--zabi-brand-100);
475
+ --color-brand-950: var(--zabi-brand-50);
476
+ /* Citron Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
477
+ --color-citron-50: var(--zabi-citron-950);
478
+ --color-citron-100: var(--zabi-citron-900);
479
+ --color-citron-200: var(--zabi-citron-800);
480
+ --color-citron-300: var(--zabi-citron-700);
481
+ --color-citron-400: var(--zabi-citron-600);
482
+ --color-citron-500: var(--zabi-citron-500);
483
+ --color-citron-600: var(--zabi-citron-400);
484
+ --color-citron-700: var(--zabi-citron-300);
485
+ --color-citron-800: var(--zabi-citron-200);
486
+ --color-citron-900: var(--zabi-citron-100);
487
+ --color-citron-950: var(--zabi-citron-50);
488
+ /* Accent Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
489
+ --color-accent-50: var(--zabi-accent-950);
490
+ --color-accent-100: var(--zabi-accent-900);
491
+ --color-accent-200: var(--zabi-accent-800);
492
+ --color-accent-300: var(--zabi-accent-700);
493
+ --color-accent-400: var(--zabi-accent-600);
494
+ --color-accent-500: var(--zabi-accent-500);
495
+ --color-accent-600: var(--zabi-accent-400);
496
+ --color-accent-700: var(--zabi-accent-300);
497
+ --color-accent-800: var(--zabi-accent-200);
498
+ --color-accent-900: var(--zabi-accent-100);
499
+ --color-accent-950: var(--zabi-accent-50);
500
+ /* Pine Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
501
+ --color-pine-50: var(--zabi-pine-950);
502
+ --color-pine-100: var(--zabi-pine-900);
503
+ --color-pine-200: var(--zabi-pine-800);
504
+ --color-pine-300: var(--zabi-pine-700);
505
+ --color-pine-400: var(--zabi-pine-600);
506
+ --color-pine-500: var(--zabi-pine-500);
507
+ --color-pine-600: var(--zabi-pine-400);
508
+ --color-pine-700: var(--zabi-pine-300);
509
+ --color-pine-800: var(--zabi-pine-200);
510
+ --color-pine-900: var(--zabi-pine-100);
511
+ --color-pine-950: var(--zabi-pine-50);
512
+ /* Iris Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
513
+ --color-iris-50: var(--zabi-iris-950);
514
+ --color-iris-100: var(--zabi-iris-900);
515
+ --color-iris-200: var(--zabi-iris-800);
516
+ --color-iris-300: var(--zabi-iris-700);
517
+ --color-iris-400: var(--zabi-iris-600);
518
+ --color-iris-500: var(--zabi-iris-500);
519
+ --color-iris-600: var(--zabi-iris-400);
520
+ --color-iris-700: var(--zabi-iris-300);
521
+ --color-iris-800: var(--zabi-iris-200);
522
+ --color-iris-900: var(--zabi-iris-100);
523
+ --color-iris-950: var(--zabi-iris-50);
524
+ /* Warning Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
525
+ --color-warning-50: var(--zabi-warning-950);
526
+ --color-warning-100: var(--zabi-warning-900);
527
+ --color-warning-200: var(--zabi-warning-800);
528
+ --color-warning-300: var(--zabi-warning-700);
529
+ --color-warning-400: var(--zabi-warning-600);
530
+ --color-warning-500: var(--zabi-warning-500);
531
+ --color-warning-600: var(--zabi-warning-400);
532
+ --color-warning-700: var(--zabi-warning-300);
533
+ --color-warning-800: var(--zabi-warning-200);
534
+ --color-warning-900: var(--zabi-warning-100);
535
+ --color-warning-950: var(--zabi-warning-50);
536
+ /* Error Color Scale — semantic → physical mirror (1000 − step); 500 fixed point */
537
+ --color-error-50: var(--zabi-error-950);
538
+ --color-error-100: var(--zabi-error-900);
539
+ --color-error-200: var(--zabi-error-800);
540
+ --color-error-300: var(--zabi-error-700);
541
+ --color-error-400: var(--zabi-error-600);
542
+ --color-error-500: var(--zabi-error-500);
543
+ --color-error-600: var(--zabi-error-400);
544
+ --color-error-700: var(--zabi-error-300);
545
+ --color-error-800: var(--zabi-error-200);
546
+ --color-error-900: var(--zabi-error-100);
547
+ --color-error-950: var(--zabi-error-50);
548
+ /* Base Color Scale — semantic → physical mirror (1000 − step); 500 is fixed point */
549
+ --color-base-50: var(--zabi-base-950);
550
+ --color-base-75: var(--zabi-base-925);
551
+ --color-base-100: var(--zabi-base-900);
552
+ --color-base-150: var(--zabi-base-850);
553
+ --color-base-200: var(--zabi-base-800);
554
+ --color-base-250: var(--zabi-base-750);
555
+ --color-base-300: var(--zabi-base-700);
556
+ --color-base-350: var(--zabi-base-650);
557
+ --color-base-400: var(--zabi-base-600);
558
+ --color-base-450: var(--zabi-base-550);
559
+ --color-base-500: var(--zabi-base-500);
560
+ --color-base-550: var(--zabi-base-450);
561
+ --color-base-600: var(--zabi-base-400);
562
+ --color-base-650: var(--zabi-base-350);
563
+ --color-base-700: var(--zabi-base-300);
564
+ --color-base-750: var(--zabi-base-250);
565
+ --color-base-800: var(--zabi-base-200);
566
+ --color-base-850: var(--zabi-base-150);
567
+ --color-base-900: var(--zabi-base-100);
568
+ --color-base-925: var(--zabi-base-75);
569
+ --color-base-950: var(--zabi-base-50);
570
+ /* Background Colors - No dark mode overrides needed, base colors are already inverted */
571
+ /* Page Colors - No dark mode overrides needed, base colors are already inverted */
572
+ /* Surface elevation — shadows don't read on dark, so the surfaces carry it by tone, in two
573
+ * steps: page L 21.0, card L 24.1, elevated and overlay L 27.4 (D133/D134).
574
+ *
575
+ * GENERATED by scripts/generate-surfaces.js from tokens/surface-ladder.js — do not hand-edit.
576
+ * Every role is a plain step of the neutral ramp (--zabi-base-N), so hue and chroma are the
577
+ * ramp's own, and a --zabi-base-* override or a tinted neutral carries all of them. An overlay
578
+ * (sheet, menu, modal) is the same tone as elevated: it is told apart by its edge
579
+ * (--color-material-rim) and its shadow, not by being greyer. The hover on an overlay is one
580
+ * ramp step lighter; the inset is the page step, told apart by its 3:1 edge.
581
+ * With the default greys: #18181b / #1f1f22 / #27272a / #27272a, hover #333338, inset #18181b.
582
+ * Enforced by scripts/check-surface-elevation.js (ramp steps, never lighter downwards, at most
583
+ * two tone steps of 2–5 points, the overlay edge and the card edge). */
584
+ --color-surface-base: var(--zabi-base-900);
585
+ --color-surface-raised: var(--zabi-base-850);
586
+ --color-surface-elevated: var(--zabi-base-800);
587
+ --color-surface-overlay: var(--zabi-base-800);
588
+ --color-surface-overlay-hover: var(--zabi-base-750);
589
+ /* Inset — the page step, 3 points below the card (L 24.1). A field on the page is told apart
590
+ * by its 3:1 edge, as a white field on the near-white light page is. */
591
+ --color-surface-inset: var(--zabi-base-900);
592
+ /* Chrome and the bar tokens — restated so a light-only override of the page
593
+ * or the raised surface does not reach dark. */
594
+ --color-surface-chrome: var(--color-surface-base);
595
+ --color-bar: var(--color-surface-chrome);
596
+ --color-bar-border: color-mix(in srgb, var(--color-headline) 10%, transparent);
597
+ --color-bar-brand: var(--color-action-primary);
598
+ --color-tabbar-active: var(--color-nav-menu-active);
599
+ /* Distinct from base, raised AND elevated — a neutral chip has no hue to
600
+ * separate it, so it has to separate on lightness wherever it lands:
601
+ * base-300 is 1.70:1 on the page, 1.57:1 on the card, 1.43:1 on elevated. */
602
+ --color-neutral-subtle: var(--color-base-300);
603
+ --color-neutral-border: var(--color-base-200);
604
+ --color-border-overlay: var(--color-base-450);
605
+ /* Background Colors */
606
+ --color-background: var(--color-surface-base);
607
+ --color-background-tertiary: var(--color-base-100);
608
+ /* Page Colors — the dark page (base-100 here is --zabi-base-900, the same value as before) */
609
+ --color-page: var(--color-surface-base);
610
+ /* Card Colors — aliases of the surface levels */
611
+ --color-card: var(--color-surface-raised);
612
+ --color-card-hover: var(--color-surface-elevated);
613
+ --color-card-active: var(--color-surface-overlay-hover);
614
+ --color-card-elevated: var(--color-surface-elevated);
615
+ /* Card tint, dark: the brand at 8% over the card (as the status tints of D136,
616
+ * which are 16%: here the field edge sets the ceiling, base-500 is 3.07:1 on
617
+ * this and 2.90:1 at 12%). 8% is #252733: 1.11:1 on the card and 1.20:1 on the
618
+ * page; headline 13.49, body 11.68, label and description 10.03, caption 7.68,
619
+ * link 8.81, ring 6.59:1. */
620
+ --color-card-tint: color-mix(in srgb, var(--zabi-brand-500) 8%, var(--color-surface-raised));
621
+ /* Card variant="flat", dark: a translucent step of the neutral ramp (base-50 at 7%), so a flat card
622
+ * is lighter than whatever it sits on, and a flat card inside a flat card is lighter again. Shadows
623
+ * do not carry layers on a dark page; alpha does. Hover and pressed are the same step at 11% and 15%.
624
+ * Restore the opaque fill: overrides: { dark: { '--color-card-flat': 'var(--color-card)' } }. */
625
+ --color-card-flat: color-mix(in srgb, var(--zabi-base-50) 7%, transparent);
626
+ --color-card-flat-hover: color-mix(in srgb, var(--zabi-base-50) 11%, transparent);
627
+ --color-card-flat-active: color-mix(in srgb, var(--zabi-base-50) 15%, transparent);
628
+ /* Surfaces — numbered aliases of the surface levels */
629
+ --color-surface-1: var(--color-surface-raised);
630
+ --color-surface-2: var(--color-surface-elevated);
631
+ --color-surface-3: var(--color-surface-overlay);
632
+ --color-surface-4: var(--color-surface-overlay-hover);
633
+ /*
634
+ * Secondary text keeps ≥ 4.5:1 on every surface level, including overlays (L27).
635
+ * Caption takes base-650 and description base-700 to stay visibly stronger than it.
636
+ */
637
+ --color-description: var(--color-base-700);
638
+ --color-caption: var(--color-base-650);
639
+ /* Interaction fills — light tint on dark, mirroring the light-mode rule.
640
+ * Alpha keeps these one step away from every surface level, which a fixed
641
+ * ramp step cannot guarantee (base-100 in dark IS the page background). */
642
+ --color-surface-hover: rgba(250, 250, 250, 0.08);
643
+ --color-surface-active: rgba(250, 250, 250, 0.14);
644
+ /* Overlay Colors */
645
+ --color-overlay: rgba(0, 0, 0, 0.7);
646
+ /* Input Colors
647
+ * Dark fields are a translucent step of the neutral ramp (base-50 at 7%), the
648
+ * same idea as the flat card: a well one step LIGHTER than whatever it sits on,
649
+ * without a rule per surface. It was the page step (--color-surface-inset), so
650
+ * a dark form was told from the page by its 3:1 edge alone. 7% is 1.20:1 on
651
+ * the page (#28282b), 1.22:1 on a card (#2e2e31) and 1.23:1 on the overlay
652
+ * (#363639); hover 10% and pressed 15% (1.30:1 against the resting field on
653
+ * all three). The edge below stays 3:1 against the surface outside it.
654
+ * Restore the opaque field: overrides: { dark: {
655
+ * '--color-input': 'var(--color-surface-inset)', '--color-input-hover': 'var(--color-base-200)',
656
+ * '--color-input-focus': 'var(--color-base-150)',
657
+ * '--color-input-active': 'color-mix(in srgb, var(--zabi-base-50) 10%, var(--color-surface-inset))' } }. */
658
+ --color-input: color-mix(in srgb, var(--zabi-base-50) 7%, transparent);
659
+ /* What a field is inside a colour block (.on-brand, .on-accent, .on-fill): the translucent
660
+ * well would sit on the block's fill, which the theme's text is not set for, so the field
661
+ * takes these opaque steps there. */
662
+ --color-input-solid: var(--color-surface-inset);
663
+ --color-input-solid-hover: var(--color-base-200);
664
+ --color-input-solid-focus: var(--color-base-150);
665
+ --color-input-solid-active: color-mix(in srgb, var(--zabi-base-50) 10%, var(--color-surface-inset));
666
+ /* Restated here: the root value of a var() alias is resolved at :root. */
667
+ --color-progress-fill: var(--color-action-primary);
668
+ /* The field step is the page now, so the track takes its own: base-75
669
+ * (#101013), a well just below the page: 1.06:1 on the page, 1.14:1 on the
670
+ * card, 1.45:1 on the elevated surface. It was base-250 (#333338, 1.41:1 on
671
+ * the page). The fill is a mid step now (brand-600), and 3:1 on its rail
672
+ * needs a track this dark: 3.91:1 here with the default brand (2.59:1 on
673
+ * base-250, 2.94:1 for an amber brand on base-200). */
674
+ --color-progress-track: var(--color-base-75);
675
+ /* Restated: the root value of a var() alias is resolved at :root. The field
676
+ * edge, 3.67:1 on the page and 3.40:1 on the card. */
677
+ --color-progress-track-border: var(--color-input-border);
678
+ /* base-500 (the mirror's fixed point): 3.67:1 on the dark field and the page,
679
+ * 3.40:1 on the card, 3.08:1 on the elevated surface and the overlay.
680
+ * base-300 was 1.70, 1.57 and 1.43. */
681
+ --color-input-border: var(--color-base-500);
682
+ --color-input-border-hover: var(--color-input-border);
683
+ /* The decorative hairline (Card's default variant, list dividers). Quiet, like
684
+ * light's: base-250 is #333338, 1.41:1 on the page and 1.31:1 on the card
685
+ * (base-300 was 1.70 and 1.57, base-200 only 1.10 on the card). Restated: the
686
+ * root value of a var() alias is resolved at :root. -medium (2.29:1) and
687
+ * -strong (3.67:1) keep their order above it. */
688
+ --color-border: var(--color-base-250);
689
+ --color-border-weak: var(--color-base-250);
690
+ /* Toggle track, off. The thumb is the card (#1f1f22), so the track cannot
691
+ * be as dark as it. base-300 (#3f3f46) is 1.57:1 against the thumb, and the
692
+ * field edge gives the 3:1: 3.67:1 on the page, 3.40:1 on the card. */
693
+ --color-toggle-track: var(--color-base-300);
694
+ --color-toggle-track-hover: var(--color-base-350);
695
+ --color-toggle-track-active: var(--color-base-400);
696
+ --color-toggle-track-border: var(--color-input-border);
697
+ /* Toggle knob in dark: off, a light knob on the dark track (base-700, #d4d4d8:
698
+ * 7.07:1 resting, 5.23:1 pressed); on, as in light (the same 4.86:1 and up). */
699
+ --color-toggle-knob: var(--color-base-700);
700
+ --color-toggle-knob-checked: var(--color-action-primary-text);
701
+ /* Hover 10%: 1.10:1 above the resting well on the page, the card and the overlay, body 8.65:1
702
+ * or more and placeholder 4.68:1 or more on it. Was base-200. */
703
+ --color-input-hover: color-mix(in srgb, var(--zabi-base-50) 10%, transparent);
704
+ /* Pressed 15% of the light end of the ramp (unmirrored, --zabi-base-50): 1.30:1 against the
705
+ * resting well on the page (#3a3a3c), the card (#404042) and the overlay (#474749), 1.18:1
706
+ * past hover, body 7.34:1 or more, placeholder 4.54:1 on a card and 4.08:1 on the overlay,
707
+ * short of the border (2.35:1 or less). 14% is 1.254:1 on the default and under 1.25 on a tinted ramp. Was 10% into the page step (#2f2f31). */
708
+ --color-input-active: color-mix(in srgb, var(--zabi-base-50) 15%, transparent);
709
+ /* Focus is the resting well: the ring shows focus, and hover still reads on a focused field.
710
+ * Was base-150. */
711
+ --color-input-focus: color-mix(in srgb, var(--zabi-base-50) 7%, transparent);
712
+ /* The field is the page step now, so the disabled field goes one step below
713
+ * the page (base-75, #101013): 1.07:1 on the page, 1.16:1 on the card. */
714
+ --color-input-disabled: var(--color-base-75);
715
+ /* base-500 is the mirror's fixed point, the same grey as it was in light,
716
+ * and a dark field is a far lighter ground for it than a white one is dark:
717
+ * 3.40:1 at rest, 3.08:1 on hover, 2.60:1 pressed. base-600 mirrors to
718
+ * --zabi-base-400 (#a1a1aa): 6.41, 5.81 and 4.90. base-550 would be 4.74
719
+ * at rest but under 4.5 on hover. The value text is 2.0:1 stronger.
720
+ * The well is lighter now (a translucent step over the surface), and the
721
+ * pressed one over a card held base-400 to 4.04:1: so 40% of the next step
722
+ * toward the value (base-350, #babac1) is mixed in, #ababb3: 6.46, 5.89 and
723
+ * 4.98:1 at rest, hover and pressed on the page, 5.91, 5.37 and 4.54:1 on a
724
+ * card, 5.30, 4.82 and 4.08:1 on the overlay (pressed there is held to 4:1,
725
+ * see contrast-pairs.js), and 1.80:1 under the value (1.75 is the floor; 50%
726
+ * would be 1.75). Was base-600 (#a1a1aa). */
727
+ --color-input-placeholder: color-mix(in srgb, var(--zabi-base-350) 40%, var(--zabi-base-400));
728
+ /* Text Colors - No dark mode overrides needed, base colors are already inverted */
729
+ /* Border Colors - the decorative edges need no override, base colors are
730
+ * already inverted. The control boundary does: base-500 is the mirror's
731
+ * fixed point (#71717a in both themes), and the dark surfaces above the card
732
+ * are too light for it (2.49:1 on elevated, 1.98:1 on the overlay). base-600
733
+ * mirrors to --zabi-base-400 (#a1a1aa): 3.73:1 on the overlay, the lightest
734
+ * surface, and more on every level below it. base-550 is 2.76:1 there. */
735
+ --color-control-border: var(--color-base-600);
736
+ /* Segmented control thumb — restated: the aliases resolve at :root, so without
737
+ * these dark would keep the light card colour. The track is a light tint over
738
+ * the page or a card (#2c2c2f / #333335), which the overlay tone now sits
739
+ * below, so the thumb takes base-400 (#52525b): 1.80:1 over the page track,
740
+ * 1.63:1 over the card track, headline text 7.03:1. */
741
+ --color-segment-thumb: var(--color-base-400);
742
+ --color-segment-thumb-text: var(--color-headline);
743
+ --color-segment-thumb-border: var(--color-control-border);
744
+ /* Focus Colors — the same steps as light, through the mirror: brand-600 is
745
+ * --zabi-brand-400 here, which is also the dark primary fill, so on a
746
+ * primary button the ring is separated by its offset gap exactly as in light.
747
+ * Dark used to stay one step back, on brand-500, the mirror's fixed point.
748
+ * That is 5.4:1 on the dark page but only 2.91:1 on the overlay, the
749
+ * lightest surface (2.78:1 for an amber brand), and a ring in a modal or a
750
+ * menu needs 3:1 too. Restated rather than left to inherit, so an app's
751
+ * light-only override of --color-focus does not reach dark. */
752
+ --color-focus: var(--color-brand-600);
753
+ --color-focus-weak: var(--color-brand-700);
754
+ --color-focus-medium: var(--color-brand-800);
755
+ --color-focus-strong: var(--color-brand-900);
756
+ /* The muted ring, for the same reason as the control boundary above: one
757
+ * step lighter than the fixed point, 3.73:1 on the overlay. */
758
+ --color-focus-ring-muted: var(--color-base-600);
759
+ /* Primary Colors - No dark mode overrides needed, brand colors are already inverted */
760
+ /* Secondary Colors - No dark mode overrides needed, base colors are already inverted */
761
+ /* Tinted fills and edges — the hue thinned into the card surface, not the
762
+ * mirrored step 100 / 200 (physical 900 / 800: deep, saturated, the loudest
763
+ * area on a dark screen). A tint here is a low-chroma tint of the card, and
764
+ * the hue is carried by the icon and the text. The mid step (500) is where
765
+ * the ramp's chroma peaks and the mirror's fixed point. The base is the card
766
+ * surface, so a badge or alert on a card is never darker than the card, and
767
+ * an app's override of the card surface carries through. The edge is the
768
+ * same mix, stronger. */
769
+ --color-success-subtle: color-mix(in srgb, var(--zabi-pine-500) 16%, var(--color-surface-raised));
770
+ --color-success-border: color-mix(in srgb, var(--zabi-pine-500) 36%, var(--color-surface-raised));
771
+ --color-warning-subtle: color-mix(in srgb, var(--zabi-warning-500) 16%, var(--color-surface-raised));
772
+ --color-warning-border: color-mix(in srgb, var(--zabi-warning-500) 36%, var(--color-surface-raised));
773
+ --color-error-subtle: color-mix(in srgb, var(--zabi-error-500) 16%, var(--color-surface-raised));
774
+ --color-error-border: color-mix(in srgb, var(--zabi-error-500) 36%, var(--color-surface-raised));
775
+ --color-energetic-subtle: color-mix(in srgb, var(--zabi-citron-500) 16%, var(--color-surface-raised));
776
+ --color-energetic-border: color-mix(in srgb, var(--zabi-citron-500) 36%, var(--color-surface-raised));
777
+ --color-accent-subtle: color-mix(in srgb, var(--zabi-accent-500) 16%, var(--color-surface-raised));
778
+ --color-accent-border: color-mix(in srgb, var(--zabi-accent-500) 36%, var(--color-surface-raised));
779
+ /* Label on a solid accent fill: the dark end of the ramp on its light end. */
780
+ --color-on-accent: var(--zabi-on-accent-dark);
781
+ --color-info-subtle: color-mix(in srgb, var(--zabi-iris-500) 16%, var(--color-surface-raised));
782
+ --color-info-border: color-mix(in srgb, var(--zabi-iris-500) 36%, var(--color-surface-raised));
783
+ /* Neutral Colors — base-550 mirrors to L* 57, which is only 4.35:1 on a
784
+ * raised surface. One step lighter clears AA on every dark surface level. */
785
+ --color-neutral: var(--color-base-600);
786
+ /* Info Colors — no further overrides: @theme uses --color-iris-* (incl. --color-info-active); iris mirrors in .dark via --zabi-iris-* */
787
+ /* ========================================
788
+ ACTION COLORS - Dark Mode Overrides
789
+ ======================================== */
790
+ /* Primary Actions - the brand hue in dark too: the same physical steps as
791
+ * light (600 / 700 / 800), not the mirrored ones, which would be the pale
792
+ * 400 / 300 / 200. White on step 600 is 4.76 to 4.86:1 (every ramp is on one
793
+ * lightness curve); with the default brand the fill is 3.65:1 on the page,
794
+ * 3.39:1 on the card and 3.07:1 on the overlay (3:1 holds on all three, WCAG
795
+ * 1.4.11). Hover and pressed go darker, as in light.
796
+ * createTheme({ darkPrimary: 'mirror' }) writes the mirrored fills instead.
797
+ * 🎯 TO CHANGE bg-action-primary IN DARK MODE: override --color-action-primary under `dark`. */
798
+ --color-action-primary: var(--zabi-brand-600);
799
+ --color-action-primary-hover: var(--zabi-brand-700);
800
+ --color-action-primary-active: var(--zabi-brand-800);
801
+ /* "On brand" in dark: --zabi-on-brand-dark, which follows the light label (white). If an app
802
+ * moves the dark primary to a pale step, it sets the knob to a dark one.
803
+ * --color-action-primary-text is restated, as it always was here, so that an
804
+ * app's light-only override of it does not carry a different label onto the
805
+ * dark fill. */
806
+ --color-on-brand: var(--zabi-on-brand-dark);
807
+ --color-action-primary-text: var(--color-on-brand);
808
+ /* Pinned like the other tints: light moved these a step darker. */
809
+ --color-action-primary-subtle: var(--color-brand-100);
810
+ --color-action-primary-subtle-hover: var(--color-brand-200);
811
+ --color-action-primary-border: var(--color-brand-200);
812
+ /* Half a step past the dark hover fill, as in light. */
813
+ --color-action-primary-subtle-active: color-mix(in srgb, var(--color-brand-300) 50%, var(--color-brand-200));
814
+ /* Secondary Actions - light alpha tint instead of the light-mode dark tint */
815
+ --color-action-secondary: rgba(250, 250, 250, 0.09);
816
+ --color-action-secondary-hover: rgba(250, 250, 250, 0.15);
817
+ --color-action-secondary-active: rgba(250, 250, 250, 0.21);
818
+ /* Tonal Actions - the deep brand tint (brand-100 in dark is the deep end of
819
+ * the mirrored ramp) with a light brand label. Restated: the root values are
820
+ * var() aliases of roles that move in dark. Brand-800 is the light end of the
821
+ * mirrored ramp here: 9.48, 6.94 and 5.86:1 on the three fills. */
822
+ --color-action-tonal: var(--color-action-primary-subtle);
823
+ --color-action-tonal-hover: var(--color-action-primary-subtle-hover);
824
+ --color-action-tonal-active: color-mix(in srgb, var(--color-brand-300) 50%, var(--color-brand-200));
825
+ --color-action-tonal-text: var(--color-brand-800);
826
+ /* Chip, dark - its own steps, not the mirror of light. The ladder rises from
827
+ * the page (base-900, card base-850): rest base-750 is 1.41:1 on the page and
828
+ * 1.31:1 on the card, hover base-700 and pressed base-650 lighter again (1.70
829
+ * and 1.96 on the page). Headline is 11.43, 9.50 and 8.24:1 on the three.
830
+ * Restated, with the selected chip, because the root values are var() aliases. */
831
+ --color-chip: var(--zabi-base-750);
832
+ --color-chip-hover: var(--zabi-base-700);
833
+ --color-chip-active: var(--zabi-base-650);
834
+ --color-chip-text: var(--color-headline);
835
+ --color-chip-selected: var(--color-action-tonal);
836
+ --color-chip-selected-hover: var(--color-action-tonal-hover);
837
+ --color-chip-selected-active: var(--color-action-tonal-active);
838
+ --color-chip-selected-text: var(--color-action-tonal-text);
839
+ /* Outline Actions - the field edge, restated for the same reason. */
840
+ --color-action-outline-border: var(--color-input-border);
841
+ --color-action-outline-border-hover: var(--color-input-border-hover);
842
+ /* Disabled Actions - base-200 in dark is #27272a (the elevated tone), still
843
+ * the quietest fill, and the one the disabled label (base-500) reads on at 3.08:1.
844
+ * Pinned: light moved a step darker to stay visible on its darker page. */
845
+ --color-action-disabled: var(--color-base-200);
846
+ --color-action-disabled-border: var(--color-base-250);
847
+ /* Danger Actions — the same physical steps as light danger (600 / 700 / 800
848
+ * of --zabi-error-*) with the same label (step 50), so a destructive button
849
+ * is one red in both modes and shares the primary's veil. Physical, not
850
+ * through the mirror, which would be the pale 400 / 300 / 200. Restated
851
+ * because `zabi-components/theme-dark-only` has to stand alone as a complete
852
+ * import (validate-theme.js enforces that). The subtle tints are the thin mix below. */
853
+ --color-action-danger: var(--zabi-error-600);
854
+ --color-action-danger-hover: var(--zabi-error-700);
855
+ --color-action-danger-active: var(--zabi-error-800);
856
+ --color-action-danger-subtle: var(--color-error-subtle);
857
+ --color-action-danger-subtle-hover: color-mix(in srgb, var(--zabi-error-500) 20%, var(--color-surface-raised));
858
+ --color-action-danger-subtle-active: color-mix(in srgb, var(--zabi-error-500) 32%, var(--color-surface-raised));
859
+ --color-action-danger-text: var(--zabi-error-50);
860
+ /* Shadow Colors — black, not the light theme's ink tint. Much stronger than
861
+ * light (0.1 / 0.06): an overlay is the same tone as the elevated surface
862
+ * now, so a sheet (L 27.4) floats over a card (L 24.1) by its shadow and its
863
+ * edge, and the shadow has to carry it. */
864
+ --shadow-color: 0 0 0;
865
+ --shadow-opacity: 0.5;
866
+ --shadow-opacity-contact: 0.4;
867
+ --shadow-sm: 0 1px 2px 0 rgb(var(--shadow-color) / var(--shadow-opacity-contact)), 0 2px 6px -1px rgb(var(--shadow-color) / var(--shadow-opacity));
868
+ --shadow-md: 0 1px 3px 0 rgb(var(--shadow-color) / var(--shadow-opacity-contact)), 0 6px 14px -2px rgb(var(--shadow-color) / var(--shadow-opacity));
869
+ --shadow-lg: 0 1px 2px 0 rgb(var(--shadow-color) / var(--shadow-opacity-contact)), 0 10px 30px 0 rgb(var(--shadow-color) / var(--shadow-opacity));
870
+ --shadow-xl: 0 2px 4px 0 rgb(var(--shadow-color) / var(--shadow-opacity-contact)), 0 20px 50px -8px rgb(var(--shadow-color) / var(--shadow-opacity));
871
+ --shadow-material: 0 1px 2px 0 rgb(var(--shadow-color) / var(--shadow-opacity-contact)), 0 10px 30px 0 rgb(var(--shadow-color) / var(--shadow-opacity));
872
+ /* Materials — the alphas and the backdrop brightness differ (see @theme).
873
+ * The fills are not restated: they follow the surface tokens above. The
874
+ * filters are restated, because they hold a var() that resolves where it is
875
+ * declared; the fallbacks below are one class more specific than this rule
876
+ * and set them to none, so they still win in dark. */
877
+ --material-backdrop-brightness: 0.6;
878
+ --material-alpha-thin: 60%;
879
+ --material-alpha-regular: 68%;
880
+ --material-alpha-thick: 72%;
881
+ --material-filter-thin: blur(var(--material-blur-thin)) saturate(var(--material-saturate)) brightness(var(--material-backdrop-brightness));
882
+ --material-filter-regular: blur(var(--material-blur-regular)) saturate(var(--material-saturate)) brightness(var(--material-backdrop-brightness));
883
+ --material-filter-thick: blur(var(--material-blur-thick)) saturate(var(--material-saturate)) brightness(var(--material-backdrop-brightness));
884
+ --color-material-highlight: color-mix(in srgb, var(--zabi-base-50) 14%, transparent);
885
+ --color-material-rim: color-mix(in srgb, var(--zabi-base-50) 14%, transparent);
886
+ /* Gradients: the wash is quieter in dark (see @theme). The stops follow. */
887
+ --gradient-canvas-strength: 25%;
888
+ --gradient-control-top-strength: 0%;
889
+ --gradient-control-bottom-strength: 14%;
890
+ /* The accent's own strengths, no longer the shared ones: in dark its fill is
891
+ * the light step with a dark label, which a darkening veil would fail, so it
892
+ * keeps the lighter top and slight dark bottom it had (22 / 6). */
893
+ --gradient-control-accent-top-strength: 22%;
894
+ --gradient-control-accent-bottom-strength: 6%;
895
+ --shadow-control-highlight: inset 0 1px 0 color-mix(in srgb, var(--zabi-base-50) 25%, transparent);
896
+ /* Not a token: tells the browser the page is dark, so what it draws itself
897
+ * (date and time pickers, scrollbars, autofill, the caret of a native
898
+ * select) is dark too. It is the last declaration on purpose:
899
+ * scripts/sync-theme-tokens.js rewrites the ramp aliases at the top of this
900
+ * rule. The build publishes this rule under [data-theme="dark"] and, inside
901
+ * the dark media query, [data-theme="auto"], and every one of them carries
902
+ * it. Until 8.1 only the attributes set it and the class did not. */
903
+ color-scheme: dark;
904
+ }
905
+ }