@adamarant/designsystem 0.11.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.
Files changed (84) hide show
  1. package/README.md +101 -0
  2. package/dist/designsystem.css +13494 -0
  3. package/dist/designsystem.js +67 -0
  4. package/dist/designsystem.min.css +2 -0
  5. package/package.json +111 -0
  6. package/src/base/index.css +2 -0
  7. package/src/base/reset.css +119 -0
  8. package/src/base/typography.css +172 -0
  9. package/src/components/accordion.css +166 -0
  10. package/src/components/admin-layout.css +371 -0
  11. package/src/components/alert.css +159 -0
  12. package/src/components/avatar.css +109 -0
  13. package/src/components/badge.css +80 -0
  14. package/src/components/bottom-nav.css +125 -0
  15. package/src/components/bottom-sheet.css +146 -0
  16. package/src/components/breadcrumb.css +102 -0
  17. package/src/components/button.css +250 -0
  18. package/src/components/card.css +117 -0
  19. package/src/components/chip.css +79 -0
  20. package/src/components/collapsible.css +112 -0
  21. package/src/components/color-picker.css +82 -0
  22. package/src/components/combobox.css +420 -0
  23. package/src/components/command.css +210 -0
  24. package/src/components/context-menu.css +162 -0
  25. package/src/components/copy-button.css +106 -0
  26. package/src/components/custom-select.css +446 -0
  27. package/src/components/datepicker.css +301 -0
  28. package/src/components/description-list.css +100 -0
  29. package/src/components/divider.css +66 -0
  30. package/src/components/drawer.css +234 -0
  31. package/src/components/drop-zone.css +166 -0
  32. package/src/components/dropdown.css +169 -0
  33. package/src/components/empty-state.css +75 -0
  34. package/src/components/field.css +112 -0
  35. package/src/components/gallery.css +257 -0
  36. package/src/components/hero.css +111 -0
  37. package/src/components/icon-btn.css +103 -0
  38. package/src/components/index.css +74 -0
  39. package/src/components/input.css +311 -0
  40. package/src/components/kbd.css +54 -0
  41. package/src/components/media-library.css +230 -0
  42. package/src/components/modal.css +136 -0
  43. package/src/components/nav.css +198 -0
  44. package/src/components/number-input.css +163 -0
  45. package/src/components/pagination.css +175 -0
  46. package/src/components/pin-input.css +136 -0
  47. package/src/components/popover.css +111 -0
  48. package/src/components/progress.css +217 -0
  49. package/src/components/prose.css +337 -0
  50. package/src/components/result.css +80 -0
  51. package/src/components/scroll-area.css +73 -0
  52. package/src/components/search.css +311 -0
  53. package/src/components/segmented-control.css +94 -0
  54. package/src/components/skeleton.css +100 -0
  55. package/src/components/slider.css +133 -0
  56. package/src/components/sortable.css +70 -0
  57. package/src/components/spinner.css +60 -0
  58. package/src/components/star-rating.css +121 -0
  59. package/src/components/stat-card.css +44 -0
  60. package/src/components/table.css +359 -0
  61. package/src/components/tabs.css +215 -0
  62. package/src/components/tag.css +188 -0
  63. package/src/components/timeline.css +130 -0
  64. package/src/components/toast.css +90 -0
  65. package/src/components/toggle.css +173 -0
  66. package/src/components/toolbar.css +206 -0
  67. package/src/components/tooltip.css +167 -0
  68. package/src/components/truncated-text.css +75 -0
  69. package/src/index.css +21 -0
  70. package/src/js/theme.js +67 -0
  71. package/src/tokens/colors.css +256 -0
  72. package/src/tokens/index.css +11 -0
  73. package/src/tokens/shadows.css +55 -0
  74. package/src/tokens/spacing.css +82 -0
  75. package/src/tokens/tokens.json +413 -0
  76. package/src/tokens/typography.css +90 -0
  77. package/src/utilities/a11y.css +102 -0
  78. package/src/utilities/index.css +7 -0
  79. package/src/utilities/interactive.css +121 -0
  80. package/src/utilities/layout.css +273 -0
  81. package/src/utilities/sizing.css +85 -0
  82. package/src/utilities/spacing.css +204 -0
  83. package/src/utilities/states.css +182 -0
  84. package/src/utilities/text.css +381 -0
