css-is-awesome 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/AGENTS.md +343 -0
  2. package/CHANGELOG.md +1036 -0
  3. package/CLAUDE.md +9 -0
  4. package/CONTRACT.md +580 -0
  5. package/GEMINI.md +9 -0
  6. package/LICENSE +21 -0
  7. package/LICENSE-third-party +88 -0
  8. package/MIGRATION.md +312 -0
  9. package/README.md +380 -0
  10. package/ROADMAP.md +714 -0
  11. package/THEMING.md +290 -0
  12. package/THREE-TIERS.md +158 -0
  13. package/VERSIONING.md +200 -0
  14. package/_index.scss +34 -0
  15. package/api.scss +16 -0
  16. package/bin/README.md +57 -0
  17. package/bin/cia.cjs +114 -0
  18. package/bin/migrate-bootstrap.cjs +427 -0
  19. package/bin/migrate-tailwind.cjs +832 -0
  20. package/css-is-awesome.instructions.md +533 -0
  21. package/dist/css-is-awesome.core.css +598 -0
  22. package/dist/css-is-awesome.core.min.css +1 -0
  23. package/dist/css-is-awesome.css +3733 -0
  24. package/dist/css-is-awesome.min.css +1 -0
  25. package/dist/css-is-awesome.utilities.css +2445 -0
  26. package/dist/css-is-awesome.utilities.min.css +1 -0
  27. package/dist/tokens.css +508 -0
  28. package/dist/tokens.d.ts +266 -0
  29. package/dist/tokens.min.css +1 -0
  30. package/figma-tokens/README.md +57 -0
  31. package/figma-tokens/primitives-brand.scss +121 -0
  32. package/figma-tokens/semantic-dark.scss +61 -0
  33. package/figma-tokens/semantic-light.scss +61 -0
  34. package/figma-tokens/tokens.json +144 -0
  35. package/llm.txt +183 -0
  36. package/mcp/server.cjs +1495 -0
  37. package/package.json +199 -0
  38. package/public/icons/README.md +278 -0
  39. package/public/icons/arrow-right.svg +4 -0
  40. package/public/icons/check.svg +4 -0
  41. package/public/icons/chevron-down.svg +4 -0
  42. package/public/icons/close.svg +4 -0
  43. package/public/icons/core/arrow-down.svg +13 -0
  44. package/public/icons/core/arrow-left.svg +13 -0
  45. package/public/icons/core/arrow-right.svg +13 -0
  46. package/public/icons/core/arrow-up.svg +13 -0
  47. package/public/icons/core/bell.svg +13 -0
  48. package/public/icons/core/calendar.svg +15 -0
  49. package/public/icons/core/check.svg +12 -0
  50. package/public/icons/core/chevron-down.svg +12 -0
  51. package/public/icons/core/chevron-left.svg +12 -0
  52. package/public/icons/core/chevron-right.svg +12 -0
  53. package/public/icons/core/chevron-up.svg +12 -0
  54. package/public/icons/core/clock.svg +13 -0
  55. package/public/icons/core/close.svg +13 -0
  56. package/public/icons/core/copy.svg +13 -0
  57. package/public/icons/core/download.svg +14 -0
  58. package/public/icons/core/edit.svg +13 -0
  59. package/public/icons/core/error.svg +14 -0
  60. package/public/icons/core/external-link.svg +14 -0
  61. package/public/icons/core/eye-off.svg +15 -0
  62. package/public/icons/core/eye.svg +13 -0
  63. package/public/icons/core/filter.svg +12 -0
  64. package/public/icons/core/heart.svg +12 -0
  65. package/public/icons/core/help.svg +14 -0
  66. package/public/icons/core/home.svg +13 -0
  67. package/public/icons/core/info.svg +14 -0
  68. package/public/icons/core/loading.svg +12 -0
  69. package/public/icons/core/lock.svg +13 -0
  70. package/public/icons/core/mail.svg +13 -0
  71. package/public/icons/core/menu.svg +14 -0
  72. package/public/icons/core/message.svg +12 -0
  73. package/public/icons/core/minus.svg +12 -0
  74. package/public/icons/core/more-horizontal.svg +14 -0
  75. package/public/icons/core/pause.svg +13 -0
  76. package/public/icons/core/play.svg +12 -0
  77. package/public/icons/core/plus.svg +13 -0
  78. package/public/icons/core/refresh.svg +15 -0
  79. package/public/icons/core/save.svg +14 -0
  80. package/public/icons/core/search.svg +13 -0
  81. package/public/icons/core/settings.svg +13 -0
  82. package/public/icons/core/share.svg +14 -0
  83. package/public/icons/core/sort.svg +15 -0
  84. package/public/icons/core/star.svg +12 -0
  85. package/public/icons/core/success.svg +13 -0
  86. package/public/icons/core/trash.svg +16 -0
  87. package/public/icons/core/unlock.svg +13 -0
  88. package/public/icons/core/upload.svg +14 -0
  89. package/public/icons/core/user.svg +13 -0
  90. package/public/icons/core/users.svg +15 -0
  91. package/public/icons/core/warning.svg +14 -0
  92. package/public/icons/download.svg +4 -0
  93. package/public/icons/edit.svg +4 -0
  94. package/public/icons/menu.svg +4 -0
  95. package/public/icons/search.svg +4 -0
  96. package/public/theme.css +4179 -0
  97. package/public/themes/README.md +102 -0
  98. package/public/themes/boilerplate/theme.css +154 -0
  99. package/public/themes/boilerplate-dark/theme.css +171 -0
  100. package/public/themes/boilerplate-light/theme.css +171 -0
  101. package/public/themes/cupertino/theme.css +165 -0
  102. package/public/themes/cupertino-dark/theme.css +200 -0
  103. package/public/themes/cupertino-light/theme.css +227 -0
  104. package/public/themes/glass/theme.css +190 -0
  105. package/public/themes/glass-dark/theme.css +201 -0
  106. package/public/themes/glass-light/theme.css +229 -0
  107. package/public/themes/graphite/theme.css +155 -0
  108. package/public/themes/graphite-dark/theme.css +223 -0
  109. package/public/themes/graphite-light/theme.css +191 -0
  110. package/public/themes/press/theme.css +189 -0
  111. package/public/themes/press-dark/theme.css +199 -0
  112. package/public/themes/press-light/theme.css +235 -0
  113. package/public/themes/prism/theme.css +159 -0
  114. package/public/themes/prism-dark/theme.css +185 -0
  115. package/public/themes/prism-light/theme.css +188 -0
  116. package/public/themes/sketchbook/theme.css +152 -0
  117. package/public/themes/sketchbook-dark/theme.css +194 -0
  118. package/public/themes/sketchbook-light/theme.css +188 -0
  119. package/public/themes/terminal/theme.css +159 -0
  120. package/public/themes/terminal-dark/theme.css +229 -0
  121. package/public/themes/terminal-light/theme.css +152 -0
  122. package/scripts/README.md +70 -0
  123. package/scripts/icon-contract.json +67 -0
  124. package/scripts/icon-validator.js +205 -0
  125. package/scripts/prepare-dist.mjs +65 -0
  126. package/scripts/theme-a11y.js +415 -0
  127. package/scripts/theme-contract.json +171 -0
  128. package/scripts/theme-validator.js +674 -0
  129. package/scss/README.md +55 -0
  130. package/scss/_animations-utilities.scss +107 -0
  131. package/scss/_animations.scss +248 -0
  132. package/scss/_app-styles.scss +15 -0
  133. package/scss/_generator.scss +174 -0
  134. package/scss/_icons.scss +475 -0
  135. package/scss/_index.scss +17 -0
  136. package/scss/_layout.scss +597 -0
  137. package/scss/_mixins.scss +1036 -0
  138. package/scss/_system.scss +291 -0
  139. package/scss/_utilities.scss +377 -0
  140. package/scss/api.scss +61 -0
  141. package/scss/components/_accordion.scss +72 -0
  142. package/scss/components/_buttons.scss +171 -0
  143. package/scss/components/_copy-button.scss +69 -0
  144. package/scss/components/_data.scss +190 -0
  145. package/scss/components/_feedback.scss +197 -0
  146. package/scss/components/_forms.scss +272 -0
  147. package/scss/components/_index.scss +17 -0
  148. package/scss/components/_navigation.scss +186 -0
  149. package/scss/components/_overlay.scss +259 -0
  150. package/scss/components/_stepper.scss +159 -0
  151. package/scss/components/_tabs.scss +72 -0
  152. package/scss/core.scss +54 -0
  153. package/scss/examples/_theming.scss +107 -0
  154. package/scss/examples/_usage.scss +317 -0
  155. package/scss/main.scss +64 -0
  156. package/scss/recipes/README.md +110 -0
  157. package/scss/recipes/_bare-tags.scss +232 -0
  158. package/scss/recipes/_recipe-template.md +119 -0
  159. package/scss/recipes/combobox.md +509 -0
  160. package/scss/recipes/dialog.md +265 -0
  161. package/scss/recipes/print-to-pdf.md +263 -0
  162. package/scss/theme/README.md +67 -0
  163. package/scss/theme/_brand.scss +18 -0
  164. package/scss/theme/_colors-dark.scss +68 -0
  165. package/scss/theme/_colors-light.scss +70 -0
  166. package/scss/theme/_components.scss +94 -0
  167. package/scss/theme/_icons.scss +104 -0
  168. package/scss/theme/_index.scss +62 -0
  169. package/scss/theme/_shadows.scss +65 -0
  170. package/scss/theme/_shape.scss +13 -0
  171. package/scss/theme/_typography.scss +9 -0
  172. package/scss/theme/registry.json +447 -0
  173. package/scss/themes/boilerplate-dark.scss +212 -0
  174. package/scss/themes/boilerplate-light.scss +209 -0
  175. package/scss/themes/boilerplate.scss +181 -0
  176. package/scss/themes/cupertino-dark.scss +238 -0
  177. package/scss/themes/cupertino-light.scss +266 -0
  178. package/scss/themes/cupertino.scss +194 -0
  179. package/scss/themes/glass-dark.scss +238 -0
  180. package/scss/themes/glass-light.scss +266 -0
  181. package/scss/themes/glass.scss +220 -0
  182. package/scss/themes/graphite-dark.scss +260 -0
  183. package/scss/themes/graphite-light.scss +228 -0
  184. package/scss/themes/graphite.scss +182 -0
  185. package/scss/themes/press-dark.scss +237 -0
  186. package/scss/themes/press-light.scss +273 -0
  187. package/scss/themes/press.scss +241 -0
  188. package/scss/themes/prism-dark.scss +217 -0
  189. package/scss/themes/prism-light.scss +220 -0
  190. package/scss/themes/prism.scss +190 -0
  191. package/scss/themes/sketchbook-dark.scss +231 -0
  192. package/scss/themes/sketchbook-light.scss +231 -0
  193. package/scss/themes/sketchbook.scss +178 -0
  194. package/scss/themes/terminal-dark.scss +267 -0
  195. package/scss/themes/terminal-light.scss +175 -0
  196. package/scss/themes/terminal.scss +185 -0
  197. package/scss/tokens.scss +23 -0
  198. package/scss/utilities-only.scss +4 -0
