@attrus-ds/core 1.0.6 → 1.0.11

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 (50) hide show
  1. package/dist/css/components/action-bar.css +93 -0
  2. package/dist/css/components/ambient.css +97 -0
  3. package/dist/css/components/animated-bg.css +261 -0
  4. package/dist/css/components/buttons.css +4 -4
  5. package/dist/css/components/callout.css +4 -3
  6. package/dist/css/components/cards.css +4 -3
  7. package/dist/css/components/combobox.css +16 -13
  8. package/dist/css/components/inputs.css +99 -15
  9. package/dist/css/components/number-input.css +6 -3
  10. package/dist/css/components/primitives.css +20 -15
  11. package/dist/css/components/sel-card.css +212 -0
  12. package/dist/css/components/sidebar.css +11 -9
  13. package/dist/css/components/smart-search.css +13 -11
  14. package/dist/css/components/status-pills.css +1 -1
  15. package/dist/css/components/stepper.css +81 -4
  16. package/dist/css/components/table.css +168 -7
  17. package/dist/css/components/tabs.css +4 -3
  18. package/dist/css/components/toast.css +2 -2
  19. package/dist/css/components/toggle-chip.css +137 -0
  20. package/dist/css/components/tooltip.css +8 -5
  21. package/dist/css/components/topbar.css +8 -7
  22. package/dist/css/index.css +5 -0
  23. package/dist/css/tokens.css +126 -22
  24. package/dist/react/ActionBar/ActionBar.d.ts +19 -0
  25. package/dist/react/ActionBar/ActionBar.tsx +54 -0
  26. package/dist/react/AmbientBackdrop/AmbientBackdrop.d.ts +17 -0
  27. package/dist/react/AmbientBackdrop/AmbientBackdrop.tsx +53 -0
  28. package/dist/react/AnimatedBackdrop/AnimatedBackdrop.d.ts +22 -0
  29. package/dist/react/AnimatedBackdrop/AnimatedBackdrop.tsx +317 -0
  30. package/dist/react/Callout/Callout.d.ts +1 -1
  31. package/dist/react/Callout/Callout.tsx +1 -1
  32. package/dist/react/Combobox/Combobox.d.ts +2 -0
  33. package/dist/react/Combobox/Combobox.tsx +85 -39
  34. package/dist/react/DataTable/DataTable.tsx +3 -3
  35. package/dist/react/Drawer/Drawer.tsx +7 -1
  36. package/dist/react/Input/Input.d.ts +1 -1
  37. package/dist/react/Input/Input.tsx +1 -1
  38. package/dist/react/Modal/Modal.tsx +8 -1
  39. package/dist/react/SelectableCard/SelectableCard.d.ts +39 -0
  40. package/dist/react/SelectableCard/SelectableCard.tsx +94 -0
  41. package/dist/react/SmartSearch/SmartSearch.tsx +2 -2
  42. package/dist/react/Stepper/Stepper.d.ts +3 -0
  43. package/dist/react/Stepper/Stepper.tsx +7 -0
  44. package/dist/react/Toast/Toast.d.ts +1 -1
  45. package/dist/react/Toast/Toast.tsx +1 -1
  46. package/dist/react/ToggleChip/ToggleChip.d.ts +29 -0
  47. package/dist/react/ToggleChip/ToggleChip.tsx +76 -0
  48. package/dist/react/Tooltip/Tooltip.d.ts +1 -1
  49. package/dist/react/Tooltip/Tooltip.tsx +1 -1
  50. package/package.json +1 -1
