kern-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1078 -0
  3. package/dist/kern.css +705 -0
  4. package/dist/kern.js +529 -0
  5. package/dist/kern.min.css +1 -0
  6. package/dist/kern.min.js +17 -0
  7. package/package.json +43 -0
  8. package/src/base/index.css +3 -0
  9. package/src/base/reset.css +9 -0
  10. package/src/base/typography.css +26 -0
  11. package/src/components/accordion.css +21 -0
  12. package/src/components/alert.css +13 -0
  13. package/src/components/avatar.css +9 -0
  14. package/src/components/badge.css +18 -0
  15. package/src/components/breadcrumb.css +8 -0
  16. package/src/components/button.css +43 -0
  17. package/src/components/card.css +13 -0
  18. package/src/components/dialog.css +19 -0
  19. package/src/components/drawer.css +12 -0
  20. package/src/components/dropdown.css +22 -0
  21. package/src/components/form.css +53 -0
  22. package/src/components/index.css +22 -0
  23. package/src/components/pagination.css +6 -0
  24. package/src/components/progress.css +15 -0
  25. package/src/components/sidebar.css +16 -0
  26. package/src/components/skeleton.css +8 -0
  27. package/src/components/stepper.css +12 -0
  28. package/src/components/switch.css +11 -0
  29. package/src/components/table.css +17 -0
  30. package/src/components/tabs.css +20 -0
  31. package/src/components/toast.css +31 -0
  32. package/src/components/tooltip.css +31 -0
  33. package/src/kern.css +14 -0
  34. package/src/kern.js +427 -0
  35. package/src/layout/divider.css +5 -0
  36. package/src/layout/grid.css +12 -0
  37. package/src/layout/index.css +4 -0
  38. package/src/layout/stack.css +13 -0
  39. package/src/tokens/accent.css +20 -0
  40. package/src/tokens/colors.css +37 -0
  41. package/src/tokens/components.css +17 -0
  42. package/src/tokens/index.css +10 -0
  43. package/src/tokens/motion.css +12 -0
  44. package/src/tokens/radius.css +20 -0
  45. package/src/tokens/shadow.css +25 -0
  46. package/src/tokens/spacing.css +13 -0
  47. package/src/tokens/typography.css +10 -0
  48. package/src/tokens/z-index.css +9 -0
  49. package/src/utils/helpers.css +13 -0
  50. package/src/utils/index.css +4 -0
  51. package/src/utils/keyframes.css +11 -0
  52. package/src/utils/responsive.css +8 -0
  53. package/src-js/api.js +103 -0
  54. package/src-js/behaviors/accordion.js +51 -0
  55. package/src-js/behaviors/table-sort.js +61 -0
  56. package/src-js/behaviors/toggle.js +27 -0
  57. package/src-js/boot.js +37 -0
  58. package/src-js/components/dialog.js +72 -0
  59. package/src-js/components/drawer.js +60 -0
  60. package/src-js/components/dropdown.js +88 -0
  61. package/src-js/components/tabs.js +92 -0
  62. package/src-js/components/toaster.js +89 -0
  63. package/src-js/kern.js +34 -0
  64. package/src-js/utils.js +33 -0
