astralkit 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,567 +1,543 @@
1
1
  /* ══════════════════════════════════════════════════════════
2
- AstralKit Component Primitives
3
- Only things Tailwind classes can't express:
4
- - Pseudo-elements (tooltips)
5
- - Parent-state child selectors ([data-expanded] children)
6
- - Transitions on width (not supported by Tailwind)
7
-
8
- IMPORTANT: All rules MUST be inside @layer so they don't
9
- become unlayered CSS. Unlayered styles override ALL layered
10
- utility classes (text-white, text-[#fff], etc.) regardless
11
- of specificity — this is how CSS cascade layers work.
12
- ══════════════════════════════════════════════════════════ */
13
-
14
- @layer base {
15
- /* Tailwind v4 preflight already sets a { color: inherit },
16
- so we only add text-decoration: none here. */
17
- a { text-decoration: none; }
18
- }
2
+ AstralKit Component CSS & Primitives
19
3
 
20
- @layer components {
4
+ Tokens live in astralkit-theme.css (v3/:root) or
5
+ astralkit-theme-v4.css (v4/@theme). This file contains
6
+ only base resets, component primitives, and utility classes.
21
7
 
22
- /* Focus ring Tailwind v4 has no --focus-* namespace, so this must be a utility class */
23
- .ak-focus-ring {
24
- outline: none;
25
- }
26
- .ak-focus-ring:focus-visible {
27
- outline: 2px solid var(--color-ak-border-focus);
28
- outline-offset: 2px;
29
- }
30
- /* Inset variant for menu items inside panels */
31
- .ak-focus-ring-inset {
32
- outline: none;
33
- }
34
- .ak-focus-ring-inset:focus-visible {
35
- outline: 2px solid var(--color-ak-border-focus);
36
- outline-offset: -2px;
37
- }
38
-
39
- /* ── Heading Presets ──
40
- Composite heading styles. Usage: <h1 class="ak-h1">
41
- Combine font-size, line-height, letter-spacing, weight. */
42
- .ak-h1 {
43
- font-size: var(--text-ak-5xl);
44
- line-height: var(--leading-ak-tight);
45
- letter-spacing: var(--tracking-ak-tighter);
46
- font-weight: 700;
47
- color: var(--color-ak-text);
48
- }
49
- .ak-h2 {
50
- font-size: var(--text-ak-4xl);
51
- line-height: var(--leading-ak-tight);
52
- letter-spacing: var(--tracking-ak-tight);
53
- font-weight: 700;
54
- color: var(--color-ak-text);
55
- }
56
- .ak-h3 {
57
- font-size: var(--text-ak-3xl);
58
- line-height: var(--leading-ak-snug);
59
- letter-spacing: var(--tracking-ak-tight);
60
- font-weight: 600;
61
- color: var(--color-ak-text);
62
- }
63
- .ak-h4 {
64
- font-size: var(--text-ak-2xl);
65
- line-height: var(--leading-ak-snug);
66
- letter-spacing: var(--tracking-ak-normal);
67
- font-weight: 600;
68
- color: var(--color-ak-text);
69
- }
70
- .ak-h5 {
71
- font-size: var(--text-ak-xl);
72
- line-height: var(--leading-ak-snug);
73
- letter-spacing: var(--tracking-ak-normal);
74
- font-weight: 600;
75
- color: var(--color-ak-text);
76
- }
77
- .ak-h6 {
78
- font-size: var(--text-ak-lg);
79
- line-height: var(--leading-ak-snug);
80
- letter-spacing: var(--tracking-ak-normal);
81
- font-weight: 500;
82
- color: var(--color-ak-text);
83
- }
84
-
85
- /* ── Body / Caption Presets ── */
86
- .ak-body {
87
- font-size: var(--text-ak-base);
88
- line-height: var(--leading-ak-normal);
89
- color: var(--color-ak-text);
90
- }
91
- .ak-body-secondary {
92
- font-size: var(--text-ak-base);
93
- line-height: var(--leading-ak-normal);
94
- color: var(--color-ak-text-secondary);
95
- }
96
- .ak-small {
97
- font-size: var(--text-ak-sm);
98
- line-height: var(--leading-ak-normal);
99
- color: var(--color-ak-text-secondary);
100
- }
101
- .ak-caption {
102
- font-size: var(--text-ak-xs);
103
- line-height: var(--leading-ak-normal);
104
- color: var(--color-ak-text-muted);
105
- }
106
- .ak-label {
107
- font-size: var(--text-ak-xs);
108
- line-height: var(--leading-ak-normal);
109
- font-weight: 600;
110
- letter-spacing: var(--tracking-ak-wider);
111
- text-transform: uppercase;
112
- color: var(--color-ak-text-muted);
113
- }
114
-
115
- /* ── UI Chrome Typography Presets ──
116
- For shell, nav, panels, forms — NOT document content.
117
- Each bundles size + weight + line-height + tracking + color. */
118
- .ak-overline { font-size: var(--text-ak-xs); font-weight: 600; line-height: 1; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-ak-text-muted); }
119
- .ak-form-label { font-size: var(--text-ak-sm); font-weight: 500; line-height: 1; color: var(--color-ak-text); }
120
- .ak-helper { font-size: var(--text-ak-xs); font-weight: 400; line-height: 1.3; color: var(--color-ak-text-muted); }
121
- .ak-ui-body { font-size: var(--text-ak-sm); font-weight: 400; line-height: 1.5; color: var(--color-ak-text-secondary); }
122
- .ak-nav-label-text { font-size: var(--text-ak-base); font-weight: 500; line-height: 1; color: var(--color-ak-text); }
123
- .ak-card-title { font-size: var(--text-ak-base); font-weight: 600; line-height: 1.2; letter-spacing: -0.01em; color: var(--color-ak-text); }
124
- .ak-panel-title { font-size: var(--text-ak-lg); font-weight: 600; line-height: 1.2; letter-spacing: -0.01em; color: var(--color-ak-text); }
125
- .ak-page-title { font-size: var(--text-ak-xl); font-weight: 600; line-height: 1.15; letter-spacing: -0.015em; color: var(--color-ak-text); }
126
-
127
- /* Icon sizes (referenced by theme, will move to @theme when Tailwind supports --size-*) */
128
- .ak-icon-xs { font-size: var(--size-ak-icon-xs); line-height: 1; }
129
- .ak-icon-sm { font-size: var(--size-ak-icon-sm); line-height: 1; }
130
- .ak-icon-md { font-size: var(--size-ak-icon-md); line-height: 1; }
131
- .ak-icon-lg { font-size: var(--size-ak-icon-lg); line-height: 1; }
132
- .ak-icon-xl { font-size: var(--size-ak-icon-xl); line-height: 1; }
133
- .ak-icon-2xl { font-size: var(--size-ak-icon-2xl); line-height: 1; }
134
- .ak-icon-3xl { font-size: var(--size-ak-icon-3xl); line-height: 1; }
135
-
136
- /* Sidebar: width transition (Tailwind can't transition between two width values) */
137
- [data-ak-sidebar] {
138
- width: 5rem;
139
- transition: width 240ms cubic-bezier(0.4, 0, 0.2, 1);
140
- }
141
- [data-ak-sidebar][data-expanded] {
142
- width: 18rem;
143
- align-items: stretch;
144
- }
145
-
146
- /* Expanded: nav items go full-width left-aligned */
147
- [data-expanded] .ak-nav-item {
148
- width: 100%;
149
- justify-content: flex-start;
150
- padding-left: 1rem;
151
- padding-right: 0.75rem;
152
- gap: 0.75rem;
153
- }
154
- [data-expanded] .ak-nav-item.ak-logo-item {
155
- padding-left: 0.5rem;
156
- padding-right: 0.5rem;
157
- gap: 0.5rem;
158
- }
159
-
160
- /* Mobile bar labels */
161
- .ak-mobile-label { font-size: var(--size-ak-icon-sm); font-weight: 500; line-height: 1.25; }
162
-
163
- /* Nav labels: hidden collapsed, shown expanded */
164
- .ak-nav-label {
165
- display: none;
166
- font-size: 1rem;
167
- line-height: 1.5;
168
- white-space: nowrap;
169
- overflow: hidden;
170
- text-overflow: ellipsis;
171
- flex: 1;
172
- min-width: 0;
173
- text-align: left;
174
- }
175
- [data-expanded] .ak-nav-label { display: block; }
176
-
177
- /* Tooltips (CSS pseudo-elements — can't do in Tailwind) */
178
- [data-ak-tooltip] { position: relative; }
179
- [data-ak-tooltip]::before {
180
- content: '';
181
- position: absolute;
182
- left: 100%; top: 50%; transform: translateY(-50%);
183
- width: 0.75rem; height: 100%;
184
- pointer-events: none;
185
- }
186
- [data-ak-tooltip]::after {
187
- content: attr(data-ak-tooltip);
188
- position: absolute;
189
- left: calc(100% + 0.5rem); top: 50%;
190
- transform: translateY(-50%);
191
- background: var(--color-ak-text);
192
- color: var(--color-ak-text-inverse);
193
- font-size: var(--size-ak-icon-sm);
194
- line-height: 1.25;
195
- padding: 0.375rem 0.75rem;
196
- border-radius: var(--radius-ak-md);
197
- white-space: nowrap;
198
- pointer-events: none;
199
- opacity: 0;
200
- transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);
201
- z-index: var(--z-ak-modal);
202
- }
203
- [data-ak-tooltip]:hover::after,
204
- [data-ak-tooltip]:focus-visible::after { opacity: 1; }
205
- [data-ak-tooltip]:hover::before { pointer-events: auto; }
206
- [data-expanded] [data-ak-tooltip]::after,
207
- [data-expanded] [data-ak-tooltip]::before { display: none; }
208
- @media (max-width: 767px) {
209
- [data-ak-tooltip]::before,
210
- [data-ak-tooltip]::after { display: none; }
211
- }
212
-
213
- /* Account switcher: collapsed vs expanded (complex child selectors) */
214
- [data-expanded] .ak-profile-info { display: flex; }
215
- [data-expanded] .ak-account-chevron { display: flex; }
216
- [data-expanded] .ak-account-trigger {
217
- justify-content: space-between;
218
- border: 1px solid var(--color-ak-border);
219
- border-radius: var(--radius-ak-lg);
220
- padding: 0.625rem 0.75rem;
221
- gap: 0.625rem;
222
- min-height: auto;
223
- }
224
- [data-expanded] .ak-account-left { gap: 0.625rem; }
225
-
226
- /* Mobile overlay transition */
227
- .ak-mobile-overlay {
228
- position: fixed; inset: 0;
229
- z-index: var(--z-ak-overlay);
230
- background: var(--color-ak-overlay);
231
- opacity: 0; visibility: hidden;
232
- transition: opacity 240ms cubic-bezier(0.4, 0, 0.2, 1),
233
- visibility 240ms cubic-bezier(0.4, 0, 0.2, 1);
234
- }
235
- .ak-mobile-overlay-open { opacity: 1; visibility: visible; }
236
-
237
- /* Mobile sheet transition */
238
- .ak-mobile-sheet {
239
- position: fixed;
240
- bottom: 0; left: 0; right: 0;
241
- z-index: var(--z-ak-modal);
242
- max-height: 85vh;
243
- overflow-y: auto;
244
- border-radius: var(--radius-ak-lg) var(--radius-ak-lg) 0 0;
245
- transform: translateY(100%);
246
- transition: transform 240ms cubic-bezier(0.4, 0, 0.2, 1);
247
- }
248
- .ak-mobile-sheet-open { transform: translateY(0); }
249
- .ak-mobile-sheet-handle {
250
- display: flex;
251
- justify-content: center;
252
- padding-top: var(--spacing-ak-1);
253
- touch-action: none;
254
- -webkit-user-select: none;
255
- user-select: none;
256
- cursor: grab;
257
- }
258
- .ak-mobile-sheet-handle:active { cursor: grabbing; }
259
- .ak-mobile-sheet-handle::before {
260
- content: "";
261
- display: block;
262
- width: var(--size-ak-sheet-handle-width);
263
- height: var(--size-ak-sheet-handle-height);
264
- background: var(--color-ak-sheet-handle);
265
- border-radius: var(--radius-ak-full);
266
- }
267
-
268
- /* Profile panel */
269
- .ak-profile-panel {
270
- position: fixed;
271
- width: 16rem;
272
- background: var(--color-ak-bg);
273
- border: 1px solid var(--color-ak-border);
274
- border-radius: var(--radius-ak-lg);
275
- box-shadow: var(--shadow-ak-lg);
276
- opacity: 0; visibility: hidden;
277
- transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1),
278
- visibility 150ms cubic-bezier(0.4, 0, 0.2, 1);
279
- z-index: var(--z-ak-modal);
280
- }
281
- .ak-profile-panel-open { opacity: 1; visibility: visible; }
8
+ All CSS is UNLAYERED. No @layer declarations.
9
+ Compatible with Tailwind v3 and v4.
10
+ ══════════════════════════════════════════════════════════ */
282
11
 
