@attrus-ds/core 0.2.0 → 1.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.
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 +713 -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 +66 -64
@@ -1,602 +1,602 @@
1
- /* ============================================================
2
- TABLES & DATA GRIDS — ATTRUS Design System
3
- Component CSS — pure tokens, no hardcoded values.
4
-
5
- Anatomy (vertical stack):
6
- [.dt-wrap] container card
7
- [.dt-toolbar] top — count + filters + actions
8
- [.dt] the <table>
9
- [thead > tr > th] overline column headers
10
- [tbody > tr.hov] hoverable data row
11
- [td] cell — text / num / status / actions
12
- [.dt-pagination] bottom — page nav + range
13
-
14
- Sizes:
15
- .dt--sm compact — 8 / 12 padding, fs-xs body, fs-xxs head
16
- default standard — 12 / 16 padding, fs-md body, fs-xxs head
17
- .dt--lg spacious — 16 / 20 padding, fs-md body, fs-xs head
18
-
19
- Density helpers:
20
- .dt--zebra alternating row backgrounds
21
- .dt--sticky thead sticks to top while scrolling
22
- .dt--bordered vertical column borders
23
-
24
- Cell helpers:
25
- .dt-cell-stack primary line + sub line
26
- .dt-num right-aligned, tabular numerals
27
- .dt-id monospace identifier
28
- .dt-actions trailing action cluster
29
- .dt-th-sort sortable header (cursor + chevron)
30
-
31
- Row states:
32
- .is-selected blue tint, persistent
33
- .is-muted dimmed (cancelled, returned)
34
- .is-error danger tint
35
-
36
- Special rows:
37
- .dt-empty zero-state inside <tbody>
38
- .dt-skeleton loading row placeholder
39
- .dt-row-divider group separator
40
-
41
- Inverse:
42
- .dt.on-inverse / .dark .dt
43
-
44
- Responsive:
45
- .dt-responsive wrapper — collapses rows to label:value
46
- cards below 560px (container query). Each
47
- <td> needs data-label="…". See section 11.
48
- ============================================================ */
49
-
50
-
51
- /* ----------------------------------------------------------------
52
- 1. WRAPPER + TOOLBAR + PAGINATION (the surrounding card)
53
- ---------------------------------------------------------------- */
54
- .dt-wrap {
55
- background: var(--color-background-surface);
56
- border: 1px solid var(--color-border-default);
57
- border-radius: var(--radius-md);
58
- overflow: hidden;
59
- box-shadow: var(--shadow-xs);
60
- }
61
-
62
- .dt-toolbar {
63
- display: flex;
64
- align-items: center;
65
- gap: var(--space-4);
66
- padding: var(--space-4) var(--space-6);
67
- min-height: 53px;
68
- box-sizing: border-box;
69
- border-bottom: 1px solid var(--color-border-subtle);
70
- background: var(--color-background-surface);
71
- font-family: var(--font-sans);
72
- font-size: var(--fs-sm);
73
- color: var(--color-foreground-secondary);
74
- }
75
- .dt-toolbar .count {
76
- color: var(--color-foreground-default);
77
- font-weight: var(--w-semibold);
78
- }
79
- .dt-toolbar .count .total {
80
- color: var(--color-foreground-muted);
81
- font-weight: var(--w-regular);
82
- margin-left: var(--space-2);
83
- }
84
- .dt-toolbar .spacer { flex: 1; }
85
- .dt-toolbar .group-actions {
86
- display: inline-flex;
87
- align-items: center;
88
- gap: var(--space-2);
89
- }
90
-
91
- .dt-toolbar .helper {
92
- font-size: var(--fs-xs);
93
- color: var(--color-foreground-muted);
94
- }
95
-
96
- .dt-pagination {
97
- display: flex;
98
- align-items: center;
99
- gap: var(--space-4);
100
- padding: var(--space-3) var(--space-6);
101
- border-top: 1px solid var(--color-border-subtle);
102
- background: var(--color-background-surface);
103
- font-family: var(--font-sans);
104
- font-size: var(--fs-sm);
105
- color: var(--color-foreground-secondary);
106
- }
107
- .dt-pagination .range {
108
- font-family: var(--font-mono);
109
- font-size: var(--fs-xs);
110
- color: var(--color-foreground-muted);
111
- }
112
- .dt-pagination .pager {
113
- margin-left: auto;
114
- display: inline-flex;
115
- align-items: center;
116
- gap: var(--space-2);
117
- }
118
- .dt-pagination .page-btn {
119
- display: inline-flex;
120
- align-items: center;
121
- justify-content: center;
122
- height: 28px;
123
- min-width: 28px;
124
- padding: 0 var(--space-3);
125
- border: 1px solid var(--color-border-default);
126
- background: var(--color-background-surface);
127
- border-radius: var(--radius-sm);
128
- font-family: var(--font-mono);
129
- font-size: var(--fs-xs);
130
- font-weight: var(--w-semibold);
131
- color: var(--color-foreground-secondary);
132
- cursor: pointer;
133
- transition:
134
- background var(--transition-fast),
135
- border-color var(--transition-fast),
136
- color var(--transition-fast);
137
- }
138
- .dt-pagination .page-btn:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
139
- .dt-pagination .page-btn:disabled { opacity: 0.4; cursor: not-allowed; }
140
- .dt-pagination .page-btn.is-current {
141
- background: color-mix(in srgb, var(--color-brand-accent-500) 14%, transparent);
142
- border-color: color-mix(in srgb, var(--color-brand-accent-500) 36%, transparent);
143
- color: var(--color-foreground-accent);
144
- }
145
- .dt-pagination .page-btn > i, .dt-pagination .page-btn > svg,
146
- .dt-pagination .page-btn > svg { width: 12px; height: 12px; stroke-width: var(--icon-stroke); }
147
-
148
-
149
- /* ----------------------------------------------------------------
150
- 2. TABLE BASE
151
- ---------------------------------------------------------------- */
152
- .dt {
153
- width: 100%;
154
- border-collapse: collapse;
155
- font-family: var(--font-sans);
156
- font-size: var(--fs-md);
157
- color: var(--color-foreground-default);
158
- /* Numbers should align across rows by default — opt-out per cell with .dt-no-tab */
159
- font-variant-numeric: tabular-nums;
160
- }
161
- .dt-no-tab { font-variant-numeric: normal; }
162
-
163
- /* ----------------------------------------------------------------
164
- 3. HEAD
165
- ---------------------------------------------------------------- */
166
- .dt thead th {
167
- font-family: var(--font-mono);
168
- font-size: var(--fs-xxs);
169
- font-weight: var(--w-semibold);
170
- color: var(--color-foreground-muted);
171
- text-transform: uppercase;
172
- letter-spacing: var(--ls-caps);
173
- text-align: left;
174
- padding: var(--space-3) var(--space-5);
175
- background: var(--color-background-surface);
176
- border-bottom: 1px solid var(--color-border-subtle);
177
- white-space: nowrap;
178
- vertical-align: middle;
179
- }
180
- .dt thead th.right { text-align: right; }
181
- .dt thead th.center { text-align: center; }
182
-
183
- /* Sortable header */
184
- .dt-th-sort {
185
- cursor: pointer;
186
- user-select: none;
187
- transition: color var(--transition-fast);
188
- }
189
- .dt-th-sort:hover { color: var(--color-foreground-default); }
190
- .dt-th-sort .chev {
191
- display: inline-flex;
192
- width: 10px;
193
- height: 10px;
194
- margin-left: var(--space-2);
195
- vertical-align: -1px;
196
- color: var(--color-foreground-placeholder);
197
- stroke-width: var(--icon-stroke-bold);
198
- transition: color var(--transition-fast), transform var(--transition-fast);
199
- }
200
- .dt-th-sort.is-asc .chev { color: var(--color-foreground-accent); transform: rotate(180deg); }
201
- .dt-th-sort.is-desc .chev { color: var(--color-foreground-accent); }
202
-
203
- /* ----------------------------------------------------------------
204
- 4. BODY ROWS
205
- ---------------------------------------------------------------- */
206
- .dt tbody tr {
207
- border-bottom: 1px solid var(--color-border-subtle);
208
- transition: background var(--transition-fast);
209
- }
210
- .dt tbody tr:last-child { border-bottom: 0; }
211
-
212
- .dt tbody tr.hov:hover,
213
- .dt tbody tr.is-clickable:hover { background: var(--color-background-subtle); cursor: pointer; }
214
-
215
- .dt tbody tr.is-selected,
216
- .dt tbody tr.is-selected:hover { background: var(--color-background-selected); }
217
-
218
- .dt tbody tr.is-muted td,
219
- .dt tbody tr.is-muted .dt-cell-stack > .sub { opacity: 0.55; }
220
-
221
- .dt tbody tr.is-error { background: color-mix(in srgb, var(--color-feedback-danger-background) 60%, transparent); }
222
- .dt tbody tr.is-error:hover { background: var(--color-feedback-danger-background); }
223
-
224
-
225
- /* ----------------------------------------------------------------
226
- 5. CELLS
227
- ---------------------------------------------------------------- */
228
- .dt tbody td {
229
- padding: var(--space-4) var(--space-5);
230
- font-size: var(--fs-md);
231
- color: var(--color-foreground-default);
232
- vertical-align: middle;
233
- }
234
- .dt tbody td.right { text-align: right; }
235
- .dt tbody td.center { text-align: center; }
236
-
237
- /* Common cell patterns */
238
- .dt-cell-stack {
239
- display: flex;
240
- flex-direction: column;
241
- gap: 2px;
242
- line-height: var(--lh-snug);
243
- min-width: 0;
244
- }
245
- .dt-cell-stack > .pri {
246
- font-size: var(--fs-md);
247
- font-weight: var(--w-semibold);
248
- color: var(--color-foreground-default);
249
- white-space: nowrap;
250
- overflow: hidden;
251
- text-overflow: ellipsis;
252
- }
253
- .dt-cell-stack > .sub {
254
- font-size: var(--fs-xs);
255
- color: var(--color-foreground-muted);
256
- white-space: nowrap;
257
- }
258
- .dt-cell-stack > .sub.mono {
259
- font-family: var(--font-mono);
260
- font-size: var(--fs-xs);
261
- }
262
-
263
- /* Lead avatar / icon + stacked label */
264
- .dt-cell-lead {
265
- display: flex;
266
- align-items: center;
267
- gap: var(--space-3);
268
- min-width: 0;
269
- }
270
- .dt-cell-lead > .ic-tile {
271
- width: 36px;
272
- height: 36px;
273
- border-radius: var(--radius-md);
274
- background: var(--color-background-subtle);
275
- border: 1px solid var(--color-border-subtle);
276
- display: inline-flex;
277
- align-items: center;
278
- justify-content: center;
279
- flex-shrink: 0;
280
- color: var(--color-foreground-secondary);
281
- }
282
- .dt-cell-lead > .ic-tile.tone-success { background: var(--color-feedback-success-background); border-color: var(--color-feedback-success-border); color: var(--color-feedback-success-foreground); }
283
- .dt-cell-lead > .ic-tile.tone-info { background: var(--color-feedback-info-background); border-color: var(--color-feedback-info-border); color: var(--color-feedback-info-foreground); }
284
- .dt-cell-lead > .ic-tile.tone-warning { background: var(--color-feedback-warning-background); border-color: var(--color-feedback-warning-border); color: var(--color-feedback-warning-foreground); }
285
- .dt-cell-lead > .ic-tile.tone-danger { background: var(--color-feedback-danger-background); border-color: var(--color-feedback-danger-border); color: var(--color-feedback-danger-foreground); }
286
- .dt-cell-lead > .ic-tile > i, .dt-cell-lead > .ic-tile > svg,
287
- .dt-cell-lead > .ic-tile > svg {
288
- width: var(--icon-md);
289
- height: var(--icon-md);
290
- stroke-width: var(--icon-stroke);
291
- }
292
- .dt-cell-lead > .ic-round {
293
- width: 26px; height: 26px; border-radius: var(--radius-pill);
294
- display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
295
- background: var(--color-background-subtle); color: var(--color-foreground-secondary);
296
- }
297
- .dt-cell-lead > .ic-round.tone-success { background: var(--color-feedback-success-background); color: var(--color-feedback-success-foreground); }
298
- .dt-cell-lead > .ic-round.tone-info { background: var(--color-feedback-info-background); color: var(--color-feedback-info-foreground); }
299
- .dt-cell-lead > .ic-round.tone-warning { background: var(--color-feedback-warning-background); color: var(--color-feedback-warning-foreground); }
300
- .dt-cell-lead > .ic-round.tone-danger { background: var(--color-feedback-danger-background); color: var(--color-feedback-danger-foreground); }
301
- .dt-cell-lead > .ic-round > i, .dt-cell-lead > .ic-round > svg,
302
- .dt-cell-lead > .ic-round > svg { width: var(--icon-sm); height: var(--icon-sm); stroke-width: var(--icon-stroke-bold); }
303
-
304
- /* Numbers — explicit class wins over per-cell .right alignment */
305
- .dt-num {
306
- font-variant-numeric: tabular-nums;
307
- font-feature-settings: 'tnum' on, 'lnum' on;
308
- text-align: right;
309
- white-space: nowrap;
310
- letter-spacing: -0.01em;
311
- }
312
- .dt-num .ccy {
313
- color: var(--color-foreground-muted);
314
- font-weight: var(--w-regular);
315
- margin-right: var(--space-2);
316
- font-size: var(--fs-sm);
317
- }
318
- .dt-num.bold { font-weight: var(--w-bold); font-size: var(--fs-base); }
319
- .dt-num.delta-pos { color: var(--color-feedback-success-foreground); }
320
- .dt-num.delta-neg { color: var(--color-feedback-danger-foreground); }
321
-
322
- /* IDs / hashes */
323
- .dt-id {
324
- font-family: var(--font-mono);
325
- font-size: var(--fs-xs);
326
- color: var(--color-foreground-muted);
327
- white-space: nowrap;
328
- }
329
-
330
- /* Trailing actions cluster */
331
- .dt-actions {
332
- display: inline-flex;
333
- align-items: center;
334
- gap: var(--space-2);
335
- justify-content: flex-end;
336
- }
337
- .dt-actions > .chev {
338
- width: var(--icon-sm); height: var(--icon-sm);
339
- stroke-width: var(--icon-stroke);
340
- color: var(--color-foreground-muted);
341
- transition: color var(--transition-fast), transform var(--transition-fast);
342
- }
343
- .dt tbody tr.hov:hover .dt-actions > .chev,
344
- .dt tbody tr.is-clickable:hover .dt-actions > .chev {
345
- color: var(--color-foreground-default);
346
- transform: translateX(2px);
347
- }
348
-
349
- /* Selection checkbox column — narrow */
350
- .dt th.col-select,
351
- .dt td.col-select {
352
- width: 36px;
353
- padding-left: var(--space-5);
354
- padding-right: 0;
355
- }
356
-
357
-
358
- /* ----------------------------------------------------------------
359
- 6. SIZES
360
- ---------------------------------------------------------------- */
361
- .dt--sm thead th { padding: var(--space-2) var(--space-4); }
362
- .dt--sm tbody td { padding: var(--space-3) var(--space-4); font-size: var(--fs-sm); }
363
- .dt--sm .dt-cell-stack > .pri { font-size: var(--fs-sm); }
364
- .dt--sm .dt-cell-stack > .sub { font-size: var(--fs-xxs); }
365
- .dt--sm .dt-cell-lead > .ic-tile { width: 28px; height: 28px; border-radius: var(--radius-sm); }
366
- .dt--sm .dt-cell-lead > .ic-tile > i, .dt--sm .dt-cell-lead > .ic-tile > svg,
367
- .dt--sm .dt-cell-lead > .ic-tile > svg { width: var(--icon-sm); height: var(--icon-sm); }
368
-
369
- .dt--lg thead th { padding: var(--space-4) var(--space-6); font-size: var(--fs-xs); }
370
- .dt--lg tbody td { padding: var(--space-5) var(--space-6); font-size: var(--fs-base); }
371
- .dt--lg .dt-cell-stack > .pri { font-size: var(--fs-base); }
372
- .dt--lg .dt-cell-lead > .ic-tile { width: 40px; height: 40px; }
373
-
374
-
375
- /* ----------------------------------------------------------------
376
- 7. DENSITY HELPERS
377
- ---------------------------------------------------------------- */
378
- /* Zebra — alternating bg */
379
- .dt--zebra tbody tr:nth-child(even):not(.is-selected):not(:hover) {
380
- background: color-mix(in srgb, var(--color-background-subtle) 55%, var(--color-background-surface));
381
- }
382
-
383
- /* Sticky head */
384
- .dt--sticky thead th {
385
- position: sticky;
386
- top: 0;
387
- z-index: 1;
388
- /* Solid bg so it covers content scrolling underneath */
389
- background: var(--color-background-surface);
390
- }
391
-
392
- /* Vertical column borders */
393
- .dt--bordered th + th,
394
- .dt--bordered td + td {
395
- border-left: 1px solid var(--color-border-subtle);
396
- }
397
-
398
-
399
- /* ----------------------------------------------------------------
400
- 8. EMPTY + SKELETON
401
- ---------------------------------------------------------------- */
402
- .dt-empty td {
403
- padding: var(--space-12) var(--space-6);
404
- text-align: center;
405
- color: var(--color-foreground-muted);
406
- background: var(--color-background-canvas);
407
- }
408
- .dt-empty .ic {
409
- width: 32px; height: 32px;
410
- stroke-width: var(--icon-stroke-thin);
411
- color: var(--color-foreground-placeholder);
412
- margin: 0 auto var(--space-3);
413
- display: block;
414
- }
415
- .dt-empty .ttl {
416
- display: block;
417
- font-size: var(--fs-base);
418
- font-weight: var(--w-semibold);
419
- color: var(--color-foreground-default);
420
- margin-bottom: var(--space-2);
421
- }
422
- .dt-empty .sub {
423
- display: block;
424
- font-size: var(--fs-sm);
425
- color: var(--color-foreground-muted);
426
- max-width: 48ch;
427
- margin: 0 auto;
428
- line-height: var(--lh-relaxed);
429
- }
430
-
431
- /* Skeleton row — shimmer */
432
- @keyframes dt-shimmer {
433
- 0% { background-position: -240px 0; }
434
- 100% { background-position: 240px 0; }
435
- }
436
- .dt-skeleton td > span {
437
- display: inline-block;
438
- height: 12px;
439
- border-radius: var(--radius-2xs);
440
- /* theme-aware: border tokens are light-gray hairlines in light and
441
- white-alpha in dark — raw neutral-50/100 read near-white on ink */
442
- background:
443
- linear-gradient(90deg,
444
- var(--color-border-default) 0%,
445
- var(--color-border-subtle) 40%,
446
- var(--color-border-default) 80%);
447
- background-size: 480px 100%;
448
- animation: dt-shimmer 1.4s var(--ease-linear) infinite;
449
- }
450
- .dt-skeleton td > span.w-md { width: 140px; }
451
- .dt-skeleton td > span.w-lg { width: 220px; }
452
- .dt-skeleton td > span.w-sm { width: 80px; }
453
-
454
-
455
- /* ----------------------------------------------------------------
456
- 9. GROUP / SECTION ROW
457
- ---------------------------------------------------------------- */
458
- .dt tbody tr.dt-row-divider td {
459
- background: var(--color-background-subtle);
460
- padding: var(--space-3) var(--space-5);
461
- font-family: var(--font-mono);
462
- font-size: var(--fs-xxs);
463
- font-weight: var(--w-regular);
464
- color: var(--color-foreground-muted);
465
- letter-spacing: var(--ls-label);
466
- border-top: 1px solid var(--color-border-subtle);
467
- }
468
-
469
-
470
- /* ----------------------------------------------------------------
471
- 10. INVERSE — dark surfaces
472
- ---------------------------------------------------------------- */
473
- .dt.on-inverse,
474
- .dark .dt {
475
- color: var(--color-foreground-inverse-default);
476
- }
477
- .dt.on-inverse thead th,
478
- .dark .dt thead th {
479
- background: var(--color-background-inverse);
480
- color: var(--color-foreground-inverse-muted);
481
- border-bottom-color: var(--color-border-inverse);
482
- }
483
- .dt.on-inverse tbody tr,
484
- .dark .dt tbody tr {
485
- border-bottom-color: var(--color-border-inverse);
486
- }
487
- .dt.on-inverse tbody tr.hov:hover,
488
- .dark .dt tbody tr.hov:hover {
489
- background: color-mix(in srgb, var(--color-pure-white) 4%, transparent);
490
- }
491
- .dt.on-inverse tbody tr.is-selected,
492
- .dark .dt tbody tr.is-selected {
493
- background: var(--color-background-inverse-selected);
494
- }
495
- .dt.on-inverse tbody td,
496
- .dark .dt tbody td { color: var(--color-foreground-inverse-default); }
497
- .dt.on-inverse .dt-id,
498
- .dark .dt .dt-id { color: var(--color-foreground-inverse-muted); }
499
- .dt.on-inverse .dt-cell-stack > .sub,
500
- .dark .dt .dt-cell-stack > .sub { color: var(--color-foreground-inverse-muted); }
501
- .dt.on-inverse .dt-cell-lead > .ic-tile,
502
- .dark .dt .dt-cell-lead > .ic-tile {
503
- background: color-mix(in srgb, var(--color-pure-white) 6%, transparent);
504
- border-color: var(--color-border-inverse);
505
- color: var(--color-foreground-inverse-secondary);
506
- }
507
-
508
-
509
- /* ----------------------------------------------------------------
510
- 11. RESPONSIVE — stacked cards on narrow widths
511
- --------------------------------------------------------------
512
-
513
- Two strategies, pick per table:
514
-
515
- A. SCROLL (default) — keep the grid, let it scroll sideways.
516
- Wrap .dt in an element with overflow-x:auto. Best for
517
- comparison-heavy / numeric tables where column alignment
518
- is the point (ledgers, FX rates).
519
-
520
- B. STACK (.dt-responsive) — collapse each row into a card,
521
- label : value per field. Best for action-oriented record
522
- lists (transactions, counterparties) the user taps into.
523
-
524
- Uses CONTAINER queries (not viewport) so the same component
525
- reflows correctly inside a drawer, split-pane or phone frame —
526
- not just at the page edge. Each <td> needs a data-label="…".
527
- ---------------------------------------------------------------- */
528
- .dt-responsive { container-type: inline-size; }
529
-
530
- @container (max-width: 560px) {
531
- /* Drop the header row — labels move inline via data-label */
532
- .dt-responsive .dt thead { display: none; }
533
-
534
- .dt-responsive .dt,
535
- .dt-responsive .dt tbody,
536
- .dt-responsive .dt tr,
537
- .dt-responsive .dt td { display: block; width: 100%; box-sizing: border-box; }
538
-
539
- /* Each row becomes a card */
540
- .dt-responsive .dt tbody tr {
541
- border: 1px solid var(--color-border-default);
542
- border-radius: var(--radius-md);
543
- background: var(--color-background-surface);
544
- padding: var(--space-2) var(--space-4);
545
- margin-bottom: var(--space-3);
546
- box-shadow: var(--shadow-xs);
547
- }
548
- .dt-responsive .dt tbody tr:last-child { margin-bottom: 0; border-bottom: 1px solid var(--color-border-default); }
549
-
550
- /* Each cell becomes a label : value line */
551
- .dt-responsive .dt tbody td {
552
- display: flex;
553
- align-items: center;
554
- justify-content: space-between;
555
- gap: var(--space-4);
556
- padding: var(--space-3) 0;
557
- border-bottom: 1px solid var(--color-border-subtle);
558
- text-align: right;
559
- white-space: normal;
560
- min-width: 0;
561
- }
562
- .dt-responsive .dt tbody td > * { min-width: 0; }
563
- .dt-responsive .dt tbody td:last-child { border-bottom: 0; }
564
-
565
- .dt-responsive .dt tbody td::before {
566
- content: attr(data-label);
567
- flex-shrink: 0;
568
- font-family: var(--font-mono);
569
- font-size: var(--fs-xxs);
570
- font-weight: var(--w-semibold);
571
- text-transform: uppercase;
572
- letter-spacing: var(--ls-caps);
573
- color: var(--color-foreground-muted);
574
- text-align: left;
575
- }
576
- /* Cells with no label render full-width (e.g. a lead/title row) */
577
- .dt-responsive .dt tbody td[data-label=""]::before,
578
- .dt-responsive .dt tbody td:not([data-label])::before { content: none; }
579
-
580
- /* Promote the first cell to a card title */
581
- .dt-responsive .dt tbody td.dt-card-title {
582
- justify-content: flex-start;
583
- text-align: left;
584
- font-size: var(--fs-base);
585
- font-weight: var(--w-semibold);
586
- padding-top: var(--space-3);
587
- }
588
- /* The lead block (avatar + name + country/doc) reads left-to-right */
589
- .dt-responsive .dt tbody td.dt-card-title .dt-cell-stack { text-align: left; align-items: flex-start; }
590
-
591
- /* Right-aligned numbers stay flush right next to their label */
592
- .dt-responsive .dt-num { text-align: right; }
593
-
594
- /* Selection / action columns sit inline like any other field */
595
- .dt-responsive .dt td.col-select { width: 100%; }
596
-
597
- /* Empty + skeleton rows shouldn't become cards */
598
- .dt-responsive .dt tbody tr.dt-empty,
599
- .dt-responsive .dt tbody tr.dt-skeleton { border: 0; box-shadow: none; padding: 0; }
600
- .dt-responsive .dt tbody tr.dt-empty td { border: 0; text-align: center; }
601
- .dt-responsive .dt tbody tr.dt-empty td::before { content: none; }
602
- }
1
+ /* ============================================================
2
+ TABLES & DATA GRIDS — ATTRUS Design System
3
+ Component CSS — pure tokens, no hardcoded values.
4
+
5
+ Anatomy (vertical stack):
6
+ [.dt-wrap] container card
7
+ [.dt-toolbar] top — count + filters + actions
8
+ [.dt] the <table>
9
+ [thead > tr > th] overline column headers
10
+ [tbody > tr.hov] hoverable data row
11
+ [td] cell — text / num / status / actions
12
+ [.dt-pagination] bottom — page nav + range
13
+
14
+ Sizes:
15
+ .dt--sm compact — 8 / 12 padding, fs-xs body, fs-xxs head
16
+ default standard — 12 / 16 padding, fs-md body, fs-xxs head
17
+ .dt--lg spacious — 16 / 20 padding, fs-md body, fs-xs head
18
+
19
+ Density helpers:
20
+ .dt--zebra alternating row backgrounds
21
+ .dt--sticky thead sticks to top while scrolling
22
+ .dt--bordered vertical column borders
23
+
24
+ Cell helpers:
25
+ .dt-cell-stack primary line + sub line
26
+ .dt-num right-aligned, tabular numerals
27
+ .dt-id monospace identifier
28
+ .dt-actions trailing action cluster
29
+ .dt-th-sort sortable header (cursor + chevron)
30
+
31
+ Row states:
32
+ .is-selected blue tint, persistent
33
+ .is-muted dimmed (cancelled, returned)
34
+ .is-error danger tint
35
+
36
+ Special rows:
37
+ .dt-empty zero-state inside <tbody>
38
+ .dt-skeleton loading row placeholder
39
+ .dt-row-divider group separator
40
+
41
+ Inverse:
42
+ .dt.on-inverse / .dark .dt
43
+
44
+ Responsive:
45
+ .dt-responsive wrapper — collapses rows to label:value
46
+ cards below 560px (container query). Each
47
+ <td> needs data-label="…". See section 11.
48
+ ============================================================ */
49
+
50
+
51
+ /* ----------------------------------------------------------------
52
+ 1. WRAPPER + TOOLBAR + PAGINATION (the surrounding card)
53
+ ---------------------------------------------------------------- */
54
+ .dt-wrap {
55
+ background: var(--color-background-surface);
56
+ border: 1px solid var(--color-border-default);
57
+ border-radius: var(--radius-md);
58
+ overflow: hidden;
59
+ box-shadow: var(--shadow-xs);
60
+ }
61
+
62
+ .dt-toolbar {
63
+ display: flex;
64
+ align-items: center;
65
+ gap: var(--space-4);
66
+ padding: var(--space-4) var(--space-6);
67
+ min-height: 53px;
68
+ box-sizing: border-box;
69
+ border-bottom: 1px solid var(--color-border-subtle);
70
+ background: var(--color-background-surface);
71
+ font-family: var(--font-sans);
72
+ font-size: var(--fs-sm);
73
+ color: var(--color-foreground-secondary);
74
+ }
75
+ .dt-toolbar .count {
76
+ color: var(--color-foreground-default);
77
+ font-weight: var(--w-semibold);
78
+ }
79
+ .dt-toolbar .count .total {
80
+ color: var(--color-foreground-muted);
81
+ font-weight: var(--w-regular);
82
+ margin-left: var(--space-2);
83
+ }
84
+ .dt-toolbar .spacer { flex: 1; }
85
+ .dt-toolbar .group-actions {
86
+ display: inline-flex;
87
+ align-items: center;
88
+ gap: var(--space-2);
89
+ }
90
+
91
+ .dt-toolbar .helper {
92
+ font-size: var(--fs-xs);
93
+ color: var(--color-foreground-muted);
94
+ }
95
+
96
+ .dt-pagination {
97
+ display: flex;
98
+ align-items: center;
99
+ gap: var(--space-4);
100
+ padding: var(--space-3) var(--space-6);
101
+ border-top: 1px solid var(--color-border-subtle);
102
+ background: var(--color-background-surface);
103
+ font-family: var(--font-sans);
104
+ font-size: var(--fs-sm);
105
+ color: var(--color-foreground-secondary);
106
+ }
107
+ .dt-pagination .range {
108
+ font-family: var(--font-mono);
109
+ font-size: var(--fs-xs);
110
+ color: var(--color-foreground-muted);
111
+ }
112
+ .dt-pagination .pager {
113
+ margin-left: auto;
114
+ display: inline-flex;
115
+ align-items: center;
116
+ gap: var(--space-2);
117
+ }
118
+ .dt-pagination .page-btn {
119
+ display: inline-flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ height: 28px;
123
+ min-width: 28px;
124
+ padding: 0 var(--space-3);
125
+ border: 1px solid var(--color-border-default);
126
+ background: var(--color-background-surface);
127
+ border-radius: var(--radius-sm);
128
+ font-family: var(--font-mono);
129
+ font-size: var(--fs-xs);
130
+ font-weight: var(--w-semibold);
131
+ color: var(--color-foreground-secondary);
132
+ cursor: pointer;
133
+ transition:
134
+ background var(--transition-fast),
135
+ border-color var(--transition-fast),
136
+ color var(--transition-fast);
137
+ }
138
+ .dt-pagination .page-btn:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
139
+ .dt-pagination .page-btn:disabled { opacity: 0.4; cursor: not-allowed; }
140
+ .dt-pagination .page-btn.is-current {
141
+ background: color-mix(in srgb, var(--color-brand-accent-500) 14%, transparent);
142
+ border-color: color-mix(in srgb, var(--color-brand-accent-500) 36%, transparent);
143
+ color: var(--color-foreground-accent);
144
+ }
145
+ .dt-pagination .page-btn > i, .dt-pagination .page-btn > svg,
146
+ .dt-pagination .page-btn > svg { width: 12px; height: 12px; stroke-width: var(--icon-stroke); }
147
+
148
+
149
+ /* ----------------------------------------------------------------
150
+ 2. TABLE BASE
151
+ ---------------------------------------------------------------- */
152
+ .dt {
153
+ width: 100%;
154
+ border-collapse: collapse;
155
+ font-family: var(--font-sans);
156
+ font-size: var(--fs-md);
157
+ color: var(--color-foreground-default);
158
+ /* Numbers should align across rows by default — opt-out per cell with .dt-no-tab */
159
+ font-variant-numeric: tabular-nums;
160
+ }
161
+ .dt-no-tab { font-variant-numeric: normal; }
162
+
163
+ /* ----------------------------------------------------------------
164
+ 3. HEAD
165
+ ---------------------------------------------------------------- */
166
+ .dt thead th {
167
+ font-family: var(--font-mono);
168
+ font-size: var(--fs-xxs);
169
+ font-weight: var(--w-semibold);
170
+ color: var(--color-foreground-muted);
171
+ text-transform: uppercase;
172
+ letter-spacing: var(--ls-caps);
173
+ text-align: left;
174
+ padding: var(--space-3) var(--space-5);
175
+ background: var(--color-background-surface);
176
+ border-bottom: 1px solid var(--color-border-subtle);
177
+ white-space: nowrap;
178
+ vertical-align: middle;
179
+ }
180
+ .dt thead th.right { text-align: right; }
181
+ .dt thead th.center { text-align: center; }
182
+
183
+ /* Sortable header */
184
+ .dt-th-sort {
185
+ cursor: pointer;
186
+ user-select: none;
187
+ transition: color var(--transition-fast);
188
+ }
189
+ .dt-th-sort:hover { color: var(--color-foreground-default); }
190
+ .dt-th-sort .chev {
191
+ display: inline-flex;
192
+ width: 10px;
193
+ height: 10px;
194
+ margin-left: var(--space-2);
195
+ vertical-align: -1px;
196
+ color: var(--color-foreground-placeholder);
197
+ stroke-width: var(--icon-stroke-bold);
198
+ transition: color var(--transition-fast), transform var(--transition-fast);
199
+ }
200
+ .dt-th-sort.is-asc .chev { color: var(--color-foreground-accent); transform: rotate(180deg); }
201
+ .dt-th-sort.is-desc .chev { color: var(--color-foreground-accent); }
202
+
203
+ /* ----------------------------------------------------------------
204
+ 4. BODY ROWS
205
+ ---------------------------------------------------------------- */
206
+ .dt tbody tr {
207
+ border-bottom: 1px solid var(--color-border-subtle);
208
+ transition: background var(--transition-fast);
209
+ }
210
+ .dt tbody tr:last-child { border-bottom: 0; }
211
+
212
+ .dt tbody tr.hov:hover,
213
+ .dt tbody tr.is-clickable:hover { background: var(--color-background-subtle); cursor: pointer; }
214
+
215
+ .dt tbody tr.is-selected,
216
+ .dt tbody tr.is-selected:hover { background: var(--color-background-selected); }
217
+
218
+ .dt tbody tr.is-muted td,
219
+ .dt tbody tr.is-muted .dt-cell-stack > .sub { opacity: 0.55; }
220
+
221
+ .dt tbody tr.is-error { background: color-mix(in srgb, var(--color-feedback-danger-background) 60%, transparent); }
222
+ .dt tbody tr.is-error:hover { background: var(--color-feedback-danger-background); }
223
+
224
+
225
+ /* ----------------------------------------------------------------
226
+ 5. CELLS
227
+ ---------------------------------------------------------------- */
228
+ .dt tbody td {
229
+ padding: var(--space-4) var(--space-5);
230
+ font-size: var(--fs-md);
231
+ color: var(--color-foreground-default);
232
+ vertical-align: middle;
233
+ }
234
+ .dt tbody td.right { text-align: right; }
235
+ .dt tbody td.center { text-align: center; }
236
+
237
+ /* Common cell patterns */
238
+ .dt-cell-stack {
239
+ display: flex;
240
+ flex-direction: column;
241
+ gap: 2px;
242
+ line-height: var(--lh-snug);
243
+ min-width: 0;
244
+ }
245
+ .dt-cell-stack > .pri {
246
+ font-size: var(--fs-md);
247
+ font-weight: var(--w-semibold);
248
+ color: var(--color-foreground-default);
249
+ white-space: nowrap;
250
+ overflow: hidden;
251
+ text-overflow: ellipsis;
252
+ }
253
+ .dt-cell-stack > .sub {
254
+ font-size: var(--fs-xs);
255
+ color: var(--color-foreground-muted);
256
+ white-space: nowrap;
257
+ }
258
+ .dt-cell-stack > .sub.mono {
259
+ font-family: var(--font-mono);
260
+ font-size: var(--fs-xs);
261
+ }
262
+
263
+ /* Lead avatar / icon + stacked label */
264
+ .dt-cell-lead {
265
+ display: flex;
266
+ align-items: center;
267
+ gap: var(--space-3);
268
+ min-width: 0;
269
+ }
270
+ .dt-cell-lead > .ic-tile {
271
+ width: 36px;
272
+ height: 36px;
273
+ border-radius: var(--radius-md);
274
+ background: var(--color-background-subtle);
275
+ border: 1px solid var(--color-border-subtle);
276
+ display: inline-flex;
277
+ align-items: center;
278
+ justify-content: center;
279
+ flex-shrink: 0;
280
+ color: var(--color-foreground-secondary);
281
+ }
282
+ .dt-cell-lead > .ic-tile.tone-success { background: var(--color-feedback-success-background); border-color: var(--color-feedback-success-border); color: var(--color-feedback-success-foreground); }
283
+ .dt-cell-lead > .ic-tile.tone-info { background: var(--color-feedback-info-background); border-color: var(--color-feedback-info-border); color: var(--color-feedback-info-foreground); }
284
+ .dt-cell-lead > .ic-tile.tone-warning { background: var(--color-feedback-warning-background); border-color: var(--color-feedback-warning-border); color: var(--color-feedback-warning-foreground); }
285
+ .dt-cell-lead > .ic-tile.tone-danger { background: var(--color-feedback-danger-background); border-color: var(--color-feedback-danger-border); color: var(--color-feedback-danger-foreground); }
286
+ .dt-cell-lead > .ic-tile > i, .dt-cell-lead > .ic-tile > svg,
287
+ .dt-cell-lead > .ic-tile > svg {
288
+ width: var(--icon-md);
289
+ height: var(--icon-md);
290
+ stroke-width: var(--icon-stroke);
291
+ }
292
+ .dt-cell-lead > .ic-round {
293
+ width: 26px; height: 26px; border-radius: var(--radius-pill);
294
+ display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
295
+ background: var(--color-background-subtle); color: var(--color-foreground-secondary);
296
+ }
297
+ .dt-cell-lead > .ic-round.tone-success { background: var(--color-feedback-success-background); color: var(--color-feedback-success-foreground); }
298
+ .dt-cell-lead > .ic-round.tone-info { background: var(--color-feedback-info-background); color: var(--color-feedback-info-foreground); }
299
+ .dt-cell-lead > .ic-round.tone-warning { background: var(--color-feedback-warning-background); color: var(--color-feedback-warning-foreground); }
300
+ .dt-cell-lead > .ic-round.tone-danger { background: var(--color-feedback-danger-background); color: var(--color-feedback-danger-foreground); }
301
+ .dt-cell-lead > .ic-round > i, .dt-cell-lead > .ic-round > svg,
302
+ .dt-cell-lead > .ic-round > svg { width: var(--icon-sm); height: var(--icon-sm); stroke-width: var(--icon-stroke-bold); }
303
+
304
+ /* Numbers — explicit class wins over per-cell .right alignment */
305
+ .dt-num {
306
+ font-variant-numeric: tabular-nums;
307
+ font-feature-settings: 'tnum' on, 'lnum' on;
308
+ text-align: right;
309
+ white-space: nowrap;
310
+ letter-spacing: -0.01em;
311
+ }
312
+ .dt-num .ccy {
313
+ color: var(--color-foreground-muted);
314
+ font-weight: var(--w-regular);
315
+ margin-right: var(--space-2);
316
+ font-size: var(--fs-sm);
317
+ }
318
+ .dt-num.bold { font-weight: var(--w-bold); font-size: var(--fs-base); }
319
+ .dt-num.delta-pos { color: var(--color-feedback-success-foreground); }
320
+ .dt-num.delta-neg { color: var(--color-feedback-danger-foreground); }
321
+
322
+ /* IDs / hashes */
323
+ .dt-id {
324
+ font-family: var(--font-mono);
325
+ font-size: var(--fs-xs);
326
+ color: var(--color-foreground-muted);
327
+ white-space: nowrap;
328
+ }
329
+
330
+ /* Trailing actions cluster */
331
+ .dt-actions {
332
+ display: inline-flex;
333
+ align-items: center;
334
+ gap: var(--space-2);
335
+ justify-content: flex-end;
336
+ }
337
+ .dt-actions > .chev {
338
+ width: var(--icon-sm); height: var(--icon-sm);
339
+ stroke-width: var(--icon-stroke);
340
+ color: var(--color-foreground-muted);
341
+ transition: color var(--transition-fast), transform var(--transition-fast);
342
+ }
343
+ .dt tbody tr.hov:hover .dt-actions > .chev,
344
+ .dt tbody tr.is-clickable:hover .dt-actions > .chev {
345
+ color: var(--color-foreground-default);
346
+ transform: translateX(2px);
347
+ }
348
+
349
+ /* Selection checkbox column — narrow */
350
+ .dt th.col-select,
351
+ .dt td.col-select {
352
+ width: 36px;
353
+ padding-left: var(--space-5);
354
+ padding-right: 0;
355
+ }
356
+
357
+
358
+ /* ----------------------------------------------------------------
359
+ 6. SIZES
360
+ ---------------------------------------------------------------- */
361
+ .dt--sm thead th { padding: var(--space-2) var(--space-4); }
362
+ .dt--sm tbody td { padding: var(--space-3) var(--space-4); font-size: var(--fs-sm); }
363
+ .dt--sm .dt-cell-stack > .pri { font-size: var(--fs-sm); }
364
+ .dt--sm .dt-cell-stack > .sub { font-size: var(--fs-xxs); }
365
+ .dt--sm .dt-cell-lead > .ic-tile { width: 28px; height: 28px; border-radius: var(--radius-sm); }
366
+ .dt--sm .dt-cell-lead > .ic-tile > i, .dt--sm .dt-cell-lead > .ic-tile > svg,
367
+ .dt--sm .dt-cell-lead > .ic-tile > svg { width: var(--icon-sm); height: var(--icon-sm); }
368
+
369
+ .dt--lg thead th { padding: var(--space-4) var(--space-6); font-size: var(--fs-xs); }
370
+ .dt--lg tbody td { padding: var(--space-5) var(--space-6); font-size: var(--fs-base); }
371
+ .dt--lg .dt-cell-stack > .pri { font-size: var(--fs-base); }
372
+ .dt--lg .dt-cell-lead > .ic-tile { width: 40px; height: 40px; }
373
+
374
+
375
+ /* ----------------------------------------------------------------
376
+ 7. DENSITY HELPERS
377
+ ---------------------------------------------------------------- */
378
+ /* Zebra — alternating bg */
379
+ .dt--zebra tbody tr:nth-child(even):not(.is-selected):not(:hover) {
380
+ background: color-mix(in srgb, var(--color-background-subtle) 55%, var(--color-background-surface));
381
+ }
382
+
383
+ /* Sticky head */
384
+ .dt--sticky thead th {
385
+ position: sticky;
386
+ top: 0;
387
+ z-index: 1;
388
+ /* Solid bg so it covers content scrolling underneath */
389
+ background: var(--color-background-surface);
390
+ }
391
+
392
+ /* Vertical column borders */
393
+ .dt--bordered th + th,
394
+ .dt--bordered td + td {
395
+ border-left: 1px solid var(--color-border-subtle);
396
+ }
397
+
398
+
399
+ /* ----------------------------------------------------------------
400
+ 8. EMPTY + SKELETON
401
+ ---------------------------------------------------------------- */
402
+ .dt-empty td {
403
+ padding: var(--space-12) var(--space-6);
404
+ text-align: center;
405
+ color: var(--color-foreground-muted);
406
+ background: var(--color-background-canvas);
407
+ }
408
+ .dt-empty .ic {
409
+ width: 32px; height: 32px;
410
+ stroke-width: var(--icon-stroke-thin);
411
+ color: var(--color-foreground-placeholder);
412
+ margin: 0 auto var(--space-3);
413
+ display: block;
414
+ }
415
+ .dt-empty .ttl {
416
+ display: block;
417
+ font-size: var(--fs-base);
418
+ font-weight: var(--w-semibold);
419
+ color: var(--color-foreground-default);
420
+ margin-bottom: var(--space-2);
421
+ }
422
+ .dt-empty .sub {
423
+ display: block;
424
+ font-size: var(--fs-sm);
425
+ color: var(--color-foreground-muted);
426
+ max-width: 48ch;
427
+ margin: 0 auto;
428
+ line-height: var(--lh-relaxed);
429
+ }
430
+
431
+ /* Skeleton row — shimmer */
432
+ @keyframes dt-shimmer {
433
+ 0% { background-position: -240px 0; }
434
+ 100% { background-position: 240px 0; }
435
+ }
436
+ .dt-skeleton td > span {
437
+ display: inline-block;
438
+ height: 12px;
439
+ border-radius: var(--radius-2xs);
440
+ /* theme-aware: border tokens are light-gray hairlines in light and
441
+ white-alpha in dark — raw neutral-50/100 read near-white on ink */
442
+ background:
443
+ linear-gradient(90deg,
444
+ var(--color-border-default) 0%,
445
+ var(--color-border-subtle) 40%,
446
+ var(--color-border-default) 80%);
447
+ background-size: 480px 100%;
448
+ animation: dt-shimmer 1.4s var(--ease-linear) infinite;
449
+ }
450
+ .dt-skeleton td > span.w-md { width: 140px; }
451
+ .dt-skeleton td > span.w-lg { width: 220px; }
452
+ .dt-skeleton td > span.w-sm { width: 80px; }
453
+
454
+
455
+ /* ----------------------------------------------------------------
456
+ 9. GROUP / SECTION ROW
457
+ ---------------------------------------------------------------- */
458
+ .dt tbody tr.dt-row-divider td {
459
+ background: var(--color-background-subtle);
460
+ padding: var(--space-3) var(--space-5);
461
+ font-family: var(--font-mono);
462
+ font-size: var(--fs-xxs);
463
+ font-weight: var(--w-regular);
464
+ color: var(--color-foreground-muted);
465
+ letter-spacing: var(--ls-label);
466
+ border-top: 1px solid var(--color-border-subtle);
467
+ }
468
+
469
+
470
+ /* ----------------------------------------------------------------
471
+ 10. INVERSE — dark surfaces
472
+ ---------------------------------------------------------------- */
473
+ .dt.on-inverse,
474
+ .dark .dt {
475
+ color: var(--color-foreground-inverse-default);
476
+ }
477
+ .dt.on-inverse thead th,
478
+ .dark .dt thead th {
479
+ background: var(--color-background-inverse);
480
+ color: var(--color-foreground-inverse-muted);
481
+ border-bottom-color: var(--color-border-inverse);
482
+ }
483
+ .dt.on-inverse tbody tr,
484
+ .dark .dt tbody tr {
485
+ border-bottom-color: var(--color-border-inverse);
486
+ }
487
+ .dt.on-inverse tbody tr.hov:hover,
488
+ .dark .dt tbody tr.hov:hover {
489
+ background: color-mix(in srgb, var(--color-pure-white) 4%, transparent);
490
+ }
491
+ .dt.on-inverse tbody tr.is-selected,
492
+ .dark .dt tbody tr.is-selected {
493
+ background: var(--color-background-inverse-selected);
494
+ }
495
+ .dt.on-inverse tbody td,
496
+ .dark .dt tbody td { color: var(--color-foreground-inverse-default); }
497
+ .dt.on-inverse .dt-id,
498
+ .dark .dt .dt-id { color: var(--color-foreground-inverse-muted); }
499
+ .dt.on-inverse .dt-cell-stack > .sub,
500
+ .dark .dt .dt-cell-stack > .sub { color: var(--color-foreground-inverse-muted); }
501
+ .dt.on-inverse .dt-cell-lead > .ic-tile,
502
+ .dark .dt .dt-cell-lead > .ic-tile {
503
+ background: color-mix(in srgb, var(--color-pure-white) 6%, transparent);
504
+ border-color: var(--color-border-inverse);
505
+ color: var(--color-foreground-inverse-secondary);
506
+ }
507
+
508
+
509
+ /* ----------------------------------------------------------------
510
+ 11. RESPONSIVE — stacked cards on narrow widths
511
+ --------------------------------------------------------------
512
+
513
+ Two strategies, pick per table:
514
+
515
+ A. SCROLL (default) — keep the grid, let it scroll sideways.
516
+ Wrap .dt in an element with overflow-x:auto. Best for
517
+ comparison-heavy / numeric tables where column alignment
518
+ is the point (ledgers, FX rates).
519
+
520
+ B. STACK (.dt-responsive) — collapse each row into a card,
521
+ label : value per field. Best for action-oriented record
522
+ lists (transactions, counterparties) the user taps into.
523
+
524
+ Uses CONTAINER queries (not viewport) so the same component
525
+ reflows correctly inside a drawer, split-pane or phone frame —
526
+ not just at the page edge. Each <td> needs a data-label="…".
527
+ ---------------------------------------------------------------- */
528
+ .dt-responsive { container-type: inline-size; }
529
+
530
+ @container (max-width: 560px) {
531
+ /* Drop the header row — labels move inline via data-label */
532
+ .dt-responsive .dt thead { display: none; }
533
+
534
+ .dt-responsive .dt,
535
+ .dt-responsive .dt tbody,
536
+ .dt-responsive .dt tr,
537
+ .dt-responsive .dt td { display: block; width: 100%; box-sizing: border-box; }
538
+
539
+ /* Each row becomes a card */
540
+ .dt-responsive .dt tbody tr {
541
+ border: 1px solid var(--color-border-default);
542
+ border-radius: var(--radius-md);
543
+ background: var(--color-background-surface);
544
+ padding: var(--space-2) var(--space-4);
545
+ margin-bottom: var(--space-3);
546
+ box-shadow: var(--shadow-xs);
547
+ }
548
+ .dt-responsive .dt tbody tr:last-child { margin-bottom: 0; border-bottom: 1px solid var(--color-border-default); }
549
+
550
+ /* Each cell becomes a label : value line */
551
+ .dt-responsive .dt tbody td {
552
+ display: flex;
553
+ align-items: center;
554
+ justify-content: space-between;
555
+ gap: var(--space-4);
556
+ padding: var(--space-3) 0;
557
+ border-bottom: 1px solid var(--color-border-subtle);
558
+ text-align: right;
559
+ white-space: normal;
560
+ min-width: 0;
561
+ }
562
+ .dt-responsive .dt tbody td > * { min-width: 0; }
563
+ .dt-responsive .dt tbody td:last-child { border-bottom: 0; }
564
+
565
+ .dt-responsive .dt tbody td::before {
566
+ content: attr(data-label);
567
+ flex-shrink: 0;
568
+ font-family: var(--font-mono);
569
+ font-size: var(--fs-xxs);
570
+ font-weight: var(--w-semibold);
571
+ text-transform: uppercase;
572
+ letter-spacing: var(--ls-caps);
573
+ color: var(--color-foreground-muted);
574
+ text-align: left;
575
+ }
576
+ /* Cells with no label render full-width (e.g. a lead/title row) */
577
+ .dt-responsive .dt tbody td[data-label=""]::before,
578
+ .dt-responsive .dt tbody td:not([data-label])::before { content: none; }
579
+
580
+ /* Promote the first cell to a card title */
581
+ .dt-responsive .dt tbody td.dt-card-title {
582
+ justify-content: flex-start;
583
+ text-align: left;
584
+ font-size: var(--fs-base);
585
+ font-weight: var(--w-semibold);
586
+ padding-top: var(--space-3);
587
+ }
588
+ /* The lead block (avatar + name + country/doc) reads left-to-right */
589
+ .dt-responsive .dt tbody td.dt-card-title .dt-cell-stack { text-align: left; align-items: flex-start; }
590
+
591
+ /* Right-aligned numbers stay flush right next to their label */
592
+ .dt-responsive .dt-num { text-align: right; }
593
+
594
+ /* Selection / action columns sit inline like any other field */
595
+ .dt-responsive .dt td.col-select { width: 100%; }
596
+
597
+ /* Empty + skeleton rows shouldn't become cards */
598
+ .dt-responsive .dt tbody tr.dt-empty,
599
+ .dt-responsive .dt tbody tr.dt-skeleton { border: 0; box-shadow: none; padding: 0; }
600
+ .dt-responsive .dt tbody tr.dt-empty td { border: 0; text-align: center; }
601
+ .dt-responsive .dt tbody tr.dt-empty td::before { content: none; }
602
+ }