css-is-awesome 1.16.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -148,7 +148,7 @@ Authoring template (in your own project — a theme file is a global stylesheet,
148
148
 
149
149
  `$standalone` defaults to `true` (emit `:root, :root[data-theme="<name>"]`). Pass `$standalone: false` only when your block is going into a multi-theme bundle where the bare `:root` would collide.
150
150
 
151
- The validator (`node scripts/theme-validator.js`) enforces the token contract — **127 required + 36 optional = 163 slots** — plus WCAG 2.2 AA contrast (**22 audited pairs per theme**, including five `--code-*` pairs). Themes that miss required tokens or fail contrast cannot ship without `--allow-a11y-fail`.
151
+ The validator (`node scripts/theme-validator.js`) enforces the token contract — **127 required + 41 optional = 168 slots** — plus WCAG 2.2 AA contrast (**22 audited pairs per theme**, including five `--code-*` pairs). Themes that miss required tokens or fail contrast cannot ship without `--allow-a11y-fail`.
152
152
 
153
153
  ### Theming spacing (new — read this before you set a size token)
154
154
 
@@ -168,7 +168,7 @@ Why it matters: components call `cia.space(4)`, which resolves to `var(--space-4
168
168
 
169
169
  Two `<link media>` themes still work under the new selector model: a stylesheet whose `media` doesn't match is loaded but never applied, so only the matching file's `:root` block lands.
170
170
 
171
- Validator: `node scripts/theme-validator.js path/to/theme.css` (or `--all` for every shipped theme). Every theme must declare every required contract token (127 required in v1; missing tokens always fail). The audit also runs a WCAG 2.2 AA contrast check over 22 pairs; **a11y FAILs are fatal by default** as of v0.7. Pass `--allow-a11y-fail` to downgrade contrast failures to a report-only warning (the older `--strict` flag is accepted as a no-op alias). `--border-default` is treated as decorative per WCAG 2.2 SC 1.4.11 and reports as info, not FAIL.
171
+ Validator: `node scripts/theme-validator.js path/to/theme.css` (or `--all` for every shipped theme). Every theme must declare every required contract token (127 required in contract 1.1; missing required tokens always fail, missing optional ones are reported as info). The audit also runs a WCAG 2.2 AA contrast check over 22 pairs; **a11y FAILs are fatal by default** as of v0.7. Pass `--allow-a11y-fail` to downgrade contrast failures to a report-only warning (the older `--strict` flag is accepted as a no-op alias). `--border-default` is treated as decorative per WCAG 2.2 SC 1.4.11 and reports as info, not FAIL.
172
172
 
173
173
  ### Theme init (Next.js / SSR consumers)
174
174
 
@@ -338,21 +338,21 @@ Or run this in-repo copy directly — needs its SDK peer deps installed manually
338
338
  }
339
339
  ```
340
340
 
341
- Either way it exposes **31 tools** across 8 families:
341
+ Either way it exposes **32 tools** across 8 families:
342
342
 
343
343
  - **Themes** — `list_themes`, `get_theme`, `search_themes`
344
344
  - **Mixins** — `list_mixins`, `get_mixin`, `search_mixins` (real signatures — don't guess)
345
345
  - **Functions** — `list_functions`, `get_function`, `search_functions`
346
- - **Tokens** — `list_tokens`, `get_token`, `search_tokens` (127 required + 36 optional contract tokens)
346
+ - **Tokens** — `list_tokens`, `get_token`, `search_tokens` (127 required + 41 optional contract tokens)
347
347
  - **Animations** — `list_animations`, `get_animation`
348
348
  - **Components** — `list_components`, `get_component`, `search_components`
349
349
  - **Recipes** — `list_recipes`, `get_recipe`
350
350
  - **Doc readers** — `read_llm_txt`, `read_changelog`, `read_migration`, `read_theming`, `read_agents`, `read_contract`, `read_three_tiers`, `read_readme`, `read_versioning`
351
- - **Helpers** — `assemble_prompt` (bundle context), `resolve_size` (snap a design px value to cia's 4px grid — call this whenever a design tool hands you a raw px value), `validate_theme` (run the real theme validator — contract + contrast — on a CSS string before you ship it)
351
+ - **Helpers** — `assemble_prompt` (bundle context), `resolve_size` (snap a design px value to cia's 4px grid — call this whenever a design tool hands you a raw px value), `validate_theme` (run the real theme validator — contract + contrast — on a CSS string before you ship it), `theme_from_tokens` (DTCG / Tokens Studio / flat token JSON → a complete theme.css, base-inherited and validated; same function as `cia theme from-tokens`)
352
352
 
353
353
  ## Other tooling (shipped)
354
354
 
355
- - **`cia` CLI** — ships as `bin/cia.cjs`, exposed as the `cia` bin. Three verbs:
355
+ - **`cia` CLI** — ships as `bin/cia.cjs`, exposed as the `cia` bin. Four verbs:
356
356
  `npx cia migrate tailwind|bootstrap [path]` parses another system's config and
357
357
  dumps a cia theme; `npx cia add <recipe>` (`--list` to browse) copies a recipe
358
358
  from the book into the project — own the pattern; `npx cia analyze [path]`
@@ -360,9 +360,14 @@ Either way it exposes **31 tools** across 8 families:
360
360
  the `space()` 1–9 scale trap, off-contract tokens (near-miss typos only), hard-coded
361
361
  hex colors, BEM chains — with a health score and CI-ready exit codes. Low-noise on
362
362
  color: a hex in a `var(--token, #hex)` fallback is token-driven, and a literal inside
363
- `@media print` is an intentional paper colour — neither is flagged. Run any verb with `--help`. (`cia init` remains
363
+ `@media print` is an intentional paper colour — neither is flagged; `npx cia theme from-tokens <tokens.json> --name <slug>`
364
+ turns a design-tokens file (DTCG v2025.10, Tokens Studio for Figma, or a flat `--token` map; format auto-detected)
365
+ into a complete theme.css — every required token the file lacks inherits from a shipped base theme (`--base`,
366
+ default boilerplate), unmapped paths pass through verbatim and are reported, a `--dark` file or paired
367
+ `color-light`/`color-dark` groups become `light-dark()`, and the validator + WCAG audit run before anything is
368
+ written. Same function as the MCP `theme_from_tokens` tool. Run any verb with `--help`. (`cia init` remains
364
369
  planned.)
365
- - **JSON token export** — DTCG-format token list in `figma-tokens/`.
370
+ - **JSON token export** — Tokens Studio-format sample in `figma-tokens/tokens.json`; it round-trips through `cia theme from-tokens` (paired light/dark groups → one `light-dark()` theme).
366
371
  - **`llm.txt`** — at the repo root and served from the docs site; single-fetch
367
372
  summary for any AI agent. Also readable over MCP via `read_llm_txt`.
368
373
 
package/CHANGELOG.md CHANGED
@@ -1,3 +1,28 @@
1
+ # Changelog
2
+
3
+ # [1.17.0](https://github.com/Jerry2d3d/css-is-awesome/compare/v1.16.1...v1.17.0) (2026-09-19)
4
+
5
+
6
+ ### Features
7
+
8
+ * **cli:** cia theme from-tokens — design-tokens JSON → validated theme.css ([066b484](https://github.com/Jerry2d3d/css-is-awesome/commit/066b4849d2e937f0362e8f21cb212f3fcc144c5f))
9
+ * **mcp:** theme_from_tokens tool + in-process handler (32 tools) ([9dc90c4](https://github.com/Jerry2d3d/css-is-awesome/commit/9dc90c40574a5e21b7b724f97792b0fd9c4182b0))
10
+
11
+ ## [1.16.1](https://github.com/Jerry2d3d/css-is-awesome/compare/v1.16.0...v1.16.1) (2026-09-18)
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * **contract:** --space-unit is optional, not required — contract 1.1 + CI growth gate ([42292ff](https://github.com/Jerry2d3d/css-is-awesome/commit/42292ff995a3e6d7fa1623404614f3519e30a284))
17
+
18
+
19
+ ### Features
20
+
21
+ * **site:** "Try in playground" on every recipe page ([9d2c7cc](https://github.com/Jerry2d3d/css-is-awesome/commit/9d2c7cc18399ff0c55c5c986ed70bdd9b6e1ddb5))
22
+ * **site:** /playground — in-browser Sass compile, CodeMirror panes, live preview ([c1474e4](https://github.com/Jerry2d3d/css-is-awesome/commit/c1474e40bfecaa7bd7b742ca545bf7f8f6756021))
23
+ * **site:** link the playground from the nav, the docs intro and the README ([9acabcc](https://github.com/Jerry2d3d/css-is-awesome/commit/9acabcc66f84e30f83cc8a7ff01e4845635ee2c4))
24
+ * **site:** playground groundwork — scss source map, [@use](https://github.com/use) resolver, share codec ([f5fb619](https://github.com/Jerry2d3d/css-is-awesome/commit/f5fb619d5b3d11dff9c77beeb77cd192b4b6d090))
25
+
1
26
  # [1.16.0](https://github.com/Jerry2d3d/css-is-awesome/compare/v1.15.0...v1.16.0) (2026-09-17)
2
27
 
3
28
 
@@ -400,132 +425,17 @@
400
425
  * **site:** print the story, not the chrome — dogfoods cia's print mixins ([ece519c](https://github.com/Jerry2d3d/css-is-awesome/commit/ece519c43f62230e1b3392538dae5148fc31ddf6))
401
426
  * **themes:** themes own the spacing rhythm, not just the palette ([4bc1e24](https://github.com/Jerry2d3d/css-is-awesome/commit/4bc1e24f1b64f33cacd35f3bab12327019634fea))
402
427
 
403
- # [1.1.0](https://github.com/Jerry2d3d/css-is-awesome/compare/v1.0.0...v1.1.0) (2026-09-01)
404
-
405
-
406
- ### Bug Fixes
407
-
408
- * **a11y:** copy button used code-surface ink on a page-surface background ([bf84bf4](https://github.com/Jerry2d3d/css-is-awesome/commit/bf84bf4d6c23e3ebafdb5dc98a303d9961d68714))
409
- * **a11y:** validator ignored unquoted [data-theme]; grade the code palette ([2437f41](https://github.com/Jerry2d3d/css-is-awesome/commit/2437f4182ddccc01b372d9aacd898b6222fcabd3)), closes [#fafafa](https://github.com/Jerry2d3d/css-is-awesome/issues/fafafa) [#0a0a0a](https://github.com/Jerry2d3d/css-is-awesome/issues/0a0a0a)
410
- * **ci:** snapshot job installed chromium but ran all three engines ([f7b7fc9](https://github.com/Jerry2d3d/css-is-awesome/commit/f7b7fc9e29883863c6a525f44391e6eb4b4b9662))
411
- * **ci:** snapshot workflow silently discarded the baselines it created ([3358cac](https://github.com/Jerry2d3d/css-is-awesome/commit/3358cacb6fbf88d9dcf0109597bed301efeda483))
412
- * **compare:** correct every measurable claim on the comparison page ([3d1b602](https://github.com/Jerry2d3d/css-is-awesome/commit/3d1b602ff6074712a2e2d0aea5a1ad27128d2d70))
413
- * **pkg:** build dist/ on git installs via a prepare hook ([1a0deb1](https://github.com/Jerry2d3d/css-is-awesome/commit/1a0deb19e4fc6de15b7b3530847779920d01d784))
414
- * **print:** stop the freeze from flattening deliberate opacity and transform ([1af51d2](https://github.com/Jerry2d3d/css-is-awesome/commit/1af51d2e3a08cd61e51ac3b857eeaa261afd044e))
415
- * root barrel emitted no tokens; retract the false Turbopack claim ([d7f71e3](https://github.com/Jerry2d3d/css-is-awesome/commit/d7f71e366a1ef4b918cfcfd6dafcba8d352afcb5))
416
- * **sass:** stop using the deprecated if() function; sharpen the AI on-ramp ([61df05a](https://github.com/Jerry2d3d/css-is-awesome/commit/61df05a31228fce169664690c2562d128bf06958))
417
- * **site:** moat card uses grid; Tailwind sample updated to Headless UI v2 ([cb39e44](https://github.com/Jerry2d3d/css-is-awesome/commit/cb39e44b4eb8d7ab1a86377c1d828b1cde3ed58b))
418
- * **site:** moat code blocks now fill their card ([8e53d35](https://github.com/Jerry2d3d/css-is-awesome/commit/8e53d355b0f9279125b9dfd6f913851cf2ebcdc3))
419
- * six upstream bugs from the Boiler audit (BUG-1..7) ([84f4c4f](https://github.com/Jerry2d3d/css-is-awesome/commit/84f4c4fc6f6259bf74541a833fe0ad343821ab12))
420
- * **themes:** prism was missing from every theme picker ([4ce4f5f](https://github.com/Jerry2d3d/css-is-awesome/commit/4ce4f5f8a696728b513aa1adc148b33c5808e26e))
421
-
422
-
423
- ### Features
424
-
425
- * **animate:** accept a raw duration; add letter-spacing() coverage fixture ([25b7cd6](https://github.com/Jerry2d3d/css-is-awesome/commit/25b7cd6cbc09d76b51c9dd0b74077ec1af78c327))
426
- * **blog:** real posts from real commits, replacing seven dead stubs ([f37c5be](https://github.com/Jerry2d3d/css-is-awesome/commit/f37c5be94cd64f99548a6a119820325d559e6920))
427
- * **site:** print the story, not the chrome — dogfoods cia's print mixins ([ece519c](https://github.com/Jerry2d3d/css-is-awesome/commit/ece519c43f62230e1b3392538dae5148fc31ddf6))
428
- * **themes:** themes own the spacing rhythm, not just the palette ([4bc1e24](https://github.com/Jerry2d3d/css-is-awesome/commit/4bc1e24f1b64f33cacd35f3bab12327019634fea))
429
-
430
- # [1.1.0](https://github.com/Jerry2d3d/css-is-awesome/compare/v1.0.0...v1.1.0) (2026-09-01)
431
-
432
-
433
- ### Bug Fixes
434
-
435
- * **a11y:** copy button used code-surface ink on a page-surface background ([bf84bf4](https://github.com/Jerry2d3d/css-is-awesome/commit/bf84bf4d6c23e3ebafdb5dc98a303d9961d68714))
436
- * **a11y:** validator ignored unquoted [data-theme]; grade the code palette ([2437f41](https://github.com/Jerry2d3d/css-is-awesome/commit/2437f4182ddccc01b372d9aacd898b6222fcabd3)), closes [#fafafa](https://github.com/Jerry2d3d/css-is-awesome/issues/fafafa) [#0a0a0a](https://github.com/Jerry2d3d/css-is-awesome/issues/0a0a0a)
437
- * **ci:** snapshot job installed chromium but ran all three engines ([f7b7fc9](https://github.com/Jerry2d3d/css-is-awesome/commit/f7b7fc9e29883863c6a525f44391e6eb4b4b9662))
438
- * **ci:** snapshot workflow silently discarded the baselines it created ([3358cac](https://github.com/Jerry2d3d/css-is-awesome/commit/3358cacb6fbf88d9dcf0109597bed301efeda483))
439
- * **compare:** correct every measurable claim on the comparison page ([3d1b602](https://github.com/Jerry2d3d/css-is-awesome/commit/3d1b602ff6074712a2e2d0aea5a1ad27128d2d70))
440
- * **pkg:** build dist/ on git installs via a prepare hook ([1a0deb1](https://github.com/Jerry2d3d/css-is-awesome/commit/1a0deb19e4fc6de15b7b3530847779920d01d784))
441
- * **print:** stop the freeze from flattening deliberate opacity and transform ([1af51d2](https://github.com/Jerry2d3d/css-is-awesome/commit/1af51d2e3a08cd61e51ac3b857eeaa261afd044e))
442
- * root barrel emitted no tokens; retract the false Turbopack claim ([d7f71e3](https://github.com/Jerry2d3d/css-is-awesome/commit/d7f71e366a1ef4b918cfcfd6dafcba8d352afcb5))
443
- * **sass:** stop using the deprecated if() function; sharpen the AI on-ramp ([61df05a](https://github.com/Jerry2d3d/css-is-awesome/commit/61df05a31228fce169664690c2562d128bf06958))
444
- * **site:** moat card uses grid; Tailwind sample updated to Headless UI v2 ([cb39e44](https://github.com/Jerry2d3d/css-is-awesome/commit/cb39e44b4eb8d7ab1a86377c1d828b1cde3ed58b))
445
- * **site:** moat code blocks now fill their card ([8e53d35](https://github.com/Jerry2d3d/css-is-awesome/commit/8e53d355b0f9279125b9dfd6f913851cf2ebcdc3))
446
- * six upstream bugs from the Boiler audit (BUG-1..7) ([84f4c4f](https://github.com/Jerry2d3d/css-is-awesome/commit/84f4c4fc6f6259bf74541a833fe0ad343821ab12))
447
- * **themes:** prism was missing from every theme picker ([4ce4f5f](https://github.com/Jerry2d3d/css-is-awesome/commit/4ce4f5f8a696728b513aa1adc148b33c5808e26e))
448
-
449
-
450
- ### Features
451
-
452
- * **animate:** accept a raw duration; add letter-spacing() coverage fixture ([25b7cd6](https://github.com/Jerry2d3d/css-is-awesome/commit/25b7cd6cbc09d76b51c9dd0b74077ec1af78c327))
453
- * **blog:** real posts from real commits, replacing seven dead stubs ([f37c5be](https://github.com/Jerry2d3d/css-is-awesome/commit/f37c5be94cd64f99548a6a119820325d559e6920))
454
- * **site:** print the story, not the chrome — dogfoods cia's print mixins ([ece519c](https://github.com/Jerry2d3d/css-is-awesome/commit/ece519c43f62230e1b3392538dae5148fc31ddf6))
455
- * **themes:** themes own the spacing rhythm, not just the palette ([4bc1e24](https://github.com/Jerry2d3d/css-is-awesome/commit/4bc1e24f1b64f33cacd35f3bab12327019634fea))
456
-
457
- # [1.1.0](https://github.com/Jerry2d3d/css-is-awesome/compare/v1.0.0...v1.1.0) (2026-08-30)
458
-
459
-
460
- ### Bug Fixes
461
-
462
- * **a11y:** copy button used code-surface ink on a page-surface background ([bf84bf4](https://github.com/Jerry2d3d/css-is-awesome/commit/bf84bf4d6c23e3ebafdb5dc98a303d9961d68714))
463
- * **a11y:** validator ignored unquoted [data-theme]; grade the code palette ([2437f41](https://github.com/Jerry2d3d/css-is-awesome/commit/2437f4182ddccc01b372d9aacd898b6222fcabd3)), closes [#fafafa](https://github.com/Jerry2d3d/css-is-awesome/issues/fafafa) [#0a0a0a](https://github.com/Jerry2d3d/css-is-awesome/issues/0a0a0a)
464
- * **ci:** snapshot job installed chromium but ran all three engines ([f7b7fc9](https://github.com/Jerry2d3d/css-is-awesome/commit/f7b7fc9e29883863c6a525f44391e6eb4b4b9662))
465
- * **ci:** snapshot workflow silently discarded the baselines it created ([3358cac](https://github.com/Jerry2d3d/css-is-awesome/commit/3358cacb6fbf88d9dcf0109597bed301efeda483))
466
- * **compare:** correct every measurable claim on the comparison page ([3d1b602](https://github.com/Jerry2d3d/css-is-awesome/commit/3d1b602ff6074712a2e2d0aea5a1ad27128d2d70))
467
- * **pkg:** build dist/ on git installs via a prepare hook ([1a0deb1](https://github.com/Jerry2d3d/css-is-awesome/commit/1a0deb19e4fc6de15b7b3530847779920d01d784))
468
- * **print:** stop the freeze from flattening deliberate opacity and transform ([1af51d2](https://github.com/Jerry2d3d/css-is-awesome/commit/1af51d2e3a08cd61e51ac3b857eeaa261afd044e))
469
- * root barrel emitted no tokens; retract the false Turbopack claim ([d7f71e3](https://github.com/Jerry2d3d/css-is-awesome/commit/d7f71e366a1ef4b918cfcfd6dafcba8d352afcb5))
470
- * **sass:** stop using the deprecated if() function; sharpen the AI on-ramp ([61df05a](https://github.com/Jerry2d3d/css-is-awesome/commit/61df05a31228fce169664690c2562d128bf06958))
471
- * **site:** moat card uses grid; Tailwind sample updated to Headless UI v2 ([cb39e44](https://github.com/Jerry2d3d/css-is-awesome/commit/cb39e44b4eb8d7ab1a86377c1d828b1cde3ed58b))
472
- * **site:** moat code blocks now fill their card ([8e53d35](https://github.com/Jerry2d3d/css-is-awesome/commit/8e53d355b0f9279125b9dfd6f913851cf2ebcdc3))
473
- * six upstream bugs from the Boiler audit (BUG-1..7) ([84f4c4f](https://github.com/Jerry2d3d/css-is-awesome/commit/84f4c4fc6f6259bf74541a833fe0ad343821ab12))
474
- * **themes:** prism was missing from every theme picker ([4ce4f5f](https://github.com/Jerry2d3d/css-is-awesome/commit/4ce4f5f8a696728b513aa1adc148b33c5808e26e))
475
-
476
-
477
- ### Features
478
-
479
- * **animate:** accept a raw duration; add letter-spacing() coverage fixture ([25b7cd6](https://github.com/Jerry2d3d/css-is-awesome/commit/25b7cd6cbc09d76b51c9dd0b74077ec1af78c327))
480
- * **blog:** real posts from real commits, replacing seven dead stubs ([f37c5be](https://github.com/Jerry2d3d/css-is-awesome/commit/f37c5be94cd64f99548a6a119820325d559e6920))
481
- * **site:** print the story, not the chrome — dogfoods cia's print mixins ([ece519c](https://github.com/Jerry2d3d/css-is-awesome/commit/ece519c43f62230e1b3392538dae5148fc31ddf6))
482
- * **themes:** themes own the spacing rhythm, not just the palette ([4bc1e24](https://github.com/Jerry2d3d/css-is-awesome/commit/4bc1e24f1b64f33cacd35f3bab12327019634fea))
483
-
484
- ## [1.1.1](https://github.com/Jerry2d3d/css-is-awesome/compare/v1.1.0...v1.1.1) (2026-08-30)
485
-
486
-
487
- ### Bug Fixes
488
-
489
- * **sass:** stop using the deprecated if() function; sharpen the AI on-ramp ([61df05a](https://github.com/Jerry2d3d/css-is-awesome/commit/61df05a31228fce169664690c2562d128bf06958))
490
-
491
- # [1.1.0](https://github.com/Jerry2d3d/css-is-awesome/compare/v1.0.0...v1.1.0) (2026-08-30)
492
-
493
-
494
- ### Bug Fixes
495
-
496
- * **a11y:** copy button used code-surface ink on a page-surface background ([bf84bf4](https://github.com/Jerry2d3d/css-is-awesome/commit/bf84bf4d6c23e3ebafdb5dc98a303d9961d68714))
497
- * **a11y:** validator ignored unquoted [data-theme]; grade the code palette ([2437f41](https://github.com/Jerry2d3d/css-is-awesome/commit/2437f4182ddccc01b372d9aacd898b6222fcabd3)), closes [#fafafa](https://github.com/Jerry2d3d/css-is-awesome/issues/fafafa) [#0a0a0a](https://github.com/Jerry2d3d/css-is-awesome/issues/0a0a0a)
498
- * **ci:** snapshot job installed chromium but ran all three engines ([f7b7fc9](https://github.com/Jerry2d3d/css-is-awesome/commit/f7b7fc9e29883863c6a525f44391e6eb4b4b9662))
499
- * **ci:** snapshot workflow silently discarded the baselines it created ([3358cac](https://github.com/Jerry2d3d/css-is-awesome/commit/3358cacb6fbf88d9dcf0109597bed301efeda483))
500
- * **compare:** correct every measurable claim on the comparison page ([3d1b602](https://github.com/Jerry2d3d/css-is-awesome/commit/3d1b602ff6074712a2e2d0aea5a1ad27128d2d70))
501
- * **pkg:** build dist/ on git installs via a prepare hook ([1a0deb1](https://github.com/Jerry2d3d/css-is-awesome/commit/1a0deb19e4fc6de15b7b3530847779920d01d784))
502
- * **print:** stop the freeze from flattening deliberate opacity and transform ([1af51d2](https://github.com/Jerry2d3d/css-is-awesome/commit/1af51d2e3a08cd61e51ac3b857eeaa261afd044e))
503
- * root barrel emitted no tokens; retract the false Turbopack claim ([d7f71e3](https://github.com/Jerry2d3d/css-is-awesome/commit/d7f71e366a1ef4b918cfcfd6dafcba8d352afcb5))
504
- * **site:** moat card uses grid; Tailwind sample updated to Headless UI v2 ([cb39e44](https://github.com/Jerry2d3d/css-is-awesome/commit/cb39e44b4eb8d7ab1a86377c1d828b1cde3ed58b))
505
- * **site:** moat code blocks now fill their card ([8e53d35](https://github.com/Jerry2d3d/css-is-awesome/commit/8e53d355b0f9279125b9dfd6f913851cf2ebcdc3))
506
- * six upstream bugs from the Boiler audit (BUG-1..7) ([84f4c4f](https://github.com/Jerry2d3d/css-is-awesome/commit/84f4c4fc6f6259bf74541a833fe0ad343821ab12))
507
- * **themes:** prism was missing from every theme picker ([4ce4f5f](https://github.com/Jerry2d3d/css-is-awesome/commit/4ce4f5f8a696728b513aa1adc148b33c5808e26e))
508
-
509
-
510
- ### Features
511
-
512
- * **animate:** accept a raw duration; add letter-spacing() coverage fixture ([25b7cd6](https://github.com/Jerry2d3d/css-is-awesome/commit/25b7cd6cbc09d76b51c9dd0b74077ec1af78c327))
513
- * **blog:** real posts from real commits, replacing seven dead stubs ([f37c5be](https://github.com/Jerry2d3d/css-is-awesome/commit/f37c5be94cd64f99548a6a119820325d559e6920))
514
- * **site:** print the story, not the chrome — dogfoods cia's print mixins ([ece519c](https://github.com/Jerry2d3d/css-is-awesome/commit/ece519c43f62230e1b3392538dae5148fc31ddf6))
515
- * **themes:** themes own the spacing rhythm, not just the palette ([4bc1e24](https://github.com/Jerry2d3d/css-is-awesome/commit/4bc1e24f1b64f33cacd35f3bab12327019634fea))
516
-
517
- # Changelog
518
-
519
- All notable changes to this project will be documented in this file.
428
+ ---
520
429
 
521
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
522
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
430
+ ## Hand-written history (before automated releases)
523
431
 
524
- **See also:** [`VERSIONING.md`](./VERSIONING.md) — version policy, deprecation
525
- lifecycle, and the Conventional Commits → changelog section mapping that drives
526
- automated releases.
432
+ > Everything above this line is generated by `semantic-release`. Everything
433
+ > below was written by hand, up to and including the launch notes for 1.1.0
434
+ > (the first version published to npm, 2026-09-01). The generated 1.1.0 entry
435
+ > above is the terse commit list; the section right below is the same release
436
+ > explained.
527
437
 
528
- ## [Unreleased]
438
+ ## [1.1.0] — 2026-09-01 — launch notes (hand-written detail for the generated entry above)
529
439
 
530
440
  > Ships as **1.1.0** — the first release actually published to npm. `1.0.0` was
531
441
  > tagged but never published. The number is computed by `semantic-release` from
package/CONTRACT.md CHANGED
@@ -223,6 +223,7 @@ The **numbered scale is the source of truth and is contract-required**: a theme
223
223
  | Token | Type | Example (default rhythm) | Purpose |
224
224
  | --------------------------- | ------ | --------------------------------- | -------------------------------- |
225
225
  | `--space-0` … `--space-9` | length | `0`, `0.25rem`, `0.5rem`, … `6rem` | The numbered scale — **required** |
226
+ | `--space-unit` | length | `0.25rem` | The density knob — **optional** (contract 1.1). Shipped themes derive every `--space-N` from it via `calc()`; a hand-written theme that declares absolute `--space-N` values never references it, so nothing breaks without it. It was listed as *required* by mistake in library 1.12.0–1.16.0. |
226
227
 
227
228
  The t-shirt names are **optional aliases**. The library emits `xs`–`xl` as `var()` references into the numbered scale, so they follow it automatically; `--space-2xs` sits outside the numbered scale and emits as a literal:
228
229
 
package/MIGRATION.md CHANGED
@@ -2,6 +2,154 @@
2
2
 
3
3
  Breaking changes between css-is-awesome versions, and how to migrate.
4
4
 
5
+ ## v1.0 — mixin-first goes stable (published as 1.1.0)
6
+
7
+ **There are no breaking changes between v0.8.1/0.8.2 and v1.0.0.** 1.0.0
8
+ (tagged 2026-08-17) is the point at which the v0.8 mixin-first surface —
9
+ mixins, functions, token contract, theme architecture — became stable under
10
+ strict SemVer (see [`VERSIONING.md`](./VERSIONING.md)). Every mixin you called
11
+ in v0.8.1 compiles unchanged in v1.x; `npm run validate-api` guards the barrel
12
+ surface on every commit. The 67 commits between 0.8.2 and 1.0.0 carry no
13
+ rename, removal or signature change.
14
+
15
+ 1.0.0 itself was never published to npm. The first published release is
16
+ **1.1.0 (2026-09-01)**, so upgrading from v0.8 in practice means landing on
17
+ 1.1.x — and that release does carry **one action-required change for authors
18
+ of custom themes** (section 2 below). Consumers of the shipped themes have
19
+ nothing to do.
20
+
21
+ ### What changed at a glance
22
+
23
+ | Area | v0.8.x | v1.x |
24
+ |---|---|---|
25
+ | Component stylesheet import | `@use 'css-is-awesome/scss/mixins' as m` (deep path) or the emitting bundle | **`@use 'css-is-awesome/api' as cia`** — zero-emit barrel, safe in CSS Modules (additive; the deep paths still work) |
26
+ | Root-level `@use 'css-is-awesome'` | Worked only via the deep `scss/…` paths on a clean install | **Resolves on a clean install** — root shims `api.scss` + `_index.scss` shipped (Sass ignores `package.json` `exports`) |
27
+ | Custom-theme contract | `--space-{2xs,xs,sm,md,lg,xl}` required | **`--space-0` … `--space-9` required**, t-shirt names optional (1.1.0 — validator fails an unconverted theme) |
28
+ | Six `--radius-{button,card,input,modal,badge,avatar}` tokens | Required of every theme, read by nothing | **Dropped from the contract** — the live knobs are `--btn-radius`, `--card-radius`, … |
29
+ | Library defaults selector | `:root { … }` (tied a drop-in theme at 0,1,0 — library won) | **`:where(:root) { … }`** — a theme's bare `:root` always wins |
30
+ | `theme()` mixin output | Inconsistent (`:root`, `[data-theme]`, or `:root[data-theme]`) | **`:root, :root[data-theme="<name>"]`** — drop-in with no markup change; `$standalone: false` for bundles |
31
+ | `spinner` / `skeleton` keyframes | Emitted at module top level on import (leaked; CSS Modules renamed them) | **Emitted via `@at-root` inside the mixin** — only when called |
32
+ | Print / PDF | — | **New**: `print`, `print-base`, `print-hidden`, `print-only` mixins + `print-to-pdf` recipe |
33
+
34
+ ### 1. Adopt the two-import model (recommended, not required)
35
+
36
+ v0.8 consumers typically imported the whole library into every component
37
+ stylesheet, or reached for the deep `scss/mixins` path. Both still compile.
38
+ The v1 shape separates the two jobs:
39
+
40
+ ```scss
41
+ // app/globals.scss — loaded ONCE at the app root. Emits :root tokens + base.
42
+ @use 'css-is-awesome';
43
+
44
+ // Card.module.scss — per component. Emits NOTHING until a mixin is called,
45
+ // so it is safe under Next.js CSS Modules "pure" mode.
46
+ @use 'css-is-awesome/api' as cia;
47
+ .card { @include cia.card-base($shadow: 2); background: cia.color(surface-default); }
48
+ ```
49
+
50
+ If you were on the deep path, the swap is one line:
51
+
52
+ ```scss
53
+ // v0.8
54
+ @use 'css-is-awesome/scss/mixins' as m;
55
+ .btn { @include m.btn(primary); }
56
+
57
+ // v1.x — same mixins, one namespace for the whole API (layout + components too)
58
+ @use 'css-is-awesome/api' as cia;
59
+ .btn { @include cia.btn(primary); }
60
+ ```
61
+
62
+ `m.` was only ever the `_mixins.scss` leaf; `cia.` forwards every module, so
63
+ `cia.stack`, `cia.card-base` and `cia.print-base` are all reachable without a
64
+ second import. Deep paths remain supported for anyone who prefers them.
65
+
66
+ ### 2. Custom themes: declare `--space-0` … `--space-9` (1.1.0, action required)
67
+
68
+ In v0.8 a theme could satisfy the contract with the six t-shirt spacing
69
+ names, but components read the numbered scale (`space(4)` → `var(--space-4)`),
70
+ so a theme's spacing was never actually applied. 1.1.0 makes the numbered
71
+ scale the required source of truth and turns the t-shirt names into optional
72
+ aliases that reference it.
73
+
74
+ ```css
75
+ /* v0.8 custom theme — passes the old validator, but components ignored it */
76
+ :root[data-theme="brand"] {
77
+ --space-xs: 4px; --space-sm: 8px; --space-md: 16px;
78
+ --space-lg: 24px; --space-xl: 32px; --space-2xs: 2px;
79
+ }
80
+
81
+ /* v1.x custom theme — required. `npm run validate-themes` fails without it. */
82
+ :root[data-theme="brand"] {
83
+ --space-0: 0; --space-1: 4px; --space-2: 8px; --space-3: 12px;
84
+ --space-4: 16px; --space-5: 24px; --space-6: 32px; --space-7: 48px;
85
+ --space-8: 64px; --space-9: 96px;
86
+ /* optional aliases — keep them only if your own CSS reads them */
87
+ --space-md: var(--space-4);
88
+ }
89
+ ```
90
+
91
+ Shipped themes were all converted; if you copied one as a starting point,
92
+ re-copy its spacing block. `--space-unit` (the density knob, 1.12.0) is
93
+ **optional** — since contract 1.1 (library 1.16.1) the validator reports a
94
+ missing optional token as info, never a failure; between 1.12.0 and 1.16.0 it
95
+ was wrongly listed as required, which is why a custom theme could fail
96
+ validation after a minor upgrade. (Later 1.x releases derive the whole scale from a
97
+ single `--space-unit`; see the theme authoring docs for the current shape.)
98
+
99
+ While you are in the file: the six `--radius-button` / `-card` / `-input` /
100
+ `-modal` / `-badge` / `-avatar` tokens can be deleted. Nothing read them. The
101
+ per-component radius knobs that do work are `--btn-radius`, `--card-radius`,
102
+ `--input-radius`, `--modal-radius`, `--badge-radius` and `--tag-radius`.
103
+
104
+ ### 3. Drop-in themes need no markup (1.1.0, behaviour change, no action)
105
+
106
+ Two changes make a single theme file work when dropped into any page:
107
+
108
+ - Library defaults now emit under `:where(:root)` (specificity 0,0,0). In
109
+ v0.8 the library's own `:root` tied a theme's `:root` and, loading second,
110
+ won — so a drop-in theme rendered an untokenised page unless you also set
111
+ `<html data-theme>`. Specificity only *decreased*, so nothing that used to
112
+ win can start losing.
113
+ - `cia.theme('name')` now emits `:root, :root[data-theme="name"]`. If you build
114
+ a multi-theme bundle yourself, pass `$standalone: false` so twenty blocks
115
+ don't all claim `:root`.
116
+
117
+ If your app overrode a library default with a bare `:root` rule that only
118
+ worked because of source order, it now works by specificity instead.
119
+
120
+ ### 4. `spinner` / `skeleton` in CSS Modules (fix, no action)
121
+
122
+ v0.8 defined those mixins' `@keyframes` at module top level, so importing the
123
+ file leaked CSS and CSS Modules renamed the keyframes away from the
124
+ `animation-name` that referenced them. They now emit via `@at-root` inside the
125
+ mixin, co-located with the reference, so CSS Modules renames both together.
126
+ If you had worked around it by importing `animations-utilities` globally,
127
+ that workaround is harmless and can stay.
128
+
129
+ ### New mixins/features (additive, no migration needed)
130
+
131
+ - `css-is-awesome/api` — the zero-emit authoring barrel (section 1)
132
+ - `cia.print`, `cia.print-base($freeze-animations, $size, $margin)`,
133
+ `cia.print-hidden`, `cia.print-only` — pure-CSS print/PDF layer;
134
+ `print-base` is root-only (emits `@page`) and exposes `--is-print`,
135
+ `--print-hide`, `--print-show`. Recipe: `scss/recipes/print-to-pdf.md`
136
+ - The recipes book (`scss/recipes/*.md`) and the MCP server (`mcp/server.cjs`)
137
+ ship in the package; `npx cia add <recipe>` copies a recipe into your project
138
+ - `npm run validate-package` — packs, installs into a temp project and compiles
139
+ every documented `@use` specifier, which is how the root-shim break was found
140
+ - Theme build + drift gates (`check:theme-drift`), a corrected contrast
141
+ validator (it previously skipped unquoted `[data-theme=x]` blocks), and
142
+ 24 shipped themes all passing the contract and the a11y audit
143
+
144
+ ### Where to read more
145
+
146
+ - [`CHANGELOG.md`](./CHANGELOG.md) — `[1.0.0]` and `[1.1.0]` entries carry the
147
+ full detail and the reasoning behind each change
148
+ - [`VERSIONING.md`](./VERSIONING.md) — what counts as MAJOR from 1.0 on
149
+ - [`CONTRACT.md`](./CONTRACT.md) — the current required/optional token list
150
+
151
+ ---
152
+
5
153
  ## v0.8.1 — animations split + small renames
6
154
 
7
155
  Patch release with one real fix (animations CSS Modules bug) and two small
package/README.md CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  **Read [`llm.txt`](./llm.txt) first.** One file, the whole system: install path, hard rules, the mixin vocabulary, and the traps that make agents write wrong cia code. It ships in the npm package, so it's at `node_modules/css-is-awesome/llm.txt` in any project that has cia.
16
16
 
17
- **Then connect the MCP server** and stop guessing at signatures. It answers from the real source — 31 tools covering themes, mixins, functions, tokens, recipes, components and theme validation.
17
+ **Then connect the MCP server** and stop guessing at signatures. It answers from the real source — 32 tools covering themes, mixins, functions, tokens, recipes, components, theme validation and theme generation from design tokens.
18
18
 
19
19
  ```json
20
20
  {
@@ -145,7 +145,7 @@ node scripts/theme-validator.js public/themes/midnight/theme.css
145
145
  # <link rel="stylesheet" href="/themes/midnight/theme.css">
146
146
  ```
147
147
 
148
- Full authoring walkthrough: [`/docs/authoring/themes`](https://cssisawesome.com/docs/authoring/themes/). The contract (127 required + 36 optional tokens) is at [`scripts/theme-contract.json`](./scripts/theme-contract.json).
148
+ Full authoring walkthrough: [`/docs/authoring/themes`](https://cssisawesome.com/docs/authoring/themes/). The contract (127 required + 41 optional tokens) is at [`scripts/theme-contract.json`](./scripts/theme-contract.json).
149
149
 
150
150
  ## Token contract
151
151
 
@@ -226,6 +226,10 @@ npx cia analyze src/styles # design-system health: dead cia.* symbols, the
226
226
  # space() scale trap, off-contract tokens (typos),
227
227
  # off-scale lengths, hard-coded colors, BEM creep,
228
228
  # missing focus-visible styling
229
+ npx cia theme from-tokens tokens.json --name acme --out src/styles/acme.css
230
+ # design tokens (DTCG v2025.10, Tokens Studio, or a
231
+ # flat --token map) → a complete, validated theme.css;
232
+ # missing required tokens inherit from a shipped base
229
233
  ```
230
234
 
231
235
  `cia analyze` reads the real API surface from the installed package and exits non-zero on errors, so it slots straight into CI. It's deliberately low-noise about color: a hex used as a `var(--token, #hex)` fallback is token-driven (not flagged), and a literal inside `@media print` is an intentional paper colour (print escapes theme colours by design). Off-contract-token findings only fire on a **near-miss** of a real token — a typo like `--inkk` — never on your own custom tokens. Off-scale-length findings suggest the nearest named step (e.g. `--radius-md`) for a literal `border-radius`/`padding`/`margin`/`gap` value, as a hint toward using a token — never a claim about your active theme's exact pixel value, since themes are free to set their own numbers (Terminal sets every `--radius-*` to `0`, deliberately). The default output is a **graded report** — a health score, a section per concern (Contract / Spacing / Color / Naming / Layout / API / Accessibility) with a `✓` when clean, and a suggested fix on each finding; add `--verbose` for the flat per-file list or `--json` for the machine shape. Full rule reference: [`/docs/analyzer`](https://cssisawesome.com/docs/analyzer/).
@@ -294,7 +298,7 @@ The scope is kept narrow: 8 `!important` declarations, all inside `@media print`
294
298
 
295
299
  ## MCP server (for AI agents)
296
300
 
297
- cia ships a Model Context Protocol stdio server (JSON-RPC over stdio, protocol `2024-11-05`) exposing **31 tools** across 8 families (themes, mixins, functions, tokens · 127 required of them, animations, components, recipes, doc readers) plus `assemble_prompt` (context bundles) , `resolve_size` (snap design px values to cia's 4px grid) and `validate_theme` (run the real theme validator on CSS you just wrote). Any MCP-aware client (Claude Code, Cursor, Aider, Gemini, Copilot) can then query cia's real design system — mixin signatures, tokens, themes, recipes — instead of guessing, without grep-walking the repo. Full reference: [`/docs/mcp`](https://cssisawesome.com/docs/mcp/).
301
+ cia ships a Model Context Protocol stdio server (JSON-RPC over stdio, protocol `2024-11-05`) exposing **32 tools** across 8 families (themes, mixins, functions, tokens · 127 required of them, animations, components, recipes, doc readers) plus `assemble_prompt` (context bundles) , `resolve_size` (snap design px values to cia's 4px grid) `validate_theme` (run the real theme validator on CSS you just wrote) and `theme_from_tokens` (design-tokens JSON → a complete, validated theme.css). Any MCP-aware client (Claude Code, Cursor, Aider, Gemini, Copilot) can then query cia's real design system — mixin signatures, tokens, themes, recipes — instead of guessing, without grep-walking the repo. Full reference: [`/docs/mcp`](https://cssisawesome.com/docs/mcp/).
298
302
 
299
303
  **Recommended — zero install:** use the dedicated [`css-is-awesome-mcp`](https://www.npmjs.com/package/css-is-awesome-mcp) package. It depends on `css-is-awesome` and resolves your installed version's real source, so it's never out of sync — and the MCP SDK ships as a real dependency, not an optional peer you have to remember to add.
300
304
 
@@ -334,7 +338,7 @@ npm install -D @modelcontextprotocol/sdk zod
334
338
 
335
339
  ## Docs site
336
340
 
337
- The docs site is live at **https://cssisawesome.com** (production — Vercel, deployed from the `prod-css-is-awesome` branch), with a GitHub Pages mirror at **https://jerry2d3d.github.io/css-is-awesome/** that auto-deploys from `main`. To run it locally:
341
+ The docs site is live at **https://cssisawesome.com** (production — Vercel, building `main` on every push), with a GitHub Pages mirror at **https://jerry2d3d.github.io/css-is-awesome/** that deploys after each release. To run it locally:
338
342
 
339
343
  ```bash
340
344
  git clone https://github.com/Jerry2d3d/css-is-awesome.git
@@ -345,6 +349,8 @@ npm run dev # http://localhost:5173
345
349
 
346
350
  The docs site is a Next.js 16 app at `src/` that dogfoods the library — every page uses CSS Modules composed from the same tokens and mixins the library ships.
347
351
 
352
+ It also hosts the **[playground](https://cssisawesome.com/playground/)**: write SCSS with cia mixins, see it render live against any of the 24 themes, and share the result as a link. Sass runs in your browser (dart-sass in a web worker against cia's own source), so nothing is uploaded and the site stays a static export. Every recipe page has a “Try in playground” button.
353
+
348
354
  ## Scripts
349
355
 
350
356
  | Script | Does |
@@ -359,7 +365,7 @@ The docs site is a Next.js 16 app at `src/` that dogfoods the library — every
359
365
  | `npm run dtcg-to-scss` | Convert DTCG-format design tokens into cia SCSS |
360
366
  | `npm run lint` | ESLint on the Next.js app |
361
367
  | `npm run lint:scss` | Stylelint on the SCSS library |
362
- | `npm run validate-themes` | Validate every theme against the 127-token contract + WCAG 2.2 AA contrast (FAIL-by-default since v0.7; checks both `light-dark()` branches and reports the worse) |
368
+ | `npm run validate-themes` | Validate every theme against the 127-required-token contract + WCAG 2.2 AA contrast (FAIL-by-default since v0.7; checks both `light-dark()` branches and reports the worse) |
363
369
  | `npm run validate-icons` | Validate the `core` icon pack against the 49-glyph contract |
364
370
  | `npm run validate-api` | Assert the `css-is-awesome/api` barrel stays zero-emit |
365
371
  | `npm run validate-package` | Pack + install into a temp project and compile every documented `@use` form — catches breakage that in-repo checks can't see |
@@ -408,9 +414,9 @@ Full detail: [`/docs/testing`](https://cssisawesome.com/docs/testing/).
408
414
 
409
415
  **Stable, [published on npm](https://www.npmjs.com/package/css-is-awesome)** (first published 2026-09-01). The mixin API, functions, token contract, and theme architecture are stable and under strict SemVer — breaking changes require a major bump. See [`VERSIONING.md`](./VERSIONING.md) for the policy.
410
416
 
411
- The 1.0 surface is the v0.8 mixin-first reframe — twelve mixin renames, theme system collapsed to 8 single-file theme families, six zero-JS components, intrinsic-layout vocabulary, opt-in utilities — plus the recipes book, the Tailwind/Bootstrap migration on-ramp, print/PDF support, and the 31-tool MCP server (now also available zero-install via the companion [`css-is-awesome-mcp`](https://www.npmjs.com/package/css-is-awesome-mcp) package). The npm package ships ZERO JavaScript by hard rule.
417
+ The 1.0 surface is the v0.8 mixin-first reframe — twelve mixin renames, theme system collapsed to 8 single-file theme families, six zero-JS components, intrinsic-layout vocabulary, opt-in utilities — plus the recipes book, the Tailwind/Bootstrap migration on-ramp, print/PDF support, and the 32-tool MCP server (now also available zero-install via the companion [`css-is-awesome-mcp`](https://www.npmjs.com/package/css-is-awesome-mcp) package). The npm package ships ZERO JavaScript by hard rule.
412
418
 
413
- See [CHANGELOG.md](./CHANGELOG.md) for the full history and [MIGRATION.md](./MIGRATION.md) for the v0.7 → v0.8 upgrade path.
419
+ See [CHANGELOG.md](./CHANGELOG.md) for the full history and [MIGRATION.md](./MIGRATION.md) for the v0.7 → v0.8 and v0.8 → v1.0 upgrade paths.
414
420
 
415
421
  For the deep authoring reference (tier decisions, mixin contracts, agent rules), read [`AGENTS.md`](./AGENTS.md).
416
422
 
package/VERSIONING.md CHANGED
@@ -30,6 +30,7 @@ Any change that can break a consumer upgrading blindly.
30
30
  | SCSS mixin renamed, removed, or breaking signature change | `m.btn($variant)` now requires `$size` |
31
31
  | SCSS mixin default changes rendered output | `m.card()` default radius flips from `md` → `lg` |
32
32
  | Contract: required token renamed or removed | `--surface-default` → `--surface-base` |
33
+ | Contract: **new required token added** (existing custom themes stop validating) | `--space-unit` added as required in 1.12.0 — a mistake, relaxed in contract 1.1 |
33
34
  | Contract: `version` field bumps to a new major (`"1"` → `"2"`) | Required-token removal in `scripts/theme-contract.json` |
34
35
  | Optional-peer floor rises | `@modelcontextprotocol/sdk` minimum raised |
35
36
 
@@ -42,6 +43,7 @@ Additive, non-breaking changes.
42
43
  | New public CSS class | `.cia-grid-auto-fit` added |
43
44
  | New public SCSS mixin | `m.cluster($gap)` added |
44
45
  | New optional token added to contract (`"1"` → `"1.1"`) | `--dropdown-offset-y` added to component section |
46
+ | Required token relaxed to optional (contract minor bump) | `--space-unit` required → optional, contract `"1"` → `"1.1"` (2026-09-18) |
45
47
  | New theme or recipe shipped | `prism` family added; `mobile-nav` recipe added |
46
48
  | New utility class (`.cia-*`) | `.cia-text-balance` added |
47
49
 
@@ -68,6 +70,8 @@ While the library was pre-1.0 (`0.x.x`), the rules above applied with one carve-
68
70
 
69
71
  **`1.0.0` locked the contract** (cut 2026-08-17). Breaking changes now require a MAJOR bump, no exceptions.
70
72
 
73
+ `npm run check:contract` (CI-gated since 2026-09-18) diffs `scripts/theme-contract.json` against the last release tag and fails the build when the required/optional lists change without the version bump these tables demand. It exists because 1.12.0 shipped a new *required* token in a MINOR and nothing caught it until a consumer's validator broke.
74
+
71
75
  ---
72
76
 
73
77
  ## 3. Deprecation policy
package/bin/cia.cjs CHANGED
@@ -11,6 +11,7 @@
11
11
  * migrate bootstrap — parse Bootstrap SCSS/CSS vars + dump theme JSON
12
12
  * migrate mui — parse a MUI createTheme() result + dump theme JSON
13
13
  * migrate chakra — parse a Chakra extendTheme() result + dump theme JSON
14
+ * theme from-tokens — design-tokens JSON (DTCG / Tokens Studio) → validated theme.css
14
15
  *
15
16
  * cia core ships ZERO JavaScript in the `files` manifest. The CLI lives in
16
17
  * `bin/` which is explicitly allowed per the architecture lock — same path
@@ -36,11 +37,15 @@ Commands:
36
37
  analyze [path] Design-system health check: dead cia.* symbols,
37
38
  the space() scale trap, hard-coded colors, BEM,
38
39
  hand-written area maps.
40
+ theme from-tokens <f> Design-tokens JSON (DTCG v2025.10, Tokens Studio,
41
+ or flat --token map) → a complete, validated
42
+ theme.css. \`cia theme from-tokens --help\`.
39
43
 
40
44
  Examples:
41
45
  cia migrate tailwind ./tailwind.config.js
42
46
  cia add bottom-nav
43
47
  cia analyze src/styles
48
+ cia theme from-tokens tokens.json --name acme --out src/styles/acme.css
44
49
 
45
50
  Run \`cia <command> --help\` for command-specific help.
46
51
  `;
@@ -149,6 +154,20 @@ async function main() {
149
154
  return;
150
155
  }
151
156
 
157
+ if (command === 'theme') {
158
+ const [sub, ...themeArgs] = rest;
159
+ if (!sub || sub === '-h' || sub === '--help' || sub === 'help') {
160
+ process.stdout.write(require('./theme-from-tokens.cjs').HELP);
161
+ return;
162
+ }
163
+ if (sub === 'from-tokens') {
164
+ const { run } = require('./theme-from-tokens.cjs');
165
+ await run(themeArgs);
166
+ return;
167
+ }
168
+ fail(`unknown theme subcommand '${sub}'. Available: from-tokens.`);
169
+ }
170
+
152
171
  fail(`unknown command '${command}'. Run \`cia --help\` for usage.`);
153
172
  }
154
173