@@ -0,0 +1,93 @@
1
+ /* ============================================================
2
+ ACTION BAR — components/action-bar.css
3
+ Persistent action strip for wizards, drawers and editors: primary
4
+ action on the right, secondary/back on the left, optional context
5
+ (progress, count, hint) in the middle.
6
+
7
+ IMPORTANT: right-align with `.action-bar-actions { margin-left:auto }`.
8
+ Never use a flex:1 spacer — a spacer competing with a stepper in the
9
+ same row collapses it (that is exactly how the stepper label overlap
10
+ bug happened).
11
+
12
+ Structure:
13
+ .action-bar
14
+ .action-bar-lead back / secondary (optional)
15
+ .action-bar-context progress text, count, hint (optional)
16
+ .action-bar-actions primary cluster — margin-left:auto
17
+ Variants: .is-fixed (viewport-pinned) · .action-bar-sm · .on-inverse
18
+ ============================================================ */
19
+
20
+ .action-bar {
21
+ display: flex;
22
+ align-items: center;
23
+ gap: var(--space-4);
24
+ padding: var(--space-4) var(--space-6);
25
+ background: var(--glass-chrome);
26
+ color: var(--glass-chrome-fg);
27
+ -webkit-backdrop-filter: var(--glass-blur);
28
+ backdrop-filter: var(--glass-blur);
29
+ border-top: 1px solid var(--color-border-subtle);
30
+ box-sizing: border-box;
31
+ font-family: var(--font-sans);
32
+ width: 100%;
33
+ }
34
+
35
+ /* Pinned to the viewport bottom — for full-page wizards */
36
+ .action-bar.is-fixed {
37
+ position: fixed;
38
+ left: 0;
39
+ right: 0;
40
+ bottom: 0;
41
+ z-index: 900;
42
+ box-shadow: var(--shadow-lg);
43
+ }
44
+
45
+ .action-bar-lead {
46
+ display: inline-flex;
47
+ align-items: center;
48
+ gap: var(--space-3);
49
+ flex-shrink: 0;
50
+ }
51
+ .action-bar-context {
52
+ display: inline-flex;
53
+ align-items: center;
54
+ gap: var(--space-3);
55
+ min-width: 0;
56
+ font-size: var(--fs-sm);
57
+ color: var(--color-foreground-secondary);
58
+ }
59
+ .action-bar-context .strong {
60
+ font-weight: var(--w-regular);
61
+ color: var(--color-foreground-default);
62
+ }
63
+ /* Right cluster — margin-left:auto, NOT a flex spacer */
64
+ .action-bar-actions {
65
+ margin-left: auto;
66
+ display: inline-flex;
67
+ align-items: center;
68
+ gap: var(--space-3);
69
+ flex-shrink: 0;
70
+ }
71
+
72
+ /* ---------- Dense ---------- */
73
+ .action-bar-sm {
74
+ padding: var(--space-3) var(--space-5);
75
+ gap: var(--space-3);
76
+ }
77
+ .action-bar-sm .action-bar-context { font-size: var(--fs-xs); }
78
+
79
+ /* ---------- On inverse ---------- */
80
+ .action-bar.on-inverse {
81
+ background: var(--glass-hero);
82
+ color: var(--glass-hero-fg);
83
+ border-top-color: var(--color-border-inverse);
84
+ }
85
+ .action-bar.on-inverse .action-bar-context { color: var(--color-foreground-inverse-secondary); }
86
+ .action-bar.on-inverse .action-bar-context .strong { color: var(--color-foreground-inverse-default); }
87
+
88
+ /* ---------- Responsive ---------- */
89
+ @media (max-width: 640px) {
90
+ .action-bar { flex-wrap: wrap; gap: var(--space-3); padding: var(--space-4); }
91
+ .action-bar-context { order: 3; width: 100%; }
92
+ .action-bar-actions { margin-left: auto; }
93
+ }
@@ -0,0 +1,97 @@
1
+ /* ============================================================
2
+ AMBIENT BACKDROP — components/ambient.css
3
+ The official decorative layer: soft radial brand blobs behind hero
4
+ and marketing content. Exists so the effect stops being re-invented
5
+ (with raw hex and random blur) on every landing page.
6
+
7
+ Structure:
8
+ .ambient the positioned container (position:relative host)
9
+ .ambient-blob 1–3 radial blobs (.is-1 / .is-2 / .is-3)
10
+ .ambient-scrim MANDATORY readability veil over the blobs
11
+ .ambient-content your content, above the layers
12
+
13
+ Blobs derive from --color-brand-solid / --color-accent-solid, so they
14
+ follow the active product. Motion respects prefers-reduced-motion.
15
+ ============================================================ */
16
+
17
+ .ambient {
18
+ position: relative;
19
+ isolation: isolate;
20
+ overflow: hidden;
21
+ }
22
+
23
+ .ambient-blob {
24
+ position: absolute;
25
+ z-index: 0;
26
+ border-radius: var(--radius-pill);
27
+ filter: blur(80px);
28
+ pointer-events: none;
29
+ opacity: 0.55;
30
+ will-change: transform;
31
+ }
32
+ .ambient-blob.is-1 {
33
+ width: 46%;
34
+ aspect-ratio: 1;
35
+ top: -12%;
36
+ left: -8%;
37
+ background: radial-gradient(circle at 50% 50%, var(--color-brand-solid) 0%, transparent 70%);
38
+ animation: ambient-drift-a 22s var(--ease-linear) infinite alternate;
39
+ }
40
+ .ambient-blob.is-2 {
41
+ width: 38%;
42
+ aspect-ratio: 1;
43
+ bottom: -16%;
44
+ right: -6%;
45
+ background: radial-gradient(circle at 50% 50%, var(--color-accent-solid) 0%, transparent 70%);
46
+ animation: ambient-drift-b 28s var(--ease-linear) infinite alternate;
47
+ }
48
+ .ambient-blob.is-3 {
49
+ width: 30%;
50
+ aspect-ratio: 1;
51
+ top: 30%;
52
+ left: 42%;
53
+ background: radial-gradient(circle at 50% 50%, var(--color-brand-solid) 0%, transparent 72%);
54
+ opacity: 0.35;
55
+ animation: ambient-drift-a 34s var(--ease-linear) infinite alternate-reverse;
56
+ }
57
+
58
+ @keyframes ambient-drift-a {
59
+ from { transform: translate3d(0, 0, 0) scale(1); }
60
+ to { transform: translate3d(6%, 8%, 0) scale(1.12); }
61
+ }
62
+ @keyframes ambient-drift-b {
63
+ from { transform: translate3d(0, 0, 0) scale(1.06); }
64
+ to { transform: translate3d(-7%, -6%, 0) scale(1); }
65
+ }
66
+
67
+ /* Readability veil — REQUIRED. Without it, body copy over the blobs
68
+ drops below AA at the blob centres. */
69
+ .ambient-scrim {
70
+ position: absolute;
71
+ inset: 0;
72
+ z-index: 1;
73
+ pointer-events: none;
74
+ background: linear-gradient(180deg,
75
+ color-mix(in srgb, var(--color-background-canvas) 62%, transparent) 0%,
76
+ color-mix(in srgb, var(--color-background-canvas) 86%, transparent) 100%);
77
+ }
78
+ /* On a permanently-dark hero, veil with ink instead of the ambient canvas */
79
+ .ambient.on-inverse .ambient-scrim {
80
+ background: linear-gradient(180deg,
81
+ color-mix(in srgb, var(--color-background-inverse) 58%, transparent) 0%,
82
+ color-mix(in srgb, var(--color-background-inverse) 84%, transparent) 100%);
83
+ }
84
+ .ambient.on-inverse { background: var(--color-background-inverse); color: var(--color-foreground-inverse-default); }
85
+
86
+ .ambient-content {
87
+ position: relative;
88
+ z-index: 2;
89
+ }
90
+
91
+ /* Intensity modifiers */
92
+ .ambient.is-subtle .ambient-blob { opacity: 0.3; }
93
+ .ambient.is-strong .ambient-blob { opacity: 0.75; filter: blur(64px); }
94
+
95
+ @media (prefers-reduced-motion: reduce) {
96
+ .ambient-blob { animation: none; }
97
+ }
@@ -0,0 +1,261 @@
1
+ /* ============================================================
2
+ ANIMATED BACKDROP — components/animated-bg.css
3
+ Nine full-bleed animated backgrounds for hero, onboarding and
4
+ marketing surfaces. Companion to `.ambient` (which is the plain
5
+ blob layer): these carry motion vocabulary — aurora drift, cursor
6
+ mesh, scanning grid, ripples, beams, orbits, apex bloom, triangles.
7
+
8
+ Structure (mirrors .ambient so the two are interchangeable):
9
+ .abg[.abg-<variant>] positioned host
10
+ .abg-layer one or more decorative layers (aria-hidden)
11
+ .abg-scrim MANDATORY readability veil when text sits on top
12
+ .abg-content your content, above every layer
13
+
14
+ Every tint derives from --color-brand-solid / --color-accent-solid and the
15
+ Sky/Royal accent stops, so a backdrop follows the active product theme.
16
+ The ambient ink base uses --abg-ink, which flips with the theme.
17
+
18
+ Variants: aurora · mesh · grid · ripple · beams · orbits · apex · triangles
19
+ Modifiers: .is-subtle / .is-strong (layer opacity) · .on-inverse (dark hero)
20
+ Motion is disabled under prefers-reduced-motion.
21
+ ============================================================ */
22
+
23
+ .abg {
24
+ position: relative;
25
+ isolation: isolate;
26
+ overflow: hidden;
27
+ /* Ink base — the deep field every variant paints on. Theme-aware. */
28
+ --abg-ink: var(--color-background-canvas);
29
+ --abg-base: var(--color-background-subtle);
30
+ --abg-glint: var(--color-brand-accent-700);
31
+ background: var(--abg-ink);
32
+ }
33
+ [data-theme="dark"] .abg,
34
+ .abg.on-inverse {
35
+ --abg-ink: var(--color-ink-deep);
36
+ --abg-base: var(--color-ink-base);
37
+ --abg-glint: var(--color-brand-accent-200);
38
+ }
39
+ .abg.on-inverse {
40
+ background: var(--abg-ink);
41
+ color: var(--color-foreground-inverse-default);
42
+ }
43
+
44
+ .abg-layer {
45
+ position: absolute;
46
+ inset: 0;
47
+ z-index: 0;
48
+ pointer-events: none;
49
+ }
50
+ /* On a light ambient surface a translucent layer over white turns grey;
51
+ multiply keeps the hue and only darkens what is actually painted. */
52
+ .abg:not(.on-inverse) .abg-layer.is-tinted { mix-blend-mode: multiply; }
53
+ [data-theme="dark"] .abg:not(.on-inverse) .abg-layer.is-tinted { mix-blend-mode: normal; }
54
+
55
+ /* Readability veil — REQUIRED whenever content sits on the backdrop. */
56
+ .abg-scrim {
57
+ position: absolute;
58
+ inset: 0;
59
+ z-index: 1;
60
+ pointer-events: none;
61
+ background: linear-gradient(100deg,
62
+ var(--abg-ink) 24%,
63
+ color-mix(in srgb, var(--abg-ink) 76%, transparent) 48%,
64
+ transparent 74%);
65
+ }
66
+ /* Vertical veil — for centred hero copy instead of a left-anchored block */
67
+ .abg-scrim.is-vertical {
68
+ background: linear-gradient(180deg,
69
+ color-mix(in srgb, var(--abg-ink) 58%, transparent) 0%,
70
+ color-mix(in srgb, var(--abg-ink) 86%, transparent) 100%);
71
+ }
72
+
73
+ .abg-content { position: relative; z-index: 2; }
74
+
75
+ /* Intensity — subtle dims the layers; strong cannot use opacity > 1 (it clamps
76
+ to 1 and does nothing), so it lifts saturation and brightness instead. */
77
+ .abg.is-subtle .abg-layer { opacity: .55; }
78
+ .abg.is-strong .abg-layer { filter: saturate(1.3) brightness(1.18); }
79
+ .abg.is-strong .abg-blob { filter: blur(64px) saturate(1.3) brightness(1.18); }
80
+
81
+ /* Shared vignette — pulls focus to the centre, mutes the edges */
82
+ .abg-vignette {
83
+ background: radial-gradient(125% 100% at 50% 45%, transparent 40%,
84
+ color-mix(in srgb, var(--abg-ink) 92%, transparent) 100%);
85
+ }
86
+
87
+ /* ============================================================
88
+ 01 · AURORA — four drifting radial blobs, heavy blur
89
+ ============================================================ */
90
+ .abg-aurora .abg-blob {
91
+ position: absolute;
92
+ border-radius: var(--radius-pill);
93
+ filter: blur(64px);
94
+ will-change: transform;
95
+ }
96
+ .abg-aurora .abg-blob.is-1 {
97
+ top: -30%; right: -20%; width: 70%; aspect-ratio: 1; opacity: .38;
98
+ background: radial-gradient(circle, color-mix(in srgb, var(--color-brand-accent-500) 52%, transparent), transparent 66%);
99
+ animation: abg-drift-a 26s var(--ease-standard) infinite;
100
+ }
101
+ .abg-aurora .abg-blob.is-2 {
102
+ bottom: -40%; left: -18%; width: 82%; aspect-ratio: 1; opacity: .35;
103
+ background: radial-gradient(circle, color-mix(in srgb, var(--color-brand-secondary-400) 60%, transparent), transparent 68%);
104
+ animation: abg-drift-b 32s var(--ease-standard) infinite;
105
+ }
106
+ .abg-aurora .abg-blob.is-3 {
107
+ top: 8%; left: 24%; width: 46%; aspect-ratio: 1; opacity: .29;
108
+ background: radial-gradient(circle, color-mix(in srgb, var(--dataviz-cat-5) 48%, transparent), transparent 66%);
109
+ animation: abg-drift-c 38s var(--ease-standard) infinite;
110
+ }
111
+ .abg-aurora .abg-blob.is-4 {
112
+ bottom: -14%; right: 6%; width: 52%; aspect-ratio: 1; opacity: .26;
113
+ background: radial-gradient(circle, color-mix(in srgb, var(--dataviz-cat-3) 44%, transparent), transparent 66%);
114
+ animation: abg-drift-d 44s var(--ease-standard) infinite;
115
+ }
116
+ @keyframes abg-drift-a { 0%,100% { transform: translate3d(0,0,0) scale(1); } 50% { transform: translate3d(18%,-14%,0) scale(1.3); } }
117
+ @keyframes abg-drift-b { 0%,100% { transform: translate3d(0,0,0) scale(1.12); } 50% { transform: translate3d(-22%,16%,0) scale(.82); } }
118
+ @keyframes abg-drift-c { 0%,100% { transform: translate3d(0,0,0) scale(1); } 50% { transform: translate3d(16%,20%,0) scale(1.18); } }
119
+ @keyframes abg-drift-d { 0%,100% { transform: translate3d(0,0,0) scale(1); } 33% { transform: translate3d(-24%,14%,0) scale(1.26); } 66% { transform: translate3d(20%,-18%,0) scale(.86); } }
120
+
121
+ /* ============================================================
122
+ 02 · MESH — static dot mesh; dots brighten around the cursor.
123
+ The bright layer is revealed through a radial mask at --mx/--my,
124
+ updated by a pointermove listener on the host.
125
+ ============================================================ */
126
+ .abg-mesh .abg-dotglow {
127
+ position: absolute;
128
+ inset: 0;
129
+ opacity: 0;
130
+ transition: opacity var(--duration-slower) var(--ease-standard);
131
+ -webkit-mask-image: radial-gradient(210px 210px at var(--mx, -999px) var(--my, -999px), rgba(0,0,0,.6) 0%, rgba(0,0,0,.3) 46%, rgba(0,0,0,.12) 68%, transparent 84%);
132
+ mask-image: radial-gradient(210px 210px at var(--mx, -999px) var(--my, -999px), rgba(0,0,0,.6) 0%, rgba(0,0,0,.3) 46%, rgba(0,0,0,.12) 68%, transparent 84%);
133
+ }
134
+ .abg-mesh:hover .abg-dotglow { animation: abg-dotpulse 4.2s var(--ease-standard) infinite; }
135
+ @keyframes abg-dotpulse { 0%,100% { opacity: .18; } 50% { opacity: .5; } }
136
+
137
+ /* ============================================================
138
+ 03 · GRID — flat relative grid with glints running the lines
139
+ ============================================================ */
140
+ .abg-grid .abg-gridlines {
141
+ -webkit-mask-image: radial-gradient(115% 95% at 58% 46%, #000 26%, transparent 78%);
142
+ mask-image: radial-gradient(115% 95% at 58% 46%, #000 26%, transparent 78%);
143
+ background-image:
144
+ linear-gradient(color-mix(in srgb, var(--color-brand-accent-500) 11%, transparent) 1px, transparent 1px),
145
+ linear-gradient(90deg, color-mix(in srgb, var(--color-brand-accent-500) 11%, transparent) 1px, transparent 1px);
146
+ background-size: 3.846% 6.25%;
147
+ }
148
+ .abg-grid .abg-glint-x,
149
+ .abg-grid .abg-glint-y { position: absolute; }
150
+ .abg-grid .abg-glint-x {
151
+ left: 0; height: 1px;
152
+ background: linear-gradient(90deg, transparent, var(--abg-glint), transparent);
153
+ animation: abg-glint-x 12s var(--ease-standard) infinite;
154
+ }
155
+ .abg-grid .abg-glint-y {
156
+ top: 0; width: 1px;
157
+ background: linear-gradient(180deg, transparent, var(--abg-glint), transparent);
158
+ animation: abg-glint-y 14s var(--ease-standard) infinite;
159
+ }
160
+ /* Travel the whole line: animate left/top in % of the host, not translate in %
161
+ of the element's own width (which only moved it ~25% across). */
162
+ @keyframes abg-glint-x {
163
+ 0% { left: -26%; opacity: 0; } 10% { opacity: .34; }
164
+ 46% { opacity: .34; } 56%, 100% { left: 100%; opacity: 0; }
165
+ }
166
+ @keyframes abg-glint-y {
167
+ 0% { top: -26%; opacity: 0; } 10% { opacity: .3; }
168
+ 46% { opacity: .3; } 56%, 100% { top: 100%; opacity: 0; }
169
+ }
170
+
171
+ /* ============================================================
172
+ 04 · RIPPLE — concentric waves emanating from one point
173
+ ============================================================ */
174
+ @keyframes abg-ripple { 0% { transform: scale(.06); opacity: .6; } 100% { transform: scale(1); opacity: 0; } }
175
+ @keyframes abg-ripple-soft { 0% { transform: scale(.06); opacity: .2; } 100% { transform: scale(1); opacity: 0; } }
176
+
177
+ /* ============================================================
178
+ 05 · BEAMS — horizontal light trails at mixed speeds
179
+ ============================================================ */
180
+ .abg-beams .abg-tracks {
181
+ inset: 6% 0;
182
+ display: flex;
183
+ flex-direction: column;
184
+ justify-content: space-between;
185
+ }
186
+ .abg-beams .abg-track {
187
+ position: relative;
188
+ height: 1px;
189
+ width: 100%;
190
+ overflow: hidden;
191
+ background: linear-gradient(90deg, transparent,
192
+ color-mix(in srgb, var(--color-brand-accent-500) 7%, transparent) 45%,
193
+ color-mix(in srgb, var(--color-brand-accent-500) 4%, transparent));
194
+ }
195
+ .abg-beams .abg-beam {
196
+ position: absolute;
197
+ top: 0; height: 1px;
198
+ border-radius: var(--radius-pill);
199
+ background: linear-gradient(90deg, transparent, var(--color-brand-accent-300), transparent);
200
+ animation: abg-beam-h 9s linear infinite;
201
+ }
202
+ .abg-beams .abg-beam.is-strong {
203
+ top: -1px; height: 3px;
204
+ background: linear-gradient(90deg, transparent, var(--color-brand-accent-200), transparent);
205
+ }
206
+ @keyframes abg-beam-h { 0% { transform: translateX(-110%); } 100% { transform: translateX(240%); } }
207
+
208
+ /* ============================================================
209
+ 06 · ORBITS — concentric rings with satellites, alternating spin
210
+ ============================================================ */
211
+ .abg-orbits .abg-hub {
212
+ position: absolute;
213
+ top: 50%; left: 62%;
214
+ width: 0; height: 0;
215
+ }
216
+ .abg-orbits .abg-ring {
217
+ position: absolute;
218
+ border-radius: var(--radius-pill);
219
+ border: 1px solid color-mix(in srgb, var(--color-brand-accent-500) 14%, transparent);
220
+ animation: abg-orbit 32s linear infinite;
221
+ }
222
+ .abg-orbits .abg-sat {
223
+ position: absolute;
224
+ top: -1.5px; left: 50%;
225
+ width: 3px; height: 3px;
226
+ border-radius: var(--radius-pill);
227
+ background: var(--color-brand-accent-300);
228
+ box-shadow: 0 0 6px var(--color-brand-accent-500);
229
+ }
230
+ .abg-orbits .abg-core {
231
+ position: absolute;
232
+ left: -4px; top: -4px;
233
+ width: 8px; height: 8px;
234
+ border-radius: var(--radius-pill);
235
+ background: var(--color-brand-accent-300);
236
+ box-shadow: 0 0 16px var(--color-brand-accent-500);
237
+ }
238
+ @keyframes abg-orbit { to { transform: rotate(360deg); } }
239
+
240
+ /* ============================================================
241
+ 07 · APEX — the brand mark outlined, with a light beam tracing it.
242
+ The dash period equals the path length, so exactly one beam rides
243
+ the contour and its tail re-enters at the start.
244
+ ============================================================ */
245
+ @keyframes abg-apex-glint { from { stroke-dashoffset: 628; } to { stroke-dashoffset: 0; } }
246
+
247
+ /* ============================================================
248
+ 08 · TRIANGLES — oversized translucent planes in slow drift
249
+ ============================================================ */
250
+ @keyframes abg-tri-a { 0% { transform: translate3d(-6%, 4%, 0) rotate(0deg); } 100% { transform: translate3d(8%, -6%, 0) rotate(14deg); } }
251
+ @keyframes abg-tri-b { 0% { transform: translate3d(6%, -5%, 0) rotate(0deg); } 100% { transform: translate3d(-9%, 7%, 0) rotate(-18deg); } }
252
+ @keyframes abg-tri-c { 0% { transform: translate3d(0, 8%, 0) rotate(-8deg); } 100% { transform: translate3d(-7%, -9%, 0) rotate(10deg); } }
253
+ @keyframes abg-tri-d { 0% { transform: translate3d(-8%, -7%, 0) rotate(6deg); } 100% { transform: translate3d(10%, 8%, 0) rotate(-12deg); } }
254
+
255
+ @media (prefers-reduced-motion: reduce) {
256
+ .abg-layer, .abg-blob, .abg-glint-x, .abg-glint-y, .abg-beam,
257
+ .abg-ring, .abg-dotglow, .abg [style*="animation"] {
258
+ animation: none !important;
259
+ }
260
+ .abg-dotglow { transition: none; }
261
+ }
@@ -47,7 +47,7 @@
47
47
  /* Type */
48
48
  font-family: var(--font-sans);
49
49
  font-size: var(--fs-md);
50
- font-weight: var(--w-semibold);
50
+ font-weight: var(--w-regular);
51
51
  line-height: 1;
52
52
  letter-spacing: var(--ls-body);
53
53
 
@@ -184,8 +184,8 @@
184
184
  border-radius: var(--radius-2xs);
185
185
  text-decoration: none;
186
186
  }
187
- .btn-link:hover { color: var(--color-brand-text); text-decoration: underline; text-underline-offset: 2px; }
188
- .btn-link:active { color: var(--color-brand-text-strong); }
187
+ .btn-link:hover { color: var(--color-foreground-brand); text-decoration: underline; text-underline-offset: 2px; }
188
+ .btn-link:active { color: var(--color-foreground-brand); filter: brightness(.9); }
189
189
  .btn-link:focus-visible { box-shadow: var(--shadow-focus); }
190
190
 
191
191
 
@@ -223,7 +223,7 @@
223
223
  /* INVERSE — white pill on dark/brand surfaces */
224
224
  .btn-inverse {
225
225
  background: var(--color-pure-white);
226
- color: var(--color-brand-text);
226
+ color: var(--color-brand-text-on-light);
227
227
  }
228
228
  .btn-inverse:hover { background: var(--color-neutral-100); color: var(--color-brand-text-strong); }
229
229
  .btn-inverse:active { background: var(--color-neutral-150); }
@@ -70,7 +70,7 @@
70
70
 
71
71
  .callout-title {
72
72
  font-size: var(--fs-md);
73
- font-weight: var(--w-semibold);
73
+ font-weight: var(--w-regular);
74
74
  letter-spacing: var(--ls-title);
75
75
  color: var(--color-foreground-default);
76
76
  line-height: var(--lh-tight);
@@ -81,13 +81,14 @@
81
81
  color: var(--color-foreground-secondary);
82
82
  line-height: var(--lh-snug);
83
83
  }
84
- .callout-body strong { color: var(--color-foreground-default); font-weight: var(--w-semibold); }
84
+ .callout-body strong { color: var(--color-foreground-default); font-weight: var(--w-regular); }
85
85
  .callout-body code {
86
86
  font-family: var(--font-mono);
87
+ font-size-adjust: var(--font-mono-adjust);
87
88
  font-size: var(--fs-xs);
88
89
  color: var(--color-foreground-accent);
89
90
  }
90
- .callout-body a { color: var(--color-foreground-accent); text-decoration: none; font-weight: var(--w-semibold); }
91
+ .callout-body a { color: var(--color-foreground-accent); text-decoration: none; font-weight: var(--w-regular); }
91
92
  .callout-body p { margin: 0 0 var(--space-2); }
92
93
  .callout-body p:last-child { margin-bottom: 0; }
93
94
  .callout-body ul { margin: var(--space-2) 0 0; padding-left: var(--space-5); }
@@ -144,7 +144,7 @@
144
144
  .card-header h4 {
145
145
  margin: 0;
146
146
  font-size: var(--fs-md);
147
- font-weight: var(--w-semibold);
147
+ font-weight: var(--w-regular);
148
148
  letter-spacing: var(--ls-title);
149
149
  color: var(--color-foreground-default);
150
150
  }
@@ -206,8 +206,9 @@
206
206
  }