package/CLAUDE.md ADDED
@@ -0,0 +1,9 @@
1
+ # CLAUDE.md
2
+
3
+ This project is **css-is-awesome**, a token-driven SCSS design system.
4
+
5
+ For all rules, install, examples, and gotchas, read **[`AGENTS.md`](./AGENTS.md)** at the package root.
6
+
7
+ The deep authoring reference is **[`css-is-awesome.instructions.md`](./css-is-awesome.instructions.md)**.
8
+
9
+ Both ship inside the npm package, so you can read them at `node_modules/css-is-awesome/AGENTS.md` when working in a consumer project.
package/CONTRACT.md ADDED
@@ -0,0 +1,580 @@
1
+ # css-is-awesome — Token Contract
2
+
3
+ Every theme declares these tokens. The [theme validator](./scripts/theme-validator.js) enforces completeness on every PR against the machine-readable companion at [`scripts/theme-contract.json`](./scripts/theme-contract.json).
4
+
5
+ - **Source of truth:** this document.
6
+ - **Reference implementation:** [`public/theme.css`](./public/theme.css) (Sketchbook).
7
+ - **Validate a theme:** `node scripts/theme-validator.js <path-to-theme.css>`
8
+ - **Validate every theme in the repo:** `npm run validate-themes`
9
+
10
+ A theme file is a single `:root { … }` block plus (optionally) an `@import` for fonts. No component CSS lives in a theme file. Tokens only.
11
+
12
+ ---
13
+
14
+ ## How tokens reach the library
15
+
16
+ Library mixins resolve every token through a `var(--token, fallback)` pattern, so:
17
+
18
+ | Mixin call | Emitted CSS | Required token |
19
+ | -------------------------------- | ---------------------------------------- | -------------------- |
20
+ | `m.color(surface-default)` | `var(--surface-default, #fff)` | `--surface-default` |
21
+ | `m.space(md)` | `var(--space-md, 1rem)` | `--space-md` |
22
+ | `m.radius(lg)` | `var(--radius-lg, 0.5rem)` | `--radius-lg` |
23
+ | `m.shadow(md)` | `var(--shadow-md, …)` | `--shadow-md` |
24
+ | `m.font-family(primary)` | `var(--font-primary, sans-serif)` | `--font-primary` |
25
+ | `m.font-size(base)` | `var(--font-size-base, 1rem)` | `--font-size-base` |
26
+ | `m.line-height(normal)` | `var(--line-height-normal, 1.5)` | `--line-height-normal` |
27
+ | `m.font-weight(medium)` | `var(--font-weight-medium, 500)` | `--font-weight-medium` |
28
+ | `m.z(modal)` | `var(--z-modal, 0)` | `--z-modal` |
29
+
30
+ If a token is missing from a theme the mixin silently falls back to a sensible SCSS default — which means the theme swap is no longer lossless. That is what the contract prevents.
31
+
32
+ ---
33
+
34
+ ## Native Sketchbook palette
35
+
36
+ These are the raw pigment tokens. Semantic aliases below reference them. In other themes (Press, Graphite, Glass, …) the native names change; the aliases do not.
37
+
38
+ ### Paper (surfaces)
39
+
40
+ | Token | Type | Example | Purpose |
41
+ | --------------- | ----- | ------------------------------- | ---------------------------------- |
42
+ | `--paper` | color | `#F7F3EA` | Page background — the "paper" |
43
+ | `--paper-raised`| color | `#FDFAF2` | Lifted panel / card background |
44
+ | `--paper-sunk` | color | `#ECE5D3` | Pressed / recessed surface |
45
+ | `--paper-glass` | color | `rgba(253, 250, 242, 0.75)` | Translucent surface (glass themes) |
46
+
47
+ ### Ink (text hierarchy)
48
+
49
+ | Token | Type | Example | Purpose |
50
+ | ------------- | ----- | --------- | ---------------------------------- |
51
+ | `--ink` | color | `#2A241E` | Primary type — body copy, headings |
52
+ | `--ink-soft` | color | `#4A4037` | Secondary type |
53
+ | `--ink-faint` | color | `#726858` | Muted / hint type |
54
+ | `--graphite` | color | `#3A332B` | Emphasis stroke / chart ink |
55
+ | `--muted` | color | `#948977` | Captions, low-emphasis metadata |
56
+
57
+ ### Construction lines
58
+
59
+ | Token | Type | Example | Purpose |
60
+ | -------------- | ----- | --------- | ---------------------- |
61
+ | `--guide` | color | `#C9BDA5` | Layout guide / grid line |
62
+ | `--guide-soft` | color | `#DDD4C0` | Secondary guide |
63
+ | `--hair` | color | `#D4CCBB` | Default border |
64
+ | `--hair-soft` | color | `#E8E2D4` | Subtle divider |
65
+
66
+ ### Primary accent (indigo)
67
+
68
+ | Token | Type | Example | Purpose |
69
+ | ------------ | ----- | --------- | ---------------------------------- |
70
+ | `--ai` | color | `#1F3A5F` | Primary action / link / focus ring |
71
+ | `--ai-ink` | color | `#14263F` | Hover / active darker variant |
72
+ | `--ai-wash` | color | `#E5EBF1` | Wash tint for backgrounds |
73
+
74
+ ### Seal (vermilion)
75
+
76
+ | Token | Type | Example | Purpose |
77
+ | ----------- | ----- | --------- | ----------------------------- |
78
+ | `--shu` | color | `#C1272D` | Secondary / editorial emphasis |
79
+ | `--shu-wash`| color | `#F6E3E1` | Wash tint |
80
+
81
+ ### Draft / marginalia (ochre)
82
+
83
+ | Token | Type | Example | Purpose |
84
+ | ------------- | ----- | --------- | ------------------------- |
85
+ | `--ochre` | color | `#A37B30` | Tertiary / warning accent |
86
+ | `--ochre-wash`| color | `#F0E5CC` | Wash tint |
87
+
88
+ ### Code panel
89
+
90
+ | Token | Type | Example | Purpose |
91
+ | --------------- | ----- | --------- | ----------------------------- |
92
+ | `--code-bg` | color | `#2B2420` | Code block background |
93
+ | `--code-ink` | color | `#F7F3EA` | Code body text |
94
+ | `--code-muted` | color | `#A39787` | Code comments |
95
+ | `--code-accent` | color | `#E5B660` | Literals / values |
96
+ | `--code-green` | color | `#A8B86C` | Keywords / properties |
97
+ | `--code-blue` | color | `#94AFC9` | Selectors / tags |
98
+
99
+ ---
100
+
101
+ ## Semantic aliases (library mixins read these)
102
+
103
+ ### Backgrounds (page-level)
104
+
105
+ | Token | Type | Purpose |
106
+ | ---------------------- | ----- | ------------------------------------ |
107
+ | `--background-default` | color | Default page background |
108
+ | `--background-subtle` | color | Alternate / striped section |
109
+ | `--background-navbar` | color | Dedicated navbar background |
110
+
111
+ ### Surfaces (panel-level)
112
+
113
+ | Token | Type | Purpose |
114
+ | -------------------- | ----- | --------------------------------- |
115
+ | `--surface-default` | color | Card / panel default |
116
+ | `--surface-raised` | color | Lifted card (elevation) |
117
+ | `--surface-sunk` | color | Pressed / recessed |
118
+ | `--surface-muted` | color | Muted field / disabled panel |
119
+ | `--surface-subtle` | color | Subtle highlight |
120
+ | `--surface-emphasis` | color | Inverse / emphasis surface |
121
+ | `--surface-glass` | color | Translucent (glass themes) |
122
+
123
+ ### Text
124
+
125
+ | Token | Type | Purpose |
126
+ | -------------------- | ----- | --------------------------------- |
127
+ | `--text-primary` | color | Body copy, headings |
128
+ | `--text-secondary` | color | Supporting copy |
129
+ | `--text-muted` | color | Hint / help / placeholder |
130
+ | `--text-tertiary` | color | Low-emphasis metadata |
131
+ | `--text-inverse` | color | Text on dark / colored surface |
132
+ | `--text-link` | color | Default anchor color |
133
+ | `--text-link-hover` | color | Anchor hover color |
134
+
135
+ ### Borders
136
+
137
+ | Token | Type | Purpose |
138
+ | -------------------- | ----- | -------------------------------- |
139
+ | `--border-default` | color | Default border |
140
+ | `--border-subtle` | color | Subtle divider |
141
+ | `--border-emphasis` | color | Emphasized border |
142
+ | `--border-focus` | color | Focus ring color |
143
+
144
+ ### Interactive (hover / active wash)
145
+
146
+ | Token | Type | Purpose |
147
+ | --------------------- | ----- | ---------------------------------- |
148
+ | `--interactive-hover` | color | Wash applied to interactive hover |
149
+ | `--interactive-active`| color | Wash applied to interactive active |
150
+
151
+ ### Brand
152
+
153
+ | Token | Type | Purpose |
154
+ | ---------------------- | ----- | --------------------------------- |
155
+ | `--brand-primary` | color | Brand identity color |
156
+ | `--brand-primary-hover`| color | Brand hover color |
157
+
158
+ ### Action — primary / secondary / tertiary
159
+
160
+ | Token | Type | Purpose |
161
+ | ----------------------------- | ----- | --------------------------- |
162
+ | `--action-primary-default` | color | Primary button / CTA |
163
+ | `--action-primary-hover` | color | Primary hover |
164
+ | `--action-primary-active` | color | Primary pressed |
165
+ | `--action-primary-wash` | color | Primary subtle background |
166
+ | `--action-secondary-default` | color | Secondary button |
167
+ | `--action-secondary-hover` | color | Secondary hover |
168
+ | `--action-secondary-active` | color | Secondary pressed |
169
+ | `--action-secondary-wash` | color | Secondary subtle background |
170
+ | `--action-tertiary-default` | color | Tertiary button |
171
+ | `--action-tertiary-hover` | color | Tertiary hover |
172
+ | `--action-tertiary-active` | color | Tertiary pressed |
173
+ | `--action-tertiary-wash` | color | Tertiary subtle background |
174
+
175
+ ### Feedback (high-level semantic)
176
+
177
+ | Token | Type | Purpose |
178
+ | -------------------- | ----- | -------------------- |
179
+ | `--feedback-info` | color | Info / neutral cue |
180
+ | `--feedback-success` | color | Success cue |
181
+ | `--feedback-warning` | color | Warning cue |
182
+ | `--feedback-error` | color | Error / destructive |
183
+
184
+ ### Status (three-part: default / subtle / text)
185
+
186
+ | Token | Type | Purpose |
187
+ | -------------------- | ----- | -------------------------------------------- |
188
+ | `--info-default` | color | Alert / badge strong tone |
189
+ | `--info-subtle` | color | Alert / badge wash background |
190
+ | `--info-text` | color | Alert / badge body copy |
191
+ | `--success-default` | color | Success alert strong tone |
192
+ | `--success-subtle` | color | Success wash |
193
+ | `--success-text` | color | Success body copy |
194
+ | `--warning-default` | color | Warning strong tone |
195
+ | `--warning-subtle` | color | Warning wash |
196
+ | `--warning-text` | color | Warning body copy |
197
+ | `--error-default` | color | Error strong tone |
198
+ | `--error-subtle` | color | Error wash |
199
+ | `--error-text` | color | Error body copy |
200
+
201
+ ---
202
+
203
+ ## Typography
204
+
205
+ | Token | Type | Example | Purpose |
206
+ | -------------------- | ------------ | --------------------------------- | ------------------------------ |
207
+ | `--font-display` | font-family | `'DM Serif Display', …, serif` | Large display / hero type |
208
+ | `--font-serif` | font-family | `'Noto Serif JP', …, serif` | Body serif |
209
+ | `--font-sans` | font-family | `'Noto Sans JP', …, sans-serif` | Body sans |
210
+ | `--font-script` | font-family | `'Caveat', …, cursive` | Handwriting / marginalia |
211
+ | `--font-mono` | font-family | `'JetBrains Mono', …, monospace` | Code |
212
+ | `--font-primary` | font-family | `var(--font-sans)` | Default body — emitted by `m.font-family(primary)` |
213
+ | `--font-size-base` | length | `1rem` | Base body size |
214
+ | `--line-height-normal` | number | `1.5` | Default line-height |
215
+ | `--font-weight-medium` | number | `500` | Medium weight (used by buttons) |
216
+
217
+ ---
218
+
219
+ ## Space scale
220
+
221
+ | Token | Type | Example | Purpose |
222
+ | ------------- | ------ | --------- | --------------------------- |
223
+ | `--space-2xs` | length | `0.25rem` | Hairline gap / 2xs padding |
224
+ | `--space-xs` | length | `0.5rem` | Tight gap / xs padding |
225
+ | `--space-sm` | length | `0.75rem` | Compact gap / sm padding |
226
+ | `--space-md` | length | `1rem` | Default gap / md padding |
227
+ | `--space-lg` | length | `1.5rem` | Comfortable gap / lg padding |
228
+ | `--space-xl` | length | `2rem` | Section gap / xl padding |
229
+
230
+ ---
231
+
232
+ ## Radius
233
+
234
+ Sketchbook keeps native `--r-*` (drawn-on-paper feel) plus an alias set `--radius-*` that the library mixins emit. Other themes may set both to the same value.
235
+
236
+ | Token | Type | Example | Purpose |
237
+ | ------------- | ------ | ------------- | ------------------------------- |
238
+ | `--r-sm` | length | `2px` | Native small radius (Sketchbook) |
239
+ | `--r-md` | length | `3px` | Native medium radius |
240
+ | `--r-lg` | length | `6px` | Native large radius |
241
+ | `--radius-sm` | length | `var(--r-sm)` | Library alias (mixins emit this) |
242
+ | `--radius-md` | length | `var(--r-md)` | Library alias |
243
+ | `--radius-lg` | length | `var(--r-lg)` | Library alias |
244
+ | `--radius-xl` | length | `0.75rem` | Modals / large panels |
245
+ | `--radius-full` | length | `9999px` | Pills, avatars, circles |
246
+
247
+ ---
248
+
249
+ ## Shadow
250
+
251
+ | Token | Type | Example | Purpose |
252
+ | ------------- | ---------- | --------------------------------------- | ---------------------------- |
253
+ | `--shadow-sm` | box-shadow | `0 1px 2px rgba(…, .06)` | Card-level lift |
254
+ | `--shadow-md` | box-shadow | `0 4px 18px rgba(…, .08)` | Dropdowns, popovers |
255
+ | `--shadow-lg` | box-shadow | `0 12px 40px rgba(…, .12)` | Toasts, floating panels |
256
+ | `--shadow-xl` | box-shadow | `0 20px 50px rgba(…, .16)` | High-elevation surfaces |
257
+ | `--shadow-2xl`| box-shadow | `0 28px 70px rgba(…, .22)` | Modal backdrops |
258
+
259
+ ---
260
+
261
+ ## Blur / Glow
262
+
263
+ Paper themes declare these as `none` / `transparent` so a swap to a glass or phosphor theme is lossless.
264
+
265
+ | Token | Type | Example | Purpose |
266
+ | ------------ | ------ | ------------------- | -------------------------------------- |
267
+ | `--blur-sm` | length | `none` | Glass surface subtle blur |
268
+ | `--blur-md` | length | `none` | Glass medium blur |
269
+ | `--blur-lg` | length | `none` | Glass heavy blur |
270
+ | `--glow-sm` | shadow | `0 0 0 transparent` | Subtle glow (phosphor / emphasis themes) |
271
+ | `--glow-md` | shadow | `0 0 0 transparent` | Medium glow |
272
+ | `--glow-lg` | shadow | `0 0 0 transparent` | Heavy glow |
273
+
274
+ ---
275
+
276
+ ## Motion
277
+
278
+ | Token | Type | Example | Purpose |
279
+ | ------------------- | -------- | ------------------------------ | ------------------------- |
280
+ | `--duration-fast` | duration | `180ms` | Fast interactions (hover) |
281
+ | `--duration-normal` | duration | `240ms` | Default transitions |
282
+ | `--duration-slow` | duration | `380ms` | Deliberate motion |
283
+ | `--ease` | timing | `cubic-bezier(.33,.66,.33,1)` | Default easing curve |
284
+
285
+ ---
286
+
287
+ ## Z-index layers
288
+
289
+ | Token | Type | Example | Purpose |
290
+ | -------------- | ------ | ------- | ---------------------- |
291
+ | `--z-sticky` | number | `1020` | Sticky headers |
292
+ | `--z-dropdown` | number | `1030` | Dropdown menus |
293
+ | `--z-backdrop` | number | `1040` | Modal backdrop |
294
+ | `--z-modal` | number | `1050` | Modal surface |
295
+ | `--z-popover` | number | `1060` | Popover / detached panel |
296
+ | `--z-tooltip` | number | `1070` | Tooltips (always top) |
297
+
298
+ ---
299
+
300
+ ## Component overrides (optional)
301
+
302
+ These are per-component tokens a theme MAY override to change how a single family of components renders (buttons, cards, inputs, etc.) without touching the library or rebuilding SCSS. They are **optional** — the library emits every one of them on `:root` with a sensible default, and every component mixin reads them via `var(--<key>, <library-default>)`. A theme that sets none of them renders exactly the same as today.
303
+
304
+ To override, declare the variable inside your theme's `:root { … }` block, e.g.:
305
+
306
+ ```css
307
+ :root {
308
+ --btn-radius: 0; /* Terminal — zero radii everywhere */
309
+ --card-shadow: none; /* Press — editorial flat */
310
+ --input-radius: var(--r-sm); /* Cupertino — AppKit text field */
311
+ }
312
+ ```
313
+
314
+ ### Buttons
315
+
316
+ | Token | Type | Default | Purpose |
317
+ | -------------------- | ---------- | ------------------------------- | -------------------------------------- |
318
+ | `--btn-padding-y` | length | `var(--space-1, 0.5rem)` | Vertical padding on `btn-base` |
319
+ | `--btn-padding-x` | length | `var(--space-4, 1rem)` | Horizontal padding on `btn-base` |
320
+ | `--btn-radius` | length | `var(--radius-md, 0.25rem)` | Corner radius |
321
+ | `--btn-font-weight` | number | `var(--font-weight-medium, 500)`| Type weight |
322
+ | `--btn-font-size` | length | `var(--font-size-base, 1rem)` | Font size (used when size is explicit) |
323
+ | `--btn-border-width` | length | `1px` | Border stroke (outline / ghost) |
324
+
325
+ ### Cards
326
+
327
+ | Token | Type | Default | Purpose |
328
+ | ---------------- | ---------- | ------------------------------------ | ----------------------------- |
329
+ | `--card-padding` | length | `var(--space-4, 1rem)` | Inner padding |
330
+ | `--card-radius` | length | `var(--radius-lg, 0.5rem)` | Corner radius |
331
+ | `--card-shadow` | box-shadow | `var(--shadow-sm, …)` | Elevation (set `none` to flatten) |
332
+ | `--card-border` | border | `1px solid var(--border-default)` | Edge treatment (when enabled) |
333
+
334
+ ### Inputs
335
+
336
+ | Token | Type | Default | Purpose |
337
+ | ---------------------- | ------ | --------------------------- | ------------------ |
338
+ | `--input-padding-y` | length | `var(--space-1, 0.5rem)` | Vertical padding |
339
+ | `--input-padding-x` | length | `var(--space-2, 0.75rem)` | Horizontal padding |
340
+ | `--input-radius` | length | `var(--radius-md, 0.25rem)` | Corner radius |
341
+ | `--input-border-width` | length | `1px` | Border stroke |
342
+
343
+ ### Alerts
344
+
345
+ | Token | Type | Default | Purpose |
346
+ | ------------------- | ------ | --------------------------- | ------------------ |
347
+ | `--alert-padding-y` | length | `var(--space-2, 0.75rem)` | Vertical padding |
348
+ | `--alert-padding-x` | length | `var(--space-4, 1rem)` | Horizontal padding |
349
+ | `--alert-radius` | length | `var(--radius-md, 0.25rem)` | Corner radius |
350
+
351
+ ### Badges
352
+
353
+ | Token | Type | Default | Purpose |
354
+ | ------------------- | ------ | --------------------------- | ------------------ |
355
+ | `--badge-padding-y` | length | `var(--space-1, 0.5rem)` | Vertical padding |
356
+ | `--badge-padding-x` | length | `var(--space-1, 0.5rem)` | Horizontal padding |
357
+ | `--badge-radius` | length | `var(--radius-full, 9999px)`| Corner radius |
358
+
359
+ ### Tags / Chips
360
+
361
+ | Token | Type | Default | Purpose |
362
+ | ----------------- | ------ | ---------------------------- | ------------------ |
363
+ | `--tag-padding-y` | length | `var(--space-2xs, 0.25rem)` | Vertical padding |
364
+ | `--tag-padding-x` | length | `var(--space-2, 0.75rem)` | Horizontal padding |
365
+ | `--tag-radius` | length | `var(--radius-md, 0.25rem)` | Corner radius |
366
+
367
+ ### Modals
368
+
369
+ | Token | Type | Default | Purpose |
370
+ | ----------------- | ---------- | ------------------------------- | --------------- |
371
+ | `--modal-padding` | length | `var(--space-5, 1.5rem)` | Inner padding |
372
+ | `--modal-radius` | length | `var(--radius-xl, 0.75rem)` | Corner radius |
373
+ | `--modal-shadow` | box-shadow | `var(--shadow-2xl, …)` | Elevation |
374
+
375
+ ### Popovers
376
+
377
+ | Token | Type | Default | Purpose |
378
+ | ------------------- | ---------- | ------------------------------ | ------------- |
379
+ | `--popover-padding` | length | `var(--space-4, 1rem)` | Inner padding |
380
+ | `--popover-radius` | length | `var(--radius-lg, 0.5rem)` | Corner radius |
381
+ | `--popover-shadow` | box-shadow | `var(--shadow-lg, …)` | Elevation |
382
+
383
+ ### Tooltips
384
+
385
+ | Token | Type | Default | Purpose |
386
+ | --------------------- | ------ | --------------------------- | ------------------ |
387
+ | `--tooltip-padding-y` | length | `var(--space-1, 0.5rem)` | Vertical padding |
388
+ | `--tooltip-padding-x` | length | `var(--space-1, 0.5rem)` | Horizontal padding |
389
+ | `--tooltip-radius` | length | `var(--radius-md, 0.25rem)` | Corner radius |
390
+
391
+ ### Dropdowns
392
+
393
+ | Token | Type | Default | Purpose |
394
+ | -------------------- | ---------- | --------------------------- | ------------- |
395
+ | `--dropdown-radius` | length | `var(--radius-md, 0.25rem)` | Corner radius |
396
+ | `--dropdown-shadow` | box-shadow | `var(--shadow-md, …)` | Elevation |
397
+
398
+ Total: 34 optional component tokens. None are validated — a theme that omits all of them still passes `npm run validate-themes`.
399
+
400
+ ---
401
+
402
+ ## A11y contrast (WCAG 2.2 AA)
403
+
404
+ Every PR runs `npm run validate-themes`, which now also audits the most
405
+ common contrast pairs in each theme block against the
406
+ [WCAG 2.2 §1.4.3 / §1.4.11](https://www.w3.org/TR/WCAG22/#contrast-minimum)
407
+ ratios. The audit is implemented in `scripts/theme-a11y.js` (zero deps —
408
+ sRGB linearisation + relative-luminance ratio). Translucent foregrounds
409
+ are alpha-composited onto the background before the ratio is computed, and
410
+ translucent backgrounds (status `--*-subtle` washes) are first composited
411
+ onto `--paper` so the math reflects what users actually see.
412
+
413
+ | Pair | Required | Kind |
414
+ | ----------------------------------------------------- | -------- | -------- |
415
+ | `--text-primary` on `--paper` | 4.5 : 1 | text |
416
+ | `--text-secondary` on `--paper` | 4.5 : 1 | text |
417
+ | `--text-tertiary` on `--paper` | 3.0 : 1 | large |
418
+ | `--text-muted` on `--paper` | 4.5 : 1 | text |
419
+ | `--ink` / `--ink-soft` on `--paper` | 4.5 : 1 | text |
420
+ | `--ink-faint` on `--paper` | 3.0 : 1 | large |
421
+ | `--text-link` on `--paper` | 4.5 : 1 | text |
422
+ | `--text-inverse` on `--action-primary-default` | 4.5 : 1 | text |
423
+ | `--text-inverse` on `--ai` | 4.5 : 1 | text |
424
+ | `--success-text` on `--success-subtle` | 4.5 : 1 | text |
425
+ | `--warning-text` on `--warning-subtle` | 4.5 : 1 | text |
426
+ | `--error-text` on `--error-subtle` | 4.5 : 1 | text |
427
+ | `--info-text` on `--info-subtle` | 4.5 : 1 | text |
428
+ | `--border-default` on `--paper` | 3.0 : 1 | non-text |
429
+ | `--border-focus` on `--paper` | 3.0 : 1 | non-text |
430
+ | `--shu` on `--paper` | 3.0 : 1 | non-text |
431
+
432
+ Each pair is reported as **PASS**, **WARN** (close to threshold; `--text-tertiary`
433
+ and `--ink-faint` warn when they pass the 3:1 large-text bar but fall below the
434
+ 4.5:1 body threshold), or **FAIL** (red, exits non-zero). CI fails on any FAIL.
435
+
436
+ Pass `--no-a11y` to `node scripts/theme-validator.js` (or set it in
437
+ `package.json`) to skip the audit — the contract check still runs. Color
438
+ formats supported: `#rgb`, `#rrggbb`, `#rrggbbaa`, `rgb()`, `rgba()`,
439
+ `hsl()`, `hsla()`, the 148 named colors and `transparent`. Modern color
440
+ spaces (`oklch()`, `oklab()`, `color-mix()`, `lab()`, `lch()`, `hwb()`)
441
+ are reported as **SKIP** with a reason rather than silently passing.
442
+
443
+
444
+ ---
445
+
446
+ ## Versioning
447
+
448
+ The contract is versioned via `scripts/theme-contract.json` (`version: "1"`).
449
+
450
+ - **Minor bump** (`"1" → "1.1"`): adds OPTIONAL tokens. Existing themes remain valid.
451
+ - **Major bump** (`"1" → "2"`): renames or removes REQUIRED tokens. Existing themes must migrate.
452
+
453
+ Any PR that adds a new `m.color(X)` / `m.space(X)` / `m.radius(X)` reference in the library must add `--X` to both this document and `scripts/theme-contract.json`, and add a declaration to every theme in `public/theme.css` and `public/themes/*/theme.css`. The `npm run validate-themes` check in CI will block the merge otherwise.
454
+
455
+ ---
456
+
457
+ ## Icons contract
458
+
459
+ The icon system is a parallel contract to the token contract. The
460
+ machine-readable companion is [`scripts/icon-contract.json`](./scripts/icon-contract.json);
461
+ the validator is `scripts/icon-validator.js` (run `npm run validate-icons`,
462
+ or per pack with `node scripts/icon-validator.js core`). A pack that
463
+ omits any contract glyph fails the build.
464
+
465
+ ### Packs and on-disk layout
466
+
467
+ Icons are organized into named **packs**. The default pack `core` ships
468
+ 49 UI-essential glyphs vendored from Lucide (see
469
+ [`LICENSE-third-party`](./LICENSE-third-party)). Additional packs (e.g.
470
+ `files`, `editor`) follow the same layout when added.
471
+
472
+ ```
473
+ public/icons/<pack>/<glyph>.svg ← bundled defaults
474
+ public/themes/<theme>/icons/<pack>/<glyph>.svg ← per-theme override
475
+ ```
476
+
477
+ The SCSS configuration lives in `scss/theme/_icons.scss`:
478
+
479
+ | Variable | Default | Purpose |
480
+ | -------------------------- | ----------- | -------------------------------------------- |
481
+ | `$icon-path` | `/icons` | Public root that hosts every pack directory |
482
+ | `$icon-pack` | `core` | Pack folder appended to `$icon-path` |
483
+ | `$icon-size` | `24px` | Default host element size |
484
+ | `$icon-svg-alias` | small map | Compile-time semantic name → filename map |
485
+
486
+ Re-exported from `scss/theme/_index.scss` as `$theme-icon-path`,
487
+ `$theme-icon-pack`, etc.
488
+
489
+ ### Resolution order (per glyph)
490
+
491
+ `m.svg(name)` (and the `svg-bg` / `svg-text` variants) emits a CSS
492
+ custom-property lookup with the bundled URL as fallback:
493
+
494
+ ```scss
495
+ @include m.svg(check);
496
+ // → mask: var(--cia-icon-check, url('/icons/core/check.svg')) center / contain no-repeat;
497
+ ```
498
+
499
+ The resolution order at the browser is therefore:
500
+
501
+ 1. **Per-theme override.** A theme that ships a replacement glyph
502
+ declares `--cia-icon-<glyph>: url('/themes/<theme>/icons/<pack>/<glyph>.svg')`
503
+ on `:root` (or inside its `[data-theme="<name>"]` block in the
504
+ consolidated bundle). Browser uses that URL.
505
+ 2. **Core pack fallback.** If no override is declared, the browser
506
+ resolves the URL baked into the second `var()` argument
507
+ (`/icons/<pack>/<glyph>.svg`).
508
+ 3. **404.** If the file doesn't exist on disk the browser silently
509
+ renders nothing — the host element keeps its size, no error in the
510
+ layout.
511
+
512
+ Aliases (`$theme-icon-svg-alias`) resolve at compile time *before* the
513
+ override lookup, so the override key matches the canonical filename, not
514
+ the call-site alias. With the default alias `close → x`:
515
+
516
+ ```scss
517
+ @include m.svg(close); // call site uses the semantic name
518
+ // → mask: var(--cia-icon-x, url('/icons/core/x.svg')) ...;
519
+ // → theme override key is --cia-icon-x
520
+ ```
521
+
522
+ ### Naming conventions
523
+
524
+ - **Kebab-case glyph names** — `arrow-right`, `chevron-down`, `more-horizontal`.
525
+ - **Category prefix groups related glyphs alphabetically** in directory
526
+ listings — `arrow-*`, `chevron-*`, `file-*`.
527
+ - **One glyph per file.** Multi-color art uses `m.svg-bg` and lives
528
+ outside the contract.
529
+ - **Override custom property:** `--cia-icon-<filename>` (the resolved
530
+ filename after aliases, not the call-site name).
531
+
532
+ ### File-format expectations
533
+
534
+ Every glyph in a contract pack MUST:
535
+
536
+ - Be a valid SVG document — start with `<?xml version="1.0" ...?>` or
537
+ `<svg ...>`.
538
+ - Use `viewBox="0 0 24 24"` (or scale equivalently). The mixin sizes
539
+ the host element; the SVG just needs a square viewBox.
540
+ - Paint via `stroke="currentColor"` / `fill="currentColor"` (or no
541
+ paint attribute). The mixin renders the SVG as a CSS mask, so any
542
+ hardcoded color is discarded — but currentColor keeps the file
543
+ reusable in `m.svg-bg` too.
544
+ - Omit `width` / `height` attributes on `<svg>`.
545
+ - Omit Lucide / Heroicons / Feather author-class hooks
546
+ (`class="lucide ..."`, etc.) — they're noise the mixin doesn't use.
547
+
548
+ The `vendor-lucide-core.mjs` script normalizes Lucide output to match
549
+ this format. Hand-authored glyphs should follow it directly.
550
+
551
+ ### Canonical `core` pack glyph names
552
+
553
+ Every pack listed in `scripts/icon-contract.json → packs.core.glyphs`
554
+ must exist at `public/icons/core/<name>.svg`. The current contract is:
555
+
556
+ | Group | Glyphs |
557
+ | --------------- | --------------------------------------------------------------------------------------------------- |
558
+ | Already shipped | `arrow-right`, `check`, `chevron-down`, `close`, `download`, `edit`, `menu`, `search` |
559
+ | Navigation | `arrow-left`, `arrow-up`, `arrow-down`, `chevron-up`, `chevron-left`, `chevron-right`, `external-link`, `home` |
560
+ | Actions | `upload`, `copy`, `share`, `trash`, `save`, `refresh`, `settings`, `filter`, `sort`, `plus`, `minus`, `more-horizontal` |
561
+ | Status | `info`, `warning`, `error`, `success`, `help`, `loading` |
562
+ | Communication | `mail`, `bell`, `calendar`, `clock`, `message` |
563
+ | User / security | `user`, `users`, `lock`, `unlock`, `eye`, `eye-off` |
564
+ | Media | `play`, `pause`, `star`, `heart` |
565
+
566
+ Total: **49 glyphs.** Pack 2 (`files`) and Pack 3 (`editor`) are
567
+ proposed but not yet under contract — see [`roadmap/icons-proposal.md`](./roadmap/icons-proposal.md).
568
+
569
+ ### Adding to the contract
570
+
571
+ A PR that adds a new contract glyph must:
572
+
573
+ 1. Add the glyph name to `scripts/icon-contract.json → packs.<pack>.glyphs`.
574
+ 2. Drop the SVG at `public/icons/<pack>/<glyph>.svg`.
575
+ 3. Update this section's table.
576
+ 4. Pass `npm run validate-icons`.
577
+
578
+ Per-theme override glyphs are NEVER required by the contract — themes
579
+ opt in glyph-by-glyph by declaring `--cia-icon-<name>` and shipping the
580
+ replacement file alongside.
package/GEMINI.md ADDED
@@ -0,0 +1,9 @@
1
+ # GEMINI.md
2
+
3
+ This project is **css-is-awesome**, a token-driven SCSS design system.
4
+
5
+ For all rules, install, examples, and gotchas, read **[`AGENTS.md`](./AGENTS.md)** at the package root.
6
+
7
+ The deep authoring reference is **[`css-is-awesome.instructions.md`](./css-is-awesome.instructions.md)**.
8
+
9
+ Both ship inside the npm package, so you can read them at `node_modules/css-is-awesome/AGENTS.md` when working in a consumer project.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jerry2d3d
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.