@acorex/styles 22.1.0-next.0 → 22.1.0-next.2

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.
@@ -1,4 +1,11 @@
1
1
  .ax-action-sheet-panel {
2
+ --ax-comp-action-sheet-shadow-rest: var(--ax-sys-effect-modal);
3
+ --ax-comp-action-sheet-inner-border-rest: var(--ax-sys-inner-border-surface);
4
+ --ax-comp-action-sheet-contrast-inner-border-rest: var(--ax-sys-contrast-inner-border-surface);
5
+ --ax-comp-action-sheet-contrast-surface-overlay-rest: var(--ax-sys-contrast-surface-overlay-surface);
6
+ --ax-comp-action-sheet-backdrop-filter-rest: var(--ax-sys-backdrop-filter-surface);
7
+ --ax-comp-action-sheet-surface-overlay-rest: var(--ax-sys-surface-overlay-modal);
8
+
2
9
  @apply fixed! top-auto! right-auto! bottom-0! left-1/2! block! h-auto! w-auto! max-w-none!;
3
10
  transform: translateX(-50%) !important;
4
11
  align-items: unset !important;
@@ -8,10 +15,20 @@
8
15
  border-top-left-radius: var(--ax-comp-action-sheet-border-radius-size);
9
16
  border-top-right-radius: var(--ax-comp-action-sheet-border-radius-size);
10
17
  background-color: rgba(var(--ax-sys-color-surface-lowest));
11
- --ax-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
12
- --ax-shadow-colored: 0 10px 15px -3px var(--ax-shadow-color), 0 4px 6px -4px var(--ax-shadow-color);
18
+ background-image:
19
+ linear-gradient(
20
+ var(--ax-comp-action-sheet-contrast-surface-overlay-rest),
21
+ var(--ax-comp-action-sheet-contrast-surface-overlay-rest)
22
+ ),
23
+ linear-gradient(
24
+ var(--ax-comp-action-sheet-surface-overlay-rest),
25
+ var(--ax-comp-action-sheet-surface-overlay-rest)
26
+ );
13
27
  box-shadow:
14
- var(--ax-ring-offset-shadow, 0 0 rgba(0, 0, 0, 0)), var(--ax-ring-shadow, 0 0 rgba(0, 0, 0, 0)), var(--ax-shadow);
28
+ var(--ax-comp-action-sheet-contrast-inner-border-rest), var(--ax-comp-action-sheet-inner-border-rest),
29
+ var(--ax-comp-action-sheet-shadow-rest);
30
+ backdrop-filter: var(--ax-comp-action-sheet-backdrop-filter-rest);
31
+ -webkit-backdrop-filter: var(--ax-comp-action-sheet-backdrop-filter-rest);
15
32
  animation: 1s both ax-fadeInUp;
16
33
  animation-duration: var(--ax-sys-transition-duration);
17
34
  }
@@ -7,9 +7,7 @@
7
7
  overflow-x: auto;
8
8
  overflow-y: hidden;
9
9
  font-size: 0.875rem;
10
- /* 14px */
11
10
  line-height: 1.25rem;
12
- /* 20px */
13
11
  text-transform: capitalize;
14
12
  &.ax-state-disabled {
15
13
  cursor: not-allowed;
@@ -19,28 +17,51 @@
19
17
  }
20
18
 
