@tenphi/tasty 0.0.0-snapshot.27b6708 → 0.0.0-snapshot.28b6339

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 (109) hide show
  1. package/README.md +38 -54
  2. package/dist/{babel-BUQGeOXA.d.ts → babel-Zs1Q03qt.d.ts} +2 -2
  3. package/dist/chunks/async-storage-DKK-wTD4.js.map +1 -0
  4. package/dist/chunks/build-config-Mk7waOsw.js +45 -0
  5. package/dist/chunks/build-config-Mk7waOsw.js.map +1 -0
  6. package/dist/{collector-DTahQUiV.js → chunks/collector-Ducc5l3E.js} +29 -15
  7. package/dist/chunks/collector-Ducc5l3E.js.map +1 -0
  8. package/dist/chunks/config-engine-tKK7WxJO.js +331 -0
  9. package/dist/chunks/config-engine-tKK7WxJO.js.map +1 -0
  10. package/dist/chunks/css-definitions-Crstltrf.js +1229 -0
  11. package/dist/chunks/css-definitions-Crstltrf.js.map +1 -0
  12. package/dist/chunks/css-resources-Cyl_axbI.js +149 -0
  13. package/dist/chunks/css-resources-Cyl_axbI.js.map +1 -0
  14. package/dist/chunks/debug-HyyLIf6O.js +543 -0
  15. package/dist/chunks/debug-HyyLIf6O.js.map +1 -0
  16. package/dist/chunks/dsl-D7kBow--.js +1771 -0
  17. package/dist/chunks/dsl-D7kBow--.js.map +1 -0
  18. package/dist/chunks/hydration-CLdVKcH2.js +59 -0
  19. package/dist/chunks/hydration-CLdVKcH2.js.map +1 -0
  20. package/dist/chunks/react-runtime-UlZcbsEN.js +877 -0
  21. package/dist/chunks/react-runtime-UlZcbsEN.js.map +1 -0
  22. package/dist/chunks/runtime-engine-D2WOLvd6.js +3439 -0
  23. package/dist/chunks/runtime-engine-D2WOLvd6.js.map +1 -0
  24. package/dist/chunks/runtime-state-DOeH6rsG.js +138 -0
  25. package/dist/chunks/runtime-state-DOeH6rsG.js.map +1 -0
  26. package/dist/{merge-styles-oklji0KB.js → chunks/shared-utils-Bgl8FNGJ.js} +64 -24
  27. package/dist/chunks/shared-utils-Bgl8FNGJ.js.map +1 -0
  28. package/dist/chunks/style-engine-C4ZcOAPb.js +6915 -0
  29. package/dist/chunks/style-engine-C4ZcOAPb.js.map +1 -0
  30. package/dist/{css-writer-B-J87ncv.js → chunks/zero-engine-D4Rluo7u.js} +3 -3
  31. package/dist/chunks/zero-engine-D4Rluo7u.js.map +1 -0
  32. package/dist/{collector-DUaHCcTS.d.ts → collector-hl5KNH7k.d.ts} +23 -3
  33. package/dist/{config-YsxGv4tq.d.ts → config-DWL1ZYue.d.ts} +150 -55
  34. package/dist/core/index.d.ts +5 -5
  35. package/dist/core/index.js +9 -6
  36. package/dist/{index-PqN-DIpn.d.ts → index-D9N9GV24.d.ts} +129 -93
  37. package/dist/index.d.ts +5 -5
  38. package/dist/index.js +11 -922
  39. package/dist/{merge-styles-CU7JbEwg.d.ts → merge-styles-C_oMoJVd.d.ts} +2 -2
  40. package/dist/ssr/astro-client.js +1 -1
  41. package/dist/ssr/astro-middleware-extract-static.d.ts +11 -0
  42. package/dist/ssr/astro-middleware-extract-static.js +9 -0
  43. package/dist/ssr/astro-middleware-extract-static.js.map +1 -0
  44. package/dist/ssr/astro-middleware-extract.d.ts +11 -0
  45. package/dist/ssr/astro-middleware-extract.js +9 -0
  46. package/dist/ssr/astro-middleware-extract.js.map +1 -0
  47. package/dist/ssr/astro-middleware-static.d.ts +3 -1
  48. package/dist/ssr/astro-middleware.d.ts +3 -1
  49. package/dist/ssr/astro.d.ts +45 -3
  50. package/dist/ssr/astro.js +158 -15
  51. package/dist/ssr/astro.js.map +1 -1
  52. package/dist/ssr/index.d.ts +7 -7
  53. package/dist/ssr/index.js +4 -4
  54. package/dist/ssr/index.js.map +1 -1
  55. package/dist/ssr/next-config.d.ts +66 -0
  56. package/dist/ssr/next-config.js +135 -0
  57. package/dist/ssr/next-config.js.map +1 -0
  58. package/dist/ssr/next.d.ts +9 -2
  59. package/dist/ssr/next.js +27 -11
  60. package/dist/ssr/next.js.map +1 -1
  61. package/dist/static/index.d.ts +2 -2
  62. package/dist/static/index.js +1 -1
  63. package/dist/{index-Cd45t5NM.d.ts → types-jKZNpias.d.ts} +898 -803
  64. package/dist/zero/babel.d.ts +1 -1
  65. package/dist/zero/babel.js +25 -24
  66. package/dist/zero/babel.js.map +1 -1
  67. package/dist/zero/index.d.ts +1 -1
  68. package/dist/zero/index.js +1 -1
  69. package/dist/zero/next.d.ts +1 -1
  70. package/docs/README.md +5 -3
  71. package/docs/adoption.md +3 -3
  72. package/docs/ai-agents.md +83 -78
  73. package/docs/comparison.md +12 -12
  74. package/docs/configuration.md +47 -47
  75. package/docs/debug.md +19 -7
  76. package/docs/dsl.md +3 -3
  77. package/docs/getting-started.md +10 -10
  78. package/docs/injector.md +62 -25
  79. package/docs/methodology.md +3 -3
  80. package/docs/migration-v3.md +49 -49
  81. package/docs/plugins.md +37 -33
  82. package/docs/react-api.md +2 -2
  83. package/docs/runtime-benchmarks.md +351 -0
  84. package/docs/ssr.md +219 -61
  85. package/docs/styles.md +43 -11
  86. package/docs/tasty-static.md +136 -103
  87. package/package.json +80 -11
  88. package/dist/async-storage-DKK-wTD4.js.map +0 -1
  89. package/dist/collector-DTahQUiV.js.map +0 -1
  90. package/dist/config-B5kHzuNz.js +0 -12269
  91. package/dist/config-B5kHzuNz.js.map +0 -1
  92. package/dist/context-CA8YKeMn.js +0 -24
  93. package/dist/context-CA8YKeMn.js.map +0 -1
  94. package/dist/core-Dr4u1NVD.js +0 -1566
  95. package/dist/core-Dr4u1NVD.js.map +0 -1
  96. package/dist/css-writer-B-J87ncv.js.map +0 -1
  97. package/dist/format-global-rules-DklyaXv-.js +0 -22
  98. package/dist/format-global-rules-DklyaXv-.js.map +0 -1
  99. package/dist/format-rules-DKOA-6qu.js +0 -130
  100. package/dist/format-rules-DKOA-6qu.js.map +0 -1
  101. package/dist/hydrate-OeMX99We.js +0 -37
  102. package/dist/hydrate-OeMX99We.js.map +0 -1
  103. package/dist/index.js.map +0 -1
  104. package/dist/keyframes-CV8azJf3.js +0 -493
  105. package/dist/keyframes-CV8azJf3.js.map +0 -1
  106. package/dist/merge-styles-oklji0KB.js.map +0 -1
  107. package/dist/resolve-recipes-DTG81rzl.js +0 -144
  108. package/dist/resolve-recipes-DTG81rzl.js.map +0 -1
  109. /package/dist/{async-storage-DKK-wTD4.js → chunks/async-storage-DKK-wTD4.js} +0 -0
