@attrus-ds/core 0.1.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.
Files changed (54) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +123 -0
  3. package/dist/assets/flags/Brazil-rounded.svg +16 -0
  4. package/dist/assets/flags/Brazil-square.svg +17 -0
  5. package/dist/assets/flags/Chile-rounded.svg +11 -0
  6. package/dist/assets/flags/Chile-square.svg +11 -0
  7. package/dist/assets/flags/Colombia-rounded.svg +10 -0
  8. package/dist/assets/flags/Colombia-square.svg +10 -0
  9. package/dist/assets/flags/EUA-rounded.svg +11 -0
  10. package/dist/assets/flags/EUA-square.svg +11 -0
  11. package/dist/assets/flags/EUR-rounded.svg +9 -0
  12. package/dist/assets/flags/EUR-square.svg +9 -0
  13. package/dist/assets/flags/Mexico-rounded.svg +19 -0
  14. package/dist/assets/flags/Mexico-square.svg +19 -0
  15. package/dist/assets/icon-attrus-dark.svg +3 -0
  16. package/dist/assets/icon-attrus-light.svg +3 -0
  17. package/dist/assets/logo-attrus-dark.svg +8 -0
  18. package/dist/assets/logo-attrus-light.svg +8 -0
  19. package/dist/css/components/buttons.css +301 -0
  20. package/dist/css/components/callout.css +195 -0
  21. package/dist/css/components/cards.css +272 -0
  22. package/dist/css/components/combobox.css +303 -0
  23. package/dist/css/components/empty-states.css +61 -0
  24. package/dist/css/components/inputs.css +1027 -0
  25. package/dist/css/components/number-input.css +138 -0
  26. package/dist/css/components/overlays.css +405 -0
  27. package/dist/css/components/primitives.css +305 -0
  28. package/dist/css/components/sidebar.css +179 -0
  29. package/dist/css/components/status-pills.css +207 -0
  30. package/dist/css/components/stepper.css +309 -0
  31. package/dist/css/components/table.css +600 -0
  32. package/dist/css/components/tabs.css +319 -0
  33. package/dist/css/components/toast.css +239 -0
  34. package/dist/css/components/tooltip.css +226 -0
  35. package/dist/css/components/topbar.css +148 -0
  36. package/dist/css/fonts.css +91 -0
  37. package/dist/css/index.css +23 -0
  38. package/dist/css/tokens.css +691 -0
  39. package/dist/fonts/LICENSE-JetBrainsMono.txt +93 -0
  40. package/dist/fonts/LICENSE-Lato.txt +93 -0
  41. package/dist/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  42. package/dist/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
  43. package/dist/fonts/jetbrains-mono-latin-600-normal.woff2 +0 -0
  44. package/dist/fonts/lato-latin-100-normal.woff2 +0 -0
  45. package/dist/fonts/lato-latin-300-italic.woff2 +0 -0
  46. package/dist/fonts/lato-latin-300-normal.woff2 +0 -0
  47. package/dist/fonts/lato-latin-400-italic.woff2 +0 -0
  48. package/dist/fonts/lato-latin-400-normal.woff2 +0 -0
  49. package/dist/fonts/lato-latin-700-italic.woff2 +0 -0
  50. package/dist/fonts/lato-latin-700-normal.woff2 +0 -0
  51. package/dist/fonts/lato-latin-900-normal.woff2 +0 -0
  52. package/dist/tokens/attrus-tokens.flat.json +1235 -0
  53. package/dist/tokens/attrus-tokens.json +1090 -0
  54. package/package.json +46 -0
