@neuravision/construct 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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +227 -0
  3. package/components/README.md +566 -0
  4. package/components/_keyframes.css +23 -0
  5. package/components/_shared.css +120 -0
  6. package/components/accordion.css +124 -0
  7. package/components/alert.css +67 -0
  8. package/components/avatar.css +127 -0
  9. package/components/badge.css +67 -0
  10. package/components/banner.css +247 -0
  11. package/components/breadcrumbs.css +152 -0
  12. package/components/button.css +145 -0
  13. package/components/card.css +76 -0
  14. package/components/checkbox.css +120 -0
  15. package/components/chip.css +361 -0
  16. package/components/combobox.css +385 -0
  17. package/components/components.css +2 -0
  18. package/components/data-table.css +93 -0
  19. package/components/datepicker.css +268 -0
  20. package/components/divider.css +73 -0
  21. package/components/drawer.css +167 -0
  22. package/components/dropdown.css +401 -0
  23. package/components/empty-state.css +97 -0
  24. package/components/field.css +42 -0
  25. package/components/file-upload.css +111 -0
  26. package/components/icon.css +31 -0
  27. package/components/index.css +49 -0
  28. package/components/input.css +64 -0
  29. package/components/list.css +474 -0
  30. package/components/modal.css +164 -0
  31. package/components/navbar.css +587 -0
  32. package/components/pagination.css +131 -0
  33. package/components/popover.css +231 -0
  34. package/components/progress-bar.css +56 -0
  35. package/components/select-menu.css +267 -0
  36. package/components/select.css +30 -0
  37. package/components/sidebar.css +183 -0
  38. package/components/skeleton.css +38 -0
  39. package/components/skip-link.css +38 -0
  40. package/components/slider.css +305 -0
  41. package/components/spinner.css +72 -0
  42. package/components/switch.css +82 -0
  43. package/components/table.css +139 -0
  44. package/components/tabs.css +147 -0
  45. package/components/textarea.css +16 -0
  46. package/components/toast.css +71 -0
  47. package/components/toggle-group.css +196 -0
  48. package/components/toolbar.css +222 -0
  49. package/components/tooltip.css +124 -0
  50. package/docs/guidelines.md +141 -0
  51. package/foundations.css +299 -0
  52. package/package.json +66 -0
  53. package/tokens/README.md +179 -0
  54. package/tokens/tokens.css +434 -0
  55. package/tokens/tokens.js +1188 -0
  56. package/tokens/tokens.json +810 -0
  57. package/tokens/tokens.ts +1188 -0
