@tenphi/tasty 0.0.0-snapshot.1c5dff6 → 0.0.0-snapshot.1f1c00a

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 (331) hide show
  1. package/README.md +377 -238
  2. package/dist/babel-rZcEwPLM.d.ts +82 -0
  3. package/dist/chunks/async-storage-CG5HnUT5.js +20 -0
  4. package/dist/chunks/async-storage-CG5HnUT5.js.map +1 -0
  5. package/dist/chunks/build-config-CL4eRu2z.js +42 -0
  6. package/dist/chunks/build-config-CL4eRu2z.js.map +1 -0
  7. package/dist/chunks/collector-D2ARGT2L.js +208 -0
  8. package/dist/chunks/collector-D2ARGT2L.js.map +1 -0
  9. package/dist/chunks/config-engine-DEmmPPdp.js +272 -0
  10. package/dist/chunks/config-engine-DEmmPPdp.js.map +1 -0
  11. package/dist/chunks/css-definitions-DotDkIXt.js +876 -0
  12. package/dist/chunks/css-definitions-DotDkIXt.js.map +1 -0
  13. package/dist/chunks/css-resources-P7IBUUZs.js +142 -0
  14. package/dist/chunks/css-resources-P7IBUUZs.js.map +1 -0
  15. package/dist/chunks/debug-D8pg9RGI.js +502 -0
  16. package/dist/chunks/debug-D8pg9RGI.js.map +1 -0
  17. package/dist/chunks/dsl-DRhFWQzo.js +1378 -0
  18. package/dist/chunks/dsl-DRhFWQzo.js.map +1 -0
  19. package/dist/chunks/hydration-TRcz5vnk.js +41 -0
  20. package/dist/chunks/hydration-TRcz5vnk.js.map +1 -0
  21. package/dist/chunks/react-runtime-BpxlOTbO.js +562 -0
  22. package/dist/chunks/react-runtime-BpxlOTbO.js.map +1 -0
  23. package/dist/chunks/runtime-engine-CKFXUH-A.js +2416 -0
  24. package/dist/chunks/runtime-engine-CKFXUH-A.js.map +1 -0
  25. package/dist/chunks/runtime-state-BxaLhVdP.js +127 -0
  26. package/dist/chunks/runtime-state-BxaLhVdP.js.map +1 -0
  27. package/dist/{utils/merge-styles.js → chunks/shared-utils-y-HjvPN4.js} +61 -58
  28. package/dist/chunks/shared-utils-y-HjvPN4.js.map +1 -0
  29. package/dist/chunks/style-engine-BBbBuSkT.js +5260 -0
  30. package/dist/chunks/style-engine-BBbBuSkT.js.map +1 -0
  31. package/dist/{zero/extractor.js → chunks/zero-engine-gJrKBRiw.js} +126 -66
  32. package/dist/chunks/zero-engine-gJrKBRiw.js.map +1 -0
  33. package/dist/collector-w4mBj5gd.d.ts +164 -0
  34. package/dist/config-CZWCzBr6.d.ts +1349 -0
  35. package/dist/core/index.d.ts +5 -33
  36. package/dist/core/index.js +9 -26
  37. package/dist/index-G9JuwM9p.d.ts +1920 -0
  38. package/dist/index.d.ts +5 -48
  39. package/dist/index.js +11 -33
  40. package/dist/{utils/merge-styles.d.ts → merge-styles-VXwJ0Frr.d.ts} +3 -4
  41. package/dist/ssr/astro-client.d.ts +1 -0
  42. package/dist/ssr/astro-client.js +6 -0
  43. package/dist/ssr/astro-client.js.map +1 -0
  44. package/dist/ssr/astro-middleware-extract-static.d.ts +10 -0
  45. package/dist/ssr/astro-middleware-extract-static.js +9 -0
  46. package/dist/ssr/astro-middleware-extract-static.js.map +1 -0
  47. package/dist/ssr/astro-middleware-extract.d.ts +10 -0
  48. package/dist/ssr/astro-middleware-extract.js +9 -0
  49. package/dist/ssr/astro-middleware-extract.js.map +1 -0
  50. package/dist/ssr/astro-middleware-static.d.ts +17 -0
  51. package/dist/ssr/astro-middleware-static.js +7 -0
  52. package/dist/ssr/astro-middleware-static.js.map +1 -0
  53. package/dist/ssr/astro-middleware.d.ts +18 -0
  54. package/dist/ssr/astro-middleware.js +7 -0
  55. package/dist/ssr/astro-middleware.js.map +1 -0
  56. package/dist/ssr/astro.d.ts +127 -0
  57. package/dist/ssr/astro.js +221 -0
  58. package/dist/ssr/astro.js.map +1 -0
  59. package/dist/ssr/index.d.ts +36 -0
  60. package/dist/ssr/index.js +10 -0
  61. package/dist/ssr/index.js.map +1 -0
  62. package/dist/ssr/next-config.d.ts +64 -0
  63. package/dist/ssr/next-config.js +128 -0
  64. package/dist/ssr/next-config.js.map +1 -0
  65. package/dist/ssr/next.d.ts +46 -0
  66. package/dist/ssr/next.js +60 -0
  67. package/dist/ssr/next.js.map +1 -0
  68. package/dist/static/index.d.ts +90 -5
  69. package/dist/static/index.js +31 -4
  70. package/dist/static/index.js.map +1 -0
  71. package/dist/static/inject.d.ts +4 -0
  72. package/dist/static/inject.js +17 -0
  73. package/dist/static/inject.js.map +1 -0
  74. package/dist/types-JEY8PVYP.d.ts +1567 -0
  75. package/dist/zero/babel.d.ts +2 -113
  76. package/dist/zero/babel.js +230 -106
  77. package/dist/zero/babel.js.map +1 -1
  78. package/dist/zero/index.d.ts +80 -3
  79. package/dist/zero/index.js +2 -4
  80. package/dist/zero/next.d.ts +57 -33
  81. package/dist/zero/next.js +93 -59
  82. package/dist/zero/next.js.map +1 -1
  83. package/docs/README.md +39 -0
  84. package/docs/adoption.md +323 -0
  85. package/docs/ai-agents.md +250 -0
  86. package/docs/comparison.md +448 -0
  87. package/docs/configuration.md +684 -56
  88. package/docs/debug.md +170 -343
  89. package/docs/design-system.md +455 -0
  90. package/docs/dsl.md +1065 -0
  91. package/docs/getting-started.md +240 -0
  92. package/docs/injector.md +159 -53
  93. package/docs/methodology.md +648 -0
  94. package/docs/migration-v3.md +285 -0
  95. package/docs/pipeline.md +765 -0
  96. package/docs/plugins.md +353 -0
  97. package/docs/react-api.md +683 -0
  98. package/docs/runtime-benchmarks.md +388 -0
  99. package/docs/ssr.md +610 -0
  100. package/docs/styles.md +211 -63
  101. package/docs/tasty-static.md +273 -67
  102. package/package.json +182 -58
  103. package/tasty.config.ts +6 -0
  104. package/dist/_virtual/_rolldown/runtime.js +0 -8
  105. package/dist/chunks/cacheKey.js +0 -70
  106. package/dist/chunks/cacheKey.js.map +0 -1
  107. package/dist/chunks/definitions.d.ts +0 -37
  108. package/dist/chunks/definitions.js +0 -260
  109. package/dist/chunks/definitions.js.map +0 -1
  110. package/dist/chunks/renderChunk.js +0 -61
  111. package/dist/chunks/renderChunk.js.map +0 -1
  112. package/dist/config.d.ts +0 -288
  113. package/dist/config.js +0 -403
  114. package/dist/config.js.map +0 -1
  115. package/dist/debug.d.ts +0 -204
  116. package/dist/debug.js +0 -733
  117. package/dist/debug.js.map +0 -1
  118. package/dist/hooks/useGlobalStyles.d.ts +0 -27
  119. package/dist/hooks/useGlobalStyles.js +0 -56
  120. package/dist/hooks/useGlobalStyles.js.map +0 -1
  121. package/dist/hooks/useKeyframes.d.ts +0 -56
  122. package/dist/hooks/useKeyframes.js +0 -54
  123. package/dist/hooks/useKeyframes.js.map +0 -1
  124. package/dist/hooks/useProperty.d.ts +0 -79
  125. package/dist/hooks/useProperty.js +0 -91
  126. package/dist/hooks/useProperty.js.map +0 -1
  127. package/dist/hooks/useRawCSS.d.ts +0 -53
  128. package/dist/hooks/useRawCSS.js +0 -28
  129. package/dist/hooks/useRawCSS.js.map +0 -1
  130. package/dist/hooks/useStyles.d.ts +0 -40
  131. package/dist/hooks/useStyles.js +0 -169
  132. package/dist/hooks/useStyles.js.map +0 -1
  133. package/dist/injector/index.d.ts +0 -157
  134. package/dist/injector/index.js +0 -154
  135. package/dist/injector/index.js.map +0 -1
  136. package/dist/injector/injector.d.ts +0 -139
  137. package/dist/injector/injector.js +0 -417
  138. package/dist/injector/injector.js.map +0 -1
  139. package/dist/injector/sheet-manager.d.ts +0 -135
  140. package/dist/injector/sheet-manager.js +0 -728
  141. package/dist/injector/sheet-manager.js.map +0 -1
  142. package/dist/injector/types.d.ts +0 -144
  143. package/dist/keyframes/index.js +0 -206
  144. package/dist/keyframes/index.js.map +0 -1
  145. package/dist/parser/classify.js +0 -319
  146. package/dist/parser/classify.js.map +0 -1
  147. package/dist/parser/const.js +0 -33
  148. package/dist/parser/const.js.map +0 -1
  149. package/dist/parser/lru.js +0 -109
  150. package/dist/parser/lru.js.map +0 -1
  151. package/dist/parser/parser.d.ts +0 -25
  152. package/dist/parser/parser.js +0 -116
  153. package/dist/parser/parser.js.map +0 -1
  154. package/dist/parser/tokenizer.js +0 -69
  155. package/dist/parser/tokenizer.js.map +0 -1
  156. package/dist/parser/types.d.ts +0 -51
  157. package/dist/parser/types.js +0 -46
  158. package/dist/parser/types.js.map +0 -1
  159. package/dist/pipeline/conditions.d.ts +0 -134
  160. package/dist/pipeline/conditions.js +0 -406
  161. package/dist/pipeline/conditions.js.map +0 -1
  162. package/dist/pipeline/exclusive.js +0 -231
  163. package/dist/pipeline/exclusive.js.map +0 -1
  164. package/dist/pipeline/index.d.ts +0 -53
  165. package/dist/pipeline/index.js +0 -660
  166. package/dist/pipeline/index.js.map +0 -1
  167. package/dist/pipeline/materialize.js +0 -856
  168. package/dist/pipeline/materialize.js.map +0 -1
  169. package/dist/pipeline/parseStateKey.d.ts +0 -15
  170. package/dist/pipeline/parseStateKey.js +0 -451
  171. package/dist/pipeline/parseStateKey.js.map +0 -1
  172. package/dist/pipeline/simplify.js +0 -516
  173. package/dist/pipeline/simplify.js.map +0 -1
  174. package/dist/pipeline/warnings.js +0 -18
  175. package/dist/pipeline/warnings.js.map +0 -1
  176. package/dist/plugins/okhsl-plugin.d.ts +0 -35
  177. package/dist/plugins/okhsl-plugin.js +0 -371
  178. package/dist/plugins/okhsl-plugin.js.map +0 -1
  179. package/dist/plugins/types.d.ts +0 -69
  180. package/dist/properties/index.js +0 -221
  181. package/dist/properties/index.js.map +0 -1
  182. package/dist/properties/property-type-resolver.d.ts +0 -24
  183. package/dist/properties/property-type-resolver.js +0 -83
  184. package/dist/properties/property-type-resolver.js.map +0 -1
  185. package/dist/states/index.d.ts +0 -49
  186. package/dist/states/index.js +0 -416
  187. package/dist/states/index.js.map +0 -1
  188. package/dist/static/tastyStatic.d.ts +0 -46
  189. package/dist/static/tastyStatic.js +0 -31
  190. package/dist/static/tastyStatic.js.map +0 -1
  191. package/dist/static/types.d.ts +0 -49
  192. package/dist/static/types.js +0 -24
  193. package/dist/static/types.js.map +0 -1
  194. package/dist/styles/align.d.ts +0 -15
  195. package/dist/styles/align.js +0 -14
  196. package/dist/styles/align.js.map +0 -1
  197. package/dist/styles/border.d.ts +0 -25
  198. package/dist/styles/border.js +0 -114
  199. package/dist/styles/border.js.map +0 -1
  200. package/dist/styles/color.d.ts +0 -14
  201. package/dist/styles/color.js +0 -23
  202. package/dist/styles/color.js.map +0 -1
  203. package/dist/styles/createStyle.js +0 -77
  204. package/dist/styles/createStyle.js.map +0 -1
  205. package/dist/styles/dimension.js +0 -97
  206. package/dist/styles/dimension.js.map +0 -1
  207. package/dist/styles/display.d.ts +0 -37
  208. package/dist/styles/display.js +0 -67
  209. package/dist/styles/display.js.map +0 -1
  210. package/dist/styles/fade.d.ts +0 -15
  211. package/dist/styles/fade.js +0 -58
  212. package/dist/styles/fade.js.map +0 -1
  213. package/dist/styles/fill.d.ts +0 -42
  214. package/dist/styles/fill.js +0 -52
  215. package/dist/styles/fill.js.map +0 -1
  216. package/dist/styles/flow.d.ts +0 -16
  217. package/dist/styles/flow.js +0 -12
  218. package/dist/styles/flow.js.map +0 -1
  219. package/dist/styles/gap.d.ts +0 -31
  220. package/dist/styles/gap.js +0 -37
  221. package/dist/styles/gap.js.map +0 -1
  222. package/dist/styles/height.d.ts +0 -17
  223. package/dist/styles/height.js +0 -20
  224. package/dist/styles/height.js.map +0 -1
  225. package/dist/styles/index.d.ts +0 -2
  226. package/dist/styles/index.js +0 -9
  227. package/dist/styles/index.js.map +0 -1
  228. package/dist/styles/inset.d.ts +0 -52
  229. package/dist/styles/inset.js +0 -150
  230. package/dist/styles/inset.js.map +0 -1
  231. package/dist/styles/justify.d.ts +0 -15
  232. package/dist/styles/justify.js +0 -14
  233. package/dist/styles/justify.js.map +0 -1
  234. package/dist/styles/list.d.ts +0 -16
  235. package/dist/styles/list.js +0 -98
  236. package/dist/styles/list.js.map +0 -1
  237. package/dist/styles/margin.d.ts +0 -24
  238. package/dist/styles/margin.js +0 -104
  239. package/dist/styles/margin.js.map +0 -1
  240. package/dist/styles/outline.d.ts +0 -29
  241. package/dist/styles/outline.js +0 -65
  242. package/dist/styles/outline.js.map +0 -1
  243. package/dist/styles/padding.d.ts +0 -24
  244. package/dist/styles/padding.js +0 -104
  245. package/dist/styles/padding.js.map +0 -1
  246. package/dist/styles/predefined.d.ts +0 -73
  247. package/dist/styles/predefined.js +0 -241
  248. package/dist/styles/predefined.js.map +0 -1
  249. package/dist/styles/preset.d.ts +0 -47
  250. package/dist/styles/preset.js +0 -126
  251. package/dist/styles/preset.js.map +0 -1
  252. package/dist/styles/radius.d.ts +0 -14
  253. package/dist/styles/radius.js +0 -51
  254. package/dist/styles/radius.js.map +0 -1
  255. package/dist/styles/scrollbar.d.ts +0 -23
  256. package/dist/styles/scrollbar.js +0 -34
  257. package/dist/styles/scrollbar.js.map +0 -1
  258. package/dist/styles/shadow.d.ts +0 -14
  259. package/dist/styles/shadow.js +0 -24
  260. package/dist/styles/shadow.js.map +0 -1
  261. package/dist/styles/styledScrollbar.d.ts +0 -47
  262. package/dist/styles/styledScrollbar.js +0 -38
  263. package/dist/styles/styledScrollbar.js.map +0 -1
  264. package/dist/styles/transition.d.ts +0 -14
  265. package/dist/styles/transition.js +0 -158
  266. package/dist/styles/transition.js.map +0 -1
  267. package/dist/styles/types.d.ts +0 -498
  268. package/dist/styles/width.d.ts +0 -17
  269. package/dist/styles/width.js +0 -20
  270. package/dist/styles/width.js.map +0 -1
  271. package/dist/tasty.d.ts +0 -982
  272. package/dist/tasty.js +0 -206
  273. package/dist/tasty.js.map +0 -1
  274. package/dist/tokens/typography.d.ts +0 -19
  275. package/dist/tokens/typography.js +0 -237
  276. package/dist/tokens/typography.js.map +0 -1
  277. package/dist/types.d.ts +0 -184
  278. package/dist/utils/cache-wrapper.js +0 -26
  279. package/dist/utils/cache-wrapper.js.map +0 -1
  280. package/dist/utils/case-converter.js +0 -8
  281. package/dist/utils/case-converter.js.map +0 -1
  282. package/dist/utils/colors.d.ts +0 -5
  283. package/dist/utils/colors.js +0 -9
  284. package/dist/utils/colors.js.map +0 -1
  285. package/dist/utils/css-types.d.ts +0 -7
  286. package/dist/utils/dotize.d.ts +0 -26
  287. package/dist/utils/dotize.js +0 -122
  288. package/dist/utils/dotize.js.map +0 -1
  289. package/dist/utils/filter-base-props.d.ts +0 -15
  290. package/dist/utils/filter-base-props.js +0 -45
  291. package/dist/utils/filter-base-props.js.map +0 -1
  292. package/dist/utils/get-display-name.d.ts +0 -7
  293. package/dist/utils/get-display-name.js +0 -10
  294. package/dist/utils/get-display-name.js.map +0 -1
  295. package/dist/utils/hsl-to-rgb.js +0 -38
  296. package/dist/utils/hsl-to-rgb.js.map +0 -1
  297. package/dist/utils/is-dev-env.js +0 -19
  298. package/dist/utils/is-dev-env.js.map +0 -1
  299. package/dist/utils/is-valid-element-type.js +0 -15
  300. package/dist/utils/is-valid-element-type.js.map +0 -1
  301. package/dist/utils/merge-styles.js.map +0 -1
  302. package/dist/utils/mod-attrs.d.ts +0 -8
  303. package/dist/utils/mod-attrs.js +0 -21
  304. package/dist/utils/mod-attrs.js.map +0 -1
  305. package/dist/utils/okhsl-to-rgb.js +0 -296
  306. package/dist/utils/okhsl-to-rgb.js.map +0 -1
  307. package/dist/utils/process-tokens.d.ts +0 -31
  308. package/dist/utils/process-tokens.js +0 -171
  309. package/dist/utils/process-tokens.js.map +0 -1
  310. package/dist/utils/resolve-recipes.d.ts +0 -17
  311. package/dist/utils/resolve-recipes.js +0 -147
  312. package/dist/utils/resolve-recipes.js.map +0 -1
  313. package/dist/utils/selector-transform.js +0 -32
  314. package/dist/utils/selector-transform.js.map +0 -1
  315. package/dist/utils/string.js +0 -8
  316. package/dist/utils/string.js.map +0 -1
  317. package/dist/utils/styles.d.ts +0 -177
  318. package/dist/utils/styles.js +0 -730
  319. package/dist/utils/styles.js.map +0 -1
  320. package/dist/utils/typography.d.ts +0 -36
  321. package/dist/utils/typography.js +0 -53
  322. package/dist/utils/typography.js.map +0 -1
  323. package/dist/utils/warnings.d.ts +0 -16
  324. package/dist/utils/warnings.js +0 -16
  325. package/dist/utils/warnings.js.map +0 -1
  326. package/dist/zero/css-writer.d.ts +0 -45
  327. package/dist/zero/css-writer.js +0 -74
  328. package/dist/zero/css-writer.js.map +0 -1
  329. package/dist/zero/extractor.d.ts +0 -24
  330. package/dist/zero/extractor.js.map +0 -1
  331. package/docs/usage.md +0 -695
