@acontplus/ng-components 3.2.1 → 4.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.
@@ -1,238 +1,244 @@
1
- @use '@angular/material' as mat;
1
+ @use 'sass:list';
2
+ @use 'sass:string';
2
3
  @use '../../../core/tokens/token-utils';
3
4
  @use './m3-kpi-card';
4
5
 
5
6
  $fallbacks: m3-kpi-card.get-tokens();
6
7
 
7
- .acp-kpi-card {
8
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-primary-bg, $fallbacks)};
9
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-primary-color, $fallbacks)};
8
+ @function tok($name) {
9
+ @return token-utils.slot(kpi-card-#{$name}, $fallbacks);
10
+ }
10
11
 
11
- display: flex;
12
- vertical-align: middle;
12
+ $colors: (
13
+ primary,
14
+ secondary,
15
+ success,
16
+ success-light,
17
+ warning,
18
+ warning-light,
19
+ error,
20
+ error-light,
21
+ info,
22
+ info-light,
23
+ neutral,
24
+ surface
25
+ );
26
+
27
+ // Size scale: padding, gap, icon, avatar, title, subtitle, value, meta
28
+ $sizes: (
29
+ xs: 8px 6px 16px 28px 12px 10px 18px 11px,
30
+ sm: 12px 8px 20px 32px 13px 11px 22px 12px,
31
+ md: 16px 12px 24px 40px 14px 12px 28px 13px,
32
+ lg: 20px 16px 32px 48px 16px 13px 36px 14px,
33
+ );
34
+
35
+ .acp-kpi-card {
36
+ // Public hooks: --acp-kpi-card-bg, --acp-kpi-card-fg, --acp-kpi-card-accent
37
+ // (the `custom` color reads --acp-kpi-card-custom-bg / -fg / -accent).
38
+ display: block;
13
39
  width: 100%;
14
- max-width: 100%;
40
+ container: acp-kpi-card / inline-size;
41
+
42
+ & &__card {
43
+ --acp-kpi-card-emphasis: var(--acp-kpi-card-fg);
44
+ --acp-kpi-card-muted: color-mix(in srgb, currentColor 72%, transparent);
15
45
 
16
- &__card {
17
- width: 100%;
18
46
  display: flex;
19
47
  flex-direction: column;
20
- border-radius: 12px;
21
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
48
+ width: 100%;
22
49
  overflow: hidden;
23
- background-color: #ffffff;
50
+ border-radius: #{tok(container-shape)};
51
+ border: 1px solid transparent;
52
+ background: var(--acp-kpi-card-bg);
53
+ color: var(--acp-kpi-card-fg);
54
+ transition:
55
+ box-shadow 200ms cubic-bezier(0.2, 0, 0, 1),
56
+ transform 200ms cubic-bezier(0.2, 0, 0, 1);
57
+ }
58
+
59
+ &__header .mat-mdc-card-header-text {
60
+ display: none;
24
61
  }
25
62
 
26
- // Default (md) sizes - baseline
27
- &__header {
63
+ & &__card &__header {
28
64
  display: flex;
29
65
  align-items: center;
30
66
  justify-content: space-between;
31
- padding: 16px;
32
- gap: 12px;
67
+ gap: var(--acp-kpi-card-gap);
68
+ padding: var(--acp-kpi-card-padding) var(--acp-kpi-card-padding) 0;
33
69
  }
34
70
 
35
71
  &__header-content {
36
72
  display: flex;
37
- align-items: center;
38
- gap: 12px;
39
73
  flex: 1;
74
+ align-items: center;
75
+ justify-content: var(--acp-kpi-card-justify);
76
+ gap: var(--acp-kpi-card-gap);
40
77
  min-width: 0;
41
78
  }
42
79
 
43
80
  &__icon-container {
44
81
  display: flex;
82
+ flex-shrink: 0;
45
83
  align-items: center;
46
84
  justify-content: center;
47
- flex-shrink: 0;
85
+ color: var(--acp-kpi-card-emphasis);
86
+
87
+ &:empty {
88
+ display: none;
89
+ }
48
90
  }
49
91
 
50
92
  &__icon {
51
- font-size: 24px;
52
- width: 24px;
53
- height: 24px;
54
- color: var(--acp-kpi-card-fg);
93
+ width: var(--acp-kpi-card-icon-size);
94
+ height: var(--acp-kpi-card-icon-size);
95
+ font-size: var(--acp-kpi-card-icon-size);
55
96
  }
56
97
 
57
- &__avatar {
58
- width: 40px;
59
- height: 40px;
60
- border-radius: 50%;
98
+ &__avatar,
99
+ &__avatar-image,
100
+ &__avatar-initials {
61
101
  display: flex;
102
+ flex-shrink: 0;
62
103
  align-items: center;
63
104
  justify-content: center;
64
- background: color-mix(in srgb, var(--acp-kpi-card-bg) 30%, transparent);
65
- color: var(--acp-kpi-card-fg);
105
+ width: var(--acp-kpi-card-avatar-size);
106
+ height: var(--acp-kpi-card-avatar-size);
107
+ border-radius: 50%;
108
+ font-size: var(--acp-kpi-card-meta-size);
66
109
  font-weight: 500;
67
- font-size: 14px;
68
- flex-shrink: 0;
69
110
  }
70
111
 
71
- &__avatar-image {
72
- width: 40px;
73
- height: 40px;
74
- border-radius: 50%;
75
- object-fit: cover;
76
- flex-shrink: 0;
112
+ &__avatar,
113
+ &__avatar-initials {
114
+ background: color-mix(in srgb, var(--acp-kpi-card-emphasis) 16%, transparent);
77
115
  }
78
116
 
79
- &__avatar-initials {
80
- width: 40px;
81
- height: 40px;
82
- border-radius: 50%;
83
- display: flex;
84
- align-items: center;
85
- justify-content: center;
86
- background: color-mix(in srgb, var(--acp-kpi-card-bg) 30%, transparent);
87
- color: var(--acp-kpi-card-fg);
88
- font-weight: 500;
89
- font-size: 14px;
90
- flex-shrink: 0;
117
+ &__avatar-image {
118
+ object-fit: cover;
91
119
  }
92
120
 
93
121
  &__title-container {
94
- flex: 1;
95
122
  min-width: 0;
96
123
  }
97
124
 
98
- &__title {
99
- margin: 0;
100
- font-size: 14px;
101
- font-weight: 500;
102
- letter-spacing: 0.25px;
103
- color: var(--acp-kpi-card-fg);
104
- white-space: nowrap;
125
+ &__title,
126
+ &__subtitle {
105
127
  overflow: hidden;
128
+ white-space: nowrap;
106
129
  text-overflow: ellipsis;
107
130
  }
108
131
 
132
+ &__title {
133
+ margin: 0;
134
+ font: var(--mat-sys-title-small);
135
+ font-size: var(--acp-kpi-card-title-size);
136
+ }
137
+
109
138
  &__subtitle {
110
- margin: 2px 0 0 0;
111
- font-size: 12px;
112
- font-weight: 400;
113
- letter-spacing: 0.4px;
114
- color: rgba(var(--acp-kpi-card-fg), 0.6);
115
- white-space: nowrap;
116
- overflow: hidden;
117
- text-overflow: ellipsis;
139
+ margin: 2px 0 0;
140
+ font: var(--mat-sys-body-small);
141
+ font-size: var(--acp-kpi-card-subtitle-size);
142
+ color: var(--acp-kpi-card-muted);
118
143
  }
119
144
 
120
145
  &__menu-button {
121
146
  flex-shrink: 0;
122
- opacity: 0.7;
123
- transition: opacity 0.2s ease-in-out;
124
-
125
- &:hover {
126
- opacity: 1;
127
- }
128
-
129
- &:focus-visible {
130
- outline: 2px solid currentColor;
131
- outline-offset: 2px;
132
- }
133
- }
134
-
135
- &__menu {
136
- will-change: transform;
147
+ color: inherit;
137
148
  }
138
149
 
139
- &__content {
140
- flex: 1;
141
- padding: 16px;
150
+ & &__card &__content {
142
151
  display: flex;
152
+ flex: 1;
143
153
  flex-direction: column;
144
- gap: 12px;
154
+ gap: var(--acp-kpi-card-gap);
155
+ padding: var(--acp-kpi-card-padding);
145
156
  }
146
157
 
147
158
  &__value-section {
148
159
  display: flex;
160
+ flex-wrap: wrap;
149
161
  align-items: baseline;
150
- gap: 8px;
162
+ justify-content: var(--acp-kpi-card-justify);
163
+ gap: 4px 8px;
151
164
  }
152
165
 
153
166
  &__value {
154
- font-size: 28px;
167
+ font-family: var(--mat-sys-headline-small-font);
168
+ font-size: min(var(--acp-kpi-card-value-size), 14cqi);
155
169
  font-weight: 600;
156
- letter-spacing: -0.5px;
157
- color: var(--acp-kpi-card-fg);
170
+ font-variant-numeric: tabular-nums;
158
171
  line-height: 1.2;
172
+ letter-spacing: -0.5px;
173
+ color: var(--acp-kpi-card-emphasis);
159
174
  }
160
175
 
161
- &__metric {
162
- display: flex;
163
- align-items: center;
164
- gap: 4px;
165
- font-size: 13px;
176
+ &__affix {
177
+ font-size: 0.6em;
166
178
  font-weight: 500;
167
- letter-spacing: 0.25px;
168
- color: rgba(var(--acp-kpi-card-fg), 0.8);
169
179
  }
170
180
 
171
- &__trend-icon {
172
- font-size: 16px;
173
- width: 16px;
174
- height: 16px;
175
- // Trend icon inherits color from parent metric element
176
- }
177
-
178
- &__percentage {
181
+ &__delta {
182
+ display: inline-flex;
183
+ align-items: center;
184
+ gap: 2px;
185
+ padding: 2px 8px;
186
+ border-radius: 999px;
187
+ font: var(--mat-sys-label-medium);
188
+ font-size: var(--acp-kpi-card-meta-size);
189
+ font-variant-numeric: tabular-nums;
179
190
  white-space: nowrap;
180
- }
181
191
 
182
- // Trend color styling - applied to metric section when trending
183
- &.acp-kpi-card--success &__metric {
184
- color: #{token-utils.slot(kpi-card-success-color, $fallbacks)};
185
- }
186
-
187
- &.acp-kpi-card--success-light &__metric {
188
- color: #{token-utils.slot(kpi-card-success-light-color, $fallbacks)};
189
- }
190
-
191
- &.acp-kpi-card--warning &__metric {
192
- color: #{token-utils.slot(kpi-card-warning-color, $fallbacks)};
193
- }
194
-
195
- &.acp-kpi-card--warning-light &__metric {
196
- color: #{token-utils.slot(kpi-card-warning-light-color, $fallbacks)};
197
- }
192
+ &--positive {
193
+ background: #{tok(delta-positive-bg)};
194
+ color: #{tok(delta-positive-color)};
195
+ }
198
196
 
199
- &.acp-kpi-card--error &__metric {
200
- color: #{token-utils.slot(kpi-card-error-color, $fallbacks)};
201
- }
197
+ &--negative {
198
+ background: #{tok(delta-negative-bg)};
199
+ color: #{tok(delta-negative-color)};
200
+ }
202
201
 
203
- &.acp-kpi-card--error-light &__metric {
204
- color: #{token-utils.slot(kpi-card-error-light-color, $fallbacks)};
202
+ &--neutral {
203
+ background: #{tok(delta-neutral-bg)};
204
+ color: #{tok(delta-neutral-color)};
205
+ }
205
206
  }
206
207
 
207
- &.acp-kpi-card--info &__metric {
208
- color: #{token-utils.slot(kpi-card-info-color, $fallbacks)};
208
+ &__trend-icon {
209
+ width: 16px;
210
+ height: 16px;
211
+ font-size: 16px;
209
212
  }
210
213
 
211
- &.acp-kpi-card--info-light &__metric {
212
- color: #{token-utils.slot(kpi-card-info-light-color, $fallbacks)};
214
+ &__trend-label {
215
+ font-size: var(--acp-kpi-card-meta-size);
216
+ color: var(--acp-kpi-card-muted);
213
217
  }
214
218
 
215
219
  &__description {
216
220
  margin: 0;
217
- font-size: 12px;
218
- font-weight: 400;
219
- letter-spacing: 0.4px;
220
- color: rgba(var(--acp-kpi-card-fg), 0.6);
221
- line-height: 1.5;
221
+ font: var(--mat-sys-body-small);
222
+ font-size: var(--acp-kpi-card-meta-size);
223
+ color: var(--acp-kpi-card-muted);
222
224
  }
223
225
 
224
226
  &__progress {
225
- height: 4px;
226
- border-radius: 2px;
227
- background-color: rgba(var(--acp-kpi-card-fg), 0.12);
227
+ --mat-progress-bar-active-indicator-color: var(--acp-kpi-card-emphasis);
228
+ --mat-progress-bar-track-color: color-mix(in srgb, currentColor 16%, transparent);
229
+ --mat-progress-bar-track-shape: 2px;
230
+
231
+ &[class*='acp-kpi-card__progress--'] {
232
+ --mat-progress-bar-active-indicator-color: var(--acp-kpi-card-accent);
233
+ }
228
234
  }
229
235
 
230
236
  &__footer {
231
- padding: 12px 16px;
232
- font-size: 12px;
233
- font-weight: 400;
234
- letter-spacing: 0.4px;
235
- color: rgba(var(--acp-kpi-card-fg), 0.6);
237
+ padding: calc(var(--acp-kpi-card-padding) * 0.75) var(--acp-kpi-card-padding);
238
+ border-top: 1px solid color-mix(in srgb, currentColor 12%, transparent);
239
+ font: var(--mat-sys-body-small);
240
+ font-size: var(--acp-kpi-card-meta-size);
241
+ color: var(--acp-kpi-card-muted);
236
242
  }
237
243
 
238
244
  &__footer-text {
@@ -240,226 +246,150 @@ $fallbacks: m3-kpi-card.get-tokens();
240
246
  }
241
247
 
242
248
  &__skeleton {
243
- padding: 16px;
244
249
  display: flex;
245
250
  flex-direction: column;
246
- gap: 12px;
247
- }
248
-
249
- &__skeleton-header {
250
- width: 60%;
251
- height: 16px;
252
- background: linear-gradient(
253
- 90deg,
254
- rgba(0, 0, 0, 0.1) 25%,
255
- rgba(0, 0, 0, 0.05) 50%,
256
- rgba(0, 0, 0, 0.1) 75%
257
- );
258
- background-size: 200% 100%;
259
- animation: loading 1.5s infinite;
260
- border-radius: 4px;
261
- }
262
-
263
- &__skeleton-value {
264
- width: 40%;
265
- height: 28px;
266
- background: linear-gradient(
267
- 90deg,
268
- rgba(0, 0, 0, 0.1) 25%,
269
- rgba(0, 0, 0, 0.05) 50%,
270
- rgba(0, 0, 0, 0.1) 75%
271
- );
272
- background-size: 200% 100%;
273
- animation: loading 1.5s infinite;
274
- border-radius: 4px;
275
- }
276
-
277
- &__skeleton-text {
278
- width: 80%;
279
- height: 12px;
280
- background: linear-gradient(
281
- 90deg,
282
- rgba(0, 0, 0, 0.1) 25%,
283
- rgba(0, 0, 0, 0.05) 50%,
284
- rgba(0, 0, 0, 0.1) 75%
285
- );
286
- background-size: 200% 100%;
287
- animation: loading 1.5s infinite;
288
- border-radius: 4px;
289
- }
290
-
291
- @keyframes loading {
292
- 0% {
293
- background-position: 200% 0;
251
+ gap: var(--acp-kpi-card-gap);
252
+ padding: var(--acp-kpi-card-padding);
253
+
254
+ > span {
255
+ display: block;
256
+ height: 12px;
257
+ border-radius: 4px;
258
+ background: linear-gradient(
259
+ 90deg,
260
+ color-mix(in srgb, currentColor 14%, transparent) 25%,
261
+ color-mix(in srgb, currentColor 6%, transparent) 50%,
262
+ color-mix(in srgb, currentColor 14%, transparent) 75%
263
+ );
264
+ background-size: 200% 100%;
265
+ animation: acp-kpi-card-shimmer 1.5s infinite;
294
266
  }
295
- 100% {
296
- background-position: -200% 0;
267
+
268
+ > span:nth-child(1) {
269
+ width: 60%;
270
+ height: 16px;
297
271
  }
298
- }
299
272
 
300
- // Colors
301
- &.acp-kpi-card--primary {
302
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-primary-bg, $fallbacks)};
303
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-primary-color, $fallbacks)};
304
- }
273
+ > span:nth-child(2) {
274
+ width: 40%;
275
+ height: var(--acp-kpi-card-value-size);
276
+ }
305
277
 
306
- &.acp-kpi-card--secondary {
307
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-secondary-bg, $fallbacks)};
308
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-secondary-color, $fallbacks)};
278
+ > span:nth-child(3) {
279
+ width: 80%;
280
+ }
309
281
  }
310
282
 
311
- &.acp-kpi-card--success {
312
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-success-bg, $fallbacks)};
313
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-success-color, $fallbacks)};
283
+ // Sizes
284
+ @each $size, $v in $sizes {
285
+ &--#{$size} {
286
+ --acp-kpi-card-padding: #{list.nth($v, 1)};
287
+ --acp-kpi-card-gap: #{list.nth($v, 2)};
288
+ --acp-kpi-card-icon-size: #{list.nth($v, 3)};
289
+ --acp-kpi-card-avatar-size: #{list.nth($v, 4)};
290
+ --acp-kpi-card-title-size: #{list.nth($v, 5)};
291
+ --acp-kpi-card-subtitle-size: #{list.nth($v, 6)};
292
+ --acp-kpi-card-value-size: #{list.nth($v, 7)};
293
+ --acp-kpi-card-meta-size: #{list.nth($v, 8)};
294
+ }
314
295
  }
315
296
 
316
- &.acp-kpi-card--success-light {
317
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-success-light-bg, $fallbacks)};
318
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-success-light-color, $fallbacks)};
297
+ // Alignment
298
+ &--align-start {
299
+ --acp-kpi-card-justify: flex-start;
319
300
  }
