canny-ui 2.0.0 → 3.0.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.
@@ -0,0 +1,113 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // Accordion — collapsible disclosure rows. Three variants:
4
+ // plain — minimal, dividers only between items
5
+ // bordered — single rounded panel with internal dividers
6
+ // separated — each item is its own card with vertical gap
7
+
8
+ @keyframes cny-accordion-down {
9
+ from { height: 0; }
10
+ to { height: var(--radix-accordion-content-height); }
11
+ }
12
+ @keyframes cny-accordion-up {
13
+ from { height: var(--radix-accordion-content-height); }
14
+ to { height: 0; }
15
+ }
16
+
17
+ .cny-accordion {
18
+ font-family: var(--font-body);
19
+ color: var(--text-primary);
20
+ width: 100%;
21
+
22
+ &-item {
23
+ border-bottom: 1px solid var(--border-color);
24
+ &:last-child { border-bottom: 0; }
25
+ }
26
+
27
+ &-header { all: unset; display: flex; }
28
+
29
+ &-trigger {
30
+ flex: 1;
31
+ display: flex;
32
+ align-items: center;
33
+ gap: $space-2;
34
+ width: 100%;
35
+ padding: $space-3 $space-3;
36
+ background: transparent;
37
+ border: 0;
38
+ color: var(--text-primary);
39
+ font-size: 0.875rem;
40
+ font-weight: 550;
41
+ text-align: left;
42
+ cursor: pointer;
43
+ transition: background-color 120ms ease;
44
+
45
+ &:hover { background: var(--bg-surface-low); }
46
+ &:focus-visible {
47
+ outline: 2px solid var(--color-primary);
48
+ outline-offset: -2px;
49
+ }
50
+
51
+ &-icon {
52
+ display: inline-flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ width: 20px;
56
+ height: 20px;
57
+ color: var(--text-muted);
58
+ flex: none;
59
+ }
60
+
61
+ &-label { flex: 1; min-width: 0; }
62
+
63
+ &-chevron {
64
+ flex: none;
65
+ color: var(--text-muted);
66
+ transition: transform 180ms ease;
67
+ }
68
+
69
+ &[data-state='open'] &-chevron { transform: rotate(180deg); }
70
+ // Radix puts data-state on the trigger itself
71
+ &[data-state='open'] .cny-accordion-trigger-chevron { transform: rotate(180deg); }
72
+ }
73
+
74
+ &-content {
75
+ overflow: hidden;
76
+ font-size: 0.8125rem;
77
+ color: var(--text-secondary);
78
+ line-height: 1.55;
79
+
80
+ &[data-state='open'] { animation: cny-accordion-down 200ms ease-out; }
81
+ &[data-state='closed'] { animation: cny-accordion-up 180ms ease-in; }
82
+
83
+ &-inner {
84
+ padding: 0 $space-3 $space-3;
85
+ }
86
+ }
87
+
88
+ // Variants
89
+ &-bordered {
90
+ border: 1px solid var(--border-color);
91
+ border-radius: var(--radius-md);
92
+ overflow: hidden;
93
+ background: var(--bg-surface-lowest);
94
+ }
95
+
96
+ &-separated {
97
+ display: flex;
98
+ flex-direction: column;
99
+ gap: $space-2;
100
+
101
+ .cny-accordion-item {
102
+ border: 1px solid var(--border-color);
103
+ border-radius: var(--radius-md);
104
+ background: var(--bg-surface-lowest);
105
+ overflow: hidden;
106
+ }
107
+ }
108
+
109
+ @media (prefers-reduced-motion: reduce) {
110
+ &-content { animation: none !important; }
111
+ &-trigger-chevron { transition: none; }
112
+ }
113
+ }
@@ -1,18 +1,13 @@
1
1
  @use '../tokens/primitives' as *;
2
2
 
3
- // Alert — contextual status banner. Layered tonal surface, icon chip, optional
4
- // inline action and dismiss. Solid variant reserved for high-priority announcements.
3
+ // Alert — contextual status banner. Flat tonal surface, icon chip, optional
4
+ // inline action and dismiss. Solid variant uses the accent color directly.
5
5
 
6
6
  @keyframes alert-rise {
7
- from { opacity: 0; transform: translateY(-4px); }
7
+ from { opacity: 0; transform: translateY(-2px); }
8
8
  to { opacity: 1; transform: translateY(0); }
9
9
  }