283
- /* Scrollbar thin styled scrollbar for any scrollable AstralKit container */
284
- .ak-scrollbar {
285
- scrollbar-width: thin;
286
- scrollbar-color: var(--color-ak-border-strong) transparent;
287
- }
288
- .ak-scrollbar::-webkit-scrollbar {
289
- width: 6px;
290
- height: 6px;
291
- }
292
- .ak-scrollbar::-webkit-scrollbar-track {
293
- background: transparent;
294
- }
295
- .ak-scrollbar::-webkit-scrollbar-thumb {
296
- background: var(--color-ak-border-strong);
297
- border-radius: var(--radius-ak-full);
298
- }
299
-
300
- /* Raised card / panel surface */
301
- .ak-surface-raised {
302
- background: var(--ak-surface-raised-bg, var(--color-ak-surface-raised));
303
- border: 1px solid var(--ak-surface-raised-border, var(--color-ak-border));
304
- box-shadow: var(--ak-surface-raised-shadow, var(--shadow-ak-md));
305
- }
306
- /* Glass-like elevated surface */
307
- .ak-surface-glass {
308
- background: var(--ak-surface-glass-bg, var(--color-ak-surface-glass));
309
- border: 1px solid var(--ak-surface-glass-border, var(--color-ak-border-subtle));
310
- backdrop-filter: blur(var(--ak-surface-glass-blur, 12px));
311
- }
312
- /* Optional highlight overlay for premium / elevated surfaces */
313
- .ak-sheen {
314
- position: relative;
315
- }
316
- .ak-sheen::before {
317
- content: "";
318
- position: absolute;
319
- inset: 0;
320
- border-radius: inherit;
321
- background: linear-gradient(
322
- 145deg,
323
- var(--ak-sheen-highlight, var(--color-ak-highlight-soft)),
324
- rgba(255, 255, 255, 0) 65%
325
- );
326
- opacity: var(--ak-sheen-opacity, 1);
327
- pointer-events: none;
328
- }
329
- .ak-sheen-strong {
330
- --ak-sheen-highlight: var(--color-ak-highlight-strong);
331
- }
332
- /* Standard skeleton block */
333
- .ak-skeleton {
334
- position: relative;
335
- overflow: hidden;
336
- background: linear-gradient(
337
- 180deg,
338
- var(--ak-skeleton-base, var(--color-ak-skeleton-base)),
339
- var(--ak-skeleton-base-end, var(--color-ak-surface-2))
340
- );
341
- border-radius: var(--ak-skeleton-radius, var(--radius-ak-md));
342
- color: transparent !important;
343
- user-select: none;
344
- }
345
- .ak-skeleton::after {
346
- content: "";
347
- position: absolute;
348
- inset: 0;
349
- transform: translateX(-100%);
350
- background: linear-gradient(
351
- 90deg,
352
- rgba(255, 255, 255, 0),
353
- var(--ak-skeleton-shine, var(--color-ak-skeleton-shine)),
354
- rgba(255, 255, 255, 0)
355
- );
356
- animation: ak-skeleton-shimmer var(--duration-ak-skeleton) ease-in-out infinite;
357
- }
358
- .ak-skeleton-pill {
359
- border-radius: var(--radius-ak-full);
360
- }
361
- .ak-skeleton-circle {
362
- border-radius: var(--radius-ak-full);
363
- }
364
-
365
- /* Shared card shell scaffold */
366
- .ak-card-shell {
367
- position: relative;
368
- overflow: hidden;
369
- border: 1px solid var(--ak-card-shell-border, var(--color-ak-border));
370
- border-radius: var(--ak-card-shell-radius, var(--radius-ak-lg));
371
- background: var(--ak-card-shell-bg, var(--color-ak-surface-raised));
372
- box-shadow: var(--ak-card-shell-shadow, var(--shadow-ak-md));
373
- transition:
374
- transform var(--duration-ak-base) var(--ease-ak-default),
375
- box-shadow var(--duration-ak-base) var(--ease-ak-default),
376
- border-color var(--duration-ak-base) var(--ease-ak-default);
377
- }
378
- .ak-card-shell-interactive:hover,
379
- .ak-card-shell-interactive:focus-within {
380
- transform: translateY(var(--ak-card-shell-lift, -2px));
381
- border-color: var(--ak-card-shell-border-hover, var(--color-ak-border-strong));
382
- box-shadow: var(--ak-card-shell-shadow-hover, var(--shadow-ak-lg));
383
- }
384
- .ak-card-shell-inner {
385
- position: relative;
386
- z-index: 1;
387
- display: flex;
388
- flex-direction: column;
389
- gap: var(--ak-card-shell-gap, var(--spacing-ak-3));
390
- }
391
- .ak-card-shell-header {
392
- display: grid;
393
- grid-template-columns: minmax(0, 1fr) auto;
394
- align-items: start;
395
- gap: var(--ak-card-shell-header-gap, var(--spacing-ak-2));
12
+ /* ── Base resets (unlayered always applies) ── */
13
+ a { text-decoration: none; }
14
+ html {
15
+ -webkit-font-smoothing: antialiased;
16
+ -moz-osx-font-smoothing: grayscale;
17
+ scroll-padding-top: var(--height-ak-nav, 4.5rem);
18
+ scroll-padding-bottom: var(--spacing-ak-mobile-bar, 4.5rem);
396
19
  }
397
20
 
398
21
  /* ══════════════════════════════════════════════════════════
399
- Layout Primitives
400
- Breakpoint-free, intrinsic responsive patterns.
401
- Based on Every Layout (Heydon Pickering & Andy Bell).
402
- Customize via CSS custom properties on the element.
22
+ TOKENS are now in astralkit-theme.css (v3) or astralkit-theme-v4.css (v4).
23
+ This file contains only component CSS, primitives, and base resets.
24
+ ══════════════════════════════════════════════════════════ */
25
+ /* ══════════════════════════════════════════════════════════
26
+ COMPONENT PRIMITIVES
27
+ Unlayered — source order determines cascade priority.
28
+ Component dark modifiers (e.g. .ak-sidebar-panel--dark) beat
29
+ [data-theme="dark"] because they come later in the file.
403
30
  ══════════════════════════════════════════════════════════ */
31
+ @import "./primitives/focus.css";
32
+ @import "./primitives/typography.css";
33
+ @import "./primitives/icons.css";
34
+ @import "./primitives/sidebar.css";
35
+ @import "./primitives/avatar.css";
36
+ @import "./primitives/navigation.css";
37
+ @import "./primitives/badges.css";
38
+ @import "./primitives/mobile.css";
39
+ @import "./primitives/animations.css";
40
+ @import "./primitives/layout.css";
41
+ @import "./primitives/accounts.css";
42
+ @import "./primitives/forms.css";
43
+ @import "./primitives/effects.css";
404
44
 
405
- /* Stack — vertical spacing between children.
406
- Usage: <div class="ak-stack"> or style="--ak-stack-gap: 2rem"
407
- Default gap: --spacing-ak-fl-sm (fluid 1rem → 1.5rem) */
408
- .ak-stack {
409
- display: flex;
410
- flex-direction: column;
411
- gap: var(--ak-stack-gap, var(--spacing-ak-fl-sm));
412
- }
413
-
414
- /* Cluster — horizontal wrapping group (tags, nav links, badges).
415
- Usage: <div class="ak-cluster">
416
- Default gap: --spacing-ak-fl-xs */
417
- .ak-cluster {
418
- display: flex;
419
- flex-wrap: wrap;
420
- gap: var(--ak-cluster-gap, var(--spacing-ak-fl-xs));
421
- align-items: var(--ak-cluster-align, center);
422
- }
423
-
424
- /* Center — horizontally centered content with max-width.
425
- Usage: <div class="ak-center">
426
- Default max-width: 75rem (1200px), with fluid side padding */
427
- .ak-center {
428
- box-sizing: content-box;
429
- max-inline-size: var(--ak-center-max, 75rem);
430
- margin-inline: auto;
431
- padding-inline: var(--ak-center-gutter, var(--spacing-ak-fl-sm));
432
- }
433
-
434
- /* Sidebar — two-panel: one fixed-width sidebar + one flexible main.
435
- Auto-stacks vertically when content would overflow.
436
- Usage: <div class="ak-sidebar"><aside>Sidebar</aside><main>Content</main></div>
437
- Default sidebar width: 18rem, switch point: 50% */
438
- .ak-sidebar {
439
- display: flex;
440
- flex-wrap: wrap;
441
- gap: var(--ak-sidebar-gap, var(--spacing-ak-fl-md));
442
- }
443
- .ak-sidebar > :first-child {
444
- flex-basis: var(--ak-sidebar-width, 18rem);
445
- flex-grow: 1;
446
- }
447
- .ak-sidebar > :last-child {
448
- flex-basis: 0;
449
- flex-grow: 999;
450
- min-inline-size: var(--ak-sidebar-threshold, 50%);
451
- }
452
-
453
- /* Switcher — horizontal layout that flips to vertical at a threshold.
454
- Usage: <div class="ak-switcher">
455
- Default threshold: 30rem (480px container width) */
456
- .ak-switcher {
457
- display: flex;
458
- flex-wrap: wrap;
459
- gap: var(--ak-switcher-gap, var(--spacing-ak-fl-sm));
460
- }
461
- .ak-switcher > * {
462
- flex-basis: calc((var(--ak-switcher-threshold, 30rem) - 100%) * 999);
463
- flex-grow: 1;
464
- }
465
-
466
- /* Cover — fills viewport height, vertically centers primary content.
467
- Usage: <div class="ak-cover"><header/><div class="ak-cover-center">Hero</div><footer/></div>
468
- The .ak-cover-center child gets vertically centered. */
469
- .ak-cover {
470
- display: flex;
471
- flex-direction: column;
472
- min-block-size: var(--ak-cover-min, 100dvh);
473
- padding: var(--ak-cover-padding, var(--spacing-ak-fl-md));
474
- }
475
- .ak-cover > * { margin-block: auto; }
476
- .ak-cover > :first-child:not(.ak-cover-center) { margin-block-start: 0; }
477
- .ak-cover > :last-child:not(.ak-cover-center) { margin-block-end: 0; }
45
+ @keyframes ak-skeleton-shimmer {
46
+ 100% { transform: translateX(100%); }
47
+ }
48
+
49
+ /* Note: The unlayered override block that was here (170 lines) has been
50
+ removed. With @layer gone, all primitive declarations are unlayered and
51
+ compete with Tailwind preflight via specificity (.class > *). */
478
52
 
479
53
  /* ══════════════════════════════════════════════════════════
480
- Auto-Responsive Grid
481
- The RAM pattern (Repeat, Auto-fit, Minmax).
482
- Columns reflow automatically zero breakpoints needed.
483
- Usage: <div class="ak-grid"> or style="--ak-grid-min: 320px"
484
- Default min column width: 280px, fluid gap.
54
+ Neobrutalist interaction helper
55
+ Apply `.ak-brutal-press` to any element that has a brutal shadow
56
+ to get the signature "push into shadow" press effect:
57
+ - default: 4px 4px shadow + translate(0,0)
58
+ - hover: 2px 2px shadow + translate(2px,2px)
59
+ - active: 0px 0px shadow + translate(4px,4px) — fully pressed
60
+ Works with any --shadow-ak-brutal-* size.
61
+ Respects prefers-reduced-motion via the rule below.
485
62
  ══════════════════════════════════════════════════════════ */
486
- .ak-grid {
487
- display: grid;
488
- gap: var(--ak-grid-gap, var(--spacing-ak-fl-sm));
489
- grid-template-columns: repeat(
490
- auto-fill,
491
- minmax(min(var(--ak-grid-min, 280px), 100%), 1fr)
492
- );
63
+ .ak-brutal-press {
64
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
65
+ }
66
+ .ak-brutal-press:hover {
67
+ transform: translate(2px, 2px);
68
+ box-shadow: var(--shadow-ak-brutal-sm);
69
+ }
70
+ .ak-brutal-press:active {
71
+ transform: translate(4px, 4px);
72
+ box-shadow: 0 0 0 0 var(--color-ak-brutal-ink);
493
73
  }
494
74
 
495
75
  /* ══════════════════════════════════════════════════════════
496
- Container Query Helper
497
- Mark any element as a query container, then use
498
- Tailwind v4's native @sm:, @md:, @lg: prefixes on children.
499
- Usage: <div class="ak-container"><div class="@md:flex-row">...</div></div>
76
+ Form Primitives — Checkbox, Radio, Switch, Range, OTP
77
+ Styles that require pseudo-elements, attribute selectors,
78
+ vendor prefixes, or keyframes things Tailwind can't do.
79
+ Components use Tailwind for everything else (layout, spacing,
80
+ colors, fonts). These are the minimal CSS escape hatches.
500
81
  ══════════════════════════════════════════════════════════ */
501
- .ak-container {
502
- container-type: inline-size;
82
+
83
+ /* ── Checkbox ── */
84
+ .ak-check {
85
+ appearance: none;
86
+ width: 22px; height: 22px;
87
+ border: 2px solid var(--color-ak-border-strong);
88
+ border-radius: 6px;
89
+ cursor: pointer; position: relative;
90
+ transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
91
+ flex-shrink: 0;
92
+ }
93
+ .ak-check:hover { border-color: var(--color-ak-primary); }
94
+ .ak-check:checked {
95
+ background: var(--color-ak-primary);
96
+ border-color: var(--color-ak-primary);
97
+ }
98
+ .ak-check:checked::after {
99
+ content: '';
100
+ position: absolute; left: 6px; top: 2px;
101
+ width: 6px; height: 11px;
102
+ border: solid var(--color-ak-on-primary);
103
+ border-width: 0 2.5px 2.5px 0;
104
+ transform: rotate(45deg);
105
+ }
106
+ .ak-check:focus-visible {
107
+ outline: 2px solid var(--color-ak-primary);
108
+ outline-offset: 2px;
109
+ }
110
+ .ak-check:disabled { cursor: not-allowed; opacity: 0.5; }
111
+
112
+ /* ── Radio ── */
113
+ .ak-radio {
114
+ appearance: none;
115
+ width: 22px; height: 22px;
116
+ border: 2px solid var(--color-ak-border-strong);
117
+ border-radius: 50%;
118
+ cursor: pointer; position: relative;
119
+ transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
120
+ flex-shrink: 0;
121
+ background: var(--color-ak-bg);
503
122
  }
504
- /* Named container variant for nesting */
505
- .ak-container-named {
506
- container-type: inline-size;
507
- container-name: var(--ak-container-name, content);
123
+ .ak-radio:hover { border-color: var(--color-ak-primary); }
124
+ .ak-radio:checked {
125
+ border-color: var(--color-ak-primary);
126
+ background: var(--color-ak-primary);
508
127
  }
128
+ .ak-radio:checked::after {
129
+ content: '';
130
+ position: absolute; top: 50%; left: 50%;
131
+ transform: translate(-50%, -50%);
132
+ width: 8px; height: 8px;
133
+ border-radius: 50%;
134
+ background: var(--color-ak-on-primary);
135
+ }
136
+ .ak-radio:focus-visible {
137
+ outline: 2px solid var(--color-ak-primary);
138
+ outline-offset: 2px;
139
+ }
140
+ .ak-radio:disabled { cursor: not-allowed; opacity: 0.5; }
509
141
 
510
- } /* end @layer components */
511
-
512
- @keyframes ak-skeleton-shimmer {
513
- 100% { transform: translateX(100%); }
142
+ /* ── Switch ── */
143
+ .ak-switch-track {
144
+ position: relative; width: 52px; height: 28px;
145
+ background: var(--color-ak-border-strong);
146
+ border-radius: 9999px;
147
+ transition: background-color 0.2s;
148
+ }
149
+ .ak-switch[aria-checked="true"] .ak-switch-track {
150
+ background: var(--color-ak-primary);
151
+ }
152
+ .ak-switch-knob {
153
+ position: absolute; top: 3px; left: 3px;
154
+ width: 22px; height: 22px;
155
+ background: var(--color-ak-on-primary);
156
+ border-radius: 50%;
157
+ transition: transform 0.2s;
158
+ }
159
+ .ak-switch[aria-checked="true"] .ak-switch-knob {
160
+ transform: translateX(24px);
514
161
  }
162
+ .ak-switch:focus-visible .ak-switch-track {
163
+ outline: 2px solid var(--color-ak-primary);
164
+ outline-offset: 2px;
165
+ }
166
+ /* Size: Small */
167
+ .ak-switch-sm .ak-switch-track { width: 44px; height: 24px; }
168
+ .ak-switch-sm .ak-switch-knob { width: 18px; height: 18px; }
169
+ .ak-switch-sm[aria-checked="true"] .ak-switch-knob { transform: translateX(20px); }
170
+ /* Size: Large */
171
+ .ak-switch-lg .ak-switch-track { width: 64px; height: 34px; }
172
+ .ak-switch-lg .ak-switch-knob { width: 28px; height: 28px; }
173
+ .ak-switch-lg[aria-checked="true"] .ak-switch-knob { transform: translateX(30px); }
174
+
175
+ /* Color tracks */
176
+ .ak-switch-success[aria-checked="true"] .ak-switch-track { background: var(--color-ak-success); }
177
+ .ak-switch-danger[aria-checked="true"] .ak-switch-track { background: var(--color-ak-danger); }
178
+
179
+ /* Icon switch — default (72×36)
180
+ Track icons are absolutely positioned at left/right edges.
181
+ Knob is absolute and slides over them. Knob icon shows the active state icon. */
182
+ .ak-switch-with-icons .ak-switch-track { width: 72px; height: 36px; }
183
+ .ak-switch-with-icons .ak-switch-knob {
184
+ width: 30px; height: 30px; z-index: 2;
185
+ display: flex; align-items: center; justify-content: center;
186
+ }
187
+ .ak-switch-with-icons[aria-checked="true"] .ak-switch-knob { transform: translateX(36px); }
188
+ /* Track icons — absolute, centered vertically at left/right */
189
+ .ak-switch-track-icon {
190
+ position: absolute; top: 50%; transform: translateY(-50%);
191
+ z-index: 1; line-height: 1; font-size: 14px;
192
+ display: flex; align-items: center; justify-content: center;
193
+ transition: opacity 0.2s;
194
+ }
195
+ .ak-switch-track-icon:first-child { left: 10px; }
196
+ .ak-switch-track-icon:last-child { right: 10px; }
197
+ /* Off state: left icon hidden (behind knob), right icon visible */
198
+ .ak-switch-with-icons .ak-switch-track-icon:first-child { opacity: 0; }
199
+ .ak-switch-with-icons .ak-switch-track-icon:last-child { color: var(--color-ak-on-primary); opacity: 0.7; }
200
+ /* On state: left icon visible, right icon hidden (behind knob) */
201
+ .ak-switch-with-icons[aria-checked="true"] .ak-switch-track-icon:first-child { color: var(--color-ak-on-primary); opacity: 0.7; }
202
+ .ak-switch-with-icons[aria-checked="true"] .ak-switch-track-icon:last-child { opacity: 0; }
203
+ /* Knob icon */
204
+ .ak-switch-knob-icon { font-size: 14px; color: var(--color-ak-text); line-height: 1; }
205
+
206
+ /* Icon switch — lg (88×44) */
207
+ .ak-switch-icons-lg .ak-switch-track { width: 88px; height: 44px; }
208
+ .ak-switch-icons-lg .ak-switch-knob { width: 38px; height: 38px; }
209
+ .ak-switch-icons-lg[aria-checked="true"] .ak-switch-knob { transform: translateX(44px); }
210
+ .ak-switch-icons-lg .ak-switch-track-icon:first-child { left: 12px; }
211
+ .ak-switch-icons-lg .ak-switch-track-icon:last-child { right: 12px; }
212
+ .ak-switch-icons-lg .ak-switch-track-icon,
213
+ .ak-switch-icons-lg .ak-switch-knob-icon { font-size: 18px; }
214
+ /* Icon switch — xl (104×52) */
215
+ .ak-switch-icons-xl .ak-switch-track { width: 104px; height: 52px; }
216
+ .ak-switch-icons-xl .ak-switch-knob { width: 46px; height: 46px; }
217
+ .ak-switch-icons-xl[aria-checked="true"] .ak-switch-knob { transform: translateX(52px); }
218
+ .ak-switch-icons-xl .ak-switch-track-icon:first-child { left: 14px; }
219
+ .ak-switch-icons-xl .ak-switch-track-icon:last-child { right: 14px; }
220
+ .ak-switch-icons-xl .ak-switch-track-icon,
221
+ .ak-switch-icons-xl .ak-switch-knob-icon { font-size: 22px; }
222
+ /* Icon switch — xxl (120×60) */
223
+ .ak-switch-icons-xxl .ak-switch-track { width: 120px; height: 60px; }
224
+ .ak-switch-icons-xxl .ak-switch-knob { width: 54px; height: 54px; }
225
+ .ak-switch-icons-xxl[aria-checked="true"] .ak-switch-knob { transform: translateX(60px); }
226
+ .ak-switch-icons-xxl .ak-switch-track-icon:first-child { left: 16px; }
227
+ .ak-switch-icons-xxl .ak-switch-track-icon:last-child { right: 16px; }
228
+ .ak-switch-icons-xxl .ak-switch-track-icon,
229
+ .ak-switch-icons-xxl .ak-switch-knob-icon { font-size: 26px; }
230
+
231
+ /* Reversed field (switch left, label right) */
232
+ .ak-switch-field-reversed { flex-direction: row-reverse; justify-content: flex-end; }
233
+ /* Status text beside switch */
234
+ .ak-switch-status { font-size: var(--text-ak-fl-base); font-weight: 600; color: var(--color-ak-text-muted); min-width: 24px; }
515
235
 
516
- /* ══════════════════════════════════════════════════════════
517
- Dark Mode Override
518
- Apply: <html data-theme="dark"> or <div data-theme="dark">
519
- Only overrides color tokens. Spacing, type, radius stay the same.
520
- ══════════════════════════════════════════════════════════ */
521
- [data-theme="dark"] {
522
- --color-ak-bg: #0a0a0a;
523
- --color-ak-surface: #171717;
524
- --color-ak-surface-2: #262626;
525
- --color-ak-hover: #1a1a1a;
526
- --color-ak-active: #262626;
527
- --color-ak-elevated: #171717;
528
- --color-ak-surface-raised: #171717;
529
- --color-ak-surface-raised-soft: rgba(23, 23, 23, 0.78);
530
- --color-ak-surface-glass: rgba(23, 23, 23, 0.72);
531
- --color-ak-surface-glass-strong: rgba(23, 23, 23, 0.84);
532
- --color-ak-highlight-soft: rgba(255, 255, 255, 0.06);
533
- --color-ak-highlight-strong: rgba(255, 255, 255, 0.1);
534
- --color-ak-skeleton-base: #262626;
535
- --color-ak-skeleton-shine: rgba(255, 255, 255, 0.08);
536
- --color-ak-overlay: rgba(0, 0, 0, 0.7);
537
- --color-ak-on-primary: #000000;
538
- --color-ak-primary-subtle: #262626;
539
-
540
- --color-ak-text: #f5f5f5;
541
- --color-ak-text-secondary: #a3a3a3;
542
- --color-ak-text-muted: #737373;
543
- --color-ak-text-disabled: #525252;
544
- --color-ak-text-inverse: #0a0a0a;
545
- --color-ak-text-link: #ffffff;
546
- --color-ak-text-placeholder: #525252;
547
-
548
- --color-ak-border: #262626;
549
- --color-ak-border-subtle: #1a1a1a;
550
- --color-ak-border-strong: #404040;
551
- --color-ak-border-focus: #ffffff;
552
-
553
- --shadow-ak-xs: 0 1px 2px rgba(0, 0, 0, 0.3);
554
- --shadow-ak-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
555
- --shadow-ak-md: 0 4px 12px rgba(0, 0, 0, 0.4);
556
- --shadow-ak-lg: 0 8px 30px rgba(0, 0, 0, 0.5);
557
- --shadow-ak-xl: 0 16px 50px rgba(0, 0, 0, 0.6);
558
- --shadow-ak-2xl: 0 24px 60px rgba(0, 0, 0, 0.7);
559
- }
560
-
561
- /* Reduced motion — must be unlayered to override everything */
236
+ @media (prefers-reduced-motion: reduce) {
237
+ .ak-switch-track, .ak-switch-knob, .ak-switch-track-icon { transition: none; }
238
+ }
239
+
240
+ /* ── Range Slider ── */
241
+ .ak-range input[type="range"] {
242
+ --range-track: var(--color-ak-border);
243
+ --range-fill: var(--color-ak-text);
244
+ -webkit-appearance: none; appearance: none;
245
+ width: 100%; height: 3rem;
246
+ background: transparent; cursor: pointer;
247
+ margin: 0; padding: 0;
248
+ }
249
+ .ak-range input[type="range"]::-webkit-slider-runnable-track {
250
+ height: 6px; border-radius: 999px;
251
+ background: linear-gradient(to right, var(--range-fill) var(--ak-fill, 0%), var(--range-track) var(--ak-fill, 0%));
252
+ }
253
+ .ak-range input[type="range"]::-webkit-slider-thumb {
254
+ -webkit-appearance: none; appearance: none;
255
+ width: 1.5rem; height: 1.5rem; margin-top: -0.5625rem;
256
+ border: 4px solid var(--color-ak-text); border-radius: 999px;
257
+ background: var(--color-ak-bg);
258
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
259
+ box-shadow: 0 1px 3px rgba(0,0,0,0.12);
260
+ }
261
+ .ak-range input[type="range"]::-moz-range-track {
262
+ height: 6px; border-radius: 999px;
263
+ background: var(--range-track);
264
+ }
265
+ .ak-range input[type="range"]::-moz-range-progress {
266
+ height: 6px; border-radius: 999px;
267
+ background: var(--range-fill);
268
+ }
269
+ .ak-range input[type="range"]::-moz-range-thumb {
270
+ width: 1rem; height: 1rem;
271
+ border: 4px solid var(--color-ak-text); border-radius: 999px;
272
+ background: var(--color-ak-bg);
273
+ transition: transform 0.15s ease;
274
+ box-shadow: 0 1px 3px rgba(0,0,0,0.12);
275
+ }
276
+ .ak-range input[type="range"]:hover::-webkit-slider-thumb { transform: scale(1.15); }
277
+ .ak-range input[type="range"]:hover::-moz-range-thumb { transform: scale(1.15); }
278
+ .ak-range input[type="range"]:focus-visible { outline: none; }
279
+ .ak-range input[type="range"]:focus-visible::-webkit-slider-thumb {
280
+ box-shadow: 0 0 0 4px var(--color-ak-bg), 0 0 0 7px var(--color-ak-primary);
281
+ transform: scale(1.15);
282
+ }
283
+ .ak-range input[type="range"]:focus-visible::-moz-range-thumb {
284
+ box-shadow: 0 0 0 4px var(--color-ak-bg), 0 0 0 7px var(--color-ak-primary);
285
+ transform: scale(1.15);
286
+ }
287
+
288
+ /* ── Range Dual Track ── */
289
+ .ak-dual-track { pointer-events: none; position: absolute; left: 0; right: 0; height: 6px; border-radius: 999px; background: var(--color-ak-border); z-index: 1; }
290
+ .ak-dual-fill { position: absolute; height: 100%; border-radius: 999px; background: var(--color-ak-text); z-index: 0; }
291
+ .ak-dual-input { pointer-events: none; position: absolute; left: 0; width: 100%; height: 3rem; background: transparent; z-index: 3; }
292
+ .ak-dual-input::-webkit-slider-runnable-track { height: 6px; background: transparent !important; }
293
+ .ak-dual-input::-webkit-slider-thumb { pointer-events: auto; position: relative; z-index: 10; }
294
+ .ak-dual-input::-moz-range-track, .ak-dual-input::-moz-range-progress { background: transparent !important; }
295
+ .ak-dual-input::-moz-range-thumb { pointer-events: auto; position: relative; z-index: 10; }
296
+
297
+ /* ── Number Input Spinbutton Hide ── */
298
+ .ak-stepper input,
299
+ .ak-qty input,
300
+ .ak-range input[type="number"] {
301
+ -moz-appearance: textfield; appearance: textfield;
302
+ }
303
+ .ak-stepper input::-webkit-outer-spin-button,
304
+ .ak-stepper input::-webkit-inner-spin-button,
305
+ .ak-qty input::-webkit-outer-spin-button,
306
+ .ak-qty input::-webkit-inner-spin-button,
307
+ .ak-range input[type="number"]::-webkit-outer-spin-button,
308
+ .ak-range input[type="number"]::-webkit-inner-spin-button {
309
+ -webkit-appearance: none; margin: 0;
310
+ }
311
+
312
+ /* ── OTP Input ── */
313
+ .ak-otp-input {
314
+ width: 56px; height: 64px; text-align: center;
315
+ font-size: var(--text-ak-2xl); font-weight: 700;
316
+ border: 2px solid var(--color-ak-border); border-radius: 0.75rem;
317
+ outline: none; background: var(--color-ak-bg); color: var(--color-ak-text);
318
+ transition: border-color 0.15s ease, background-color 0.15s ease;
319
+ caret-color: var(--color-ak-primary);
320
+ }
321
+ .ak-otp-input::placeholder { color: var(--color-ak-text-muted); }
322
+ .ak-otp-input:hover { border-color: var(--color-ak-border-strong); }
323
+ .ak-otp-input:focus-visible {
324
+ outline: 2px solid var(--color-ak-primary);
325
+ outline-offset: 2px;
326
+ border-color: var(--color-ak-primary);
327
+ background: var(--color-ak-surface);
328
+ }
329
+ .ak-otp-input.has-value { border-color: var(--color-ak-text); font-weight: 800; }
330
+ @media (max-width: 400px) {
331
+ .ak-otp-input { width: 44px; height: 52px; font-size: var(--text-ak-xl); }
332
+ }
333
+
334
+ /* ── Color Picker Swatch ── */
335
+ .ak-color-swatch:hover { border-color: var(--color-ak-border-strong); }
336
+ .ak-color-swatch:active { transform: scale(0.95); transition-duration: 0.1s; }
337
+ .ak-color-swatch.selected { border-color: var(--color-ak-text); }
338
+
339
+ /* ── File Upload ── */
340
+ @keyframes ak-spin { to { transform: rotate(360deg); } }
341
+ .ak-spinner { animation: ak-spin 0.8s linear infinite; }
342
+ .ak-dropzone { transition: border-color 0.2s ease, background-color 0.2s ease; }
343
+ .ak-dropzone:hover { border-color: var(--color-ak-border-strong); background: var(--color-ak-hover); }
344
+ .ak-dropzone.drag-over { border-color: var(--color-ak-primary); background: var(--color-ak-primary-subtle); }
345
+ .ak-file-row { transition: background-color 0.15s ease, border-color 0.15s ease; }
346
+ .ak-file-row:hover { background: var(--color-ak-hover); border-color: var(--color-ak-border-strong); }
347
+ .ak-progress-fill { transition: width 0.3s ease; }
348
+
349
+ /* ── Star Rating ── */
350
+ .ak-star-btn {
351
+ display: inline-flex; align-items: center; justify-content: center;
352
+ width: 48px; height: 48px; cursor: pointer;
353
+ border: none; background: none; padding: 0;
354
+ border-radius: 8px;
355
+ color: var(--color-ak-text-disabled);
356
+ transition: color 0.15s, transform 0.15s;
357
+ }
358
+ .ak-star-btn.filled { color: var(--color-ak-text); }
359
+ .ak-star-btn:hover { transform: scale(1.1); }
360
+ .ak-star-btn:focus-visible { outline: 2px solid var(--color-ak-primary); outline-offset: 2px; }
361
+ .ak-star-btn.ak-star-sm { width: 40px; height: 40px; }
362
+ .ak-star-btn.ak-star-sm .ak-star-icon { font-size: 20px; }
363
+ .ak-star-icon { font-size: 28px; }
364
+ .ak-star-btn.ak-star-lg { width: 56px; height: 56px; }
365
+ .ak-star-btn.ak-star-lg .ak-star-icon { font-size: 36px; }
366
+
367
+ /* ── Switch Layout ── */
368
+ .ak-switch {
369
+ display: inline-flex; align-items: center; justify-content: center;
370
+ background: none; border: none; padding: 8px 0; cursor: pointer;
371
+ border-radius: 9999px; flex-shrink: 0; min-height: 44px;
372
+ }
373
+ .ak-switch:focus { outline: none; }
374
+ .ak-switch:disabled, .ak-switch[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
375
+ .ak-switch-field {
376
+ display: flex; align-items: center; justify-content: space-between;
377
+ gap: 16px; min-height: 52px;
378
+ }
379
+ .ak-switch-label-wrap { display: flex; flex-direction: column; gap: 4px; cursor: pointer; flex: 1; min-width: 0; }
380
+ .ak-switch-field:has(.ak-switch:disabled) .ak-switch-label-wrap,
381
+ .ak-switch-field:has(.ak-switch[aria-disabled="true"]) .ak-switch-label-wrap { cursor: default; }
382
+ /* When icon is present, use grid so icon spans full height and text+helper align */
383
+ .ak-switch-label-wrap:has(.ak-switch-label-icon) {
384
+ display: grid;
385
+ grid-template-columns: 2.75rem 1fr;
386
+ grid-template-rows: auto auto;
387
+ column-gap: 14px;
388
+ row-gap: 2px;
389
+ align-items: center;
390
+ }
391
+ .ak-switch-label-wrap:has(.ak-switch-label-icon) .ak-switch-label-icon {
392
+ grid-column: 1;
393
+ grid-row: 1 / -1;
394
+ align-self: center;
395
+ }
396
+ .ak-switch-label-wrap:has(.ak-switch-label-icon) .ak-switch-label {
397
+ grid-column: 2;
398
+ grid-row: 1;
399
+ }
400
+ .ak-switch-label-wrap:has(.ak-switch-label-icon) .ak-switch-helper {
401
+ grid-column: 2;
402
+ grid-row: 2;
403
+ }
404
+ .ak-switch-label {
405
+ font-size: var(--text-ak-fl-lg); font-weight: 700; color: var(--color-ak-text);
406
+ }
407
+ .ak-switch-helper { font-size: var(--text-ak-fl-base); color: var(--color-ak-text-secondary); }
408
+ .ak-switch-label-icon {
409
+ font-size: 1.5rem; color: var(--color-ak-text-secondary); line-height: 1; flex-shrink: 0;
410
+ width: 2.75rem; height: 2.75rem;
411
+ display: flex; align-items: center; justify-content: center;
412
+ background: var(--color-ak-surface); border-radius: 0.75rem;
413
+ }
414
+ .ak-switch-card {
415
+ border: 2px solid var(--color-ak-border); border-radius: 0.75rem;
416
+ padding: 20px 24px; transition: border-color 0.2s;
417
+ }
418
+ .ak-switch-card-active {
419
+ border-color: var(--color-ak-primary); background: var(--color-ak-primary-subtle);
420
+ }
421
+ .ak-switch-compact .ak-switch-field { padding: 16px 0; }
422
+ .ak-switch-compact .ak-switch-field + .ak-switch-field { border-top: 1px solid var(--color-ak-border); }
423
+ .ak-switch-compact .ak-switch-label { font-size: var(--text-ak-fl-base); }
424
+ .ak-switch-compact .ak-switch-helper { font-size: var(--text-ak-fl-sm); }
425
+ .ak-switch-value { font-size: var(--text-ak-fl-base); font-weight: 600; color: var(--color-ak-text); min-width: 32px; text-align: right; }
426
+ .ak-switch-value-muted { color: var(--color-ak-text-secondary); font-weight: 400; }
427
+ .ak-switch-group { border: none; padding: 0; margin: 0; }
428
+ .ak-switch-group-legend { font-size: var(--text-ak-fl-base); font-weight: 700; color: var(--color-ak-text-secondary); padding: 0; margin-bottom: 16px; text-transform: uppercase; letter-spacing: 0.05em; }
429
+ .ak-switch-section { border: 2px solid var(--color-ak-border); border-radius: 0.75rem; padding: 24px; }
430
+ .ak-switch-section .ak-switch-group-legend { font-size: var(--text-ak-fl-lg); margin-bottom: 16px; padding: 0 8px; text-transform: none; letter-spacing: normal; }
431
+ .ak-switch-section .ak-switch-field + .ak-switch-field {
432
+ border-top: 1px solid var(--color-ak-border-subtle); padding-top: 16px; margin-top: 16px;
433
+ }
434
+ .ak-form-section { max-width: 640px; }
435
+
436
+ /* ── Number Stepper Button Press ── */
437
+ .ak-stepper-btn:active:not([aria-disabled="true"]) {
438
+ transform: translate(2px, 2px);
439
+ box-shadow: 2px 2px 0 0 var(--color-ak-brutal-ink) !important;
440
+ }
441
+ .ak-stepper-btn[aria-disabled="true"] { pointer-events: none; opacity: 0.3; }
442
+
443
+ /* ── Quantity Selector ── */
444
+ .ak-qty-btn { transition: all 0.15s ease; }
445
+ .ak-qty-btn:active:not([aria-disabled="true"]) { transform: scale(0.96); }
446
+ .ak-qty-btn[aria-disabled="true"] { opacity: 0.3; cursor: not-allowed; }
447
+
448
+ /* ── Shared Keyframes ── */
449
+ @keyframes ak-fadeInUp {
450
+ from { opacity: 0; transform: translateY(8px); }
451
+ to { opacity: 1; transform: translateY(0); }
452
+ }
453
+ @keyframes ak-slideIn {
454
+ from { opacity: 0; transform: translateY(-8px) scale(0.98); }
455
+ to { opacity: 1; transform: translateY(0) scale(1); }
456
+ }
457
+ @keyframes ak-fadeOut {
458
+ from { opacity: 1; transform: translateY(0) scale(1); }
459
+ to { opacity: 0; transform: translateY(-8px) scale(0.98); }
460
+ }
461
+ @keyframes ak-swipeOut {
462
+ from { transform: translateX(var(--radix-toast-swipe-end-x)); }
463
+ to { transform: translateX(100%); }
464
+ }
465
+
466
+ /* ── Glass Panel (split-screen logins) ── */
467
+ .ak-glass-panel {
468
+ background: rgba(255, 255, 255, 0.03);
469
+ backdrop-filter: blur(12px);
470
+ -webkit-backdrop-filter: blur(12px);
471
+ border: 1px solid rgba(255, 255, 255, 0.1);
472
+ }
473
+
474
+ /* ── Grid Pattern Background ── */
475
+ .ak-bg-grid-pattern {
476
+ background-image: linear-gradient(to right, rgba(255,255,255,0.06) 1px, transparent 1px),
477
+ linear-gradient(to bottom, rgba(255,255,255,0.06) 1px, transparent 1px);
478
+ background-size: 40px 40px;
479
+ }
480
+
481
+ /* ── Toggle Group ── */
482
+ .ak-toggle-group {
483
+ display: inline-flex; background: var(--color-ak-surface-2);
484
+ border-radius: 8px; padding: 4px; gap: 4px;
485
+ }
486
+ .ak-toggle-group-item {
487
+ display: inline-flex; align-items: center; justify-content: center; gap: 6px;
488
+ background: none; border: none; padding: 0 16px; min-height: 44px;
489
+ font-family: inherit; font-size: var(--text-ak-base, 1rem); font-weight: 600;
490
+ color: var(--color-ak-text-secondary); border-radius: 8px; cursor: pointer;
491
+ transition: background-color 0.2s, color 0.2s; white-space: nowrap; line-height: 1;
492
+ }
493
+ .ak-toggle-group-item[aria-checked="true"],
494
+ .ak-toggle-group-item[aria-pressed="true"] {
495
+ background: var(--color-ak-bg); color: var(--color-ak-text);
496
+ }
497
+ .ak-toggle-group-item[aria-checked="false"]:not(:disabled):hover,
498
+ .ak-toggle-group-item[aria-pressed="false"]:not(:disabled):hover {
499
+ color: var(--color-ak-text); background: var(--color-ak-hover);
500
+ }
501
+ .ak-toggle-group-item:focus { outline: none; }
502
+ .ak-toggle-group-item:focus-visible { outline: 2px solid var(--color-ak-primary); outline-offset: 2px; }
503
+ .ak-toggle-group-item:disabled { opacity: 0.4; cursor: not-allowed; }
504
+ .ak-toggle-group[aria-disabled="true"] { opacity: 0.5; }
505
+ .ak-toggle-group[aria-disabled="true"] .ak-toggle-group-item { cursor: not-allowed; }
506
+ .ak-toggle-group-item i { font-size: 20px; line-height: 1; }
507
+ .ak-toggle-group-item-icon { padding: 0 14px; }
508
+ /* Toggle group — small */
509
+ .ak-toggle-group-sm { padding: 3px; gap: 3px; }
510
+ .ak-toggle-group-sm .ak-toggle-group-item { min-height: 44px; padding: 0 12px; font-size: var(--text-ak-sm, 0.875rem); }
511
+ .ak-toggle-group-sm .ak-toggle-group-item i { font-size: 18px; }
512
+ .ak-toggle-group-sm .ak-toggle-group-item-icon { padding: 0 12px; }
513
+ /* Toggle group — large */
514
+ .ak-toggle-group-lg { padding: 5px; gap: 5px; }
515
+ .ak-toggle-group-lg .ak-toggle-group-item { min-height: 52px; padding: 0 24px; font-size: var(--text-ak-lg, 1.125rem); }
516
+ .ak-toggle-group-lg .ak-toggle-group-item i { font-size: 24px; }
517
+ .ak-toggle-group-lg .ak-toggle-group-item-icon { padding: 0 18px; }
518
+
519
+ /* ── Resizable Panel Cursors ── */
520
+ body.ak-col-resizing, body.ak-col-resizing * {
521
+ cursor: col-resize !important; user-select: none !important; -webkit-user-select: none !important;
522
+ }
523
+ body.ak-ew-resizing, body.ak-ew-resizing * {
524
+ cursor: ew-resize !important; user-select: none !important; -webkit-user-select: none !important;
525
+ }
526
+
527
+ /* ── Focus Ring Utility ── */
528
+ .ak-focus-ring:focus-visible { outline: 2px solid var(--color-ak-primary); outline-offset: 2px; }
529
+
530
+ /* ── Price Fade Transition ── */
531
+ .ak-price-fade { transition: opacity 0.15s ease-in-out; }
532
+
533
+ /* Reduced motion — unlayered so it overrides everything */
562
534
  @media (prefers-reduced-motion: reduce) {
563
535
  *, *::before, *::after {
564
536
  animation-duration: 0.01ms !important;
565
537
  transition-duration: 0.01ms !important;
566
538
  }
539
+ .ak-star-btn:hover { transform: none !important; }
540
+ .ak-stepper-btn:active { transform: none !important; }
541
+ @keyframes ak-slideIn { from { opacity: 0; } to { opacity: 1; } }
542
+ @keyframes ak-fadeOut { from { opacity: 1; } to { opacity: 0; } }
567
543
  }