320
301
 
321
- &.acp-kpi-card--warning {
322
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-warning-bg, $fallbacks)};
323
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-warning-color, $fallbacks)};
324
- }
302
+ &--align-center {
303
+ --acp-kpi-card-justify: center;
325
304
 
326
- &.acp-kpi-card--warning-light {
327
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-warning-light-bg, $fallbacks)};
328
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-warning-light-color, $fallbacks)};
305
+ text-align: center;
329
306
  }
330
307
 
331
- &.acp-kpi-card--error {
332
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-error-bg, $fallbacks)};
333
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-error-color, $fallbacks)};
334
- }
308
+ &--align-end {
309
+ --acp-kpi-card-justify: flex-end;
335
310
 
336
- &.acp-kpi-card--error-light {
337
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-error-light-bg, $fallbacks)};
338
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-error-light-color, $fallbacks)};
311
+ text-align: end;
339
312
  }
340
313
 
341
- &.acp-kpi-card--info {
342
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-info-bg, $fallbacks)};
343
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-info-color, $fallbacks)};
344
- }
314
+ // Colors
315
+ @each $color in $colors {
316
+ $base: $color;
317
+ @if string.index($color, '-light') {
318
+ $base: string.slice($color, 1, -7);
319
+ }
345
320
 
346
- &.acp-kpi-card--info-light {
347
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-info-light-bg, $fallbacks)};
348
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-info-light-color, $fallbacks)};
321
+ &--#{$color},
322
+ &__progress--#{$color} {
323
+ --acp-kpi-card-bg: #{tok(#{$color}-bg)};
324
+ --acp-kpi-card-fg: #{tok(#{$color}-color)};
325
+ --acp-kpi-card-accent: #{tok(#{$base}-accent)};
326
+ }
349
327
  }