package/docs/styles.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Style Properties Reference
2
2
 
3
- All standard CSS properties are supported in Tasty and benefit from its syntax sugar: design tokens (`$name`, `#name`), custom units (`2x`, `1r`, `1bw`), color opacity (`#purple.5`), auto-calc (`(100% - 2x)`), and custom functions. Values are parsed through the Tasty engine automatically.
3
+ All standard CSS properties are supported in Tasty and benefit from its syntax sugar: design tokens (`$name`, `#name`), custom units (`2x`, `1r`, `1bw`), color opacity (`#purple.5`), auto-calc (`(100% - 2x)`), and [custom functions](dsl.md#functions-function) (`$$negative(10px)`). Values are parsed through the Tasty engine automatically.
4
4
 
5
5
  The properties documented below have **custom handlers** with enhanced syntax. They should be **preferred** over their raw CSS equivalents because they:
6
6
 
@@ -20,9 +20,10 @@ Use these instead of their raw CSS counterparts:
20
20
  |-----|------------|
21
21
  | `fill` | `backgroundColor`, `background` |
22
22
  | `image` | `backgroundImage` |
23
- | `padding` (with direction modifiers) | `paddingTop`, `paddingRight`, `paddingBottom`, `paddingLeft` |
24
- | `margin` (with direction modifiers) | `marginTop`, `marginRight`, `marginBottom`, `marginLeft` |
25
- | `width` (with `min`/`max` modifiers) | `minWidth`, `maxWidth` |
23
+ | `padding` (with physical direction modifiers) | `paddingTop`, `paddingRight`, `paddingBottom`, `paddingLeft` |
24
+ | `margin` (with physical direction modifiers) | `marginTop`, `marginRight`, `marginBottom`, `marginLeft` |
25
+ | Logical block/inline category styles (with `start`/`end` modifiers) | Native logical axis/edge declarations |
26
+ | `width` / `blockSize` / `inlineSize` (with `min`/`max` modifiers) | Their separate min/max declarations when one state map is sufficient |
26
27
  | `height` (with `min`/`max` modifiers) | `minHeight`, `maxHeight` |
27
28
  | `border` | `borderColor`, `borderWidth`, `borderStyle` |
28
29
  | `radius` | `borderRadius` |
@@ -36,6 +37,24 @@ Use these instead of their raw CSS counterparts:
36
37
 
37
38
  ## Layout
38
39
 
40
+ ### `overscrollBehavior`
41
+
42
+ The native `overscrollBehavior` shorthand and its `overscrollBehaviorBlock`,
43
+ `overscrollBehaviorInline`, `overscrollBehaviorX`, and `overscrollBehaviorY`
44
+ longhands support `auto`, `contain`, `none`, and `chain`. The shorthand can set
45
+ separate X and Y values, for example `overscrollBehavior: 'chain contain'`.
46
+
47
+ `chain` allows scroll chaining to another scrollable area while suppressing
48
+ boundary effects such as bounce. It requires browser support; use a feature
49
+ query and a fallback floor when targeting browsers without it:
50
+
51
+ ```jsx
52
+ overscrollBehaviorBlock: {
53
+ _: 'auto',
54
+ '@supports(overscroll-behavior-block: chain)': 'chain',
55
+ }
56
+ ```
57
+
39
58
  ### `display`
40
59
 
41
60
  Standard CSS display values. Handled together with `hide`, `textOverflow`, `overflow`, and `whiteSpace` for priority resolution.
@@ -100,83 +119,94 @@ For flex/grid layouts, outputs native `gap`. For block layouts, emulates gap usi
100
119
 
101
120
  Element padding with directional modifiers and multi-group support. Use **comma-separated groups** to set a base value and then override specific directions.
102
121
 
103
- **Syntax:** `[value]` | `[top right]` | `[top right bottom left]` | `[value directions...]` — comma-separated for multiple groups
122
+ **Syntax:** `[value]` | `[block inline]` | `[top right bottom left]` | `[value direction...]` — comma-separated for multiple groups
104
123
 
105
124
  **Direction modifiers:** `top`, `right`, `bottom`, `left`
106
125
 
126
+ **Output modifier:** `longhand` — forces output as individual CSS longhand properties (`padding-top`, `padding-right`, `padding-bottom`, `padding-left`) instead of the `padding` shorthand. Useful when children need to selectively inherit individual directions.
127
+
128
+ **One value per directional group.** A group that names direction modifiers takes **exactly one** value, applied to every direction it names. For different values per side, use comma-separated groups: `padding: '2x top, 4x right'`. Writing `padding: '2x 4x top right'` ignores `4x` and warns in development — the parser keeps values and modifiers in separate buckets, so their interleaving in the source is not recoverable and `'2x 4x top right'`, `'2x top 4x right'` and `'top 2x right 4x'` are all the same input.
129
+
130
+ A group that names *no* direction keeps plain CSS shorthand order, which is unambiguous and unchanged.
131
+
107
132
  | Value | Effect |
108
133
  |-------|--------|
109
134
  | `"2x"` | All sides `2x` |
110
135
  | `"2x 1x"` | Top/bottom `2x`, left/right `1x` |
111
136
  | `"2x top"` | Top `2x`, right/bottom/left `0` |
112
137
  | `"1x left right"` | Left and right `1x`, top/bottom `0` |
138
+ | `"2x top, 4x right"` | Top `2x`, right `4x`, bottom/left `0` |
113
139
  | `"1x, 2x top"` | All sides `1x`, then top overridden to `2x` |
114
140
  | `"1x, 2x top bottom"` | Left/right `1x`, top/bottom `2x` |
141
+ | `"2x longhand"` | All sides `2x`, output as 4 individual `padding-*` properties |
115
142
  | `true` | All sides `1x` |
116
143
  | Number | Converted to `px` |
117
144
 
118
145
  Later comma-separated groups override earlier groups for conflicting directions.
119
146
 
120
- Individual props `paddingTop`, `paddingRight`, `paddingBottom`, `paddingLeft`, `paddingBlock`, `paddingInline` are supported but `padding` with modifiers is recommended.
121
-
122
- **Priority:** `padding` < `paddingBlock`/`paddingInline` < `paddingTop`/`paddingRight`/`paddingBottom`/`paddingLeft`
147
+ Individual physical props `paddingTop`, `paddingRight`, `paddingBottom`, and `paddingLeft` are supported, but `padding` with modifiers is recommended. Use `blockPadding` or `inlinePadding` for an enhanced logical-axis shorthand; native declarations such as `paddingInlineStart` remain ordinary CSS properties. See [Logical properties](#logical-properties).
123
148
 
124
149
  ### `margin`
125
150
 
126
151
  Element margin. Same syntax, modifiers, and multi-group support as `padding`.
127
152
 
128
- **Syntax:** `[value]` | `[top right]` | `[top right bottom left]` | `[value directions...]` — comma-separated for multiple groups
153
+ **Syntax:** `[value]` | `[block inline]` | `[top right bottom left]` | `[value direction...]` — comma-separated for multiple groups
129
154
 
130
155
  **Direction modifiers:** `top`, `right`, `bottom`, `left`
131
156
 
157
+ **Output modifier:** `longhand` — forces output as individual CSS longhand properties (`margin-top`, etc.) instead of the `margin` shorthand.
158
+
159
+ The [one-value-per-directional-group rule](#padding) from `padding` applies here too.
160
+
132
161
  | Value | Effect |
133
162
  |-------|--------|
134
163
  | `"2x"` | All sides `2x` |
135
164
  | `"2x 1x"` | Top/bottom `2x`, left/right `1x` |
136
165
  | `"2x top"` | Top `2x`, right/bottom/left `0` |
166
+ | `"2x top, 4x right"` | Top `2x`, right `4x`, bottom/left `0` |
137
167
  | `"auto left right, 1x top bottom"` | Left/right `auto`, top/bottom `1x` |
138
168
  | `true` | All sides `1x` |
139
169
  | Number | Converted to `px` |
140
170
 
141
171
  Later comma-separated groups override earlier groups for conflicting directions.
142
172
 
143
- Individual props `marginTop`, `marginRight`, `marginBottom`, `marginLeft`, `marginBlock`, `marginInline` are supported but `margin` with modifiers is recommended.
144
-
145
- **Priority:** `margin` < `marginBlock`/`marginInline` < `marginTop`/`marginRight`/`marginBottom`/`marginLeft`
173
+ Individual physical props `marginTop`, `marginRight`, `marginBottom`, and `marginLeft` are supported, but `margin` with modifiers is recommended. Use `blockMargin` or `inlineMargin` for an enhanced logical-axis shorthand; native declarations such as `marginInlineStart` remain ordinary CSS properties. See [Logical properties](#logical-properties).
146
174
 
147
175
  ### `width`
148
176
 
149
- Element width with min/max control.
177
+ Element width with min/max control. One, two, or three values set `min-width`, `width`, and `max-width` together.
150
178
 
151
- **Syntax:** `[value]` | `[min max]` | `[min value max]` | `[modifier value]`
179
+ **Positional syntax:**
152
180
 
153
- **Modifiers:** `min`, `max`, `fixed`
181
+ | Value | min-width | width | max-width |
182
+ |-------|-----------|-------|-----------|
183
+ | `"10x"` | initial | `10x` | initial |
184
+ | `"1x 10x"` | `1x` | auto | `10x` |
185
+ | `"1x 5x 10x"` | `1x` | `5x` | `10x` |
186
+ | `"0 100% 800px"` | `0` | `100%` | `800px` |
187
+ | `"initial 100% 1400px"` | initial | `100%` | `1400px` |
188
+
189
+ **Modifier syntax:**
190
+
191
+ | Value | min-width | width | max-width |
192
+ |-------|-----------|-------|-----------|
193
+ | `"min 2x"` | `2x` | auto | initial |
194
+ | `"max 100%"` | initial | auto | `100%` |
195
+ | `"fixed 200px"` | `200px` | `200px` | `200px` |
154
196
 
155
197
  **Keywords:** `stretch`, `max-content`, `min-content`, `fit-content`
156
198
 
157
199
  | Value | Effect |
158
200
  |-------|--------|
159
- | `"10x"` | Width `10x`, min `initial`, max `initial` |
160
- | `"1x 10x"` | Width `auto`, min `1x`, max `10x` |
161
- | `"1x 5x 10x"` | Min `1x`, width `5x`, max `10x` |
162
- | `"min 2x"` | Min-width `2x`, width `auto`, max `initial` |
163
- | `"max 100%"` | Max-width `100%`, width `auto`, min `initial` |
164
- | `"fixed 200px"` | Min, width, and max all set to `200px` |
165
201
  | `"stretch"` | Fill available space (cross-browser) |
166
- | `true` | Width `auto`, min `initial`, max `initial` |
202
+ | `true` | Reset to `auto` / `initial` / `initial` |
167
203
  | Number | Converted to `px` |
168
204
 
169
205
  Separate `minWidth` and `maxWidth` props are supported and override values from the `width` syntax.
170
206
 
171
207
  ### `height`
172
208
 
173
- Element height. Same syntax and modifiers as `width`.
174
-
175
- **Syntax:** `[value]` | `[min max]` | `[min value max]` | `[modifier value]`
176
-
177
- **Modifiers:** `min`, `max`, `fixed`
178
-
179
- **Keywords:** `max-content`, `min-content`, `fit-content`
209
+ Element height. Same syntax, modifiers, and positional patterns as `width`.
180
210
 
181
211
  Separate `minHeight` and `maxHeight` props are supported and override values from the `height` syntax.
182
212
 
@@ -184,23 +214,79 @@ Separate `minHeight` and `maxHeight` props are supported and override values fro
184
214
 
185
215
  Positioning offsets with directional modifiers and multi-group support. Same directional syntax as `padding`.
186
216
 
187
- **Syntax:** `[value]` | `[top right]` | `[top right bottom left]` | `[value directions...]` — comma-separated for multiple groups
217
+ **Syntax:** `[value]` | `[block inline]` | `[top right bottom left]` | `[value direction...]` — comma-separated for multiple groups
188
218
 
189
219
  **Direction modifiers:** `top`, `right`, `bottom`, `left`
190
220
 
221
+ The [one-value-per-directional-group rule](#padding) from `padding` applies here too, with `dock`
222
+ as the single exception.
223
+
224
+ **`dock` modifier:** pins the named edge and spans its full length, by also applying the value
225
+ to the two perpendicular sides. `inset: 'bottom dock'` gives `inset: auto 0 0 0` — anchored to
226
+ the bottom, full width. Without a direction, `dock` fills every side.
227
+
228
+ `dock` is the one place a directional group takes **two** values: the first insets the named
229
+ edge, the second the sides it spans. `inset: '2x 4x bottom dock'` pins the bottom at `2x` and
230
+ insets the sides by `4x`. A third value, or a second value without `dock`, is ignored and warns
231
+ in development. With several directions the first value applies to each named edge and the
232
+ second to every side they span.
233
+
234
+ **Output modifier:** `longhand` — forces output as individual CSS properties (`top`, `right`, `bottom`, `left`) instead of the `inset` shorthand.
235
+
191
236
  | Value | Effect |
192
237
  |-------|--------|
193
238
  | `"0"` | All sides `0` |
194
239
  | `"2x top"` | Top `2x`, right/bottom/left `auto` |
195
240
  | `"1x left right"` | Left and right `1x`, top/bottom `auto` |
196
241
  | `"0, 2x top"` | All sides `0`, then top overridden to `2x` |
242
+ | `"0 longhand"` | All sides `0`, output as individual `top`/`right`/`bottom`/`left` |
197
243
  | `true` | All sides `0` |
244
+ | `"bottom dock"` | Bottom/left/right `0`, top `auto` — bottom-anchored, full width |
245
+ | `"right dock"` | Right/top/bottom `0`, left `auto` — right-anchored, full height |
246
+ | `"2x bottom dock"` | Bottom/left/right `2x`, top `auto` |
247
+ | `"2x 4x bottom dock"` | Bottom `2x`, left/right `4x`, top `auto` |
248
+ | `"dock"` | All sides `0` |
198
249
 
199
250
  Later comma-separated groups override earlier groups for conflicting directions.
200
251
 
201
- Individual props `top`, `right`, `bottom`, `left`, `insetBlock`, `insetInline` are supported. When only individual direction props are used (without `inset`), individual CSS properties are output for correct cascade behavior with state overrides.
252
+ Individual physical props `top`, `right`, `bottom`, and `left` are supported. When only those props are used (without `inset`), individual CSS properties are output for correct cascade behavior with state overrides. Use `blockInset` or `inlineInset` for logical axes; native declarations such as `insetInlineStart` remain ordinary CSS properties.
253
+
254
+ ### Logical properties
202
255
 
203
- **Priority:** `inset` < `insetBlock`/`insetInline` < `top`/`right`/`bottom`/`left`
256
+ Tasty provides one enhanced handler for each logical axis/category pair. Each handler emits native logical CSS instead of converting values to `top`, `right`, `bottom`, `left`, `width`, or `height`. The browser therefore resolves `block`, `inline`, `start`, and `end` from the element's `writingMode` and `direction`.
257
+
258
+ ```jsx
259
+ styles: {
260
+ direction: 'rtl',
261
+ inlinePadding: '1x start, 2x end',
262
+ inlineBorder: '1bw solid #accent start',
263
+ blockInset: '0 end',
264
+ }
265
+ ```
266
+
267
+ An axis handler accepts one value for both edges or two values in logical **start/end** order. Use `start` and `end` modifiers, with comma-separated groups for different edge values. Unspecified padding, margin, and scroll edges reset to `0`; unspecified inset edges reset to `auto`. The `longhand` modifier emits the two native start/end declarations.
268
+
269
+ | Category | Block axis | Inline axis |
270
+ |----------|------------|-------------|
271
+ | Size | `blockSize` | `inlineSize` |
272
+ | Padding | `blockPadding` | `inlinePadding` |
273
+ | Margin | `blockMargin` | `inlineMargin` |
274
+ | Inset | `blockInset` | `inlineInset` |
275
+ | Scroll margin | `blockScrollMargin` | `inlineScrollMargin` |
276
+ | Scroll padding | `blockScrollPadding` | `inlineScrollPadding` |
277
+ | Border | `blockBorder` | `inlineBorder` |
278
+
279
+ `blockSize` and `inlineSize` use the same enhanced one/two/three-value and `min`/`max`/`fixed` syntax as `width`. Separate `minBlockSize`, `maxBlockSize`, `minInlineSize`, and `maxInlineSize` declarations override constraints produced by that shorthand.
280
+
281
+ `blockBorder` and `inlineBorder` use the same width/style/color parsing and defaults as `border`, including `1bw`, color tokens, and `true`. Logical padding, margin, scroll margin, and scroll padding default to `1x` for `true`; logical inset defaults to `0`.
282
+
283
+ Native logical CSS names—such as `paddingInlineStart`, `borderBlockColor`, and `borderStartStartRadius`—remain available as ordinary CSS properties. They support Tasty tokens and units through the normal value parser, but do not get category defaults or directional shorthand behavior.
284
+
285
+ The physical `scrollMargin` and `scrollPadding` shorthands support the same values and physical direction modifiers as `padding`. Their logical counterparts stay in separate axis handlers.
286
+
287
+ `writingMode`, `direction`, and `textOrientation` are standard CSS control properties. They use Tasty's normal value parser and need no special handler.
288
+
289
+ Avoid setting physical and logical declarations that resolve to the same edge in one style block. Tasty keeps them separate and lets the native CSS cascade resolve the overlap, whose result also depends on writing mode and direction.
204
290
 
205
291
  ---
206
292
 
@@ -218,6 +304,7 @@ Background color with design token support. Preferred over `backgroundColor` and
218
304
  | `"#purple.10"` | Token color at 10% opacity |
219
305
  | `"#surface #primary.10"` | Background `#surface` with `#primary.10` overlay (two colors enable smooth transitions between both) |
220
306
  | `"rgb(255 128 0)"` | CSS color value |
307
+ | `"color-mix(in oklab, #primary 50%, #surface)"` | CSS color function — see [CSS Color Functions](dsl.md#css-color-functions) |
221
308
  | `true` | Default fill color |
222
309
 
223
310
  When two colors are provided, the first sets the background color and the second is applied as an overlay gradient layer. This enables independent CSS transitions on each color. The overlay is only applied when no explicit `image` or `backgroundImage` is set.
@@ -250,9 +337,17 @@ Text color with design token support.
250
337
  | `"#current"` | Current inherited color |
251
338
  | `"#current.5"` | Current inherited color at 50% opacity |
252
339
  | `"(#primary, #secondary)"` | Fallback: use `#primary`, fall back to `#secondary` |
340
+ | `"light-dark(#dark, #light)"` | CSS color function — see [CSS Color Functions](dsl.md#css-color-functions) |
253
341
  | `true` | `currentColor` |
254
342
 
255
- When set to a named color token, also sets `$current-color` and `$current-color-rgb` custom properties for downstream use.
343
+ Also sets `$current-color` to the same color, for anything that needs the
344
+ inherited color as a color rather than as the `currentcolor` keyword. Every color
345
+ publishes it, not just a named token, so a reader below always takes the nearest
346
+ `color` rather than the nearest *token* color. A value that already reads the
347
+ inherited color — `#current` itself, a `#current` fade, a bare `currentColor` —
348
+ is not republished: resolving it a second time one level down would fade it
349
+ twice, and the variable into itself is a self-reference. `#current` does not go
350
+ through it; it is the keyword.
256
351
 
257
352
  ### `svgFill`
258
353
 
@@ -260,7 +355,7 @@ SVG fill color. Same color token syntax as `fill` and `color`. Outputs the nativ
260
355
 
261
356
  ```jsx
262
357
  svgFill="#purple.10"
263
- svgFill="currentColor"
358
+ svgFill="#current"
264
359
  ```
265
360
 
266
361
  ---
@@ -279,12 +374,15 @@ Border shorthand with directional and multi-group support. Use **comma-separated
279
374
 
280
375
  **Direction modifiers:** `top`, `right`, `bottom`, `left`
281
376
 
377
+ **Output modifier:** `longhand` — forces output as individual CSS properties (`border-top`, `border-right`, `border-bottom`, `border-left`) instead of the `border` shorthand. Useful when children need to selectively inherit individual sides.
378
+
282
379
  | Value | Effect |
283
380
  |-------|--------|
284
381
  | `true` | Default border (`1bw solid #border`) on all sides |
285
382
  | `"2bw dashed #purple"` | All sides: 2bw dashed purple |
286
383
  | `"2bw top"` | Top only: 2bw solid `#border`, others: 0 |
287
384
  | `"dotted #danger left right"` | Left/right: 1bw dotted `#danger`, others: 0 |
385
+ | `"1bw longhand"` | All sides: 1bw solid `#border`, output as 4 individual `border-*` properties |
288
386
  | `"1bw #red, 2bw #blue top"` | All sides: 1bw solid `#red`, top overridden to 2bw solid `#blue` |
289
387
  | `"1bw, dashed top bottom, #purple left right"` | Base: 1bw solid `#border`, top/bottom: 1bw dashed `#border`, left/right: 1bw solid `#purple` |
290
388
 
@@ -304,8 +402,15 @@ Border radius with shape presets and directional modifiers.
304
402
  | `"ellipse"` | Circular (`50%`) |
305
403
  | `"leaf"` | Asymmetric: sharp, round, sharp, round |
306
404
  | `"backleaf"` | Asymmetric: round, sharp, round, sharp |
405
+ | `"inherit"` | Inherit border-radius from parent |
406
+
407
+ **Edge modifiers:** `top`, `right`, `bottom`, `left` — rounds the *pair* of corners along that edge.
307
408
 
308
- **Direction modifiers:** `top`, `right`, `bottom`, `left` — rounds only the specified corners.
409
+ **Corner modifiers:** `top-left`, `top-right`, `bottom-right`, `bottom-left` — rounds a single corner.
410
+ Use these when an edge modifier would round one corner too many. Edge and corner modifiers combine
411
+ (`radius: 'top bottom-right'`).
412
+
413
+ **Output modifier:** `longhand` — forces output as individual CSS longhand properties (`border-top-left-radius`, `border-top-right-radius`, `border-bottom-right-radius`, `border-bottom-left-radius`) instead of the `border-radius` shorthand. Useful when children need to selectively inherit individual corners via `radius: 'inherit left'`.
309
414
 
310
415
  | Value | Effect |
311
416
  |-------|--------|
@@ -315,6 +420,12 @@ Border radius with shape presets and directional modifiers.
315
420
  | `"1r top"` | Top-left and top-right `1r`, bottom-left and bottom-right `0` |
316
421
  | `"leaf"` | Alternating sharp/round corners (top-left `0`, top-right `1r`, bottom-right `0`, bottom-left `1r`) |
317
422
  | `"backleaf"` | Inverse leaf (top-left `1r`, top-right `0`, bottom-right `1r`, bottom-left `0`) |
423
+ | `"1r longhand"` | All corners `1r`, output as 4 individual `border-*-radius` properties |
424
+ | `"inherit"` | All corners inherit from parent (`border-radius: inherit`) |
425
+ | `"inherit right"` | Right corners inherit from parent (uses longhand properties) |
426
+ | `"top-right"` | Top-right corner `1r`, every other corner `0` |
427
+ | `"4px top-left"` | Top-left corner `4px`, every other corner `0` |
428
+ | `"top bottom-right"` | Both top corners and bottom-right `1r`, bottom-left `0` |
318
429
 
319
430
  ### `outline`
320
431
 
@@ -344,7 +455,7 @@ Box shadow. Supports multiple shadows comma-separated.
344
455
 
345
456
  | Value | Effect |
346
457
  |-------|--------|
347
- | `true` | Default shadow (from `$shadow` token) |
458
+ | `true` | Default shadow (uses `var(--shadow)` — define a `$shadow` token in your design system) |
348
459
  | `"1x .5x .5x #dark.50"` | Custom shadow with Tasty units/colors |
349
460
  | `"0 1x 2x #dark.20"` | Standard shadow |
350
461
  | `"inset 0 1x 2x #dark.10"` | Inset shadow |
@@ -359,24 +470,29 @@ Multiple shadows: `shadow="1x 1x 2x #dark.20, inset 0 0 4x #dark.10"`
359
470
 
360
471
  Typography preset that sets font-size, line-height, letter-spacing, font-weight, font-style, and text-transform from named design tokens.
361
472
 
362
- **Syntax:** `[name] [modifiers...]`
473
+ **Syntax:** `name`, `name / modifier...`, or `modifier...` (shorthand)
363
474
 
364
475
  Preset names are project-specific (e.g. `h1`–`h6`, `t1`–`t4`, `p1`–`p4`). Register them for autocomplete by augmenting `TastyPresetNames`.
365
476
 
477
+ Use `/` to separate the preset name from one or more space-separated modifiers. When modifiers are used alone (without a name), the preset name defaults to `inherit`. Modifiers can be combined freely because they target different properties.
478
+
366
479
  **Modifiers:**
367
480
 
368
481
  | Modifier | Effect |
369
482
  |----------|--------|
370
- | `strong` | Sets `font-weight` to bold (from `$bold-font-weight` token) |
483
+ | `strong` (or `bold`) | Sets `font-weight` to bold (from `$bold-font-weight` token) |
371
484
  | `italic` | Sets `font-style: italic` |
372
485
  | `icon` | Sets font-size and line-height to icon size |
373
486
  | `tight` | Sets line-height equal to font-size |
374
487
 
375
488
  ```jsx
376
- preset="h1" // heading 1
377
- preset="h2 strong" // bold heading 2
378
- preset="t3 italic" // italic text 3
379
- preset="t2 tight" // text 2 with tight line-height
489
+ preset="h1" // heading 1
490
+ preset="h2 / strong" // bold heading 2
491
+ preset="h2 / strong italic" // bold + italic heading 2
492
+ preset="t3 / italic" // italic text 3
493
+ preset="t2 / strong tight" // bold text 2 with tight line-height
494
+ preset="bold" // inherit preset with bold (shorthand)
495
+ preset="bold italic" // inherit preset with bold + italic (shorthand)
380
496
  ```
381
497
 
382
498
  Individual typography props (`fontSize`, `lineHeight`, `letterSpacing`, `fontWeight`, `fontStyle`, `textTransform`) can be used alongside `preset` to override specific values, but using `preset` alone is recommended.
@@ -468,15 +584,17 @@ When easing is provided without a duration, the default timing variable is used
468
584
  | `zIndex` | `z-index` |
469
585
  | `inset` | `inset`, `top`, `right`, `bottom`, `left` |
470
586
 
471
- Default timing: `$transition` (or `${name}-transition` with `$transition` fallback per semantic name).
587
+ When two entries cover the same property, an entry that names that one property wins over a group such as `theme`, in either order: `opacity 120ms ease-in-out, theme` keeps the opacity timing. Otherwise the later entry wins, as in CSS.
588
+
589
+ Default timing: `$transition` (or `${name}-transition` with `$transition` fallback per semantic name). Prefer omitting the duration or using a duration token instead of repeating raw time values across components. Explicit zero can disable motion.
472
590
 
473
591
  ```jsx
474
- transition="theme 0.3s"
475
- transition="fill 0.2s, radius 0.3s"
476
- transition="fade 0.15s ease-in"
592
+ transition="theme"
593
+ transition="fill, radius"
594
+ transition="fade $transition ease-in"
477
595
  transition="fill ease-in" // easing without duration (uses default timing)
478
596
  transition="radius ease-in-out" // easing keyword only
479
- transition="$$custom-prop 0.3s" // custom property transition
597
+ transition="$$custom-prop" // custom property transition
480
598
  ```
481
599
 
482
600
  **Recognized easing keywords:** `ease`, `ease-in`, `ease-out`, `ease-in-out`, `linear`, `step-start`, `step-end`. CSS easing functions (`cubic-bezier(...)`, `steps(...)`, `linear(...)`) are also recognized.
@@ -485,51 +603,81 @@ If the name is not a semantic name, it is used as a literal CSS property name.
485
603
 
486
604
  ---
487
605
 
606
+ ### `animation`
607
+
608
+ `animation` is the native CSS shorthand. Tasty parses tokens in its value and
609
+ tracks local `@keyframes` names referenced by it, so it needs no custom style
610
+ handler. Define a complete animation with the shorthand, using a configured
611
+ duration token where appropriate (for example,
612
+ `animation: 'pulse $animation-duration ease-in infinite'`).
613
+
614
+ Use `animationDuration`, `animationTimeline`, `animationRange`, and other CSS
615
+ longhands when changing just one part of an existing animation in a state or
616
+ component extension. Setting `animation` resets omitted parts, including its
617
+ timeline and range. The same principle applies to `transitionDuration` and
618
+ other transition longhands when a base `transition` is already defined.
619
+ `transitionBehavior` remains a separate CSS longhand; Tasty's semantic
620
+ `transition` syntax covers name, timing, easing, and delay.
621
+
622
+ ---
623
+
488
624
  ## Scrollbar & Overflow
489
625
 
490
626
  ### `scrollbar`
491
627
 
492
- Standards-based scrollbar styling using `scrollbar-width`, `scrollbar-color`, and `scrollbar-gutter`.
628
+ Scrollbar styling using CSS standard properties (`scrollbar-width`, `scrollbar-color`, `scrollbar-gutter`).
493
629
 
494
- **Syntax:** `[modifiers...] [thumb-color] [track-color]`
630
+ **Syntax:** `[width] [modifiers...] [thumb-color] [track-color]`
495
631
 
496
- **Modifiers:**
632
+ **Width values** (controls `scrollbar-width`, default is `thin`):
633
+
634
+ | Value | Effect |
635
+ |-------|--------|
636
+ | `thin` | Thin scrollbar (default) |
637
+ | `auto` | Browser-default scrollbar width |
638
+ | `none` | Hide scrollbar (still scrollable, no colors applied) |
639
+
640
+ **Modifiers** (controls gutter and overflow behavior):
497
641
 
498
642
  | Modifier | Effect |
499
643
  |----------|--------|
500
- | `thin` | Thin scrollbar (`scrollbar-width: thin`) |
501
- | `none` | Hide scrollbar (content remains scrollable) |
502
- | `auto` | Browser-default scrollbar width (`scrollbar-width: auto`) |
503
644
  | `stable` | Reserve space for scrollbar (`scrollbar-gutter: stable`) |
504
645
  | `both-edges` | Reserve space on both sides (`scrollbar-gutter: stable both-edges`) |
505
- | `always` | Keep scrollbar visible when content overflows (`overflow: auto` + `scrollbar-gutter: stable`) |
646
+ | `always` | Force scrollbars visible (`overflow: scroll` + `scrollbar-gutter: stable`) |
647
+
648
+ **Colors:** Up to 2 color values for thumb and track (optional), applied via `scrollbar-color`.
506
649
 
507
- **Colors:** Up to 2 color values for thumb and track (optional).
650
+ **Defaults:** When no colors are specified, the thumb color comes from `var(--scrollbar-thumb-color)` and the track color from `var(--scrollbar-track-color, transparent)`. These are not built-in — your design system should define `#scrollbar-thumb` and `#scrollbar-track` tokens (e.g. `'#text.5'` and `'#dark-bg'`). If neither token is defined, the track falls back to `transparent` via a CSS fallback, while the thumb has no CSS-level fallback — the browser treats the entire `scrollbar-color` declaration as invalid and reverts to the platform-default scrollbar appearance.
508
651
 
509
- **Defaults:** thumb = `$scrollbar-thumb-color`, track = `$scrollbar-track-color` (falls back to `transparent`)
652
+ **Note:** `none` takes precedence over all other modifiers and colors. Combining `none` with other tokens (e.g., `"none always #red"`) produces a warning, and only `scrollbar-width: none` is applied.
510
653
 
511
654
  | Value | Effect |
512
655
  |-------|--------|
513
656
  | `true` | Thin scrollbar with default thumb/track colors |
514
- | `"none"` | Hidden scrollbar (content remains scrollable) |
515
- | `"thin #purple.40 #dark.04"` | Thin, thumb `#purple.40`, track `#dark.04` |
516
- | `"always #primary.50 #white.02"` | Always visible with stable gutter, thumb `#primary.50`, track `#white.02` |
517
- | `"thin stable"` | Thin scrollbar with reserved gutter space |
518
- | `"thin both-edges"` | Thin scrollbar with gutter space on both sides |
657
+ | `"none"` | Hidden scrollbar (still scrollable) |
658
+ | `"thin #purple.40 #dark.04"` | Thin scrollbar with custom colors |
659
+ | `"auto #red #blue"` | Browser-default width with custom colors |
660
+ | `"always #primary.50 #white.02"` | Always visible with custom colors |
661
+ | `"thin stable #red #blue"` | Thin, gutter reserved, custom colors |
519
662
 
520
663
  ### `fade`
521
664
 
522
665
  Gradient-based edge fading using CSS masks. Use **comma-separated groups** to set different widths and colors per direction.
523
666
 
524
- **Syntax:** `[width] [directions...] [#from-color] [#to-color]` — comma-separated for multiple groups
667
+ **Syntax:** `[width] [direction...] [#from-color] [#to-color]` — comma-separated for multiple groups
525
668
 
526
669
  **Direction modifiers:** `top`, `right`, `bottom`, `left`
527
670
 
671
+ A group that names edges takes a **single** width, applied to every edge it names — different
672
+ widths per edge come from comma groups. A group that names no edge covers all four and keeps
673
+ plain CSS shorthand order, like `padding`. See the [`padding` rule](#padding).
674
+
528
675
  | Value | Effect |
529
676
  |-------|--------|
530
677
  | `"top"` | Fade top edge, default width (`2x`), all other edges unfaded |
531
678
  | `"2x left right"` | Fade left and right edges with `2x` width, top/bottom unfaded |
532
- | `"3x 1x top bottom"` | Fade top with `3x` width, bottom with `1x` width |
679
+ | `"3x 1x"` | All edges faded — top/bottom `3x`, left/right `1x` (CSS shorthand order) |
680
+ | `"3x top, 1x bottom"` | Fade top with `3x` width, bottom with `1x` width |
533
681
  | `"2x #transparent #dark"` | All edges faded with `2x` width, from `#transparent` to `#dark` |
534
682
  | `"top #a #b, bottom #c #d"` | Top fades from `#a` to `#b`, bottom fades from `#c` to `#d` |
535
683