@seyuna/postcss 1.0.0-canary.37 → 1.0.0-canary.39

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 (54) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +444 -156
  3. package/dist/at-rules/color-scheme.d.ts +3 -2
  4. package/dist/at-rules/color-scheme.js +6 -7
  5. package/dist/at-rules/color.d.ts +5 -4
  6. package/dist/at-rules/color.js +5 -4
  7. package/dist/at-rules/config.d.ts +2 -1
  8. package/dist/at-rules/config.js +44 -13
  9. package/dist/at-rules/container.d.ts +2 -1
  10. package/dist/at-rules/container.js +4 -6
  11. package/dist/at-rules/import.d.ts +3 -2
  12. package/dist/at-rules/import.js +107 -139
  13. package/dist/at-rules/index.d.ts +2 -1
  14. package/dist/at-rules/index.js +3 -4
  15. package/dist/config.js +70 -28
  16. package/dist/errors.d.ts +3 -5
  17. package/dist/errors.js +2 -4
  18. package/dist/functions/color.d.ts +4 -4
  19. package/dist/functions/color.js +4 -4
  20. package/dist/functions/index.js +5 -7
  21. package/dist/helpers.d.ts +4 -6
  22. package/dist/helpers.js +26 -22
  23. package/dist/index.d.ts +8 -1
  24. package/dist/index.js +1 -0
  25. package/dist/parser.js +36 -49
  26. package/dist/plugin.d.ts +3 -1
  27. package/dist/plugin.js +15 -19
  28. package/dist/types.d.ts +6 -1
  29. package/dist/types.js +0 -2
  30. package/package.json +20 -3
  31. package/.github/workflows/release.yml +0 -41
  32. package/.vscode/settings.json +0 -4
  33. package/dist/functions/theme.d.ts +0 -6
  34. package/dist/functions/theme.js +0 -17
  35. package/release.config.mjs +0 -37
  36. package/src/at-rules/color-scheme.ts +0 -54
  37. package/src/at-rules/color.ts +0 -33
  38. package/src/at-rules/config.ts +0 -78
  39. package/src/at-rules/container.ts +0 -58
  40. package/src/at-rules/import.ts +0 -196
  41. package/src/at-rules/index.ts +0 -29
  42. package/src/config.ts +0 -98
  43. package/src/errors.ts +0 -27
  44. package/src/functions/color.ts +0 -123
  45. package/src/functions/index.ts +0 -22
  46. package/src/functions/theme.ts +0 -20
  47. package/src/helpers.ts +0 -75
  48. package/src/index.ts +0 -10
  49. package/src/parser.ts +0 -81
  50. package/src/plugin.ts +0 -58
  51. package/src/styles/seyuna-global.css +0 -94
  52. package/src/types.ts +0 -71
  53. package/tests/plugin.test.ts +0 -244
  54. package/tsconfig.json +0 -14