@@ -0,0 +1,247 @@
1
+ /* ----------------------------------------------------------------
2
+ Banner / Callout
3
+ Persistent page- or section-level notices.
4
+ ----------------------------------------------------------------
5
+ Variants (data-variant) : info (default) | warning | danger | success | neutral
6
+ Appearance (class) : subtle (default) | --solid | --left-accent | --top-accent
7
+ Position (class) : inline (default) | --fixed-top | --fixed-bottom | --sticky
8
+ Size (class) : default | --compact
9
+ Layout (class) : default | --full (no radius, no inline border)
10
+ State (data-state) : open (default) | closed
11
+ ---------------------------------------------------------------- */
12
+
13
+ .ct-banner {
14
+ --ct-banner-bg: var(--color-state-info-surface);
15
+ --ct-banner-border: var(--color-state-info-border);
16
+ --ct-banner-accent: var(--color-state-info);
17
+
18
+ display: flex;
19
+ align-items: start;
20
+ gap: var(--space-3) var(--space-4);
21
+ padding: var(--space-5) var(--space-6);
22
+ border-radius: var(--radius-md);
23
+ border: var(--border-thin) solid var(--ct-banner-border);
24
+ background: var(--ct-banner-bg);
25
+ color: var(--color-text-primary);
26
+ font-size: var(--font-size-sm);
27
+ line-height: var(--line-height-sm);
28
+ transition: opacity var(--duration-normal) var(--easing-standard),
29
+ transform var(--duration-normal) var(--easing-standard);
30
+ }
31
+
32
+ /* ---- Sub-elements ---- */
33
+
34
+ .ct-banner__icon {
35
+ flex-shrink: 0;
36
+ width: var(--icon-md);
37
+ height: var(--icon-md);
38
+ display: inline-flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ color: var(--ct-banner-accent);
42
+ }
43
+
44
+ .ct-banner__content {
45
+ flex: 1 1 0%;
46
+ min-width: 0;
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: var(--space-1);
50
+ }
51
+
52
+ .ct-banner__title {
53
+ font-weight: var(--font-weight-semibold);
54
+ }
55
+
56
+ .ct-banner__message {
57
+ color: var(--color-text-secondary);
58
+ }
59
+
60
+ .ct-banner__actions {
61
+ display: flex;
62
+ flex-shrink: 0;
63
+ gap: var(--space-3);
64
+ align-items: center;
65
+ }
66
+
67
+ .ct-banner__close {
68
+ flex-shrink: 0;
69
+ display: inline-flex;
70
+ align-items: center;
71
+ justify-content: center;
72
+ width: var(--control-height-sm);
73
+ height: var(--control-height-sm);
74
+ border: none;
75
+ background: transparent;
76
+ color: var(--color-text-secondary);
77
+ border-radius: var(--radius-sm);
78
+ cursor: pointer;
79
+ padding: 0;
80
+ font-size: var(--font-size-lg);
81
+ line-height: 1;
82
+ transition: background var(--duration-fast) var(--easing-standard),
83
+ color var(--duration-fast) var(--easing-standard);
84
+ }
85
+
86
+ @media (hover: hover) {
87
+ .ct-banner__close:hover {
88
+ background: color-mix(in srgb, currentColor 10%, transparent);
89
+ color: var(--color-text-primary);
90
+ }
91
+ }
92
+
93
+ .ct-banner__close:focus-visible {
94
+ outline: 2px solid var(--color-focus-ring);
95
+ outline-offset: 2px;
96
+ }
97
+
98
+ /* ---- Semantic Variants ---- */
99
+
100
+ .ct-banner[data-variant='warning'] {
101
+ --ct-banner-bg: var(--color-state-warning-surface);
102
+ --ct-banner-border: var(--color-state-warning-border);
103
+ --ct-banner-accent: var(--color-state-warning-text);
104
+ }
105
+
106
+ .ct-banner[data-variant='danger'] {
107
+ --ct-banner-bg: var(--color-state-danger-surface);
108
+ --ct-banner-border: var(--color-state-danger-border);
109
+ --ct-banner-accent: var(--color-state-danger);
110
+ }
111
+
112
+ .ct-banner[data-variant='success'] {
113
+ --ct-banner-bg: var(--color-state-success-surface);
114
+ --ct-banner-border: var(--color-state-success-border);
115
+ --ct-banner-accent: var(--color-state-success);
116
+ }
117
+
118
+ .ct-banner[data-variant='neutral'] {
119
+ --ct-banner-bg: var(--color-bg-muted);
120
+ --ct-banner-border: var(--color-border-subtle);
121
+ --ct-banner-accent: var(--color-text-secondary);
122
+ }
123
+
124
+ /* ---- Appearance: Solid ---- */
125
+ /* Compound selector raises specificity to (0,2,0) to beat variant overrides */
126
+
127
+ .ct-banner.ct-banner--solid {
128
+ --ct-banner-bg: var(--ct-banner-accent);
129
+ --ct-banner-border: var(--ct-banner-accent);
130
+ color: var(--color-text-inverse);
131
+ }
132
+
133
+ .ct-banner--solid .ct-banner__icon,
134
+ .ct-banner--solid .ct-banner__message,
135
+ .ct-banner--solid .ct-banner__close {
136
+ color: var(--color-text-inverse);
137
+ }
138
+
139
+ @media (hover: hover) {
140
+ .ct-banner--solid .ct-banner__close:hover {
141
+ background: color-mix(in srgb, var(--color-text-inverse) 20%, transparent);
142
+ }
143
+ }
144
+
145
+ /* Solid + success needs darker green for WCAG AA contrast with inverse text */
146
+ .ct-banner.ct-banner--solid[data-variant='success'] {
147
+ --ct-banner-accent: var(--color-green-700);
148
+ }
149
+
150
+ /* ---- Appearance: Accents ---- */
151
+
152
+ .ct-banner--left-accent {
153
+ border-inline-start: var(--border-thick) solid var(--ct-banner-accent);
154
+ }
155
+
156
+ .ct-banner--top-accent {
157
+ border-block-start: var(--border-thick) solid var(--ct-banner-accent);
158
+ }
159
+
160
+ /* ---- Positions ---- */
161
+
162
+ .ct-banner--fixed-top {
163
+ position: fixed;
164
+ inset-block-start: 0;
165
+ inset-inline: 0;
166
+ z-index: var(--z-sticky);
167
+ border-radius: 0;
168
+ }
169
+
170
+ .ct-banner--fixed-bottom {
171
+ position: fixed;
172
+ inset-block-end: 0;
173
+ inset-inline: 0;
174
+ z-index: var(--z-sticky);
175
+ border-radius: 0;
176
+ }
177
+
178
+ .ct-banner--sticky {
179
+ position: sticky;
180
+ inset-block-start: 0;
181
+ z-index: var(--z-sticky);
182
+ border-radius: 0;
183
+ }
184
+
185
+ /* ---- Compact ---- */
186
+
187
+ .ct-banner--compact {
188
+ padding: var(--space-3) var(--space-5);
189
+ gap: var(--space-2) var(--space-3);
190
+ font-size: var(--font-size-xs);
191
+ line-height: var(--line-height-xs);
192
+ }
193
+
194
+ .ct-banner--compact .ct-banner__icon {
195
+ width: var(--icon-sm);
196
+ height: var(--icon-sm);
197
+ }
198
+
199
+ .ct-banner--compact .ct-banner__close {
200
+ width: var(--icon-lg);
201
+ height: var(--icon-lg);
202
+ font-size: var(--font-size-sm);
203
+ }
204
+
205
+ /* ---- Full-Width ---- */
206
+
207
+ .ct-banner--full {
208
+ border-radius: 0;
209
+ border-inline: none;
210
+ }
211
+
212
+ /* ---- State ---- */
213
+
214
+ .ct-banner[data-state='closed'] {
215
+ opacity: 0;
216
+ pointer-events: none;
217
+ }
218
+
219
+ .ct-banner--fixed-top[data-state='closed'],
220
+ .ct-banner--sticky[data-state='closed'] {
221
+ transform: translateY(-100%);
222
+ }
223
+
224
+ .ct-banner--fixed-bottom[data-state='closed'] {
225
+ transform: translateY(100%);
226
+ }
227
+
228
+ /* ---- Responsive ---- */
229
+
230
+ @media (max-width: 599px) { /* < sm breakpoint (600px) */
231
+ .ct-banner {
232
+ flex-wrap: wrap;
233
+ }
234
+
235
+ .ct-banner__actions {
236
+ flex-basis: 100%;
237
+ }
238
+ }
239
+
240
+ /* ---- Reduced Motion ---- */
241
+
242
+ @media (prefers-reduced-motion: reduce) {
243
+ .ct-banner,
244
+ .ct-banner__close {
245
+ transition: none;
246
+ }
247
+ }
@@ -0,0 +1,152 @@
1
+ /* --- Breadcrumbs --- */
2
+
3
+ .ct-breadcrumbs {
4
+ --ct-breadcrumbs-font-size: var(--font-size-sm);
5
+ --ct-breadcrumbs-line-height: var(--line-height-sm);
6
+ --ct-breadcrumbs-gap: var(--space-2);
7
+ --ct-breadcrumbs-icon-size: 1em;
8
+ --ct-breadcrumbs-separator-color: var(--color-text-muted);
9
+ --ct-breadcrumbs-link-color: var(--color-text-secondary);
10
+ --ct-breadcrumbs-link-hover-color: var(--color-brand-primary);
11
+ --ct-breadcrumbs-current-color: var(--color-text-primary);
12
+
13
+ font-size: var(--ct-breadcrumbs-font-size);
14
+ line-height: var(--ct-breadcrumbs-line-height);
15
+ color: var(--color-text-muted);
16
+ }
17
+
18
+ /* Size variants */
19
+
20
+ .ct-breadcrumbs--sm {
21
+ --ct-breadcrumbs-font-size: var(--font-size-xs);
22
+ --ct-breadcrumbs-line-height: var(--line-height-xs);
23
+ --ct-breadcrumbs-gap: var(--space-1);
24
+ }
25
+
26
+ .ct-breadcrumbs--lg {
27
+ --ct-breadcrumbs-font-size: var(--font-size-md);
28
+ --ct-breadcrumbs-line-height: var(--line-height-md);
29
+ --ct-breadcrumbs-gap: var(--space-3);
30
+ }
31
+
32
+ .ct-breadcrumbs__list {
33
+ list-style: none;
34
+ display: flex;
35
+ flex-wrap: wrap;
36
+ align-items: center;
37
+ gap: var(--ct-breadcrumbs-gap);
38
+ margin: 0;
39
+ padding: 0;
40
+ }
41
+
42
+ .ct-breadcrumbs__item {
43
+ display: inline-flex;
44
+ align-items: center;
45
+ gap: var(--ct-breadcrumbs-gap);
46
+ min-width: 0;
47
+ }
48
+
49
+ .ct-breadcrumbs__link {
50
+ color: var(--ct-breadcrumbs-link-color);
51
+ text-decoration: underline;
52
+ text-decoration-thickness: 1px;
53
+ text-underline-offset: 0.15em;
54
+ transition: color var(--duration-fast) var(--easing-standard), text-decoration-thickness var(--duration-fast) var(--easing-standard);
55
+ border-radius: var(--radius-xs);
56
+ }
57
+
58
+ @media (hover: hover) {
59
+ .ct-breadcrumbs__link:hover {
60
+ color: var(--ct-breadcrumbs-link-hover-color);
61
+ text-decoration-thickness: 2px;
62
+ }
63
+ }
64
+
65
+ .ct-breadcrumbs__link:focus-visible {
66
+ outline: 2px solid var(--color-focus-ring);
67
+ outline-offset: 2px;
68
+ }
69
+
70
+ .ct-breadcrumbs__current {
71
+ color: var(--ct-breadcrumbs-current-color);
72
+ font-weight: var(--font-weight-medium);
73
+ }
74
+
75
+ .ct-breadcrumbs__separator {
76
+ color: var(--ct-breadcrumbs-separator-color);
77
+ user-select: none;
78
+ flex-shrink: 0;
79
+ }
80
+
81
+ /* Icon support */
82
+
83
+ .ct-breadcrumbs__icon {
84
+ display: inline-flex;
85
+ align-items: center;
86
+ flex-shrink: 0;
87
+ width: var(--ct-breadcrumbs-icon-size);
88
+ height: var(--ct-breadcrumbs-icon-size);
89
+ }
90
+
91
+ .ct-breadcrumbs__icon svg {
92
+ width: 100%;
93
+ height: 100%;
94
+ fill: currentColor;
95
+ }
96
+
97
+ /* Collapse trigger (ellipsis button for truncated middle items) */
98
+
99
+ .ct-breadcrumbs__collapse {
100
+ display: inline-flex;
101
+ align-items: center;
102
+ justify-content: center;
103
+ padding: var(--space-1) var(--space-2);
104
+ border: var(--border-thin) solid var(--color-border-default);
105
+ border-radius: var(--radius-sm);
106
+ background: var(--color-bg-elevated);
107
+ color: var(--ct-breadcrumbs-link-color);
108
+ font-size: inherit;
109
+ line-height: 1;
110
+ cursor: pointer;
111
+ transition: background var(--duration-fast) var(--easing-standard), color var(--duration-fast) var(--easing-standard);
112
+ }
113
+
114
+ @media (hover: hover) {
115
+ .ct-breadcrumbs__collapse:hover {
116
+ background: var(--color-bg-muted);
117
+ color: var(--ct-breadcrumbs-link-hover-color);
118
+ }
119
+ }
120
+
121
+ .ct-breadcrumbs__collapse:focus-visible {
122
+ outline: 2px solid var(--color-focus-ring);
123
+ outline-offset: 2px;
124
+ }
125
+
126
+ /* Responsive: on small viewports show only first + last items */
127
+
128
+ @media (max-width: 599px) { /* < sm breakpoint (600px) */
129
+ .ct-breadcrumbs--responsive .ct-breadcrumbs__item {
130
+ display: none;
131
+ }
132
+
133
+ .ct-breadcrumbs--responsive .ct-breadcrumbs__item:first-child,
134
+ .ct-breadcrumbs--responsive .ct-breadcrumbs__item:last-child {
135
+ display: inline-flex;
136
+ }
137
+
138
+ .ct-breadcrumbs--responsive .ct-breadcrumbs__item:first-child::after {
139
+ content: "…";
140
+ color: var(--ct-breadcrumbs-separator-color);
141
+ margin-inline-start: var(--ct-breadcrumbs-gap);
142
+ }
143
+ }
144
+
145
+ /* Reduced motion */
146
+
147
+ @media (prefers-reduced-motion: reduce) {
148
+ .ct-breadcrumbs__link,
149
+ .ct-breadcrumbs__collapse {
150
+ transition: none;
151
+ }
152
+ }
@@ -0,0 +1,145 @@
1
+ .ct-button {
2
+ --ct-button-bg: var(--color-brand-primary);
3
+ --ct-button-bg-hover: var(--color-brand-primary-hover);
4
+ --ct-button-bg-active: var(--color-brand-primary-active);
5
+ --ct-button-border: transparent;
6
+ --ct-button-color: var(--color-text-inverse);
7
+ --ct-button-height: var(--control-height-md);
8
+ --ct-button-padding-x: var(--space-6);
9
+ --ct-button-font-size: var(--font-size-sm);
10
+ --ct-button-line-height: var(--line-height-sm);
11
+
12
+ display: inline-flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ gap: var(--ct-button-gap);
16
+ min-height: var(--ct-button-height);
17
+ padding: 0 var(--ct-button-padding-x);
18
+ border-radius: var(--ct-button-radius);
19
+ border: var(--border-thin) solid var(--ct-button-border);
20
+ background: var(--ct-button-bg);
21
+ color: var(--ct-button-color);
22
+ font-weight: var(--ct-button-font-weight);
23
+ font-size: var(--ct-button-font-size);
24
+ line-height: var(--ct-button-line-height);
25
+ text-decoration: none;
26
+ white-space: nowrap;
27
+ transition: background var(--duration-fast) var(--easing-standard),
28
+ border-color var(--duration-fast) var(--easing-standard),
29
+ color var(--duration-fast) var(--easing-standard),
30
+ box-shadow var(--duration-fast) var(--easing-standard),
31
+ transform var(--duration-fast) var(--easing-standard);
32
+ }
33
+
34
+ @media (hover: hover) {
35
+ .ct-button:hover {
36
+ background: var(--ct-button-bg-hover);
37
+ }
38
+ }
39
+
40
+ .ct-button:active {
41
+ background: var(--ct-button-bg-active);
42
+ transform: translateY(1px);
43
+ }
44
+
45
+ .ct-button:focus-visible {
46
+ outline: 2px solid var(--color-focus-ring);
47
+ outline-offset: 2px;
48
+ }
49
+
50
+ .ct-button:disabled,
51
+ .ct-button[aria-disabled='true'] {
52
+ opacity: var(--opacity-disabled);
53
+ transform: none;
54
+ cursor: not-allowed;
55
+ }
56
+
57
+ .ct-button--secondary {
58
+ --ct-button-bg: var(--color-bg-surface);
59
+ --ct-button-bg-hover: var(--color-bg-muted);
60
+ --ct-button-bg-active: var(--color-border-subtle);
61
+ --ct-button-border: var(--color-border-default);
62
+ --ct-button-color: var(--color-text-primary);
63
+ }
64
+
65
+ .ct-button--outline {
66
+ --ct-button-bg: transparent;
67
+ --ct-button-bg-hover: var(--color-bg-muted);
68
+ --ct-button-bg-active: var(--color-bg-surface);
69
+ --ct-button-border: var(--color-brand-primary);
70
+ --ct-button-color: var(--color-brand-primary);
71
+ }
72
+
73
+ .ct-button--ghost {
74
+ --ct-button-bg: transparent;
75
+ --ct-button-bg-hover: var(--color-bg-muted);
76
+ --ct-button-bg-active: var(--color-bg-surface);
77
+ --ct-button-border: transparent;
78
+ --ct-button-color: var(--color-brand-primary);
79
+ }
80
+
81
+ .ct-button--accent {
82
+ --ct-button-bg: var(--color-brand-accent);
83
+ --ct-button-bg-hover: var(--color-brand-accent-hover);
84
+ --ct-button-bg-active: var(--color-brand-accent-active);
85
+ --ct-button-border: transparent;
86
+ --ct-button-color: var(--color-text-inverse);
87
+ }
88
+
89
+ .ct-button--danger {
90
+ --ct-button-bg: var(--color-state-danger);
91
+ --ct-button-bg-hover: var(--color-red-600);
92
+ --ct-button-bg-active: var(--color-red-700);
93
+ --ct-button-border: transparent;
94
+ --ct-button-color: var(--color-text-inverse);
95
+ }
96
+
97
+ .ct-button--link {
98
+ --ct-button-bg: transparent;
99
+ --ct-button-bg-hover: transparent;
100
+ --ct-button-bg-active: transparent;
101
+ --ct-button-border: transparent;
102
+ --ct-button-color: var(--color-brand-primary);
103
+ min-height: auto;
104
+ padding: 0;
105
+ font-weight: var(--font-weight-medium);
106
+ }
107
+
108
+ @media (hover: hover) {
109
+ .ct-button--link:hover {
110
+ text-decoration: underline;
111
+ }
112
+ }
113
+
114
+ .ct-button--sm {
115
+ --ct-button-height: var(--control-height-sm);
116
+ --ct-button-padding-x: var(--space-5);
117
+ --ct-button-font-size: var(--font-size-xs);
118
+ --ct-button-line-height: var(--line-height-xs);
119
+ }
120
+
121
+ .ct-button--lg {
122
+ --ct-button-height: var(--control-height-lg);
123
+ --ct-button-padding-x: var(--space-7);
124
+ --ct-button-font-size: var(--font-size-md);
125
+ --ct-button-line-height: var(--line-height-md);
126
+ }
127
+
128
+ .ct-button--icon {
129
+ width: var(--ct-button-height);
130
+ padding: 0;
131
+ }
132
+
133
+ .ct-button__icon {
134
+ width: var(--icon-sm);
135
+ height: var(--icon-sm);
136
+ display: inline-flex;
137
+ align-items: center;
138
+ justify-content: center;
139
+ }
140
+
141
+ @media (prefers-reduced-motion: reduce) {
142
+ .ct-button:active {
143
+ transform: none;
144
+ }
145
+ }
@@ -0,0 +1,76 @@
1
+ .ct-card {
2
+ --ct-card-padding: var(--space-6);
3
+ background: var(--color-bg-elevated);
4
+ border: var(--border-thin) solid var(--color-border-subtle);
5
+ border-radius: var(--radius-lg);
6
+ padding: var(--ct-card-padding);
7
+ box-shadow: var(--shadow-sm);
8
+ }
9
+
10
+ .ct-card--sm {
11
+ --ct-card-padding: var(--space-4);
12
+ }
13
+
14
+ .ct-card--lg {
15
+ --ct-card-padding: var(--space-8);
16
+ }
17
+
18
+ .ct-card__header {
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: space-between;
22
+ gap: var(--space-4);
23
+ margin-bottom: var(--space-5);
24
+ }
25
+
26
+ .ct-card__body {
27
+ display: grid;
28
+ gap: var(--space-4);
29
+ }
30
+
31
+ .ct-card__footer {
32
+ display: flex;
33
+ align-items: center;
34
+ justify-content: space-between;
35
+ gap: var(--space-4);
36
+ margin-top: var(--space-6);
37
+ padding-top: var(--space-4);
38
+ border-top: var(--border-thin) solid var(--color-border-subtle);
39
+ }
40
+
41
+ :is(a, button, [role='button'], [role='link']).ct-card--interactive {
42
+ cursor: pointer;
43
+ transition: box-shadow var(--duration-fast) var(--easing-standard),
44
+ border-color var(--duration-fast) var(--easing-standard);
45
+ }
46
+
47
+ @media (hover: hover) {
48
+ :is(a, button, [role='button'], [role='link']).ct-card--interactive:hover {
49
+ border-color: var(--color-border-strong);
50
+ box-shadow: var(--shadow-md);
51
+ }
52
+ }
53
+
54
+ :is(a, button, [role='button'], [role='link']).ct-card--interactive:focus-visible {
55
+ outline: 2px solid var(--color-focus-ring);
56
+ outline-offset: 2px;
57
+ border-color: var(--color-border-strong);
58
+ box-shadow: var(--shadow-md);
59
+ }
60
+
61
+ .ct-card--interactive[aria-selected='true'] {
62
+ border-color: var(--color-brand-primary);
63
+ box-shadow: var(--shadow-md);
64
+ }
65
+
66
+ .ct-card--interactive[aria-disabled='true'],
67
+ .ct-card--interactive:disabled {
68
+ opacity: var(--opacity-disabled);
69
+ cursor: not-allowed;
70
+ }
71
+
72
+ @media (prefers-reduced-motion: reduce) {
73
+ .ct-card--interactive {
74
+ transition: none;
75
+ }
76
+ }