10
10
 
11
- @keyframes alert-icon-pop {
12
- from { opacity: 0; transform: scale(0.82); }
13
- to { opacity: 1; transform: scale(1); }
14
- }
15
-
16
11
  .alert {
17
12
  --alert-accent: var(--color-info);
18
13
  --alert-accent-soft: var(--color-info-soft);
@@ -30,56 +25,23 @@
30
25
  font-family: var(--font-body);
31
26
  font-size: 0.875rem;
32
27
  line-height: 1.5;
33
- box-shadow:
34
- 0 1px 0 rgba(15, 23, 42, 0.02),
35
- 0 1px 2px rgba(15, 23, 42, 0.04);
36
- animation: alert-rise 220ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
37
- transition: box-shadow 180ms ease, transform 180ms ease;
38
-
39
- // Inner highlight line — subtle white bevel at the top edge
40
- &::before {
41
- content: '';
42
- position: absolute;
43
- inset: 0 1px auto 1px;
44
- height: 1px;
45
- border-radius: var(--radius-md) var(--radius-md) 0 0;
46
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.55), transparent);
47
- pointer-events: none;
48
- opacity: 0.7;
49
- }
50
-
51
- &:hover {
52
- box-shadow:
53
- 0 1px 0 rgba(15, 23, 42, 0.03),
54
- 0 6px 18px -8px color-mix(in srgb, var(--alert-accent) 30%, transparent);
55
- }
28
+ animation: alert-rise 180ms ease-out both;
56
29
 
57
30
  @media (prefers-reduced-motion: reduce) {
58
31
  animation: none;
59
- transition: none;
60
32
  }
61
33
 
62
34
  &-icon {
63
- position: relative;
64
35
  flex: none;
65
36
  display: inline-flex;
66
37
  align-items: center;
67
38
  justify-content: center;
68
- width: 30px;
69
- height: 30px;
39
+ width: 28px;
40
+ height: 28px;
70
41
  margin-top: 1px;
71
42
  border-radius: var(--radius-sm);
72
- background:
73
- linear-gradient(180deg, color-mix(in srgb, var(--alert-accent) 14%, transparent), var(--alert-accent-soft));
43
+ background: var(--alert-accent-soft);
74
44
  color: var(--alert-accent);
75
- box-shadow:
76
- inset 0 0 0 1px color-mix(in srgb, var(--alert-accent) 22%, transparent),
77
- 0 1px 2px color-mix(in srgb, var(--alert-accent) 12%, transparent);
78
- animation: alert-icon-pop 260ms cubic-bezier(0.3, 1.4, 0.4, 1) 40ms both;
79
-
80
- @media (prefers-reduced-motion: reduce) {
81
- animation: none;
82
- }
83
45
  }
84
46
 