21
19
  .ax-overlay-pane {
20
+ --ax-comp-dropdown-shadow-rest: var(--ax-sys-effect-overlay);
21
+ --ax-comp-dropdown-inner-border-rest: var(--ax-sys-inner-border-surface);
22
+ --ax-comp-dropdown-contrast-inner-border-rest: var(--ax-sys-contrast-inner-border-surface);
23
+ --ax-comp-dropdown-contrast-surface-overlay-rest: var(--ax-sys-contrast-surface-overlay-surface);
24
+ --ax-comp-dropdown-backdrop-filter-rest: var(--ax-sys-backdrop-filter-surface);
25
+ --ax-comp-dropdown-surface-overlay-rest: var(--ax-sys-surface-overlay-overlay);
26
+
22
27
  margin: 0.25rem 0;
23
- /* min-width: 10rem; */
24
28
  width: 100%;
25
29
  height: fit-content;
26
30
  overflow: hidden;
27
31
  border-width: 1px;
28
32
  border-color: rgba(var(--ax-sys-color-border-lightest-surface));
33
+ /* Resolve text against local theme tokens (overlays are portaled). */
34
+ color: rgba(var(--ax-sys-color-on-surface));
35
+ /*
36
+ * Use opaque rgba(channels) only.
37
+ * Do NOT use rgb(channels / alpha) or rgba(channels, alpha):
38
+ * LightningCSS rewrites those to slash-syntax which is invalid with
39
+ * comma-separated RGB tokens (255, 255, 255) and yields a transparent panel.
40
+ */
29
41
  background-color: rgba(var(--ax-sys-color-lightest-surface));
30
- --ax-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
31
- --ax-shadow-colored: 0 4px 6px -1px var(--ax-shadow-color), 0 2px 4px -2px var(--ax-shadow-color);
42
+ background-image:
43
+ linear-gradient(
44
+ var(--ax-comp-dropdown-contrast-surface-overlay-rest),
45
+ var(--ax-comp-dropdown-contrast-surface-overlay-rest)
46
+ ),
47
+ linear-gradient(
48
+ var(--ax-comp-dropdown-surface-overlay-rest),
49
+ var(--ax-comp-dropdown-surface-overlay-rest)
50
+ );
32
51
  box-shadow:
33
- var(--ax-ring-offset-shadow, 0 0 rgba(0, 0, 0, 0)), var(--ax-ring-shadow, 0 0 rgba(0, 0, 0, 0)), var(--ax-shadow);
52
+ var(--ax-comp-dropdown-contrast-inner-border-rest), var(--ax-comp-dropdown-inner-border-rest),
53
+ var(--ax-comp-dropdown-shadow-rest);
54
+ backdrop-filter: var(--ax-comp-dropdown-backdrop-filter-rest);
55
+ -webkit-backdrop-filter: var(--ax-comp-dropdown-backdrop-filter-rest);
34
56
  border-top-left-radius: var(--ax-comp-drop-down-border-top-left-radius, var(--ax-sys-border-radius));
35
57
  border-top-right-radius: var(--ax-comp-drop-down-border-top-right-radius, var(--ax-sys-border-radius));
36
58
  border-bottom-left-radius: var(--ax-comp-drop-down-border-bottom-left-radius, var(--ax-sys-border-radius));
37
59
  border-bottom-right-radius: var(--ax-comp-drop-down-border-bottom-right-radius, var(--ax-sys-border-radius));
38
- /* Replace the @include mixin with a normal media query */
60
+
39
61
  ax-header,
40
62
  ax-footer {
41
63
  background-color: rgba(var(--ax-sys-color-lightest-surface));
42
64
  padding: 0.75rem;
43
- /* 12px */
44
65
  }
45
66
 
46
67
  &.ax-overlay-center {
@@ -58,9 +79,13 @@
58
79
  }
59
80
  }
60
81
 