207
207
  .card-stat .stat-label {
208
208
  font-family: var(--font-mono);
209
+ font-size-adjust: var(--font-mono-adjust);
209
210
  font-size: var(--fs-xxs);
210
- font-weight: var(--w-semibold);
211
+ font-weight: var(--w-regular);
211
212
  color: var(--color-foreground-muted);
212
213
  text-transform: uppercase;
213
214
  letter-spacing: var(--ls-caps);
@@ -226,7 +227,7 @@
226
227
  align-items: center;
227
228
  gap: var(--space-1);
228
229
  font-size: var(--fs-xs);
229
- font-weight: var(--w-semibold);
230
+ font-weight: var(--w-regular);
230
231
  font-variant-numeric: tabular-nums;
231
232
  }
232
233
  .card-stat .stat-delta.up { color: var(--color-feedback-success-foreground); }
@@ -24,7 +24,7 @@
24
24
  border-radius: var(--radius-sm);
25
25
  font-family: var(--font-sans);
26
26
  font-size: var(--fs-sm);
27
- font-weight: var(--w-medium);
27
+ font-weight: var(--w-regular);
28
28
  color: var(--color-foreground-default);
29
29
  cursor: pointer;
30
30
  text-align: left;
@@ -74,10 +74,10 @@
74
74
  width: 24px; height: 24px;