350
328
 
351
- &.acp-kpi-card--neutral {
352
- --acp-kpi-card-bg: #{token-utils.slot(kpi-card-neutral-bg, $fallbacks)};
353
- --acp-kpi-card-fg: #{token-utils.slot(kpi-card-neutral-color, $fallbacks)};
329
+ &--custom {
330
+ --acp-kpi-card-bg: var(--acp-kpi-card-custom-bg, #{tok(custom-bg)});
331
+ --acp-kpi-card-fg: var(--acp-kpi-card-custom-fg, #{tok(custom-color)});
332
+ --acp-kpi-card-accent: var(--acp-kpi-card-custom-accent, #{tok(custom-accent)});
354
333
  }
355
334
 
356
- &.acp-kpi-card--white {
357
- --acp-kpi-card-bg: #ffffff;
358
- --acp-kpi-card-fg: #1f2937;
335
+ // Variants: default/elevated/filled use the solid container; outlined/tonal sit on a surface
336
+ &--default &__card {
337
+ box-shadow: var(--mat-sys-level1);
359
338
  }
360
339
 
361
- &.acp-kpi-card--custom {
362
- --acp-kpi-card-bg: var(
363
- --acp-kpi-card-custom-bg,
364
- #{token-utils.slot(kpi-card-custom-bg, $fallbacks)}
365
- );
366
- --acp-kpi-card-fg: var(
367
- --acp-kpi-card-custom-fg,
368
- #{token-utils.slot(kpi-card-custom-color, $fallbacks)}
369
- );
340
+ &--elevated &__card {
341
+ box-shadow: var(--mat-sys-level2);
370
342
  }
371
343
 
372
- // Variants - Professional Material Design 3 styling
373
- &.acp-kpi-card--default &__card {
374
- background: var(--acp-kpi-card-bg);
375
- color: var(--acp-kpi-card-fg);
376
- border: 1px solid rgba(var(--acp-kpi-card-fg), 0.12);
344
+ &--filled &__card {
345
+ box-shadow: none;
377
346
  }
378
347
 
379
- &.acp-kpi-card--elevated &__card {
380
- background: var(--acp-kpi-card-bg);
381
- color: var(--acp-kpi-card-fg);
382
- box-shadow:
383
- 0 3px 8px rgba(0, 0, 0, 0.08),
384
- 0 1px 3px rgba(0, 0, 0, 0.04);
385
- }
348
+ &--outlined &__card,
349
+ &--tonal &__card {
350
+ --acp-kpi-card-emphasis: var(--acp-kpi-card-accent);
386
351
 
387
- &.acp-kpi-card--outlined &__card {
388
- background: transparent;
389
- color: var(--acp-kpi-card-fg);
390
- border: 2px solid rgba(var(--acp-kpi-card-fg), 0.2);
352
+ box-shadow: none;
353
+ color: var(--mat-sys-on-surface);
391
354
  }
392
355
 
393
- &.acp-kpi-card--filled &__card {
394
- background: var(--acp-kpi-card-bg);
395
- color: var(--acp-kpi-card-fg);
356
+ &--outlined &__card {
357
+ background: var(--mat-sys-surface);
358
+ border-color: color-mix(in srgb, var(--acp-kpi-card-accent) 40%, transparent);
396
359
  }
397
360
 
398
- &.acp-kpi-card--tonal &__card {
399
- // Subtle tonal background using color-mix for better theme support
400
- background: color-mix(in srgb, var(--acp-kpi-card-bg) 12%, transparent);
401
- color: var(--acp-kpi-card-fg);
402
- border: 1px solid rgba(var(--acp-kpi-card-fg), 0.08);
361
+ &--tonal &__card {
362
+ background: color-mix(in srgb, var(--acp-kpi-card-accent) 12%, var(--mat-sys-surface));
403
363
  }
404
364
 
405
- // States - Professional interaction patterns
406
- &.acp-kpi-card--clickable &__card {
365
+ // States
366
+ &--clickable &__card {
407
367
  cursor: pointer;
408
368
 
409
369
  &:hover {
410
- // Subtle elevation increase on hover
411
- box-shadow:
412
- 0 6px 12px rgba(0, 0, 0, 0.1),
413
- 0 2px 4px rgba(0, 0, 0, 0.06);
414
- // Minimal vertical translation for feedback
370
+ box-shadow: var(--mat-sys-level3);
415
371
  transform: translateY(-1px);
416
372
  }
417
373
 
418
374
  &:active {
419
- // Slight press-down effect
420
- transform: translateY(0);
421
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
422
- }
423
-
424
- &:focus-visible {
425
- outline: 2px solid currentColor;
426
- outline-offset: 2px;
375
+ box-shadow: var(--mat-sys-level1);
376
+ transform: none;
427
377
  }
428
378
  }
429
379
 
430
- &.acp-kpi-card--disabled &__card {
431
- opacity: 0.6;
432
- cursor: not-allowed;
433
- pointer-events: none;
380
+ &__card:focus-visible {
381
+ outline: 2px solid var(--mat-sys-primary);
382
+ outline-offset: 2px;
434
383
  }
435
384
 
436
- &.acp-kpi-card--selected &__card {
437
- // Subtle selection indicator using border instead of inset shadow
438
- border: 2px solid var(--acp-kpi-card-fg);
385
+ &--selected &__card {
386
+ border-color: var(--acp-kpi-card-emphasis);
387
+ box-shadow: inset 0 0 0 1px var(--acp-kpi-card-emphasis);
439
388
  }
440
389
 
441
- &.acp-kpi-card--loading &__card {
390
+ &--disabled &__card {
391
+ opacity: 0.6;
442
392
  pointer-events: none;
443
- opacity: 0.8;
444
- }
445
-
446
- // Responsive
447
- @media (max-width: 768px) {
448
- &__header {
449
- padding: 12px;
450
- }
451
-
452
- &__content {
453
- padding: 12px;
454
- }
455
-
456
- &__value {
457
- font-size: 24px;
458
- }
459
-
460
- &__title {
461
- font-size: 13px;
462
- }
463
393
  }
464
394
 
465
395
  @media (prefers-reduced-motion: reduce) {
@@ -467,275 +397,22 @@ $fallbacks: m3-kpi-card.get-tokens();
467
397
  transition: none;
468
398
  }
469
399
 
470
- &__skeleton-header,
471
- &__skeleton-value,
472
- &__skeleton-text {
473
- animation: none;
400
+ &--clickable &__card:hover {
401
+ transform: none;
474
402
  }
475
- }
476
403
 
477
- @media (prefers-contrast: more) {
478
- &__card {
479
- border-width: 2px;
480
- }
481
- }
482
- }
483
-
484
- // Responsive scaling - Mobile first
485
- @media (max-width: 768px) {
486
- .acp-kpi-card {
487
- &__header {
488
- padding: 12px;
489
- gap: 8px;
490
- }
491
-
492
- &__content {
493
- padding: 12px;
494
- gap: 8px;
495
- }
496
-
497
- &__footer {
498
- padding: 12px;
499
- }
500
-
501
- &__icon {
502
- font-size: 20px;
503
- width: 20px;
504
- height: 20px;
505
- }
506
-
507
- &__avatar,
508
- &__avatar-image,
509
- &__avatar-initials {
510
- width: 32px;
511
- height: 32px;
512
- font-size: 12px;
513
- }
514
-
515
- &__title {
516
- font-size: 13px;
517
- }
518
-
519
- &__subtitle {
520
- font-size: 11px;
521
- }
522
-
523
- &__value {
524
- font-size: 24px;
404
+ &__skeleton > span {
405
+ animation: none;
525
406
  }
526
407
  }
527
408
  }
528
409
 
529
- // Size variants with harmonic scaling
530
- // xs: Very compact (tables, lists)
531
- .acp-kpi-card__card.acp-kpi-card--xs {
532
- min-height: 96px;
533
-
534
- .acp-kpi-card__header {
535
- padding: 8px;
536
- gap: 6px;
537
- }
538
-
539
- .acp-kpi-card__content {
540
- padding: 8px;
541
- gap: 6px;
542
- }
543
-
544
- .acp-kpi-card__footer {
545
- padding: 8px;
546
- }
547
-
548
- .acp-kpi-card__icon {
549
- font-size: 16px;
550
- width: 16px;
551
- height: 16px;
552
- }
553
-
554
- .acp-kpi-card__avatar,
555
- .acp-kpi-card__avatar-image,
556
- .acp-kpi-card__avatar-initials {
557
- width: 28px;
558
- height: 28px;
559
- font-size: 11px;
560
- }
561
-
562
- .acp-kpi-card__title {
563
- font-size: 12px;
564
- }
565
-
566
- .acp-kpi-card__subtitle {
567
- font-size: 10px;
568
- margin-top: 1px;
569
- }
570
-
571
- .acp-kpi-card__value {
572
- font-size: 18px;
573
- }
574
-
575
- .acp-kpi-card__percentage {
576
- font-size: 10px;
577
- }
578
-
579
- .acp-kpi-card__description {
580
- font-size: 11px;
581
- }
582
- }
583
-
584
- // sm: Compact (forms, filters)
585
- .acp-kpi-card__card.acp-kpi-card--sm {
586
- min-height: 128px;
587
-
588
- .acp-kpi-card__header {
589
- padding: 12px;
590
- gap: 8px;
591
- }
592
-
593
- .acp-kpi-card__content {
594
- padding: 12px;
595
- gap: 8px;
596
- }
597
-
598
- .acp-kpi-card__footer {
599
- padding: 12px;
600
- }
601
-
602
- .acp-kpi-card__icon {
603
- font-size: 20px;
604
- width: 20px;
605
- height: 20px;
606
- }
607
-
608
- .acp-kpi-card__avatar,
609
- .acp-kpi-card__avatar-image,
610
- .acp-kpi-card__avatar-initials {
611
- width: 32px;
612
- height: 32px;
613
- font-size: 12px;
614
- }
615
-
616
- .acp-kpi-card__title {
617
- font-size: 13px;
618
- }
619
-
620
- .acp-kpi-card__subtitle {
621
- font-size: 11px;
622
- }
623
-
624
- .acp-kpi-card__value {
625
- font-size: 22px;
626
- }
627
-
628
- .acp-kpi-card__percentage {
629
- font-size: 11px;
630
- }
631
-
632
- .acp-kpi-card__description {
633
- font-size: 12px;
634
- }
635
- }
636
-
637
- // md: Standard (general use) - DEFAULT
638
- .acp-kpi-card__card.acp-kpi-card--md {
639
- min-height: 160px;
640
-
641
- .acp-kpi-card__header {
642
- padding: 16px;
643
- gap: 12px;
644
- }
645
-
646
- .acp-kpi-card__content {
647
- padding: 16px;
648
- gap: 12px;
649
- }
650
-
651
- .acp-kpi-card__footer {
652
- padding: 16px;
653
- }
654
-
655
- .acp-kpi-card__icon {
656
- font-size: 24px;
657
- width: 24px;
658
- height: 24px;
659
- }
660
-
661
- .acp-kpi-card__avatar,
662
- .acp-kpi-card__avatar-image,
663
- .acp-kpi-card__avatar-initials {
664
- width: 40px;
665
- height: 40px;
666
- font-size: 14px;
667
- }
668
-
669
- .acp-kpi-card__title {
670
- font-size: 14px;
671
- }
672
-
673
- .acp-kpi-card__subtitle {
674
- font-size: 12px;
675
- }
676
-
677
- .acp-kpi-card__value {
678
- font-size: 28px;
679
- }
680
-
681
- .acp-kpi-card__percentage {
682
- font-size: 12px;
683
- }
684
-
685
- .acp-kpi-card__description {
686
- font-size: 13px;
687
- }
688
- }
689
-
690
- // lg: Large (dashboards, featured)
691
- .acp-kpi-card__card.acp-kpi-card--lg {
692
- min-height: 224px;
693
-
694
- .acp-kpi-card__header {
695
- padding: 20px;
696
- gap: 16px;
697
- }
698
-
699
- .acp-kpi-card__content {
700
- padding: 20px;
701
- gap: 16px;
702
- }
703
-
704
- .acp-kpi-card__footer {
705
- padding: 20px;
706
- }
707
-
708
- .acp-kpi-card__icon {
709
- font-size: 32px;
710
- width: 32px;
711
- height: 32px;
712
- }
713
-
714
- .acp-kpi-card__avatar,
715
- .acp-kpi-card__avatar-image,
716
- .acp-kpi-card__avatar-initials {
717
- width: 48px;
718
- height: 48px;
719
- font-size: 16px;
720
- }
721
-
722
- .acp-kpi-card__title {
723
- font-size: 16px;
724
- }
725
-
726
- .acp-kpi-card__subtitle {
727
- font-size: 13px;
728
- }
729
-
730
- .acp-kpi-card__value {
731
- font-size: 36px;
732
- }
733
-
734
- .acp-kpi-card__percentage {
735
- font-size: 14px;
410
+ @keyframes acp-kpi-card-shimmer {
411
+ from {
412
+ background-position: 200% 0;
736
413
  }
737
414
 
738
- .acp-kpi-card__description {
739
- font-size: 14px;
415
+ to {
416
+ background-position: -200% 0;
740
417
  }
741
418
  }