@@ -0,0 +1,305 @@
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
+
181
+ /* Compact variant — for sidebars / dense headers */
182
+ .stat-compact {
183
+ padding: var(--space-3) var(--space-4);
184
+ background: transparent;
185
+ border: 0;
186
+ }
187
+ .stat-compact .stat-value { font-size: var(--fs-xl); }
188
+
189
+ /* =================== DIVIDER =================== */
190
+ .divider {
191
+ border: 0;
192
+ border-top: 1px solid var(--color-border-default);
193
+ margin: var(--space-4) 0;
194
+ }
195
+ .divider-subtle { border-top-color: var(--color-border-subtle); }
196
+ .divider-strong { border-top-color: var(--color-border-strong); }
197
+ .divider-dashed { border-top-style: dashed; }
198
+
199
+ .divider-vertical {
200
+ width: 1px;
201
+ height: 1em;
202
+ border-top: 0;
203
+ border-left: 1px solid var(--color-border-default);
204
+ display: inline-block;
205
+ margin: 0 var(--space-3);
206
+ vertical-align: middle;
207
+ }
208
+
209
+ /* Labelled divider — splits content with a midline label */
210
+ .divider-labelled {
211
+ display: flex;
212
+ align-items: center;
213
+ gap: var(--space-3);
214
+ margin: var(--space-5) 0;
215
+ font-family: var(--font-mono);
216
+ font-size: var(--fs-xxs);
217
+ font-weight: var(--w-semibold);
218
+ letter-spacing: var(--ls-caps);
219
+ text-transform: uppercase;
220
+ color: var(--color-foreground-muted);
221
+ }
222
+ .divider-labelled::before,
223
+ .divider-labelled::after {
224
+ content: '';
225
+ flex: 1;
226
+ height: 1px;
227
+ background: var(--color-border-default);
228
+ }
229
+
230
+ /* =================== PILL =================== */
231
+ /* Canonical pill lives in components/status-pills.css (single source:
232
+ Lato, chained tones .pill.success / sizes .pill.sm). This file no
233
+ longer re-defines .pill — primitives.html loads status-pills.css. */
234
+
235
+ /* =================== EYEBROW =================== */
236
+ /* Uppercase micro-label. size = xs|sm|md, tone maps to a foreground role.
237
+ When an icon sits inline, add .has-icon (the JS wrapper does this). */
238
+ .eyebrow {
239
+ display: block;
240
+ font-size: var(--fs-xs);
241
+ font-weight: var(--w-semibold);
242
+ letter-spacing: var(--ls-caps);
243
+ text-transform: uppercase;
244
+ color: var(--color-foreground-muted);
245
+ }
246
+ .eyebrow.has-icon { display: inline-flex; align-items: center; gap: var(--space-2-5); }
247
+ .eyebrow-xs { font-size: var(--fs-xxs); font-weight: var(--w-bold); }
248
+ .eyebrow-xs.has-icon { gap: var(--space-2); }
249
+ .eyebrow-sm { font-size: var(--fs-xxs); font-weight: var(--w-semibold); }
250
+ .eyebrow-md { font-size: var(--fs-xs); font-weight: var(--w-semibold); }
251
+ .eyebrow-muted { color: var(--color-foreground-muted); }
252
+ .eyebrow-secondary { color: var(--color-foreground-secondary); }
253
+ .eyebrow-default { color: var(--color-foreground-default); }
254
+ .eyebrow-brand { color: var(--color-brand-secondary-700); }
255
+ .eyebrow-inverse { color: var(--color-foreground-inverse-muted); }
256
+
257
+ /* =================== FILTER CHIP =================== */
258
+ /* Pill-button used in filter rows. Control height matches .input / .btn (40px). */
259
+ .filter-chip {
260
+ display: inline-flex;
261
+ align-items: center;
262
+ gap: var(--space-2-5);
263
+ height: 40px;
264
+ padding: 0 var(--space-4);
265
+ border: 1px solid var(--color-border-default);
266
+ border-radius: var(--radius-md);
267
+ background: var(--color-background-surface);
268
+ font-family: inherit;
269
+ font-size: var(--fs-sm);
270
+ font-weight: var(--w-medium);
271
+ color: var(--color-foreground-secondary);
272
+ cursor: pointer;
273
+ white-space: nowrap;
274
+ transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
275
+ }
276
+ .filter-chip:hover { background: var(--color-background-hover); border-color: var(--color-border-strong); }
277
+ .filter-chip:active { background: var(--color-background-press); }
278
+ .filter-chip .chip-chevron { opacity: .55; }
279
+
280
+ /* =================== PROGRESS BAR =================== */
281
+ /* Slim track + fill. Width of fill is data-driven (set inline). */
282
+ .progress {
283
+ height: var(--progress-h, 6px);
284
+ background: var(--progress-track, var(--color-neutral-100));
285
+ border-radius: var(--radius-pill);
286
+ position: relative;
287
+ overflow: hidden;
288
+ }
289
+ .progress-fill {
290
+ position: absolute;
291
+ inset: 0;
292
+ background: var(--progress-fill, var(--grad-brand-soft));
293
+ border-radius: var(--radius-pill);
294
+ }
295
+
296
+ /* =================== DESC TERM =================== */
297
+ /* Labelled term-definition pair (receipts, detail drawers). */
298
+ .desc-term-label {
299
+ font-size: var(--fs-xxs);
300
+ font-weight: var(--w-bold);
301
+ letter-spacing: var(--ls-caps);
302
+ text-transform: uppercase;
303
+ color: var(--color-foreground-muted);
304
+ margin-bottom: var(--space-2-5);
305
+ }
@@ -0,0 +1,179 @@
1
+ /* ============================================================
2
+ SIDEBAR NAVIGATION — ATTRUS Design System
3
+ Canonical component CSS. SINGLE SOURCE consumed by BOTH the
4
+ live app shell (ui_kits/dashboard/Shell.jsx) and the doc page
5
+ (preview/sidebar-nav.html). Token-driven → themes automatically.
6
+
7
+ Class map:
8
+ .sb component root (card framing — doc demos)
9
+ .sb.sb-app app modifier: full-height rail, border-right only
10
+ .sb.collapsed 60px icon rail
11
+ .sb-head/-body/-section/-item/-foot
12
+ .sb-item.active · .ic · .label · .badge · .count
13
+ .sb-group / .sb-children / .sb-subitem (collapsible groups)
14
+
15
+ Canonical row height: 36px (comfortable — operational platform).
16
+ ============================================================ */
17
+
18
+ .sb {
19
+ width: 216px;
20
+ background: var(--color-background-surface);
21
+ border: 1px solid var(--color-border-default);
22
+ border-radius: var(--radius-md);
23
+ box-shadow: var(--shadow-sm);
24
+ display: flex; flex-direction: column;
25
+ overflow: hidden;
26
+ }
27
+ /* App rail: full-height, no card framing, animates width */
28
+ .sb.sb-app {
29
+ border: 0;
30
+ border-right: 1px solid var(--color-border-default);
31
+ border-radius: 0;
32
+ box-shadow: none;
33
+ height: 100%;
34
+ transition: width var(--duration-base) var(--ease-standard);
35
+ }
36
+
37
+ /* Header — matches TopBar (60px) so logos align */
38
+ .sb-head {
39
+ height: 60px; padding: 0 var(--space-2-5) 0 18px;
40
+ display: flex; align-items: center; justify-content: space-between;
41
+ border-bottom: 1px solid var(--color-border-subtle);
42
+ flex-shrink: 0;
43
+ }
44
+ .sb-head img { height: 14px; width: auto; }
45
+ .sb-head .toggle {
46
+ width: 26px; height: 26px; border-radius: var(--radius-sm); border: 0; padding: 0;
47
+ background: transparent; color: var(--color-foreground-muted); cursor: pointer;
48
+ display: inline-flex; align-items: center; justify-content: center;
49
+ transition: var(--transition-fast);
50
+ }
51
+ .sb-head .toggle:hover { background: var(--color-background-hover); color: var(--color-foreground-secondary); }
52
+ .sb-head .toggle svg, .sb-head .toggle i { width: 14px; height: 14px; stroke-width: var(--icon-stroke); }
53
+
54
+ .sb-body { flex: 1; padding: var(--space-3) 0; overflow-y: auto; overflow-x: hidden; }
55
+
56
+ .sb-section {
57
+ padding: var(--space-6) var(--space-5) var(--space-2);
58
+ font-family: var(--font-sans);
59
+ font-size: var(--fs-xxs); font-weight: var(--w-semibold);
60
+ color: var(--color-foreground-muted);
61
+ letter-spacing: var(--ls-caps); text-transform: uppercase;
62
+ }
63
+
64
+ .sb-item {
65
+ display: flex; align-items: center; gap: 11px;
66
+ padding: 8px 10px; margin: 3px 10px;
67
+ height: 36px; box-sizing: border-box;
68
+ border-radius: var(--radius-sm);
69
+ color: var(--color-foreground-secondary);
70
+ font-size: var(--fs-md); font-weight: var(--w-medium);
71
+ cursor: pointer; position: relative;
72
+ white-space: nowrap; overflow: hidden;
73
+ transition: background .15s, color .15s;
74
+ }
75
+ .sb-item:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
76
+ .sb-item.active {
77
+ background: var(--color-brand-secondary-50);
78
+ color: var(--color-brand-secondary-700);
79
+ font-weight: var(--w-semibold);
80
+ }
81
+ .sb-item.active::before {
82
+ content: ""; position: absolute; left: -10px; top: 9px; bottom: 9px;
83
+ width: 2px; border-radius: var(--radius-pill);
84
+ background: var(--color-brand-secondary-500);
85
+ }
86
+ .sb-item .ic { width: 15px; height: 15px; stroke-width: var(--icon-stroke); flex-shrink: 0; opacity: 0.85; }
87
+ .sb-item.active .ic { color: var(--color-brand-secondary-500); opacity: 1; }
88
+ .sb-item .label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
89
+ .sb-item.disabled { color: var(--color-foreground-placeholder); cursor: not-allowed; }
90
+ .sb-item.disabled:hover { background: transparent; }
91
+
92
+ /* Trailing decoration — badge (status) OR count (numeric), never both */
93
+ .sb-badge {
94
+ font-family: var(--font-sans); font-size: 9px; font-weight: var(--w-bold);
95
+ letter-spacing: .06em; line-height: 1.4;
96
+ padding: 1px var(--space-2-5); border-radius: var(--radius-pill);
97
+ background: var(--color-brand-secondary-500); color: var(--color-pure-white);
98
+ }
99
+ .sb-badge.alert { background: var(--color-danger-500); }
100
+ .sb-badge.warning { background: var(--color-warning-500); }
101
+ .sb-count {
102
+ font-family: var(--font-mono); font-size: var(--fs-xxs);
103
+ color: var(--color-foreground-muted);
104
+ background: var(--color-background-subtle);
105
+ padding: 1px 6px; border-radius: var(--radius-xs);
106
+ }
107
+ .sb-item.active .sb-count { background: color-mix(in srgb, var(--color-brand-secondary-200) 70%, transparent); color: var(--color-brand-secondary-700); }
108
+
109
+ /* Footer — user mini-card */
110
+ .sb-foot {
111
+ border-top: 1px solid var(--color-border-subtle);
112
+ padding: var(--space-3);
113
+ display: flex; align-items: center; gap: var(--space-3);
114
+ flex-shrink: 0;
115
+ }
116
+ .sb-foot .avatar {
117
+ width: 26px; height: 26px; border-radius: var(--radius-pill);
118
+ background: var(--color-brand-secondary-500); color: var(--color-pure-white);
119
+ font-size: 10px; font-weight: var(--w-bold);
120
+ display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
121
+ }
122
+ .sb-foot .meta { flex: 1; min-width: 0; }
123
+ .sb-foot .meta .name { font-size: var(--fs-sm); font-weight: var(--w-semibold); color: var(--color-foreground-default); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
124
+ .sb-foot .meta .role { font-size: var(--fs-xxs); color: var(--color-foreground-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
125
+ .sb-foot .logout { color: var(--color-foreground-muted); cursor: pointer; flex-shrink: 0; display: inline-flex; }
126
+ .sb-foot .logout svg, .sb-foot .logout i { width: 14px; height: 14px; stroke-width: var(--icon-stroke); }
127
+
128
+ /* ===== Collapsed (60px icon rail) ===== */
129
+ .sb.collapsed { width: 60px; }
130
+ .sb.collapsed .sb-head { padding: 0 var(--space-3); justify-content: center; }
131
+ .sb.collapsed .sb-section { padding: 0; margin: var(--space-3) var(--space-4); height: 1px; background: var(--color-border-subtle); font-size: 0; color: transparent; }
132
+ .sb.collapsed .sb-item { justify-content: center; padding: 8px 0; gap: 0; margin: 1px 10px; }
133
+ .sb.collapsed .sb-item .label, .sb.collapsed .sb-badge, .sb.collapsed .sb-count, .sb.collapsed .sb-item .chev { display: none; }
134
+ .sb.collapsed .sb-item.active::before { display: none; }
135
+ .sb.collapsed .sb-foot { justify-content: center; padding: var(--space-3) 0; }
136
+ .sb.collapsed .sb-foot .meta, .sb.collapsed .sb-foot .logout { display: none; }
137
+
138
+ /* ===== Groups & dropdowns ===== */
139
+ .sb-group { position: relative; }
140
+ .sb-group > .sb-item .chev {
141
+ width: 14px; height: 14px; stroke-width: var(--icon-stroke);
142
+ margin-left: auto; opacity: 0.7;
143
+ transition: transform var(--duration-base) var(--ease-standard);
144
+ }
145
+ .sb-group[aria-expanded="true"] > .sb-item .chev { transform: rotate(90deg); opacity: 1; }
146
+ .sb-children {
147
+ overflow: hidden; display: grid; grid-template-rows: 0fr;
148
+ transition: grid-template-rows var(--duration-base) var(--ease-standard);
149
+ }
150
+ .sb-children > .sb-children-inner { min-height: 0; }
151
+ .sb-group[aria-expanded="true"] .sb-children { grid-template-rows: 1fr; }
152
+ .sb-children-inner { padding: var(--space-1) 0; }
153
+ .sb-children .sb-subitem {
154
+ display: flex; align-items: center; gap: 10px;
155
+ padding: 8px 12px 8px 38px; margin: 2px 10px;
156
+ height: 38px; box-sizing: border-box;
157
+ border-radius: var(--radius-sm);
158
+ color: var(--color-foreground-secondary);
159
+ font-size: var(--fs-sm); font-weight: var(--w-medium);
160
+ cursor: pointer; position: relative;
161
+ transition: var(--transition-fast);
162
+ }
163
+ .sb-children .sb-subitem::before {
164
+ content: ""; position: absolute; left: 26px; top: 50%; transform: translateY(-50%);
165
+ width: 5px; height: 5px; border-radius: var(--radius-pill);
166
+ background: var(--color-border-strong); opacity: .55;
167
+ transition: var(--transition-fast);
168
+ }
169
+ .sb-children .sb-subitem:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
170
+ .sb-children .sb-subitem:hover::before { opacity: 1; background: var(--color-foreground-muted); }
171
+ .sb-children .sb-subitem.active { color: var(--color-brand-secondary-700); font-weight: var(--w-semibold); background: var(--color-brand-secondary-50); }
172
+ .sb-children .sb-subitem.active::before { background: var(--color-brand-secondary-500); opacity: 1; }
173
+ .sb-children .sb-subitem .count, .sb-children .sb-subitem .sb-count {
174
+ margin-left: auto;
175
+ font-family: var(--font-mono); font-size: var(--fs-xxs);
176
+ color: var(--color-foreground-muted);
177
+ background: var(--color-background-subtle);
178
+ padding: 1px 6px; border-radius: var(--radius-xs);
179
+ }
@@ -0,0 +1,207 @@
1
+ /* ================================================================
2
+ STATUS PILLS — components/status-pills.css
3
+ The single source of truth for status feedback.
4
+ 100% token-driven; consumed by status-pills.html and any product UI.
5
+ ================================================================ */
6
+
7
+ /* ----------------------------------------------------------------
8
+ Base — .pill
9
+ Inline pill with optional leading dot and trailing close (×).
10
+ ---------------------------------------------------------------- */
11
+ .pill {
12
+ display: inline-flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ gap: 6px;
16
+ height: 24px; /* default md */
17
+ padding: 0 10px;
18
+ border: 1px solid transparent;
19
+ border-radius: var(--radius-pill);
20
+ font-family: var(--font-sans);
21
+ font-size: var(--fs-xs);
22
+ font-weight: var(--w-semibold);
23
+ line-height: 1;
24
+ letter-spacing: var(--ls-caps);
25
+ white-space: nowrap;
26
+ user-select: none;
27
+ vertical-align: middle;
28
+ font-feature-settings: "tnum" 1;
29
+ transition:
30
+ background var(--transition-fast),
31
+ border-color var(--transition-fast),
32
+ color var(--transition-fast);
33
+ }
34
+
35
+ /* Leading dot — purely decorative; meaning lives in label + variant */
36
+ .pill > .dot {
37
+ width: 6px;
38
+ height: 6px;
39
+ border-radius: var(--radius-pill);
40
+ flex-shrink: 0;
41
+ background: currentColor;
42
+ align-self: center;
43
+ }
44
+
45
+ /* Label wrapper — runtime-injected; nudges text up 0.5px to compensate for
46
+ Lato's optical descender offset, leaving the dot at geometric centre. */
47
+ .pill > .pill-label {
48
+ display: inline-block;
49
+ transform: translateY(-0.5px);
50
+ }
51
+
52
+ /* Trailing icon (e.g. clock, arrow) */
53
+ .pill > i, .pill > svg,
54
+ .pill > svg {
55
+ display: inline-flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ width: 12px;
59
+ height: 12px;
60
+ stroke-width: var(--icon-stroke);
61
+ flex-shrink: 0;
62
+ vertical-align: middle;
63
+ }
64
+ .pill > svg, .pill > i > svg { display: block; }
65
+
66
+ /* Removable close (×) — interactive */
67
+ .pill > .pill-x {
68
+ display: inline-flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ width: 14px;
72
+ height: 14px;
73
+ margin-right: -4px;
74
+ border-radius: var(--radius-pill);
75
+ background: transparent;
76
+ border: 0;
77
+ cursor: pointer;
78
+ color: inherit;
79
+ opacity: 0.7;
80
+ transition: opacity var(--transition-fast), background var(--transition-fast);
81
+ }
82
+ .pill > .pill-x:hover { opacity: 1; background: color-mix(in srgb, currentColor 16%, transparent); }
83
+ .pill > .pill-x svg, .pill > .pill-x i { width: 10px; height: 10px; stroke-width: 2.25; }
84
+
85
+
86
+ /* ----------------------------------------------------------------
87
+ Sizes
88
+ ---------------------------------------------------------------- */
89
+ .pill.sm {
90
+ height: 20px;
91
+ padding: 0 8px;
92
+ font-size: var(--fs-xxs);
93
+ gap: 4px;
94
+ }
95
+ .pill.sm > .dot { width: 5px; height: 5px; }
96
+ .pill.sm > i, .pill.sm > svg, .pill.sm > svg { width: 10px; height: 10px; }
97
+
98
+ /* md is default (24px) */
99
+
100
+ .pill.lg {
101
+ height: 28px;
102
+ padding: 0 14px;
103
+ font-size: var(--fs-xs); /* keep label compact — lg = bigger pill, not bigger type */
104
+ gap: 8px;
105
+ }
106
+ .pill.lg > .dot { width: 6px; height: 6px; }
107
+ .pill.lg > i, .pill.lg > svg, .pill.lg > svg { width: 12px; height: 12px; }
108
+
109
+
110
+ /* ----------------------------------------------------------------
111
+ Variants — semantic
112
+ Each = bg + fg + border. Variant carries meaning; label is required.
113
+ ---------------------------------------------------------------- */
114
+ .pill.success { background: var(--color-feedback-success-background); color: var(--color-feedback-success-foreground); border-color: var(--color-feedback-success-border); }
115
+ .pill.warning { background: var(--color-feedback-warning-background); color: var(--color-feedback-warning-foreground); border-color: var(--color-feedback-warning-border); }
116
+ .pill.danger { background: var(--color-feedback-danger-background); color: var(--color-feedback-danger-foreground); border-color: var(--color-feedback-danger-border); }
117
+ .pill.info { background: var(--color-feedback-info-background); color: var(--color-feedback-info-foreground); border-color: var(--color-feedback-info-border); }
118
+ .pill.neutral { background: var(--color-background-subtle); color: var(--color-foreground-secondary); border-color: var(--color-border-default); }
119
+
120
+ /* Brand — for "in progress under our system" / featured states */
121
+ .pill.brand { background: var(--color-background-selected); color: var(--color-foreground-accent); border-color: color-mix(in srgb, var(--color-foreground-accent) 22%, transparent); }
122
+
123
+
124
+ /* ----------------------------------------------------------------
125
+ Style modifiers
126
+ .solid — filled (use sparingly, for very high salience)
127
+ .outline — transparent bg, color from variant
128
+ ---------------------------------------------------------------- */
129
+ .pill.solid.success { background: var(--color-success-500); color: var(--color-pure-white); border-color: transparent; }
130
+ .pill.solid.warning { background: var(--color-warning-500); color: var(--color-ink-base); border-color: transparent; }
131
+ .pill.solid.danger { background: var(--color-danger-500); color: var(--color-pure-white); border-color: transparent; }
132
+ .pill.solid.info { background: var(--color-info-500); color: var(--color-pure-white); border-color: transparent; }
133
+ .pill.solid.neutral { background: var(--color-neutral-700); color: var(--color-pure-white); border-color: transparent; }
134
+ .pill.solid.brand { background: var(--color-brand-secondary-500); color: var(--color-foreground-on-solid); border-color: transparent; }
135
+ .pill.solid > .dot { background: currentColor; }
136
+
137
+ .pill.outline.success { background: transparent; color: var(--color-feedback-success-foreground); border-color: var(--color-success-500); }
138
+ .pill.outline.warning { background: transparent; color: var(--color-feedback-warning-foreground); border-color: var(--color-warning-500); }
139
+ .pill.outline.danger { background: transparent; color: var(--color-feedback-danger-foreground); border-color: var(--color-danger-500); }
140
+ .pill.outline.info { background: transparent; color: var(--color-feedback-info-foreground); border-color: var(--color-info-500); }
141
+ .pill.outline.neutral { background: transparent; color: var(--color-foreground-secondary); border-color: var(--color-border-strong); }
142
+ .pill.outline.brand { background: transparent; color: var(--color-foreground-accent); border-color: var(--color-brand-secondary-500); }
143
+
144
+
145
+ /* ----------------------------------------------------------------
146
+ Interactive — for filter chips / clickable state pills
147
+ ---------------------------------------------------------------- */
148
+ .pill.interactive { cursor: pointer; }
149
+ .pill.interactive:hover {
150
+ border-color: color-mix(in srgb, currentColor 50%, transparent);
151
+ }
152
+ .pill.interactive:focus-visible {
153
+ outline: none;
154
+ box-shadow: var(--shadow-focus);
155
+ }
156
+ .pill.interactive[aria-pressed="true"],
157
+ .pill.interactive.is-selected {
158
+ background: var(--color-foreground-accent);
159
+ color: var(--color-foreground-on-solid);
160
+ border-color: var(--color-foreground-accent);
161
+ }
162
+ .pill.interactive[aria-pressed="true"] > .dot,
163
+ .pill.interactive.is-selected > .dot { background: currentColor; }
164
+
165
+
166
+ /* ----------------------------------------------------------------
167
+ On inverse — pills over dark surfaces
168
+ ---------------------------------------------------------------- */
169
+ .pill.success.on-inverse {
170
+ background: color-mix(in srgb, var(--color-success-500) 18%, transparent);
171
+ color: var(--color-feedback-success-foreground-on-inverse);
172
+ border-color: color-mix(in srgb, var(--color-success-500) 38%, transparent);
173
+ }
174
+ .pill.warning.on-inverse {
175
+ background: color-mix(in srgb, var(--color-warning-500) 18%, transparent);
176
+ color: var(--color-feedback-warning-foreground-on-inverse);
177
+ border-color: color-mix(in srgb, var(--color-warning-500) 38%, transparent);
178
+ }
179
+ .pill.danger.on-inverse {
180
+ background: color-mix(in srgb, var(--color-danger-500) 18%, transparent);
181
+ color: var(--color-feedback-danger-foreground-on-inverse);
182
+ border-color: color-mix(in srgb, var(--color-danger-500) 38%, transparent);
183
+ }
184
+ .pill.info.on-inverse {
185
+ background: color-mix(in srgb, var(--color-info-500) 18%, transparent);
186
+ color: var(--color-feedback-info-foreground-on-inverse, var(--color-info-100));
187
+ border-color: color-mix(in srgb, var(--color-info-500) 38%, transparent);
188
+ }
189
+ .pill.neutral.on-inverse {
190
+ background: var(--color-background-inverse-subtle);
191
+ color: var(--color-foreground-inverse-muted);
192
+ border-color: var(--color-border-inverse);
193
+ }
194
+ .pill.brand.on-inverse {
195
+ background: color-mix(in srgb, var(--color-brand-accent-500) 18%, transparent);
196
+ color: var(--color-brand-accent-300, var(--color-brand-accent-500));
197
+ border-color: color-mix(in srgb, var(--color-brand-accent-500) 38%, transparent);
198
+ }
199
+
200
+
201
+ /* Disabled */
202
+ .pill[aria-disabled="true"],
203
+ .pill:disabled {
204
+ opacity: 0.5;
205
+ cursor: not-allowed;
206
+ pointer-events: none;
207
+ }