package/docs/ai-agents.md CHANGED
@@ -16,7 +16,7 @@ Color tokens (`#name`), custom properties (`$name`), `preset` names, `recipe` na
16
16
  const Card = tasty({ as: 'div', styles: { … }, styleProps: ['padding'] }); // new component
17
17
  const Hero = tasty(Card, { styles: { … } }); // extend a component
18
18
  const cls = useStyles({ … }); // ad-hoc class name
19
- tastyStatic('.card', { … }); // build-time, zero runtime
19
+ tastyStatic('.card', { … }); // build-time extraction
20
20
  ```
21
21
 
22
22
  - Wrap, don't pass styles per instance: ❌ `<Box styles={{ padding: '2x' }} />` → ✅ `const Box = tasty({ styles: { padding: '2x' } })`.
@@ -29,26 +29,28 @@ Keys are camelCase — a Tasty property or a real CSS property. No kebab-case, n
29
29
 
30
30
  Prefer the Tasty shorthand over its CSS equivalents:
31
31
 
32
- | Use | Instead of |
33
- |-----|------------|
34
- | `fill` | `backgroundColor`, `background` |
35
- | `image` | `backgroundImage` |
36
- | `border` | `borderColor`, `borderWidth`, `borderStyle`, `borderTop`/`Right`/`Bottom`/`Left` |
37
- | `radius` | `borderRadius` |
38
- | `outline` | `outlineColor`, `outlineWidth`, `outlineStyle`, `outlineOffset` |
39
- | `shadow` | `boxShadow` |
40
- | `padding` | `paddingTop`/`Right`/`Bottom`/`Left` |
41
- | `margin` | `marginTop`/`Right`/`Bottom`/`Left` |
42
- | `inset` | `top`, `right`, `bottom`, `left` |
43
- | `width` / `height` | `minWidth`/`maxWidth`, `minHeight`/`maxHeight` |
44
- | `flow` | `flexDirection`, `flexWrap`, `flexFlow`, `gridAutoFlow` |
45
- | `preset` | `fontSize`, `lineHeight`, `letterSpacing`, `fontWeight`, `fontStyle`, `textTransform` |
46
- | `font` | `fontFamily` |
47
- | `scrollbar` | `scrollbarWidth`, `scrollbarColor`, `scrollbarGutter` |
48
- | `gridColumns` / `gridRows` / `gridAreas` | `gridTemplateColumns` / `Rows` / `Areas` |
49
- | `textOverflow: 'ellipsis / 3'` | `lineClamp` |
50
- | `hide: true` | `display: 'none'` |
51
- | `flexGrow` / `flexShrink` / `flexBasis` | `flex` |
32
+ | Use | Instead of |
33
+ | ---------------------------------------- | ------------------------------------------------------------------------------------- |
34
+ | `fill` | `backgroundColor`, `background` |
35
+ | `image` | `backgroundImage` |
36
+ | `border` | `borderColor`, `borderWidth`, `borderStyle`, `borderTop`/`Right`/`Bottom`/`Left` |
37
+ | `radius` | `borderRadius` |
38
+ | `outline` | `outlineColor`, `outlineWidth`, `outlineStyle`, `outlineOffset` |
39
+ | `shadow` | `boxShadow` |
40
+ | `padding` | `paddingTop`/`Right`/`Bottom`/`Left` |
41
+ | `margin` | `marginTop`/`Right`/`Bottom`/`Left` |
42
+ | `inset` | `top`, `right`, `bottom`, `left` |
43
+ | `width` / `height` | `minWidth`/`maxWidth`, `minHeight`/`maxHeight` |
44
+ | `flow` | `flexDirection`, `flexWrap`, `flexFlow`, `gridAutoFlow` |
45
+ | `preset` | `fontSize`, `lineHeight`, `letterSpacing`, `fontWeight`, `fontStyle`, `textTransform` |
46
+ | `font` | `fontFamily` |
47
+ | `scrollbar` | `scrollbarWidth`, `scrollbarColor`, `scrollbarGutter` |
48
+ | `gridColumns` / `gridRows` / `gridAreas` | `gridTemplateColumns` / `Rows` / `Areas` |
49
+ | `textOverflow: 'ellipsis / 3'` | `lineClamp` |
50
+ | `hide: true` | `display: 'none'` |
51
+ | `flexGrow` / `flexShrink` / `flexBasis` | `flex` |
52
+
53
+ Use logical category styles when layout must follow writing mode or direction: `blockSize`/`inlineSize`, `blockPadding`/`inlinePadding`, `blockMargin`/`inlineMargin`, `blockInset`/`inlineInset`, `blockScrollMargin`/`inlineScrollMargin`, `blockScrollPadding`/`inlineScrollPadding`, and `blockBorder`/`inlineBorder`. Use `start`/`end` value modifiers; do not replace them with physical sides. Native logical CSS properties remain valid as ordinary keys when an individual declaration is needed.
52
54
 
53
55
  The last row goes the other way — longhands over the shorthand — because `flex` is lossy: it resets the components you omit to non-initial values (`flex: '0'` silently sets `flex-basis: 0%`) and cannot express `flexShrink: 0` at all. The longhands also carry separate state maps.
54
56
 
@@ -56,23 +58,23 @@ The last row goes the other way — longhands over the shorthand — because `fl
56
58
 
57
59
  ### Tokens
58
60
 
59
- | Syntax | Meaning |
60
- |--------|---------|
61
- | `#name` | color token → `var(--name-color)` |
62
- | `#name.50` | token at 50% opacity (`0`–`100`) |
63
- | `#name.$opacity` | opacity from a custom property |
64
- | `#clear` / `#current` | `transparent` / `currentcolor` |
65
- | `$name` | custom property → `var(--name)` |
66
- | `(#a, #b)` | fallback chain |
67
- | `$$name` / `##name` | the custom property *name* (not its value) — inside `transition` |
68
- | `$$name(…)` | call a CSS `@function` declared via `@function`, `useFunction`, or config |
61
+ | Syntax | Meaning |
62
+ | --------------------- | ------------------------------------------------------------------------- |
63
+ | `#name` | color token → `var(--name-color)` |
64
+ | `#name.50` | token at 50% opacity (`0`–`100`) |
65
+ | `#name.$opacity` | opacity from a custom property |
66
+ | `#clear` / `#current` | `transparent` / `currentcolor` |
67
+ | `$name` | custom property → `var(--name)` |
68
+ | `(#a, #b)` | fallback chain |
69
+ | `$$name` / `##name` | the custom property _name_ (not its value) — inside `transition` |
70
+ | `$$name(…)` | call a CSS `@function` declared via `@function`, `useFunction`, or config |
69
71
 