package/dist/kern.js ADDED
@@ -0,0 +1,529 @@
1
+ (function(window){"use strict";
2
+
3
+ /* === utils.js === */
4
+ function emit(el, name, detail = {}) {
5
+ return el.dispatchEvent(
6
+ new CustomEvent(name, { bubbles: true, cancelable: true, detail })
7
+ );
8
+ }
9
+
10
+ function esc(str) {
11
+ return String(str)
12
+ .replace(/&/g, '&')
13
+ .replace(/</g, '&lt;')
14
+ .replace(/>/g, '&gt;')
15
+ .replace(/"/g, '&quot;');
16
+ }
17
+
18
+ function firstFocusable(el) {
19
+ return el?.querySelector(
20
+ 'button:not([disabled]),a[href],[tabindex]:not([tabindex="-1"]),input:not([disabled]),select:not([disabled]),textarea:not([disabled])'
21
+ ) ?? null;
22
+ }
23
+
24
+ const $ = (sel, ctx = document) => ctx.querySelector(sel);
25
+
26
+ const $$ = (sel, ctx = document) => [...ctx.querySelectorAll(sel)];
27
+
28
+ /* === behaviors/accordion.js === */
29
+ function initAccordions(root = document) {
30
+ root.querySelectorAll('[data-accordion-trigger]').forEach(trigger => {
31
+ if (trigger._kernInit) return;
32
+ trigger._kernInit = true;
33
+
34
+ trigger.setAttribute('aria-expanded', 'false');
35
+ trigger.setAttribute('type', 'button');
36
+
37
+ const content = trigger
38
+ .closest('[data-accordion-item]')
39
+ ?.querySelector('[data-accordion-content]');
40
+
41
+ if (!content) return;
42
+
43
+ trigger.addEventListener('click', () => {
44
+ const isOpen = trigger.getAttribute('aria-expanded') === 'true';
45
+ const accordion = trigger.closest('[data-accordion]');
46
+
47
+ // Close others unless data-multi is present
48
+ if (accordion && !accordion.hasAttribute('data-multi')) {
49
+ accordion.querySelectorAll('[data-accordion-trigger]').forEach(other => {
50
+ if (other === trigger) return;
51
+ other.setAttribute('aria-expanded', 'false');
52
+ other
53
+ .closest('[data-accordion-item]')
54
+ ?.querySelector('[data-accordion-content]')
55
+ ?.removeAttribute('data-open');
56
+ });
57
+ }
58
+
59
+ trigger.setAttribute('aria-expanded', isOpen ? 'false' : 'true');
60
+ isOpen ? content.removeAttribute('data-open') : content.setAttribute('data-open', '');
61
+ });
62
+ });
63
+ }
64
+
65
+ /* === behaviors/toggle.js === */
66
+ function initToggles(root = document) {
67
+ root.querySelectorAll('[data-toggle]').forEach(el => {
68
+ if (el._kernInit) return;
69
+ el._kernInit = true;
70
+
71
+ el.addEventListener('click', () => {
72
+ const targetId = el.getAttribute('data-toggle');
73
+ const target = document.getElementById(targetId);
74
+ if (!target) return;
75
+
76
+ // Walk up to find the WC wrapper (kern-dialog, kern-drawer, etc.)
77
+ const wc = target.closest('kern-dialog, kern-drawer') || target;
78
+
79
+ if (typeof wc.toggle === 'function') wc.toggle();
80
+ else if (typeof wc.open === 'function') wc.open();
81
+ });
82
+ });
83
+ }
84
+
85
+ /* === behaviors/table-sort.js === */
86
+ function initTableSort(root = document) {
87
+ root.querySelectorAll('th[data-sort]').forEach(th => {
88
+ if (th._kernInit) return;
89
+ th._kernInit = true;
90
+
91
+ th.style.cursor = 'pointer';
92
+ th.setAttribute('role', 'columnheader');
93
+ th.setAttribute('aria-sort', 'none');
94
+
95
+ th.addEventListener('click', () => {
96
+ const table = th.closest('table');
97
+ const tbody = table?.querySelector('tbody');
98
+ if (!tbody) return;
99
+
100
+ const colIndex = [...th.parentElement.children].indexOf(th);
101
+ const current = th.getAttribute('data-sort');
102
+ const asc = current !== 'asc';
103
+
104
+ // Reset all other sortable headers
105
+ table.querySelectorAll('th[data-sort]').forEach(h => {
106
+ h.setAttribute('data-sort', '');
107
+ h.setAttribute('aria-sort', 'none');
108
+ });
109
+
110
+ th.setAttribute('data-sort', asc ? 'asc' : 'desc');
111
+ th.setAttribute('aria-sort', asc ? 'ascending' : 'descending');
112
+
113
+ const rows = [...tbody.querySelectorAll('tr')];
114
+
115
+ rows.sort((a, b) => {
116
+ const av = a.cells[colIndex]?.textContent.trim() ?? '';
117
+ const bv = b.cells[colIndex]?.textContent.trim() ?? '';
118
+
119
+ // Try numeric sort first
120
+ const an = parseFloat(av.replace(/[^0-9.-]/g, ''));
121
+ const bn = parseFloat(bv.replace(/[^0-9.-]/g, ''));
122
+
123
+ if (!isNaN(an) && !isNaN(bn)) return asc ? an - bn : bn - an;
124
+ return asc ? av.localeCompare(bv) : bv.localeCompare(av);
125
+ });
126
+
127
+ rows.forEach(row => tbody.appendChild(row));
128
+ });
129
+ });
130
+ }
131
+
132
+ /* === components/tabs.js === */
133
+ class KernTabs extends HTMLElement {
134
+ connectedCallback() {
135
+ this._init();
136
+ }
137
+
138
+ _init() {
139
+ const tabs = [...this.querySelectorAll('[data-tab]')];
140
+ const panels = [...this.querySelectorAll('[data-tab-panel]')];
141
+
142
+ // Find the initial active index (first by default)
143
+ const initialActive = Math.max(0, tabs.findIndex(t => t.hasAttribute('data-active')));
144
+
145
+ tabs.forEach((tab, i) => {
146
+ // ARIA
147
+ tab.setAttribute('role', 'tab');
148
+ tab.setAttribute('tabindex', i === initialActive ? '0' : '-1');
149
+ tab.setAttribute('aria-selected', i === initialActive ? 'true' : 'false');
150
+
151
+ // Wire panel id
152
+ if (panels[i]) {
153
+ const panelId = panels[i].id || `k-panel-${Math.random().toString(36).slice(2)}`;
154
+ panels[i].id = panelId;
155
+ tab.setAttribute('aria-controls', panelId);
156
+ panels[i].setAttribute('role', 'tabpanel');
157
+ panels[i].setAttribute('aria-labelledby', tab.id || `k-tab-${i}`);
158
+ }
159
+
160
+ tab.addEventListener('click', () => this.goto(i));
161
+
162
+ tab.addEventListener('keydown', (e) => {
163
+ const count = tabs.length;
164
+ if (e.key === 'ArrowRight') { e.preventDefault(); this.goto((i + 1) % count); }
165
+ if (e.key === 'ArrowLeft') { e.preventDefault(); this.goto((i - 1 + count) % count); }
166
+ if (e.key === 'Home') { e.preventDefault(); this.goto(0); }
167
+ if (e.key === 'End') { e.preventDefault(); this.goto(count - 1); }
168
+ });
169
+ });
170
+
171
+ // Activate initial panel (no focus)
172
+ this._activate(initialActive, false);
173
+ }
174
+
175
+ goto(index) {
176
+ this._activate(index, true);
177
+ }
178
+
179
+ setActive(index) {
180
+ this._activate(index, false);
181
+ }
182
+
183
+ _activate(index, focus = false) {
184
+ const tabs = [...this.querySelectorAll('[data-tab]')];
185
+ const panels = [...this.querySelectorAll('[data-tab-panel]')];
186
+
187
+ tabs.forEach((tab, i) => {
188
+ const active = i === index;
189
+ tab.setAttribute('aria-selected', active ? 'true' : 'false');
190
+ tab.setAttribute('tabindex', active ? '0' : '-1');
191
+ });
192
+
193
+ panels.forEach((panel, i) => {
194
+ i === index ? panel.setAttribute('data-active', '') : panel.removeAttribute('data-active');
195
+ });
196
+
197
+ if (focus && tabs[index]) tabs[index].focus();
198
+
199
+ emit(this, 'kern:tab-change', { index });
200
+ }
201
+ }
202
+
203
+ customElements.define('kern-tabs', KernTabs);
204
+
205
+ /* === components/dropdown.js === */
206
+ class KernDropdown extends HTMLElement {
207
+ connectedCallback() {
208
+ this._trigger = this.querySelector('[data-dropdown-trigger]') || this.firstElementChild;
209
+ this._content = this.querySelector('[data-dropdown-content]');
210
+ this._onOutside = (e) => { if (!this.contains(e.target)) this.close(); };
211
+
212
+ if (!this._trigger) return;
213
+
214
+ this._trigger.setAttribute('aria-haspopup', 'true');
215
+ this._trigger.setAttribute('aria-expanded', 'false');
216
+
217
+ this._trigger.addEventListener('click', (e) => {
218
+ e.stopPropagation();
219
+ this.hasAttribute('open') ? this.close() : this.open();
220
+ });
221
+
222
+ this._trigger.addEventListener('keydown', (e) => {
223
+ if (e.key === 'ArrowDown') { e.preventDefault(); this.open(); this._focusFirst(); }
224
+ if (e.key === 'Escape') this.close();
225
+ });
226
+
227
+ if (this._content) {
228
+ const items = () => [...this._content.querySelectorAll('[data-dropdown-item]:not([disabled])')];
229
+
230
+ this._content.addEventListener('keydown', (e) => {
231
+ const list = items();
232
+ const idx = list.indexOf(document.activeElement);
233
+ if (e.key === 'ArrowDown') { e.preventDefault(); list[idx + 1]?.focus() ?? list[0]?.focus(); }
234
+ if (e.key === 'ArrowUp') { e.preventDefault(); idx > 0 ? list[idx - 1]?.focus() : this._trigger.focus(); }
235
+ if (e.key === 'Escape') { this.close(); this._trigger.focus(); }
236
+ if (e.key === 'Tab') this.close();
237
+ });
238
+
239
+ items().forEach(item => {
240
+ item.setAttribute('role', 'menuitem');
241
+ item.setAttribute('tabindex', '-1');
242
+ });
243
+ }
244
+ }
245
+
246
+ disconnectedCallback() {
247
+ document.removeEventListener('click', this._onOutside);
248
+ }
249
+
250
+ open() {
251
+ this.setAttribute('open', '');
252
+ this._trigger?.setAttribute('aria-expanded', 'true');
253
+ document.addEventListener('click', this._onOutside);
254
+ emit(this, 'kern:dropdown-open');
255
+ }
256
+
257
+ close() {
258
+ this.removeAttribute('open');
259
+ this._trigger?.setAttribute('aria-expanded', 'false');
260
+ document.removeEventListener('click', this._onOutside);
261
+ emit(this, 'kern:dropdown-close');
262
+ }
263
+
264
+ toggle() {
265
+ this.hasAttribute('open') ? this.close() : this.open();
266
+ }
267
+
268
+ _focusFirst() {
269
+ const first = this._content?.querySelector('[data-dropdown-item]:not([disabled])');
270
+ setTimeout(() => first?.focus(), 10);
271
+ }
272
+ }
273
+
274
+ customElements.define('kern-dropdown', KernDropdown);
275
+
276
+ /* === components/dialog.js === */
277
+ class KernDialog extends HTMLElement {
278
+ connectedCallback() {
279
+ this._dialog = this.querySelector('dialog');
280
+ if (!this._dialog) return;
281
+ this._setup();
282
+ }
283
+
284
+ _setup() {
285
+ const d = this._dialog;
286
+
287
+ // Wire close buttons
288
+ this.querySelectorAll('[data-dialog-close]').forEach(btn => {
289
+ btn.addEventListener('click', () => this.close());
290
+ });
291
+
292
+ // Backdrop click to close (unless opted out)
293
+ d.addEventListener('click', (e) => {
294
+ if (e.target === d && !d.hasAttribute('data-no-backdrop-close')) this.close();
295
+ });
296
+
297
+ // ESC (native cancel event)
298
+ d.addEventListener('cancel', (e) => {
299
+ e.preventDefault();
300
+ this.close();
301
+ });
302
+ }
303
+
304
+ open() {
305
+ if (!this._dialog) return;
306
+ this._dialog.showModal();
307
+ // Focus first focusable element
308
+ const f = firstFocusable(this._dialog);
309
+ if (f) setTimeout(() => f.focus(), 40);
310
+ emit(this, 'kern:dialog-open');
311
+ }
312
+
313
+ close() {
314
+ if (!this._dialog || !this._dialog.open) return;
315
+ this._dialog.close();
316
+ emit(this, 'kern:dialog-close');
317
+ }
318
+
319
+ toggle() {
320
+ this._dialog?.open ? this.close() : this.open();
321
+ }
322
+ }
323
+
324
+ customElements.define('kern-dialog', KernDialog);
325
+
326
+ /* === components/drawer.js === */
327
+ class KernDrawer extends HTMLElement {
328
+ connectedCallback() {
329
+ this._panel = this.querySelector('[data-drawer-panel]');
330
+ this._backdrop = this.querySelector('[data-drawer-backdrop]');
331
+
332
+ this._onKey = (e) => { if (e.key === 'Escape') this.close(); };
333
+
334
+ this.querySelectorAll('[data-drawer-close]').forEach(btn => {
335
+ btn.addEventListener('click', () => this.close());
336
+ });
337
+
338
+ this._backdrop?.addEventListener('click', () => this.close());
339
+ }
340
+
341
+ open() {
342
+ this.setAttribute('open', '');
343
+ document.body.style.overflow = 'hidden';
344
+ document.addEventListener('keydown', this._onKey);
345
+ const f = firstFocusable(this._panel);
346
+ if (f) setTimeout(() => f.focus(), 60);
347
+ emit(this, 'kern:drawer-open');
348
+ }
349
+
350
+ close() {
351
+ this.removeAttribute('open');
352
+ document.body.style.overflow = '';
353
+ document.removeEventListener('keydown', this._onKey);
354
+ emit(this, 'kern:drawer-close');
355
+ }
356
+
357
+ toggle() {
358
+ this.hasAttribute('open') ? this.close() : this.open();
359
+ }
360
+ }
361
+
362
+ customElements.define('kern-drawer', KernDrawer);
363
+
364
+ /* === components/toaster.js === */
365
+ class KernToaster extends HTMLElement {
366
+ connectedCallback() {
367
+ if (!this.hasAttribute('data-position')) {
368
+ this.setAttribute('data-position', 'bottom-right');
369
+ }
370
+ this.setAttribute('aria-live', 'polite');
371
+ this.setAttribute('aria-atomic', 'false');
372
+ }
373
+
374
+
375
+ add(options = {}) {
376
+ if (typeof options === 'string') options = { message: options };
377
+
378
+ const {
379
+ title = '',
380
+ message = '',
381
+ color = '',
382
+ duration = 4000,
383
+ dismissible = true,
384
+ } = options;
385
+
386
+ const toast = document.createElement('div');
387
+ toast.setAttribute('data-toast', '');
388
+ toast.setAttribute('role', 'status');
389
+ if (color) toast.setAttribute('data-color', color);
390
+
391
+ toast.innerHTML = `
392
+ <div data-toast-body>
393
+ ${title ? `<div data-toast-title>${esc(title)}</div>` : ''}
394
+ ${message ? `<div data-toast-message>${esc(message)}</div>` : ''}
395
+ </div>
396
+ ${dismissible ? `<button data-toast-close aria-label="Dismiss">✕</button>` : ''}
397
+ `.trim();
398
+
399
+ toast.querySelector('[data-toast-close]')?.addEventListener('click', () => this._remove(toast));
400
+
401
+ this.appendChild(toast);
402
+ emit(this, 'kern:toast-add', { toast, color, title, message });
403
+
404
+ if (duration > 0) setTimeout(() => this._remove(toast), duration);
405
+
406
+ return toast;
407
+ }
408
+
409
+ _remove(toast) {
410
+ if (!toast.isConnected) return;
411
+ toast.setAttribute('data-removing', '');
412
+ toast.addEventListener('animationend', () => {
413
+ toast.remove();
414
+ emit(this, 'kern:toast-remove', { toast });
415
+ }, { once: true });
416
+ }
417
+
418
+ clear() {
419
+ [...this.querySelectorAll('[data-toast]')].forEach(t => this._remove(t));
420
+ }
421
+ }
422
+
423
+ customElements.define('kern-toaster', KernToaster);
424
+
425
+ /* === api.js === */
426
+ const Kern = {
427
+ version: '1.0.0',
428
+
429
+
430
+ toast(options = {}) {
431
+ if (typeof options === 'string') options = { message: options };
432
+
433
+ const position = options.position ?? 'bottom-right';
434
+
435
+ // Find or create a toaster at the given position
436
+ let toaster = document.querySelector(`kern-toaster[data-position="${position}"]`)
437
+ ?? document.querySelector('kern-toaster');
438
+
439
+ if (!toaster) {
440
+ toaster = document.createElement('kern-toaster');
441
+ toaster.setAttribute('data-position', position);
442
+ document.body.appendChild(toaster);
443
+ }
444
+
445
+ return toaster.add(options);
446
+ },
447
+
448
+
449
+ dialog(selector) {
450
+ const el = typeof selector === 'string'
451
+ ? (document.getElementById(selector) ?? document.querySelector(selector))
452
+ : selector;
453
+
454
+ const wc = el?.closest?.('kern-dialog') ?? el;
455
+
456
+ if (typeof wc?.open === 'function') wc.open();
457
+ else if (el instanceof HTMLDialogElement) el.showModal();
458
+
459
+ return wc;
460
+ },
461
+
462
+
463
+ drawer(selector) {
464
+ const el = typeof selector === 'string'
465
+ ? (document.getElementById(selector) ?? document.querySelector(selector))
466
+ : selector;
467
+
468
+ const wc = el?.closest?.('kern-drawer') ?? el;
469
+
470
+ if (typeof wc?.open === 'function') wc.open();
471
+ return wc;
472
+ },
473
+
474
+
475
+ setAccent(name) {
476
+ document.documentElement.setAttribute('data-accent', name);
477
+ },
478
+
479
+
480
+ setTheme(theme) {
481
+ document.documentElement.setAttribute('data-theme', theme);
482
+ try { localStorage.setItem('kern-theme', theme); } catch (_) {}
483
+ },
484
+
485
+
486
+ setRadius(name) {
487
+ if (name === 'default') document.documentElement.removeAttribute('data-radius');
488
+ else document.documentElement.setAttribute('data-radius', name);
489
+ },
490
+
491
+
492
+ init(root = document) {
493
+ initAccordions(root);
494
+ initToggles(root);
495
+ initTableSort(root);
496
+ },
497
+ };
498
+
499
+ /* === boot.js === */
500
+ function boot() {
501
+ // Restore persisted theme before first paint
502
+ try {
503
+ const saved = localStorage.getItem('kern-theme');
504
+ if (saved) document.documentElement.setAttribute('data-theme', saved);
505
+ } catch (_) {}
506
+
507
+ // Initialize existing DOM
508
+ Kern.init();
509
+
510
+ // Auto-initialize dynamically injected HTML (htmx, alpine, fetch-swapped content, etc.)
511
+ new MutationObserver((mutations) => {
512
+ mutations.forEach(mutation => {
513
+ mutation.addedNodes.forEach(node => {
514
+ if (node.nodeType === Node.ELEMENT_NODE) {
515
+ Kern.init(node);
516
+ }
517
+ });
518
+ });
519
+ }).observe(document.body, { childList: true, subtree: true });
520
+ }
521
+
522
+ if (document.readyState === 'loading') {
523
+ document.addEventListener('DOMContentLoaded', boot);
524
+ } else {
525
+ boot();
526
+ }
527
+
528
+ if(typeof window!=="undefined")window.Kern=Kern;
529
+ })(window);
@@ -0,0 +1 @@
1
+ :root{--k-0:#fff;--k-50:#f8f8f7;--k-100:#f0efed;--k-150:#e8e6e2;--k-200:#d8d5d0;--k-300:#b8b4ae;--k-400:#918d87;--k-500:#6b6762;--k-600:#504d49;--k-700:#38352f;--k-800:#242119;--k-850:#1a1812;--k-900:#100f0a;--k-950:#080807;--k-bg:var(--k-0);--k-surface:var(--k-50);--k-surface-2:var(--k-100);--k-border:var(--k-200);--k-border-strong:var(--k-300);--k-text:var(--k-900);--k-text-2:var(--k-600);--k-text-3:var(--k-400);--k-text-invert:var(--k-0);--k-success:#2d8a4e;--k-success-bg:#edf7f1;--k-success-fg:#1a5c32;--k-warning:#c07a10;--k-warning-bg:#fef8ec;--k-warning-fg:#7a4d08;--k-danger:#c0392b;--k-danger-bg:#fdecea;--k-danger-fg:#8b1a10;--k-info:#1a6fa8;--k-info-bg:#eaf3fb;--k-info-fg:#0e4570;}@media(prefers-color-scheme:dark){:root:not([data-theme="light"]){--k-bg:var(--k-950);--k-surface:var(--k-900);--k-surface-2:var(--k-850);--k-border:var(--k-700);--k-border-strong:var(--k-600);--k-text:var(--k-50);--k-text-2:var(--k-300);--k-text-3:var(--k-500);--k-success-bg:#0f2b1a;--k-warning-bg:#2a1c07;--k-danger-bg:#2a0f0c;--k-info-bg:#0c1f2e;}}[data-theme="dark"]{--k-bg:var(--k-950);--k-surface:var(--k-900);--k-surface-2:var(--k-850);--k-border:var(--k-700);--k-border-strong:var(--k-600);--k-text:var(--k-50);--k-text-2:var(--k-300);--k-text-3:var(--k-500);--k-success-bg:#0f2b1a;--k-warning-bg:#2a1c07;--k-danger-bg:#2a0f0c;--k-info-bg:#0c1f2e;}[data-theme="light"]{--k-bg:var(--k-0);--k-surface:var(--k-50);--k-surface-2:var(--k-100);--k-border:var(--k-200);--k-border-strong:var(--k-300);--k-text:var(--k-900);--k-text-2:var(--k-600);--k-text-3:var(--k-400);--k-success-bg:#edf7f1;--k-warning-bg:#fef8ec;--k-danger-bg:#fdecea;--k-info-bg:#eaf3fb;}:root{--k-accent-h:38;--k-accent-s:92%;--k-accent-l:50%;--k-accent:hsl(var(--k-accent-h),var(--k-accent-s),var(--k-accent-l));--k-accent-subtle:hsl(var(--k-accent-h),var(--k-accent-s),94%);--k-accent-muted:hsl(var(--k-accent-h),60%,70%);--k-accent-fg:#000;}[data-theme="dark"]{--k-accent-subtle:hsl(var(--k-accent-h),30%,18%);--k-accent-muted:hsl(var(--k-accent-h),60%,45%);}@media(prefers-color-scheme:dark){:root:not([data-theme="light"]){--k-accent-subtle:hsl(var(--k-accent-h),30%,18%);--k-accent-muted:hsl(var(--k-accent-h),60%,45%);}}[data-accent="amber"]{--k-accent-h:38;--k-accent-s:92%;--k-accent-l:50%;--k-accent-fg:#000}[data-accent="blue"]{--k-accent-h:214;--k-accent-s:85%;--k-accent-l:52%;--k-accent-fg:#fff}[data-accent="green"]{--k-accent-h:142;--k-accent-s:72%;--k-accent-l:40%;--k-accent-fg:#fff}[data-accent="red"]{--k-accent-h:4;--k-accent-s:80%;--k-accent-l:50%;--k-accent-fg:#fff}[data-accent="violet"]{--k-accent-h:262;--k-accent-s:75%;--k-accent-l:58%;--k-accent-fg:#fff}[data-accent="rose"]{--k-accent-h:346;--k-accent-s:80%;--k-accent-l:55%;--k-accent-fg:#fff}[data-accent="cyan"]{--k-accent-h:192;--k-accent-s:80%;--k-accent-l:42%;--k-accent-fg:#fff}[data-accent="orange"]{--k-accent-h:24;--k-accent-s:95%;--k-accent-l:53%;--k-accent-fg:#fff}:root{--k-font-sans:'DM Sans','Inter',system-ui,sans-serif;--k-font-mono:'DM Mono','Fira Code','Cascadia Code',monospace;--k-font-size:15px;--k-line-height:1.6;--k-fw-normal:400;--k-fw-medium:500;--k-fw-bold:600;}:root{--k-sp-1:.25rem;--k-sp-2:.5rem;--k-sp-3:.75rem;--k-sp-4:1rem;--k-sp-5:1.25rem;--k-sp-6:1.5rem;--k-sp-8:2rem;--k-sp-10:2.5rem;--k-sp-12:3rem;--k-sp-16:4rem;}:root{--k-r-sm:3px;--k-r:6px;--k-r-md:8px;--k-r-lg:12px;--k-r-xl:16px;--k-r-full:9999px;--k-btn-r:var(--k-r);--k-card-r:var(--k-r-md);--k-input-r:var(--k-r);--k-badge-r:var(--k-r-sm);--k-tooltip-r:var(--k-r-sm);--k-dialog-r:var(--k-r-lg);}[data-radius="none"]{--k-r-sm:0;--k-r:0;--k-r-md:0;--k-r-lg:0;--k-r-xl:0;--k-btn-r:0;--k-card-r:0;--k-input-r:0;--k-badge-r:0}[data-radius="sharp"]{--k-r-sm:2px;--k-r:4px;--k-r-md:6px;--k-r-lg:8px;--k-r-xl:10px}[data-radius="round"]{--k-r-sm:6px;--k-r:10px;--k-r-md:14px;--k-r-lg:20px;--k-r-xl:28px;--k-btn-r:var(--k-r-full);--k-input-r:var(--k-r-full)}:root{--k-sh-sm:0 1px 2px rgba(0,0,0,.06),0 1px 3px rgba(0,0,0,.08);--k-sh:0 2px 8px rgba(0,0,0,.08),0 1px 3px rgba(0,0,0,.06);--k-sh-md:0 4px 16px rgba(0,0,0,.10),0 2px 6px rgba(0,0,0,.06);--k-sh-lg:0 8px 32px rgba(0,0,0,.12),0 4px 12px rgba(0,0,0,.08);--k-sh-xl:0 16px 48px rgba(0,0,0,.14),0 8px 24px rgba(0,0,0,.08);}[data-theme="dark"]{--k-sh-sm:0 1px 2px rgba(0,0,0,.3);--k-sh:0 2px 8px rgba(0,0,0,.4);--k-sh-md:0 4px 16px rgba(0,0,0,.5);--k-sh-lg:0 8px 32px rgba(0,0,0,.5);--k-sh-xl:0 16px 48px rgba(0,0,0,.6);}@media(prefers-color-scheme:dark){:root:not([data-theme="light"]){--k-sh-sm:0 1px 2px rgba(0,0,0,.3);--k-sh:0 2px 8px rgba(0,0,0,.4);--k-sh-md:0 4px 16px rgba(0,0,0,.5);--k-sh-lg:0 8px 32px rgba(0,0,0,.5);--k-sh-xl:0 16px 48px rgba(0,0,0,.6);}}:root{--k-ease:cubic-bezier(.16,1,.3,1);--k-ease-in:cubic-bezier(.4,0,1,1);--k-ease-out:cubic-bezier(0,0,.2,1);--k-fast:120ms;--k-dur:200ms;--k-slow:350ms;}@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}}:root{--k-z-drop:100;--k-z-sticky:200;--k-z-overlay:300;--k-z-modal:400;--k-z-toast:500;--k-z-tip:600;}:root{--k-btn-h-sm:28px;--k-btn-h:36px;--k-btn-h-lg:44px;--k-input-h:36px;--k-input-h-sm:28px;--k-input-h-lg:44px;--k-card-p:var(--k-sp-6);--k-sidebar-w:240px;}*,*::before,*::after{box-sizing:border-box;margin:0}html{font-size:var(--k-font-size);-webkit-text-size-adjust:100%;tab-size:2}body{font-family:var(--k-font-sans);font-size:1rem;line-height:var(--k-line-height);color:var(--k-text);background:var(--k-bg);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}img,video,svg{display:block;max-width:100%}input,button,textarea,select{font:inherit}a{color:var(--k-accent);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;transition:opacity var(--k-fast)}a:hover{opacity:.75}hr{border:none;border-top:1px solid var(--k-border);margin:var(--k-sp-6) 0}h1,h2,h3,h4,h5,h6{font-weight:var(--k-fw-bold);line-height:1.25;letter-spacing:-0.02em;color:var(--k-text)}h1{font-size:2.5rem;letter-spacing:-0.03em}h2{font-size:2rem}h3{font-size:1.5rem}h4{font-size:1.25rem}h5{font-size:1.1rem}h6{font-size:1rem}p{margin-bottom:var(--k-sp-4);max-width:68ch}p:last-child{margin-bottom:0}strong{font-weight:var(--k-fw-bold)}em{font-style:italic}small{font-size:.8rem;color:var(--k-text-2)}code{font-family:var(--k-font-mono);font-size:.875em;background:var(--k-surface-2);border:1px solid var(--k-border);padding:.1em .4em;border-radius:var(--k-r-sm)}pre{font-family:var(--k-font-mono);font-size:.875rem;background:var(--k-surface);border:1px solid var(--k-border);border-radius:var(--k-r-md);padding:var(--k-sp-5) var(--k-sp-6);overflow-x:auto;line-height:1.7}pre code{background:none;border:none;padding:0;font-size:inherit}blockquote{border-left:3px solid var(--k-accent);padding-left:var(--k-sp-5);margin:var(--k-sp-6) 0;color:var(--k-text-2);font-style:italic}kbd{font-family:var(--k-font-mono);font-size:.8em;background:var(--k-surface-2);border:1px solid var(--k-border);border-bottom-width:2px;padding:.1em .5em;border-radius:var(--k-r-sm)}mark{background:hsl(var(--k-accent-h),90%,85%);color:var(--k-text);padding:.05em .3em;border-radius:2px}[data-theme="dark"] mark{background:hsl(var(--k-accent-h),50%,28%)}abbr[title]{text-decoration:underline dotted;cursor:help}[data-text="xs"]{font-size:.75rem}[data-text="sm"]{font-size:.875rem}[data-text="lg"]{font-size:1.125rem}[data-text="xl"]{font-size:1.25rem}[data-text="muted"]{color:var(--k-text-2)}[data-text="faint"]{color:var(--k-text-3)}[data-text="accent"]{color:var(--k-accent)}[data-text="mono"]{font-family:var(--k-font-mono)}button,[role="button"],input[type="submit"],input[type="button"],input[type="reset"]{display:inline-flex;align-items:center;justify-content:center;gap:var(--k-sp-2);height:var(--k-btn-h);padding:0 var(--k-sp-4);font-size:.875rem;font-weight:var(--k-fw-medium);line-height:1;white-space:nowrap;border-radius:var(--k-btn-r);border:1px solid transparent;cursor:pointer;text-decoration:none;user-select:none;transition:background var(--k-fast) var(--k-ease),border-color var(--k-fast),color var(--k-fast),box-shadow var(--k-fast),filter var(--k-fast),transform var(--k-fast);background:var(--k-accent);color:var(--k-accent-fg);}button:hover{filter:brightness(1.08);box-shadow:var(--k-sh-sm)}button:active{filter:brightness(.95);transform:translateY(1px)}button:focus-visible{outline:2px solid var(--k-accent);outline-offset:2px}button[data-variant="secondary"]{background:var(--k-surface-2);color:var(--k-text);border-color:var(--k-border)}button[data-variant="secondary"]:hover{background:var(--k-surface);border-color:var(--k-border-strong);filter:none}button[data-variant="outline"]{background:transparent;color:var(--k-text);border-color:var(--k-border-strong)}button[data-variant="outline"]:hover{background:var(--k-surface);filter:none}button[data-variant="ghost"]{background:transparent;color:var(--k-text);border-color:transparent}button[data-variant="ghost"]:hover{background:var(--k-surface-2);filter:none}button[data-variant="danger"]{background:var(--k-danger);color:#fff;border-color:transparent}button[data-variant="link"]{background:transparent;color:var(--k-accent);border-color:transparent;padding:0;height:auto;text-decoration:underline;text-underline-offset:3px}button[data-size="sm"]{height:var(--k-btn-h-sm);padding:0 var(--k-sp-3);font-size:.8rem}button[data-size="lg"]{height:var(--k-btn-h-lg);padding:0 var(--k-sp-6);font-size:.95rem}button[data-size="icon"]{width:var(--k-btn-h);padding:0}button[data-size="icon"][data-size="sm"]{width:var(--k-btn-h-sm)}button[data-color="success"]{background:var(--k-success);color:#fff}button[data-color="warning"]{background:var(--k-warning);color:#fff}button[data-color="info"]{background:var(--k-info);color:#fff}button[data-loading]{pointer-events:none;opacity:.75}button[data-loading]::after{content:'';width:13px;height:13px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:k-spin .6s linear infinite;margin-left:var(--k-sp-2)}button:disabled,button[disabled]{opacity:.45;pointer-events:none;cursor:not-allowed}[role="group"]{display:inline-flex}[role="group"] button{border-radius:0}[role="group"]>:first-child{border-radius:var(--k-btn-r) 0 0 var(--k-btn-r)}[role="group"]>:last-child{border-radius:0 var(--k-btn-r) var(--k-btn-r) 0}[role="group"]>:not(:first-child){border-left-width:0}label{display:block;font-size:.875rem;font-weight:var(--k-fw-medium);color:var(--k-text);margin-bottom:var(--k-sp-1)}label[data-required]::after{content:' *';color:var(--k-danger)}input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]),textarea,select{display:block;width:100%;height:var(--k-input-h);padding:0 var(--k-sp-3);font-size:.875rem;color:var(--k-text);background:var(--k-bg);border:1px solid var(--k-border);border-radius:var(--k-input-r);outline:none;appearance:none;-webkit-appearance:none;transition:border-color var(--k-fast),box-shadow var(--k-fast);}textarea{height:auto;min-height:90px;padding:var(--k-sp-3);resize:vertical}select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:32px;cursor:pointer}input:not([type=checkbox]):not([type=radio]):focus,textarea:focus,select:focus{border-color:var(--k-accent);box-shadow:0 0 0 3px hsl(var(--k-accent-h),var(--k-accent-s),var(--k-accent-l),.15);}input[data-size="sm"]:not([type=checkbox]):not([type=radio]){height:var(--k-input-h-sm);font-size:.8rem;padding:0 var(--k-sp-2)}input[data-size="lg"]:not([type=checkbox]):not([type=radio]){height:var(--k-input-h-lg);font-size:1rem;padding:0 var(--k-sp-4)}input[data-state="error"],textarea[data-state="error"]{border-color:var(--k-danger)}input[data-state="error"]:focus{box-shadow:0 0 0 3px rgba(192,57,43,.15)}input[data-state="success"],textarea[data-state="success"]{border-color:var(--k-success)}input:disabled,textarea:disabled,select:disabled{opacity:.55;cursor:not-allowed;background:var(--k-surface)}input[readonly]{background:var(--k-surface)}input[type=checkbox],input[type=radio]{width:16px;height:16px;border:1.5px solid var(--k-border-strong);background:var(--k-bg);appearance:none;-webkit-appearance:none;cursor:pointer;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;position:relative;transition:all var(--k-fast);}input[type=checkbox]{border-radius:var(--k-r-sm)}input[type=radio]{border-radius:50%}input[type=checkbox]:checked,input[type=radio]:checked{background:var(--k-accent);border-color:var(--k-accent)}input[type=checkbox]:checked::after{content:'';width:4px;height:8px;border:2px solid var(--k-accent-fg);border-top:none;border-left:none;transform:rotate(45deg) translateY(-1px);position:absolute}input[type=radio]:checked::after{content:'';width:6px;height:6px;background:var(--k-accent-fg);border-radius:50%;position:absolute}input[type=checkbox]:focus-visible,input[type=radio]:focus-visible{outline:2px solid var(--k-accent);outline-offset:2px}input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:5px;background:var(--k-surface-2);border-radius:var(--k-r-full);outline:none;cursor:pointer}input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;background:var(--k-accent);border-radius:50%;border:2px solid var(--k-bg);box-shadow:var(--k-sh-sm);transition:transform var(--k-fast)}input[type=range]::-webkit-slider-thumb:hover{transform:scale(1.15)}[data-field]{display:flex;flex-direction:column;gap:var(--k-sp-1);margin-bottom:var(--k-sp-5)}[data-field]:last-child{margin-bottom:0}[data-hint]{font-size:.8rem;color:var(--k-text-2)}[data-hint][data-state="error"]{color:var(--k-danger)}[data-hint][data-state="success"]{color:var(--k-success)}[data-input-group]{display:flex;align-items:stretch;width:100%}[data-input-group] input{border-radius:0;flex:1}[data-input-group] [data-addon]{display:inline-flex;align-items:center;padding:0 var(--k-sp-3);background:var(--k-surface-2);border:1px solid var(--k-border);font-size:.875rem;color:var(--k-text-2);white-space:nowrap}[data-input-group] [data-addon]:first-child{border-right:none;border-radius:var(--k-input-r) 0 0 var(--k-input-r)}[data-input-group] [data-addon]:last-child{border-left:none;border-radius:0 var(--k-input-r) var(--k-input-r) 0}[data-card]{background:var(--k-surface);border:1px solid var(--k-border);border-radius:var(--k-card-r);padding:var(--k-card-p);box-shadow:var(--k-sh-sm);position:relative}[data-card][data-variant="flat"]{box-shadow:none}[data-card][data-variant="raised"]{box-shadow:var(--k-sh-md)}[data-card][data-variant="ghost"]{background:transparent;border-color:transparent;box-shadow:none}[data-card][data-variant="inset"]{background:var(--k-surface-2);border-color:transparent;box-shadow:none}[data-card][data-clickable]{cursor:pointer;transition:box-shadow var(--k-dur),transform var(--k-dur),border-color var(--k-dur)}[data-card][data-clickable]:hover{box-shadow:var(--k-sh-md);transform:translateY(-1px);border-color:var(--k-border-strong)}[data-card][data-clickable]:active{transform:translateY(0)}[data-card] [data-card-header]{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--k-sp-4);margin-bottom:var(--k-sp-5);padding-bottom:var(--k-sp-5);border-bottom:1px solid var(--k-border)}[data-card] [data-card-title]{font-size:1rem;font-weight:var(--k-fw-bold);letter-spacing:-0.01em}[data-card] [data-card-desc]{font-size:.875rem;color:var(--k-text-2);margin-top:var(--k-sp-1)}[data-card] [data-card-footer]{display:flex;align-items:center;gap:var(--k-sp-3);margin-top:var(--k-sp-5);padding-top:var(--k-sp-5);border-top:1px solid var(--k-border)}[data-badge]{display:inline-flex;align-items:center;gap:var(--k-sp-1);padding:2px var(--k-sp-2);font-size:.75rem;font-weight:var(--k-fw-medium);border-radius:var(--k-badge-r);border:1px solid var(--k-border);line-height:1.5;white-space:nowrap;background:var(--k-surface-2);color:var(--k-text-2);}[data-badge][data-color="accent"]{background:var(--k-accent-subtle);color:var(--k-accent);border-color:var(--k-accent-muted)}[data-badge][data-color="success"]{background:var(--k-success-bg);color:var(--k-success-fg);border-color:var(--k-success)}[data-badge][data-color="warning"]{background:var(--k-warning-bg);color:var(--k-warning-fg);border-color:var(--k-warning)}[data-badge][data-color="danger"]{background:var(--k-danger-bg);color:var(--k-danger-fg);border-color:var(--k-danger)}[data-badge][data-color="info"]{background:var(--k-info-bg);color:var(--k-info-fg);border-color:var(--k-info)}[data-badge][data-variant="solid"][data-color="accent"]{background:var(--k-accent);color:var(--k-accent-fg);border-color:transparent}[data-badge][data-variant="solid"][data-color="success"]{background:var(--k-success);color:#fff;border-color:transparent}[data-badge][data-variant="solid"][data-color="danger"]{background:var(--k-danger);color:#fff;border-color:transparent}[data-badge][data-variant="pill"]{border-radius:var(--k-r-full)}[data-badge][data-dot]::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor;flex-shrink:0}[role="alert"],[data-alert]{display:flex;gap:var(--k-sp-3);align-items:flex-start;padding:var(--k-sp-4) var(--k-sp-5);border-radius:var(--k-r-md);border:1px solid;font-size:.875rem;line-height:1.5;background:var(--k-info-bg);border-color:var(--k-info);color:var(--k-info-fg);}[data-alert][data-color="success"]{background:var(--k-success-bg);border-color:var(--k-success);color:var(--k-success-fg)}[data-alert][data-color="warning"]{background:var(--k-warning-bg);border-color:var(--k-warning);color:var(--k-warning-fg)}[data-alert][data-color="danger"]{background:var(--k-danger-bg);border-color:var(--k-danger);color:var(--k-danger-fg)}[data-alert][data-color="neutral"]{background:var(--k-surface-2);border-color:var(--k-border);color:var(--k-text)}[data-alert] [data-alert-title]{font-weight:var(--k-fw-bold);margin-bottom:var(--k-sp-1)}[data-alert] [data-alert-icon]{flex-shrink:0;margin-top:1px}table,[data-table]{width:100%;border-collapse:collapse;font-size:.875rem}table th{text-align:left;font-weight:var(--k-fw-medium);font-size:.75rem;color:var(--k-text-2);letter-spacing:.05em;text-transform:uppercase;padding:var(--k-sp-3) var(--k-sp-4);border-bottom:1px solid var(--k-border);white-space:nowrap;background:var(--k-surface)}table th[data-sort]{cursor:pointer;user-select:none}table th[data-sort]:hover{color:var(--k-text)}table th[data-sort]::after{content:' ⇕';opacity:.35;font-size:.75em}table th[data-sort="asc"]::after{content:' ↑';opacity:1;color:var(--k-accent)}table th[data-sort="desc"]::after{content:' ↓';opacity:1;color:var(--k-accent)}table td{padding:var(--k-sp-3) var(--k-sp-4);border-bottom:1px solid var(--k-border);vertical-align:middle}table tr:last-child td{border-bottom:none}table[data-variant="bordered"] td,table[data-variant="bordered"] th{border:1px solid var(--k-border)}table[data-variant="striped"] tbody tr:nth-child(even){background:var(--k-surface)}table[data-variant="compact"] th,table[data-variant="compact"] td{padding:var(--k-sp-2) var(--k-sp-3)}table[data-variant="comfortable"] th,table[data-variant="comfortable"] td{padding:var(--k-sp-4) var(--k-sp-5)}tbody tr{transition:background var(--k-fast)}table[data-hover] tbody tr:hover{background:var(--k-surface)}[data-table-wrap]{border:1px solid var(--k-border);border-radius:var(--k-r-md);overflow:hidden;overflow-x:auto}kern-tabs{display:block}kern-tabs [data-tabs-list]{display:flex;border-bottom:1px solid var(--k-border);overflow-x:auto;scrollbar-width:none}kern-tabs [data-tabs-list]::-webkit-scrollbar{display:none}kern-tabs [data-tab]{display:inline-flex;align-items:center;gap:var(--k-sp-2);padding:var(--k-sp-3) var(--k-sp-4);font-size:.875rem;font-weight:var(--k-fw-medium);color:var(--k-text-2);border-bottom:2px solid transparent;cursor:pointer;white-space:nowrap;transition:color var(--k-fast),border-color var(--k-fast);margin-bottom:-1px;user-select:none;background:none;border-top:none;border-left:none;border-right:none;border-radius:0;height:auto;}kern-tabs [data-tab]:hover{color:var(--k-text)}kern-tabs [data-tab][aria-selected="true"]{color:var(--k-accent);border-bottom-color:var(--k-accent)}kern-tabs [data-tab-panel]{padding:var(--k-sp-6) 0;display:none}kern-tabs [data-tab-panel][data-active]{display:block}kern-tabs[data-variant="pills"] [data-tabs-list]{border-bottom:none;gap:var(--k-sp-1);padding:var(--k-sp-1);background:var(--k-surface-2);border-radius:var(--k-r-md);display:inline-flex}kern-tabs[data-variant="pills"] [data-tab]{border:none;border-radius:var(--k-r);margin-bottom:0;color:var(--k-text-2)}kern-tabs[data-variant="pills"] [data-tab][aria-selected="true"]{background:var(--k-bg);color:var(--k-text);box-shadow:var(--k-sh-sm)}[data-accordion]{border:1px solid var(--k-border);border-radius:var(--k-r-md);overflow:hidden}[data-accordion-item]{border-bottom:1px solid var(--k-border)}[data-accordion-item]:last-child{border-bottom:none}[data-accordion-trigger]{display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--k-sp-4) var(--k-sp-5);font-size:.9rem;font-weight:var(--k-fw-medium);cursor:pointer;background:none;border:none;height:auto;color:var(--k-text);text-align:left;transition:background var(--k-fast);border-radius:0;}[data-accordion-trigger]:hover{background:var(--k-surface-2)}[data-accordion-trigger]::after{content:'';width:16px;height:16px;flex-shrink:0;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:center;transition:transform var(--k-dur) var(--k-ease);}[data-accordion-trigger][aria-expanded="true"]::after{transform:rotate(180deg)}[data-accordion-content]{overflow:hidden;max-height:0;transition:max-height var(--k-slow) var(--k-ease)}[data-accordion-content][data-open]{max-height:2000px}[data-accordion-content] [data-accordion-body]{padding:0 var(--k-sp-5) var(--k-sp-5);font-size:.875rem;color:var(--k-text-2);line-height:1.7}dialog{border:1px solid var(--k-border);border-radius:var(--k-dialog-r);box-shadow:var(--k-sh-xl);background:var(--k-bg);padding:0;max-width:520px;width:calc(100vw - 2rem);color:var(--k-text);animation:k-dialog-in var(--k-slow) var(--k-ease);}dialog[data-size="sm"]{max-width:380px}dialog[data-size="lg"]{max-width:720px}dialog[data-size="xl"]{max-width:960px}dialog[data-size="full"]{max-width:calc(100vw - 2rem);max-height:calc(100vh - 2rem)}dialog::backdrop{background:rgba(0,0,0,.55);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}dialog [data-dialog-header]{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--k-sp-4);padding:var(--k-sp-6);border-bottom:1px solid var(--k-border)}dialog [data-dialog-title]{font-size:1.05rem;font-weight:var(--k-fw-bold);letter-spacing:-0.015em}dialog [data-dialog-desc]{font-size:.875rem;color:var(--k-text-2);margin-top:var(--k-sp-1)}dialog [data-dialog-close]{background:none;border:none;color:var(--k-text-3);padding:0;height:24px;width:24px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:var(--k-r-sm);flex-shrink:0;transition:color var(--k-fast),background var(--k-fast);font-size:1.2rem;line-height:1}dialog [data-dialog-close]:hover{color:var(--k-text);background:var(--k-surface-2)}dialog [data-dialog-body]{padding:var(--k-sp-6);font-size:.9rem;line-height:1.7}dialog [data-dialog-footer]{display:flex;align-items:center;justify-content:flex-end;gap:var(--k-sp-3);padding:var(--k-sp-4) var(--k-sp-6);border-top:1px solid var(--k-border);background:var(--k-surface);border-radius:0 0 var(--k-dialog-r) var(--k-dialog-r)}kern-dropdown{display:inline-block;position:relative}kern-dropdown [data-dropdown-content]{position:absolute;top:calc(100%+6px);left:0;min-width:190px;background:var(--k-bg);border:1px solid var(--k-border);border-radius:var(--k-r-md);box-shadow:var(--k-sh-lg);padding:var(--k-sp-1);z-index:var(--k-z-drop);display:none;animation:k-fade-in var(--k-fast) var(--k-ease-out);}kern-dropdown[data-align="end"] [data-dropdown-content]{left:auto;right:0}kern-dropdown[open] [data-dropdown-content]{display:block}kern-dropdown [data-dropdown-item]{display:flex;align-items:center;gap:var(--k-sp-3);padding:var(--k-sp-2) var(--k-sp-3);font-size:.875rem;color:var(--k-text);border-radius:var(--k-r);cursor:pointer;transition:background var(--k-fast);text-decoration:none;}kern-dropdown [data-dropdown-item]:hover{background:var(--k-surface-2)}kern-dropdown [data-dropdown-item][data-color="danger"]{color:var(--k-danger)}kern-dropdown [data-dropdown-item][data-color="danger"]:hover{background:var(--k-danger-bg)}kern-dropdown [data-dropdown-item][disabled]{opacity:.45;pointer-events:none}kern-dropdown [data-dropdown-sep]{height:1px;background:var(--k-border);margin:var(--k-sp-1) 0}kern-dropdown [data-dropdown-label]{padding:var(--k-sp-2) var(--k-sp-3);font-size:.72rem;font-weight:var(--k-fw-medium);color:var(--k-text-3);text-transform:uppercase;letter-spacing:.07em}[data-tooltip]{position:relative}[data-tooltip]::before{content:attr(data-tooltip);position:absolute;bottom:calc(100%+8px);left:50%;transform:translateX(-50%) translateY(4px);background:var(--k-900);color:var(--k-50);font-size:.77rem;padding:var(--k-sp-1) var(--k-sp-3);border-radius:var(--k-tooltip-r);white-space:nowrap;pointer-events:none;opacity:0;z-index:var(--k-z-tip);box-shadow:var(--k-sh-md);max-width:240px;text-align:center;transition:opacity var(--k-fast),transform var(--k-fast);}[data-tooltip]::after{content:'';position:absolute;bottom:calc(100%+3px);left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:var(--k-900);pointer-events:none;opacity:0;transition:opacity var(--k-fast);z-index:var(--k-z-tip);}[data-tooltip]:hover::before,[data-tooltip]:hover::after{opacity:1;transform:translateX(-50%) translateY(0)}[data-tooltip][data-placement="bottom"]::before{bottom:auto;top:calc(100%+8px);transform:translateX(-50%) translateY(-4px)}[data-tooltip][data-placement="bottom"]::after{bottom:auto;top:calc(100%+3px);border-top-color:transparent;border-bottom-color:var(--k-900)}[data-tooltip][data-placement="bottom"]:hover::before{transform:translateX(-50%) translateY(0)}[data-tooltip][data-placement="left"]::before{bottom:auto;left:auto;right:calc(100%+8px);top:50%;transform:translateY(-50%) translateX(4px)}[data-tooltip][data-placement="left"]:hover::before{transform:translateY(-50%) translateX(0)}[data-tooltip][data-placement="right"]::before{bottom:auto;left:calc(100%+8px);top:50%;transform:translateY(-50%) translateX(-4px)}[data-tooltip][data-placement="right"]:hover::before{transform:translateY(-50%) translateX(0)}[data-theme="light"] [data-tooltip]::before{background:var(--k-200);color:var(--k-900)}[data-theme="light"] [data-tooltip]::after{border-top-color:var(--k-200)}kern-toaster{position:fixed;z-index:var(--k-z-toast);display:flex;flex-direction:column;gap:var(--k-sp-3);pointer-events:none;padding:var(--k-sp-4);}kern-toaster[data-position="top-right"]{top:0;right:0;align-items:flex-end}kern-toaster[data-position="top-left"]{top:0;left:0;align-items:flex-start}kern-toaster[data-position="top-center"]{top:0;left:50%;transform:translateX(-50%);align-items:center}kern-toaster[data-position="bottom-right"]{bottom:0;right:0;align-items:flex-end;flex-direction:column-reverse}kern-toaster[data-position="bottom-left"]{bottom:0;left:0;align-items:flex-start;flex-direction:column-reverse}kern-toaster[data-position="bottom-center"]{bottom:0;left:50%;transform:translateX(-50%);align-items:center;flex-direction:column-reverse}[data-toast]{display:flex;align-items:flex-start;gap:var(--k-sp-3);min-width:280px;max-width:400px;padding:var(--k-sp-4);background:var(--k-bg);border:1px solid var(--k-border);border-radius:var(--k-r-md);box-shadow:var(--k-sh-lg);pointer-events:all;animation:k-toast-in var(--k-slow) var(--k-ease);position:relative;overflow:hidden;}[data-toast]::before{content:'';position:absolute;top:0;left:0;width:3px;height:100%;background:var(--k-info)}[data-toast][data-color="success"]::before{background:var(--k-success)}[data-toast][data-color="warning"]::before{background:var(--k-warning)}[data-toast][data-color="danger"]::before{background:var(--k-danger)}[data-toast][data-color="accent"]::before{background:var(--k-accent)}[data-toast-body]{flex:1}[data-toast-title]{font-size:.875rem;font-weight:var(--k-fw-medium);margin-bottom:2px}[data-toast-message]{font-size:.8rem;color:var(--k-text-2)}[data-toast-close]{background:none;border:none;color:var(--k-text-3);cursor:pointer;padding:0;height:20px;width:20px;font-size:1rem;display:flex;align-items:center;justify-content:center;border-radius:var(--k-r-sm);transition:color var(--k-fast),background var(--k-fast);flex-shrink:0}[data-toast-close]:hover{color:var(--k-text);background:var(--k-surface-2)}[data-toast][data-removing]{animation:k-toast-out var(--k-slow) var(--k-ease) forwards}[data-progress]{width:100%;height:6px;background:var(--k-surface-2);border-radius:var(--k-r-full);overflow:hidden}[data-progress][data-size="sm"]{height:3px}[data-progress][data-size="lg"]{height:10px}[data-progress-bar]{height:100%;background:var(--k-accent);border-radius:inherit;transition:width var(--k-slow) var(--k-ease)}[data-progress][data-color="success"] [data-progress-bar]{background:var(--k-success)}[data-progress][data-color="warning"] [data-progress-bar]{background:var(--k-warning)}[data-progress][data-color="danger"] [data-progress-bar]{background:var(--k-danger)}[data-progress][data-animated] [data-progress-bar]{background:repeating-linear-gradient(-45deg,var(--k-accent),var(--k-accent) 10px,hsl(var(--k-accent-h),var(--k-accent-s),calc(var(--k-accent-l)+10%)) 10px,hsl(var(--k-accent-h),var(--k-accent-s),calc(var(--k-accent-l)+10%)) 20px);background-size:28px 100%;animation:k-progress-stripe 1s linear infinite}[data-progress][data-indeterminate] [data-progress-bar]{width:40%!important;animation:k-progress-indeterminate 1.4s ease-in-out infinite}[data-spinner]{display:inline-block;width:20px;height:20px;border:2px solid var(--k-surface-2);border-top-color:var(--k-accent);border-radius:50%;animation:k-spin .7s linear infinite}[data-spinner][data-size="sm"]{width:14px;height:14px}[data-spinner][data-size="lg"]{width:32px;height:32px;border-width:3px}[data-spinner][data-color="text"]{border-color:var(--k-surface-2);border-top-color:currentColor}[data-skeleton]{background:linear-gradient(90deg,var(--k-surface-2) 25%,var(--k-surface) 50%,var(--k-surface-2) 75%);background-size:200% 100%;animation:k-skeleton 1.5s ease-in-out infinite;border-radius:var(--k-r);display:block;}[data-skeleton][data-shape="circle"]{border-radius:50%}[data-skeleton][data-shape="text"]{height:1em;border-radius:var(--k-r-sm)}[data-switch]{position:relative;display:inline-flex;align-items:center;gap:var(--k-sp-3);cursor:pointer;user-select:none}[data-switch] input[type=checkbox]{position:absolute;opacity:0;width:0;height:0}[data-switch-track]{width:40px;height:22px;background:var(--k-border-strong);border-radius:var(--k-r-full);position:relative;transition:background var(--k-fast);flex-shrink:0}[data-switch-track]::after{content:'';position:absolute;top:3px;left:3px;width:16px;height:16px;background:#fff;border-radius:50%;transition:transform var(--k-dur) var(--k-ease);box-shadow:var(--k-sh-sm)}[data-switch] input:checked~[data-switch-track]{background:var(--k-accent)}[data-switch] input:checked~[data-switch-track]::after{transform:translateX(18px)}[data-switch] input:focus-visible~[data-switch-track]{outline:2px solid var(--k-accent);outline-offset:2px}[data-switch][data-size="sm"] [data-switch-track]{width:32px;height:18px}[data-switch][data-size="sm"] [data-switch-track]::after{width:12px;height:12px}[data-switch][data-size="sm"] input:checked~[data-switch-track]::after{transform:translateX(14px)}[data-avatar]{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:50%;background:var(--k-accent-subtle);color:var(--k-accent);font-size:.875rem;font-weight:var(--k-fw-bold);overflow:hidden;flex-shrink:0;user-select:none;border:2px solid var(--k-bg)}[data-avatar][data-size="sm"]{width:26px;height:26px;font-size:.7rem}[data-avatar][data-size="lg"]{width:48px;height:48px;font-size:1.1rem}[data-avatar][data-size="xl"]{width:64px;height:64px;font-size:1.4rem}[data-avatar] img{width:100%;height:100%;object-fit:cover}[data-avatar-group]{display:flex}[data-avatar-group] [data-avatar]{margin-left:-8px}[data-avatar-group] [data-avatar]:first-child{margin-left:0}[aria-label="breadcrumb"],[data-breadcrumb]{display:flex;align-items:center;gap:var(--k-sp-2);font-size:.875rem;color:var(--k-text-2);flex-wrap:wrap}[data-breadcrumb] a{color:var(--k-text-2);text-decoration:none}[data-breadcrumb] a:hover{color:var(--k-text)}[data-breadcrumb] [aria-current="page"]{color:var(--k-text);font-weight:var(--k-fw-medium)}[data-breadcrumb-sep]::before{content:'/';color:var(--k-text-3)}[data-breadcrumb][data-sep="dot"] [data-breadcrumb-sep]::before{content:'·'}[data-breadcrumb][data-sep="arrow"] [data-breadcrumb-sep]::before{content:'→'}[data-stepper]{display:flex;align-items:flex-start;counter-reset:step;overflow-x:auto}[data-step]{display:flex;flex-direction:column;align-items:center;flex:1;position:relative;text-align:center;counter-increment:step}[data-step]:not(:last-child)::after{content:'';position:absolute;top:16px;left:50%;width:100%;height:1px;background:var(--k-border)}[data-step][data-done]:not(:last-child)::after{background:var(--k-success)}[data-step-marker]{width:32px;height:32px;border-radius:50%;background:var(--k-surface-2);border:2px solid var(--k-border);display:flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:var(--k-fw-bold);color:var(--k-text-2);position:relative;z-index:1;transition:all var(--k-dur)}[data-step-marker]::before{content:counter(step)}[data-step][data-active] [data-step-marker]{background:var(--k-accent);border-color:var(--k-accent);color:var(--k-accent-fg)}[data-step][data-done] [data-step-marker]{background:var(--k-success);border-color:var(--k-success);color:#fff}[data-step][data-done] [data-step-marker]::before{content:'✓'}[data-step-label]{font-size:.8rem;color:var(--k-text-2);margin-top:var(--k-sp-2)}[data-step][data-active] [data-step-label]{color:var(--k-text);font-weight:var(--k-fw-medium)}[data-pagination]{display:flex;align-items:center;gap:var(--k-sp-1)}[data-pagination] [data-page]{display:inline-flex;align-items:center;justify-content:center;min-width:32px;height:32px;padding:0 var(--k-sp-2);font-size:.875rem;border-radius:var(--k-r);cursor:pointer;border:1px solid var(--k-border);background:var(--k-bg);color:var(--k-text-2);text-decoration:none;transition:all var(--k-fast)}[data-pagination] [data-page]:hover{background:var(--k-surface-2);color:var(--k-text);border-color:var(--k-border-strong)}[data-pagination] [data-page][aria-current="page"]{background:var(--k-accent);color:var(--k-accent-fg);border-color:transparent}[data-pagination] [data-page][disabled]{opacity:.4;pointer-events:none}[data-layout]{display:flex;min-height:100vh}[data-sidebar]{width:var(--k-sidebar-w);flex-shrink:0;background:var(--k-surface);border-right:1px solid var(--k-border);display:flex;flex-direction:column;position:sticky;top:0;height:100vh;overflow-y:auto;transition:width var(--k-slow) var(--k-ease);}[data-sidebar][data-collapsed]{width:60px}[data-sidebar-header]{padding:var(--k-sp-5) var(--k-sp-4);border-bottom:1px solid var(--k-border);display:flex;align-items:center;gap:var(--k-sp-3)}[data-sidebar-nav]{padding:var(--k-sp-4) var(--k-sp-3);flex:1}[data-sidebar-label]{font-size:.7rem;font-weight:var(--k-fw-bold);text-transform:uppercase;letter-spacing:.08em;color:var(--k-text-3);padding:var(--k-sp-2) var(--k-sp-3);margin-bottom:var(--k-sp-1)}[data-sidebar-item]{display:flex;align-items:center;gap:var(--k-sp-3);padding:var(--k-sp-2) var(--k-sp-3);border-radius:var(--k-r);font-size:.875rem;color:var(--k-text-2);text-decoration:none;transition:all var(--k-fast);cursor:pointer;user-select:none}[data-sidebar-item]:hover{background:var(--k-surface-2);color:var(--k-text)}[data-sidebar-item][data-active]{background:var(--k-accent-subtle);color:var(--k-accent);font-weight:var(--k-fw-medium)}[data-content]{flex:1;min-width:0;overflow-x:hidden}kern-drawer{display:none}kern-drawer[open]{display:block}[data-drawer-backdrop]{position:fixed;inset:0;background:rgba(0,0,0,.5);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);z-index:calc(var(--k-z-modal) - 1);animation:k-fade-in var(--k-dur) var(--k-ease-out)}[data-drawer-panel]{position:fixed;top:0;right:0;height:100vh;width:380px;max-width:90vw;background:var(--k-bg);border-left:1px solid var(--k-border);box-shadow:var(--k-sh-xl);z-index:var(--k-z-modal);display:flex;flex-direction:column;animation:k-drawer-in var(--k-slow) var(--k-ease);overflow:hidden}[data-drawer-panel][data-side="left"]{right:auto;left:0;border-left:none;border-right:1px solid var(--k-border);animation-name:k-drawer-in-left}kern-drawer[data-size="sm"] [data-drawer-panel]{width:280px}kern-drawer[data-size="lg"] [data-drawer-panel]{width:520px}[data-drawer-header]{display:flex;align-items:center;justify-content:space-between;padding:var(--k-sp-5) var(--k-sp-6);border-bottom:1px solid var(--k-border);flex-shrink:0}[data-drawer-title]{font-weight:var(--k-fw-bold);font-size:1rem}[data-drawer-body]{flex:1;overflow-y:auto;padding:var(--k-sp-6)}[data-drawer-footer]{padding:var(--k-sp-4) var(--k-sp-6);border-top:1px solid var(--k-border);background:var(--k-surface);display:flex;gap:var(--k-sp-3);flex-shrink:0}[data-grid]{display:grid;gap:var(--k-sp-4);grid-template-columns:repeat(var(--k-cols,1),minmax(0,1fr))}[data-grid="2"]{--k-cols:2}[data-grid="3"]{--k-cols:3}[data-grid="4"]{--k-cols:4}[data-grid="5"]{--k-cols:5}[data-grid="auto"]{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}[data-grid][data-gap="xs"]{gap:var(--k-sp-1)}[data-grid][data-gap="sm"]{gap:var(--k-sp-2)}[data-grid][data-gap="md"]{gap:var(--k-sp-4)}[data-grid][data-gap="lg"]{gap:var(--k-sp-8)}[data-grid][data-gap="xl"]{gap:var(--k-sp-12)}@media(min-width:640px){[data-grid][data-sm="2"]{--k-cols:2}[data-grid][data-sm="3"]{--k-cols:3}}@media(min-width:1024px){[data-grid][data-lg="3"]{--k-cols:3}[data-grid][data-lg="4"]{--k-cols:4}}@media(max-width:639px){[data-grid="2"],[data-grid="3"],[data-grid="4"]{--k-cols:1}}[data-stack]{display:flex;flex-direction:column;gap:var(--k-sp-4)}[data-stack][data-gap="xs"]{gap:var(--k-sp-1)}[data-stack][data-gap="sm"]{gap:var(--k-sp-2)}[data-stack][data-gap="lg"]{gap:var(--k-sp-8)}[data-stack][data-gap="xl"]{gap:var(--k-sp-12)}[data-row]{display:flex;align-items:center;gap:var(--k-sp-4);flex-wrap:wrap}[data-row][data-gap="xs"]{gap:var(--k-sp-1)}[data-row][data-gap="sm"]{gap:var(--k-sp-2)}[data-row][data-gap="lg"]{gap:var(--k-sp-8)}[data-row][data-align="start"]{align-items:flex-start}[data-row][data-align="end"]{align-items:flex-end}[data-row][data-align="stretch"]{align-items:stretch}[data-row][data-justify="between"]{justify-content:space-between}[data-row][data-justify="end"]{justify-content:flex-end}[data-row][data-justify="center"]{justify-content:center}[data-row][data-nowrap]{flex-wrap:nowrap}[data-divider]{display:flex;align-items:center;gap:var(--k-sp-4);color:var(--k-text-3);font-size:.8rem;margin:var(--k-sp-6) 0}[data-divider]::before,[data-divider]::after{content:'';flex:1;height:1px;background:var(--k-border)}[data-divider][data-vertical]{flex-direction:column;height:100%;margin:0 var(--k-sp-4);width:auto}[data-divider][data-vertical]::before,[data-divider][data-vertical]::after{width:1px;height:auto;flex:1}[data-sr-only]{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}[data-truncate]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}[data-surface]{background:var(--k-surface)}[data-surface="2"]{background:var(--k-surface-2)}[data-rounded]{border-radius:var(--k-r)}[data-rounded="full"]{border-radius:var(--k-r-full)}[data-container]{width:100%;max-width:1200px;margin:0 auto;padding:0 var(--k-sp-6)}[data-container="sm"]{max-width:720px}[data-container="lg"]{max-width:1440px}[data-scroll]{overflow:auto}[data-scroll="x"]{overflow-y:hidden;overflow-x:auto}[data-scroll="y"]{overflow-x:hidden;overflow-y:auto}@keyframes k-spin{to{transform:rotate(360deg)}}@keyframes k-fade-in{from{opacity:0}to{opacity:1}}@keyframes k-dialog-in{from{opacity:0;transform:translateY(12px) scale(.97)}to{opacity:1;transform:none}}@keyframes k-toast-in{from{opacity:0;transform:translateX(16px)}to{opacity:1;transform:none}}@keyframes k-toast-out{from{opacity:1;transform:translateX(0);max-height:100px}to{opacity:0;transform:translateX(16px);max-height:0;padding:0;margin:0}}@keyframes k-drawer-in{from{transform:translateX(100%)}to{transform:none}}@keyframes k-drawer-in-left{from{transform:translateX(-100%)}to{transform:none}}@keyframes k-skeleton{0%{background-position:200% 0}100%{background-position:-200% 0}}@keyframes k-progress-stripe{from{background-position:0 0}to{background-position:28px 0}}@keyframes k-progress-indeterminate{0%{transform:translateX(-100%)}100%{transform:translateX(350%)}}@media(max-width:768px){[data-sidebar]{display:none}[data-sidebar][data-mobile-open]{display:flex;position:fixed;inset:0;z-index:var(--k-z-modal);width:280px}dialog{width:calc(100vw - 1rem)}[data-drawer-panel]{width:100%;max-width:100%}h1{font-size:1.875rem}h2{font-size:1.5rem}}
@@ -0,0 +1,17 @@
1
+ (function(window){"use strict"; function emit(el, name, detail = {}) { return el.dispatchEvent( new CustomEvent(name, { bubbles: true, cancelable: true, detail }) );
2
+ } function esc(str) { return String(str) .replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/"/g, '&quot;');
3
+ } function firstFocusable(el) { return el?.querySelector( 'button:not([disabled]),a[href],[tabindex]:not([tabindex="-1"]),input:not([disabled]),select:not([disabled]),textarea:not([disabled])' ) ?? null;
4
+ } const $ = (sel, ctx = document) => ctx.querySelector(sel); const $$ = (sel, ctx = document) => [...ctx.querySelectorAll(sel)]; function initAccordions(root = document) { root.querySelectorAll('[data-accordion-trigger]').forEach(trigger => { if (trigger._kernInit) return; trigger._kernInit = true; trigger.setAttribute('aria-expanded', 'false'); trigger.setAttribute('type', 'button'); const content = trigger .closest('[data-accordion-item]') ?.querySelector('[data-accordion-content]'); if (!content) return; trigger.addEventListener('click', () => { const isOpen = trigger.getAttribute('aria-expanded') === 'true'; const accordion = trigger.closest('[data-accordion]'); if (accordion && !accordion.hasAttribute('data-multi')) { accordion.querySelectorAll('[data-accordion-trigger]').forEach(other => { if (other === trigger) return; other.setAttribute('aria-expanded', 'false'); other .closest('[data-accordion-item]') ?.querySelector('[data-accordion-content]') ?.removeAttribute('data-open'); }); } trigger.setAttribute('aria-expanded', isOpen ? 'false' : 'true'); isOpen ? content.removeAttribute('data-open') : content.setAttribute('data-open', ''); }); });
5
+ } function initToggles(root = document) { root.querySelectorAll('[data-toggle]').forEach(el => { if (el._kernInit) return; el._kernInit = true; el.addEventListener('click', () => { const targetId = el.getAttribute('data-toggle'); const target = document.getElementById(targetId); if (!target) return; const wc = target.closest('kern-dialog, kern-drawer') || target; if (typeof wc.toggle === 'function') wc.toggle(); else if (typeof wc.open === 'function') wc.open(); }); });
6
+ } function initTableSort(root = document) { root.querySelectorAll('th[data-sort]').forEach(th => { if (th._kernInit) return; th._kernInit = true; th.style.cursor = 'pointer'; th.setAttribute('role', 'columnheader'); th.setAttribute('aria-sort', 'none'); th.addEventListener('click', () => { const table = th.closest('table'); const tbody = table?.querySelector('tbody'); if (!tbody) return; const colIndex = [...th.parentElement.children].indexOf(th); const current = th.getAttribute('data-sort'); const asc = current !== 'asc'; table.querySelectorAll('th[data-sort]').forEach(h => { h.setAttribute('data-sort', ''); h.setAttribute('aria-sort', 'none'); }); th.setAttribute('data-sort', asc ? 'asc' : 'desc'); th.setAttribute('aria-sort', asc ? 'ascending' : 'descending'); const rows = [...tbody.querySelectorAll('tr')]; rows.sort((a, b) => { const av = a.cells[colIndex]?.textContent.trim() ?? ''; const bv = b.cells[colIndex]?.textContent.trim() ?? ''; const an = parseFloat(av.replace(/[^0-9.-]/g, '')); const bn = parseFloat(bv.replace(/[^0-9.-]/g, '')); if (!isNaN(an) && !isNaN(bn)) return asc ? an - bn : bn - an; return asc ? av.localeCompare(bv) : bv.localeCompare(av); }); rows.forEach(row => tbody.appendChild(row)); }); });
7
+ } class KernTabs extends HTMLElement { connectedCallback() { this._init(); } _init() { const tabs = [...this.querySelectorAll('[data-tab]')]; const panels = [...this.querySelectorAll('[data-tab-panel]')]; const initialActive = Math.max(0, tabs.findIndex(t => t.hasAttribute('data-active'))); tabs.forEach((tab, i) => { tab.setAttribute('role', 'tab'); tab.setAttribute('tabindex', i === initialActive ? '0' : '-1'); tab.setAttribute('aria-selected', i === initialActive ? 'true' : 'false'); if (panels[i]) { const panelId = panels[i].id || `k-panel-${Math.random().toString(36).slice(2)}`; panels[i].id = panelId; tab.setAttribute('aria-controls', panelId); panels[i].setAttribute('role', 'tabpanel'); panels[i].setAttribute('aria-labelledby', tab.id || `k-tab-${i}`); } tab.addEventListener('click', () => this.goto(i)); tab.addEventListener('keydown', (e) => { const count = tabs.length; if (e.key === 'ArrowRight') { e.preventDefault(); this.goto((i + 1) % count); } if (e.key === 'ArrowLeft') { e.preventDefault(); this.goto((i - 1 + count) % count); } if (e.key === 'Home') { e.preventDefault(); this.goto(0); } if (e.key === 'End') { e.preventDefault(); this.goto(count - 1); } }); }); this._activate(initialActive, false); } goto(index) { this._activate(index, true); } setActive(index) { this._activate(index, false); } _activate(index, focus = false) { const tabs = [...this.querySelectorAll('[data-tab]')]; const panels = [...this.querySelectorAll('[data-tab-panel]')]; tabs.forEach((tab, i) => { const active = i === index; tab.setAttribute('aria-selected', active ? 'true' : 'false'); tab.setAttribute('tabindex', active ? '0' : '-1'); }); panels.forEach((panel, i) => { i === index ? panel.setAttribute('data-active', '') : panel.removeAttribute('data-active'); }); if (focus && tabs[index]) tabs[index].focus(); emit(this, 'kern:tab-change', { index }); }
8
+ } customElements.define('kern-tabs', KernTabs); class KernDropdown extends HTMLElement { connectedCallback() { this._trigger = this.querySelector('[data-dropdown-trigger]') || this.firstElementChild; this._content = this.querySelector('[data-dropdown-content]'); this._onOutside = (e) => { if (!this.contains(e.target)) this.close(); }; if (!this._trigger) return; this._trigger.setAttribute('aria-haspopup', 'true'); this._trigger.setAttribute('aria-expanded', 'false'); this._trigger.addEventListener('click', (e) => { e.stopPropagation(); this.hasAttribute('open') ? this.close() : this.open(); }); this._trigger.addEventListener('keydown', (e) => { if (e.key === 'ArrowDown') { e.preventDefault(); this.open(); this._focusFirst(); } if (e.key === 'Escape') this.close(); }); if (this._content) { const items = () => [...this._content.querySelectorAll('[data-dropdown-item]:not([disabled])')]; this._content.addEventListener('keydown', (e) => { const list = items(); const idx = list.indexOf(document.activeElement); if (e.key === 'ArrowDown') { e.preventDefault(); list[idx + 1]?.focus() ?? list[0]?.focus(); } if (e.key === 'ArrowUp') { e.preventDefault(); idx > 0 ? list[idx - 1]?.focus() : this._trigger.focus(); } if (e.key === 'Escape') { this.close(); this._trigger.focus(); } if (e.key === 'Tab') this.close(); }); items().forEach(item => { item.setAttribute('role', 'menuitem'); item.setAttribute('tabindex', '-1'); }); } } disconnectedCallback() { document.removeEventListener('click', this._onOutside); } open() { this.setAttribute('open', ''); this._trigger?.setAttribute('aria-expanded', 'true'); document.addEventListener('click', this._onOutside); emit(this, 'kern:dropdown-open'); } close() { this.removeAttribute('open'); this._trigger?.setAttribute('aria-expanded', 'false'); document.removeEventListener('click', this._onOutside); emit(this, 'kern:dropdown-close'); } toggle() { this.hasAttribute('open') ? this.close() : this.open(); } _focusFirst() { const first = this._content?.querySelector('[data-dropdown-item]:not([disabled])'); setTimeout(() => first?.focus(), 10); }
9
+ } customElements.define('kern-dropdown', KernDropdown); class KernDialog extends HTMLElement { connectedCallback() { this._dialog = this.querySelector('dialog'); if (!this._dialog) return; this._setup(); } _setup() { const d = this._dialog; this.querySelectorAll('[data-dialog-close]').forEach(btn => { btn.addEventListener('click', () => this.close()); }); d.addEventListener('click', (e) => { if (e.target === d && !d.hasAttribute('data-no-backdrop-close')) this.close(); }); d.addEventListener('cancel', (e) => { e.preventDefault(); this.close(); }); } open() { if (!this._dialog) return; this._dialog.showModal(); const f = firstFocusable(this._dialog); if (f) setTimeout(() => f.focus(), 40); emit(this, 'kern:dialog-open'); } close() { if (!this._dialog || !this._dialog.open) return; this._dialog.close(); emit(this, 'kern:dialog-close'); } toggle() { this._dialog?.open ? this.close() : this.open(); }
10
+ } customElements.define('kern-dialog', KernDialog); class KernDrawer extends HTMLElement { connectedCallback() { this._panel = this.querySelector('[data-drawer-panel]'); this._backdrop = this.querySelector('[data-drawer-backdrop]'); this._onKey = (e) => { if (e.key === 'Escape') this.close(); }; this.querySelectorAll('[data-drawer-close]').forEach(btn => { btn.addEventListener('click', () => this.close()); }); this._backdrop?.addEventListener('click', () => this.close()); } open() { this.setAttribute('open', ''); document.body.style.overflow = 'hidden'; document.addEventListener('keydown', this._onKey); const f = firstFocusable(this._panel); if (f) setTimeout(() => f.focus(), 60); emit(this, 'kern:drawer-open'); } close() { this.removeAttribute('open'); document.body.style.overflow = ''; document.removeEventListener('keydown', this._onKey); emit(this, 'kern:drawer-close'); } toggle() { this.hasAttribute('open') ? this.close() : this.open(); }
11
+ } customElements.define('kern-drawer', KernDrawer); class KernToaster extends HTMLElement { connectedCallback() { if (!this.hasAttribute('data-position')) { this.setAttribute('data-position', 'bottom-right'); } this.setAttribute('aria-live', 'polite'); this.setAttribute('aria-atomic', 'false'); } add(options = {}) { if (typeof options === 'string') options = { message: options }; const { title = '', message = '', color = '', duration = 4000, dismissible = true, } = options; const toast = document.createElement('div'); toast.setAttribute('data-toast', ''); toast.setAttribute('role', 'status'); if (color) toast.setAttribute('data-color', color); toast.innerHTML = ` <div data-toast-body> ${title ? `<div data-toast-title>${esc(title)}</div>` : ''} ${message ? `<div data-toast-message>${esc(message)}</div>` : ''} </div> ${dismissible ? `<button data-toast-close aria-label="Dismiss">✕</button>` : ''} `.trim(); toast.querySelector('[data-toast-close]')?.addEventListener('click', () => this._remove(toast)); this.appendChild(toast); emit(this, 'kern:toast-add', { toast, color, title, message }); if (duration > 0) setTimeout(() => this._remove(toast), duration); return toast; } _remove(toast) { if (!toast.isConnected) return; toast.setAttribute('data-removing', ''); toast.addEventListener('animationend', () => { toast.remove(); emit(this, 'kern:toast-remove', { toast }); }, { once: true }); } clear() { [...this.querySelectorAll('[data-toast]')].forEach(t => this._remove(t)); }
12
+ } customElements.define('kern-toaster', KernToaster); const Kern = { version: '1.0.0', toast(options = {}) { if (typeof options === 'string') options = { message: options }; const position = options.position ?? 'bottom-right'; let toaster = document.querySelector(`kern-toaster[data-position="${position}"]`) ?? document.querySelector('kern-toaster'); if (!toaster) { toaster = document.createElement('kern-toaster'); toaster.setAttribute('data-position', position); document.body.appendChild(toaster); } return toaster.add(options); }, dialog(selector) { const el = typeof selector === 'string' ? (document.getElementById(selector) ?? document.querySelector(selector)) : selector; const wc = el?.closest?.('kern-dialog') ?? el; if (typeof wc?.open === 'function') wc.open(); else if (el instanceof HTMLDialogElement) el.showModal(); return wc; }, drawer(selector) { const el = typeof selector === 'string' ? (document.getElementById(selector) ?? document.querySelector(selector)) : selector; const wc = el?.closest?.('kern-drawer') ?? el; if (typeof wc?.open === 'function') wc.open(); return wc; }, setAccent(name) { document.documentElement.setAttribute('data-accent', name); }, setTheme(theme) { document.documentElement.setAttribute('data-theme', theme); try { localStorage.setItem('kern-theme', theme); } catch (_) {} }, setRadius(name) { if (name === 'default') document.documentElement.removeAttribute('data-radius'); else document.documentElement.setAttribute('data-radius', name); }, init(root = document) { initAccordions(root); initToggles(root); initTableSort(root); },
13
+ }; function boot() { try { const saved = localStorage.getItem('kern-theme'); if (saved) document.documentElement.setAttribute('data-theme', saved); } catch (_) {} Kern.init(); new MutationObserver((mutations) => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { Kern.init(node); } }); }); }).observe(document.body, { childList: true, subtree: true });
14
+ } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', boot);
15
+ } else { boot();
16
+ } if(typeof window!=="undefined")window.Kern=Kern;
17
+ })(window);