@@ -0,0 +1,60 @@
1
+ /* ==========================================================================
2
+ Component: Spinner
3
+ CSS-only loading spinner using border animation.
4
+
5
+ Usage:
6
+ <span class="ds-spinner"></span>
7
+ <span class="ds-spinner ds-spinner--sm"></span>
8
+ <span class="ds-spinner ds-spinner--muted"></span>
9
+
10
+ Sizes:
11
+ .ds-spinner--sm — 1.25rem (20px)
12
+ (default) — 1.5rem (24px)
13
+ .ds-spinner--lg — 2rem (32px)
14
+
15
+ Variants:
16
+ (default) — Border + interactive top
17
+ .ds-spinner--muted — Inverted colors (for dark backgrounds)
18
+ .ds-spinner--light — Light colors (for inverted/colored backgrounds)
19
+ ========================================================================== */
20
+
21
+ .ds-spinner {
22
+ display: inline-block;
23
+ width: 1.5rem;
24
+ height: 1.5rem;
25
+ border: 2px solid var(--ds-color-border);
26
+ border-top-color: var(--ds-color-interactive);
27
+ border-radius: var(--ds-radius-full);
28
+ animation: ds-spin 0.8s linear infinite;
29
+
30
+ /* Sizes */
31
+ &--sm {
32
+ width: 1rem;
33
+ height: 1rem;
34
+ }
35
+
36
+ &--md {
37
+ width: 1.25rem;
38
+ height: 1.25rem;
39
+ }
40
+
41
+ &--lg {
42
+ width: 2rem;
43
+ height: 2rem;
44
+ }
45
+
46
+ /* Color variants */
47
+ &--muted {
48
+ border-color: var(--ds-color-inverted);
49
+ border-top-color: transparent;
50
+ }
51
+
52
+ &--light {
53
+ border-color: var(--ds-color-on-inverted);
54
+ border-top-color: transparent;
55
+ }
56
+ }
57
+
58
+ @keyframes ds-spin {
59
+ to { transform: rotate(360deg); }
60
+ }
@@ -0,0 +1,121 @@
1
+ /* ==========================================================================
2
+ Component: Star Rating
3
+ Display or input star ratings. CSS-only styling with SVG/icon stars.
4
+
5
+ ARIA requirements (consumer responsibility):
6
+ - Display: aria-label="Rating: 4 out of 5"
7
+ - Input: role="radiogroup", aria-label="Rate this item"
8
+ - Each star input: role="radio", aria-checked="true|false", aria-label="[N] stars"
9
+ - Keyboard: ArrowLeft/Right to change rating
10
+
11
+ Usage (display):
12
+ <div class="ds-star-rating" aria-label="Rating: 4 out of 5">
13
+ <span class="ds-star-rating__star ds-star-rating__star--filled">★</span>
14
+ <span class="ds-star-rating__star ds-star-rating__star--filled">★</span>
15
+ <span class="ds-star-rating__star ds-star-rating__star--filled">★</span>
16
+ <span class="ds-star-rating__star ds-star-rating__star--filled">★</span>
17
+ <span class="ds-star-rating__star">★</span>
18
+ </div>
19
+
20
+ Usage (input):
21
+ <div class="ds-star-rating ds-star-rating--interactive" role="radiogroup">
22
+ <button class="ds-star-rating__star ds-star-rating__star--filled" role="radio">★</button>
23
+ ...
24
+ </div>
25
+
26
+ Modifiers:
27
+ .ds-star-rating--interactive — Hoverable stars for input
28
+ .ds-star-rating--sm — Smaller stars
29
+ .ds-star-rating--lg — Larger stars
30
+ ========================================================================== */
31
+
32
+ .ds-star-rating {
33
+ display: inline-flex;
34
+ align-items: center;
35
+ gap: var(--ds-space-0-5);
36
+
37
+ &__star {
38
+ display: inline-flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ width: 1.5rem;
42
+ height: 1.5rem;
43
+ color: var(--ds-color-border);
44
+ font-size: var(--ds-text-lg);
45
+ line-height: 1;
46
+ border: none;
47
+ background: transparent;
48
+ padding: 0;
49
+ transition: color var(--ds-duration-fast) var(--ds-ease-default);
50
+
51
+ &--filled {
52
+ color: var(--ds-color-warning);
53
+ }
54
+
55
+ &--half {
56
+ position: relative;
57
+ color: var(--ds-color-border);
58
+
59
+ &::before {
60
+ content: "★";
61
+ position: absolute;
62
+ inset-inline-start: 0;
63
+ width: 50%;
64
+ overflow: hidden;
65
+ color: var(--ds-color-warning);
66
+ }
67
+ }
68
+ }
69
+
70
+ /* --- Interactive (input mode) --- */
71
+ &--interactive &__star {
72
+ cursor: pointer;
73
+
74
+ &:hover {
75
+ color: var(--ds-color-warning);
76
+ transform: scale(1.15);
77
+ }
78
+
79
+ &:focus-visible {
80
+ outline: none;
81
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
82
+ border-radius: var(--ds-radius-sm);
83
+ scroll-margin-block: var(--ds-space-16, 4rem);
84
+ }
85
+ }
86
+
87
+ /* --- Small --- */
88
+ &--sm &__star {
89
+ width: 1rem;
90
+ height: 1rem;
91
+ font-size: var(--ds-text-sm);
92
+ }
93
+
94
+ &--sm {
95
+ gap: 0;
96
+ }
97
+
98
+ /* --- Large --- */
99
+ &--lg &__star {
100
+ width: 2rem;
101
+ height: 2rem;
102
+ font-size: var(--ds-text-2xl);
103
+ }
104
+
105
+ &--lg {
106
+ gap: var(--ds-space-1);
107
+ }
108
+
109
+ /* --- Value text --- */
110
+ &__value {
111
+ margin-inline-start: var(--ds-space-1-5);
112
+ font-size: var(--ds-text-sm);
113
+ font-weight: var(--ds-weight-medium);
114
+ color: var(--ds-color-text);
115
+ }
116
+
117
+ &__count {
118
+ font-size: var(--ds-text-xs);
119
+ color: var(--ds-color-text-tertiary);
120
+ }
121
+ }
@@ -0,0 +1,44 @@
1
+ /* ==========================================================================
2
+ Component: Stat Card
3
+ Compact metric display with label, value, detail, and optional icon.
4
+ ========================================================================== */
5
+
6
+ .ds-stat-card {
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: var(--ds-space-1);
10
+ background-color: var(--ds-color-surface);
11
+ border: 1px solid var(--ds-color-border);
12
+ border-radius: var(--ds-radius-xl);
13
+ padding: var(--ds-space-5);
14
+
15
+ &__label {
16
+ font-size: var(--ds-text-sm);
17
+ color: var(--ds-color-text-tertiary);
18
+ }
19
+
20
+ &__value {
21
+ font-family: var(--ds-font-display);
22
+ font-weight: var(--ds-font-display-weight);
23
+ font-size: var(--ds-text-2xl);
24
+ color: var(--ds-color-text);
25
+ margin-block-start: var(--ds-space-1);
26
+ }
27
+
28
+ &__detail {
29
+ font-size: var(--ds-text-xs);
30
+ color: var(--ds-color-text-tertiary);
31
+ margin-block-start: var(--ds-space-0-5);
32
+ }
33
+
34
+ &__icon {
35
+ width: 2.5rem;
36
+ height: 2.5rem;
37
+ border-radius: var(--ds-radius-xl);
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ background-color: var(--ds-color-surface-muted);
42
+ color: var(--ds-color-text-secondary);
43
+ }
44
+ }
@@ -0,0 +1,359 @@
1
+ /* ==========================================================================
2
+ Component: Table
3
+ Data table with sorting, selection, sticky headers, striping, and
4
+ responsive stacking. Composes with ds-pagination, ds-skeleton, ds-checkbox,
5
+ ds-icon-btn, and ds-empty-state for a full data-table experience.
6
+
7
+ ARIA requirements (consumer responsibility):
8
+ - Use <table> with role="grid" for interactive tables
9
+ - Sort headers: <th aria-sort="ascending|descending|none"> + <button> inside
10
+ - Select-all checkbox: aria-label="Select all rows"
11
+ - Row checkbox: aria-label="Select row [identifier]"
12
+ - Expandable rows: aria-expanded="true|false" on trigger
13
+
14
+ Usage:
15
+ <div class="ds-table-wrapper">
16
+ <table class="ds-table">
17
+ <thead>
18
+ <tr>
19
+ <th class="ds-table__cell--checkbox"><input class="ds-checkbox" /></th>
20
+ <th><button class="ds-table__sort ds-table__sort--asc">Name</button></th>
21
+ <th>Email</th>
22
+ <th class="ds-table__cell--truncate"><span>City</span></th>
23
+ <th class="ds-table__cell--shrink">Actions</th>
24
+ </tr>
25
+ </thead>
26
+ <tbody>
27
+ <tr class="ds-table__row--selected">
28
+ <td class="ds-table__cell--checkbox"><input class="ds-checkbox" /></td>
29
+ <td>John</td>
30
+ <td>john@example.com</td>
31
+ <td class="ds-table__cell--shrink">...</td>
32
+ </tr>
33
+ </tbody>
34
+ </table>
35
+ </div>
36
+
37
+ Modifiers:
38
+ .ds-table--compact — Reduced padding
39
+ .ds-table--dense — Even more compact (minimal padding)
40
+ .ds-table--striped — Alternating row backgrounds
41
+ .ds-table--bordered — Cell borders
42
+ .ds-table--sticky-header — Sticky thead with backdrop blur
43
+ .ds-table--hoverable — Explicit hover class (hover is on by default)
44
+ .ds-table--no-hover — Disable row hover
45
+ ========================================================================== */
46
+
47
+ .ds-table {
48
+ width: 100%;
49
+ text-align: start;
50
+ font-size: var(--ds-text-sm);
51
+ border-collapse: collapse;
52
+ }
53
+
54
+ /* --- Header cells --- */
55
+ .ds-table th {
56
+ padding: var(--ds-space-3) var(--ds-space-4);
57
+ font-weight: var(--ds-weight-medium);
58
+ font-size: var(--ds-text-sm);
59
+ color: var(--ds-color-text-tertiary);
60
+ text-transform: uppercase;
61
+ letter-spacing: var(--ds-tracking-wide);
62
+ border-block-end: 1px solid var(--ds-color-border);
63
+ text-align: start;
64
+ white-space: nowrap;
65
+ }
66
+
67
+ /* --- Body cells --- */
68
+ .ds-table td {
69
+ padding: var(--ds-space-3) var(--ds-space-4);
70
+ color: var(--ds-color-text);
71
+ border-block-end: 1px solid var(--ds-color-border-subtle);
72
+ vertical-align: middle;
73
+ }
74
+
75
+ /* --- Row hover (default on) --- */
76
+ .ds-table tbody tr {
77
+ transition: background-color var(--ds-duration-fast) var(--ds-ease-default);
78
+ }
79
+
80
+ .ds-table tbody tr:hover {
81
+ background-color: var(--ds-color-overlay-subtle);
82
+ }
83
+
84
+ .ds-table--no-hover tbody tr:hover {
85
+ background-color: transparent;
86
+ }
87
+
88
+ /* --- Selected row --- */
89
+ .ds-table__row--selected {
90
+ background-color: var(--ds-color-overlay-subtle);
91
+ }
92
+
93
+ .ds-table__row--selected td {
94
+ border-block-end-color: var(--ds-color-border);
95
+ }
96
+
97
+ /* --- Sort header button --- */
98
+ .ds-table__sort {
99
+ display: inline-flex;
100
+ align-items: center;
101
+ gap: var(--ds-space-1);
102
+ padding: 0;
103
+ border: none;
104
+ background: transparent;
105
+ color: inherit;
106
+ font: inherit;
107
+ text-transform: inherit;
108
+ letter-spacing: inherit;
109
+ cursor: pointer;
110
+ white-space: nowrap;
111
+ transition: color var(--ds-duration-fast) var(--ds-ease-default);
112
+ }
113
+
114
+ .ds-table__sort:hover {
115
+ color: var(--ds-color-text-secondary);
116
+ }
117
+
118
+ .ds-table__sort:focus-visible {
119
+ outline: none;
120
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
121
+ border-radius: var(--ds-radius-sm);
122
+ scroll-margin-block: var(--ds-space-16, 4rem);
123
+ }
124
+
125
+ /* Sort indicator — neutral chevron via ::after */
126
+ .ds-table__sort::after {
127
+ content: "";
128
+ display: inline-block;
129
+ width: 0;
130
+ height: 0;
131
+ border-inline-start: 4px solid transparent;
132
+ border-inline-end: 4px solid transparent;
133
+ border-block-start: 4px solid currentColor;
134
+ opacity: 0.3;
135
+ transition: opacity var(--ds-duration-fast) var(--ds-ease-default);
136
+ }
137
+
138
+ .ds-table__sort:hover::after {
139
+ opacity: 0.6;
140
+ }
141
+
142
+ /* Ascending */
143
+ .ds-table__sort--asc {
144
+ color: var(--ds-color-text);
145
+ }
146
+
147
+ .ds-table__sort--asc::after {
148
+ border-block-start: none;
149
+ border-block-end: 4px solid currentColor;
150
+ opacity: 1;
151
+ }
152
+
153
+ /* Descending */
154
+ .ds-table__sort--desc {
155
+ color: var(--ds-color-text);
156
+ }
157
+
158
+ .ds-table__sort--desc::after {
159
+ border-block-start: 4px solid currentColor;
160
+ border-block-end: none;
161
+ opacity: 1;
162
+ }
163
+
164
+ /* --- Special cell types --- */
165
+
166
+ /* Truncate cell: long text with ellipsis (city names, categories, etc.)
167
+ Usage: <td class="ds-table__cell--truncate"><span>Long text here</span></td>
168
+ The child element (span, a, div) gets the truncation. This works with
169
+ table-layout: auto because max-width applies to the inner block, not the td.
170
+ Default max-width is 12rem. Override per cell via --_cell-max. */
171
+ .ds-table__cell--truncate {
172
+ --_cell-max: 12rem;
173
+ }
174
+
175
+ .ds-table__cell--truncate > * {
176
+ display: block;
177
+ max-width: var(--_cell-max);
178
+ overflow: hidden;
179
+ text-overflow: ellipsis;
180
+ white-space: nowrap;
181
+ }
182
+
183
+ /* Primary cell: the main identifier column (title, name). Gets min-width
184
+ so it never compresses when other columns claim space.
185
+ Default min-width is 16rem. Override per cell via --_cell-min. */
186
+ .ds-table__cell--primary {
187
+ --_cell-min: 16rem;
188
+ min-width: var(--_cell-min);
189
+ }
190
+
191
+ /* Shrink cell: action buttons, icons, checkboxes */
192
+ .ds-table__cell--shrink {
193
+ width: 1%;
194
+ white-space: nowrap;
195
+ }
196
+
197
+ /* Number cell: right-aligned with tabular numbers */
198
+ .ds-table__cell--number {
199
+ text-align: end;
200
+ font-variant-numeric: tabular-nums;
201
+ font-feature-settings: "tnum" 1;
202
+ }
203
+
204
+ /* Checkbox cell: narrow centered */
205
+ .ds-table__cell--checkbox {
206
+ width: 1%;
207
+ padding-inline-end: 0;
208
+ vertical-align: middle;
209
+ }
210
+
211
+ /* --- Empty state row --- */
212
+ .ds-table__empty {
213
+ text-align: center;
214
+ padding: var(--ds-space-12) var(--ds-space-4);
215
+ color: var(--ds-color-text-tertiary);
216
+ }
217
+
218
+ .ds-table__empty td {
219
+ border-block-end: none;
220
+ }
221
+
222
+ /* --- Loading skeleton rows --- */
223
+ .ds-table__loading td {
224
+ color: transparent;
225
+ position: relative;
226
+ }
227
+
228
+ .ds-table__loading td::after {
229
+ content: "";
230
+ position: absolute;
231
+ inset-block-start: 50%;
232
+ inset-inline-start: var(--ds-space-4);
233
+ inset-inline-end: var(--ds-space-4);
234
+ height: 0.75rem;
235
+ transform: translateY(-50%);
236
+ background: var(--ds-color-surface-muted);
237
+ border-radius: var(--ds-radius-sm);
238
+ animation: ds-table-skeleton-pulse 1.5s ease-in-out infinite;
239
+ }
240
+
241
+ @keyframes ds-table-skeleton-pulse {
242
+ 0%, 100% { opacity: 1; }
243
+ 50% { opacity: 0.4; }
244
+ }
245
+
246
+ /* --- Compact modifier --- */
247
+ .ds-table--compact th,
248
+ .ds-table--compact td {
249
+ padding: var(--ds-space-2) var(--ds-space-3);
250
+ }
251
+
252
+ /* --- Dense modifier --- */
253
+ .ds-table--dense th,
254
+ .ds-table--dense td {
255
+ padding: var(--ds-space-1-5) var(--ds-space-2);
256
+ font-size: var(--ds-text-xs);
257
+ }
258
+
259
+ /* --- Striped modifier --- */
260
+ .ds-table--striped tbody tr:nth-child(even) {
261
+ background-color: var(--ds-color-overlay-subtle);
262
+ }
263
+
264
+ .ds-table--striped tbody tr:hover {
265
+ background-color: var(--ds-color-surface-hover);
266
+ }
267
+
268
+ /* --- Bordered modifier --- */
269
+ .ds-table--bordered th,
270
+ .ds-table--bordered td {
271
+ border: 1px solid var(--ds-color-border-subtle);
272
+ }
273
+
274
+ .ds-table--bordered th {
275
+ border-block-end-color: var(--ds-color-border);
276
+ }
277
+
278
+ /* --- Sticky header modifier --- */
279
+ .ds-table--sticky-header thead {
280
+ position: sticky;
281
+ inset-block-start: 0;
282
+ z-index: var(--ds-z-sticky);
283
+ }
284
+
285
+ .ds-table--sticky-header th {
286
+ background-color: var(--ds-color-surface);
287
+ backdrop-filter: blur(var(--ds-blur-md));
288
+ -webkit-backdrop-filter: blur(var(--ds-blur-md));
289
+ }
290
+
291
+ /* --- Table wrapper --- */
292
+ .ds-table-wrapper {
293
+ overflow-x: auto;
294
+ border: 1px solid var(--ds-color-border);
295
+ border-radius: var(--ds-radius-xl);
296
+ background-color: var(--ds-color-surface);
297
+ }
298
+
299
+ .ds-table-wrapper .ds-table {
300
+ margin: 0;
301
+ }
302
+
303
+ /* Remove outer borders when inside wrapper (wrapper provides them) */
304
+ .ds-table-wrapper .ds-table tr:last-child td {
305
+ border-block-end: none;
306
+ }
307
+
308
+ /* --- Table footer (pagination area) --- */
309
+ .ds-table-footer {
310
+ display: flex;
311
+ align-items: center;
312
+ justify-content: space-between;
313
+ gap: var(--ds-space-4);
314
+ padding: var(--ds-space-3) var(--ds-space-4);
315
+ border-block-start: 1px solid var(--ds-color-border);
316
+ font-size: var(--ds-text-sm);
317
+ color: var(--ds-color-text-tertiary);
318
+ }
319
+
320
+ /* --- Responsive: card-style stacking on mobile --- */
321
+ @media (max-width: 767px) {
322
+ .ds-table--stack thead {
323
+ display: none;
324
+ }
325
+
326
+ .ds-table--stack tbody tr {
327
+ display: flex;
328
+ flex-direction: column;
329
+ gap: var(--ds-space-1);
330
+ padding: var(--ds-space-3) var(--ds-space-4);
331
+ border-block-end: 1px solid var(--ds-color-border);
332
+ }
333
+
334
+ .ds-table--stack td {
335
+ display: flex;
336
+ align-items: baseline;
337
+ gap: var(--ds-space-2);
338
+ padding: 0;
339
+ border: none;
340
+ }
341
+
342
+ .ds-table--stack td::before {
343
+ content: attr(data-label);
344
+ flex-shrink: 0;
345
+ min-width: 8rem;
346
+ font-size: var(--ds-text-xs);
347
+ font-weight: var(--ds-weight-medium);
348
+ color: var(--ds-color-text-tertiary);
349
+ text-transform: uppercase;
350
+ letter-spacing: var(--ds-tracking-wide);
351
+ }
352
+ }
353
+
354
+ /* --- Reduced motion --- */
355
+ @media (prefers-reduced-motion: reduce) {
356
+ .ds-table__loading td::after {
357
+ animation: none;
358
+ }
359
+ }