61
- .dark {
82
+ .ax-dark .ax-overlay-pane {
83
+ background-color: rgba(var(--ax-sys-color-darker-surface));
84
+ border-color: rgba(var(--ax-sys-color-border-darker-surface));
85
+ }
86
+
87
+ @supports not (backdrop-filter: blur(1px)) {
62
88
  .ax-overlay-pane {
63
- background-color: rgba(var(--ax-sys-color-darker-surface));
64
- border-color: rgba(var(--ax-sys-color-border-darker-surface));
89
+ --ax-comp-dropdown-backdrop-filter-rest: none;
65
90
  }
66
91
  }
@@ -2,7 +2,56 @@
2
2
 
3
3
  @layer base {
4
4
  .ax-editor-container {
5
+ --ax-comp-editor-shadow-rest: var(--ax-sys-effect-field-rest);
6
+ --ax-comp-editor-shadow-hover: var(--ax-sys-effect-field-hover);
7
+ --ax-comp-editor-shadow-focus: var(--ax-sys-effect-field-focus);
8
+ --ax-comp-editor-shadow-readonly: var(--ax-sys-effect-field-readonly);
9
+ --ax-comp-editor-shadow-disabled: var(--ax-sys-effect-field-disabled);
10
+ --ax-comp-editor-surface-overlay-rest: var(--ax-sys-surface-overlay-field-rest);
11
+ --ax-comp-editor-surface-overlay-hover: var(--ax-sys-surface-overlay-field-hover);
12
+ --ax-comp-editor-surface-overlay-focus: var(--ax-sys-surface-overlay-field-focus);
13
+ --ax-comp-editor-surface-overlay-readonly: var(--ax-sys-surface-overlay-field-readonly);
14
+ --ax-comp-editor-surface-overlay-disabled: var(--ax-sys-surface-overlay-field-disabled);
15
+ --ax-comp-editor-highlight-rest: var(--ax-sys-highlight-control-subtle);
16
+ --ax-comp-editor-inner-border-rest: var(--ax-sys-inner-border-control);
17
+ --ax-comp-editor-contrast-inner-border-rest: var(--ax-sys-contrast-inner-border-field);
18
+ --ax-comp-editor-contrast-inner-border-hover: var(--ax-sys-contrast-inner-border-field);
19
+ --ax-comp-editor-contrast-inner-border-focus: var(--ax-sys-contrast-inner-border-field);
20
+ --ax-comp-editor-contrast-inner-border-invalid: var(--ax-sys-contrast-inner-border-invalid);
21
+ --ax-comp-editor-contrast-surface-overlay-rest: var(--ax-sys-contrast-surface-overlay-field);
22
+ --ax-comp-editor-contrast-ring: var(--ax-comp-editor-contrast-inner-border-rest);
23
+ --ax-comp-editor-transition-duration: var(--ax-sys-motion-duration);
24
+ --ax-comp-editor-transition-timing: var(--ax-sys-motion-timing);
25
+
5
26
  @apply rounded-default h-default min-h-default relative flex items-center justify-between overflow-hidden px-3 py-3 text-sm leading-5;
27
+ /*
28
+ * Field inset/elevation only on the host. Contrast border is painted on ::after
29
+ * so native controls (textarea) cannot cover it.
30
+ */
31
+ box-shadow: var(--ax-comp-editor-shadow-rest);
32
+ background-image:
33
+ linear-gradient(
34
+ var(--ax-comp-editor-contrast-surface-overlay-rest),
35
+ var(--ax-comp-editor-contrast-surface-overlay-rest)
36
+ ),
37
+ linear-gradient(
38
+ var(--ax-comp-editor-surface-overlay-rest),
39
+ var(--ax-comp-editor-surface-overlay-rest)
40
+ );
41
+ transform: none;
42
+ transition-property: box-shadow, border-color, background-color, color;
43
+ transition-duration: var(--ax-comp-editor-transition-duration);
44
+ transition-timing-function: var(--ax-comp-editor-transition-timing);
45
+
46
+ &::after {
47
+ content: '';
48
+ position: absolute;
49
+ inset: 0;
50
+ border-radius: inherit;
51
+ pointer-events: none;
52
+ z-index: 1;
53
+ box-shadow: var(--ax-comp-editor-contrast-ring);
54
+ }
6
55
 
7
56
  .ax-content {
8
57
  @apply text-sm;
@@ -27,13 +76,16 @@
27
76
  }
28
77
 
29
78
  &.ax-state-error {
30
- @apply border-danger-600!;
79
+ --ax-comp-editor-contrast-ring: var(--ax-comp-editor-contrast-inner-border-invalid);
80
+ border-color: var(--ax-sys-contrast-border-invalid);
81
+
31
82
  &:focus-within {
32
- @apply outline-danger-light outline-2 outline-offset-0;
83
+ --ax-comp-editor-contrast-ring: var(--ax-comp-editor-contrast-inner-border-invalid);
84
+ outline: var(--ax-sys-contrast-focus-ring-invalid);
85
+ outline-offset: 0;
33
86
  }
34
87
  }
35
88
 
36
- /* Keep end padding for spin/clear controls, but not when a suffix button is attached */
37
89
  &:has(.ax-general-button-control, .ax-general-button-icon):not(:has(ax-suffix > ax-button)) {
38
90
  @apply pe-2;
39
91
  }
@@ -81,7 +133,6 @@
81
133
  }
82
134
  }
83
135
 
84
- /* Components layer so these beat button size utilities and spin-button pe-2 */
85
136
  @layer components {
86
137
  .ax-editor-container {
87
138
  &:has(ax-prefix > ax-button),
@@ -109,5 +160,99 @@
109
160
  @apply aspect-square size-auto! h-full w-auto!;
110
161
  }
111
162
  }
163
+
164
+ /* Field appearance — recessed inset for all looks; never outer elevation */
165
+ &:is(.ax-solid, .ax-outline, .ax-twotone, .ax-fill, .ax-flat, .ax-blank) {
166
+ --ax-comp-editor-contrast-ring: var(--ax-comp-editor-contrast-inner-border-rest);
167
+ box-shadow: var(--ax-comp-editor-shadow-rest);
168
+ background-image:
169
+ linear-gradient(
170
+ var(--ax-comp-editor-contrast-surface-overlay-rest),
171
+ var(--ax-comp-editor-contrast-surface-overlay-rest)
172
+ ),
173
+ linear-gradient(
174
+ var(--ax-comp-editor-surface-overlay-rest),
175
+ var(--ax-comp-editor-surface-overlay-rest)
176
+ );
177
+ transform: none;
178
+ }
179
+
180
+ &:is(.ax-solid, .ax-outline, .ax-twotone, .ax-fill, .ax-flat, .ax-blank):hover:not(
181
+ .ax-state-disabled,
182
+ .ax-state-readonly,
183
+ .ax-state-error
184
+ ) {
185
+ --ax-comp-editor-contrast-ring: var(--ax-comp-editor-contrast-inner-border-hover);
186
+ box-shadow: var(--ax-comp-editor-shadow-hover);
187
+ background-image:
188
+ linear-gradient(
189
+ var(--ax-comp-editor-contrast-surface-overlay-rest),
190
+ var(--ax-comp-editor-contrast-surface-overlay-rest)
191
+ ),
192
+ linear-gradient(
193
+ var(--ax-comp-editor-surface-overlay-hover),
194
+ var(--ax-comp-editor-surface-overlay-hover)
195
+ );
196
+ }
197
+
198
+ &:is(.ax-solid, .ax-outline, .ax-twotone, .ax-fill, .ax-flat, .ax-blank).ax-state-readonly {
199
+ --ax-comp-editor-contrast-ring: var(--ax-comp-editor-contrast-inner-border-rest);
200
+ box-shadow: var(--ax-comp-editor-shadow-readonly);
201
+ background-image:
202
+ linear-gradient(
203
+ var(--ax-comp-editor-contrast-surface-overlay-rest),
204
+ var(--ax-comp-editor-contrast-surface-overlay-rest)
205
+ ),
206
+ linear-gradient(
207
+ var(--ax-comp-editor-surface-overlay-readonly),
208
+ var(--ax-comp-editor-surface-overlay-readonly)
209
+ );
210
+ }
211
+
212
+ &:is(.ax-solid, .ax-outline, .ax-twotone, .ax-fill, .ax-flat, .ax-blank).ax-state-disabled {
213
+ --ax-comp-editor-contrast-ring: var(--ax-comp-editor-contrast-inner-border-rest);
214
+ box-shadow: var(--ax-comp-editor-shadow-disabled);
215
+ background-image:
216
+ linear-gradient(
217
+ var(--ax-comp-editor-contrast-surface-overlay-rest),
218
+ var(--ax-comp-editor-contrast-surface-overlay-rest)
219
+ ),
220
+ linear-gradient(
221
+ var(--ax-comp-editor-surface-overlay-disabled),
222
+ var(--ax-comp-editor-surface-overlay-disabled)
223
+ );
224
+ opacity: var(--ax-sys-contrast-disabled-opacity, 1);
225
+ }
226
+
227
+ &:is(.ax-solid, .ax-outline, .ax-twotone, .ax-fill, .ax-flat, .ax-blank):focus-within:not(
228
+ .ax-state-disabled,
229
+ .ax-state-readonly,
230
+ .ax-state-error
231
+ ) {
232
+ --ax-comp-editor-contrast-ring: var(--ax-comp-editor-contrast-inner-border-focus);
233
+ box-shadow: var(--ax-comp-editor-shadow-focus);
234
+ background-image:
235
+ linear-gradient(
236
+ var(--ax-comp-editor-contrast-surface-overlay-rest),
237
+ var(--ax-comp-editor-contrast-surface-overlay-rest)
238
+ ),
239
+ linear-gradient(
240
+ var(--ax-comp-editor-surface-overlay-focus),
241
+ var(--ax-comp-editor-surface-overlay-focus)
242
+ );
243
+ }
244
+
245
+ &.ax-state-error {
246
+ --ax-comp-editor-contrast-ring: var(--ax-comp-editor-contrast-inner-border-invalid);
247
+ border-color: var(--ax-sys-contrast-border-invalid);
248
+ box-shadow: var(--ax-comp-editor-shadow-rest);
249
+
250
+ &:focus-within {
251
+ --ax-comp-editor-contrast-ring: var(--ax-comp-editor-contrast-inner-border-invalid);
252
+ box-shadow: var(--ax-comp-editor-shadow-focus);
253
+ outline: var(--ax-sys-contrast-focus-ring-invalid);
254
+ outline-offset: 0;
255
+ }
256
+ }
112
257
  }