package/README.md CHANGED
@@ -3,91 +3,65 @@
3
3
  [![NPM Version](https://img.shields.io/npm/v/@seyuna/postcss.svg)](https://www.npmjs.com/package/@seyuna/postcss)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- > Design once. Deploy everywhere. Light and dark, effortlessly.
6
+ > A CSS compiler for theme-aware design tokens.
7
7
 
8
8
  ---
9
9
 
10
- ## Philosophy
10
+ ## Overview
11
11
 
12
- Seyuna PostCSS is not just another CSS preprocessor. It's a design system compiler that embraces four core principles:
12
+ `@seyuna/postcss` is a PostCSS plugin that turns Seyuna-specific CSS syntax into plain CSS.
13
13
 
14
- ### 1. Design Once at 1080p, Deploy Everywhere
14
+ It is designed for projects that want:
15
15
 
16
- Traditional responsive design means designing the same component three or four times for different screen sizes. Seyuna takes a different approach: viewport-relative scaling.
16
+ - design tokens declared directly in CSS
17
+ - theme-aware colors without runtime JavaScript
18
+ - reusable light/dark/system mode styling
19
+ - container query shortcuts
20
+ - generated utility-like selectors from token lists
17
21
 
18
- ```css
19
- html {
20
- font-size: max(1rem, 0.833vw);
21
- }
22
- ```
23
-
24
- At 1920px viewport width, `0.833vw` equals exactly `16px`. On a 4K display, everything scales proportionally. Your 1080p design becomes a 4K design automatically. No breakpoints. No media queries. No redesigning.
25
-
26
- ### 2. Seamless Dark / Light Mode
27
-
28
- Theme switching shouldn't require duplicating your entire stylesheet. With Seyuna, colors are defined once and adapt automatically:
29
-
30
- ```css
31
- .button {
32
- background: SeyunaStandardColor(primary);
33
- }
34
- ```
22
+ In practice, you write Seyuna syntax such as:
35
23
 
36
- When the user switches from light to dark mode, every standard color updates its lightness and chroma automatically. No conditional classes. No theme-specific stylesheets.
24
+ - `@config "seyuna"` for tokens and theme settings
25
+ - `@seyuna;` to inject the generated design system
26
+ - helper functions like `SeyunaTone(primary)` and `SeyunaSwatch(brand)`
27
+ - at-rules like `@dark`, `@light`, `@xs`, `@each-tone`, and `@each-swatch`
37
28
 
38
- ### 3. Cleaner Codebase
29
+ Seyuna compiles that into regular CSS:
39
30
 
40
- CSS shouldn't be bloated with repetitive color definitions and hardcoded values. Seyuna keeps your stylesheets lean:
31
+ - custom properties
32
+ - light and dark mode selectors
33
+ - system preference media queries
34
+ - container queries
35
+ - repeated selectors for palette iteration
36
+ - a global reset and layer setup
41
37
 
42
- ```css
43
- /* Instead of this */
44
- .card {
45
- background: rgba(66, 133, 244, 0.5);
46
- border: 1px solid rgba(66, 133, 244, 0.8);
47
- }
38
+ The important idea is that the source stays token-driven, but the browser receives standard CSS with no JavaScript color runtime.
48
39
 
49
- /* Write this */
50
- .card {
51
- background: SeyunaAlpha(primary, 0.5);
52
- border: 1px solid SeyunaAlpha(primary, 0.8);
53
- }
54
- ```
55
-
56
- Your color palette is defined directly in your CSS. Your stylesheets reference colors by name. Change a value once in `@config`, and it updates everywhere.
40
+ ---
57
41
 
58
- ### 4. Seamless Color Functions
42
+ ## Core Idea
59
43
 
60
- Need a hover state that's slightly lighter? A disabled state that's more transparent? Seyuna provides color manipulation functions that work with your design tokens:
44
+ Seyuna works in three steps:
61
45
 
62
- ```css
63
- .button {
64
- background: SeyunaStandardColor(primary);
65
- }
66
-
67
- .button:hover {
68
- background: SeyunaLighten(primary, 0.1);
69
- }
70
-
71
- .button:disabled {
72
- background: SeyunaAlpha(primary, 0.3);
73
- }
74
- ```
46
+ 1. Define tokens in CSS with `@config "seyuna"`.
47
+ 2. Generate the runtime variables and theme rules with `@seyuna;`.
48
+ 3. Reference those generated variables through helper functions like `SeyunaTone()` and `SeyunaAlpha()`.
75
49
 
76
- These functions compile to pure CSS using `calc()` and CSS custom properties. No JavaScript runtime. No color processing at page load.
50
+ That means your source CSS stays token-based, while the browser receives plain CSS variables and selectors.
77
51
 
78
52
  ---
79
53
 
80
54
  ## Quick Start
81
55
 
82
- ### Installation
56
+ ### Install
83
57
 
84
58
  ```bash
85
59
  npm install @seyuna/postcss postcss-import postcss-advanced-variables postcss-preset-env --save-dev
86
60
  ```
87
61
 
88
- ### PostCSS Configuration
62
+ ### Configure PostCSS
89
63
 
90
- ```javascript
64
+ ```js
91
65
  // postcss.config.js
92
66
  import seyunaPostcss from "@seyuna/postcss";
93
67
  import postcssImport from "postcss-import";
@@ -96,9 +70,9 @@ import postcssPresetEnv from "postcss-preset-env";
96
70
 
97
71
  export default {
98
72
  plugins: [
73
+ postcssImport(),
99
74
  seyunaPostcss(),
100
- postcssImport,
101
- postcssAdvancedVariables,
75
+ postcssAdvancedVariables(),
102
76
  postcssPresetEnv({
103
77
  stage: 3,
104
78
  features: {
@@ -109,138 +83,442 @@ export default {
109
83
  };
110
84
  ```
111
85
 
112
- ### CSS Setup
86
+ ### Recommended Plugin Order
87
+
88
+ Seyuna should run early in the pipeline.
113
89
 
114
- Configure your design tokens directly in your CSS using the `@config "seyuna"` at-rule, and then initialize the design system using `@seyuna;`:
90
+ - `postcss-import()` first if your CSS is split across files
91
+ - `seyunaPostcss()` next so it can see `@config`, `@seyuna`, and Seyuna helper functions before another plugin rewrites them
92
+ - nesting and other syntax transforms after that
93
+
94
+ If Seyuna runs too late, another plugin may already have removed or changed the syntax it needs to process.
95
+
96
+ ---
97
+
98
+ ## Smallest Working Example
115
99
 
116
100
  ```css
117
101
  @config "seyuna" {
118
- /* Define hues (0-360) */
119
102
  --hue-primary: 240;
120
- --hue-secondary: 30;
121
-
122
- /* Define fixed colors (lightness chroma hue) */
123
- --color-white: 1 0 0;
124
- --color-black: 0 0 0;
125
-
126
- /* Configure theme modes */
127
103
  --light-lightness: 0.66;
128
104
  --light-chroma: 0.26;
105
+ --dark-lightness: 0.78;
106
+ --dark-chroma: 0.18;
129
107
  --light-background: 1 0 0;
130
108
  --light-text: 0 0 0;
131
-
132
- --dark-lightness: 0.66;
133
- --dark-chroma: 0.26;
134
109
  --dark-background: 0 0 0;
135
110
  --dark-text: 1 0 0;
136
111
  }
137
112
 
138
113
  @seyuna;
139
114
 
140
- /* Your styles here */
115
+ .button {
116
+ background: SeyunaTone(primary);
117
+ color: SeyunaContrast(primary);
118
+ }
119
+
120
+ .button:hover {
121
+ background: SeyunaTint(primary, 0.06);
122
+ }
123
+ ```
124
+
125
+ What this does:
126
+
127
+ 1. `--hue-primary` defines the hue token named `primary`.
128
+ 2. `--light-lightness` and `--dark-lightness` define the base lightness used by theme-aware standard colors.
129
+ 3. `--light-chroma` and `--dark-chroma` define the base chroma used by theme-aware standard colors.
130
+ 4. `@seyuna;` injects the variables, theme selectors, and reset.
131
+ 5. `SeyunaTone(primary)` resolves to an `oklch(...)` color using the current theme's `--lightness`, `--chroma`, and the `--primary-hue`.
132
+ 6. `SeyunaTint(primary, 0.06)` creates a lighter version of the same standard color.
133
+
134
+ ---
135
+
136
+ ## How `@config "seyuna"` Works
137
+
138
+ `@config "seyuna"` is a build-time configuration block written directly in CSS.
139
+
140
+ The plugin reads its custom properties, merges them into the Seyuna theme config, and removes the block from the final output.
141
+
142
+ You can have one `@config "seyuna"` block or several. If there are several, they are merged in source order.
143
+
144
+ Example:
145
+
146
+ ```css
147
+ @config "seyuna" {
148
+ --hue-primary: 240;
149
+ }
150
+
151
+ @config "seyuna" {
152
+ --dark-lightness: 0.8;
153
+ }
141
154
  ```
142
155
 
143
- The `@config` rule is parsed and removed at build time. It populates:
156
+ That behaves as one combined configuration.
157
+
158
+ ---
159
+
160
+ ## What `@seyuna;` Injects
161
+
162
+ `@seyuna;` expands the config into runtime CSS.
163
+
164
+ It injects:
165
+
166
+ - the global Seyuna reset and cascade layers
167
+ - `:root` hue variables such as `--primary-hue`
168
+ - `:root` fixed color variables such as `--brand-lightness`, `--brand-chroma`, and `--brand-hue`
169
+ - `[data-mode="light"]` and `[data-mode="dark"]` blocks
170
+ - system preference media queries for `[data-mode="system"]`
144
171
 
145
- - CSS custom properties for all your colors and hues
146
- - Theme mode selectors (`[data-mode="light"]`, `[data-mode="dark"]`)
147
- - System preference media queries
148
- - A modern CSS reset with cascade layers
172
+ Use `@seyuna;` once in the compiled stylesheet output. If it appears multiple times, Seyuna keeps the first one and warns about the duplicates.
149
173
 
150
174
  ---
151
175
 
152
- ## Color System
176
+ ## Understanding the Color Model
153
177
 
154
- Seyuna operates entirely in the **OKLCH color space**.
178
+ Seyuna uses **OKLCH**.
179
+
180
+ You do not usually write full `oklch(...)` values in your component styles. Instead, you define tokens and let the helpers produce the final colors.
181
+
182
+ There are two kinds of color tokens:
155
183
 
156
184
  ### Standard Colors
157
185
 
158
- Standard colors define only a hue angle in the config and inherit theme lightness.
186
+ Standard colors are hue-driven.
159
187
 
160
- ### Default Hues
188
+ They use:
161
189
 
162
- Seyuna comes with 24 default hues based on the Greek alphabet, spaced evenly at 15-degree increments:
190
+ - a hue from `--hue-*`
191
+ - a theme lightness from `--light-lightness` or `--dark-lightness`
192
+ - a theme chroma from `--light-chroma` or `--dark-chroma`
163
193
 
164
- `alpha (15)`, `beta (30)`, `gamma (45)`, `delta (60)`, `epsilon (75)`, `zeta (90)`, `eta (105)`, `theta (120)`, `iota (135)`, `kappa (150)`, `lambda (165)`, `mu (180)`, `nu (195)`, `xi (210)`, `omicron (225)`, `pi (240)`, `rho (255)`, `sigma (270)`, `tau (285)`, `upsilon (300)`, `phi (315)`, `chi (330)`, `psi (345)`, `omega (360)`.
194
+ That means standard colors automatically adapt between light and dark modes.
165
195
 
166
- You can use these directly without configuration, or override them in the `@config` block.
196
+ Example:
167
197
 
168
198
  ```css
169
199
  @config "seyuna" {
170
- --hue-alpha: 200; /* Override default Alpha hue */
200
+ --hue-primary: 240;
201
+ --light-lightness: 0.66;
202
+ --light-chroma: 0.26;
203
+ --dark-lightness: 0.78;
204
+ --dark-chroma: 0.18;
171
205
  }
172
206
 
173
- .badge {
174
- background: SeyunaStandardColor(alpha);
207
+ .button {
208
+ background: SeyunaTone(primary);
175
209
  }
176
210
  ```
177
211
 
212
+ In light mode, `SeyunaTone(primary)` uses:
213
+
214
+ - `var(--lightness)` from the light palette
215
+ - `var(--chroma)` from the light palette
216
+ - `var(--primary-hue)`
217
+
218
+ In dark mode, the same function call uses the dark palette values instead.
219
+
178
220
  ### Fixed Colors
179
221
 
180
- Fixed colors have explicit lightness, chroma, and hue values. They can also be overridden per theme mode.
222
+ Fixed colors are fully specified tokens.
223
+
224
+ They use:
225
+
226
+ - `--color-name: lightness chroma hue`
227
+
228
+ and become three runtime variables:
229
+
230
+ - `--name-lightness`
231
+ - `--name-chroma`
232
+ - `--name-hue`
233
+
234
+ Example:
181
235
 
182
236
  ```css
183
237
  @config "seyuna" {
184
- --color-white: 1 0 0;
185
- --color-brand: 0.5 0.2 100; /* Global value */
186
- --light-color-brand: 1 0 100; /* Light mode override */
238
+ --color-brand: 0.5 0.2 100;
187
239
  }
188
240
 
189
241
  .logo {
190
- color: SeyunaFixedColor(white);
242
+ color: SeyunaSwatch(brand);
243
+ }
244
+ ```
245
+
246
+ Unlike standard colors, fixed colors do not depend on the theme-wide `--lightness` and `--chroma` values unless you override them per mode.
247
+
248
+ ---
249
+
250
+ ## What `--light-lightness` and `--dark-lightness` Actually Do
251
+
252
+ This is the most important config concept to understand.
253
+
254
+ `--light-lightness` and `--dark-lightness` do **not** define one specific named color.
255
+
256
+ Instead, they define the base `--lightness` variable for the active theme mode:
257
+
258
+ - `--light-lightness` becomes `--lightness` inside `[data-mode="light"]`
259
+ - `--dark-lightness` becomes `--lightness` inside `[data-mode="dark"]`
260
+ - both are also emitted inside the matching `prefers-color-scheme` media queries for `[data-mode="system"]`
261
+
262
+ That `--lightness` value is then used by standard-color helpers such as:
263
+
264
+ - `SeyunaTone()`
265
+ - `SeyunaAlpha()` when the referenced token is a standard color
266
+ - `SeyunaTint()` when the referenced token is a standard color
267
+ - `SeyunaShade()` when the referenced token is a standard color
268
+ - `SeyunaContrast()` when the referenced token is a standard color
269
+
270
+ So this:
271
+
272
+ ```css
273
+ @config "seyuna" {
274
+ --hue-primary: 240;
275
+ --light-lightness: 0.66;
276
+ --dark-lightness: 0.8;
191
277
  }
192
278
 
193
- .highlight {
194
- background: SeyunaFixedColor(brand);
279
+ .button {
280
+ background: SeyunaTone(primary);
195
281
  }
196
282
  ```
197
283
 
284
+ means:
285
+
286
+ - in light mode, `primary` uses lightness `0.66`
287
+ - in dark mode, `primary` uses lightness `0.8`
288
+
289
+ The same idea applies to `--light-chroma` and `--dark-chroma`. They define the shared `--chroma` variable for standard colors in each mode.
290
+
198
291
  ---
199
292
 
200
- ## Color Functions
293
+ ## Theme Palette Properties
294
+
295
+ Inside `@config "seyuna"`, theme-level properties control the generated palette for light and dark modes.
296
+
297
+ ### Shared Theme Controls
298
+
299
+ These values shape standard colors in each mode:
300
+
301
+ - `--light-lightness`
302
+ - `--light-chroma`
303
+ - `--dark-lightness`
304
+ - `--dark-chroma`
305
+
306
+ They are used to populate:
307
+
308
+ - `--lightness`
309
+ - `--chroma`
201
310
 
202
- | Function | Purpose | Example |
203
- | :----------------------------- | :---------------------------------------- | :----------------------------- |
204
- | `SeyunaStandardColor(name)` | Standard color with theme-aware lightness | `SeyunaStandardColor(primary)` |
205
- | `SeyunaFixedColor(name)` | Fixed color with explicit values | `SeyunaFixedColor(white)` |
206
- | `SeyunaAlpha(color, value)` | Adjusts opacity | `SeyunaAlpha(primary, 0.5)` |
207
- | `SeyunaLighten(color, amount)` | Increases lightness | `SeyunaLighten(primary, 0.1)` |
208
- | `SeyunaDarken(color, amount)` | Decreases lightness | `SeyunaDarken(primary, 0.1)` |
209
- | `SeyunaContrast(color)` | Returns black or white for readability | `SeyunaContrast(surface)` |
311
+ inside each generated mode selector.
210
312
 
211
- The `SeyunaContrast()` function uses dynamic CSS calculations. If the underlying color changes at runtime, the contrast color updates automatically.
313
+ ### Theme Surface Colors
314
+
315
+ These values define the page-level background and text colors for each mode:
316
+
317
+ - `--light-background`
318
+ - `--light-text`
319
+ - `--dark-background`
320
+ - `--dark-text`
321
+
322
+ Each one must be written as:
323
+
324
+ ```css
325
+ lightness chroma hue
326
+ ```
327
+
328
+ For example:
329
+
330
+ ```css
331
+ --dark-background: 0 0 0;
332
+ --dark-text: 1 0 0;
333
+ ```
334
+
335
+ They become:
336
+
337
+ - `--background`
338
+ - `--text`
339
+
340
+ inside the generated mode blocks.
341
+
342
+ ### Mode-Specific Fixed Color Overrides
343
+
344
+ You can override a fixed color inside a specific mode by using:
345
+
346
+ - `--light-color-*`
347
+ - `--dark-color-*`
348
+
349
+ Example:
350
+
351
+ ```css
352
+ @config "seyuna" {
353
+ --color-brand: 0.5 0.2 100;
354
+ --light-color-brand: 0.92 0.05 100;
355
+ }
356
+ ```
357
+
358
+ That keeps `brand` global by default but changes it when light mode is active.
359
+
360
+ ---
361
+
362
+ ## Full Configuration Reference
363
+
364
+ Within `@config "seyuna"`, the following prefixes are supported:
365
+
366
+ | Prefix | What it means | Used by |
367
+ | :----- | :------------ | :------ |
368
+ | `--hue-*` | Defines a standard color hue token | `SeyunaTone`, standard-color `SeyunaAlpha`, `SeyunaTint`, `SeyunaShade`, `SeyunaContrast` |
369
+ | `--color-*` | Defines a global fixed color as `lightness chroma hue` | `SeyunaSwatch`, fixed-color `SeyunaAlpha`, `SeyunaTint`, `SeyunaShade`, `SeyunaContrast` |
370
+ | `--light-lightness` | Sets the base `--lightness` for light mode | Standard colors in light mode |
371
+ | `--light-chroma` | Sets the base `--chroma` for light mode | Standard colors in light mode |
372
+ | `--dark-lightness` | Sets the base `--lightness` for dark mode | Standard colors in dark mode |
373
+ | `--dark-chroma` | Sets the base `--chroma` for dark mode | Standard colors in dark mode |
374
+ | `--light-background` | Sets `--background` in light mode | Your global/page styling |
375
+ | `--light-text` | Sets `--text` in light mode | Your global/page styling |
376
+ | `--dark-background` | Sets `--background` in dark mode | Your global/page styling |
377
+ | `--dark-text` | Sets `--text` in dark mode | Your global/page styling |
378
+ | `--light-color-*` | Overrides a fixed color in light mode | Fixed colors in light mode |
379
+ | `--dark-color-*` | Overrides a fixed color in dark mode | Fixed colors in dark mode |
380
+
381
+ If a value is malformed, Seyuna warns and skips it rather than generating broken CSS.
382
+
383
+ ---
384
+
385
+ ## Color Helper Functions
386
+
387
+ The `Seyuna` prefix is intentionally kept on the helper names so they are obviously custom and do not collide with CSS or other tooling.
388
+
389
+ | Function | What it returns | Best use |
390
+ | :------- | :-------------- | :------- |
391
+ | `SeyunaTone(name)` | A theme-aware standard color | Buttons, accents, semantic hues |
392
+ | `SeyunaSwatch(name)` | A fixed named color | Brand colors, literal palette tokens |
393
+ | `SeyunaAlpha(color, value)` | The same color with a different alpha | Borders, overlays, subtle backgrounds |
394
+ | `SeyunaTint(color, amount)` | A lighter version of the color | Hover states, active states |
395
+ | `SeyunaShade(color, amount)` | A darker version of the color | Pressed states, stronger contrast |
396
+ | `SeyunaContrast(color)` | A readable contrast color | Foreground text over token-driven backgrounds |
397
+
398
+ ### `SeyunaTone(name)`
399
+
400
+ Uses:
401
+
402
+ - `var(--lightness)`
403
+ - `var(--chroma)`
404
+ - `var(--name-hue)`
405
+
406
+ Example:
407
+
408
+ ```css
409
+ .button {
410
+ background: SeyunaTone(primary);
411
+ }
412
+ ```
413
+
414
+ ### `SeyunaSwatch(name)`
415
+
416
+ Uses:
417
+
418
+ - `var(--name-lightness)`
419
+ - `var(--name-chroma)`
420
+ - `var(--name-hue)`
421
+
422
+ Example:
423
+
424
+ ```css
425
+ .logo {
426
+ color: SeyunaSwatch(brand);
427
+ }
428
+ ```
429
+
430
+ ### `SeyunaAlpha(color, value)`
431
+
432
+ Keeps the same base color but changes the alpha channel.
433
+
434
+ Example:
435
+
436
+ ```css
437
+ .overlay {
438
+ background: SeyunaAlpha(primary, 0.12);
439
+ }
440
+ ```
441
+
442
+ ### `SeyunaTint(color, amount)`
443
+
444
+ Adds to the lightness value using `calc(...)`.
445
+
446
+ Example:
447
+
448
+ ```css
449
+ .button:hover {
450
+ background: SeyunaTint(primary, 0.08);
451
+ }
452
+ ```
453
+
454
+ ### `SeyunaShade(color, amount)`
455
+
456
+ Subtracts from the lightness value using `calc(...)`.
457
+
458
+ Example:
459
+
460
+ ```css
461
+ .button:active {
462
+ background: SeyunaShade(primary, 0.08);
463
+ }
464
+ ```
465
+
466
+ ### `SeyunaContrast(color)`
467
+
468
+ Returns a black-or-white-style readable contrast color based on the color's lightness.
469
+
470
+ Example:
471
+
472
+ ```css
473
+ .badge {
474
+ background: SeyunaTone(primary);
475
+ color: SeyunaContrast(primary);
476
+ }
477
+ ```
212
478
 
213
479
  ---
214
480
 
215
481
  ## Theme Switching
216
482
 
217
- Seyuna supports three modes: `light`, `dark`, and `system`. Control the active mode via the `data-mode` attribute:
483
+ Seyuna supports three modes:
484
+
485
+ - `light`
486
+ - `dark`
487
+ - `system`
488
+
489
+ Use the `data-mode` attribute on a parent element, usually `<html>`:
218
490
 
219
491
  ```html
220
492
  <html data-mode="system"></html>
221
493
  ```
222
494
 
223
- ### In-CSS Theme Overrides
495
+ Behavior:
496
+
497
+ - `[data-mode="light"]` forces the light palette
498
+ - `[data-mode="dark"]` forces the dark palette
499
+ - `[data-mode="system"]` follows `prefers-color-scheme`
224
500
 
225
- Need a component to look different in dark mode? Use the `@dark` and `@light` at-rules:
501
+ ### `@light` and `@dark`
502
+
503
+ You can write mode-specific overrides directly in CSS:
226
504
 
227
505
  ```css
228
506
  .card {
229
- background: SeyunaFixedColor(white);
507
+ background: SeyunaSwatch(white);
230
508
 
231
509
  @dark {
232
- background: SeyunaFixedColor(black);
510
+ background: SeyunaSwatch(black);
233
511
  }
234
512
  }
235
513
  ```
236
514
 
237
- Compiles to rules that target both explicit mode selection and system preferences.
515
+ This compiles to selectors for explicit mode choice and system preference behavior.
238
516
 
239
517
  ---
240
518
 
241
- ## Container Queries
519
+ ## Container Query Shortcuts
242
520
 
243
- Seyuna includes shorthand breakpoints that compile to CSS Container Queries:
521
+ Seyuna provides shorthand at-rules that compile to native `@container` rules:
244
522
 
245
523
  ```css
246
524
  .grid {
@@ -250,73 +528,83 @@ Seyuna includes shorthand breakpoints that compile to CSS Container Queries:
250
528
  @md {
251
529
  grid-template-columns: repeat(2, 1fr);
252
530
  }
253
-
254
- @lg {
255
- grid-template-columns: repeat(3, 1fr);
256
- }
257
531
  }
258
532
  ```
259
533
 
260
- | At-Rule | Container Width |
261
- | :------ | :-------------- |
262
- | `@xs` | 20rem |
263
- | `@sm` | 40rem |
264
- | `@md` | 48rem |
265
- | `@lg` | 64rem |
266
- | `@xl` | 80rem |
267
- | `@2xl` | 96rem |
534
+ Supported shorthands:
268
535
 
269
- Components respond to their container size, not the viewport. True component-based responsive design.
536
+ | At-rule | Expands to |
537
+ | :------ | :--------- |
538
+ | `@xs` | `@container (min-width: 20rem)` |
539
+ | `@sm` | `@container (min-width: 40rem)` |
540
+ | `@md` | `@container (min-width: 48rem)` |
541
+ | `@lg` | `@container (min-width: 64rem)` |
542
+ | `@xl` | `@container (min-width: 80rem)` |
543
+ | `@2xl` | `@container (min-width: 96rem)` |
544
+
545
+ These react to the container, not the viewport, so components stay reusable in nested layouts.
270
546
 
271
547
  ---
272
548
 
273
549
  ## Palette Iteration
274
550
 
275
- Generate utility classes by iterating over your color configuration:
551
+ Seyuna can generate repeated selectors from your token lists.
552
+
553
+ The recommended shape is to pass a selector template as the at-rule parameter. This keeps the CSS parseable while still letting you generate class selectors.
554
+
555
+ ### `@each-tone "<selector-template>"`
556
+
557
+ Iterates over the names in the standard hue map.
276
558
 
277
559
  ```css
278
- @each-standard-color {
279
- .bg-{name} {
280
- background-color: SeyunaStandardColor({name});
281
- }
560
+ @each-tone ".bg-{name}" {
561
+ background-color: SeyunaTone({name});
282
562
  }
563
+ ```
283
564
 
284
- @each-fixed-color {
285
- .text-{name} {
286
- color: SeyunaFixedColor({name});
287
- }
565
+ That generates selectors such as:
566
+
567
+ - `.bg-primary`
568
+ - `.bg-alpha`
569
+ - `.bg-omega`
570
+
571
+ ### `@each-swatch "<selector-template>"`
572
+
573
+ Iterates over fixed colors from:
574
+
575
+ - global fixed colors declared with `--color-*`
576
+ - light-mode fixed color overrides
577
+ - dark-mode fixed color overrides
578
+
579
+ ```css
580
+ @each-swatch ".text-{name}" {
581
+ color: SeyunaSwatch({name});
288
582
  }
289
583
  ```
290
584
 
291
- ---
292
-
293
- ## Configuration Properties
585
+ That generates selectors such as:
294
586
 
295
- Within the `@config "seyuna"` block, you can use the following property prefixes:
587
+ - `.text-white`
588
+ - `.text-black`
589
+ - `.text-brand`
296
590
 
297
- | Prefix | Description | Example |
298
- | :---------------- | :--------------------------------------------------------------- | :---------------------------------- |
299
- | `--hue-*` | Defines a hue angle for a standard color | `--hue-primary: 240;` |
300
- | `--color-*` | Defines a global fixed color (L C H) | `--color-brand: 0.6 0.2 120;` |
301
- | `--light-color-*` | Overrides a fixed color for light mode | `--light-color-brand: 0.8 0.1 120;` |
302
- | `--light-*` | Configures the light theme (lightness, chroma, background, text) | `--light-lightness: 0.8;` |
303
- | `--dark-color-*` | Overrides a fixed color for dark mode | `--dark-color-brand: 0.4 0.1 120;` |
304
- | `--dark-*` | Configures the dark theme | `--dark-background: 0 0 0;` |
591
+ `{name}` is replaced inside the selector template and inside declaration values.
305
592
 
306
- For colors and background/text, use a space-separated list of values: `lightness chroma hue`.
593
+ If you write nested parseable selectors inside the block, Seyuna still replaces `{name}` there as well. But for class generation, the selector-template parameter is the easiest and safest approach.
307
594
 
308
595
  ---
309
596
 
310
- ## Accessing Config Values
597
+ ## Common Gotchas
311
598
 
312
- Use `SeyunaTheme()` to access any value from your design tokens:
599
+ - Run Seyuna early in the PostCSS chain.
600
+ - Keep `@seyuna;` to a single final injection point.
601
+ - Do not use the same token name for both a hue and a fixed color unless you intentionally want both variable shapes to exist.
602
+ - If CSS is split across files, make sure the files containing `@config "seyuna"` and `@seyuna;` are processed together in the same build pipeline.
603
+ - Prefer selector templates for palette iteration, e.g. `@each-tone ".bg-{name}"`.
313
604
 
314
- ```css
315
- .container {
316
- max-width: SeyunaTheme(ui.theme.breakpoints.lg);
317
- }
318
- ```
605
+ If output looks wrong, check plugin order first. That is the most common source of problems.
319
606
 
607
+ ---
320
608
  ---
321
609
 
322
610
  ## License