@attrus-ds/core 0.1.1 → 0.3.1

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 (82) hide show
  1. package/LICENSE +27 -27
  2. package/README.md +63 -9
  3. package/dist/assets/flags/Brazil-rounded.svg +15 -15
  4. package/dist/assets/flags/Brazil-square.svg +16 -16
  5. package/dist/assets/flags/Chile-rounded.svg +10 -10
  6. package/dist/assets/flags/Chile-square.svg +10 -10
  7. package/dist/assets/flags/Colombia-rounded.svg +9 -9
  8. package/dist/assets/flags/Colombia-square.svg +9 -9
  9. package/dist/assets/flags/EUA-rounded.svg +10 -10
  10. package/dist/assets/flags/EUA-square.svg +10 -10
  11. package/dist/assets/flags/EUR-rounded.svg +8 -8
  12. package/dist/assets/flags/EUR-square.svg +8 -8
  13. package/dist/assets/flags/Mexico-rounded.svg +18 -18
  14. package/dist/assets/flags/Mexico-square.svg +18 -18
  15. package/dist/assets/icon-attrus-dark.svg +2 -2
  16. package/dist/assets/icon-attrus-light.svg +2 -2
  17. package/dist/assets/logo-attrus-dark.svg +7 -7
  18. package/dist/assets/logo-attrus-light.svg +7 -7
  19. package/dist/css/components/buttons.css +301 -301
  20. package/dist/css/components/callout.css +195 -195
  21. package/dist/css/components/cards.css +272 -272
  22. package/dist/css/components/combobox.css +319 -303
  23. package/dist/css/components/empty-states.css +61 -61
  24. package/dist/css/components/inputs.css +975 -1027
  25. package/dist/css/components/number-input.css +138 -138
  26. package/dist/css/components/overlays.css +374 -405
  27. package/dist/css/components/primitives.css +314 -305
  28. package/dist/css/components/sidebar.css +179 -179
  29. package/dist/css/components/smart-search.css +91 -0
  30. package/dist/css/components/status-pills.css +207 -207
  31. package/dist/css/components/stepper.css +309 -309
  32. package/dist/css/components/table.css +602 -600
  33. package/dist/css/components/tabs.css +319 -319
  34. package/dist/css/components/toast.css +243 -239
  35. package/dist/css/components/tooltip.css +231 -226
  36. package/dist/css/components/topbar.css +148 -148
  37. package/dist/css/index.css +1 -0
  38. package/dist/css/tokens.css +666 -666
  39. package/dist/react/AppSidebar/AppSidebar.d.ts +50 -0
  40. package/dist/react/AppSidebar/AppSidebar.tsx +197 -0
  41. package/dist/react/AppTopbar/AppTopbar.d.ts +58 -0
  42. package/dist/react/AppTopbar/AppTopbar.tsx +203 -0
  43. package/dist/react/Atoms/Atoms.d.ts +149 -0
  44. package/dist/react/Atoms/Atoms.tsx +407 -0
  45. package/dist/react/Button/Button.d.ts +25 -0
  46. package/dist/react/Button/Button.tsx +83 -0
  47. package/dist/react/Callout/Callout.d.ts +29 -0
  48. package/dist/react/Callout/Callout.tsx +98 -0
  49. package/dist/react/Card/Card.d.ts +38 -0
  50. package/dist/react/Card/Card.tsx +93 -0
  51. package/dist/react/Combobox/Combobox.d.ts +52 -0
  52. package/dist/react/Combobox/Combobox.tsx +254 -0
  53. package/dist/react/DataTable/DataTable.d.ts +81 -0
  54. package/dist/react/DataTable/DataTable.tsx +308 -0
  55. package/dist/react/Drawer/Drawer.d.ts +35 -0
  56. package/dist/react/Drawer/Drawer.tsx +226 -0
  57. package/dist/react/Input/Input.d.ts +155 -0
  58. package/dist/react/Input/Input.tsx +478 -0
  59. package/dist/react/Modal/Modal.d.ts +27 -0
  60. package/dist/react/Modal/Modal.tsx +173 -0
  61. package/dist/react/NumberInput/NumberInput.d.ts +25 -0
  62. package/dist/react/NumberInput/NumberInput.tsx +117 -0
  63. package/dist/react/Pill/Pill.d.ts +31 -0
  64. package/dist/react/Pill/Pill.tsx +104 -0
  65. package/dist/react/SearchPill/SearchPill.d.ts +14 -0
  66. package/dist/react/SearchPill/SearchPill.tsx +40 -0
  67. package/dist/react/SmartSearch/SmartSearch.d.ts +65 -0
  68. package/dist/react/SmartSearch/SmartSearch.tsx +271 -0
  69. package/dist/react/Stepper/Stepper.d.ts +25 -0
  70. package/dist/react/Stepper/Stepper.tsx +94 -0
  71. package/dist/react/Tabs/Tabs.d.ts +32 -0
  72. package/dist/react/Tabs/Tabs.tsx +147 -0
  73. package/dist/react/Toast/Toast.d.ts +30 -0
  74. package/dist/react/Toast/Toast.tsx +94 -0
  75. package/dist/react/Tooltip/Tooltip.d.ts +23 -0
  76. package/dist/react/Tooltip/Tooltip.tsx +80 -0
  77. package/dist/react/ZeroState/ZeroState.d.ts +17 -0
  78. package/dist/react/ZeroState/ZeroState.tsx +45 -0
  79. package/dist/react/index.ts +35 -0
  80. package/dist/tokens/attrus-tokens.flat.json +1234 -1234
  81. package/dist/tokens/attrus-tokens.json +1089 -1089
  82. package/package.json +64 -54