85
47
  &-content {
@@ -90,7 +52,6 @@
90
52
 
91
53
  &-title {
92
54
  font-weight: 600;
93
- letter-spacing: -0.005em;
94
55
  line-height: 1.35;
95
56
  margin: 0 0 2px;
96
57
  color: var(--text-primary);
@@ -123,84 +84,57 @@
123
84
  cursor: pointer;
124
85
  border-radius: var(--radius-sm);
125
86
  line-height: 1;
126
- transition: color 120ms ease, background-color 120ms ease, transform 120ms ease;
87
+ transition: color 120ms ease, background-color 120ms ease;
127
88
 
128
89
  &:hover {
129
90
  color: var(--text-primary);
130
- background: color-mix(in srgb, var(--alert-accent) 10%, transparent);
91
+ background: var(--bg-surface-low);
131
92
  }
132
- &:active { transform: scale(0.94); }
133
93
  &:focus-visible {
134
94
  outline: 2px solid var(--alert-accent);
135
95
  outline-offset: 1px;
136
96
  }
137
97
  }
138
98
 
139
- // Soft variants — layered tonal surface + tonal hairline border
99
+ // Soft variants — flat tonal surface + tonal hairline border
140
100
  &.info {
141
101
  --alert-accent: var(--color-info);
142
102
  --alert-accent-soft: var(--color-info-soft);
143
103
  --alert-accent-on: var(--color-info-on);
144
- background:
145
- linear-gradient(180deg, color-mix(in srgb, var(--color-info) 6%, transparent), transparent 60%),
146
- var(--color-info-soft);
147
- border-color: color-mix(in srgb, var(--color-info) 28%, transparent);
104
+ background: var(--color-info-soft);
105
+ border-color: color-mix(in srgb, var(--color-info) 22%, transparent);
148
106
  .alert-title { color: var(--color-info); }
149
107
  }
150
108
  &.success {
151
109
  --alert-accent: var(--color-success);
152
110
  --alert-accent-soft: var(--color-success-soft);
153
111
  --alert-accent-on: var(--color-success-on);
154
- background:
155
- linear-gradient(180deg, color-mix(in srgb, var(--color-success) 6%, transparent), transparent 60%),
156
- var(--color-success-soft);
157
- border-color: color-mix(in srgb, var(--color-success) 28%, transparent);
112
+ background: var(--color-success-soft);
113
+ border-color: color-mix(in srgb, var(--color-success) 22%, transparent);
158
114
  .alert-title { color: var(--color-success); }
159
115
  }
160
116
  &.warning {
161
117
  --alert-accent: var(--color-warning);
162
118
  --alert-accent-soft: var(--color-warning-soft);
163
119
  --alert-accent-on: var(--color-warning-on);
164
- background:
165
- linear-gradient(180deg, color-mix(in srgb, var(--color-warning) 7%, transparent), transparent 60%),
166
- var(--color-warning-soft);
167
- border-color: color-mix(in srgb, var(--color-warning) 30%, transparent);
120
+ background: var(--color-warning-soft);
121
+ border-color: color-mix(in srgb, var(--color-warning) 24%, transparent);
168
122
  .alert-title { color: var(--color-warning); }
169
123
  }
170
124
  &.danger {
171
125
  --alert-accent: var(--color-danger);
172
126
  --alert-accent-soft: var(--color-danger-soft);
173
127
  --alert-accent-on: var(--color-danger-on);
174
- background:
175
- linear-gradient(180deg, color-mix(in srgb, var(--color-danger) 8%, transparent), transparent 60%),
176
- var(--color-danger-soft);
177
- border-color: color-mix(in srgb, var(--color-danger) 32%, transparent);
128
+ background: var(--color-danger-soft);
129
+ border-color: color-mix(in srgb, var(--color-danger) 26%, transparent);
178
130
  .alert-title { color: var(--color-danger); }
179
131
  }
180
132
 
181
- // Solid variant — premium depth: layered gradient, inner ring, tonal glow
133
+ // Solid variant — flat accent fill
182
134
  &.solid {
183
135
  border: 0;
184
136
  color: var(--alert-accent-on);
185
- background:
186
- radial-gradient(120% 140% at 0% 0%, rgba(255, 255, 255, 0.22), transparent 55%),
187
- linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(0, 0, 0, 0.08) 100%),
188
- var(--alert-accent);
189
- box-shadow:
190
- inset 0 1px 0 rgba(255, 255, 255, 0.22),
191
- inset 0 0 0 1px rgba(255, 255, 255, 0.08),
192
- 0 1px 2px rgba(15, 23, 42, 0.14),
193
- 0 12px 28px -14px color-mix(in srgb, var(--alert-accent) 70%, transparent);
194
-
195
- &::before { opacity: 1; }
196
-
197
- &:hover {
198
- box-shadow:
199
- inset 0 1px 0 rgba(255, 255, 255, 0.26),
200
- inset 0 0 0 1px rgba(255, 255, 255, 0.1),
201
- 0 2px 4px rgba(15, 23, 42, 0.16),
202
- 0 18px 36px -14px color-mix(in srgb, var(--alert-accent) 80%, transparent);
203
- }
137
+ background: var(--alert-accent);
204
138
 
205
139
  .alert-title { color: var(--alert-accent-on); }
206
140
  .alert-body { color: var(--alert-accent-on); opacity: 0.88; }
@@ -208,9 +142,6 @@
208
142
  .alert-icon {
209
143
  background: rgba(255, 255, 255, 0.18);
210
144
  color: var(--alert-accent-on);
211
- box-shadow:
212
- inset 0 0 0 1px rgba(255, 255, 255, 0.28),
213
- inset 0 1px 0 rgba(255, 255, 255, 0.2);
214
145
  }
215
146
 
216
147
  .alert-close {
@@ -0,0 +1,188 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // Autocomplete — searchable combobox built on cmdk + Radix Popover.
4
+ // Trigger composes the .input shape; popover styling matches CommandPalette.
5
+
6
+ @keyframes cny-ac-in {
7
+ from { opacity: 0; transform: translateY(-4px) scale(0.98); }
8
+ to { opacity: 1; transform: translateY(0) scale(1); }
9
+ }
10
+
11
+ // ── Trigger ───────────────────────────────────────────────────
12
+ .cny-ac-trigger {
13
+ display: inline-flex;
14
+ align-items: center;
15
+ gap: $space-2;
16
+ width: 100%;
17
+ text-align: left;
18
+ cursor: pointer;
19
+ padding: 0 $space-3;
20
+
21
+ &.is-open { border-color: var(--border-focus); }
22
+ &[disabled] { cursor: not-allowed; opacity: 0.6; }
23
+ }
24
+
25
+ .cny-ac-value {
26
+ flex: 1 1 auto;
27
+ min-width: 0;
28
+ color: var(--text-primary);
29
+ font-size: inherit;
30
+ line-height: 1.4;
31
+ white-space: nowrap;
32
+ overflow: hidden;
33
+ text-overflow: ellipsis;
34
+
35
+ &.is-placeholder { color: var(--text-muted); }
36
+ }
37
+
38
+ .cny-ac-clear {
39
+ flex: none;
40
+ display: inline-flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ width: 18px;
44
+ height: 18px;
45
+ border-radius: var(--radius-xs);
46
+ color: var(--text-muted);
47
+ cursor: pointer;
48
+ transition: color 120ms ease, background-color 120ms ease;
49
+
50
+ &:hover { color: var(--text-primary); background: var(--bg-surface-low); }
51
+ }
52
+
53
+ .cny-ac-chevron {
54
+ flex: none;
55
+ color: var(--text-muted);
56
+ }
57
+
58
+ // ── Popover content ──────────────────────────────────────────
59
+ .cny-ac-content {
60
+ z-index: 1010;
61
+ background: var(--bg-surface-lowest);
62
+ border: 1px solid var(--border-color);
63
+ border-radius: var(--radius-sm);
64
+ box-shadow:
65
+ 0 1px 0 rgba(15, 23, 42, 0.04),
66
+ 0 12px 28px -12px rgba(15, 23, 42, 0.22);
67
+ overflow: hidden;
68
+ font-family: var(--font-body);
69
+ animation: cny-ac-in 140ms cubic-bezier(0.2, 0.8, 0.2, 1);
70
+ outline: none;
71
+ }
72
+
73
+ .cny-ac-cmdk { display: flex; flex-direction: column; }
74
+
75
+ .cny-ac-search {
76
+ padding: 8px 10px;
77
+ border-bottom: 1px solid var(--hairline-color);
78
+
79
+ [cmdk-input] {
80
+ width: 100%;
81
+ border: 0;
82
+ background: transparent;
83
+ font: inherit;
84
+ font-size: 0.875rem;
85
+ color: var(--text-primary);
86
+ outline: none;
87
+ padding: 0;
88
+
89
+ &::placeholder { color: var(--text-muted); }
90
+ }
91
+ }
92
+
93
+ .cny-ac-list {
94
+ overflow-y: auto;
95
+ max-height: 280px;
96
+ padding: 6px;
97
+ scrollbar-width: thin;
98
+ }
99
+
100
+ .cny-ac-empty,
101
+ .cny-ac-loading {
102
+ padding: 18px 12px;
103
+ text-align: center;
104
+ color: var(--text-muted);
105
+ font-size: 0.875rem;
106
+ }
107
+
108
+ .cny-ac-loading {
109
+ display: flex;
110
+ align-items: center;
111
+ justify-content: center;
112
+ gap: 8px;
113
+ }
114
+ .cny-ac-loading-spinner { animation: cny-ac-spin 1s linear infinite; }
115
+ @keyframes cny-ac-spin { to { transform: rotate(360deg); } }
116
+
117
+ [cmdk-group-heading] {
118
+ padding: 8px 10px 4px;
119
+ font-size: 0.6875rem;
120
+ font-weight: 650;
121
+ letter-spacing: 0.08em;
122
+ text-transform: uppercase;
123
+ color: var(--text-muted);
124
+ }
125
+
126
+ .cny-ac-item {
127
+ display: flex;
128
+ align-items: center;
129
+ gap: 10px;
130
+ padding: 8px 10px;
131
+ border-radius: var(--radius-xs);
132
+ cursor: pointer;
133
+ color: var(--text-primary);
134
+ font-size: 0.875rem;
135
+ outline: none;
136
+ user-select: none;
137
+ position: relative;
138
+
139
+ &[data-selected='true'] {
140
+ background: color-mix(in srgb, var(--color-primary) 10%, var(--bg-surface-low));
141
+ }
142
+ &[data-disabled='true'] {
143
+ color: var(--text-disabled);
144
+ pointer-events: none;
145
+ }
146
+
147
+ &-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
148
+ &-hint {
149
+ flex: none;
150
+ font-size: 0.75rem;
151
+ color: var(--text-muted);
152
+ margin-left: 8px;
153
+ }
154
+ }
155
+
156
+ .cny-ac-icon {
157
+ flex: none;
158
+ display: inline-flex;
159
+ align-items: center;
160
+ justify-content: center;
161
+ width: 16px;
162
+ height: 16px;
163
+ color: var(--color-primary);
164
+ }
165
+
166
+ .cny-ac-checkbox {
167
+ flex: none;
168
+ display: inline-flex;
169
+ align-items: center;
170
+ justify-content: center;
171
+ width: 16px;
172
+ height: 16px;
173
+ border: 1px solid var(--border-color);
174
+ border-radius: var(--radius-xs);
175
+ background: var(--bg-surface-lowest);
176
+ color: var(--color-primary-on, white);
177
+ transition: background-color 120ms ease, border-color 120ms ease;
178
+
179
+ &.is-checked {
180
+ background: var(--color-primary);
181
+ border-color: var(--color-primary);
182
+ }
183
+ }
184
+
185
+ @media (prefers-reduced-motion: reduce) {
186
+ .cny-ac-content { animation: none; }
187
+ .cny-ac-loading-spinner { animation: none; }
188
+ }
@@ -0,0 +1,56 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // Breadcrumb — flat horizontal trail with separator nodes.
4
+
5
+ .cny-breadcrumb {
6
+ font-family: var(--font-body);
7
+ font-size: 0.8125rem;
8
+ color: var(--text-muted);
9
+ line-height: 1.4;
10
+
11
+ &-list {
12
+ list-style: none;
13
+ margin: 0;
14
+ padding: 0;
15
+ display: flex;
16
+ flex-wrap: wrap;
17
+ align-items: center;
18
+ gap: 6px;
19
+ }
20
+
21
+ &-item {
22
+ display: inline-flex;
23
+ align-items: center;
24
+ gap: 6px;
25
+ min-width: 0;
26
+ }
27
+
28
+ &-link {
29
+ color: var(--text-secondary);
30
+ text-decoration: none;
31
+ border-radius: var(--radius-sm);
32
+ padding: 2px 4px;
33
+ transition: color 120ms ease, background-color 120ms ease;
34
+ &:hover { color: var(--text-primary); background: var(--bg-surface-low); }
35
+ &:focus-visible {
36
+ outline: 2px solid var(--color-primary);
37
+ outline-offset: 1px;
38
+ }
39
+ }
40
+
41
+ &-label.is-current {
42
+ color: var(--text-primary);
43
+ font-weight: 500;
44
+ }
45
+
46
+ &-sep {
47
+ display: inline-flex;
48
+ color: var(--text-muted);
49
+ opacity: 0.7;
50
+ }
51
+
52
+ &-sm {
53
+ font-size: 0.75rem;
54
+ .cny-breadcrumb-list { gap: 4px; }
55
+ }
56
+ }
@@ -0,0 +1,122 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // Chip — compact label / status / filter pill / removable token.
4
+
5
+ .cny-chip {
6
+ --chip-color: var(--text-secondary);
7
+ --chip-bg: var(--bg-surface-low);
8
+ --chip-border: var(--hairline-color);
9
+
10
+ display: inline-flex;
11
+ align-items: center;
12
+ gap: 6px;
13
+ height: 26px;
14
+ padding: 0 10px;
15
+ border-radius: 999px;
16
+ font-family: var(--font-body);
17
+ font-size: 0.75rem;
18
+ font-weight: 550;
19
+ letter-spacing: -0.005em;
20
+ white-space: nowrap;
21
+ background: var(--chip-bg);
22
+ color: var(--chip-color);
23
+ border: 1px solid var(--chip-border);
24
+ transition: background-color 140ms ease, border-color 140ms ease, transform 140ms ease;
25
+ user-select: none;
26
+
27
+ &.sm {
28
+ height: 22px;
29
+ padding: 0 8px;
30
+ font-size: 0.6875rem;
31
+ gap: 4px;
32
+ }
33
+
34
+ &-icon, &-avatar {
35
+ display: inline-flex;
36
+ align-items: center;
37
+ flex: none;
38
+ }
39
+ &-avatar { margin-left: -4px; }
40
+ &-label { line-height: 1; }
41
+
42
+ &-delete {
43
+ flex: none;
44
+ display: inline-flex;
45
+ align-items: center;
46
+ justify-content: center;
47
+ width: 16px;
48
+ height: 16px;
49
+ margin-right: -4px;
50
+ background: transparent;
51
+ border: 0;
52
+ border-radius: 50%;
53
+ color: currentColor;
54
+ opacity: 0.6;
55
+ cursor: pointer;
56
+ transition: opacity 120ms ease, background-color 120ms ease;
57
+
58
+ &:hover {
59
+ opacity: 1;
60
+ background: color-mix(in srgb, var(--chip-color) 15%, transparent);
61
+ }
62
+ &:focus-visible {
63
+ outline: 2px solid var(--chip-color);
64
+ outline-offset: 1px;
65
+ }
66
+ }
67
+ .sm &-delete { width: 14px; height: 14px; margin-right: -3px; }
68
+
69
+ // Interactive (clickable) state
70
+ &.is-interactive {
71
+ cursor: pointer;
72
+ &:hover { transform: translateY(-1px); }
73
+ &:active { transform: translateY(0); }
74
+ &:focus-visible {
75
+ outline: 2px solid color-mix(in srgb, var(--chip-color) 60%, transparent);
76
+ outline-offset: 2px;
77
+ }
78
+ }
79
+ &.is-disabled {
80
+ opacity: 0.55;
81
+ cursor: not-allowed;
82
+ pointer-events: none;
83
+ }
84
+
85
+ // ── Color tones ──
86
+ &.primary {
87
+ --chip-color: var(--color-primary);
88
+ --chip-bg: color-mix(in srgb, var(--color-primary) 10%, transparent);
89
+ --chip-border: color-mix(in srgb, var(--color-primary) 22%, transparent);
90
+ }
91
+ &.success {
92
+ --chip-color: var(--color-success);
93
+ --chip-bg: color-mix(in srgb, var(--color-success) 10%, transparent);
94
+ --chip-border: color-mix(in srgb, var(--color-success) 24%, transparent);
95
+ }
96
+ &.info {
97
+ --chip-color: var(--color-info);
98
+ --chip-bg: color-mix(in srgb, var(--color-info) 10%, transparent);
99
+ --chip-border: color-mix(in srgb, var(--color-info) 24%, transparent);
100
+ }
101
+ &.warning {
102
+ --chip-color: var(--color-warning);
103
+ --chip-bg: color-mix(in srgb, var(--color-warning) 12%, transparent);
104
+ --chip-border: color-mix(in srgb, var(--color-warning) 26%, transparent);
105
+ }
106
+ &.danger {
107
+ --chip-color: var(--color-danger);
108
+ --chip-bg: color-mix(in srgb, var(--color-danger) 10%, transparent);
109
+ --chip-border: color-mix(in srgb, var(--color-danger) 26%, transparent);
110
+ }
111
+
112
+ // ── Variants ──
113
+ &.outline {
114
+ background: transparent;
115
+ }
116
+ &.solid.primary { background: var(--color-primary); color: var(--color-primary-on, #fff); border-color: var(--color-primary); }
117
+ &.solid.success { background: var(--color-success); color: var(--color-success-on, #fff); border-color: var(--color-success); }
118
+ &.solid.info { background: var(--color-info); color: var(--color-info-on, #fff); border-color: var(--color-info); }
119
+ &.solid.warning { background: var(--color-warning); color: var(--color-warning-on, #fff); border-color: var(--color-warning); }
120
+ &.solid.danger { background: var(--color-danger); color: var(--color-danger-on, #fff); border-color: var(--color-danger); }
121
+ &.solid.default { background: var(--text-primary); color: var(--bg-surface-lowest); border-color: var(--text-primary); }
122
+ }