@acontplus/ng-components 2.3.0 → 2.4.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acontplus/ng-components",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Comprehensive Angular Material UI component library featuring dynamic Tabulator tables, theme toggle with dark mode, dialog wrappers, autocomplete components, cards, buttons, icons, input chips, spinners, directives, pipes, and SCSS styling utilities.",
5
5
  "peerDependencies": {
6
6
  "@acontplus/ui-kit": "^1.0.2",
package/src/_index.scss CHANGED
@@ -1,12 +1,17 @@
1
1
  @forward './lib/components/alert/alert-theme' as alert-* show alert-theme, alert-color,
2
2
  alert-typography, alert-density, alert-base, alert-overrides;
3
3
 
4
+ @forward './lib/components/badge/badge-theme' as badge-* show badge-theme, badge-color,
5
+ badge-typography, badge-density, badge-base, badge-overrides;
6
+
4
7
  @forward './lib/components/drawer/drawer-theme' as drawer-* show drawer-theme, drawer-color,
5
8
  drawer-typography, drawer-density, drawer-base, drawer-overrides;
6
9
  @forward './lib/components/grid/grid-theme' as grid-* show grid-theme, grid-color, grid-typography,
7
10
  grid-density, grid-base, grid-overrides;
8
11
  @forward './lib/components/popover/popover-theme' as popover-* show popover-theme, popover-color,
9
12
  popover-typography, popover-density, popover-base, popover-overrides;
13
+ @forward './lib/components/kpi-card/kpi-card-theme' as kpi-card-* show kpi-card-theme,
14
+ kpi-card-color, kpi-card-typography, kpi-card-density, kpi-card-base, kpi-card-overrides;
10
15
  @forward './core/theming/definition' show define-theme, define-colors, define-typography,
11
16
  define-density;
12
17
  @forward './core/theming/color-api-backwards-compatibility' show
@@ -1,22 +1,28 @@
1
1
  @use '@angular/material' as mat;
2
2
  @use './../../lib/components/alert/alert-theme';
3
+ @use './../../lib/components/badge/badge-theme';
3
4
  @use './../../lib/components/drawer/drawer-theme';
4
5
  @use './../../lib/components/grid/grid-theme';
5
6
  @use './../../lib/components/popover/popover-theme';
7
+ @use './../../lib/components/kpi-card/kpi-card-theme';
6
8
 
7
9
  // Create a theme.
8
10
  @mixin all-component-themes($theme) {
9
11
  @include alert-theme.theme($theme);
12
+ @include badge-theme.theme($theme);
10
13
  @include drawer-theme.theme($theme);
11
14
  @include grid-theme.theme($theme);
12
15
  @include popover-theme.theme($theme);
16
+ @include kpi-card-theme.theme($theme);
13
17
  }
14
18
 
15
19
  @mixin all-component-bases($theme) {
16
20
  @include alert-theme.base($theme);
21
+ @include badge-theme.base($theme);
17
22
  @include drawer-theme.base($theme);
18
23
  @include grid-theme.base($theme);
19
24
  @include popover-theme.base($theme);
25
+ @include kpi-card-theme.base($theme);
20
26
  }
21
27
 
22
28
  // Custom component overrides for all themes
@@ -0,0 +1,58 @@
1
+ @use 'sass:map';
2
+ @use '@angular/material' as mat;
3
+ @use '../../../core/tokens/token-utils';
4
+ @use './m3-badge';
5
+
6
+ $fallbacks: m3-badge.get-tokens();
7
+
8
+ @mixin base($theme) {
9
+ $tokens: map.get(m3-badge.get-tokens($theme), base);
10
+
11
+ @include token-utils.values($tokens);
12
+ }
13
+
14
+ @mixin color($theme) {
15
+ $tokens: map.get(m3-badge.get-tokens($theme), color);
16
+
17
+ @include token-utils.values($tokens);
18
+ }
19
+
20
+ @mixin typography($theme) {
21
+ $tokens: map.get(m3-badge.get-tokens($theme), typography);
22
+
23
+ @include token-utils.values($tokens);
24
+ }
25
+
26
+ @mixin density($theme) {
27
+ $tokens: map.get(m3-badge.get-tokens($theme), density);
28
+
29
+ @include token-utils.values($tokens);
30
+ }
31
+
32
+ @function _define-overrides() {
33
+ @return ((namespace: badge, tokens: token-utils.get-overrides(m3-badge.get-tokens(), badge)));
34
+ }
35
+
36
+ @mixin overrides($tokens: ()) {
37
+ @include token-utils.batch-create-token-values($tokens, _define-overrides());
38
+ }
39
+
40
+ @mixin theme($theme, $color-variant: null) {
41
+ @if mat.get-theme-version($theme) == 1 {
42
+ @include base($theme);
43
+ @include color($theme);
44
+ @include density($theme);
45
+ @include typography($theme);
46
+ } @else {
47
+ @include base($theme);
48
+ @if mat.theme-has($theme, color) {
49
+ @include color($theme);
50
+ }
51
+ @if mat.theme-has($theme, density) {
52
+ @include density($theme);
53
+ }
54
+ @if mat.theme-has($theme, typography) {
55
+ @include typography($theme);
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,52 @@
1
+ @use 'sass:map';
2
+ @use '@angular/material' as mat;
3
+ @use '../../../core/tokens/m3-utils';
4
+ @use '../../../core/tokens/m3';
5
+
6
+ @function get-tokens($theme: m3.$sys-theme) {
7
+ $system: m3-utils.get-system($theme);
8
+
9
+ $semantic-palettes: (
10
+ success: mat.$green-palette,
11
+ warning: mat.$orange-palette,
12
+ danger: mat.$red-palette,
13
+ info: mat.$azure-palette,
14
+ );
15
+
16
+ $color-tokens: ();
17
+ @each $name, $palette in $semantic-palettes {
18
+ $color-tokens: map.merge(
19
+ $color-tokens,
20
+ (
21
+ badge-#{$name}-fg: light-dark(map.get($palette, 95), map.get($palette, 20)),
22
+ badge-#{$name}-bg: light-dark(map.get($palette, 40), map.get($palette, 80))
23
+ )
24
+ );
25
+ }
26
+
27
+ $tokens: (
28
+ base: (
29
+ badge-container-shape: map.get($system, corner-small),
30
+ badge-pill-shape: map.get($system, corner-full),
31
+ ),
32
+ color: map.merge(
33
+ (
34
+ badge-primary-color: map.get($system, on-primary),
35
+ badge-primary-bg: map.get($system, primary),
36
+ badge-secondary-color: map.get($system, on-secondary),
37
+ badge-secondary-bg: map.get($system, secondary),
38
+ badge-tertiary-color: map.get($system, on-tertiary),
39
+ badge-tertiary-bg: map.get($system, tertiary),
40
+ badge-neutral-color: map.get($system, on-surface-variant),
41
+ badge-neutral-bg: map.get($system, surface-variant),
42
+ badge-custom-color: map.get($system, on-surface),
43
+ badge-custom-bg: map.get($system, surface-container),
44
+ ),
45
+ $color-tokens
46
+ ),
47
+ typography: (),
48
+ density: (),
49
+ );
50
+
51
+ @return $tokens;
52
+ }
@@ -0,0 +1,318 @@
1
+ @use '@angular/material' as mat;
2
+ @use '../../../core/tokens/token-utils';
3
+ @use './m3-badge';
4
+
5
+ $fallbacks: m3-badge.get-tokens();
6
+
7
+ .acp-badge {
8
+ --acp-badge-bg: #{token-utils.slot(badge-primary-bg, $fallbacks)};
9
+ --acp-badge-fg: #{token-utils.slot(badge-primary-color, $fallbacks)};
10
+
11
+ display: inline-flex;
12
+ vertical-align: middle;
13
+ max-width: 100%;
14
+
15
+ &__set {
16
+ display: inline-flex;
17
+ max-width: 100%;
18
+ }
19
+
20
+ &__chip.mat-mdc-chip {
21
+ position: relative;
22
+ max-width: 100%;
23
+ }
24
+
25
+ &__label,
26
+ &__value {
27
+ white-space: nowrap;
28
+ overflow: hidden;
29
+ text-overflow: ellipsis;
30
+ }
31
+
32
+ &__separator {
33
+ margin: 0 6px;
34
+ opacity: 0.6;
35
+ }
36
+
37
+ &__loader {
38
+ position: absolute;
39
+ inset: 0;
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ background: inherit;
44
+ border-radius: inherit;
45
+ z-index: 1;
46
+
47
+ &::after {
48
+ content: '';
49
+ width: 16px;
50
+ height: 16px;
51
+ border: 2px solid currentColor;
52
+ border-right-color: transparent;
53
+ border-radius: 50%;
54
+ animation: acp-badge-spin 0.75s linear infinite;
55
+ }
56
+ }
57
+
58
+ &__remove {
59
+ cursor: pointer;
60
+
61
+ &:focus-visible {
62
+ outline: 2px solid currentColor;
63
+ outline-offset: 1px;
64
+ }
65
+ }
66
+
67
+ @keyframes acp-badge-spin {
68
+ to {
69
+ transform: rotate(360deg);
70
+ }
71
+ }
72
+
73
+ // Colors - set CSS variables on host
74
+ &.acp-badge--primary {
75
+ --acp-badge-bg: #{token-utils.slot(badge-primary-bg, $fallbacks)};
76
+ --acp-badge-fg: #{token-utils.slot(badge-primary-color, $fallbacks)};
77
+ }
78
+
79
+ &.acp-badge--secondary {
80
+ --acp-badge-bg: #{token-utils.slot(badge-secondary-bg, $fallbacks)};
81
+ --acp-badge-fg: #{token-utils.slot(badge-secondary-color, $fallbacks)};
82
+ }
83
+
84
+ &.acp-badge--tertiary {
85
+ --acp-badge-bg: #{token-utils.slot(badge-tertiary-bg, $fallbacks)};
86
+ --acp-badge-fg: #{token-utils.slot(badge-tertiary-color, $fallbacks)};
87
+ }
88
+
89
+ &.acp-badge--success {
90
+ --acp-badge-bg: #{token-utils.slot(badge-success-bg, $fallbacks)};
91
+ --acp-badge-fg: #{token-utils.slot(badge-success-fg, $fallbacks)};
92
+ }
93
+
94
+ &.acp-badge--warning {
95
+ --acp-badge-bg: #{token-utils.slot(badge-warning-bg, $fallbacks)};
96
+ --acp-badge-fg: #{token-utils.slot(badge-warning-fg, $fallbacks)};
97
+ }
98
+
99
+ &.acp-badge--danger {
100
+ --acp-badge-bg: #{token-utils.slot(badge-danger-bg, $fallbacks)};
101
+ --acp-badge-fg: #{token-utils.slot(badge-danger-fg, $fallbacks)};
102
+ }
103
+
104
+ &.acp-badge--info {
105
+ --acp-badge-bg: #{token-utils.slot(badge-info-bg, $fallbacks)};
106
+ --acp-badge-fg: #{token-utils.slot(badge-info-fg, $fallbacks)};
107
+ }
108
+
109
+ &.acp-badge--neutral {
110
+ --acp-badge-bg: #{token-utils.slot(badge-neutral-bg, $fallbacks)};
111
+ --acp-badge-fg: #{token-utils.slot(badge-neutral-color, $fallbacks)};
112
+ }
113
+
114
+ &.acp-badge--custom {
115
+ --acp-badge-bg: var(--acp-badge-custom-bg, #{token-utils.slot(badge-custom-bg, $fallbacks)});
116
+ --acp-badge-fg: var(--acp-badge-custom-fg, #{token-utils.slot(badge-custom-color, $fallbacks)});
117
+ }
118
+
119
+ // Variants - apply styles based on variant
120
+ &.acp-badge--filled &__chip.mat-mdc-chip {
121
+ @include mat.chips-overrides(
122
+ (
123
+ elevated-container-color: var(--acp-badge-bg),
124
+ elevated-selected-container-color: var(--acp-badge-bg),
125
+ label-text-color: var(--acp-badge-fg),
126
+ selected-label-text-color: var(--acp-badge-fg),
127
+ with-icon-icon-color: var(--acp-badge-fg),
128
+ with-icon-selected-icon-color: var(--acp-badge-fg),
129
+ with-trailing-icon-trailing-icon-color: var(--acp-badge-fg),
130
+ selected-trailing-icon-color: var(--acp-badge-fg),
131
+ outline-color: transparent,
132
+ )
133
+ );
134
+ }
135
+
136
+ &.acp-badge--outlined &__chip.mat-mdc-chip {
137
+ @include mat.chips-overrides(
138
+ (
139
+ elevated-container-color: transparent,
140
+ elevated-selected-container-color: transparent,
141
+ label-text-color: var(--acp-badge-bg),
142
+ selected-label-text-color: var(--acp-badge-bg),
143
+ with-icon-icon-color: var(--acp-badge-bg),
144
+ with-icon-selected-icon-color: var(--acp-badge-bg),
145
+ with-trailing-icon-trailing-icon-color: var(--acp-badge-bg),
146
+ selected-trailing-icon-color: var(--acp-badge-bg),
147
+ outline-color: var(--acp-badge-bg),
148
+ outline-width: 1px,
149
+ )
150
+ );
151
+ }
152
+
153
+ &.acp-badge--soft &__chip.mat-mdc-chip {
154
+ @include mat.chips-overrides(
155
+ (
156
+ elevated-container-color: color-mix(in srgb, var(--acp-badge-bg) 12%, transparent),
157
+ elevated-selected-container-color: color-mix(in srgb, var(--acp-badge-bg) 12%, transparent),
158
+ label-text-color: var(--acp-badge-bg),
159
+ selected-label-text-color: var(--acp-badge-bg),
160
+ with-icon-icon-color: var(--acp-badge-bg),
161
+ with-icon-selected-icon-color: var(--acp-badge-bg),
162
+ with-trailing-icon-trailing-icon-color: var(--acp-badge-bg),
163
+ selected-trailing-icon-color: var(--acp-badge-bg),
164
+ outline-color: transparent,
165
+ )
166
+ );
167
+ }
168
+
169
+ &.acp-badge--tonal &__chip.mat-mdc-chip {
170
+ @include mat.chips-overrides(
171
+ (
172
+ elevated-container-color: color-mix(in srgb, var(--acp-badge-bg) 22%, transparent),
173
+ elevated-selected-container-color: color-mix(in srgb, var(--acp-badge-bg) 22%, transparent),
174
+ label-text-color: var(--acp-badge-bg),
175
+ selected-label-text-color: var(--acp-badge-bg),
176
+ with-icon-icon-color: var(--acp-badge-bg),
177
+ with-icon-selected-icon-color: var(--acp-badge-bg),
178
+ with-trailing-icon-trailing-icon-color: var(--acp-badge-bg),
179
+ selected-trailing-icon-color: var(--acp-badge-bg),
180
+ outline-color: transparent,
181
+ )
182
+ );
183
+ }
184
+
185
+ &.acp-badge--text &__chip.mat-mdc-chip {
186
+ @include mat.chips-overrides(
187
+ (
188
+ elevated-container-color: transparent,
189
+ elevated-selected-container-color: transparent,
190
+ label-text-color: var(--acp-badge-bg),
191
+ selected-label-text-color: var(--acp-badge-bg),
192
+ with-icon-icon-color: var(--acp-badge-bg),
193
+ with-icon-selected-icon-color: var(--acp-badge-bg),
194
+ with-trailing-icon-trailing-icon-color: var(--acp-badge-bg),
195
+ selected-trailing-icon-color: var(--acp-badge-bg),
196
+ outline-color: transparent,
197
+ )
198
+ );
199
+ }
200
+
201
+ // Sizes
202
+ &.acp-badge--xs &__chip.mat-mdc-chip {
203
+ @include mat.chips-overrides(
204
+ (
205
+ container-height: 20px,
206
+ label-text-size: 10px,
207
+ )
208
+ );
209
+
210
+ .mat-icon {
211
+ --acp-badge-icon-size: 12px;
212
+ }
213
+ }
214
+
215
+ &.acp-badge--sm &__chip.mat-mdc-chip {
216
+ @include mat.chips-overrides(
217
+ (
218
+ container-height: 24px,
219
+ label-text-size: 11px,
220
+ )
221
+ );
222
+
223
+ .mat-icon {
224
+ --acp-badge-icon-size: 14px;
225
+ }
226
+ }
227
+
228
+ &.acp-badge--md &__chip.mat-mdc-chip {
229
+ @include mat.chips-overrides(
230
+ (
231
+ container-height: 28px,
232
+ label-text-size: 12px,
233
+ )
234
+ );
235
+
236
+ .mat-icon {
237
+ --acp-badge-icon-size: 16px;
238
+ }
239
+ }
240
+
241
+ &.acp-badge--lg &__chip.mat-mdc-chip {
242
+ @include mat.chips-overrides(
243
+ (
244
+ container-height: 32px,
245
+ label-text-size: 14px,
246
+ )
247
+ );
248
+
249
+ .mat-icon {
250
+ --acp-badge-icon-size: 18px;
251
+ }
252
+ }
253
+
254
+ // Shapes
255
+ &.acp-badge--rounded &__chip.mat-mdc-chip {
256
+ @include mat.chips-overrides(
257
+ (
258
+ container-shape-radius: #{token-utils.slot(badge-container-shape, $fallbacks)},
259
+ )
260
+ );
261
+ }
262
+
263
+ &.acp-badge--pill &__chip.mat-mdc-chip {
264
+ @include mat.chips-overrides(
265
+ (
266
+ container-shape-radius: #{token-utils.slot(badge-pill-shape, $fallbacks)},
267
+ )
268
+ );
269
+ }
270
+
271
+ &.acp-badge--square &__chip.mat-mdc-chip {
272
+ @include mat.chips-overrides(
273
+ (
274
+ container-shape-radius: 0,
275
+ )
276
+ );
277
+ }
278
+
279
+ // Icon sizing
280
+ &__chip.mat-mdc-chip .mat-icon {
281
+ width: var(--acp-badge-icon-size, 18px);
282
+ height: var(--acp-badge-icon-size, 18px);
283
+ font-size: var(--acp-badge-icon-size, 18px);
284
+ line-height: var(--acp-badge-icon-size, 18px);
285
+ }
286
+
287
+ // States
288
+ &.acp-badge--interactive &__chip.mat-mdc-chip {
289
+ cursor: pointer;
290
+ }
291
+
292
+ &.acp-badge--disabled &__chip.mat-mdc-chip {
293
+ cursor: not-allowed;
294
+ opacity: 0.5;
295
+ }
296
+
297
+ &.acp-badge--loading &__chip.mat-mdc-chip {
298
+ pointer-events: none;
299
+ }
300
+
301
+ &.acp-badge--selected &__chip.mat-mdc-chip.mdc-evolution-chip--selected,
302
+ &.acp-badge--selected &__chip.mat-mdc-chip.mat-mdc-chip-highlighted {
303
+ box-shadow: inset 0 0 0 2px currentColor;
304
+ }
305
+
306
+ @media (prefers-reduced-motion: reduce) {
307
+ &__loader::after {
308
+ animation: none;
309
+ }
310
+ }
311
+
312
+ @media (prefers-contrast: more) {
313
+ &__chip.mat-mdc-chip {
314
+ outline: 2px solid currentColor;
315
+ outline-offset: 1px;
316
+ }
317
+ }
318
+ }
@@ -0,0 +1,41 @@
1
+ @use 'sass:map';
2
+ @use '@angular/material' as mat;
3
+ @use '../../../core/tokens/token-utils';
4
+ @use './_m3-kpi-card' as m3-kpi-card;
5
+
6
+ @mixin color($colors) {
7
+ @include token-utils.batch-create-token-values(
8
+ $colors,
9
+ ((namespace: kpi-card, tokens: token-utils.get-overrides(m3-kpi-card.get-tokens(), kpi-card)))
10
+ );
11
+ }
12
+
13
+ @mixin typography($typography) {
14
+ // Typography handled by Material tokens
15
+ }
16
+
17
+ @mixin density($density) {
18
+ // Density handled by Material tokens
19
+ }
20
+
21
+ @mixin base($base) {
22
+ @include token-utils.batch-create-token-values(
23
+ $base,
24
+ ((namespace: kpi-card, tokens: token-utils.get-overrides(m3-kpi-card.get-tokens(), kpi-card)))
25
+ );
26
+ }
27
+
28
+ @mixin theme($theme) {
29
+ @include color(map.get(m3-kpi-card.get-tokens($theme), color));
30
+ @include typography(map.get(m3-kpi-card.get-tokens($theme), typography));
31
+ @include density(map.get(m3-kpi-card.get-tokens($theme), density));
32
+ @include base(map.get(m3-kpi-card.get-tokens($theme), base));
33
+ }
34
+
35
+ @function color-variants-backwards-compatibility($theme) {
36
+ @return ();
37
+ }
38
+
39
+ @function overrides($tokens: ()) {
40
+ @return $tokens;
41
+ }
@@ -0,0 +1,98 @@
1
+ @use 'sass:map';
2
+ @use '@angular/material' as mat;
3
+ @use '../../../core/tokens/m3-utils';
4
+ @use '../../../core/tokens/m3';
5
+
6
+ @function get-tokens($theme: m3.$sys-theme) {
7
+ $system: m3-utils.get-system($theme);
8
+
9
+ // Semantic color palettes for professional appearance
10
+ // Using more subtle tones for enterprise dashboard aesthetics
11
+ $semantic-palettes: (
12
+ success-light: mat.$green-palette,
13
+ warning-light: mat.$orange-palette,
14
+ error-light: mat.$red-palette,
15
+ info-light: mat.$azure-palette,
16
+ );
17
+
18
+ $color-tokens: ();
19
+ @each $name, $palette in $semantic-palettes {
20
+ $color-tokens: map.merge(
21
+ $color-tokens,
22
+ (
23
+ // Use on-surface for better contrast and professional appearance
24
+ kpi-card-#{$name}-color: map.get($system, on-surface),
25
+ // Use subtle background with semantic color accent (95 for light, 25 for dark)
26
+ kpi-card-#{$name}-bg: light-dark(map.get($palette, 95), map.get($palette, 25))
27
+ )
28
+ );
29
+ }
30
+
31
+ // Add success (bright) color using green palette
32
+ $success-palette: mat.$green-palette;
33
+ $color-tokens: map.merge(
34
+ $color-tokens,
35
+ (
36
+ // Use white text for bright success color for better contrast
37
+ kpi-card-success-color: light-dark(#ffffff, map.get($success-palette, 20)),
38
+ kpi-card-success-bg: light-dark(map.get($success-palette, 50), map.get($success-palette, 70))
39
+ )
40
+ );
41
+
42
+ // Add warning (bright) color - use Material Design warning/error color
43
+ // Material Design uses error color for warnings in some contexts, but we'll use orange palette
44
+ // to match Material button warning color
45
+ $warning-palette: mat.$orange-palette;
46
+ $color-tokens: map.merge(
47
+ $color-tokens,
48
+ (
49
+ // Use white text for bright warning color for better contrast
50
+ kpi-card-warning-color: light-dark(#ffffff, map.get($warning-palette, 20)),
51
+ // Use orange 60 for light mode (similar to Material button warning), 80 for dark mode
52
+ kpi-card-warning-bg: light-dark(map.get($warning-palette, 60), map.get($warning-palette, 80))
53
+ )
54
+ );
55
+
56
+ // Add info (bright) color using azure palette
57
+ $info-palette: mat.$azure-palette;
58
+ $color-tokens: map.merge(
59
+ $color-tokens,
60
+ (
61
+ // Use white text for bright info color for better contrast
62
+ kpi-card-info-color: light-dark(#ffffff, map.get($info-palette, 20)),
63
+ kpi-card-info-bg: light-dark(map.get($info-palette, 50), map.get($info-palette, 70))
64
+ )
65
+ );
66
+
67
+ $tokens: (
68
+ base: (
69
+ kpi-card-container-shape: map.get($system, corner-medium),
70
+ kpi-card-container-height: 200px,
71
+ kpi-card-container-elevation: 1,
72
+ ),
73
+ color: map.merge(
74
+ (
75
+ // Primary: Use primary theme color with on-primary text
76
+ kpi-card-primary-color: map.get($system, on-primary),
77
+ kpi-card-primary-bg: map.get($system, primary),
78
+ // Secondary: Use secondary theme color with on-secondary text
79
+ kpi-card-secondary-color: map.get($system, on-secondary),
80
+ kpi-card-secondary-bg: map.get($system, secondary),
81
+ // Error: Use error theme color with on-error text (Material Design 3 standard)
82
+ kpi-card-error-color: map.get($system, on-error),
83
+ kpi-card-error-bg: map.get($system, error),
84
+ // Neutral: Minimal styling for subtle cards
85
+ kpi-card-neutral-color: map.get($system, on-surface-variant),
86
+ kpi-card-neutral-bg: map.get($system, surface-variant),
87
+ // Custom: Allow full customization
88
+ kpi-card-custom-color: map.get($system, on-surface),
89
+ kpi-card-custom-bg: map.get($system, surface-container)
90
+ ),
91
+ $color-tokens
92
+ ),
93
+ typography: (),
94
+ density: (),
95
+ );
96
+
97
+ @return $tokens;
98
+ }