@attrus-ds/core 0.2.0 → 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 (80) hide show
  1. package/LICENSE +27 -27
  2. package/dist/assets/flags/Brazil-rounded.svg +15 -15
  3. package/dist/assets/flags/Brazil-square.svg +16 -16
  4. package/dist/assets/flags/Chile-rounded.svg +10 -10
  5. package/dist/assets/flags/Chile-square.svg +10 -10
  6. package/dist/assets/flags/Colombia-rounded.svg +9 -9
  7. package/dist/assets/flags/Colombia-square.svg +9 -9
  8. package/dist/assets/flags/EUA-rounded.svg +10 -10
  9. package/dist/assets/flags/EUA-square.svg +10 -10
  10. package/dist/assets/flags/EUR-rounded.svg +8 -8
  11. package/dist/assets/flags/EUR-square.svg +8 -8
  12. package/dist/assets/flags/Mexico-rounded.svg +18 -18
  13. package/dist/assets/flags/Mexico-square.svg +18 -18
  14. package/dist/assets/icon-attrus-dark.svg +2 -2
  15. package/dist/assets/icon-attrus-light.svg +2 -2
  16. package/dist/assets/logo-attrus-dark.svg +7 -7
  17. package/dist/assets/logo-attrus-light.svg +7 -7
  18. package/dist/css/components/buttons.css +301 -301
  19. package/dist/css/components/callout.css +195 -195
  20. package/dist/css/components/cards.css +272 -272
  21. package/dist/css/components/combobox.css +319 -319
  22. package/dist/css/components/empty-states.css +61 -61
  23. package/dist/css/components/inputs.css +975 -975
  24. package/dist/css/components/number-input.css +138 -138
  25. package/dist/css/components/overlays.css +374 -374
  26. package/dist/css/components/primitives.css +314 -314
  27. package/dist/css/components/sidebar.css +179 -179
  28. package/dist/css/components/smart-search.css +91 -91
  29. package/dist/css/components/status-pills.css +207 -207
  30. package/dist/css/components/stepper.css +309 -309
  31. package/dist/css/components/table.css +602 -602
  32. package/dist/css/components/tabs.css +319 -319
  33. package/dist/css/components/toast.css +243 -243
  34. package/dist/css/components/tooltip.css +231 -231
  35. package/dist/css/components/topbar.css +148 -148
  36. package/dist/css/tokens.css +666 -666
  37. package/dist/react/AppSidebar/AppSidebar.d.ts +50 -50
  38. package/dist/react/AppSidebar/AppSidebar.tsx +197 -197
  39. package/dist/react/AppTopbar/AppTopbar.d.ts +58 -58
  40. package/dist/react/AppTopbar/AppTopbar.tsx +203 -203
  41. package/dist/react/Atoms/Atoms.d.ts +149 -149
  42. package/dist/react/Atoms/Atoms.tsx +407 -407
  43. package/dist/react/Button/Button.d.ts +25 -25
  44. package/dist/react/Button/Button.tsx +83 -83
  45. package/dist/react/Callout/Callout.d.ts +29 -29
  46. package/dist/react/Callout/Callout.tsx +98 -98
  47. package/dist/react/Card/Card.d.ts +38 -38
  48. package/dist/react/Card/Card.tsx +93 -93
  49. package/dist/react/Combobox/Combobox.d.ts +52 -52
  50. package/dist/react/Combobox/Combobox.tsx +254 -254
  51. package/dist/react/DataTable/DataTable.d.ts +81 -81
  52. package/dist/react/DataTable/DataTable.tsx +308 -308
  53. package/dist/react/Drawer/Drawer.d.ts +35 -35
  54. package/dist/react/Drawer/Drawer.tsx +226 -226
  55. package/dist/react/Input/Input.d.ts +155 -155
  56. package/dist/react/Input/Input.tsx +478 -478
  57. package/dist/react/Modal/Modal.d.ts +27 -27
  58. package/dist/react/Modal/Modal.tsx +173 -173
  59. package/dist/react/NumberInput/NumberInput.d.ts +25 -25
  60. package/dist/react/NumberInput/NumberInput.tsx +117 -117
  61. package/dist/react/Pill/Pill.d.ts +31 -31
  62. package/dist/react/Pill/Pill.tsx +104 -104
  63. package/dist/react/SearchPill/SearchPill.d.ts +14 -14
  64. package/dist/react/SearchPill/SearchPill.tsx +40 -40
  65. package/dist/react/SmartSearch/SmartSearch.d.ts +65 -65
  66. package/dist/react/SmartSearch/SmartSearch.tsx +271 -271
  67. package/dist/react/Stepper/Stepper.d.ts +25 -25
  68. package/dist/react/Stepper/Stepper.tsx +94 -94
  69. package/dist/react/Tabs/Tabs.d.ts +32 -32
  70. package/dist/react/Tabs/Tabs.tsx +147 -147
  71. package/dist/react/Toast/Toast.d.ts +30 -30
  72. package/dist/react/Toast/Toast.tsx +94 -94
  73. package/dist/react/Tooltip/Tooltip.d.ts +23 -23
  74. package/dist/react/Tooltip/Tooltip.tsx +80 -80
  75. package/dist/react/ZeroState/ZeroState.d.ts +17 -17
  76. package/dist/react/ZeroState/ZeroState.tsx +45 -45
  77. package/dist/react/index.ts +35 -35
  78. package/dist/tokens/attrus-tokens.flat.json +1234 -1234
  79. package/dist/tokens/attrus-tokens.json +1089 -1089
  80. package/package.json +64 -64
