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
@@ -0,0 +1,259 @@
1
+ // ============================================================================
2
+ // OVERLAY — Modal, Tooltip, Popover, Dropdown
3
+ // ============================================================================
4
+ @use 'sass:map';
5
+ @use '../theme' as t;
6
+ @use '../system' as s;
7
+ @use '../mixins' as m;
8
+
9
+ // ----------------------------------------------------------------------------
10
+ // MODAL
11
+ // ----------------------------------------------------------------------------
12
+ @mixin modal-backdrop($bg: rgba(0, 0, 0, 0.5)) {
13
+ position: fixed;
14
+ inset: 0;
15
+ background: $bg;
16
+ z-index: m.z(backdrop);
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ }
21
+
22
+ @mixin modal-base(
23
+ $p: 5,
24
+ $r: xl,
25
+ $shadow: 5,
26
+ $max-width: 500px
27
+ ) {
28
+ padding: var(--modal-padding, #{m.space($p)});
29
+ border-radius: var(--modal-radius, #{m.radius($r)});
30
+ background: m.color(surface-default);
31
+ box-shadow: var(--modal-shadow, #{m.shadow($shadow)});
32
+ width: 90%;
33
+ max-width: $max-width;
34
+ max-height: 90vh;
35
+ overflow-y: auto;
36
+ z-index: m.z(modal);
37
+ }
38
+
39
+ @mixin modal-header($pb: 2) {
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: space-between;
43
+ padding-block-end: m.space($pb);
44
+ border-block-end: 1px solid m.color(border-default);
45
+ margin-block-end: m.space(4);
46
+ }
47
+
48
+ @mixin modal-footer($pt: 2) {
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: flex-end;
52
+ gap: m.space(2);
53
+ padding-block-start: m.space($pt);
54
+ border-block-start: 1px solid m.color(border-default);
55
+ margin-block-start: m.space(4);
56
+ }
57
+
58
+ // ----------------------------------------------------------------------------
59
+ // MODAL — public mixin (wraps modal-base for <dialog> semantics)
60
+ // ----------------------------------------------------------------------------
61
+ // Usage (mixin):
62
+ // .my-dialog { @include modal; }
63
+ //
64
+ // Usage (utility class, opt-in convenience):
65
+ // <dialog class="cia-modal">…</dialog>
66
+ //
67
+ // Consumer triggers via native DOM: dialog.showModal() / dialog.close().
68
+ // Escape-to-close, focus trapping, background-inert are all native browser
69
+ // behavior — Baseline since 2022. cia ships zero JS for this.
70
+ // ----------------------------------------------------------------------------
71
+ @mixin modal {
72
+ @include modal-base;
73
+
74
+ /* Reset <dialog> browser defaults */
75
+ border: 0;
76
+ margin: auto;
77
+
78
+ /* Backdrop — native ::backdrop pseudo styles the dimmed background */
79
+ &::backdrop {
80
+ background: rgba(0, 0, 0, 0.5);
81
+ backdrop-filter: blur(2px);
82
+ }
83
+
84
+ /* Open animation — only emits when [open] mounts */
85
+ &[open] {
86
+ animation: cia-modal-open var(--duration-normal, 240ms) var(--ease, ease) both;
87
+ }
88
+ &[open]::backdrop {
89
+ animation: cia-modal-backdrop var(--duration-normal, 240ms) var(--ease, ease) both;
90
+ }
91
+
92
+ @media (prefers-reduced-motion: reduce) {
93
+ &[open], &[open]::backdrop { animation: none; }
94
+ }
95
+
96
+ /* Keyframes scoped via @at-root — emit only when the mixin is called */
97
+ @at-root {
98
+ @keyframes cia-modal-open {
99
+ from { opacity: 0; transform: scale(0.96) translateY(8px); }
100
+ to { opacity: 1; transform: scale(1) translateY(0); }
101
+ }
102
+ @keyframes cia-modal-backdrop {
103
+ from { opacity: 0; }
104
+ to { opacity: 1; }
105
+ }
106
+ }
107
+ }
108
+
109
+ // ----------------------------------------------------------------------------
110
+ // TOOLTIP
111
+ // ----------------------------------------------------------------------------
112
+ @mixin tooltip-base(
113
+ $py: 1,
114
+ $px: 1,
115
+ $r: md,
116
+ $bg: text-primary,
117
+ $color: text-inverse
118
+ ) {
119
+ padding: var(--tooltip-padding-y, #{m.space($py)}) var(--tooltip-padding-x, #{m.space($px)});
120
+ border-radius: var(--tooltip-radius, #{m.radius($r)});
121
+ background: m.color($bg);
122
+ color: m.color($color);
123
+ @include m.font(reg, 1);
124
+ white-space: nowrap;
125
+ z-index: m.z(tooltip);
126
+ }
127
+
128
+ // ----------------------------------------------------------------------------
129
+ // TOOLTIP — public mixin (wraps tooltip-base for [popover] semantics)
130
+ // ----------------------------------------------------------------------------
131
+ // Usage (mixin):
132
+ // .info-tip { @include tooltip; }
133
+ //
134
+ // Usage (utility class):
135
+ // <div popover="hint" class="cia-tooltip">…</div>
136
+ //
137
+ // Consumer pairs with a trigger button:
138
+ // <button popovertarget="tip-1" type="button" aria-describedby="tip-1">?</button>
139
+ //
140
+ // Browser handles show/close/Escape natively. cia ships zero JS.
141
+ // Position is the consumer's responsibility — anchor() + position-area
142
+ // recipes documented separately.
143
+ // ----------------------------------------------------------------------------
144
+ @mixin tooltip {
145
+ @include tooltip-base;
146
+
147
+ /* Reset [popover] browser defaults */
148
+ &[popover] {
149
+ margin: 0;
150
+ border: 0;
151
+ inset: unset;
152
+ overflow: visible;
153
+ }
154
+
155
+ &:popover-open {
156
+ animation: cia-tooltip-show var(--duration-fast, 180ms) var(--ease, ease) both;
157
+ }
158
+
159
+ @media (prefers-reduced-motion: reduce) {
160
+ &:popover-open { animation: none; }
161
+ }
162
+
163
+ @at-root {
164
+ @keyframes cia-tooltip-show {
165
+ from { opacity: 0; transform: translateY(4px); }
166
+ to { opacity: 1; transform: translateY(0); }
167
+ }
168
+ }
169
+ }
170
+
171
+ // ----------------------------------------------------------------------------
172
+ // POPOVER
173
+ // ----------------------------------------------------------------------------
174
+ @mixin popover-base($p: 4, $r: lg, $shadow: 3, $max-width: 320px) {
175
+ padding: var(--popover-padding, #{m.space($p)});
176
+ border-radius: var(--popover-radius, #{m.radius($r)});
177
+ background: m.color(surface-default);
178
+ box-shadow: var(--popover-shadow, #{m.shadow($shadow)});
179
+ border: 1px solid m.color(border-default);
180
+ max-width: $max-width;
181
+ z-index: m.z(popover);
182
+ }
183
+
184
+ // ----------------------------------------------------------------------------
185
+ // DROPDOWN
186
+ // ----------------------------------------------------------------------------
187
+ @mixin dropdown-menu($py: 1, $r: md, $shadow: 2, $min-width: 12rem) {
188
+ display: flex;
189
+ flex-direction: column;
190
+ padding: m.space($py) 0;
191
+ border-radius: var(--dropdown-radius, #{m.radius($r)});
192
+ background: m.color(surface-default);
193
+ box-shadow: var(--dropdown-shadow, #{m.shadow($shadow)});
194
+ border: 1px solid m.color(border-default);
195
+ min-width: $min-width;
196
+ z-index: m.z(dropdown);
197
+ }
198
+
199
+ @mixin dropdown-item($py: 1, $px: 4) {
200
+ display: flex;
201
+ align-items: center;
202
+ gap: m.space(2);
203
+ padding: m.space($py) m.space($px);
204
+ @include m.font(reg, 2);
205
+ color: m.color(text-primary);
206
+ text-decoration: none;
207
+ cursor: pointer;
208
+ @include m.transition(background-color);
209
+
210
+ &:hover { background: m.color(interactive-hover); }
211
+ &:active { background: m.color(interactive-active); }
212
+ }
213
+
214
+ @mixin dropdown-divider($spacing: 1) {
215
+ border: none;
216
+ border-top: 1px solid m.color(border-default);
217
+ margin: m.space($spacing) 0;
218
+ }
219
+
220
+ // ----------------------------------------------------------------------------
221
+ // DROPDOWN — public mixin (wraps dropdown-menu for [popover] semantics)
222
+ // ----------------------------------------------------------------------------
223
+ // Usage (mixin):
224
+ // .user-menu { @include dropdown; }
225
+ //
226
+ // Usage (utility class):
227
+ // <div popover class="cia-dropdown">…</div>
228
+ //
229
+ // Consumer pairs with a trigger:
230
+ // <button popovertarget="user-menu" type="button">Menu</button>
231
+ //
232
+ // Browser handles auto-dismiss (click outside), Escape, focus. Zero cia JS.
233
+ // Anchor positioning (anchor() + position-area) covered in a separate docs
234
+ // recipe for browsers that support it.
235
+ // ----------------------------------------------------------------------------
236
+ @mixin dropdown {
237
+ @include dropdown-menu;
238
+
239
+ /* Reset [popover] browser defaults */
240
+ &[popover] {
241
+ margin: 0;
242
+ inset: unset;
243
+ }
244
+
245
+ &:popover-open {
246
+ animation: cia-dropdown-show var(--duration-fast, 180ms) var(--ease, ease) both;
247
+ }
248
+
249
+ @media (prefers-reduced-motion: reduce) {
250
+ &:popover-open { animation: none; }
251
+ }
252
+
253
+ @at-root {
254
+ @keyframes cia-dropdown-show {
255
+ from { opacity: 0; transform: translateY(-4px); }
256
+ to { opacity: 1; transform: translateY(0); }
257
+ }
258
+ }
259
+ }
@@ -0,0 +1,159 @@
1
+ // ============================================================================
2
+ // STEPPER — multi-step progress indicator with status-driven styling
3
+ // ============================================================================
4
+ // Mixin-first surface — consumer owns the markup (which React component goes
5
+ // in each slot, how status is computed). cia provides the geometry + status
6
+ // palette via [data-status="upcoming|active|completed|warning|error"] on the
7
+ // <li> element.
8
+ //
9
+ // Three composable mixins:
10
+ // - stepper-circle($size, $r) — single step indicator (default = upcoming look)
11
+ // - stepper-connector — line between two steps (default = neutral)
12
+ // - stepper($orientation, $size, $gap) — composed router. Wraps circles +
13
+ // connectors + labels and applies the FULL status palette via parent
14
+ // [data-status] on each <li>.
15
+ //
16
+ // Usage:
17
+ // <ol class="checkout-stepper">
18
+ // <li data-status="completed"><span data-slot="circle">✓</span><span data-slot="label">Account</span></li>
19
+ // <li data-status="active" ><span data-slot="circle">2</span><span data-slot="label">Profile</span></li>
20
+ // <li data-status="upcoming" ><span data-slot="circle">3</span><span data-slot="label">Review</span></li>
21
+ // </ol>
22
+ // .checkout-stepper { @include stepper; }
23
+ //
24
+ // Colorblind-friendly status shapes (check / triangle / diamond) are
25
+ // React-side concerns; pair this mixin with a Status component that swaps
26
+ // the data-status icon. The mixin only ships the color palette.
27
+ // ============================================================================
28
+ @use 'sass:map';
29
+ @use '../theme' as t;
30
+ @use '../system' as s;
31
+ @use '../mixins' as m;
32
+
33
+ // ----------------------------------------------------------------------------
34
+ // STEPPER-CIRCLE — single indicator (default "upcoming" appearance)
35
+ // ----------------------------------------------------------------------------
36
+ // Status palette is applied by stepper() at the composer level where the
37
+ // parent [data-status] context exists. Standalone use gives you the
38
+ // upcoming look — override the status palette in your own SCSS.
39
+ @mixin stepper-circle(
40
+ $size: 36px,
41
+ $r: full,
42
+ ) {
43
+ inline-size: $size;
44
+ block-size: $size;
45
+ border-radius: m.radius($r);
46
+ display: inline-flex;
47
+ align-items: center;
48
+ justify-content: center;
49
+ flex-shrink: 0;
50
+ @include m.transition(background-color, border-color, color);
51
+
52
+ // Default = upcoming status
53
+ background: m.color(surface-default);
54
+ border: 2px solid m.color(border-default);
55
+ color: m.color(text-muted);
56
+ }
57
+
58
+ // ----------------------------------------------------------------------------
59
+ // STEPPER-CONNECTOR — line between steps (default neutral)
60
+ // ----------------------------------------------------------------------------
61
+ @mixin stepper-connector($thickness: 2px) {
62
+ flex-grow: 1;
63
+ block-size: $thickness;
64
+ background: m.color(border-default);
65
+ @include m.transition(background-color);
66
+ }
67
+
68
+ // ----------------------------------------------------------------------------
69
+ // STEPPER — composed router (applies the full status palette)
70
+ // ----------------------------------------------------------------------------
71
+ @mixin stepper(
72
+ $orientation: horizontal,
73
+ $size: 36px,
74
+ $gap: 2,
75
+ ) {
76
+ list-style: none;
77
+ margin: 0;
78
+ padding: 0;
79
+ display: flex;
80
+ gap: m.space($gap);
81
+
82
+ @if $orientation == horizontal {
83
+ flex-direction: row;
84
+ align-items: center;
85
+ } @else if $orientation == vertical {
86
+ flex-direction: column;
87
+ align-items: flex-start;
88
+ } @else {
89
+ @error "stepper(): unknown orientation '#{$orientation}'. Known: horizontal, vertical";
90
+ }
91
+
92
+ > li {
93
+ display: inline-flex;
94
+ align-items: center;
95
+ gap: m.space($gap);
96
+ flex-shrink: 0;
97
+
98
+ @if $orientation == horizontal {
99
+ flex-grow: 1;
100
+ &:last-child { flex-grow: 0; }
101
+ }
102
+ }
103
+
104
+ // Slot primitives — defaults
105
+ [data-slot='circle'] { @include stepper-circle($size); }
106
+ [data-slot='connector'] { @include stepper-connector; }
107
+ [data-slot='label'] {
108
+ @include m.font(medium, 2);
109
+ color: m.color(text-secondary);
110
+ }
111
+
112
+ // Status palette — applied at the composer level so the parent <li>
113
+ // [data-status] context is available without selector contortions.
114
+ > li[data-status='active'] {
115
+ > [data-slot='circle'] {
116
+ background: m.color(action-primary-default);
117
+ border-color: transparent;
118
+ color: m.color(text-inverse);
119
+ box-shadow: 0 0 0 4px color-mix(in oklch, m.color(action-primary-default), transparent 80%);
120
+ }
121
+ > [data-slot='label'] {
122
+ color: m.color(text-primary);
123
+ }
124
+ }
125
+
126
+ > li[data-status='completed'] {
127
+ > [data-slot='circle'] {
128
+ background: m.color(success-default);
129
+ border-color: transparent;
130
+ color: m.color(text-inverse);
131
+ }
132
+ > [data-slot='label'] {
133
+ color: m.color(success-text);
134
+ }
135
+ }
136
+
137
+ > li[data-status='warning'] {
138
+ > [data-slot='circle'] {
139
+ background: m.color(warning-subtle);
140
+ border-color: m.color(warning-text);
141
+ color: m.color(warning-text);
142
+ }
143
+ }
144
+
145
+ > li[data-status='error'] {
146
+ > [data-slot='circle'] {
147
+ background: m.color(error-subtle);
148
+ border-color: m.color(error-text);
149
+ color: m.color(error-text);
150
+ }
151
+ }
152
+
153
+ // Connector palette — only the connector IMMEDIATELY after a completed
154
+ // step gets the success color. Adjacent sibling (+), not general sibling (~),
155
+ // so connectors after an "upcoming" step don't get over-greened.
156
+ > li[data-status='completed'] + li > [data-slot='connector'] {
157
+ background: m.color(success-default);
158
+ }
159
+ }
@@ -0,0 +1,72 @@
1
+ // ============================================================================
2
+ // TABS
3
+ // ============================================================================
4
+ // Native <input type="radio"> state + :has() + :nth-of-type() pattern.
5
+ // Zero JavaScript for panel-switching.
6
+ //
7
+ // Usage:
8
+ // <div class="cia-tabs">
9
+ // <input type="radio" name="t" id="t1" checked>
10
+ // <input type="radio" name="t" id="t2">
11
+ // <div class="cia-tab-list" role="tablist">
12
+ // <label for="t1" role="tab">Tab 1</label>
13
+ // <label for="t2" role="tab">Tab 2</label>
14
+ // </div>
15
+ // <div class="cia-tab-panel" role="tabpanel">Content 1</div>
16
+ // <div class="cia-tab-panel" role="tabpanel">Content 2</div>
17
+ // </div>
18
+ //
19
+ // A11y baseline: keyboard nav (Tab + arrows + Space) and screen-reader text
20
+ // are native. For full aria-selected sync ship the tiny opt-in JS shim
21
+ // documented at /docs/components/tabs#aria.
22
+ //
23
+ // :has() Baseline Dec 2023; :nth-of-type() universal.
24
+ // ============================================================================
25
+ @use '../mixins' as m;
26
+
27
+ @mixin tabs($max-tabs: 12) {
28
+ display: flex;
29
+ flex-direction: column;
30
+
31
+ /* Hide radios — functional only, not visual */
32
+ > input[type="radio"] {
33
+ position: absolute;
34
+ opacity: 0;
35
+ pointer-events: none;
36
+ }
37
+
38
+ > .cia-tab-list {
39
+ display: flex;
40
+ gap: m.space(1);
41
+ border-block-end: 1px solid m.color(border-default);
42
+
43
+ > label {
44
+ padding: m.space(2) m.space(3);
45
+ cursor: pointer;
46
+ color: m.color(text-secondary);
47
+ border-block-end: 2px solid transparent;
48
+ margin-block-end: -1px;
49
+ min-height: var(--touch-target-min, 24px);
50
+ @include m.transition(border-color, color);
51
+
52
+ &:hover { color: m.color(text-primary); }
53
+ @include m.focus-ring;
54
+ }
55
+ }
56
+
57
+ > .cia-tab-panel {
58
+ display: none;
59
+ padding-block-start: m.space(4);
60
+ }
61
+
62
+ /* For each (nth input checked) → show nth panel + style nth label */
63
+ @for $i from 1 through $max-tabs {
64
+ &:has(> input:nth-of-type(#{$i}):checked) > .cia-tab-panel:nth-of-type(#{$i}) {
65
+ display: block;
66
+ }
67
+ &:has(> input:nth-of-type(#{$i}):checked) > .cia-tab-list > label:nth-of-type(#{$i}) {
68
+ color: m.color(text-primary);
69
+ border-block-end-color: m.color(action-primary-default);
70
+ }
71
+ }
72
+ }
package/scss/core.scss ADDED
@@ -0,0 +1,54 @@
1
+ // ============================================================================
2
+ // CORE - Tokens + resets only (no utilities)
3
+ // ============================================================================
4
+ @use './generator';
5
+ @use './mixins' as m;
6
+
7
+ @include generator.generate-theme;
8
+
9
+ // WCAG 2.2 SC 2.5.8 — minimum touch-target size. Themes can override.
10
+ :root {
11
+ --touch-target-min: 24px;
12
+ }
13
+
14
+ *,
15
+ *::before,
16
+ *::after {
17
+ box-sizing: border-box;
18
+ }
19
+
20
+ html {
21
+ -webkit-font-smoothing: antialiased;
22
+ -moz-osx-font-smoothing: grayscale;
23
+ }
24
+
25
+ body {
26
+ margin: 0;
27
+ font-family: m.font-family(primary);
28
+ font-size: m.font-size(base);
29
+ line-height: m.line-height(normal);
30
+ color: m.color(text-primary);
31
+ background: m.color(surface-default);
32
+ }
33
+
34
+ @include m.header-reset;
35
+ @include m.form-reset;
36
+
37
+ a {
38
+ color: m.color(text-link);
39
+ text-decoration: none;
40
+ @include m.transition(color);
41
+
42
+ &:hover {
43
+ color: m.color(text-link-hover);
44
+ }
45
+ }
46
+
47
+ :focus-visible {
48
+ outline: 2px solid m.color(border-focus);
49
+ outline-offset: 2px;
50
+ }
51
+
52
+ :focus:not(:focus-visible) {
53
+ outline: none;
54
+ }
@@ -0,0 +1,107 @@
1
+ // ============================================================================
2
+ // THEMING EXAMPLES
3
+ // ============================================================================
4
+ // Shows how consumers can customize css-is-awesome without forking.
5
+ // ============================================================================
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // METHOD 1: CSS Custom Property Overrides (easiest, runtime-capable)
9
+ // ---------------------------------------------------------------------------
10
+ // Just set CSS custom properties at :root to remap any token.
11
+ // This works with the compiled CSS — no SCSS needed.
12
+ //
13
+ // :root {
14
+ // --brand-primary: #E11D48;
15
+ // --brand-primary-hover: #BE123C;
16
+ // --brand-primary-active: #9F1239;
17
+ // --action-primary-default: #E11D48;
18
+ // --action-primary-hover: #BE123C;
19
+ // --action-primary-active: #9F1239;
20
+ // --font-primary: "Poppins", sans-serif;
21
+ // --radius-md: 0.5rem;
22
+ // }
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // METHOD 2: SCSS-Level Overrides (full control, compile-time)
26
+ // ---------------------------------------------------------------------------
27
+ // Override the theme maps before importing the generator.
28
+ //
29
+ // @use "css-is-awesome/scss/theme" with (
30
+ // $brand: (
31
+ // primary: #E11D48,
32
+ // primary-hover: #BE123C,
33
+ // primary-active: #9F1239,
34
+ // secondary: #8B5CF6,
35
+ // secondary-hover:#7C3AED,
36
+ // secondary-active:#6D28D9,
37
+ // accent: #06B6D4,
38
+ // accent-hover: #0891B2,
39
+ // )
40
+ // );
41
+ // @use "css-is-awesome/scss/generator";
42
+ // @include generator.generate-theme;
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // METHOD 3: Multi-Brand Theming
46
+ // ---------------------------------------------------------------------------
47
+ // Use data-theme attributes for brand + mode combinations.
48
+
49
+ // Brand A — Rose theme
50
+ [data-theme="brand-a-light"] {
51
+ --brand-primary: #E11D48;
52
+ --brand-primary-hover: #BE123C;
53
+ --brand-primary-active: #9F1239;
54
+ --action-primary-default: #E11D48;
55
+ --action-primary-hover: #BE123C;
56
+ --action-primary-active: #9F1239;
57
+ --brand-secondary: #8B5CF6;
58
+ --brand-secondary-hover: #7C3AED;
59
+ --brand-secondary-active: #6D28D9;
60
+ --action-secondary-default: #8B5CF6;
61
+ --action-secondary-hover: #7C3AED;
62
+ --action-secondary-active: #6D28D9;
63
+ }
64
+
65
+ [data-theme="brand-a-dark"] {
66
+ --brand-primary: #FB7185;
67
+ --brand-primary-hover: #F43F5E;
68
+ --brand-primary-active: #E11D48;
69
+ --action-primary-default: #FB7185;
70
+ --action-primary-hover: #F43F5E;
71
+ --action-primary-active: #E11D48;
72
+ --brand-secondary: #A78BFA;
73
+ --brand-secondary-hover: #8B5CF6;
74
+ --brand-secondary-active: #7C3AED;
75
+ --action-secondary-default: #A78BFA;
76
+ --action-secondary-hover: #8B5CF6;
77
+ --action-secondary-active: #7C3AED;
78
+ --background-default: #0A0A0A;
79
+ --surface-default: #151515;
80
+ --text-primary: #FFF;
81
+ --text-secondary: #B8B8B8;
82
+ --border-default: #2A2A2A;
83
+ }
84
+
85
+ // Brand B — Teal theme
86
+ [data-theme="brand-b-light"] {
87
+ --brand-primary: #0D9488;
88
+ --brand-primary-hover: #0F766E;
89
+ --brand-primary-active: #115E59;
90
+ --action-primary-default: #0D9488;
91
+ --action-primary-hover: #0F766E;
92
+ --action-primary-active: #115E59;
93
+ }
94
+
95
+ [data-theme="brand-b-dark"] {
96
+ --brand-primary: #2DD4BF;
97
+ --brand-primary-hover: #14B8A6;
98
+ --brand-primary-active: #0D9488;
99
+ --action-primary-default: #2DD4BF;
100
+ --action-primary-hover: #14B8A6;
101
+ --action-primary-active: #0D9488;
102
+ --background-default: #0A0A0A;
103
+ --surface-default: #151515;
104
+ --text-primary: #FFF;
105
+ --text-secondary: #B8B8B8;
106
+ --border-default: #2A2A2A;
107
+ }