75
75
  border-radius: var(--radius-pill);
76
76
  background: var(--color-brand-subtle-solid);
77
- color: var(--color-brand-text);
77
+ color: var(--color-brand-text-on-light);
78
78
  display: inline-flex; align-items: center; justify-content: center;
79
79
  font-size: var(--fs-xxs);
80
- font-weight: var(--w-semibold);
80
+ font-weight: var(--w-regular);
81
81
  flex-shrink: 0;
82
82
  margin-left: calc(var(--space-1) * -1);
83
83
  }
@@ -148,8 +148,9 @@
148
148
  .combobox-group-label {
149
149
  padding: var(--space-2) var(--space-3) var(--space-1);
150
150
  font-family: var(--font-mono);
151
+ font-size-adjust: var(--font-mono-adjust);
151
152
  font-size: var(--fs-xxs);
152
- font-weight: var(--w-semibold);
153
+ font-weight: var(--w-regular);
153
154
  letter-spacing: var(--ls-caps);
154
155
  text-transform: uppercase;
155
156
  color: var(--color-foreground-muted);
@@ -173,7 +174,7 @@
173
174
  .combobox-option.is-selected {
174
175
  background: var(--color-background-selected);
175
176
  color: var(--color-foreground-accent);
176
- font-weight: var(--w-semibold);
177
+ font-weight: var(--w-regular);
177
178
  }
178
179
  .combobox-option.is-disabled {
179
180
  opacity: 0.5;
@@ -198,7 +199,7 @@
198
199
  margin-top: 1px;
199
200
  }
200
201
  .combobox-option.is-selected .combobox-option-meta {
201
- color: var(--color-brand-text);
202
+ color: var(--color-foreground-brand);
202
203
  }
203
204
 
204
205
  .combobox-option-check {
@@ -212,6 +213,7 @@
212
213
 
213
214
  .combobox-option-trailing {
214
215
  font-family: var(--font-mono);
216
+ font-size-adjust: var(--font-mono-adjust);
215
217
  font-size: var(--fs-xxs);
216
218
  color: var(--color-foreground-muted);
217
219
  flex-shrink: 0;
@@ -227,7 +229,7 @@
227
229
  .combobox-empty strong {
228
230
  display: block;
229
231
  color: var(--color-foreground-default);
230
- font-weight: var(--w-semibold);
232
+ font-weight: var(--w-regular);
231
233
  margin-bottom: var(--space-1);
232
234
  }
233
235
 
@@ -251,7 +253,7 @@
251
253
  border-radius: var(--radius-sm);
252
254
  font-family: var(--font-sans);
253
255
  font-size: var(--fs-sm);
254
- font-weight: var(--w-semibold);
256
+ font-weight: var(--w-regular);
255
257
  color: var(--color-foreground-default);
256
258
  cursor: pointer;
257
259
  text-align: center;
@@ -304,12 +306,13 @@
304
306
  `filters` / `meta` / `footMeta`.
305
307
  ---------------------------------------------------------------- */
306
308
  .combobox-filters { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-3); border-bottom: 1px solid var(--color-border-subtle); }
307
- .combobox-filter-chip { display: inline-flex; align-items: center; gap: var(--space-2); padding: 4px var(--space-3); background: var(--color-background-surface); border: 1px solid var(--color-border-default); border-radius: var(--radius-pill); font-family: var(--font-sans); font-size: var(--fs-xs); font-weight: var(--w-medium); color: var(--color-foreground-secondary); cursor: pointer; transition: var(--transition-fast); }
309
+ .combobox-filter-chip { display: inline-flex; align-items: center; gap: var(--space-2); padding: 4px var(--space-3); background: var(--color-background-surface); border: 1px solid var(--color-border-default); border-radius: var(--radius-pill); font-family: var(--font-sans); font-size: var(--fs-xs); font-weight: var(--w-regular); color: var(--color-foreground-secondary); cursor: pointer; transition: var(--transition-fast); }
308
310
  .combobox-filter-chip:hover { background: var(--color-background-hover); border-color: var(--color-border-strong); color: var(--color-foreground-default); }
309
- .combobox-filter-chip.is-active { background: var(--color-background-selected); border-color: var(--color-brand-border); color: var(--color-foreground-brand); font-weight: var(--w-semibold); }
310
- .combobox-filter-chip .count { font-family: var(--font-mono); font-size: var(--fs-xxs); color: var(--color-foreground-muted); }
311
- .combobox-filter-chip.is-active .count { color: var(--color-brand-text); }
312
- .combobox-meta { padding: var(--space-2) var(--space-3) var(--space-1); font-size: var(--fs-xxs); font-weight: var(--w-semibold); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--color-foreground-muted); border-bottom: 1px solid var(--color-border-subtle); }
311
+ .combobox-filter-chip.is-active { background: var(--color-background-selected); border-color: var(--color-brand-border); color: var(--color-foreground-brand); font-weight: var(--w-regular); }
312
+ .combobox-filter-chip .count { font-family: var(--font-mono);
313
+ font-size-adjust: var(--font-mono-adjust); font-size: var(--fs-xxs); color: var(--color-foreground-muted); }
314
+ .combobox-filter-chip.is-active .count { color: var(--color-foreground-brand); }
315
+ .combobox-meta { padding: var(--space-2) var(--space-3) var(--space-1); font-size: var(--fs-xxs); font-weight: var(--w-regular); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--color-foreground-muted); border-bottom: 1px solid var(--color-border-subtle); }
313
316
  .combobox-foot-meta { padding: var(--space-2) var(--space-3); font-size: var(--fs-xs); color: var(--color-foreground-muted); border-top: 1px solid var(--color-border-subtle); }
314
317
 
315
318
  /* Reduced motion */