@@ -1,314 +1,314 @@
1
- /* ============================================================
2
- PRIMITIVES — Avatar · Money · Stat · Divider · Pill
3
- Atoms used across every product surface. All values from tokens.
4
- (Tabs moved to components/tabs.css — it's a stateful nav component.)
5
- ============================================================ */
6
-
7
- /* =================== AVATAR =================== */
8
- .av {
9
- display: inline-flex;
10
- align-items: center;
11
- justify-content: center;
12
- flex-shrink: 0;
13
- width: var(--av-size, 36px);
14
- height: var(--av-size, 36px);
15
- border-radius: var(--radius-pill);
16
- font-family: var(--font-mono);
17
- font-size: var(--av-fs, var(--fs-xs));
18
- font-weight: var(--w-bold);
19
- letter-spacing: var(--ls-caps);
20
- text-transform: uppercase;
21
- user-select: none;
22
- overflow: hidden;
23
- position: relative;
24
- }
25
- .av img { width: 100%; height: 100%; object-fit: cover; display: block; }
26
-
27
- .av-xs { --av-size: 20px; --av-fs: 9px; }
28
- .av-sm { --av-size: 28px; --av-fs: var(--fs-xxs); }
29
- .av-md { --av-size: 36px; --av-fs: var(--fs-xs); }
30
- .av-lg { --av-size: 48px; --av-fs: var(--fs-sm); }
31
- .av-xl { --av-size: 64px; --av-fs: var(--fs-md); }
32
-
33
- /* Tone — accent-on-tinted-bg uses the same background+foreground pair as feedback pills,
34
- so an Avatar reads as the same "object" as a status pill that references it. */
35
- .av-brand { background: var(--color-brand-secondary-50); color: var(--color-brand-secondary-700); }
36
- .av-success { background: var(--color-feedback-success-background); color: var(--color-feedback-success-foreground); }
37
- .av-warning { background: var(--color-feedback-warning-background); color: var(--color-feedback-warning-foreground); }
38
- .av-danger { background: var(--color-feedback-danger-background); color: var(--color-feedback-danger-foreground); }
39
- .av-info { background: var(--color-feedback-info-background); color: var(--color-feedback-info-foreground); }
40
- .av-neutral { background: var(--color-background-subtle); color: var(--color-foreground-muted); }
41
-
42
- /* Status dot — overlay for presence/online state */
43
- .av-dot {
44
- position: absolute;
45
- bottom: 0;
46
- right: 0;
47
- width: 30%;
48
- height: 30%;
49
- min-width: 8px;
50
- min-height: 8px;
51
- border-radius: var(--radius-pill);
52
- background: var(--color-success-500);
53
- box-shadow: 0 0 0 2px var(--color-background-surface);
54
- }
55
- .av-dot-busy { background: var(--color-feedback-danger-foreground); }
56
- .av-dot-away { background: var(--color-feedback-warning-foreground); }
57
- .av-dot-off { background: var(--color-foreground-muted); }
58
-
59
- /* Avatar group — overlapping stack */
60
- .av-group {
61
- display: inline-flex;
62
- align-items: center;
63
- isolation: isolate;
64
- }
65
- .av-group .av {
66
- margin-left: -8px;
67
- border: 2px solid var(--color-background-surface);
68
- }
69
- .av-group .av:first-child { margin-left: 0; }
70
- .av-group .av-more {
71
- background: var(--color-background-surface);
72
- color: var(--color-foreground-secondary);
73
- border: 1px dashed var(--color-border-default);
74
- }
75
-
76
- /* =================== MONEY =================== */
77
- .money {
78
- display: inline-flex;
79
- align-items: baseline;
80
- gap: var(--space-1);
81
- font-family: var(--font-mono);
82
- font-variant-numeric: tabular-nums;
83
- font-size: var(--money-fs, var(--fs-sm));
84
- font-weight: var(--w-semibold);
85
- color: var(--color-foreground-default);
86
- white-space: nowrap;
87
- }
88
- .money-cur {
89
- font-size: 0.78em;
90
- font-weight: var(--w-semibold);
91
- letter-spacing: var(--ls-caps);
92
- text-transform: uppercase;
93
- color: var(--color-foreground-muted);
94
- }
95
- .money-frac { color: var(--color-foreground-secondary); font-weight: var(--w-medium); }
96
-
97
- .money-sm { --money-fs: var(--fs-xs); }
98
- .money-md { --money-fs: var(--fs-sm); }
99
- .money-lg { --money-fs: var(--fs-md); font-weight: var(--w-bold); }
100
- .money-xl { --money-fs: var(--fs-2xl); font-weight: var(--w-bold); letter-spacing: var(--ls-tight); }
101
- .money-display { --money-fs: var(--fs-4xl); font-weight: var(--w-bold); letter-spacing: var(--ls-display); }
102
-
103
- .money-pos { color: var(--color-feedback-success-foreground); }
104
- .money-neg { color: var(--color-feedback-danger-foreground); }
105
- .money-muted { color: var(--color-foreground-muted); font-weight: var(--w-medium); }
106
-
107
- /* =================== METRIC (hero display number) ===================
108
- Big, display-weight figure for hero/KPI moments. Distinct from .money
109
- (mono, inline): .metric is SANS display, tabular, with a dimmed currency
110
- prefix and dimmed fraction. Colour INHERITS (works on light + inverse);
111
- dimming uses opacity so it reads on any surface. Tone via inline color
112
- or a utility (e.g. success). Size via .metric-{sm,md,lg}. */
113
- .metric {
114
- font-family: var(--font-display);
115
- font-weight: var(--w-bold);
116
- letter-spacing: var(--ls-display);
117
- line-height: 1;
118
- font-variant-numeric: tabular-nums;
119
- color: inherit;
120
- white-space: nowrap;
121
- font-size: var(--metric-fs, 38px);
122
- }
123
- .metric-cur { font-size: 0.58em; font-weight: var(--w-semibold); opacity: 0.55; margin-right: 0.32em; }
124
- .metric-frac { font-size: 0.68em; opacity: 0.55; }
125
- .metric-sm { --metric-fs: 30px; }
126
- .metric-md { --metric-fs: 38px; }
127
- .metric-lg { --metric-fs: var(--fs-5xl); }
128
- .metric-pos { color: var(--color-success-700); }
129
- .metric-neg { color: var(--color-danger-700); }
130
-
131
- /* =================== STAT =================== */
132
- .stat-row {
133
- display: grid;
134
- grid-template-columns: repeat(var(--stat-cols, 3), 1fr);
135
- gap: var(--space-3);
136
- }
137
- .stat {
138
- display: flex;
139
- flex-direction: column;
140
- gap: var(--space-2);
141
- padding: var(--space-5);
142
- background: var(--color-background-surface);
143
- border: 1px solid var(--color-border-default);
144
- border-radius: var(--radius-md);
145
- }
146
- .stat-label {
147
- font-family: var(--font-mono);
148
- font-size: var(--fs-xxs);
149
- font-weight: var(--w-semibold);
150
- letter-spacing: var(--ls-caps);
151
- text-transform: uppercase;
152
- color: var(--color-foreground-muted);
153
- }
154
- .stat-value {
155
- font-size: var(--fs-3xl);
156
- font-weight: var(--w-bold);
157
- letter-spacing: var(--ls-tight);
158
- color: var(--color-foreground-default);
159
- font-variant-numeric: tabular-nums;
160
- line-height: 1.1;
161
- }
162
- .stat-delta {
163
- display: inline-flex;
164
- align-items: center;
165
- gap: var(--space-1);
166
- font-family: var(--font-mono);
167
- font-size: var(--fs-xs);
168
- font-weight: var(--w-semibold);
169
- }
170
- .stat-delta i, .stat-delta svg { width: 14px; height: 14px; stroke-width: 2.25; }
171
- .stat-delta-up { color: var(--color-feedback-success-foreground); }
172
- .stat-delta-down { color: var(--color-feedback-danger-foreground); }
173
- .stat-delta-flat { color: var(--color-foreground-muted); }
174
-
175
- .stat-foot {
176
- font-size: var(--fs-xs);
177
- color: var(--color-foreground-secondary);
178
- margin-top: var(--space-1);
179
- }
180
- /* Bare stat — figure block without tile chrome, for use inside a Card */
181
- .stat.is-bare { background: none; border: 0; padding: 0; border-radius: 0; }
182
-
183
- /* Compact variant — for sidebars / dense headers */
184
- .stat-compact {
185
- padding: var(--space-3) var(--space-4);
186
- background: transparent;
187
- border: 0;
188
- }
189
- .stat-compact .stat-value { font-size: var(--fs-xl); }
190
-
191
- /* =================== DIVIDER =================== */
192
- .divider {
193
- border: 0;
194
- border-top: 1px solid var(--color-border-default);
195
- margin: var(--space-4) 0;
196
- }
197
- .divider-subtle { border-top-color: var(--color-border-subtle); }
198
- .divider-strong { border-top-color: var(--color-border-strong); }
199
- .divider-dashed { border-top-style: dashed; }
200
-
201
- .divider-vertical {
202
- width: 1px;
203
- height: 1em;
204
- border-top: 0;
205
- border-left: 1px solid var(--color-border-default);
206
- display: inline-block;
207
- margin: 0 var(--space-3);
208
- vertical-align: middle;
209
- }
210
-
211
- /* Labelled divider — splits content with a midline label */
212
- .divider-labelled {
213
- display: flex;
214
- align-items: center;
215
- gap: var(--space-3);
216
- margin: var(--space-5) 0;
217
- font-family: var(--font-mono);
218
- font-size: var(--fs-xxs);
219
- font-weight: var(--w-semibold);
220
- letter-spacing: var(--ls-caps);
221
- text-transform: uppercase;
222
- color: var(--color-foreground-muted);
223
- }
224
- .divider-labelled::before,
225
- .divider-labelled::after {
226
- content: '';
227
- flex: 1;
228
- height: 1px;
229
- background: var(--color-border-default);
230
- }
231
-
232
- /* =================== PILL =================== */
233
- /* Canonical pill lives in components/status-pills.css (single source:
234
- Lato, chained tones .pill.success / sizes .pill.sm). This file no
235
- longer re-defines .pill — primitives.html loads status-pills.css. */
236
-
237
- /* =================== EYEBROW =================== */
238
- /* Uppercase micro-label. size = xs|sm|md, tone maps to a foreground role.
239
- When an icon sits inline, add .has-icon (the JS wrapper does this). */
240
- .eyebrow {
241
- display: block;
242
- font-size: var(--fs-xs);
243
- font-weight: var(--w-semibold);
244
- letter-spacing: var(--ls-caps);
245
- text-transform: uppercase;
246
- color: var(--color-foreground-muted);
247
- }
248
- .eyebrow.has-icon { display: inline-flex; align-items: center; gap: var(--space-2-5); }
249
- .eyebrow-xs { font-size: var(--fs-xxs); font-weight: var(--w-bold); }
250
- .eyebrow-xs.has-icon { gap: var(--space-2); }
251
- .eyebrow-sm { font-size: var(--fs-xxs); font-weight: var(--w-semibold); }
252
- .eyebrow-md { font-size: var(--fs-xs); font-weight: var(--w-semibold); }
253
- .eyebrow-muted { color: var(--color-foreground-muted); }
254
- .eyebrow-secondary { color: var(--color-foreground-secondary); }
255
- .eyebrow-default { color: var(--color-foreground-default); }
256
- .eyebrow-brand { color: var(--color-brand-secondary-700); }
257
- .eyebrow-inverse { color: var(--color-foreground-inverse-muted); }
258
-
259
- /* =================== FILTER CHIP =================== */
260
- /* Pill-button used in filter rows. Control height matches .input / .btn (40px). */
261
- .filter-chip {
262
- display: inline-flex;
263
- align-items: center;
264
- gap: var(--space-2-5);
265
- height: 40px;
266
- padding: 0 var(--space-4);
267
- border: 1px solid var(--color-border-default);
268
- border-radius: var(--radius-md);
269
- background: var(--color-background-surface);
270
- font-family: inherit;
271
- font-size: var(--fs-sm);
272
- font-weight: var(--w-medium);
273
- color: var(--color-foreground-secondary);
274
- cursor: pointer;
275
- white-space: nowrap;
276
- transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
277
- }
278
- .filter-chip:hover { background: var(--color-background-hover); border-color: var(--color-border-strong); }
279
- .filter-chip:active { background: var(--color-background-press); }
280
- /* Selected (aria-pressed via FilterChip TSX) — same active treatment as combobox filter chips */
281
- .filter-chip[aria-pressed="true"] {
282
- background: var(--color-background-selected);
283
- border-color: var(--color-brand-secondary-200);
284
- color: var(--color-foreground-brand);
285
- font-weight: var(--w-semibold);
286
- }
287
- .filter-chip .chip-chevron { opacity: .55; }
288
-
289
- /* =================== PROGRESS BAR =================== */
290
- /* Slim track + fill. Width of fill is data-driven (set inline). */
291
- .progress {
292
- height: var(--progress-h, 6px);
293
- background: var(--progress-track, var(--color-border-default));
294
- border-radius: var(--radius-pill);
295
- position: relative;
296
- overflow: hidden;
297
- }
298
- .progress-fill {
299
- position: absolute;
300
- inset: 0;
301
- background: var(--progress-fill, var(--grad-brand-soft));
302
- border-radius: var(--radius-pill);
303
- }
304
-
305
- /* =================== DESC TERM =================== */
306
- /* Labelled term-definition pair (receipts, detail drawers). */
307
- .desc-term-label {
308
- font-size: var(--fs-xxs);
309
- font-weight: var(--w-bold);
310
- letter-spacing: var(--ls-caps);
311
- text-transform: uppercase;
312
- color: var(--color-foreground-muted);
313
- margin-bottom: var(--space-2-5);
314
- }
1
+ /* ============================================================
2
+ PRIMITIVES — Avatar · Money · Stat · Divider · Pill
3
+ Atoms used across every product surface. All values from tokens.
4
+ (Tabs moved to components/tabs.css — it's a stateful nav component.)
5
+ ============================================================ */
6
+
7
+ /* =================== AVATAR =================== */
8
+ .av {
9
+ display: inline-flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ flex-shrink: 0;
13
+ width: var(--av-size, 36px);
14
+ height: var(--av-size, 36px);
15
+ border-radius: var(--radius-pill);
16
+ font-family: var(--font-mono);
17
+ font-size: var(--av-fs, var(--fs-xs));
18
+ font-weight: var(--w-bold);
19
+ letter-spacing: var(--ls-caps);
20
+ text-transform: uppercase;
21
+ user-select: none;
22
+ overflow: hidden;
23
+ position: relative;
24
+ }
25
+ .av img { width: 100%; height: 100%; object-fit: cover; display: block; }
26
+
27
+ .av-xs { --av-size: 20px; --av-fs: 9px; }
28
+ .av-sm { --av-size: 28px; --av-fs: var(--fs-xxs); }
29
+ .av-md { --av-size: 36px; --av-fs: var(--fs-xs); }
30
+ .av-lg { --av-size: 48px; --av-fs: var(--fs-sm); }
31
+ .av-xl { --av-size: 64px; --av-fs: var(--fs-md); }
32
+
33
+ /* Tone — accent-on-tinted-bg uses the same background+foreground pair as feedback pills,
34
+ so an Avatar reads as the same "object" as a status pill that references it. */
35
+ .av-brand { background: var(--color-brand-secondary-50); color: var(--color-brand-secondary-700); }
36
+ .av-success { background: var(--color-feedback-success-background); color: var(--color-feedback-success-foreground); }
37
+ .av-warning { background: var(--color-feedback-warning-background); color: var(--color-feedback-warning-foreground); }
38
+ .av-danger { background: var(--color-feedback-danger-background); color: var(--color-feedback-danger-foreground); }
39
+ .av-info { background: var(--color-feedback-info-background); color: var(--color-feedback-info-foreground); }
40
+ .av-neutral { background: var(--color-background-subtle); color: var(--color-foreground-muted); }
41
+
42
+ /* Status dot — overlay for presence/online state */
43
+ .av-dot {
44
+ position: absolute;
45
+ bottom: 0;
46
+ right: 0;
47
+ width: 30%;
48
+ height: 30%;
49
+ min-width: 8px;
50
+ min-height: 8px;
51
+ border-radius: var(--radius-pill);
52
+ background: var(--color-success-500);
53
+ box-shadow: 0 0 0 2px var(--color-background-surface);
54
+ }
55
+ .av-dot-busy { background: var(--color-feedback-danger-foreground); }
56
+ .av-dot-away { background: var(--color-feedback-warning-foreground); }
57
+ .av-dot-off { background: var(--color-foreground-muted); }
58
+
59
+ /* Avatar group — overlapping stack */
60
+ .av-group {
61
+ display: inline-flex;
62
+ align-items: center;
63
+ isolation: isolate;
64
+ }
65
+ .av-group .av {
66
+ margin-left: -8px;
67
+ border: 2px solid var(--color-background-surface);
68
+ }
69
+ .av-group .av:first-child { margin-left: 0; }
70
+ .av-group .av-more {
71
+ background: var(--color-background-surface);
72
+ color: var(--color-foreground-secondary);
73
+ border: 1px dashed var(--color-border-default);
74
+ }
75
+
76
+ /* =================== MONEY =================== */
77
+ .money {
78
+ display: inline-flex;
79
+ align-items: baseline;
80
+ gap: var(--space-1);
81
+ font-family: var(--font-mono);
82
+ font-variant-numeric: tabular-nums;
83
+ font-size: var(--money-fs, var(--fs-sm));
84
+ font-weight: var(--w-semibold);
85
+ color: var(--color-foreground-default);
86
+ white-space: nowrap;
87
+ }
88
+ .money-cur {
89
+ font-size: 0.78em;
90
+ font-weight: var(--w-semibold);
91
+ letter-spacing: var(--ls-caps);
92
+ text-transform: uppercase;
93
+ color: var(--color-foreground-muted);
94
+ }
95
+ .money-frac { color: var(--color-foreground-secondary); font-weight: var(--w-medium); }
96
+
97
+ .money-sm { --money-fs: var(--fs-xs); }
98
+ .money-md { --money-fs: var(--fs-sm); }
99
+ .money-lg { --money-fs: var(--fs-md); font-weight: var(--w-bold); }
100
+ .money-xl { --money-fs: var(--fs-2xl); font-weight: var(--w-bold); letter-spacing: var(--ls-tight); }
101
+ .money-display { --money-fs: var(--fs-4xl); font-weight: var(--w-bold); letter-spacing: var(--ls-display); }
102
+
103
+ .money-pos { color: var(--color-feedback-success-foreground); }
104
+ .money-neg { color: var(--color-feedback-danger-foreground); }
105
+ .money-muted { color: var(--color-foreground-muted); font-weight: var(--w-medium); }
106
+
107
+ /* =================== METRIC (hero display number) ===================
108
+ Big, display-weight figure for hero/KPI moments. Distinct from .money
109
+ (mono, inline): .metric is SANS display, tabular, with a dimmed currency
110
+ prefix and dimmed fraction. Colour INHERITS (works on light + inverse);
111
+ dimming uses opacity so it reads on any surface. Tone via inline color
112
+ or a utility (e.g. success). Size via .metric-{sm,md,lg}. */
113
+ .metric {
114
+ font-family: var(--font-display);
115
+ font-weight: var(--w-bold);
116
+ letter-spacing: var(--ls-display);
117
+ line-height: 1;
118
+ font-variant-numeric: tabular-nums;
119
+ color: inherit;
120
+ white-space: nowrap;
121
+ font-size: var(--metric-fs, 38px);
122
+ }
123
+ .metric-cur { font-size: 0.58em; font-weight: var(--w-semibold); opacity: 0.55; margin-right: 0.32em; }
124
+ .metric-frac { font-size: 0.68em; opacity: 0.55; }
125
+ .metric-sm { --metric-fs: 30px; }
126
+ .metric-md { --metric-fs: 38px; }
127
+ .metric-lg { --metric-fs: var(--fs-5xl); }
128
+ .metric-pos { color: var(--color-success-700); }
129
+ .metric-neg { color: var(--color-danger-700); }
130
+
131
+ /* =================== STAT =================== */
132
+ .stat-row {
133
+ display: grid;
134
+ grid-template-columns: repeat(var(--stat-cols, 3), 1fr);
135
+ gap: var(--space-3);
136
+ }
137
+ .stat {
138
+ display: flex;
139
+ flex-direction: column;
140
+ gap: var(--space-2);
141
+ padding: var(--space-5);
142
+ background: var(--color-background-surface);
143
+ border: 1px solid var(--color-border-default);
144
+ border-radius: var(--radius-md);
145
+ }
146
+ .stat-label {
147
+ font-family: var(--font-mono);
148
+ font-size: var(--fs-xxs);
149
+ font-weight: var(--w-semibold);
150
+ letter-spacing: var(--ls-caps);
151
+ text-transform: uppercase;
152
+ color: var(--color-foreground-muted);
153
+ }
154
+ .stat-value {
155
+ font-size: var(--fs-3xl);
156
+ font-weight: var(--w-bold);
157
+ letter-spacing: var(--ls-tight);
158
+ color: var(--color-foreground-default);
159
+ font-variant-numeric: tabular-nums;
160
+ line-height: 1.1;
161
+ }
162
+ .stat-delta {
163
+ display: inline-flex;
164
+ align-items: center;
165
+ gap: var(--space-1);
166
+ font-family: var(--font-mono);
167
+ font-size: var(--fs-xs);
168
+ font-weight: var(--w-semibold);
169
+ }
170
+ .stat-delta i, .stat-delta svg { width: 14px; height: 14px; stroke-width: 2.25; }
171
+ .stat-delta-up { color: var(--color-feedback-success-foreground); }
172
+ .stat-delta-down { color: var(--color-feedback-danger-foreground); }
173
+ .stat-delta-flat { color: var(--color-foreground-muted); }
174
+
175
+ .stat-foot {
176
+ font-size: var(--fs-xs);
177
+ color: var(--color-foreground-secondary);
178
+ margin-top: var(--space-1);
179
+ }
180
+ /* Bare stat — figure block without tile chrome, for use inside a Card */
181
+ .stat.is-bare { background: none; border: 0; padding: 0; border-radius: 0; }
182
+
183
+ /* Compact variant — for sidebars / dense headers */
184
+ .stat-compact {
185
+ padding: var(--space-3) var(--space-4);
186
+ background: transparent;
187
+ border: 0;
188
+ }
189
+ .stat-compact .stat-value { font-size: var(--fs-xl); }
190
+
191
+ /* =================== DIVIDER =================== */
192
+ .divider {
193
+ border: 0;
194
+ border-top: 1px solid var(--color-border-default);
195
+ margin: var(--space-4) 0;
196
+ }
197
+ .divider-subtle { border-top-color: var(--color-border-subtle); }
198
+ .divider-strong { border-top-color: var(--color-border-strong); }
199
+ .divider-dashed { border-top-style: dashed; }
200
+
201
+ .divider-vertical {
202
+ width: 1px;
203
+ height: 1em;
204
+ border-top: 0;
205
+ border-left: 1px solid var(--color-border-default);
206
+ display: inline-block;
207
+ margin: 0 var(--space-3);
208
+ vertical-align: middle;
209
+ }
210
+
211
+ /* Labelled divider — splits content with a midline label */
212
+ .divider-labelled {
213
+ display: flex;
214
+ align-items: center;
215
+ gap: var(--space-3);
216
+ margin: var(--space-5) 0;
217
+ font-family: var(--font-mono);
218
+ font-size: var(--fs-xxs);
219
+ font-weight: var(--w-semibold);
220
+ letter-spacing: var(--ls-caps);
221
+ text-transform: uppercase;
222
+ color: var(--color-foreground-muted);
223
+ }
224
+ .divider-labelled::before,
225
+ .divider-labelled::after {
226
+ content: '';
227
+ flex: 1;
228
+ height: 1px;
229
+ background: var(--color-border-default);
230
+ }
231
+
232
+ /* =================== PILL =================== */
233
+ /* Canonical pill lives in components/status-pills.css (single source:
234
+ Lato, chained tones .pill.success / sizes .pill.sm). This file no
235
+ longer re-defines .pill — primitives.html loads status-pills.css. */
236
+
237
+ /* =================== EYEBROW =================== */
238
+ /* Uppercase micro-label. size = xs|sm|md, tone maps to a foreground role.
239
+ When an icon sits inline, add .has-icon (the JS wrapper does this). */
240
+ .eyebrow {
241
+ display: block;
242
+ font-size: var(--fs-xs);
243
+ font-weight: var(--w-semibold);
244
+ letter-spacing: var(--ls-caps);
245
+ text-transform: uppercase;
246
+ color: var(--color-foreground-muted);
247
+ }
248
+ .eyebrow.has-icon { display: inline-flex; align-items: center; gap: var(--space-2-5); }
249
+ .eyebrow-xs { font-size: var(--fs-xxs); font-weight: var(--w-bold); }
250
+ .eyebrow-xs.has-icon { gap: var(--space-2); }
251
+ .eyebrow-sm { font-size: var(--fs-xxs); font-weight: var(--w-semibold); }
252
+ .eyebrow-md { font-size: var(--fs-xs); font-weight: var(--w-semibold); }
253
+ .eyebrow-muted { color: var(--color-foreground-muted); }
254
+ .eyebrow-secondary { color: var(--color-foreground-secondary); }
255
+ .eyebrow-default { color: var(--color-foreground-default); }
256
+ .eyebrow-brand { color: var(--color-brand-secondary-700); }
257
+ .eyebrow-inverse { color: var(--color-foreground-inverse-muted); }
258
+
259
+ /* =================== FILTER CHIP =================== */
260
+ /* Pill-button used in filter rows. Control height matches .input / .btn (40px). */
261
+ .filter-chip {
262
+ display: inline-flex;
263
+ align-items: center;
264
+ gap: var(--space-2-5);
265
+ height: 40px;
266
+ padding: 0 var(--space-4);
267
+ border: 1px solid var(--color-border-default);
268
+ border-radius: var(--radius-md);
269
+ background: var(--color-background-surface);
270
+ font-family: inherit;
271
+ font-size: var(--fs-sm);
272
+ font-weight: var(--w-medium);
273
+ color: var(--color-foreground-secondary);
274
+ cursor: pointer;
275
+ white-space: nowrap;
276
+ transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
277
+ }
278
+ .filter-chip:hover { background: var(--color-background-hover); border-color: var(--color-border-strong); }
279
+ .filter-chip:active { background: var(--color-background-press); }
280
+ /* Selected (aria-pressed via FilterChip TSX) — same active treatment as combobox filter chips */
281
+ .filter-chip[aria-pressed="true"] {
282
+ background: var(--color-background-selected);
283
+ border-color: var(--color-brand-secondary-200);
284
+ color: var(--color-foreground-brand);
285
+ font-weight: var(--w-semibold);
286
+ }
287
+ .filter-chip .chip-chevron { opacity: .55; }
288
+
289
+ /* =================== PROGRESS BAR =================== */
290
+ /* Slim track + fill. Width of fill is data-driven (set inline). */
291
+ .progress {
292
+ height: var(--progress-h, 6px);
293
+ background: var(--progress-track, var(--color-border-default));
294
+ border-radius: var(--radius-pill);
295
+ position: relative;
296
+ overflow: hidden;
297
+ }
298
+ .progress-fill {
299
+ position: absolute;
300
+ inset: 0;
301
+ background: var(--progress-fill, var(--grad-brand-soft));
302
+ border-radius: var(--radius-pill);
303
+ }
304
+
305
+ /* =================== DESC TERM =================== */
306
+ /* Labelled term-definition pair (receipts, detail drawers). */
307
+ .desc-term-label {
308
+ font-size: var(--fs-xxs);
309
+ font-weight: var(--w-bold);
310
+ letter-spacing: var(--ls-caps);
311
+ text-transform: uppercase;
312
+ color: var(--color-foreground-muted);
313
+ margin-bottom: var(--space-2-5);
314
+ }