70
72
  - ❌ `#f5f5f5`, `rgb(0 0 0)`, `oklch(…)`, `okhsl(…)`, `red` → ✅ `#surface` (add the token to the config if it doesn't exist).
71
73
  - ❌ `var(--gap)` → ✅ `$gap` · ❌ `$accent-color` → ✅ `#accent` · ❌ `transparent` → ✅ `#clear` · ❌ `currentColor` → ✅ `#current`.
72
74
  - A `$name` must be declared as a `'$name': value` key in the same styles object, or in the config.
73
75
  - Names are case-sensitive and start lowercase — `$myVar` → `--myVar`; a leading capital folds (`$Foo` → `--foo`). Prefer kebab-case.
74
76
  - A `$name` reference is untyped: it fills the first free slot in a shorthand (`border: '1bw $my-style'` → the line style). Write colors as `#name`; `$name-color` is a fallback for pointing at a raw CSS custom property that holds a color.
75
- - `preset` and `transition` take token *names*, not values, so a `$name` cannot stand in for one (it warns in dev and is ignored).
77
+ - `preset` and `transition` take token _names_, not values, so a `$name` cannot stand in for one (it warns in dev and is ignored).
76
78
 
77
79
  ### Units
78
80
 
@@ -86,7 +88,7 @@ Prefer units over raw pixels: `8px` → `1x` … `64px` → `8x`; `radius: '6px'
86
88
 
87
89
  ### `true`
88
90
 
89
- `true` means "the design-system default" and is accepted **only** by: `border`, `radius`, `outline`, `shadow`, `padding`, `margin`, `gap`, `inset`, `width`, `height`, `fill`, `color`, `fade`, `preset`, `font`, `scrollbar`, `hide`. Anywhere else it is an error.
91
+ `true` means "the design-system default" and is accepted **only** by: `border`, `radius`, `outline`, `shadow`, `padding`, `margin`, `gap`, `inset`, `width`, `height`, `fill`, `color`, `fade`, `preset`, `font`, `scrollbar`, `scrollMargin`, `scrollPadding`, and the enhanced logical category styles listed above, plus `hide`. Anywhere else it is an error.
90
92
 
91
93
  ### `!important`
92
94
 
@@ -96,29 +98,31 @@ Never use it. Tasty owns specificity through doubled selectors and state orderin
96
98
 
97
99
  A value is `[values…] [modifiers…]`, and several groups can be comma-separated (later groups override earlier ones). A group that names **direction** modifiers takes a **single** value, applied to every direction it names — per-side values come from comma groups. A group naming no direction keeps plain CSS shorthand order (1–4 values). (`inset` + `dock` is the one exception: a second value insets the spanned sides.) Only the modifiers a property knows are valid:
98
100
 
99
- | Property | Modifiers |
100
- |----------|-----------|
101
- | `padding`, `margin`, `inset`, `fade` | `top` `right` `bottom` `left` |
102
- | `border` | the four directions + `solid` `dashed` `dotted` `double` `groove` `ridge` `inset` `outset` `none` `hidden` |
103
- | `outline` | the style keywords above |
104
- | `radius` | `top` `right` `bottom` `left` + shapes `round` `ellipse` `leaf` `backleaf` |
105
- | `width`, `height` | `min` `max` `fixed` |
106
- | `flow` | `row` `column` `row-reverse` `column-reverse` `wrap` `nowrap` `dense` |
107
- | `overflow` | `visible` `hidden` `scroll` `clip` `auto` `overlay` |
108
- | `position` | `static` `relative` `absolute` `fixed` `sticky` |
109
- | `shadow` | `inset` |
110
- | `preset` | `name / strong` (or `bold`) `italic` `icon` `tight` |
111
- | box properties | `longhand` — emit CSS longhands instead of the shorthand |
101
+ | Property | Modifiers |
102
+ | ------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
103
+ | `padding`, `margin`, `inset`, `fade` | `top` `right` `bottom` `left` |
104
+ | `border` | the four directions + `solid` `dashed` `dotted` `double` `groove` `ridge` `inset` `outset` `none` `hidden` |
105
+ | logical axis spacing/inset styles | `start` `end` |
106
+ | `blockBorder`, `inlineBorder` | `start` `end` + the border style keywords above |
107
+ | `outline` | the style keywords above |
108
+ | `radius` | `top` `right` `bottom` `left` + shapes `round` `ellipse` `leaf` `backleaf` |
109
+ | `width`, `height`, `blockSize`, `inlineSize` | `min` `max` `fixed` |
110
+ | `flow` | `row` `column` `row-reverse` `column-reverse` `wrap` `nowrap` `dense` |
111
+ | `overflow` | `visible` `hidden` `scroll` `clip` `auto` `overlay` |
112
+ | `position` | `static` `relative` `absolute` `fixed` `sticky` |
113
+ | `shadow` | `inset` |
114
+ | `preset` | `name / strong` (or `bold`) `italic` `icon` `tight` |
115
+ | box properties | `longhand` — emit CSS longhands instead of the shorthand |
112
116
 
113
117
  Directional modifiers beat placeholder zeros:
114
118
 
115
119
  - ❌ `padding: '0 0 2x 0'` → ✅ `padding: '2x bottom'`
116
120
  - ❌ `padding: '1x 1x 2x 1x'` → ✅ `padding: '1x, 2x bottom'`
117
- - ❌ `border: '0 0 1bw 0'` — four tokens parse as *one* border value, so this renders no border at all → ✅ `border: '1bw bottom'`
121
+ - ❌ `border: '0 0 1bw 0'` — four tokens parse as _one_ border value, so this renders no border at all → ✅ `border: '1bw bottom'`
118
122
  - ❌ `padding: '2x 4x top right'` — a directional group takes one value, so `4x` is dropped → ✅ `padding: '2x top, 4x right'`
119
123
  - ❌ `fade: '3x 1x top bottom'` → ✅ `fade: '3x top, 1x bottom'`
120
124
 
121
- Value-only properties reject both colors and modifiers: `gap`, `columnGap`, `rowGap`, `opacity`, `zIndex`, `order`, `flexGrow`, `flexShrink`, `flexBasis`, `aspectRatio`, `lineClamp`, `tabSize`, `paddingInline`, `paddingBlock`. `fill` and `color` take a color (plus `none` / `transparent`); `caretColor` and `accentColor` take a color only.
125
+ Value-only properties reject both colors and modifiers: `gap`, `columnGap`, `rowGap`, `opacity`, `zIndex`, `order`, `flexGrow`, `flexShrink`, `flexBasis`, `aspectRatio`, `lineClamp`, and `tabSize`. Logical axis category styles accept one or two values in start/end order and the `start`, `end`, and `longhand` modifiers. `fill` and `color` take a color (plus `none` / `transparent`); `caretColor` and `accentColor` take a color only.
122
126
 
123
127
  ### `transition`
124
128
 
@@ -130,17 +134,17 @@ Use semantic names, not CSS property names: `fade` `fill` `color` `theme` `borde
130
134
 
131
135
  A property value can be an object of `state: value`. Key order is priority — later keys win.
132
136
 
133
- | Key | Generated selector |
134
- |-----|--------------------|
135
- | `hovered` | `[data-hovered]` (boolean modifier from `mods`) |
136
- | `theme=danger` | `[data-theme="danger"]` (value modifier) |
137
- | `:hover` | pseudo-class |
138
- | `.active` | class selector |
139
- | `[aria-expanded="true"]` | attribute selector |
140
- | `hovered & .active` | AND |
141
- | `hovered \| focused` | OR (`,` also means OR) |
142
- | `!disabled` | NOT |
143
- | `hovered ^ focused` | XOR — exactly one (keep chains ≤ 4 operands) |
137
+ | Key | Generated selector |
138
+ | ------------------------ | ----------------------------------------------- |
139
+ | `hovered` | `[data-hovered]` (boolean modifier from `mods`) |
140
+ | `theme=danger` | `[data-theme="danger"]` (value modifier) |
141
+ | `:hover` | pseudo-class |
142
+ | `.active` | class selector |
143
+ | `[aria-expanded="true"]` | attribute selector |
144
+ | `hovered & .active` | AND |
145
+ | `hovered \| focused` | OR (`,` also means OR) |
146
+ | `!disabled` | NOT |
147
+ | `hovered ^ focused` | XOR — exactly one (keep chains ≤ 4 operands) |
144
148
 
145
149
  Precedence `!` > `^` > `|` > `&`; use parentheses to override.
146
150
 
@@ -148,7 +152,7 @@ Rules:
148
152
 
149
153
  1. **`''` comes first.** The bare default is the lowest-priority state; placing it later would override everything above it.
150
154
  2. **Every state map needs `''` or `_`** — except when extending (`tasty(Parent, …)`), where omitting `''` merges into the parent's states and including `''` replaces them wholesale.
151
- 3. **`_` is standalone-only** and always first (with `''` right after it, if present). `_` is a never-negated fallback floor for cases where a higher-priority branch may be *unknown* (`@supports`, container queries). If a map contains only `_` and `''`, drop the `''`.
155
+ 3. **`_` is standalone-only** and always first (with `''` right after it, if present). `_` is a never-negated fallback floor for cases where a higher-priority branch may be _unknown_ (`@supports`, container queries). If a map contains only `_` and `''`, drop the `''`.
152
156
  4. **No nested maps:** ❌ `{ hovered: { pressed: 'x' } }` → ✅ `{ 'hovered & pressed': 'x' }`
153
157
  5. **State keys never sit at the top level** of a styles object — `:hover`, `.active`, `[open]` belong inside a property value.
154
158
  6. **Prefer automatic native states:** use `disabled` and `checked` in Tasty component styles instead of `[disabled]` and `[checked]`. The concise states track the corresponding native prop or attribute automatically.
@@ -159,16 +163,16 @@ color: { '': '#text', hovered: '#accent', disabled: '#text.40' }
159
163
 
160
164
  Advanced states:
161
165
 
162
- | Prefix | Use | Example |
163
- |--------|-----|---------|
164
- | `@media(…)` | media query; dimensions `w` `h`; types `@media:print` `:screen` `:all` `:speech` | `@media(w < 768px)`, `@media(600px <= w < 1200px)` |
165
- | `@(…)` | container query; dimensions `w` `h` `is` `bs` | `@(layout, w >= 600px)`, `@($variant=primary)` |
166
- | `@supports(…)` | feature query; `$` first argument tests a selector | `@supports(display: grid)`, `@supports($, :has(*))` |
167
- | `@root(…)` | condition on `:root` | `@root(schema=dark)` |
168
- | `@parent(…)` | condition on an ancestor; `, >` for the direct parent | `@parent(hovered, >)` |
169
- | `@own(…)` | a sub-element's own state — **only inside sub-element styles** | `@own(:hover)` |
170
- | `@starting` | `@starting-style` entry animation | `@starting` |
171
- | `@name` | project state alias | `@mobile` |
166
+ | Prefix | Use | Example |
167
+ | -------------- | -------------------------------------------------------------------------------- | --------------------------------------------------- |
168
+ | `@media(…)` | media query; dimensions `w` `h`; types `@media:print` `:screen` `:all` `:speech` | `@media(w < 768px)`, `@media(600px <= w < 1200px)` |
169
+ | `@(…)` | container query; dimensions `w` `h` `is` `bs` | `@(layout, w >= 600px)`, `@($variant=primary)` |
170
+ | `@supports(…)` | feature query; `$` first argument tests a selector | `@supports(display: grid)`, `@supports($, :has(*))` |
171
+ | `@root(…)` | condition on `:root` | `@root(schema=dark)` |
172
+ | `@parent(…)` | condition on an ancestor; `, >` for the direct parent | `@parent(hovered, >)` |
173
+ | `@own(…)` | a sub-element's own state — **only inside sub-element styles** | `@own(:hover)` |
174
+ | `@starting` | `@starting-style` entry animation | `@starting` |
175
+ | `@name` | project state alias | `@mobile` |
172
176
 
173
177
  - At root level write the selector directly: ❌ `'@own(:hover)'` → ✅ `':hover'`.
174
178
  - `@name` aliases must exist in `states` in the config or be declared locally as an `'@name': '<state expression>'` key; alias keys start with `@` and their value must be a valid state expression.
@@ -188,14 +192,14 @@ styles: { Title: { preset: 'h3' }, Icon: { $: '>@:last-child', color: '#accent'
188
192
 
189
193
  ## 6. Special top-level keys
190
194
 
191
- | Key | Shape |
192
- |-----|-------|
193
- | `@keyframes` | `{ name: { '0%': styles, … } }` |
194
- | `@property` | `{ '$name': { syntax, inherits, initialValue } }` |
195
- | `@font-face` | `{ 'Family Name': descriptors \| descriptors[] }` |
196
- | `@counter-style` | `{ name: descriptors }` |
197
- | `@function` | `{ '$$name': { args, returns?, result, '$local'? } }` |
198
- | `recipe` | a **string** of configured recipe names: `'card elevated'`, `'reset input / autofill'`, `'none / disabled'` |
195
+ | Key | Shape |
196
+ | ---------------- | ----------------------------------------------------------------------------------------------------------- |
197
+ | `@keyframes` | `{ name: { '0%': styles, … } }` |
198
+ | `@property` | `{ '$name': { syntax, inherits, initialValue } }` |
199
+ | `@font-face` | `{ 'Family Name': descriptors \| descriptors[] }` |
200
+ | `@counter-style` | `{ name: descriptors }` |
201
+ | `@function` | `{ '$$name': { args, returns?, result, '$local'? } }` |
202
+ | `recipe` | a **string** of configured recipe names: `'card elevated'`, `'reset input / autofill'`, `'none / disabled'` |
199
203
 
200
204
  At-rule keys match the real CSS at-rule names, so they are kebab-case, not camelCase. Inside `@function`, the callable is `$$name` but its parameters and local variables are `$name`:
201
205
 
@@ -214,6 +218,7 @@ The selector must be a string literal and valid CSS. Values must be static — s
214
218
 
215
219
  - Token, preset, recipe, unit and `@alias` names exist in the project config.
216
220
  - Tasty shorthand chosen over CSS longhands; `flexGrow`/`flexShrink`/`flexBasis` over `flex`; `hide: true` over `display: 'none'`.
221
+ - Logical category styles keep native `block`/`inline` declarations and accept `start`/`end`, never physical direction modifiers.
217
222
  - Colors are `#tokens`, not hex/rgb/oklch/named; `$prop` not `var(--prop)`.
218
223
  - Spacing uses `x`/`r`/`bw`/`ow` units; math uses `(…)`, not `calc(…)`.
219
224
  - `true` only on the properties that accept it; no `!important`.
@@ -259,12 +259,12 @@ Tasty is more opinionated.
259
259
 
260
260
  It behaves less like "TypeScript that outputs CSS" and more like a **state-aware style compiler**. It is designed to encode higher-level styling semantics rather than only expose CSS primitives in typed form.
261
261
 
262
- This also makes Tasty's rendering model notable:
262
+ This also makes Tasty's delivery model notable:
263
263
 
264
- - `tasty()` components are hook-free and work as React Server Components. In server-only contexts (Next.js RSC, Astro without islands), they produce static HTML + CSS with zero client JavaScript — the full feature set is available without sacrificing server rendering
265
- - `tastyStatic()` with the Babel plugin produces static class name strings via build-time extraction, with no React dependency at runtime — the output works with any JavaScript framework
264
+ - `tasty()` components are hook-free and work as React Server Components. In server-only contexts, they produce HTML + CSS with zero Tasty styling runtime in the browser while retaining the full React feature set. Astro without islands is the concrete integration; server-only Next.js RSC uses the same architecture.
265
+ - `tastyStatic()` with the Babel plugin produces static class-name objects via build-time extraction, with no React dependency — the output works with any JavaScript framework.
266
266
 
267
- Runtime features like `styleProps`, sub-element components, and dynamic variants are available in the `tasty()` path. The `tastyStatic()` path is framework-agnostic but limited to the DSL, tokens, and state logic.
267
+ React component features like `styleProps`, sub-element components, and dynamic variants are available in the `tasty()` path whether it renders on the server or in the browser. The `tastyStatic()` path is framework-agnostic but limited to the DSL, tokens, and state logic.
268
268
 
269
269
  So the tradeoff is roughly:
270
270
 
@@ -326,28 +326,28 @@ So while Stitches and Emotion are strong tools for building components, Tasty is
326
326
 
327
327
  That makes it narrower in audience, but deeper in architectural ambition.
328
328
 
329
- There is also a fundamental architectural difference: Emotion and styled-components rely on React context and hooks internally, which means they require `'use client'` in modern React and cannot run as React Server Components. Tasty's style functions and `tasty()` components are hook-free, so they work as server components by default and produce zero client JavaScript in server-only contexts. This is not a minor compatibility detail — it means Tasty-based components stay as server components until _your_ code needs interactivity, while Emotion and styled-components force the client boundary at the styling layer.
329
+ There is also a fundamental architectural difference: Emotion and styled-components rely on React context and hooks internally, which means they require `'use client'` in modern React and cannot run as React Server Components. Tasty's style functions and `tasty()` components are hook-free, so they work as server components by default and ship no Tasty styling runtime in server-only contexts. This is not a minor compatibility detail — it means Tasty-based components stay as server components until _your_ code needs interactivity, while Emotion and styled-components force the client boundary at the styling layer.
330
330
 
331
331
  For teams evaluating runtime styling at scale, Tasty also documents its runtime benchmarks and caching model in the main [README](../README.md#performance). That matters, but it is still secondary to the core question of whether you want Tasty's deterministic selector model.
332
332
 
333
333
  ---
334
334
 
335
- ## Build-time vs runtime
335
+ ## Where styles are computed
336
336
 
337
337
  Tasty is not limited to one execution model.
338
338
 
339
- The term "runtime" in `tasty()` refers to _when_ style computation happens — during React rendering — not to where that rendering occurs. In server-only contexts (Next.js RSC without `'use client'`, Astro without `client:*` directives, SSG), `tasty()` components render on the server, produce static HTML + CSS, and ship **zero client JavaScript**. The full feature set — `styleProps`, sub-elements, variants, state maps — is available. The result is the same as what `tastyStatic()` produces, but without giving up any runtime capabilities.
339
+ Zero-runtime delivery is an outcome, not a synonym for `tastyStatic()`. `tasty()` computes styles during React rendering, but that rendering can happen only on the server. In that case it produces HTML + CSS and ships **zero Tasty styling runtime** to the browser. The full feature set — `styleProps`, sub-elements, variants, state maps — remains available. Astro's `tastyIntegration({ islands: false })` is the explicit setup for this path. Server-only Next.js RSC follows the same architecture; verify the generated output for the target deployment.
340
340
 
341
341
  Client JavaScript only enters the picture when a component needs React interactivity (state, effects, event handlers) — and that is the consuming component's decision, never Tasty's. Tasty never forces the `'use client'` boundary.
342
342
 
343
- `tastyStatic()` with the Babel plugin is for a different scenario: when you want build-time CSS extraction **without React at runtime**. The output is framework-agnostic — any JavaScript framework can consume the resulting class names and CSS. This makes Tasty usable as the compiler layer underneath a design-system implementation, even outside the React ecosystem.
343
+ `tastyStatic()` with the Babel plugin reaches zero-runtime delivery differently: CSS is extracted **during the build**, without React. The output is framework-agnostic — any JavaScript framework can consume the resulting class names and CSS. This makes Tasty usable as the compiler layer underneath a design-system implementation, even outside the React ecosystem.
344
344
 
345
345
  The tradeoff is that some capabilities — `styleProps`, sub-element components (`<Card.Title>`), dynamic variants — are tied to the `tasty()` path. The `tastyStatic()` path is best understood as extraction and compilation of the DSL, tokens, and state logic without a React dependency.
346
346
 
347
- This flexibility is one of Tasty's more unusual strengths:
347
+ This gives Tasty two zero-runtime paths:
348
348
 
349
- - `tasty()` as the default for all React setups — zero client JS in server-only contexts, full feature set, SSR integration available when client hydration is needed
350
- - `tastyStatic()` as a static compiler whose output works with any framework, including non-React ones
349
+ - server-only `tasty()` for the full React component API, with CSS generated during server or static rendering
350
+ - `tastyStatic()` as a build-time compiler whose output works with any framework, including non-React ones
351
351
 
352
352
  ---
353
353
 
@@ -443,6 +443,6 @@ Tasty is most compelling when the problem is not just "how do we write styles,"
443
443
  - [React API](react-api.md) — `tasty()` factory, component props, variants, sub-elements, style functions
444
444
  - [Style Properties](styles.md) — complete reference for all enhanced style properties
445
445
  - [Configuration](configuration.md) — tokens, recipes, custom units, style handlers, and TypeScript extensions
446
- - [Zero Runtime (tastyStatic)](tasty-static.md) — build-time static styling with Babel plugin
446
+ - [Build-Time Extraction (`tastyStatic`)](tasty-static.md) — static styling with the Babel plugin
447
447
  - [Adoption Guide](adoption.md) — where Tasty sits in the stack, incremental adoption, and what changes for product engineers
448
448
  - [Server-Side Rendering](ssr.md) — SSR setup for Next.js, Astro, and generic frameworks
@@ -47,35 +47,35 @@ These docs use `data-schema="dark"` in examples. If your app already standardize
47
47
 
48
48
  ## Options
49
49
 
50
- | Option | Type | Default | Description |
51
- | -------------------- | ------------------------------------------------ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
52
- | `nonce` | `string` | - | CSP nonce for style elements |
53
- | `maxRulesPerSheet` | `number` | `8192` | Maximum rules per injected stylesheet |
54
- | `forceTextInjection` | `boolean` | auto (`true` in test envs) | Force text-node CSS injection instead of constructable stylesheets |
55
- | `devMode` | `boolean` | auto | Enable development-mode features: performance metrics and debug info |
56
- | `states` | `Record<string, string>` | - | Global state aliases for advanced state mapping |
57
- | `parserCacheSize` | `number` | `1000` | Parser LRU cache size |
58
- | `units` | `Record<string, string \| UnitHandler>` | Built-in | Custom units (merged with built-in). See [built-in units](dsl.md#built-in-units) |
59
- | `functions` | `Record<string, FunctionDefinition \| Function>` | - | Custom functions (merged). Bare keys → parse functions; `$$name` keys → declarative CSS `@function` definitions |
60
- | `handlers` | `Record<string, StyleHandlerDefinition>` | Built-in | Custom style handlers (replace built-in). See [Custom Style Handlers](#custom-style-handlers) |
61
- | `propHandlers` | `Record<string, PropHandlerDefinition>` | - | Props middleware for every component — props in, props out. See [Props Middleware](#props-middleware) |
62
- | `baseStyleProps` | `readonly string[]` | - | Style names exposed as props on **every** component. See [Base Style Props](#base-style-props) |
63
- | `tokens` | `Record<string, value \| stateMap>` | - | Design tokens injected as `:root` CSS custom properties |
64
- | `replaceTokens` | `Record<string, string \| number \| boolean>` | - | Parse-time token substitution (inline replacement). `boolean` is allowed for `#` color tokens |
65
- | `keyframes` | `Record<string, KeyframesSteps>` | - | Global keyframes for animations |
66
- | `properties` | `Record<string, PropertyDefinition>` | - | Global CSS @property definitions |
67
- | `fontFaces` | `Record<string, FontFaceInput>` | - | Global @font-face definitions |
68
- | `counterStyles` | `Record<string, CounterStyleDescriptors>` | - | Global @counter-style definitions |
69
- | `polyfills` | `{ functions?: boolean }` | `{}` | Opt-in polyfills for not-yet-baseline features. `functions: true` inlines `@function` calls into plain CSS at parse time |
70
- | `autoPropertyTypes` | `boolean` | `true` | Auto-infer and register `@property` types from values |
71
- | `recipes` | `Record<string, RecipeStyles>` | - | Predefined style recipes (named style bundles) |
72
- | `presets` | `Record<string, TypographyPreset>` | - | Typography presets — shorthand for `generateTypographyTokens()` |
73
- | `globalStyles` | `Record<string, Styles>` | - | Global Tasty styles keyed by CSS selector |
74
- | `plugins` | `TastyPlugin[]` | - | Plugins that bundle any of the above (processed in order; later override earlier, and direct config wins over all). See [Plugins](plugins.md) |
75
- | `gc` | `GCConfig` | - | Garbage-collection tuning for unused styles (`{ touchInterval, capacity }`) |
76
- | `batchInjection` | `boolean \| 'always'` | `false` | Defer stylesheet writes and apply them in one batch. See [Batched injection](#batched-injection) |
77
- | `colorSpace` | `'rgb' \| 'hsl' \| 'oklch'` | - | **Deprecated** — no longer has any effect. See [Color space](#color-space) |
78
- | `namePrefix` | `string` | `'t'` (runtime) / `'ts'` (zero-runtime) | Prefix prepended to every generated identifier (class, keyframe, counter-style names). Must match `^[a-zA-Z_][a-zA-Z0-9_-]{0,31}$`. See [Name prefix](#name-prefix). |
50
+ | Option | Type | Default | Description |
51
+ | -------------------- | ------------------------------------------------ | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
52
+ | `nonce` | `string` | - | CSP nonce for style elements |
53
+ | `maxRulesPerSheet` | `number` | `8192` | Maximum rules per injected stylesheet |
54
+ | `forceTextInjection` | `boolean` | auto (`true` in test envs) | Force text-node CSS injection instead of constructable stylesheets |
55
+ | `devMode` | `boolean` | auto | Enable development-mode features: performance metrics and debug info |
56
+ | `states` | `Record<string, string>` | - | Global state aliases for advanced state mapping |
57
+ | `parserCacheSize` | `number` | `1000` | Parser LRU cache size |
58
+ | `units` | `Record<string, string \| UnitHandler>` | Built-in | Custom units (merged with built-in). See [built-in units](dsl.md#built-in-units) |
59
+ | `functions` | `Record<string, FunctionDefinition \| Function>` | - | Custom functions (merged). Bare keys → parse functions; `$$name` keys → declarative CSS `@function` definitions |
60
+ | `handlers` | `Record<string, StyleHandlerDefinition>` | Built-in | Custom style handlers (replace built-in). See [Custom Style Handlers](#custom-style-handlers) |
61
+ | `propHandlers` | `Record<string, PropHandlerDefinition>` | - | Props middleware for every component — props in, props out. See [Props Middleware](#props-middleware) |
62
+ | `baseStyleProps` | `readonly string[]` | - | Style names exposed as props on **every** component. See [Base Style Props](#base-style-props) |
63
+ | `tokens` | `Record<string, value \| stateMap>` | - | Design tokens injected as `:root` CSS custom properties |
64
+ | `replaceTokens` | `Record<string, string \| number \| boolean>` | - | Parse-time token substitution (inline replacement). `boolean` is allowed for `#` color tokens |
65
+ | `keyframes` | `Record<string, KeyframesSteps>` | - | Global keyframes for animations |
66
+ | `properties` | `Record<string, PropertyDefinition>` | - | Global CSS @property definitions |
67
+ | `fontFaces` | `Record<string, FontFaceInput>` | - | Global @font-face definitions |
68
+ | `counterStyles` | `Record<string, CounterStyleDescriptors>` | - | Global @counter-style definitions |
69
+ | `polyfills` | `{ functions?: boolean }` | `{}` | Opt-in polyfills for not-yet-baseline features. `functions: true` inlines `@function` calls into plain CSS at parse time |
70
+ | `autoPropertyTypes` | `boolean` | `true` | Auto-infer and register `@property` types from values |
71
+ | `recipes` | `Record<string, RecipeStyles>` | - | Predefined style recipes (named style bundles) |
72
+ | `presets` | `Record<string, TypographyPreset>` | - | Typography presets — shorthand for `generateTypographyTokens()` |
73
+ | `globalStyles` | `Record<string, Styles>` | - | Global Tasty styles keyed by CSS selector |
74
+ | `plugins` | `TastyPlugin[]` | - | Plugins that bundle any of the above (processed in order; later override earlier, and direct config wins over all). See [Plugins](plugins.md) |
75
+ | `gc` | `GCConfig` | - | Garbage-collection tuning for unused styles (`{ touchInterval, capacity }`) |
76
+ | `batchInjection` | `boolean \| 'always'` | `false` | Defer stylesheet writes and apply them in one batch. See [Batched injection](#batched-injection) |
77
+ | `colorSpace` | `'rgb' \| 'hsl' \| 'oklch'` | - | **Deprecated** — no longer has any effect. See [Color space](#color-space) |
78
+ | `namePrefix` | `string` | `'t'` (`tasty`) / `'ts'` (build-time) | Prefix prepended to every generated identifier (class, keyframe, counter-style names). Must match `^[a-zA-Z_][a-zA-Z0-9_-]{0,31}$`. See [Name prefix](#name-prefix). |
79
79
 
80
80
  ---
81
81
 
@@ -150,7 +150,7 @@ All writes share one FIFO queue — component rules, global rules, raw CSS,
150
150
  Draining it in insertion order keeps the sheet byte-identical to unbatched
151
151
  output, which matters because equal-specificity rules resolve by document order.
152
152
 
153
- ### SSR, RSC and zero-runtime
153
+ ### Client rendering, server rendering, and build-time extraction
154
154
 
155
155
  **Server render — nothing to batch, safe to leave enabled.** SSR and RSC collect
156
156
  CSS as text through `ServerStyleCollector`; the runtime injector never runs
@@ -175,12 +175,12 @@ tasty components to be worth it. `'always'` needs no provider and covers every
175
175
  island, at the cost of the measurement hazard above. Either way, an island that
176
176
  only re-hydrates server-rendered classes has nothing to batch.
177
177
 
178
- **Zero-runtime (`tastyStatic`) — unaffected.** Build-time extraction never
178
+ **Build-time extraction (`tastyStatic`) — unaffected.** The Babel plugin never
179
179
  touches the injector: the babel plugin emits either a CSS file import or an
180
180
  `injectCSS()` call from `@tenphi/tasty/static/inject`, which appends text to a
181
181
  single `<style data-tasty-static>` element. `batchInjection` only defers CSSOM
182
- writes made by the runtime injector, so extracted styles are unchanged. In an app
183
- that mixes both, it still applies to the runtime half.
182
+ writes made by the browser injector, so extracted styles are unchanged. In an app
183
+ that mixes both, it still applies to the `tasty()` half.
184
184
 
185
185
  ### `flushStyles()`
186
186
 
@@ -284,7 +284,7 @@ color syntax works on every `<color>`, including a `color-mix()`, a
284
284
 
285
285
  ## Name Prefix
286
286
 
287
- Every identifier Tasty generates — class names, keyframe names, counter-style names — starts with a configurable prefix. The runtime, SSR, and RSC paths default to `'t'`; the zero-runtime build path (`tastyStatic` via the Babel plugin) defaults to `'ts'` so static-extracted classes can never collide with runtime classes when both are loaded on the same page.
287
+ Every identifier Tasty generates — class names, keyframe names, counter-style names — starts with a configurable prefix. The `tasty()` client, SSR, and RSC paths default to `'t'`; the build-time extraction path (`tastyStatic` via the Babel plugin) defaults to `'ts'` so extracted classes can never collide with `tasty()` classes when both are loaded on the same page.
288
288
 
289
289
  ```jsx
290
290
  configure({
@@ -294,12 +294,12 @@ configure({
294
294
 
295
295
  The prefix is prepended verbatim to the hash, so include any separator inside the prefix string itself:
296
296
 
297
- | Setting | Class | Keyframe | Counter-style |
298
- | ----------------------------- | ------------- | -------------- | -------------- |
299
- | `'t'` (runtime default) | `t1a2b3` | `tk1a2b3` | `tc1a2b3` |
300
- | `'ts'` (zero-runtime default) | `ts1a2b3` | `tsk1a2b3` | `tsc1a2b3` |
301
- | `'mb'` | `mb1a2b3` | `mbk1a2b3` | `mbc1a2b3` |
302
- | `'myapp-'` | `myapp-1a2b3` | `myapp-k1a2b3` | `myapp-c1a2b3` |
297
+ | Setting | Class | Keyframe | Counter-style |
298
+ | --------------------------- | ------------- | -------------- | -------------- |
299
+ | `'t'` (`tasty` default) | `t1a2b3` | `tk1a2b3` | `tc1a2b3` |
300
+ | `'ts'` (build-time default) | `ts1a2b3` | `tsk1a2b3` | `tsc1a2b3` |
301
+ | `'mb'` | `mb1a2b3` | `mbk1a2b3` | `mbc1a2b3` |
302
+ | `'myapp-'` | `myapp-1a2b3` | `myapp-k1a2b3` | `myapp-c1a2b3` |
303
303
 
304
304
  The single-letter discriminators (`k` for keyframes, `c` for counter-styles) keep the three kinds visually distinct in devtools — they are not required for correctness because CSS keeps these in separate namespaces.
305
305
 
@@ -309,12 +309,12 @@ The single-letter discriminators (`k` for keyframes, `c` for counter-styles) kee
309
309
  - Validated at `configure()` time; an invalid prefix throws synchronously rather than silently producing broken hydration.
310
310
  - Locked once styles have been generated, like all other config.
311
311
 
312
- ### Coexistence with the zero-runtime build
312
+ ### Coexistence with build-time extraction
313
313
 
314
- The runtime and zero-runtime builds **must use different prefixes** when both are loaded on the same page. Defaults already guarantee this; if you customize one, customize the other accordingly:
314
+ The `tasty()` and `tastyStatic()` paths **must use different prefixes** when both are loaded on the same page. Defaults already guarantee this; if you customize one, customize the other accordingly:
315
315
 
316
316
  ```jsx
317
- // app config (runtime / SSR / RSC)
317
+ // app config (client / SSR / RSC)
318
318
  configure({ namePrefix: 'mb' });
319
319
 
320
320
  // tasty-zero.config.ts (Babel plugin)
@@ -352,7 +352,7 @@ configure({
352
352
  - `#name` keys become `--name-color` custom properties
353
353
  - Names keep their case, since CSS custom properties are case-sensitive: `$myVar` is `--myVar` and is referenced as `$myVar`. A leading capital is not supported and folds — `$Foo` and `#Purple` become `--foo` and `--purple-color` — so start names lowercase. Kebab-case (`$my-var`) remains the convention.
354
354
 
355
- Tokens are automatically emitted in all rendering modes: runtime (client), SSR, and zero-runtime (Babel plugin).
355
+ Tokens are automatically emitted in all delivery modes: client rendering, server rendering, and build-time extraction with the Babel plugin.
356
356
 
357
357
  ---
358
358
 
@@ -617,7 +617,7 @@ configure({
617
617
 
618
618
  Each key is a CSS selector, and each value is a Tasty `Styles` object supporting the full style syntax including style properties, tokens, state maps, and selector-based sub-styling (e.g. `$: '> .app'` for elements outside React scope). Global styles are injected alongside `:root` tokens when the first style is rendered.
619
619
 
620
- Global styles are automatically emitted in all rendering modes: runtime (client), SSR, and zero-runtime (Babel plugin). Plugins can also provide `globalStyles`; they are merged per selector with config global styles (config wins on conflict).
620
+ Global styles are automatically emitted in all delivery modes: client rendering, server rendering, and build-time extraction with the Babel plugin. Plugins can also provide `globalStyles`; they are merged per selector with config global styles (config wins on conflict).
621
621
 
622
622
  ---
623
623
 
@@ -625,7 +625,7 @@ Global styles are automatically emitted in all rendering modes: runtime (client)
625
625
 
626
626
  CSS cannot transition or animate custom properties unless their type is declared via [`@property`](https://developer.mozilla.org/en-US/docs/Web/CSS/@property). Tasty handles this automatically — when a custom property is assigned a concrete value (e.g. `'$scale': 1`, `'$gap': '10px'`, `'#accent': 'purple'`), the type is inferred and a `@property` rule is registered.
627
627
 
628
- This works across all declaration contexts: component styles, `@keyframes`, global config, and the zero-runtime Babel plugin. It also resolves `var()` chains — if `$a` references `var(--b)`, the type propagates once `--b` is resolved.
628
+ This works across all declaration contexts: component styles, `@keyframes`, global config, and build-time extraction with the Babel plugin. It also resolves `var()` chains — if `$a` references `var(--b)`, the type propagates once `--b` is resolved.
629
629
 
630
630
  Supported types:
631
631
 
@@ -784,7 +784,7 @@ Handlers run at the very top of every component's render, before any prop is des
784
784
 
785
785
  Handlers must be **pure** and must not mutate their input, and should memoize the styles they build per input value: style values are cached by object identity, so mutating one in place yields stale CSS, and a reference-stable object avoids re-serializing on every render.
786
786
 
787
- Injected styles occupy the `styles` slot, so they beat a component's own default styles and lose to a style prop at the call site. Prop handlers do not apply to sub-elements or to zero-runtime `tastyStatic()`, which has no props.
787
+ Injected styles occupy the `styles` slot, so they beat a component's own default styles and lose to a style prop at the call site. Prop handlers do not apply to sub-elements or to build-time `tastyStatic()`, which has no props.
788
788
 
789
789
  See [Plugins → Props middleware](plugins.md#props-middleware) for the full contract and a worked example.
790
790
 
package/docs/debug.md CHANGED
@@ -6,9 +6,7 @@ Runtime CSS inspection and diagnostics for the Tasty styling system. Inspect inj
6
6
 
7
7
  ## Overview
8
8
 
9
- `tastyDebug` is a diagnostic object that exposes Tasty's runtime CSS state. It is designed for development use but can be manually installed in production for debugging.
10
-
11
- In development mode (`isDevEnv()` returns `true`), `tastyDebug` is automatically installed on `window.tastyDebug`. In production, install it manually when needed.
9
+ `tastyDebug` is a diagnostic object that exposes Tasty's runtime CSS state. It is designed for development use and can be installed on `window` explicitly when needed.
12
10
 
13
11
  All methods **log to the console by default**. Pass `{ raw: true }` to suppress logging and only return data.
14
12
 
@@ -19,7 +17,6 @@ All methods **log to the console by default**. Pass `{ raw: true }` to suppress
19
17
  ## Quick Start
20
18
 
21
19
  ```typescript
22
- // Auto-installed in dev mode. Otherwise:
23
20
  import { tastyDebug } from '@tenphi/tasty';
24
21
  tastyDebug.install();
25
22
 
@@ -54,6 +51,19 @@ interface DebugOptions {
54
51
 
55
52
  When `raw` is `false` (the default), results are logged to the console **and** returned. When `raw` is `true`, results are returned silently.
56
53
 
54
+ ### Environments Without a DOM
55
+
56
+ `tastyDebug` reads the document, so on a server — SSR, a Node REPL, a test
57
+ runner in the `node` environment — there is nothing for it to read. Every
58
+ method returns its empty result (`''`, an empty `InspectResult`, a summary of
59
+ zeroes, `metrics: null`) instead of throwing, and explains itself once with a
60
+ console warning. `{ raw: true }` suppresses that warning along with the rest of
61
+ the logging.
62
+
63
+ To see the styles a server render produced, read the `ServerStyleCollector`
64
+ instead — `collector.getCSS()` and `collector.getRenderedClassNames()`. See
65
+ [SSR](./ssr.md).
66
+
57
67
  ---
58
68
 
59
69
  ## API Reference
@@ -68,7 +78,7 @@ Retrieves CSS text for a given target. Logs the result with rule count and size.
68
78
  |---|---|
69
79
  | `'all'` | All tasty CSS (component + global + raw) |
70
80
  | `'active'` | CSS for classes currently in the DOM |
71
- | `'unused'` | CSS with refCount = 0 (cached but not used) |
81
+ | `'unused'` | CSS for injected classes no element carries (cached but not rendered) |
72
82
  | `'global'` | Only global CSS (from `injectGlobal`) |
73
83
  | `'page'` | All CSS on the page (including non-tasty) |
74
84
  | `'t3a5f'` | CSS for a specific tasty class (class names are `t` + base36 hash) |
@@ -241,7 +251,9 @@ tastyDebug.cache();
241
251
 
242
252
  ### `cleanup(opts?): void`
243
253
 
244
- Forces immediate cleanup of all unused styles (those with `refCount = 0`).
254
+ Removes every injected style that is neither carried by an element nor pinned by
255
+ an outstanding `inject()` handle — the same set `summary()` reports as unused.
256
+ Equivalent to `gc({ force: true })`.
245
257
 
246
258
  ```typescript
247
259
  tastyDebug.cleanup();
@@ -262,7 +274,7 @@ tastyDebug.help();
262
274
 
263
275
  ### `install(): void`
264
276
 
265
- Attaches `tastyDebug` to `window.tastyDebug`. Called automatically in development mode.
277
+ Attaches `tastyDebug` to `window.tastyDebug`.
266
278
 
267
279
  ```typescript
268
280
  import { tastyDebug } from '@tenphi/tasty';
package/docs/dsl.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  This is the language behind Tasty’s predictable state resolution. Every property can use a state map; later branches declare higher priority, and Tasty compiles them so only one generated selector can match.
4
4
 
5
- The same value syntax, state maps, tokens, units, extension semantics, and special declarations apply to runtime `tasty()` and build-time `tastyStatic()`.
5
+ The same value syntax, state maps, tokens, units, extension semantics, and special declarations apply to React `tasty()`—whether rendered on the client or server—and build-time `tastyStatic()`.
6
6
 
7
- For the runtime React API (`tasty()`, hooks, component props), see [React API](react-api.md). For all enhanced style properties, see [Style Properties](styles.md). For global configuration, see [Configuration](configuration.md).
7
+ For the React API (`tasty()`, style functions, component props), see [React API](react-api.md). For all enhanced style properties, see [Style Properties](styles.md). For global configuration, see [Configuration](configuration.md).
8
8
 
9
9
  ---
10
10
 
@@ -1018,4 +1018,4 @@ For a complete reference of all enhanced style properties — syntax, values, mo
1018
1018
  - **[Methodology](methodology.md)** — Recommended patterns: root + sub-elements, styleProps, tokens, wrapping
1019
1019
  - **[Configuration](configuration.md)** — Tokens, recipes, custom units, style handlers, TypeScript extensions
1020
1020
  - **[Style Properties](styles.md)** — Complete reference for all enhanced style properties
1021
- - **[Zero Runtime (tastyStatic)](tasty-static.md)** — Build-time static styling with Babel plugin
1021
+ - **[Build-Time Extraction (`tastyStatic`)](tasty-static.md)** — Static styling with the Babel plugin