@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,125 @@
1
+ /* ==========================================================================
2
+ Component: Bottom Nav
3
+ Mobile bottom navigation bar. Hidden on desktop, shown on mobile.
4
+ Fixed to bottom with safe-area insets for notched devices.
5
+
6
+ ARIA requirements (consumer responsibility):
7
+ - Container: <nav aria-label="Bottom navigation">
8
+ - Active item: aria-current="page" on the current tab
9
+ - Badge: aria-label on badge parent (e.g., "Home, 3 notifications")
10
+ - Create button: aria-label="Create new"
11
+
12
+ Usage:
13
+ <nav class="ds-bottom-nav" aria-label="Bottom navigation">
14
+ <a href="/" class="ds-bottom-nav__item ds-bottom-nav__item--active" aria-current="page">
15
+ <span class="ds-bottom-nav__icon">
16
+ <svg>...</svg>
17
+ <span class="ds-bottom-nav__badge">3</span>
18
+ </span>
19
+ <span class="ds-bottom-nav__label">Home</span>
20
+ </a>
21
+ <button class="ds-bottom-nav__item ds-bottom-nav__item--create" aria-label="Create new">
22
+ <span class="ds-bottom-nav__create-icon">+</span>
23
+ <span class="ds-bottom-nav__label">New</span>
24
+ </button>
25
+ </nav>
26
+
27
+ Modifiers:
28
+ .ds-bottom-nav__item--active — Active/current tab
29
+ .ds-bottom-nav__item--create — Elevated center action button
30
+ ========================================================================== */
31
+
32
+ .ds-bottom-nav {
33
+ display: none;
34
+ position: fixed;
35
+ inset-block-end: 0;
36
+ inset-inline-start: 0;
37
+ inset-inline-end: 0;
38
+ z-index: var(--ds-z-dropdown);
39
+ background: var(--ds-color-surface);
40
+ border-block-start: 1px solid var(--ds-color-border);
41
+ padding-block-end: env(safe-area-inset-bottom, 0px);
42
+
43
+ /* Nav item */
44
+ &__item {
45
+ display: flex;
46
+ flex-direction: column;
47
+ align-items: center;
48
+ justify-content: center;
49
+ gap: var(--ds-space-1);
50
+ flex: 1;
51
+ padding: var(--ds-space-2) 0;
52
+ color: var(--ds-color-text-tertiary);
53
+ text-decoration: none;
54
+ border: none;
55
+ background: none;
56
+ cursor: pointer;
57
+ font: inherit;
58
+ transition: color var(--ds-duration-fast) var(--ds-ease-default);
59
+ -webkit-tap-highlight-color: transparent;
60
+
61
+ &--active {
62
+ color: var(--ds-color-text);
63
+ }
64
+
65
+ &--create {
66
+ color: var(--ds-color-text-tertiary);
67
+ }
68
+ }
69
+
70
+ /* Icon wrapper */
71
+ &__icon {
72
+ position: relative;
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ }
77
+
78
+ /* Notification badge */
79
+ &__badge {
80
+ position: absolute;
81
+ inset-block-start: calc(-1 * var(--ds-space-1));
82
+ inset-inline-end: calc(-1 * var(--ds-space-2));
83
+ min-width: var(--ds-space-4);
84
+ height: var(--ds-space-4);
85
+ padding: 0 var(--ds-space-1);
86
+ border-radius: var(--ds-radius-full);
87
+ background: var(--ds-color-error);
88
+ color: var(--ds-color-on-inverted);
89
+ font-size: var(--ds-text-2xs);
90
+ font-weight: var(--ds-weight-semibold);
91
+ line-height: var(--ds-space-4);
92
+ text-align: center;
93
+ }
94
+
95
+ /* Label */
96
+ &__label {
97
+ font-size: var(--ds-text-2xs);
98
+ font-weight: var(--ds-weight-medium);
99
+ letter-spacing: var(--ds-tracking-wide);
100
+ }
101
+
102
+ /* Create button — elevated center icon */
103
+ &__create-icon {
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ width: 2.25rem;
108
+ height: 2.25rem;
109
+ border-radius: var(--ds-radius-full);
110
+ background: var(--ds-color-text);
111
+ color: var(--ds-color-bg);
112
+ }
113
+ }
114
+
115
+ @media (max-width: 1023px) /* below --ds-breakpoint-lg */ {
116
+ .ds-bottom-nav {
117
+ display: flex;
118
+ justify-content: space-around;
119
+ align-items: stretch;
120
+ }
121
+ }
122
+
123
+ @media (min-width: 1024px) /* --ds-breakpoint-lg */ {
124
+ .ds-bottom-nav { display: none !important; }
125
+ }
@@ -0,0 +1,146 @@
1
+ /* ==========================================================================
2
+ Component: Bottom Sheet
3
+ Mobile overlay sliding up from the bottom. Alternative to dropdown on mobile.
4
+
5
+ ARIA requirements (consumer responsibility):
6
+ - Container: role="dialog", aria-label="[title]", aria-modal="true"
7
+ - Close button: aria-label="Close"
8
+ - Focus trap when open
9
+ - Keyboard: Escape to close
10
+
11
+ Usage:
12
+ <div class="ds-bottom-sheet ds-bottom-sheet--open">
13
+ <div class="ds-bottom-sheet__backdrop"></div>
14
+ <div class="ds-bottom-sheet__panel">
15
+ <div class="ds-bottom-sheet__handle"></div>
16
+ <div class="ds-bottom-sheet__header">
17
+ <h3 class="ds-bottom-sheet__title">Title</h3>
18
+ <button class="ds-bottom-sheet__close" aria-label="Close">&times;</button>
19
+ </div>
20
+ <div class="ds-bottom-sheet__body">
21
+ ...content...
22
+ </div>
23
+ </div>
24
+ </div>
25
+
26
+ Modifiers:
27
+ .ds-bottom-sheet--open — Visible
28
+ .ds-bottom-sheet--full — Full height (90dvh)
29
+ ========================================================================== */
30
+
31
+ .ds-bottom-sheet {
32
+ position: fixed;
33
+ inset: 0;
34
+ z-index: var(--ds-z-modal);
35
+ display: none;
36
+
37
+ &--open {
38
+ display: block;
39
+ }
40
+
41
+ /* --- Backdrop --- */
42
+ &__backdrop {
43
+ position: fixed;
44
+ inset: 0;
45
+ background-color: var(--ds-color-overlay);
46
+ animation: ds-bottom-sheet-backdrop-in var(--ds-duration-normal) var(--ds-ease-default) forwards;
47
+ }
48
+
49
+ /* --- Panel --- */
50
+ &__panel {
51
+ position: fixed;
52
+ inset-inline-start: 0;
53
+ inset-inline-end: 0;
54
+ inset-block-end: 0;
55
+ max-height: 75dvh;
56
+ display: flex;
57
+ flex-direction: column;
58
+ background-color: var(--ds-color-surface);
59
+ border-radius: var(--ds-radius-xl) var(--ds-radius-xl) 0 0;
60
+ box-shadow: var(--ds-shadow-lg);
61
+ overflow: hidden;
62
+ animation: ds-bottom-sheet-slide-up var(--ds-duration-normal) var(--ds-ease-out-expo) forwards;
63
+ }
64
+
65
+ /* --- Drag handle --- */
66
+ &__handle {
67
+ width: 2.5rem;
68
+ height: 4px;
69
+ margin: var(--ds-space-2) auto;
70
+ border-radius: var(--ds-radius-full);
71
+ background-color: var(--ds-color-surface-muted);
72
+ flex-shrink: 0;
73
+ }
74
+
75
+ /* --- Header --- */
76
+ &__header {
77
+ display: flex;
78
+ align-items: center;
79
+ justify-content: space-between;
80
+ padding: var(--ds-space-2) var(--ds-space-4) var(--ds-space-3);
81
+ flex-shrink: 0;
82
+ }
83
+
84
+ &__title {
85
+ font-family: var(--ds-font-display);
86
+ font-weight: var(--ds-weight-semibold);
87
+ font-size: var(--ds-text-lg);
88
+ color: var(--ds-color-text);
89
+ }
90
+
91
+ &__close {
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ width: var(--ds-size-2);
96
+ height: var(--ds-size-2);
97
+ border: none;
98
+ border-radius: var(--ds-radius-md);
99
+ background: transparent;
100
+ color: var(--ds-color-text-tertiary);
101
+ cursor: pointer;
102
+ transition: color var(--ds-duration-fast) var(--ds-ease-default);
103
+
104
+ &:hover {
105
+ color: var(--ds-color-text);
106
+ }
107
+
108
+ &:focus-visible {
109
+ outline: none;
110
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
111
+ }
112
+ }
113
+
114
+ /* --- Body --- */
115
+ &__body {
116
+ flex: 1;
117
+ overflow-y: auto;
118
+ overscroll-behavior: contain;
119
+ padding: 0 var(--ds-space-4) var(--ds-space-4);
120
+ }
121
+
122
+ /* --- Full height modifier --- */
123
+ &--full &__panel {
124
+ max-height: 90dvh;
125
+ }
126
+ }
127
+
128
+ @keyframes ds-bottom-sheet-backdrop-in {
129
+ from { opacity: 0; }
130
+ to { opacity: 1; }
131
+ }
132
+
133
+ @keyframes ds-bottom-sheet-slide-up {
134
+ from { transform: translateY(100%); }
135
+ to { transform: translateY(0); }
136
+ }
137
+
138
+ @media (prefers-reduced-motion: reduce) {
139
+ .ds-bottom-sheet__panel {
140
+ animation: none;
141
+ }
142
+ .ds-bottom-sheet__backdrop {
143
+ animation: none;
144
+ opacity: 1;
145
+ }
146
+ }
@@ -0,0 +1,102 @@
1
+ /* ==========================================================================
2
+ Breadcrumb Navigation
3
+ ==========================================================================
4
+ A horizontal breadcrumb trail for hierarchical navigation.
5
+
6
+ ARIA requirements (consumer responsibility):
7
+ - Container: <nav aria-label="Breadcrumb">
8
+ - Current page: aria-current="page" on the last item
9
+ - Links: use <a> elements for navigation
10
+ - Separator: decorative (generated via CSS ::after, not in DOM)
11
+
12
+ Usage:
13
+ <nav class="ds-breadcrumb" aria-label="Breadcrumb">
14
+ <span class="ds-breadcrumb__item">
15
+ <a href="/" class="ds-breadcrumb__link">Home</a>
16
+ </span>
17
+ <span class="ds-breadcrumb__item">
18
+ <a href="/products" class="ds-breadcrumb__link">Products</a>
19
+ </span>
20
+ <span class="ds-breadcrumb__item">
21
+ <span class="ds-breadcrumb__current" aria-current="page">Widget</span>
22
+ </span>
23
+ </nav>
24
+ ========================================================================== */
25
+
26
+ /* ---------------------------------------------------------------------------
27
+ Container
28
+ --------------------------------------------------------------------------- */
29
+
30
+ .ds-breadcrumb {
31
+ display: flex;
32
+ flex-direction: row;
33
+ align-items: center;
34
+ gap: var(--ds-space-1);
35
+ font-size: var(--ds-text-sm);
36
+ font-family: var(--ds-font-sans);
37
+ list-style: none;
38
+ margin: 0;
39
+ padding: 0;
40
+
41
+ /* ---------------------------------------------------------------------------
42
+ Item
43
+ --------------------------------------------------------------------------- */
44
+
45
+ &__item {
46
+ display: flex;
47
+ align-items: center;
48
+ gap: var(--ds-space-1);
49
+
50
+ /* Separator — rendered via ::after on every item except the last */
51
+ &:not(:last-child)::after {
52
+ content: "/";
53
+ color: var(--ds-color-text-tertiary);
54
+ flex-shrink: 0;
55
+ user-select: none;
56
+ pointer-events: none;
57
+ }
58
+ }
59
+
60
+ /* ---------------------------------------------------------------------------
61
+ Link
62
+ --------------------------------------------------------------------------- */
63
+
64
+ &__link {
65
+ color: var(--ds-color-text-tertiary);
66
+ text-decoration: none;
67
+ transition: color var(--ds-duration-fast) var(--ds-ease-out);
68
+
69
+ &:hover {
70
+ color: var(--ds-color-text-secondary);
71
+ }
72
+
73
+ &:focus-visible {
74
+ outline: none;
75
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
76
+ border-radius: var(--ds-radius-sm);
77
+ scroll-margin-block: var(--ds-space-16, 4rem);
78
+ }
79
+ }
80
+
81
+ /* ---------------------------------------------------------------------------
82
+ Current page (non-interactive)
83
+ --------------------------------------------------------------------------- */
84
+
85
+ &__current {
86
+ color: var(--ds-color-text);
87
+ font-weight: var(--ds-weight-medium);
88
+ }
89
+
90
+ /* ---------------------------------------------------------------------------
91
+ Modifier: Compact
92
+ --------------------------------------------------------------------------- */
93
+
94
+ &--compact {
95
+ gap: var(--ds-space-0-5, 0.125rem);
96
+ font-size: var(--ds-text-xs);
97
+
98
+ & .ds-breadcrumb__item {
99
+ gap: var(--ds-space-0-5, 0.125rem);
100
+ }
101
+ }
102
+ }
@@ -0,0 +1,250 @@
1
+ /* ==========================================================================
2
+ Component: Button
3
+ Inverted primary, rounded-full CTAs, refined sizing.
4
+
5
+ ARIA requirements (consumer responsibility):
6
+ - Use <button> or <a role="button"> elements
7
+ - Disabled: add aria-disabled="true" (supported by DS styles)
8
+ - Loading: add aria-busy="true" when --loading is applied
9
+ - Icon-only: add aria-label="[action]" for screen readers
10
+ - Button groups: wrap in role="group" with aria-label
11
+ ========================================================================== */
12
+
13
+ .ds-btn {
14
+ display: inline-flex;
15
+ align-items: center;
16
+ justify-content: center;
17
+ height: var(--ds-size-3);
18
+ gap: var(--ds-space-2);
19
+ padding: 0 var(--ds-space-4);
20
+ font-family: var(--ds-font-sans);
21
+ font-size: var(--ds-text-sm);
22
+ font-weight: var(--ds-weight-medium);
23
+ line-height: var(--ds-leading-none);
24
+ white-space: nowrap;
25
+ border-radius: var(--ds-radius-lg);
26
+ border: 1px solid transparent;
27
+ cursor: pointer;
28
+ transition: all var(--ds-duration-fast) var(--ds-ease-default);
29
+
30
+ /* Default: inverted (dark bg in light mode, light bg in dark mode) */
31
+ background-color: var(--ds-color-inverted);
32
+ color: var(--ds-color-on-inverted);
33
+
34
+ &:hover {
35
+ opacity: 0.9;
36
+ }
37
+
38
+ &:focus-visible {
39
+ outline: none;
40
+ box-shadow: 0 0 0 var(--ds-ring-width) var(--ds-ring-color);
41
+ scroll-margin-block: var(--ds-space-16, 4rem);
42
+ }
43
+
44
+ &:disabled,
45
+ &[aria-disabled="true"] {
46
+ opacity: var(--ds-opacity-disabled);
47
+ cursor: not-allowed;
48
+ pointer-events: none;
49
+ }
50
+
51
+ /* --- Variants --- */
52
+
53
+ &--secondary {
54
+ background-color: var(--ds-color-surface-muted);
55
+ color: var(--ds-color-text);
56
+ border-color: var(--ds-color-border);
57
+
58
+ &:hover {
59
+ border-color: var(--ds-color-border-hover);
60
+ background-color: var(--ds-color-surface-muted-hover);
61
+ opacity: 1;
62
+ }
63
+ }
64
+
65
+ &--outline {
66
+ background-color: transparent;
67
+ color: var(--ds-color-text-secondary);
68
+ border-color: var(--ds-color-border);
69
+
70
+ &:hover {
71
+ color: var(--ds-color-text);
72
+ border-color: var(--ds-color-border-hover);
73
+ opacity: 1;
74
+ }
75
+ }
76
+
77
+ &--ghost {
78
+ background-color: transparent;
79
+ color: var(--ds-color-text-secondary);
80
+
81
+ &:hover {
82
+ color: var(--ds-color-text);
83
+ background-color: var(--ds-color-surface-hover);
84
+ opacity: 1;
85
+ }
86
+ }
87
+
88
+ &--danger {
89
+ background-color: var(--ds-color-error-subtle);
90
+ color: var(--ds-color-error);
91
+ border-color: var(--ds-color-error-border);
92
+
93
+ &:hover {
94
+ background-color: var(--ds-color-error);
95
+ color: var(--ds-color-on-inverted);
96
+ opacity: 1;
97
+ }
98
+ }
99
+
100
+ &--success {
101
+ background-color: var(--ds-color-success-subtle);
102
+ color: var(--ds-color-success);
103
+ border-color: var(--ds-color-success-border);
104
+
105
+ &:hover {
106
+ background-color: var(--ds-color-success);
107
+ color: var(--ds-color-on-inverted);
108
+ opacity: 1;
109
+ }
110
+ }
111
+
112
+ &--success-solid {
113
+ background-color: var(--ds-color-success);
114
+ color: var(--ds-color-on-inverted);
115
+ border-color: transparent;
116
+
117
+ &:hover {
118
+ opacity: 0.85;
119
+ }
120
+ }
121
+
122
+ /* --- Sizes --- */
123
+
124
+ &--xs {
125
+ height: var(--ds-size-1);
126
+ padding: 0 var(--ds-space-2);
127
+ font-size: var(--ds-text-xs);
128
+ gap: var(--ds-space-1);
129
+ border-radius: var(--ds-radius-md);
130
+ }
131
+
132
+ &--sm {
133
+ height: var(--ds-size-2);
134
+ padding: 0 var(--ds-space-3);
135
+ font-size: var(--ds-text-sm);
136
+ gap: var(--ds-space-1-5);
137
+ border-radius: var(--ds-radius-md);
138
+ }
139
+
140
+ &--lg {
141
+ height: var(--ds-size-4);
142
+ padding: 0 var(--ds-space-6);
143
+ font-size: var(--ds-text-base);
144
+ border-radius: var(--ds-radius-lg);
145
+ }
146
+
147
+ &--xl {
148
+ height: var(--ds-size-5);
149
+ padding: 0 var(--ds-space-8);
150
+ font-size: var(--ds-text-base);
151
+ border-radius: var(--ds-radius-lg);
152
+ }
153
+
154
+ &--2xl {
155
+ height: var(--ds-size-6);
156
+ padding: 0 var(--ds-space-8);
157
+ font-size: var(--ds-text-lg);
158
+ border-radius: var(--ds-radius-xl);
159
+ }
160
+
161
+ /* --- Pill (rounded-full, like hero CTAs) --- */
162
+ &--pill {
163
+ border-radius: var(--ds-radius-full);
164
+ padding: 0 var(--ds-space-6);
165
+
166
+ &.ds-btn--xs {
167
+ padding: 0 var(--ds-space-3);
168
+ }
169
+
170
+ &.ds-btn--sm {
171
+ padding: 0 var(--ds-space-5);
172
+ }
173
+
174
+ &.ds-btn--xl {
175
+ padding: 0 var(--ds-space-8);
176
+ }
177
+
178
+ &.ds-btn--2xl {
179
+ padding: 0 var(--ds-space-10);
180
+ }
181
+ }
182
+
183
+ /* --- Full Width --- */
184
+ &--full { width: 100%; }
185
+
186
+ /* --- Icon Only --- */
187
+ &--icon {
188
+ padding: 0;
189
+ width: var(--ds-size-3);
190
+ height: var(--ds-size-3);
191
+ border-radius: var(--ds-radius-md);
192
+
193
+ &.ds-btn--xs {
194
+ width: var(--ds-size-1);
195
+ height: var(--ds-size-1);
196
+ }
197
+
198
+ &.ds-btn--sm {
199
+ width: var(--ds-size-2);
200
+ height: var(--ds-size-2);
201
+ }
202
+
203
+ &.ds-btn--xl {
204
+ width: var(--ds-size-5);
205
+ height: var(--ds-size-5);
206
+ }
207
+
208
+ &.ds-btn--2xl {
209
+ width: var(--ds-size-6);
210
+ height: var(--ds-size-6);
211
+ }
212
+ }
213
+
214
+ /* --- Loading spinner --- */
215
+ &--loading {
216
+ position: relative;
217
+ color: transparent !important;
218
+ pointer-events: none;
219
+
220
+ &::after {
221
+ content: '';
222
+ position: absolute;
223
+ width: 1em;
224
+ height: 1em;
225
+ border: 2px solid currentColor;
226
+ border-inline-end-color: transparent;
227
+ border-radius: var(--ds-radius-full);
228
+ animation: ds-btn-spin 0.6s linear infinite;
229
+ color: var(--ds-color-on-inverted);
230
+ }
231
+ }
232
+ }
233
+
234
+ /* --- Button Group --- */
235
+ .ds-btn-group {
236
+ display: inline-flex;
237
+
238
+ & .ds-btn { border-radius: 0; }
239
+ & .ds-btn:first-child { border-radius: var(--ds-radius-lg) 0 0 var(--ds-radius-lg); }
240
+ & .ds-btn:last-child { border-radius: 0 var(--ds-radius-lg) var(--ds-radius-lg) 0; }
241
+ & .ds-btn + .ds-btn { margin-inline-start: -1px; }
242
+ }
243
+
244
+ @keyframes ds-btn-spin {
245
+ to { transform: rotate(360deg); }
246
+ }
247
+
248
+ @media (prefers-reduced-motion: reduce) {
249
+ .ds-btn--loading::after { animation: none; opacity: 0.6; }
250
+ }