113
258
  }
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Floating overlays opt out of Appearance + Contrast decorative boundaries.
3
+ * Theme (ax-light / ax-dark) and size still inherit from overlay visual context.
4
+ *
5
+ * Loaded after contrast/appearance theme sheets so these resets win on-pane.
6
+ */
7
+ :is(.ax-popup, ax-toast, .ax-overlay-pane, .ax-dialog) {
8
+ --ax-sys-contrast-inner-border-surface: 0 0 #0000;
9
+ --ax-sys-contrast-surface-overlay-surface: transparent;
10
+
11
+ --ax-sys-inner-border-surface: 0 0 #0000;
12
+ --ax-sys-highlight-surface: 0 0 #0000;
13
+ --ax-sys-gradient-surface: none;
14
+ --ax-sys-backdrop-filter-surface: none;
15
+ --ax-sys-surface-overlay-surface: transparent;
16
+ --ax-sys-surface-overlay-floating: transparent;
17
+ --ax-sys-surface-overlay-overlay: transparent;
18
+ --ax-sys-surface-overlay-modal: transparent;
19
+
20
+ /* Flat elevation — ignore depth/translucent shadow stacks on floating shells */
21
+ --ax-sys-effect-floating: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
22
+ --ax-sys-effect-overlay: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
23
+ --ax-sys-effect-modal: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
24
+ }
@@ -1,4 +1,4 @@
1
- .dark {
1
+ .ax-dark {
2
2
  .ax-list-item {
3
3
  &.ax-state-selected {
4
4
  background-color: rgba(var(--ax-sys-color-primary-800)) !important;
@@ -99,6 +99,7 @@
99
99
  padding-inline-start: 0.75rem;
100
100
  font-size: 1rem;
101
101
  line-height: 1.5rem;
102
+ color: rgba(var(--ax-sys-color-on-surface));
102
103
  &:focus,
103
104
  &:focus-visible {
104
105
  outline-width: 2px;
@@ -3,6 +3,7 @@
3
3
  @import './_check-box.css';
4
4
  @import './_drop-down.css';
5
5
  @import './_editor-container.css';
6
+ @import './_floating-surface.css';
6
7
  @import './_general-button.css';
7
8
  @import './_list.css';
8
9
  @import './_radio.css';
package/package.json CHANGED
@@ -1,9 +1,80 @@
1
1
  {
2
2
  "name": "@acorex/styles",
3
- "version": "22.1.0-next.0",
3
+ "version": "22.1.0-next.2",
4
4
  "main": "index.css",
5
5
  "author": "Ali Safari",
6
6
  "license": "ISC",
7
+ "exports": {
8
+ ".": {
9
+ "style": "./index.css",
10
+ "default": "./index.css"
11
+ },
12
+ "./index.css": {
13
+ "style": "./index.css",
14
+ "default": "./index.css"
15
+ },
16
+ "./package.json": "./package.json",
17
+ "./themes/default.css": {
18
+ "style": "./themes/default.css",
19
+ "default": "./themes/default.css"
20
+ },
21
+ "./themes/appearance.css": {
22
+ "style": "./themes/appearance.css",
23
+ "default": "./themes/appearance.css"
24
+ },
25
+ "./themes/appearances": {
26
+ "style": "./themes/appearances/index.css",
27
+ "default": "./themes/appearances/index.css"
28
+ },
29
+ "./themes/appearances/index.css": {
30
+ "style": "./themes/appearances/index.css",
31
+ "default": "./themes/appearances/index.css"
32
+ },
33
+ "./themes/appearances/flat.css": {
34
+ "style": "./themes/appearances/flat.css",
35
+ "default": "./themes/appearances/flat.css"
36
+ },
37
+ "./themes/appearances/depth.css": {
38
+ "style": "./themes/appearances/depth.css",
39
+ "default": "./themes/appearances/depth.css"
40
+ },
41
+ "./themes/appearances/translucent.css": {
42
+ "style": "./themes/appearances/translucent.css",
43
+ "default": "./themes/appearances/translucent.css"
44
+ },
45
+ "./themes/contrast": {
46
+ "style": "./themes/contrast/index.css",
47
+ "default": "./themes/contrast/index.css"
48
+ },
49
+ "./themes/contrast/index.css": {
50
+ "style": "./themes/contrast/index.css",
51
+ "default": "./themes/contrast/index.css"
52
+ },
53
+ "./themes/contrast/enhanced.css": {
54
+ "style": "./themes/contrast/enhanced.css",
55
+ "default": "./themes/contrast/enhanced.css"
56
+ },
57
+ "./themes/contrast/high.css": {
58
+ "style": "./themes/contrast/high.css",
59
+ "default": "./themes/contrast/high.css"
60
+ },
61
+ "./icons/fontawesome/index.css": {
62
+ "style": "./icons/fontawesome/index.css",
63
+ "default": "./icons/fontawesome/index.css"
64
+ },
65
+ "./icons/material/index.css": {
66
+ "style": "./icons/material/index.css",
67
+ "default": "./icons/material/index.css"
68
+ },
69
+ "./icons/lucide/index.css": {
70
+ "style": "./icons/lucide/index.css",
71
+ "default": "./icons/lucide/index.css"
72
+ },
73
+ "./components/index.css": {
74
+ "style": "./components/index.css",
75
+ "default": "./components/index.css"
76
+ }
77
+ },
7
78
  "peerDependencies": {
8
79
  "@angular/cdk": ">=21.0.0",
9
80
  "tailwindcss": ">=4.0.0",
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Contract checks for the optional Depth appearance layer.
3
+ * Run: node packages/styles/themes/appearance.contract.mjs
4
+ */
5
+ import { readFileSync } from 'node:fs';
6
+ import { dirname, join } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const root = join(__dirname, '../../..');
11
+
12
+ const defaultCss = readFileSync(join(__dirname, 'default.css'), 'utf8');
13
+ const appearanceCss = readFileSync(join(__dirname, 'appearance.css'), 'utf8');
14
+
15
+ let failed = 0;
16
+
17
+ function assert(condition, message) {
18
+ if (!condition) {
19
+ failed += 1;
20
+ console.error(`FAIL: ${message}`);
21
+ } else {
22
+ console.log(`PASS: ${message}`);
23
+ }
24
+ }
25
+
26
+ assert(defaultCss.includes('--ax-sys-elevation-control-rest:'), 'Flat elevation tokens exist');
27
+ assert(defaultCss.includes('--ax-sys-effect-control-rest:'), 'Combined effect tokens exist');
28
+ assert(!defaultCss.includes('--ax-sys-press-offset'), 'Press offset token removed from Flat defaults');
29
+ assert(defaultCss.includes('@utility ax-effect-control'), 'ax-effect-control utility exists');
30
+ assert(defaultCss.includes('@utility ax-effect-input'), 'ax-effect-input utility exists');
31
+ assert(defaultCss.includes('@utility ax-focus-ring'), 'Focus ring utility preserved');
32
+ assert(/@utility ax-effect-control-active \{[\s\S]*?transform: none/.test(defaultCss), 'Active utility keeps transform none');
33
+ assert(
34
+ /@utility ax-effect-transition \{[\s\S]*?transition-property: box-shadow, background-image, border-color/.test(
35
+ defaultCss,
36
+ ),
37
+ 'Button effect transition excludes transform',
38
+ );
39
+ assert(/@utility ax-solid \{[\s\S]*?ax-effect-control/.test(defaultCss), 'Solid uses control effect');
40
+ assert(/@utility ax-outline \{[\s\S]*?ax-effect-control-subtle/.test(defaultCss), 'Outline uses subtle effect');
41
+ assert(/@utility ax-link \{[\s\S]*?ax-effect-control/.test(defaultCss) === false, 'Link has no control elevation');
42
+ assert(defaultCss.includes('box-shadow: var(--ax-sys-effect-input)'), 'Editors use inset effect');
43
+ assert(!defaultCss.includes('translateY(var(--ax-sys-press-offset))'), 'No press-offset translateY remains');
44
+
45
+ assert(appearanceCss.includes('.ax-appearance-depth'), 'Depth activator class exists');
46
+ assert(appearanceCss.includes('0 1px 1px rgb(15 23 42 / 0.08)'), 'Solid rest uses tight contact shadow');
47
+ assert(appearanceCss.includes('0 1px 2px rgb(15 23 42 / 0.1)'), 'Solid hover stays close to control');
48
+ assert(appearanceCss.includes('0 1px 1px rgb(15 23 42 / 0.05)'), 'Subtle rest is weaker than Solid');
49
+ assert(appearanceCss.includes('--ax-sys-elevation-control-subtle-rest:'), 'Subtle control elevation exists');
50
+ assert(appearanceCss.includes('--ax-sys-gradient-control-subtle: none'), 'Outline/Twotone keep no gradient');
51
+ assert(appearanceCss.includes('rgb(255 255 255 / 0.06)'), 'Solid gradient is nearly imperceptible');
52
+ assert(!appearanceCss.includes('--ax-sys-press-offset'), 'Press offset token removed from Depth');
53
+ assert(!appearanceCss.includes('translateY'), 'Depth sheet has no translateY');
54
+ assert(
55
+ appearanceCss.includes('--ax-sys-effect-control-active: var(--ax-sys-inset-pressed)'),
56
+ 'Active uses inset pressed',
57
+ );
58
+ assert(appearanceCss.includes('.ax-dark.ax-appearance-depth'), 'Dark depth selector exists');
59
+ assert(appearanceCss.includes('.ax-dark.ax-appearance-depth .ax-light'), 'Nested light depth reset exists');
60
+ assert(!/(^|[^a-z-])\.dark(\s|,|\{)/.test(appearanceCss), 'No non-ax .dark selector');
61
+ assert(appearanceCss.includes('@media (forced-colors: active)'), 'Forced colors support');
62
+
63
+ const entries = [
64
+ join(root, 'apps/showcase/src/styles.css'),
65
+ join(root, 'apps/documentation/src/styles.css'),
66
+ join(root, 'packages/components/.storybook/styles.css'),
67
+ ];
68
+
69
+ for (const entry of entries) {
70
+ const css = readFileSync(entry, 'utf8');
71
+ const defaultIndex = css.indexOf('themes/default.css');
72
+ const appearanceIndex = css.indexOf('themes/appearance.css');
73
+ assert(defaultIndex >= 0 && appearanceIndex > defaultIndex, `Import order OK: ${entry}`);
74
+ }
75
+
76
+ if (failed > 0) {
77
+ console.error(`\n${failed} assertion(s) failed`);
78
+ process.exit(1);
79
+ }
80
+
81
+ console.log('\nAll appearance contract checks passed.');