@@ -1,272 +1,272 @@
1
- /* ================================================================
2
- CARDS — components/cards.css
3
- The container component. Defines surface, elevation, radius, padding.
4
- 100% token-driven; consumed by cards.html and any product UI.
5
- ================================================================ */
6
-
7
- /* ----------------------------------------------------------------
8
- Base — .card
9
- Default = surface + xs shadow + md radius + hairline border.
10
- ---------------------------------------------------------------- */
11
- .card {
12
- display: block;
13
- background: var(--color-background-surface);
14
- border: 1px solid var(--color-border-default);
15
- border-radius: var(--radius-md);
16
- box-shadow: var(--shadow-xs);
17
- color: var(--color-foreground-default);
18
- font-family: var(--font-sans);
19
- /* base padding kicks in only when the card holds direct content
20
- (no .card-header / .card-body subdivision) */
21
- padding: var(--space-5) var(--space-6);
22
- transition:
23
- box-shadow var(--transition-base),
24
- border-color var(--transition-base),
25
- transform var(--transition-base),
26
- background var(--transition-base);
27
- }
28
-
29
- /* If the card uses structured slots, drop the base padding —
30
- each slot brings its own. */
31
- .card:has(> .card-header),
32
- .card:has(> .card-body),
33
- .card:has(> .card-footer),
34
- .card:has(> .card-canvas),
35
- .card:has(> .card-divider) {
36
- padding: 0;
37
- }
38
-
39
-
40
- /* ----------------------------------------------------------------
41
- Surface variants — pick by "what role does this container play"
42
- ---------------------------------------------------------------- */
43
-
44
- /* Flat — no shadow. Use inside another card, or for table rows. */
45
- .card.flat { box-shadow: none; }
46
-
47
- /* Subtle / inset — neutral fill, no shadow. Use for nested groups. */
48
- .card.subtle { background: var(--color-background-subtle); box-shadow: none; }
49
-
50
- /* Sunken — like an input well; nested receipt/totals. */
51
- .card.sunken { background: var(--color-background-sunken); box-shadow: none; border-color: var(--color-border-subtle); }
52
-
53
- /* Raised — md shadow. Floating panels, popovers, dropdowns. */
54
- .card.raised { box-shadow: var(--shadow-md); }
55
-
56
- /* Floating — lg shadow. Modals, command palettes. */
57
- .card.floating { box-shadow: var(--shadow-lg); border: 0; }
58
-
59
- /* Hero — brand gradient. For dashboard summary tiles only. */
60
- .card.hero {
61
- background: var(--grad-hero);
62
- color: var(--color-foreground-on-solid);
63
- border: 0;
64
- position: relative;
65
- overflow: hidden;
66
- }
67
- .card.hero::before {
68
- content: "";
69
- position: absolute;
70
- inset: 0;
71
- background: var(--grad-radial-glow);
72
- pointer-events: none;
73
- }
74
- .card.hero > * { position: relative; z-index: 1; }
75
-
76
- /* Inverse — for cards on dark surfaces */
77
- .card.inverse {
78
- background: var(--color-background-inverse);
79
- color: var(--color-foreground-inverse-default);
80
- border-color: var(--color-border-inverse);
81
- box-shadow: none;
82
- }
83
-
84
-
85
- /* ----------------------------------------------------------------
86
- Semantic accents — banner-style cards with semantic shadow
87
- ---------------------------------------------------------------- */
88
- .card.accent-success {
89
- background: var(--color-feedback-success-background);
90
- border-color: var(--color-feedback-success-border);
91
- box-shadow: var(--shadow-success-sm);
92
- color: var(--color-foreground-default);
93
- }
94
- .card.accent-warning {
95
- background: var(--color-feedback-warning-background);
96
- border-color: var(--color-feedback-warning-border);
97
- box-shadow: var(--shadow-warning-sm);
98
- color: var(--color-foreground-default);
99
- }
100
- .card.accent-danger {
101
- background: var(--color-feedback-danger-background);
102
- border-color: var(--color-feedback-danger-border);
103
- box-shadow: var(--shadow-danger-sm);
104
- color: var(--color-foreground-default);
105
- }
106
- .card.accent-info {
107
- background: var(--color-feedback-info-background);
108
- border-color: var(--color-feedback-info-border);
109
- box-shadow: var(--shadow-info-sm);
110
- color: var(--color-foreground-default);
111
- }
112
-
113
-
114
- /* ----------------------------------------------------------------
115
- Density modifiers — affect both .card and slot padding
116
- ---------------------------------------------------------------- */
117
- .card.compact > .card-header,
118
- .card.compact > .card-body,
119
- .card.compact > .card-footer { padding: var(--space-3) var(--space-4); }
120
- .card.compact:not(:has(> .card-header)):not(:has(> .card-body)):not(:has(> .card-footer)):not(:has(> .card-canvas)):not(:has(> .card-divider)) {
121
- padding: var(--space-3) var(--space-4);
122
- }
123
-
124
- .card.spacious > .card-header,
125
- .card.spacious > .card-body,
126
- .card.spacious > .card-footer { padding: var(--space-7) var(--space-8); }
127
- .card.spacious:not(:has(> .card-header)):not(:has(> .card-body)):not(:has(> .card-footer)):not(:has(> .card-canvas)):not(:has(> .card-divider)) {
128
- padding: var(--space-7) var(--space-8);
129
- }
130
-
131
-
132
- /* ----------------------------------------------------------------
133
- Slots — header / body / footer / canvas / divider
134
- ---------------------------------------------------------------- */
135
- .card-header {
136
- padding: var(--space-5) var(--space-6);
137
- display: flex;
138
- align-items: flex-start;
139
- justify-content: space-between;
140
- gap: var(--space-4);
141
- border-bottom: 1px solid var(--color-border-subtle);
142
- }
143
- .card-header h3,
144
- .card-header h4 {
145
- margin: 0;
146
- font-size: var(--fs-md);
147
- font-weight: var(--w-semibold);
148
- letter-spacing: var(--ls-title);
149
- color: var(--color-foreground-default);
150
- }
151
- .card-header p {
152
- margin: var(--space-1) 0 0;
153
- font-size: var(--fs-sm);
154
- color: var(--color-foreground-secondary);
155
- line-height: var(--lh-relaxed);
156
- }
157
- .card-header .actions {
158
- display: flex;
159
- gap: var(--space-2);
160
- flex-shrink: 0;
161
- }
162
-
163
- .card-body {
164
- padding: var(--space-5) var(--space-6);
165
- }
166
-
167
- .card-footer {
168
- padding: var(--space-4) var(--space-6);
169
- border-top: 1px solid var(--color-border-subtle);
170
- background: var(--color-background-subtle);
171
- border-bottom-left-radius: inherit;
172
- border-bottom-right-radius: inherit;
173
- display: flex;
174
- align-items: center;
175
- justify-content: space-between;
176
- gap: var(--space-4);
177
- }
178
-
179
- /* Canvas slot — full-bleed image / chart area */
180
- .card-canvas {
181
- background: var(--color-background-canvas);
182
- border-bottom: 1px solid var(--color-border-subtle);
183
- overflow: hidden;
184
- border-top-left-radius: inherit;
185
- border-top-right-radius: inherit;
186
- }
187
-
188
- /* Divider — thin separator inside body sections */
189
- .card-divider {
190
- height: 1px;
191
- background: var(--color-border-subtle);
192
- margin: 0;
193
- border: 0;
194
- }
195
-
196
-
197
- /* ----------------------------------------------------------------
198
- Card layouts (helpers — common compositions)
199
- ---------------------------------------------------------------- */
200
-
201
- /* KPI / stat card */
202
- .card-stat {
203
- display: flex;
204
- flex-direction: column;
205
- gap: var(--space-2);
206
- }
207
- .card-stat .stat-label {
208
- font-family: var(--font-mono);
209
- font-size: var(--fs-xxs);
210
- font-weight: var(--w-semibold);
211
- color: var(--color-foreground-muted);
212
- text-transform: uppercase;
213
- letter-spacing: var(--ls-caps);
214
- }
215
- .card-stat .stat-value {
216
- font-family: var(--font-sans);
217
- font-weight: var(--w-bold);
218
- font-size: var(--fs-3xl);
219
- letter-spacing: var(--ls-display);
220
- font-variant-numeric: tabular-nums;
221
- color: var(--color-foreground-default);
222
- line-height: 1.1;
223
- }
224
- .card-stat .stat-delta {
225
- display: inline-flex;
226
- align-items: center;
227
- gap: var(--space-1);
228
- font-size: var(--fs-xs);
229
- font-weight: var(--w-semibold);
230
- font-variant-numeric: tabular-nums;
231
- }
232
- .card-stat .stat-delta.up { color: var(--color-feedback-success-foreground); }
233
- .card-stat .stat-delta.down { color: var(--color-feedback-danger-foreground); }
234
- .card-stat .stat-delta.flat { color: var(--color-foreground-muted); }
235
- .card-stat .stat-delta i, .card-stat .stat-delta svg,
236
- .card-stat .stat-delta svg { width: 12px; height: 12px; stroke-width: var(--icon-stroke); }
237
-
238
- /* Hero stat — for .card.hero */
239
- .card.hero .card-stat .stat-label { color: color-mix(in srgb, var(--color-pure-white) 70%, transparent); }
240
- .card.hero .card-stat .stat-value { color: var(--color-foreground-on-solid); font-size: var(--fs-5xl); }
241
-
242
-
243
- /* ----------------------------------------------------------------
244
- Interactive — link / button cards
245
- Apply .card.interactive to make the whole card clickable.
246
- The card itself should be wrapped in <a> or <button>.
247
- ---------------------------------------------------------------- */
248
- .card.interactive {
249
- cursor: pointer;
250
- text-decoration: none;
251
- color: inherit;
252
- }
253
- .card.interactive:hover {
254
- border-color: var(--color-border-strong);
255
- box-shadow: var(--shadow-sm);
256
- transform: translateY(-1px);
257
- }
258
- .card.interactive:active {
259
- transform: translateY(0);
260
- box-shadow: var(--shadow-xs);
261
- }
262
- .card.interactive:focus-visible {
263
- outline: none;
264
- box-shadow: var(--shadow-focus);
265
- border-color: var(--color-border-focus);
266
- }
267
-
268
- /* On inverse interactive */
269
- .card.inverse.interactive:hover {
270
- background: var(--color-background-inverse-hover);
271
- border-color: var(--color-border-inverse-strong);
272
- }
1
+ /* ================================================================
2
+ CARDS — components/cards.css
3
+ The container component. Defines surface, elevation, radius, padding.
4
+ 100% token-driven; consumed by cards.html and any product UI.
5
+ ================================================================ */
6
+
7
+ /* ----------------------------------------------------------------
8
+ Base — .card
9
+ Default = surface + xs shadow + md radius + hairline border.
10
+ ---------------------------------------------------------------- */
11
+ .card {
12
+ display: block;
13
+ background: var(--color-background-surface);
14
+ border: 1px solid var(--color-border-default);
15
+ border-radius: var(--radius-md);
16
+ box-shadow: var(--shadow-xs);
17
+ color: var(--color-foreground-default);
18
+ font-family: var(--font-sans);
19
+ /* base padding kicks in only when the card holds direct content
20
+ (no .card-header / .card-body subdivision) */
21
+ padding: var(--space-5) var(--space-6);
22
+ transition:
23
+ box-shadow var(--transition-base),
24
+ border-color var(--transition-base),
25
+ transform var(--transition-base),
26
+ background var(--transition-base);
27
+ }
28
+
29
+ /* If the card uses structured slots, drop the base padding —
30
+ each slot brings its own. */
31
+ .card:has(> .card-header),
32
+ .card:has(> .card-body),
33
+ .card:has(> .card-footer),
34
+ .card:has(> .card-canvas),
35
+ .card:has(> .card-divider) {
36
+ padding: 0;
37
+ }
38
+
39
+
40
+ /* ----------------------------------------------------------------
41
+ Surface variants — pick by "what role does this container play"
42
+ ---------------------------------------------------------------- */
43
+
44
+ /* Flat — no shadow. Use inside another card, or for table rows. */
45
+ .card.flat { box-shadow: none; }
46
+
47
+ /* Subtle / inset — neutral fill, no shadow. Use for nested groups. */
48
+ .card.subtle { background: var(--color-background-subtle); box-shadow: none; }
49
+
50
+ /* Sunken — like an input well; nested receipt/totals. */
51
+ .card.sunken { background: var(--color-background-sunken); box-shadow: none; border-color: var(--color-border-subtle); }
52
+
53
+ /* Raised — md shadow. Floating panels, popovers, dropdowns. */
54
+ .card.raised { box-shadow: var(--shadow-md); }
55
+
56
+ /* Floating — lg shadow. Modals, command palettes. */
57
+ .card.floating { box-shadow: var(--shadow-lg); border: 0; }
58
+
59
+ /* Hero — brand gradient. For dashboard summary tiles only. */
60
+ .card.hero {
61
+ background: var(--grad-hero);
62
+ color: var(--color-foreground-on-solid);
63
+ border: 0;
64
+ position: relative;
65
+ overflow: hidden;
66
+ }
67
+ .card.hero::before {
68
+ content: "";
69
+ position: absolute;
70
+ inset: 0;
71
+ background: var(--grad-radial-glow);
72
+ pointer-events: none;
73
+ }
74
+ .card.hero > * { position: relative; z-index: 1; }
75
+
76
+ /* Inverse — for cards on dark surfaces */
77
+ .card.inverse {
78
+ background: var(--color-background-inverse);
79
+ color: var(--color-foreground-inverse-default);
80
+ border-color: var(--color-border-inverse);
81
+ box-shadow: none;
82
+ }
83
+
84
+
85
+ /* ----------------------------------------------------------------
86
+ Semantic accents — banner-style cards with semantic shadow
87
+ ---------------------------------------------------------------- */
88
+ .card.accent-success {
89
+ background: var(--color-feedback-success-background);
90
+ border-color: var(--color-feedback-success-border);
91
+ box-shadow: var(--shadow-success-sm);
92
+ color: var(--color-foreground-default);
93
+ }
94
+ .card.accent-warning {
95
+ background: var(--color-feedback-warning-background);
96
+ border-color: var(--color-feedback-warning-border);
97
+ box-shadow: var(--shadow-warning-sm);
98
+ color: var(--color-foreground-default);
99
+ }
100
+ .card.accent-danger {
101
+ background: var(--color-feedback-danger-background);
102
+ border-color: var(--color-feedback-danger-border);
103
+ box-shadow: var(--shadow-danger-sm);
104
+ color: var(--color-foreground-default);
105
+ }
106
+ .card.accent-info {
107
+ background: var(--color-feedback-info-background);
108
+ border-color: var(--color-feedback-info-border);
109
+ box-shadow: var(--shadow-info-sm);
110
+ color: var(--color-foreground-default);
111
+ }
112
+
113
+
114
+ /* ----------------------------------------------------------------
115
+ Density modifiers — affect both .card and slot padding
116
+ ---------------------------------------------------------------- */
117
+ .card.compact > .card-header,
118
+ .card.compact > .card-body,
119
+ .card.compact > .card-footer { padding: var(--space-3) var(--space-4); }
120
+ .card.compact:not(:has(> .card-header)):not(:has(> .card-body)):not(:has(> .card-footer)):not(:has(> .card-canvas)):not(:has(> .card-divider)) {
121
+ padding: var(--space-3) var(--space-4);
122
+ }
123
+
124
+ .card.spacious > .card-header,
125
+ .card.spacious > .card-body,
126
+ .card.spacious > .card-footer { padding: var(--space-7) var(--space-8); }
127
+ .card.spacious:not(:has(> .card-header)):not(:has(> .card-body)):not(:has(> .card-footer)):not(:has(> .card-canvas)):not(:has(> .card-divider)) {
128
+ padding: var(--space-7) var(--space-8);
129
+ }
130
+
131
+
132
+ /* ----------------------------------------------------------------
133
+ Slots — header / body / footer / canvas / divider
134
+ ---------------------------------------------------------------- */
135
+ .card-header {
136
+ padding: var(--space-5) var(--space-6);
137
+ display: flex;
138
+ align-items: flex-start;
139
+ justify-content: space-between;
140
+ gap: var(--space-4);
141
+ border-bottom: 1px solid var(--color-border-subtle);
142
+ }
143
+ .card-header h3,
144
+ .card-header h4 {
145
+ margin: 0;
146
+ font-size: var(--fs-md);
147
+ font-weight: var(--w-semibold);
148
+ letter-spacing: var(--ls-title);
149
+ color: var(--color-foreground-default);
150
+ }
151
+ .card-header p {
152
+ margin: var(--space-1) 0 0;
153
+ font-size: var(--fs-sm);
154
+ color: var(--color-foreground-secondary);
155
+ line-height: var(--lh-relaxed);
156
+ }
157
+ .card-header .actions {
158
+ display: flex;
159
+ gap: var(--space-2);
160
+ flex-shrink: 0;
161
+ }
162
+
163
+ .card-body {
164
+ padding: var(--space-5) var(--space-6);
165
+ }
166
+
167
+ .card-footer {
168
+ padding: var(--space-4) var(--space-6);
169
+ border-top: 1px solid var(--color-border-subtle);
170
+ background: var(--color-background-subtle);
171
+ border-bottom-left-radius: inherit;
172
+ border-bottom-right-radius: inherit;
173
+ display: flex;
174
+ align-items: center;
175
+ justify-content: space-between;
176
+ gap: var(--space-4);
177
+ }
178
+
179
+ /* Canvas slot — full-bleed image / chart area */
180
+ .card-canvas {
181
+ background: var(--color-background-canvas);
182
+ border-bottom: 1px solid var(--color-border-subtle);
183
+ overflow: hidden;
184
+ border-top-left-radius: inherit;
185
+ border-top-right-radius: inherit;
186
+ }
187
+
188
+ /* Divider — thin separator inside body sections */
189
+ .card-divider {
190
+ height: 1px;
191
+ background: var(--color-border-subtle);
192
+ margin: 0;
193
+ border: 0;
194
+ }
195
+
196
+
197
+ /* ----------------------------------------------------------------
198
+ Card layouts (helpers — common compositions)
199
+ ---------------------------------------------------------------- */
200
+
201
+ /* KPI / stat card */
202
+ .card-stat {
203
+ display: flex;
204
+ flex-direction: column;
205
+ gap: var(--space-2);
206
+ }
207
+ .card-stat .stat-label {
208
+ font-family: var(--font-mono);
209
+ font-size: var(--fs-xxs);
210
+ font-weight: var(--w-semibold);
211
+ color: var(--color-foreground-muted);
212
+ text-transform: uppercase;
213
+ letter-spacing: var(--ls-caps);
214
+ }
215
+ .card-stat .stat-value {
216
+ font-family: var(--font-sans);
217
+ font-weight: var(--w-bold);
218
+ font-size: var(--fs-3xl);
219
+ letter-spacing: var(--ls-display);
220
+ font-variant-numeric: tabular-nums;
221
+ color: var(--color-foreground-default);
222
+ line-height: 1.1;
223
+ }
224
+ .card-stat .stat-delta {
225
+ display: inline-flex;
226
+ align-items: center;
227
+ gap: var(--space-1);
228
+ font-size: var(--fs-xs);
229
+ font-weight: var(--w-semibold);
230
+ font-variant-numeric: tabular-nums;
231
+ }
232
+ .card-stat .stat-delta.up { color: var(--color-feedback-success-foreground); }
233
+ .card-stat .stat-delta.down { color: var(--color-feedback-danger-foreground); }
234
+ .card-stat .stat-delta.flat { color: var(--color-foreground-muted); }
235
+ .card-stat .stat-delta i, .card-stat .stat-delta svg,
236
+ .card-stat .stat-delta svg { width: 12px; height: 12px; stroke-width: var(--icon-stroke); }
237
+
238
+ /* Hero stat — for .card.hero */
239
+ .card.hero .card-stat .stat-label { color: color-mix(in srgb, var(--color-pure-white) 70%, transparent); }
240
+ .card.hero .card-stat .stat-value { color: var(--color-foreground-on-solid); font-size: var(--fs-5xl); }
241
+
242
+
243
+ /* ----------------------------------------------------------------
244
+ Interactive — link / button cards
245
+ Apply .card.interactive to make the whole card clickable.
246
+ The card itself should be wrapped in <a> or <button>.
247
+ ---------------------------------------------------------------- */
248
+ .card.interactive {
249
+ cursor: pointer;
250
+ text-decoration: none;
251
+ color: inherit;
252
+ }
253
+ .card.interactive:hover {
254
+ border-color: var(--color-border-strong);
255
+ box-shadow: var(--shadow-sm);
256
+ transform: translateY(-1px);
257
+ }
258
+ .card.interactive:active {
259
+ transform: translateY(0);
260
+ box-shadow: var(--shadow-xs);
261
+ }
262
+ .card.interactive:focus-visible {
263
+ outline: none;
264
+ box-shadow: var(--shadow-focus);
265
+ border-color: var(--color-border-focus);
266
+ }
267
+
268
+ /* On inverse interactive */
269
+ .card.inverse.interactive:hover {
270
+ background: var(--color-background-inverse-hover);
271
+ border-color: var(--color-border-inverse-strong);
272
+ }