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