@ids-group-ltd/ids-design-system 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.
@@ -0,0 +1,614 @@
1
+ /* ============================================================
2
+ Design Tokens — Tier 3 component + scale layer.
3
+
4
+ Tier 1 colour primitives (ramps + HSL channels) live in
5
+ ../themes/default/_palette.scss. Tier 2 semantic role assignments
6
+ (surface, border, text, primary/secondary/tertiary, status, focus)
7
+ live in ../themes/default/_theme.scss.
8
+
9
+ THIS file owns the theme-INDEPENDENT layer:
10
+ · scales — spacing, radius, sizes, hit targets, breakpoints
11
+ · typography — families, sizes, weights, line-height, tracking
12
+ · motion — durations, easings
13
+ · elevation — shadows, blur, z-index layers
14
+ · opacity — state-overlay alphas
15
+ · component — Tier 3 --ds-*-* tokens (per-component geometry)
16
+
17
+ Components consume only Tier 2/3 tokens. Direct use of palette
18
+ primitives (--blue-600, --neutral-200, …) inside component
19
+ styles is a violation — fix by introducing or reusing a role.
20
+ ============================================================ */
21
+
22
+ :root {
23
+ /* ============================================================
24
+ Spacing — 4 px base, with named half-steps where atoms need them
25
+ ============================================================ */
26
+ --space-0: 0;
27
+ --space-px: 1px;
28
+ --space-0-5: 2px; /* hairline insets, icon close button pad */
29
+ --space-1: 4px;
30
+ --space-1-5: 6px; /* badge gap, tag gap, field-label gap */
31
+ --space-2: 8px;
32
+ --space-2-5: 10px; /* tooltip pad-x, badge pad-x */
33
+ --space-3: 12px;
34
+ --space-4: 16px;
35
+ --space-5: 20px;
36
+ --space-6: 24px;
37
+ --space-8: 32px;
38
+ --space-10: 40px;
39
+ --space-12: 48px;
40
+ --space-14: 56px;
41
+ --space-16: 64px;
42
+ --space-20: 80px;
43
+ --space-24: 96px;
44
+ --space-32: 128px;
45
+
46
+ /* ============================================================
47
+ Radius — six-stop scale.
48
+ Each step is functionally distinct; adjacent steps are
49
+ visually distinguishable at standard zoom.
50
+ ============================================================ */
51
+ --radius-0: 0;
52
+ --radius-sm: 4px; /* kbd, indeterminate-checkbox tick, link focus halo */
53
+ --radius-md: 8px; /* buttons, fields, tooltips, search, segmented, tags */
54
+ --radius-lg: 12px; /* menus, popovers, dropdowns, cards, modals, drawers, empty-state icons, toasts */
55
+ --radius-xl: 16px; /* large containers — viewport/scanner frames, hero cards */
56
+ --radius-2xl: 24px; /* heroic surfaces — reserved, no current consumer */
57
+
58
+ /* --radius-pill is configurable so themes can override pill-shaped surfaces
59
+ (switches, status chips, avatars, segmented thumb) without forking the
60
+ full radius scale. A spreadsheet-style client can square pills with:
61
+ :root[data-theme="spreadsheet"] { --radius-pill-value: var(--radius-sm); } */
62
+ --radius-pill-value: 999px;
63
+ --radius-pill: var(--radius-pill-value);
64
+
65
+ /* Component-scoped radius — kept only when the semantic intent matters
66
+ beyond the value itself, OR when the global scale doesn't fit. */
67
+ --radius-flat: var(--radius-0); /* explicit "intentionally squared" — middle of btn-group, in-range datepicker */
68
+
69
+ /* ============================================================
70
+ Border widths — two-stop scale.
71
+ Adjacent widths must be visually distinguishable; 1.5/2.5
72
+ mid-stops were dropped because they read identically to
73
+ 1/2 on standard displays.
74
+ ============================================================ */
75
+ --border-width-default: 1px; /* every border, divider, field outline */
76
+ --border-width-strong: 2px; /* radio dot, slider thumb, tabs underline, focus ring inner band, dropzone dash */
77
+
78
+ /* ============================================================
79
+ Elevation
80
+ Channel-split substrate so a re-skin can re-tint shadows.
81
+ Light theme: cool near-black slate (225 / 39% / 7%).
82
+ Dark theme: override --shadow-tint-l to ~95% so the same
83
+ alphas render as soft light glows over dark surfaces.
84
+ The alpha values stay constant across themes — only the
85
+ hue/saturation/lightness become configurable.
86
+ ============================================================ */
87
+ /* --shadow-tint-h/s/l live in themes/default/_palette.scss — palette-level
88
+ so dark palettes can override --shadow-tint-l → ~95% for soft light glows. */
89
+
90
+ --shadow-1: 0 1px 2px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .06),
91
+ 0 1px 3px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .08);
92
+ --shadow-2: 0 4px 8px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .06),
93
+ 0 4px 16px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .10);
94
+ --shadow-3: 0 8px 16px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .08),
95
+ 0 16px 32px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .14);
96
+ --shadow-4: 0 16px 32px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .12),
97
+ 0 24px 48px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .18);
98
+ --shadow-popover: var(--shadow-2);
99
+ --shadow-modal: var(--shadow-4);
100
+ --shadow-toast: var(--shadow-3);
101
+ --shadow-card: var(--shadow-1);
102
+
103
+ /* Backdrop blur */
104
+ --blur-sm: 4px;
105
+ --blur-md: 8px;
106
+
107
+ /* ============================================================
108
+ Z-index — global stacking scale.
109
+ Component-internal stacking (e.g. sticky headers within a
110
+ scroll container) uses component-scoped tokens derived from
111
+ the global scale so refactors stay local. */
112
+ --layer-base: 0;
113
+ --layer-raised: 1;
114
+ --layer-sticky: 100;
115
+ --layer-dropdown: 1000;
116
+ --layer-overlay: 1100;
117
+ --layer-drawer: 1200;
118
+ --layer-modal: 1300;
119
+ --layer-popover: 1400;
120
+ --layer-toast: 1500;
121
+ --layer-tooltip: 1600;
122
+
123
+ /* Component-scoped stacking */
124
+ --table-sticky-header-z: var(--layer-raised);
125
+ --table-sticky-col-z: var(--layer-raised);
126
+ --table-sticky-corner-z: 2; /* sticky col header sits over both axes */
127
+ --btn-focus-z: var(--layer-raised);
128
+ --btn-group-focus-z: 2; /* focused button rises above its neighbour */
129
+
130
+ /* ============================================================
131
+ Motion
132
+ ============================================================ */
133
+ --duration-instant: 80ms;
134
+ --duration-fast: 120ms;
135
+ --duration-base: 180ms;
136
+ --duration-slow: 260ms;
137
+ --duration-slower: 400ms;
138
+
139
+ /* Loop durations — for indeterminate spinners, skeletons, progress.
140
+ These deliberately sit outside the transition scale because
141
+ they describe rhythm, not response. */
142
+ --duration-loop-fast: 700ms;
143
+ --duration-loop-slow: 1400ms;
144
+
145
+ /* Easing.
146
+ - standard: default for transitions; decelerates into rest.
147
+ Use for state changes (hover, focus, toggle).
148
+ - emphasized: accelerate-decelerate; bigger movements that
149
+ "pick up and put down". Use for entries/exits
150
+ of overlays, modals, drawers.
151
+ - decelerate: incoming-only (out → in). Use when something
152
+ appears (toast, tooltip, popover open).
153
+ - accelerate: outgoing-only (in → out). Use when something
154
+ leaves (toast dismiss, modal close).
155
+ - spring: playful overshoot; sparingly. Reserved for
156
+ small celebratory feedback. */
157
+ --ease-standard: cubic-bezier(.2, 0, 0, 1);
158
+ --ease-emphasized: cubic-bezier(.3, 0, .1, 1.4);
159
+ --ease-decelerate: cubic-bezier(0, 0, 0, 1);
160
+ --ease-accelerate: cubic-bezier(.3, 0, 1, 1);
161
+ --ease-spring: cubic-bezier(.5, 1.5, .5, 1);
162
+
163
+ /* Opacity — semantic, purpose-named (Material/Carbon/Polaris convention).
164
+ Each token has a real consumer in the codebase; symmetric "unused"
165
+ numeric stops are deliberately omitted. */
166
+ --opacity-disabled: 0.5; /* full disabled state on interactive components */
167
+ --opacity-muted: 0.6; /* legacy alias — being phased out in favour of --text-* roles */
168
+ --opacity-text-disabled: 0.38; /* disabled text alpha (WCAG-derived) */
169
+ --opacity-scrim: 0.55; /* modal/drawer backdrop overlay (light theme) */
170
+ --opacity-state-hover: 0.08; /* hover layer over surface (overlay vs surface swap) */
171
+ --opacity-state-pressed: 0.16; /* active/pressed layer */
172
+
173
+ /* ============================================================
174
+ Breakpoints
175
+ ============================================================ */
176
+ --bp-xs: 480px;
177
+ --bp-sm: 640px;
178
+ --bp-md: 768px;
179
+ --bp-lg: 1024px;
180
+ --bp-xl: 1441px; /* Page-grid wide-tier threshold (12 cols, container caps at --col-cap-content). */
181
+ --bp-2xl:1536px;
182
+
183
+ /* ============================================================
184
+ Page grid — tier-specific gutters + margins.
185
+ Consumed by `.page-grid` in _page-grid.scss; one column-count
186
+ per tier (4 / 8 / 12 / 12) with `--page-gutter` and
187
+ `--page-margin` swapping at the matching min-width breakpoint.
188
+ ============================================================ */
189
+ --page-gutter-mobile: var(--space-3); /* 12px — <= 640px, 4-col tier */
190
+ --page-gutter-tablet: var(--space-4); /* 16px — 641–1024px, 8-col tier */
191
+ --page-gutter-desktop: var(--space-5); /* 20px — 1025–1440px, 12-col tier */
192
+ --page-gutter-wide: var(--space-6); /* 24px — >= 1441px, 12-col tier, container caps */
193
+ --page-margin-mobile: var(--space-4); /* 16px */
194
+ --page-margin-tablet: var(--space-6); /* 24px */
195
+ --page-margin-desktop: var(--space-8); /* 32px */
196
+ --page-margin-wide: var(--space-10); /* 40px */
197
+
198
+ /* ============================================================
199
+ System chrome
200
+ ============================================================ */
201
+ --scrollbar-w: 10px;
202
+ --scrollbar-thumb: var(--neutral-300);
203
+ --scrollbar-thumb-hover: var(--neutral-400);
204
+ --scrollbar-thumb-active: var(--neutral-500);
205
+ --select-bg: color-mix(in srgb, var(--primary) 22%, transparent);
206
+ --col-cap-text: 720px;
207
+ --col-cap-content: 1280px;
208
+
209
+ /* ============================================================
210
+ Typography scale (theme-independent). Font FAMILIES are a theme
211
+ choice and live in themes/default/_theme.scss (--font-sans/mono/
212
+ display/heading); the size/weight/leading/tracking scale below is
213
+ constant across themes.
214
+ ============================================================ */
215
+ --font-weight-regular: 400;
216
+ --font-weight-medium: 500;
217
+ --font-weight-semibold: 600;
218
+ --font-weight-bold: 700;
219
+ --font-weight-extrabold:800;
220
+
221
+ --font-size-display: 64px;
222
+ --font-size-h1: 48px;
223
+ --font-size-h2: 36px;
224
+ --font-size-h3: 28px;
225
+ --font-size-h4: 22px;
226
+ --font-size-h5: 18px;
227
+ --font-size-h5-strong: 20px; /* modal titles, condensed headers */
228
+ --font-size-l: 18px;
229
+ --font-size-m: 16px;
230
+ --font-size-s: 14px;
231
+ --font-size-xs: 12px;
232
+ --font-size-2xs: 11px;
233
+ --font-size-3xs: 10px; /* avatar-sm font */
234
+ --font-size-4xs: 9px; /* avatar-xs font */
235
+ --font-size-mono: 13px;
236
+
237
+ --line-height-tight: 1.1;
238
+ --line-height-snug: 1.25;
239
+ --line-height-base: 1.4;
240
+ --line-height-loose: 1.6;
241
+ --line-height-flat: 1; /* button labels, single-line UI */
242
+
243
+ --letter-spacing-tight: -.02em;
244
+ --letter-spacing-snug: -.01em;
245
+ --letter-spacing-normal: 0;
246
+ --letter-spacing-wide: .02em;
247
+ --letter-spacing-wider: .08em;
248
+
249
+ /* ============================================================
250
+ Hit targets — the canonical size scale for interactive height
251
+ ============================================================ */
252
+ --hit-xs: 24px; /* btn-s, datepicker nav, modal close */
253
+ --hit-sm: 28px; /* segmented btn, stepper node */
254
+ --hit-md: 36px; /* search, pagination, tag-input rows */
255
+ --hit-min: 32px; /* dense desktop default (alias of --hit-cozy-tier-0) */
256
+ --hit-cozy: 40px; /* default control height */
257
+ --hit-comfy: 44px; /* WCAG min for touch */
258
+ --hit-touch: 48px; /* mobile-friendly — also used by floating-label fields */
259
+
260
+ /* ============================================================
261
+ Iconography
262
+ ============================================================ */
263
+ --icon-2xs: 10px;
264
+ --icon-xs: 12px;
265
+ --icon-sm: 14px;
266
+ --icon-md: 16px;
267
+ --icon-lg: 20px;
268
+
269
+ /* ============================================================
270
+ 3 · COMPONENT-SCOPED dimensions
271
+ Atom-level geometry that doesn't fit cleanly in a global
272
+ scale. Density Tweaks override these at :root.
273
+ ============================================================ */
274
+
275
+ /* Field padding — density-aware, consumed by input, search and
276
+ textarea controls. Tokenised so the ultra-compact tier can
277
+ compress without component edits. */
278
+ --field-pad-x: var(--space-3);
279
+ --field-pad-y: 0;
280
+
281
+ /* Shared inner padding for surface containers (card, stat, …). Components
282
+ default their own --ds-*-pad to this, so a consumer retunes all at once. */
283
+ --ds-container-pad: var(--space-6);
284
+
285
+ /* Table cell padding — density-aware, consumed by .tbl td/th. */
286
+ --table-cell-pad-x: var(--space-4);
287
+ --table-cell-pad-y: var(--space-3);
288
+ --table-head-pad-y: var(--space-3);
289
+ --check-size: 20px;
290
+ --check-bw: var(--border-width-default);
291
+ --check-tick-size: 12px;
292
+ --check-indet-w: 10px;
293
+ --check-indet-h: 2px;
294
+ --radio-dot-size: 10px;
295
+ --radio-bw-checked: var(--border-width-strong);
296
+
297
+ /* Switch */
298
+ --switch-track-w: 36px;
299
+ --switch-track-h: 20px;
300
+ --switch-thumb-size: 16px;
301
+ --switch-thumb-pad: 2px;
302
+ --switch-thumb-travel: 16px; /* track-w − thumb − 2*pad */
303
+
304
+ /* Slider */
305
+ --slider-track-h: 4px;
306
+ --slider-thumb-size: 18px;
307
+ --slider-thumb-bw: var(--border-width-strong);
308
+
309
+ /* Status dot, badge dot */
310
+ --status-dot-size: 8px;
311
+ --badge-dot-size: 6px;
312
+
313
+ /* Badge */
314
+ --badge-pad-y: 4px;
315
+ --badge-pad-x: 10px;
316
+ --badge-gap: var(--space-1-5);
317
+ --badge-count-size: 20px;
318
+
319
+ /* Tag */
320
+ --tag-pad-y: 6px;
321
+ --tag-pad-x: 10px;
322
+ --tag-pad-x-close: 6px;
323
+ --tag-gap: var(--space-1-5);
324
+ --tag-close-size: 14px;
325
+ --tag-close-pad: 2px;
326
+
327
+ /* Avatar */
328
+ --avatar-xs: 20px;
329
+ --avatar-sm: 24px;
330
+ --avatar-md: 32px;
331
+ --avatar-lg: 40px;
332
+ --avatar-bw-group: var(--border-width-strong);
333
+
334
+ /* Spinner */
335
+ --spinner-sm: 12px;
336
+ --spinner-md: 16px;
337
+ --spinner-lg: 24px;
338
+ --spinner-bw: var(--border-width-strong);
339
+
340
+ /* Progress */
341
+ --progress-h: 6px;
342
+
343
+ /* Stepper */
344
+ --stepper-node-size: 28px; /* === --hit-sm */
345
+ --stepper-bar-w: 56px;
346
+ --stepper-bar-h: 2px;
347
+
348
+ /* Segmented control */
349
+ --segmented-btn-h: var(--hit-sm);
350
+ --segmented-r-inner: var(--radius-md);
351
+ --segmented-pad: 2px;
352
+
353
+ /* Sidenav */
354
+ --sidenav-w: 240px;
355
+ --sidenav-w-collapsed: 64px;
356
+
357
+ /* Modal */
358
+ --modal-w-sm: 480px;
359
+ --modal-w-md: 640px;
360
+ --modal-w-lg: 800px;
361
+
362
+ /* Drawer */
363
+ --drawer-w-md: 480px;
364
+ --drawer-w-lg: 640px;
365
+
366
+ /* Popover / cmdk */
367
+ --popover-maxh: 360px;
368
+
369
+ /* Field */
370
+ --field-gap-label: var(--space-1-5); /* label↔control */
371
+ --field-gap-req: var(--space-1); /* label↔asterisk */
372
+ --field-h-sm: var(--hit-min);
373
+ --field-h-md: var(--hit-cozy);
374
+ --field-h-lg: var(--hit-touch);
375
+ --field-h-floating: var(--hit-touch);
376
+ --field-textarea-min: 96px;
377
+ --field-floating-label-fs: var(--font-size-2xs);
378
+ --field-floating-label-lh: 14px;
379
+ --field-floating-label-top: 8px;
380
+ --field-num-stepper-w: var(--space-8);
381
+
382
+ /* Search */
383
+ --search-h: var(--hit-md);
384
+ --search-maxw: 320px;
385
+
386
+ /* ============================================================
387
+ 3b · COMPONENT-SCOPED dimensions (Phase 4 additions)
388
+ Tokens for atom geometries that previously lived as literals
389
+ inside component CSS. Grouped by component for readability.
390
+ ============================================================ */
391
+
392
+ /* Top bar / app shell */
393
+ --topbar-h: var(--space-14); /* 56px — global app bar height */
394
+
395
+ /* Sidenav internals — w / w-collapsed defined above */
396
+ --sidenav-pad-brand-y: var(--space-2); /* logo top padding */
397
+ --sidenav-pad-brand-b: var(--space-6); /* logo bottom padding */
398
+ --sidenav-logo-size: var(--hit-sm); /* 28px — square brand mark */
399
+ --sidenav-collapsed-item: var(--hit-cozy); /* 40px — collapsed nav-item hit area */
400
+ --sidenav-section-pad-b: var(--space-1-5); /* nav-section bottom padding */
401
+
402
+ /* Form section grid */
403
+ --form-section-label-w: 280px; /* labels column width */
404
+
405
+ /* Page header */
406
+ --page-header-sub-mt: var(--space-1); /* subtitle top margin */
407
+
408
+ /* Field internals */
409
+ --field-textarea-rows-min: 60px; /* min-h for inline textarea inside the field wrapper */
410
+ --field-floating-pad-t: 18px; /* top padding when --floating, leaves room for label */
411
+ --field-select-pad-r: var(--space-6); /* select chevron clearance */
412
+ --field-affix-overlap: var(--border-width-default); /* affix bleed over field border */
413
+
414
+ /* Button group */
415
+ --btn-group-overlap: calc(var(--border-width-default) * -1); /* -1px — collapses adjacent borders */
416
+ --btn-link-uloff: 3px; /* underline-offset on link buttons */
417
+
418
+ /* Card */
419
+ --card-hover-lift: 1px; /* translateY on .card--hover */
420
+ --card-title-fs: var(--font-size-h4);
421
+
422
+ /* Sort icon (table headers) */
423
+ --sort-ic-size: var(--icon-xs); /* 12px */
424
+ --sort-ic-gap: var(--space-1-5); /* 6px */
425
+
426
+ /* Tag close glyph (when literal svg sits inside .tag .x) */
427
+ --tag-close-glyph: var(--icon-xs); /* 12px */
428
+
429
+ /* Bulk action toolbar */
430
+ --bulk-bar-offset: var(--space-4); /* sticky offset from container bottom */
431
+
432
+ /* Menu */
433
+ --menu-minw: 200px; /* dropdown menu min width */
434
+ --menu-sep-h: var(--border-width-default);
435
+
436
+ /* Tooltip */
437
+ --tooltip-maxw: 240px;
438
+ --tooltip-arrow: var(--space-2); /* 8px — caret edge length, halved for offset */
439
+
440
+ /* Popover */
441
+ --popover-maxw: 320px;
442
+
443
+ /* Toast */
444
+ --toast-minw: 320px;
445
+ --toast-maxw: 480px;
446
+ --toast-bar-w: 3px; /* left accent bar */
447
+ --toast-enter-y: var(--space-1); /* slide-in distance */
448
+
449
+ /* Banner / Alert */
450
+ --banner-bar-w: 4px; /* left accent bar */
451
+ --banner-ic-mt: var(--border-width-default); /* optical bump for icon alignment */
452
+
453
+ /* Empty state */
454
+ --empty-icon-size: var(--space-16); /* 64px */
455
+ --empty-body-maxw: 360px;
456
+
457
+ /* Combobox */
458
+ --combobox-offset: var(--space-1); /* gap below trigger */
459
+ --combobox-maxh: 280px; /* listbox max height */
460
+
461
+ /* Command palette (cmdk) */
462
+ --cmdk-w: 560px;
463
+ --cmdk-list-maxh: var(--popover-maxh); /* alias — keeps cmdk + popover synced */
464
+
465
+ /* Datepicker */
466
+ --datepicker-w: 280px;
467
+ --datepicker-cell-gap: var(--space-0-5); /* 2px — grid gap between day cells */
468
+ --datepicker-nav-size: var(--hit-xs); /* 24px — month-step buttons */
469
+
470
+ /* Modal close button */
471
+ --modal-close-size: var(--hit-xs); /* 24px */
472
+ --modal-enter-y: var(--space-2); /* 8px slide-in */
473
+
474
+ /* Error page */
475
+ --errorpage-body-maxw: 520px;
476
+
477
+ /* Wizard (extras) */
478
+ --wizard-body-minh: 200px;
479
+ --wizard-step-bar-w: var(--space-8); /* 32px connector */
480
+
481
+ /* Inline edit */
482
+ --inline-edit-input-minw: var(--space-20); /* 80px */
483
+ --inline-edit-btn-size: var(--hit-xs); /* 24px */
484
+
485
+ /* Settings */
486
+ --settings-nav-w: 220px;
487
+ --settings-row-label-w: 240px;
488
+ --settings-row-label-gap: var(--space-0-5); /* 2px between strong + helper */
489
+
490
+ /* Matrix */
491
+ --matrix-maxh: 360px; /* shares optical with --popover-maxh by intent */
492
+ --matrix-cell-pad-y: var(--space-2); /* 8px */
493
+ --matrix-cell-pad-x: var(--space-2-5); /* 10px */
494
+ --matrix-cell-minw: var(--space-16); /* 64px */
495
+ --matrix-rowhdr-minw: 160px;
496
+
497
+ /* Calendar / timeline */
498
+ --calendar-rowlabel-w: 160px;
499
+ --calendar-row-h: var(--hit-touch); /* 48px */
500
+ --calendar-cell-min: var(--hit-cozy); /* 40px minimum column width */
501
+ --calendar-cell-pad: var(--space-1); /* 4px inner padding */
502
+ --calendar-bar-h: var(--space-8); /* 32px */
503
+ --calendar-bar-inset-y: var(--space-2); /* 8px from top of cell */
504
+
505
+ /* Bin pack visualisation */
506
+ --binpack-bay-h: var(--hit-touch); /* 48px */
507
+
508
+ /* Map placeholder chip */
509
+ --map-chip-pad-y: var(--space-1-5); /* 6px */
510
+ --map-chip-pad-x: var(--space-2-5); /* 10px */
511
+ --map-chip-inset: var(--space-3); /* 12px from top-left */
512
+
513
+ /* KBD badge */
514
+ --kbd-pad-y: var(--space-0-5); /* 2px */
515
+ --kbd-pad-x: var(--space-1-5); /* 6px */
516
+
517
+ /* Chart */
518
+ --chart-empty-h: 160px;
519
+ --chart-skeleton-h: 160px;
520
+ --chart-legend-dot: var(--icon-2xs); /* 10px */
521
+
522
+ /* Compare layout */
523
+ --compare-dt-w: 90px;
524
+
525
+ /* Do/Don't stage */
526
+ --dodont-stage-minh: 100px;
527
+
528
+ /* Statemap arrow */
529
+ --statemap-arrow-w: var(--space-8); /* 32px */
530
+ --statemap-arrow-cap: var(--space-1); /* 4px caret border-width */
531
+
532
+ /* Page composition (extras) */
533
+ --grid-table-min: 220px; /* auto-fit minmax */
534
+ --grid-cols-card-minh: 120px;
535
+ --grid-cols-card-thumb: 80px;
536
+ --dl-spec-label-w: 120px;
537
+ --scroll-spec-h: 220px;
538
+ --tab-spec-maxw: 220px;
539
+ --tab-spec-dot-offset: var(--border-width-strong); /* -2px notification offset (negated inline) */
540
+ }
541
+
542
+ /* ============================================================
543
+ Reduced motion
544
+ ============================================================ */
545
+ @media (prefers-reduced-motion: reduce) {
546
+ :root {
547
+ --duration-instant: 0ms;
548
+ --duration-fast: 0ms;
549
+ --duration-base: 0ms;
550
+ --duration-slow: 0ms;
551
+ --duration-slower: 0ms;
552
+ --duration-loop-fast: 0ms;
553
+ --duration-loop-slow: 0ms;
554
+ }
555
+ *, *::before, *::after {
556
+ transition-duration: 0ms !important;
557
+ animation-duration: 0ms !important;
558
+ animation-iteration-count: 1 !important;
559
+ }
560
+ }
561
+
562
+ /* ============================================================
563
+ Density tiers — applied by Tweaks panel via [data-density]
564
+ ============================================================ */
565
+ [data-density="ultra-compact"] {
566
+ /* Power-user / tradesperson tier: financial dashboards, log viewers,
567
+ dense data grids. 24px hits sit BELOW WCAG 2.5.5 (44px enhanced)
568
+ and WCAG 2.5.8 (24px minimum) margins — acceptable only when:
569
+ (a) the screen is keyboard-first, (b) input is mouse/keys not
570
+ touch, (c) accidental-tap risk is low, (d) the user opted in.
571
+ Do not enable for mobile / field-ops layouts. */
572
+ --hit-cozy: 24px;
573
+ --hit-min: 24px;
574
+ --check-size: 14px;
575
+ --switch-track-w: 24px;
576
+ --switch-thumb-size: 12px;
577
+ --segmented-btn-h: 20px;
578
+ --field-pad-x: var(--space-2);
579
+ --field-pad-y: var(--space-1);
580
+ --table-cell-pad-x: var(--space-2);
581
+ --table-cell-pad-y: var(--space-1);
582
+ --table-head-pad-y: var(--space-1);
583
+ }
584
+ [data-density="compact"] {
585
+ --hit-cozy: 32px;
586
+ --check-size: 16px;
587
+ --switch-track-w: 30px;
588
+ --switch-track-h: 16px;
589
+ --switch-thumb-size: 12px;
590
+ --switch-thumb-travel: 14px;
591
+ --avatar-md: 24px;
592
+ --badge-dot-size: 5px;
593
+ --status-dot-size: 6px;
594
+ --sidenav-w: 220px;
595
+ --field-floating-label-top: 6px;
596
+ --segmented-btn-h: 24px;
597
+ }
598
+ [data-density="cozy"] {
599
+ --hit-cozy: 40px;
600
+ /* defaults */
601
+ }
602
+ [data-density="comfy"] {
603
+ --hit-cozy: 48px;
604
+ --check-size: 22px;
605
+ --switch-track-w: 44px;
606
+ --switch-track-h: 24px;
607
+ --switch-thumb-size: 20px;
608
+ --switch-thumb-travel: 20px;
609
+ --avatar-md: 36px;
610
+ --badge-dot-size: 8px;
611
+ --status-dot-size: 10px;
612
+ --sidenav-w: 264px;
613
+ --segmented-btn-h: 32px;
614
+ }
@@ -0,0 +1,30 @@
1
+ // Type utility classes — ported from CLAUDE_DESIGN_DS/tokens.css §Type utilities.
2
+ // These are GLOBAL by design — consumers apply them via class.
3
+
4
+ .t-display { font: var(--font-weight-extrabold) var(--font-size-display)/var(--line-height-tight) var(--font-display); letter-spacing: var(--letter-spacing-tight); }
5
+ .t-h1 { font: var(--font-weight-extrabold) var(--font-size-h1)/var(--line-height-tight) var(--font-heading); letter-spacing: var(--letter-spacing-tight); }
6
+ .t-h2 { font: var(--font-weight-extrabold) var(--font-size-h2)/var(--line-height-snug) var(--font-heading); letter-spacing: var(--letter-spacing-snug); }
7
+ .t-h3 { font: var(--font-weight-extrabold) var(--font-size-h3)/var(--line-height-snug) var(--font-heading); letter-spacing: var(--letter-spacing-snug); }
8
+ .t-h4 { font: var(--font-weight-bold) var(--font-size-h4)/var(--line-height-snug) var(--font-heading); }
9
+ .t-h5 { font: var(--font-weight-bold) var(--font-size-h5)/var(--line-height-snug) var(--font-heading); }
10
+ .t-card-title { font: var(--font-weight-bold) var(--card-title-fs)/var(--line-height-snug) var(--font-heading); margin: 0; color: var(--text-primary); }
11
+ .t-l { font: var(--font-weight-regular) var(--font-size-l)/var(--line-height-base) var(--font-sans); }
12
+ .t-l-bold { font: var(--font-weight-bold) var(--font-size-l)/var(--line-height-base) var(--font-sans); }
13
+ .t-m { font: var(--font-weight-regular) var(--font-size-m)/var(--line-height-base) var(--font-sans); }
14
+ .t-m-bold { font: var(--font-weight-bold) var(--font-size-m)/var(--line-height-base) var(--font-sans); }
15
+ .t-s { font: var(--font-weight-regular) var(--font-size-s)/var(--line-height-base) var(--font-sans); }
16
+ .t-s-bold { font: var(--font-weight-bold) var(--font-size-s)/var(--line-height-base) var(--font-sans); }
17
+ .t-xs { font: var(--font-weight-regular) var(--font-size-xs)/var(--line-height-base) var(--font-sans); }
18
+ .t-xs-bold { font: var(--font-weight-bold) var(--font-size-xs)/var(--line-height-base) var(--font-sans); }
19
+ .t-overline { font: var(--font-weight-bold) var(--font-size-2xs)/var(--line-height-base) var(--font-sans); letter-spacing: var(--letter-spacing-wider); text-transform: uppercase; color: var(--text-tertiary); }
20
+ .t-caption { font: var(--font-weight-regular) var(--font-size-xs)/var(--line-height-base) var(--font-sans); color: var(--text-tertiary); }
21
+ .t-mono { font: var(--font-weight-medium) var(--font-size-mono)/var(--line-height-base) var(--font-mono); }
22
+ .t-mono-block { font: var(--font-weight-regular) var(--font-size-mono)/var(--line-height-loose) var(--font-mono); background: var(--surface-secondary); border: var(--border-width-default) solid var(--border-divider); border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); }
23
+
24
+ .sr-only {
25
+ position: absolute !important;
26
+ width: 1px; height: 1px;
27
+ padding: 0; margin: -1px;
28
+ overflow: hidden; clip: rect(0,0,0,0);
29
+ white-space: nowrap; border: 0;
30
+ }
package/styles/ds.scss ADDED
@@ -0,0 +1,27 @@
1
+ // Public DS stylesheet entry. Consumers import once at the top of their styles.scss:
2
+ // @use 'styles/ds';
3
+ //
4
+ // Bundles the default palette + theme for out-of-the-box rendering. Layers:
5
+ // default/palette — Tier 1 concrete colours (ramps + HSL channels)
6
+ // default/theme — Tier 2 semantic role → palette assignments + font families
7
+ // tokens — Tier 3 geometry / typography scale / motion / component tokens
8
+ // Advanced consumers can swap the palette/theme and keep tokens — global
9
+ // side-effects (fonts, link) are then opt-in:
10
+ // @use 'themes/X/palette'; @use 'themes/X/theme'; @use 'styles/tokens';
11
+ // @use 'styles/fonts'; @use 'styles/link'; …
12
+
13
+ @forward '../themes/default/palette';
14
+ @forward '../themes/default/theme';
15
+ @forward 'tokens';
16
+ @forward 'tokens-charts';
17
+ @forward 'fonts';
18
+ @forward 'reset';
19
+ @forward 'typography';
20
+ @forward 'link';
21
+ @forward 'layout-utils';
22
+ @forward 'page-grid';
23
+ @forward 'scrollbar';
24
+ @forward 'icon-base';
25
+ @forward 'dropdown-overlay';
26
+ @forward 'toast-overlay';
27
+ @forward 'skeleton-shimmer';