@ngxsmk/theme 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,80 @@
1
+ import { DOCUMENT } from '@angular/common';
2
+ import { Injectable, computed, effect, inject, signal } from '@angular/core';
3
+ import { buildThemeCss } from './css';
4
+ import * as i0 from "@angular/core";
5
+ const STORAGE_KEY = 'ngxsmk-theme-mode';
6
+ const STYLE_ID = 'ngxsmk-theme';
7
+ /**
8
+ * Runtime theme control: dark-mode switching (class strategy) and dynamic
9
+ * theme application by injecting generated token CSS into the document.
10
+ *
11
+ * SSR-safe: all DOM access goes through the injected document and degrades
12
+ * gracefully when `window`/`matchMedia` are unavailable.
13
+ */
14
+ export class NgxsmkThemeService {
15
+ constructor() {
16
+ // Inject DOCUMENT first so that restoreMode() and matchSystemDark()
17
+ // can safely access it when the signals are initialised below.
18
+ this.document = inject(DOCUMENT);
19
+ this.mode = signal(this.restoreMode());
20
+ this.systemDark = signal(this.matchSystemDark());
21
+ this.isDark = computed(() => this.mode() === 'system' ? this.systemDark() : this.mode() === 'dark');
22
+ const media = this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)');
23
+ media?.addEventListener('change', (e) => this.systemDark.set(e.matches));
24
+ effect(() => {
25
+ this.document.documentElement.classList.toggle('dark', this.isDark());
26
+ });
27
+ }
28
+ setMode(mode) {
29
+ this.mode.set(mode);
30
+ try {
31
+ this.document.defaultView?.localStorage?.setItem(STORAGE_KEY, mode);
32
+ }
33
+ catch {
34
+ // Storage unavailable (SSR, privacy mode) — preference is session-only.
35
+ }
36
+ }
37
+ toggle() {
38
+ this.setMode(this.isDark() ? 'light' : 'dark');
39
+ }
40
+ /**
41
+ * Apply a theme at runtime. Generates token CSS from the config and swaps
42
+ * it into a dedicated `<style>` element, overriding the build-time theme.
43
+ */
44
+ applyTheme(config) {
45
+ const head = this.document.head;
46
+ let style = this.document.getElementById(STYLE_ID);
47
+ if (!style) {
48
+ style = this.document.createElement('style');
49
+ style.id = STYLE_ID;
50
+ head.appendChild(style);
51
+ }
52
+ style.textContent = buildThemeCss(config);
53
+ }
54
+ /** Remove a runtime-applied theme, falling back to the build-time CSS. */
55
+ clearTheme() {
56
+ this.document.getElementById(STYLE_ID)?.remove();
57
+ }
58
+ restoreMode() {
59
+ try {
60
+ const stored = this.document.defaultView?.localStorage?.getItem(STORAGE_KEY);
61
+ if (stored === 'light' || stored === 'dark' || stored === 'system') {
62
+ return stored;
63
+ }
64
+ }
65
+ catch {
66
+ // Fall through to default.
67
+ }
68
+ return 'system';
69
+ }
70
+ matchSystemDark() {
71
+ return this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
72
+ }
73
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: NgxsmkThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
74
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: NgxsmkThemeService, providedIn: 'root' }); }
75
+ }
76
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: NgxsmkThemeService, decorators: [{
77
+ type: Injectable,
78
+ args: [{ providedIn: 'root' }]
79
+ }], ctorParameters: () => [] });
80
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhlbWUuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL3RoZW1lL3NyYy9saWIvdGhlbWUuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDN0UsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLE9BQU8sQ0FBQzs7QUFLdEMsTUFBTSxXQUFXLEdBQUcsbUJBQW1CLENBQUM7QUFDeEMsTUFBTSxRQUFRLEdBQUcsY0FBYyxDQUFDO0FBRWhDOzs7Ozs7R0FNRztBQUVILE1BQU0sT0FBTyxrQkFBa0I7SUFXN0I7UUFDRSxvRUFBb0U7UUFDcEUsK0RBQStEO1FBQy9ELElBQUksQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRWpDLElBQUksQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFZLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELElBQUksQ0FBQyxVQUFVLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxNQUFNLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUMxQixJQUFJLENBQUMsSUFBSSxFQUFFLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsS0FBSyxNQUFNLENBQ3RFLENBQUM7UUFFRixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxVQUFVLEVBQUUsQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO1FBQ3RGLEtBQUssRUFBRSxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBRXpFLE1BQU0sQ0FBQyxHQUFHLEVBQUU7WUFDVixJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUN4RSxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxPQUFPLENBQUMsSUFBZTtRQUNyQixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwQixJQUFJLENBQUM7WUFDSCxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxZQUFZLEVBQUUsT0FBTyxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUN0RSxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1Asd0VBQXdFO1FBQzFFLENBQUM7SUFDSCxDQUFDO0lBRUQsTUFBTTtRQUNKLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFFRDs7O09BR0c7SUFDSCxVQUFVLENBQUMsTUFBbUI7UUFDNUIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7UUFDaEMsSUFBSSxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUE0QixDQUFDO1FBQzlFLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNYLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUM3QyxLQUFLLENBQUMsRUFBRSxHQUFHLFFBQVEsQ0FBQztZQUNwQixJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzFCLENBQUM7UUFDRCxLQUFLLENBQUMsV0FBVyxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBRUQsMEVBQTBFO0lBQzFFLFVBQVU7UUFDUixJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQztJQUNuRCxDQUFDO0lBRU8sV0FBVztRQUNqQixJQUFJLENBQUM7WUFDSCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxZQUFZLEVBQUUsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQzdFLElBQUksTUFBTSxLQUFLLE9BQU8sSUFBSSxNQUFNLEtBQUssTUFBTSxJQUFJLE1BQU0sS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDbkUsT0FBTyxNQUFNLENBQUM7WUFDaEIsQ0FBQztRQUNILENBQUM7UUFBQyxNQUFNLENBQUM7WUFDUCwyQkFBMkI7UUFDN0IsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFFTyxlQUFlO1FBQ3JCLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsVUFBVSxFQUFFLENBQUMsOEJBQThCLENBQUMsQ0FBQyxPQUFPLElBQUksS0FBSyxDQUFDO0lBQ2xHLENBQUM7OEdBN0VVLGtCQUFrQjtrSEFBbEIsa0JBQWtCLGNBREwsTUFBTTs7MkZBQ25CLGtCQUFrQjtrQkFEOUIsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBJbmplY3RhYmxlLCBjb21wdXRlZCwgZWZmZWN0LCBpbmplY3QsIHNpZ25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgYnVpbGRUaGVtZUNzcyB9IGZyb20gJy4vY3NzJztcbmltcG9ydCB7IFRoZW1lQ29uZmlnIH0gZnJvbSAnLi90eXBlcyc7XG5cbmV4cG9ydCB0eXBlIFRoZW1lTW9kZSA9ICdsaWdodCcgfCAnZGFyaycgfCAnc3lzdGVtJztcblxuY29uc3QgU1RPUkFHRV9LRVkgPSAnbmd4c21rLXRoZW1lLW1vZGUnO1xuY29uc3QgU1RZTEVfSUQgPSAnbmd4c21rLXRoZW1lJztcblxuLyoqXG4gKiBSdW50aW1lIHRoZW1lIGNvbnRyb2w6IGRhcmstbW9kZSBzd2l0Y2hpbmcgKGNsYXNzIHN0cmF0ZWd5KSBhbmQgZHluYW1pY1xuICogdGhlbWUgYXBwbGljYXRpb24gYnkgaW5qZWN0aW5nIGdlbmVyYXRlZCB0b2tlbiBDU1MgaW50byB0aGUgZG9jdW1lbnQuXG4gKlxuICogU1NSLXNhZmU6IGFsbCBET00gYWNjZXNzIGdvZXMgdGhyb3VnaCB0aGUgaW5qZWN0ZWQgZG9jdW1lbnQgYW5kIGRlZ3JhZGVzXG4gKiBncmFjZWZ1bGx5IHdoZW4gYHdpbmRvd2AvYG1hdGNoTWVkaWFgIGFyZSB1bmF2YWlsYWJsZS5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBOZ3hzbWtUaGVtZVNlcnZpY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IGRvY3VtZW50OiBEb2N1bWVudDtcblxuICAvKiogVXNlciBwcmVmZXJlbmNlOiBleHBsaWNpdCBsaWdodC9kYXJrIG9yIGZvbGxvdyB0aGUgT1MuICovXG4gIHJlYWRvbmx5IG1vZGU6IFJldHVyblR5cGU8dHlwZW9mIHNpZ25hbDxUaGVtZU1vZGU+PjtcblxuICBwcml2YXRlIHJlYWRvbmx5IHN5c3RlbURhcms6IFJldHVyblR5cGU8dHlwZW9mIHNpZ25hbDxib29sZWFuPj47XG5cbiAgLyoqIEVmZmVjdGl2ZSBkYXJrbmVzcyBhZnRlciByZXNvbHZpbmcgYHN5c3RlbWAgYWdhaW5zdCB0aGUgT1Mgc2V0dGluZy4gKi9cbiAgcmVhZG9ubHkgaXNEYXJrOiBSZXR1cm5UeXBlPHR5cGVvZiBjb21wdXRlZDxib29sZWFuPj47XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gSW5qZWN0IERPQ1VNRU5UIGZpcnN0IHNvIHRoYXQgcmVzdG9yZU1vZGUoKSBhbmQgbWF0Y2hTeXN0ZW1EYXJrKClcbiAgICAvLyBjYW4gc2FmZWx5IGFjY2VzcyBpdCB3aGVuIHRoZSBzaWduYWxzIGFyZSBpbml0aWFsaXNlZCBiZWxvdy5cbiAgICB0aGlzLmRvY3VtZW50ID0gaW5qZWN0KERPQ1VNRU5UKTtcblxuICAgIHRoaXMubW9kZSA9IHNpZ25hbDxUaGVtZU1vZGU+KHRoaXMucmVzdG9yZU1vZGUoKSk7XG4gICAgdGhpcy5zeXN0ZW1EYXJrID0gc2lnbmFsKHRoaXMubWF0Y2hTeXN0ZW1EYXJrKCkpO1xuICAgIHRoaXMuaXNEYXJrID0gY29tcHV0ZWQoKCkgPT5cbiAgICAgIHRoaXMubW9kZSgpID09PSAnc3lzdGVtJyA/IHRoaXMuc3lzdGVtRGFyaygpIDogdGhpcy5tb2RlKCkgPT09ICdkYXJrJyxcbiAgICApO1xuXG4gICAgY29uc3QgbWVkaWEgPSB0aGlzLmRvY3VtZW50LmRlZmF1bHRWaWV3Py5tYXRjaE1lZGlhPy4oJyhwcmVmZXJzLWNvbG9yLXNjaGVtZTogZGFyayknKTtcbiAgICBtZWRpYT8uYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgKGUpID0+IHRoaXMuc3lzdGVtRGFyay5zZXQoZS5tYXRjaGVzKSk7XG5cbiAgICBlZmZlY3QoKCkgPT4ge1xuICAgICAgdGhpcy5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LnRvZ2dsZSgnZGFyaycsIHRoaXMuaXNEYXJrKCkpO1xuICAgIH0pO1xuICB9XG5cbiAgc2V0TW9kZShtb2RlOiBUaGVtZU1vZGUpOiB2b2lkIHtcbiAgICB0aGlzLm1vZGUuc2V0KG1vZGUpO1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmRvY3VtZW50LmRlZmF1bHRWaWV3Py5sb2NhbFN0b3JhZ2U/LnNldEl0ZW0oU1RPUkFHRV9LRVksIG1vZGUpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gU3RvcmFnZSB1bmF2YWlsYWJsZSAoU1NSLCBwcml2YWN5IG1vZGUpIOKAlCBwcmVmZXJlbmNlIGlzIHNlc3Npb24tb25seS5cbiAgICB9XG4gIH1cblxuICB0b2dnbGUoKTogdm9pZCB7XG4gICAgdGhpcy5zZXRNb2RlKHRoaXMuaXNEYXJrKCkgPyAnbGlnaHQnIDogJ2RhcmsnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBcHBseSBhIHRoZW1lIGF0IHJ1bnRpbWUuIEdlbmVyYXRlcyB0b2tlbiBDU1MgZnJvbSB0aGUgY29uZmlnIGFuZCBzd2Fwc1xuICAgKiBpdCBpbnRvIGEgZGVkaWNhdGVkIGA8c3R5bGU+YCBlbGVtZW50LCBvdmVycmlkaW5nIHRoZSBidWlsZC10aW1lIHRoZW1lLlxuICAgKi9cbiAgYXBwbHlUaGVtZShjb25maWc6IFRoZW1lQ29uZmlnKTogdm9pZCB7XG4gICAgY29uc3QgaGVhZCA9IHRoaXMuZG9jdW1lbnQuaGVhZDtcbiAgICBsZXQgc3R5bGUgPSB0aGlzLmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFNUWUxFX0lEKSBhcyBIVE1MU3R5bGVFbGVtZW50IHwgbnVsbDtcbiAgICBpZiAoIXN0eWxlKSB7XG4gICAgICBzdHlsZSA9IHRoaXMuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3R5bGUnKTtcbiAgICAgIHN0eWxlLmlkID0gU1RZTEVfSUQ7XG4gICAgICBoZWFkLmFwcGVuZENoaWxkKHN0eWxlKTtcbiAgICB9XG4gICAgc3R5bGUudGV4dENvbnRlbnQgPSBidWlsZFRoZW1lQ3NzKGNvbmZpZyk7XG4gIH1cblxuICAvKiogUmVtb3ZlIGEgcnVudGltZS1hcHBsaWVkIHRoZW1lLCBmYWxsaW5nIGJhY2sgdG8gdGhlIGJ1aWxkLXRpbWUgQ1NTLiAqL1xuICBjbGVhclRoZW1lKCk6IHZvaWQge1xuICAgIHRoaXMuZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoU1RZTEVfSUQpPy5yZW1vdmUoKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzdG9yZU1vZGUoKTogVGhlbWVNb2RlIHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc3RvcmVkID0gdGhpcy5kb2N1bWVudC5kZWZhdWx0Vmlldz8ubG9jYWxTdG9yYWdlPy5nZXRJdGVtKFNUT1JBR0VfS0VZKTtcbiAgICAgIGlmIChzdG9yZWQgPT09ICdsaWdodCcgfHwgc3RvcmVkID09PSAnZGFyaycgfHwgc3RvcmVkID09PSAnc3lzdGVtJykge1xuICAgICAgICByZXR1cm4gc3RvcmVkO1xuICAgICAgfVxuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gRmFsbCB0aHJvdWdoIHRvIGRlZmF1bHQuXG4gICAgfVxuICAgIHJldHVybiAnc3lzdGVtJztcbiAgfVxuXG4gIHByaXZhdGUgbWF0Y2hTeXN0ZW1EYXJrKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmRvY3VtZW50LmRlZmF1bHRWaWV3Py5tYXRjaE1lZGlhPy4oJyhwcmVmZXJzLWNvbG9yLXNjaGVtZTogZGFyayknKS5tYXRjaGVzID8/IGZhbHNlO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Cool blue-grey neutral scale matching the Astryx (Meta) design language.
3
+ * Light steps carry a subtle blue tint; the darkest steps flatten toward
4
+ * a near-neutral charcoal so dark-mode surfaces read like Astryx's
5
+ * (#111112 body / #1F1F22 card) rather than a saturated navy.
6
+ */
7
+ export const DEFAULT_NEUTRAL = {
8
+ 50: '#F1F4F7',
9
+ 100: '#E4E9EE',
10
+ 200: '#CCD3DB',
11
+ 300: '#A4B0BC',
12
+ 400: '#778593',
13
+ 500: '#4E606F',
14
+ 600: '#3A4650',
15
+ 700: '#2A333B',
16
+ 800: '#1F1F22',
17
+ 900: '#18181A',
18
+ 950: '#111112',
19
+ };
20
+ export const DEFAULT_SEMANTIC = {
21
+ success: '#0D8626',
22
+ warning: '#E9AF08',
23
+ error: '#E3193B',
24
+ info: '#0064E0',
25
+ };
26
+ export const DEFAULT_FONT_FAMILY = {
27
+ sans: "'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif",
28
+ mono: "'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace",
29
+ };
30
+ export const DEFAULT_TYPOGRAPHY = {
31
+ display: {
32
+ large: { size: '3.5625rem', lineHeight: '4rem', weight: '700' },
33
+ medium: { size: '2.8125rem', lineHeight: '3.25rem', weight: '700' },
34
+ small: { size: '2.25rem', lineHeight: '2.75rem', weight: '700' },
35
+ },
36
+ headline: {
37
+ large: { size: '2rem', lineHeight: '2.5rem', weight: '600' },
38
+ medium: { size: '1.75rem', lineHeight: '2.25rem', weight: '600' },
39
+ small: { size: '1.5rem', lineHeight: '2rem', weight: '600' },
40
+ },
41
+ title: {
42
+ large: { size: '1.375rem', lineHeight: '1.75rem', weight: '600' },
43
+ medium: { size: '1.125rem', lineHeight: '1.5rem', weight: '600' },
44
+ small: { size: '1rem', lineHeight: '1.5rem', weight: '600' },
45
+ },
46
+ body: {
47
+ large: { size: '1rem', lineHeight: '1.5rem', weight: '400' },
48
+ medium: { size: '0.875rem', lineHeight: '1.25rem', weight: '400' },
49
+ small: { size: '0.75rem', lineHeight: '1rem', weight: '400' },
50
+ },
51
+ label: {
52
+ large: { size: '0.875rem', lineHeight: '1.25rem', weight: '500' },
53
+ medium: { size: '0.75rem', lineHeight: '1rem', weight: '500' },
54
+ small: { size: '0.6875rem', lineHeight: '1rem', weight: '500' },
55
+ },
56
+ };
57
+ /**
58
+ * Standard height for single-line text controls (input, select, number-input,
59
+ * combobox, input-group, power-search, multi-select). All controls in the
60
+ * family use this so they read as one consistent size.
61
+ */
62
+ export const CONTROL_HEIGHT = '2.5rem';
63
+ export const SPACING = {
64
+ '0': '0px',
65
+ '0-5': '0.125rem',
66
+ '1': '0.25rem',
67
+ '1-5': '0.375rem',
68
+ '2': '0.5rem',
69
+ '3': '0.75rem',
70
+ '4': '1rem',
71
+ '5': '1.25rem',
72
+ '6': '1.5rem',
73
+ '8': '2rem',
74
+ '10': '2.5rem',
75
+ '12': '3rem',
76
+ '16': '4rem',
77
+ '20': '5rem',
78
+ '24': '6rem',
79
+ '32': '8rem',
80
+ };
81
+ /**
82
+ * Astryx radius scale: inner 4px, element 8px (buttons/inputs, the base),
83
+ * container 12px (cards), then progressively larger through 28px "page"
84
+ * rounding. Deliberately generous — Astryx reads soft and rounded.
85
+ */
86
+ export const RADIUS = {
87
+ none: '0px',
88
+ sm: '0.25rem', // 4px — inner (nested chips, checkboxes)
89
+ md: '0.5rem', // 8px — element (buttons, inputs) — default base
90
+ lg: '0.75rem', // 12px — container (cards, popovers)
91
+ xl: '1rem', // 16px
92
+ '2xl': '1.25rem', // 20px
93
+ '3xl': '1.75rem', // 28px — page / hero surfaces
94
+ full: '9999px',
95
+ };
96
+ /**
97
+ * Soft, diffuse, layered shadows in the Astryx style (two stacked blurs,
98
+ * low alpha). Overlay CSS resolves these to slightly stronger values in
99
+ * dark mode via the elevation tokens on each surface.
100
+ */
101
+ export const SHADOW = {
102
+ sm: '0 1px 1px rgb(0 0 0 / 0.08), 0 2px 8px rgb(0 0 0 / 0.08)',
103
+ md: '0 1px 2px rgb(0 0 0 / 0.1), 0 2px 12px rgb(0 0 0 / 0.1)',
104
+ lg: '0 2px 2px rgb(0 0 0 / 0.1), 0 8px 24px rgb(0 0 0 / 0.12)',
105
+ xl: '0 4px 6px rgb(0 0 0 / 0.1), 0 12px 32px rgb(0 0 0 / 0.16)',
106
+ '2xl': '0 8px 12px rgb(0 0 0 / 0.14), 0 24px 48px rgb(0 0 0 / 0.22)',
107
+ };
108
+ /**
109
+ * Stacking ladder for overlay components. Anchored popups sit lowest;
110
+ * tooltips always win. Components must use these instead of ad-hoc values
111
+ * so overlays never fight each other.
112
+ */
113
+ export const Z_INDEX = {
114
+ dropdown: '1000',
115
+ sticky: '1100',
116
+ banner: '1200',
117
+ overlay: '1300',
118
+ modal: '1400',
119
+ popover: '1500',
120
+ toast: '1600',
121
+ tooltip: '1700',
122
+ };
123
+ export const DURATION = {
124
+ instant: '0ms',
125
+ fast: '100ms',
126
+ normal: '200ms',
127
+ slow: '300ms',
128
+ slower: '500ms',
129
+ };
130
+ export const EASING = {
131
+ linear: 'linear',
132
+ in: 'cubic-bezier(0.4, 0, 1, 1)',
133
+ out: 'cubic-bezier(0, 0, 0.2, 1)',
134
+ 'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
135
+ emphasized: 'cubic-bezier(0.2, 0, 0, 1)',
136
+ };
137
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvdGhlbWUvc3JjL2xpYi90b2tlbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUE7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQWU7SUFDekMsRUFBRSxFQUFFLFNBQVM7SUFDYixHQUFHLEVBQUUsU0FBUztJQUNkLEdBQUcsRUFBRSxTQUFTO0lBQ2QsR0FBRyxFQUFFLFNBQVM7SUFDZCxHQUFHLEVBQUUsU0FBUztJQUNkLEdBQUcsRUFBRSxTQUFTO0lBQ2QsR0FBRyxFQUFFLFNBQVM7SUFDZCxHQUFHLEVBQUUsU0FBUztJQUNkLEdBQUcsRUFBRSxTQUFTO0lBQ2QsR0FBRyxFQUFFLFNBQVM7SUFDZCxHQUFHLEVBQUUsU0FBUztDQUNmLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBbUI7SUFDOUMsT0FBTyxFQUFFLFNBQVM7SUFDbEIsT0FBTyxFQUFFLFNBQVM7SUFDbEIsS0FBSyxFQUFFLFNBQVM7SUFDaEIsSUFBSSxFQUFFLFNBQVM7Q0FDaEIsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFpQjtJQUMvQyxJQUFJLEVBQUUsMkRBQTJEO0lBQ2pFLElBQUksRUFBRSwyREFBMkQ7Q0FDbEUsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFvQjtJQUNqRCxPQUFPLEVBQUU7UUFDUCxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtRQUMvRCxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtRQUNuRSxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtLQUNqRTtJQUNELFFBQVEsRUFBRTtRQUNSLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO1FBQzVELE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO1FBQ2pFLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO0tBQzdEO0lBQ0QsS0FBSyxFQUFFO1FBQ0wsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUU7UUFDakUsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUU7UUFDakUsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUU7S0FDN0Q7SUFDRCxJQUFJLEVBQUU7UUFDSixLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtRQUM1RCxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtRQUNsRSxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtLQUM5RDtJQUNELEtBQUssRUFBRTtRQUNMLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO1FBQ2pFLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO1FBQzlELEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO0tBQ2hFO0NBQ0YsQ0FBQztBQUVGOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDO0FBRXZDLE1BQU0sQ0FBQyxNQUFNLE9BQU8sR0FBMkI7SUFDN0MsR0FBRyxFQUFFLEtBQUs7SUFDVixLQUFLLEVBQUUsVUFBVTtJQUNqQixHQUFHLEVBQUUsU0FBUztJQUNkLEtBQUssRUFBRSxVQUFVO0lBQ2pCLEdBQUcsRUFBRSxRQUFRO0lBQ2IsR0FBRyxFQUFFLFNBQVM7SUFDZCxHQUFHLEVBQUUsTUFBTTtJQUNYLEdBQUcsRUFBRSxTQUFTO0lBQ2QsR0FBRyxFQUFFLFFBQVE7SUFDYixHQUFHLEVBQUUsTUFBTTtJQUNYLElBQUksRUFBRSxRQUFRO0lBQ2QsSUFBSSxFQUFFLE1BQU07SUFDWixJQUFJLEVBQUUsTUFBTTtJQUNaLElBQUksRUFBRSxNQUFNO0lBQ1osSUFBSSxFQUFFLE1BQU07SUFDWixJQUFJLEVBQUUsTUFBTTtDQUNiLENBQUM7QUFFRjs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUEyQjtJQUM1QyxJQUFJLEVBQUUsS0FBSztJQUNYLEVBQUUsRUFBRSxTQUFTLEVBQUUsMENBQTBDO0lBQ3pELEVBQUUsRUFBRSxRQUFRLEVBQUUsa0RBQWtEO0lBQ2hFLEVBQUUsRUFBRSxTQUFTLEVBQUUscUNBQXFDO0lBQ3BELEVBQUUsRUFBRSxNQUFNLEVBQUUsT0FBTztJQUNuQixLQUFLLEVBQUUsU0FBUyxFQUFFLE9BQU87SUFDekIsS0FBSyxFQUFFLFNBQVMsRUFBRSw4QkFBOEI7SUFDaEQsSUFBSSxFQUFFLFFBQVE7Q0FDZixDQUFDO0FBRUY7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLE1BQU0sR0FBMkI7SUFDNUMsRUFBRSxFQUFFLDBEQUEwRDtJQUM5RCxFQUFFLEVBQUUseURBQXlEO0lBQzdELEVBQUUsRUFBRSwwREFBMEQ7SUFDOUQsRUFBRSxFQUFFLDJEQUEyRDtJQUMvRCxLQUFLLEVBQUUsNkRBQTZEO0NBQ3JFLENBQUM7QUFFRjs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUEyQjtJQUM3QyxRQUFRLEVBQUUsTUFBTTtJQUNoQixNQUFNLEVBQUUsTUFBTTtJQUNkLE1BQU0sRUFBRSxNQUFNO0lBQ2QsT0FBTyxFQUFFLE1BQU07SUFDZixLQUFLLEVBQUUsTUFBTTtJQUNiLE9BQU8sRUFBRSxNQUFNO0lBQ2YsS0FBSyxFQUFFLE1BQU07SUFDYixPQUFPLEVBQUUsTUFBTTtDQUNoQixDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sUUFBUSxHQUEyQjtJQUM5QyxPQUFPLEVBQUUsS0FBSztJQUNkLElBQUksRUFBRSxPQUFPO0lBQ2IsTUFBTSxFQUFFLE9BQU87SUFDZixJQUFJLEVBQUUsT0FBTztJQUNiLE1BQU0sRUFBRSxPQUFPO0NBQ2hCLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxNQUFNLEdBQTJCO0lBQzVDLE1BQU0sRUFBRSxRQUFRO0lBQ2hCLEVBQUUsRUFBRSw0QkFBNEI7SUFDaEMsR0FBRyxFQUFFLDRCQUE0QjtJQUNqQyxRQUFRLEVBQUUsOEJBQThCO0lBQ3hDLFVBQVUsRUFBRSw0QkFBNEI7Q0FDekMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbG9yU2NhbGUsIEZvbnRGYW1pbGllcywgU2VtYW50aWNDb2xvcnMsIFR5cG9ncmFwaHlTY2FsZSB9IGZyb20gJy4vdHlwZXMnO1xuXG4vKipcbiAqIENvb2wgYmx1ZS1ncmV5IG5ldXRyYWwgc2NhbGUgbWF0Y2hpbmcgdGhlIEFzdHJ5eCAoTWV0YSkgZGVzaWduIGxhbmd1YWdlLlxuICogTGlnaHQgc3RlcHMgY2FycnkgYSBzdWJ0bGUgYmx1ZSB0aW50OyB0aGUgZGFya2VzdCBzdGVwcyBmbGF0dGVuIHRvd2FyZFxuICogYSBuZWFyLW5ldXRyYWwgY2hhcmNvYWwgc28gZGFyay1tb2RlIHN1cmZhY2VzIHJlYWQgbGlrZSBBc3RyeXgnc1xuICogKCMxMTExMTIgYm9keSAvICMxRjFGMjIgY2FyZCkgcmF0aGVyIHRoYW4gYSBzYXR1cmF0ZWQgbmF2eS5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfTkVVVFJBTDogQ29sb3JTY2FsZSA9IHtcbiAgNTA6ICcjRjFGNEY3JyxcbiAgMTAwOiAnI0U0RTlFRScsXG4gIDIwMDogJyNDQ0QzREInLFxuICAzMDA6ICcjQTRCMEJDJyxcbiAgNDAwOiAnIzc3ODU5MycsXG4gIDUwMDogJyM0RTYwNkYnLFxuICA2MDA6ICcjM0E0NjUwJyxcbiAgNzAwOiAnIzJBMzMzQicsXG4gIDgwMDogJyMxRjFGMjInLFxuICA5MDA6ICcjMTgxODFBJyxcbiAgOTUwOiAnIzExMTExMicsXG59O1xuXG5leHBvcnQgY29uc3QgREVGQVVMVF9TRU1BTlRJQzogU2VtYW50aWNDb2xvcnMgPSB7XG4gIHN1Y2Nlc3M6ICcjMEQ4NjI2JyxcbiAgd2FybmluZzogJyNFOUFGMDgnLFxuICBlcnJvcjogJyNFMzE5M0InLFxuICBpbmZvOiAnIzAwNjRFMCcsXG59O1xuXG5leHBvcnQgY29uc3QgREVGQVVMVF9GT05UX0ZBTUlMWTogRm9udEZhbWlsaWVzID0ge1xuICBzYW5zOiBcIidJbnRlcicsIHN5c3RlbS11aSwgLWFwcGxlLXN5c3RlbSwgJ1NlZ29lIFVJJywgc2Fucy1zZXJpZlwiLFxuICBtb25vOiBcIidKZXRCcmFpbnMgTW9ubycsICdGaXJhIENvZGUnLCAnQ2FzY2FkaWEgQ29kZScsIG1vbm9zcGFjZVwiLFxufTtcblxuZXhwb3J0IGNvbnN0IERFRkFVTFRfVFlQT0dSQVBIWTogVHlwb2dyYXBoeVNjYWxlID0ge1xuICBkaXNwbGF5OiB7XG4gICAgbGFyZ2U6IHsgc2l6ZTogJzMuNTYyNXJlbScsIGxpbmVIZWlnaHQ6ICc0cmVtJywgd2VpZ2h0OiAnNzAwJyB9LFxuICAgIG1lZGl1bTogeyBzaXplOiAnMi44MTI1cmVtJywgbGluZUhlaWdodDogJzMuMjVyZW0nLCB3ZWlnaHQ6ICc3MDAnIH0sXG4gICAgc21hbGw6IHsgc2l6ZTogJzIuMjVyZW0nLCBsaW5lSGVpZ2h0OiAnMi43NXJlbScsIHdlaWdodDogJzcwMCcgfSxcbiAgfSxcbiAgaGVhZGxpbmU6IHtcbiAgICBsYXJnZTogeyBzaXplOiAnMnJlbScsIGxpbmVIZWlnaHQ6ICcyLjVyZW0nLCB3ZWlnaHQ6ICc2MDAnIH0sXG4gICAgbWVkaXVtOiB7IHNpemU6ICcxLjc1cmVtJywgbGluZUhlaWdodDogJzIuMjVyZW0nLCB3ZWlnaHQ6ICc2MDAnIH0sXG4gICAgc21hbGw6IHsgc2l6ZTogJzEuNXJlbScsIGxpbmVIZWlnaHQ6ICcycmVtJywgd2VpZ2h0OiAnNjAwJyB9LFxuICB9LFxuICB0aXRsZToge1xuICAgIGxhcmdlOiB7IHNpemU6ICcxLjM3NXJlbScsIGxpbmVIZWlnaHQ6ICcxLjc1cmVtJywgd2VpZ2h0OiAnNjAwJyB9LFxuICAgIG1lZGl1bTogeyBzaXplOiAnMS4xMjVyZW0nLCBsaW5lSGVpZ2h0OiAnMS41cmVtJywgd2VpZ2h0OiAnNjAwJyB9LFxuICAgIHNtYWxsOiB7IHNpemU6ICcxcmVtJywgbGluZUhlaWdodDogJzEuNXJlbScsIHdlaWdodDogJzYwMCcgfSxcbiAgfSxcbiAgYm9keToge1xuICAgIGxhcmdlOiB7IHNpemU6ICcxcmVtJywgbGluZUhlaWdodDogJzEuNXJlbScsIHdlaWdodDogJzQwMCcgfSxcbiAgICBtZWRpdW06IHsgc2l6ZTogJzAuODc1cmVtJywgbGluZUhlaWdodDogJzEuMjVyZW0nLCB3ZWlnaHQ6ICc0MDAnIH0sXG4gICAgc21hbGw6IHsgc2l6ZTogJzAuNzVyZW0nLCBsaW5lSGVpZ2h0OiAnMXJlbScsIHdlaWdodDogJzQwMCcgfSxcbiAgfSxcbiAgbGFiZWw6IHtcbiAgICBsYXJnZTogeyBzaXplOiAnMC44NzVyZW0nLCBsaW5lSGVpZ2h0OiAnMS4yNXJlbScsIHdlaWdodDogJzUwMCcgfSxcbiAgICBtZWRpdW06IHsgc2l6ZTogJzAuNzVyZW0nLCBsaW5lSGVpZ2h0OiAnMXJlbScsIHdlaWdodDogJzUwMCcgfSxcbiAgICBzbWFsbDogeyBzaXplOiAnMC42ODc1cmVtJywgbGluZUhlaWdodDogJzFyZW0nLCB3ZWlnaHQ6ICc1MDAnIH0sXG4gIH0sXG59O1xuXG4vKipcbiAqIFN0YW5kYXJkIGhlaWdodCBmb3Igc2luZ2xlLWxpbmUgdGV4dCBjb250cm9scyAoaW5wdXQsIHNlbGVjdCwgbnVtYmVyLWlucHV0LFxuICogY29tYm9ib3gsIGlucHV0LWdyb3VwLCBwb3dlci1zZWFyY2gsIG11bHRpLXNlbGVjdCkuIEFsbCBjb250cm9scyBpbiB0aGVcbiAqIGZhbWlseSB1c2UgdGhpcyBzbyB0aGV5IHJlYWQgYXMgb25lIGNvbnNpc3RlbnQgc2l6ZS5cbiAqL1xuZXhwb3J0IGNvbnN0IENPTlRST0xfSEVJR0hUID0gJzIuNXJlbSc7XG5cbmV4cG9ydCBjb25zdCBTUEFDSU5HOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAnMCc6ICcwcHgnLFxuICAnMC01JzogJzAuMTI1cmVtJyxcbiAgJzEnOiAnMC4yNXJlbScsXG4gICcxLTUnOiAnMC4zNzVyZW0nLFxuICAnMic6ICcwLjVyZW0nLFxuICAnMyc6ICcwLjc1cmVtJyxcbiAgJzQnOiAnMXJlbScsXG4gICc1JzogJzEuMjVyZW0nLFxuICAnNic6ICcxLjVyZW0nLFxuICAnOCc6ICcycmVtJyxcbiAgJzEwJzogJzIuNXJlbScsXG4gICcxMic6ICczcmVtJyxcbiAgJzE2JzogJzRyZW0nLFxuICAnMjAnOiAnNXJlbScsXG4gICcyNCc6ICc2cmVtJyxcbiAgJzMyJzogJzhyZW0nLFxufTtcblxuLyoqXG4gKiBBc3RyeXggcmFkaXVzIHNjYWxlOiBpbm5lciA0cHgsIGVsZW1lbnQgOHB4IChidXR0b25zL2lucHV0cywgdGhlIGJhc2UpLFxuICogY29udGFpbmVyIDEycHggKGNhcmRzKSwgdGhlbiBwcm9ncmVzc2l2ZWx5IGxhcmdlciB0aHJvdWdoIDI4cHggXCJwYWdlXCJcbiAqIHJvdW5kaW5nLiBEZWxpYmVyYXRlbHkgZ2VuZXJvdXMg4oCUIEFzdHJ5eCByZWFkcyBzb2Z0IGFuZCByb3VuZGVkLlxuICovXG5leHBvcnQgY29uc3QgUkFESVVTOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICBub25lOiAnMHB4JyxcbiAgc206ICcwLjI1cmVtJywgLy8gNHB4ICDigJQgaW5uZXIgKG5lc3RlZCBjaGlwcywgY2hlY2tib3hlcylcbiAgbWQ6ICcwLjVyZW0nLCAvLyA4cHggIOKAlCBlbGVtZW50IChidXR0b25zLCBpbnB1dHMpIOKAlCBkZWZhdWx0IGJhc2VcbiAgbGc6ICcwLjc1cmVtJywgLy8gMTJweCDigJQgY29udGFpbmVyIChjYXJkcywgcG9wb3ZlcnMpXG4gIHhsOiAnMXJlbScsIC8vIDE2cHhcbiAgJzJ4bCc6ICcxLjI1cmVtJywgLy8gMjBweFxuICAnM3hsJzogJzEuNzVyZW0nLCAvLyAyOHB4IOKAlCBwYWdlIC8gaGVybyBzdXJmYWNlc1xuICBmdWxsOiAnOTk5OXB4Jyxcbn07XG5cbi8qKlxuICogU29mdCwgZGlmZnVzZSwgbGF5ZXJlZCBzaGFkb3dzIGluIHRoZSBBc3RyeXggc3R5bGUgKHR3byBzdGFja2VkIGJsdXJzLFxuICogbG93IGFscGhhKS4gT3ZlcmxheSBDU1MgcmVzb2x2ZXMgdGhlc2UgdG8gc2xpZ2h0bHkgc3Ryb25nZXIgdmFsdWVzIGluXG4gKiBkYXJrIG1vZGUgdmlhIHRoZSBlbGV2YXRpb24gdG9rZW5zIG9uIGVhY2ggc3VyZmFjZS5cbiAqL1xuZXhwb3J0IGNvbnN0IFNIQURPVzogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgc206ICcwIDFweCAxcHggcmdiKDAgMCAwIC8gMC4wOCksIDAgMnB4IDhweCByZ2IoMCAwIDAgLyAwLjA4KScsXG4gIG1kOiAnMCAxcHggMnB4IHJnYigwIDAgMCAvIDAuMSksIDAgMnB4IDEycHggcmdiKDAgMCAwIC8gMC4xKScsXG4gIGxnOiAnMCAycHggMnB4IHJnYigwIDAgMCAvIDAuMSksIDAgOHB4IDI0cHggcmdiKDAgMCAwIC8gMC4xMiknLFxuICB4bDogJzAgNHB4IDZweCByZ2IoMCAwIDAgLyAwLjEpLCAwIDEycHggMzJweCByZ2IoMCAwIDAgLyAwLjE2KScsXG4gICcyeGwnOiAnMCA4cHggMTJweCByZ2IoMCAwIDAgLyAwLjE0KSwgMCAyNHB4IDQ4cHggcmdiKDAgMCAwIC8gMC4yMiknLFxufTtcblxuLyoqXG4gKiBTdGFja2luZyBsYWRkZXIgZm9yIG92ZXJsYXkgY29tcG9uZW50cy4gQW5jaG9yZWQgcG9wdXBzIHNpdCBsb3dlc3Q7XG4gKiB0b29sdGlwcyBhbHdheXMgd2luLiBDb21wb25lbnRzIG11c3QgdXNlIHRoZXNlIGluc3RlYWQgb2YgYWQtaG9jIHZhbHVlc1xuICogc28gb3ZlcmxheXMgbmV2ZXIgZmlnaHQgZWFjaCBvdGhlci5cbiAqL1xuZXhwb3J0IGNvbnN0IFpfSU5ERVg6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gIGRyb3Bkb3duOiAnMTAwMCcsXG4gIHN0aWNreTogJzExMDAnLFxuICBiYW5uZXI6ICcxMjAwJyxcbiAgb3ZlcmxheTogJzEzMDAnLFxuICBtb2RhbDogJzE0MDAnLFxuICBwb3BvdmVyOiAnMTUwMCcsXG4gIHRvYXN0OiAnMTYwMCcsXG4gIHRvb2x0aXA6ICcxNzAwJyxcbn07XG5cbmV4cG9ydCBjb25zdCBEVVJBVElPTjogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgaW5zdGFudDogJzBtcycsXG4gIGZhc3Q6ICcxMDBtcycsXG4gIG5vcm1hbDogJzIwMG1zJyxcbiAgc2xvdzogJzMwMG1zJyxcbiAgc2xvd2VyOiAnNTAwbXMnLFxufTtcblxuZXhwb3J0IGNvbnN0IEVBU0lORzogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgbGluZWFyOiAnbGluZWFyJyxcbiAgaW46ICdjdWJpYy1iZXppZXIoMC40LCAwLCAxLCAxKScsXG4gIG91dDogJ2N1YmljLWJlemllcigwLCAwLCAwLjIsIDEpJyxcbiAgJ2luLW91dCc6ICdjdWJpYy1iZXppZXIoMC40LCAwLCAwLjIsIDEpJyxcbiAgZW1waGFzaXplZDogJ2N1YmljLWJlemllcigwLjIsIDAsIDAsIDEpJyxcbn07XG4iXX0=
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Design token model for the NGXSMK universal theme engine.
3
+ *
4
+ * A `ThemeConfig` is the single source of truth for a theme. The token
5
+ * engine transforms it into platform outputs (CSS custom properties today;
6
+ * SCSS/Tailwind/JSON exporters build on the same model).
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy90aGVtZS9zcmMvbGliL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRGVzaWduIHRva2VuIG1vZGVsIGZvciB0aGUgTkdYU01LIHVuaXZlcnNhbCB0aGVtZSBlbmdpbmUuXG4gKlxuICogQSBgVGhlbWVDb25maWdgIGlzIHRoZSBzaW5nbGUgc291cmNlIG9mIHRydXRoIGZvciBhIHRoZW1lLiBUaGUgdG9rZW5cbiAqIGVuZ2luZSB0cmFuc2Zvcm1zIGl0IGludG8gcGxhdGZvcm0gb3V0cHV0cyAoQ1NTIGN1c3RvbSBwcm9wZXJ0aWVzIHRvZGF5O1xuICogU0NTUy9UYWlsd2luZC9KU09OIGV4cG9ydGVycyBidWlsZCBvbiB0aGUgc2FtZSBtb2RlbCkuXG4gKi9cblxuLyoqIEFuIDExLXN0ZXAgY29sb3Igc2NhbGUsIDUwIChsaWdodGVzdCkgdG8gOTUwIChkYXJrZXN0KS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29sb3JTY2FsZSB7XG4gIDUwOiBzdHJpbmc7XG4gIDEwMDogc3RyaW5nO1xuICAyMDA6IHN0cmluZztcbiAgMzAwOiBzdHJpbmc7XG4gIDQwMDogc3RyaW5nO1xuICA1MDA6IHN0cmluZztcbiAgNjAwOiBzdHJpbmc7XG4gIDcwMDogc3RyaW5nO1xuICA4MDA6IHN0cmluZztcbiAgOTAwOiBzdHJpbmc7XG4gIDk1MDogc3RyaW5nO1xufVxuXG5leHBvcnQgdHlwZSBDb2xvclNjYWxlU3RlcCA9IGtleW9mIENvbG9yU2NhbGU7XG5cbi8qKiBTdGF0dXMgY29sb3JzIHVzZWQgYnkgYWxlcnRzLCBiYWRnZXMsIGZvcm0gdmFsaWRhdGlvbiwgdG9hc3RzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZW1hbnRpY0NvbG9ycyB7XG4gIHN1Y2Nlc3M6IHN0cmluZztcbiAgd2FybmluZzogc3RyaW5nO1xuICBlcnJvcjogc3RyaW5nO1xuICBpbmZvOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRm9udEZhbWlsaWVzIHtcbiAgc2Fuczogc3RyaW5nO1xuICBtb25vOiBzdHJpbmc7XG59XG5cbi8qKiBBIHNpbmdsZSB0eXBvZ3JhcGhpYyByb2xlIChzaXplICsgbGluZSBoZWlnaHQgKyB3ZWlnaHQpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBUeXBlU3R5bGUge1xuICBzaXplOiBzdHJpbmc7XG4gIGxpbmVIZWlnaHQ6IHN0cmluZztcbiAgd2VpZ2h0OiBzdHJpbmc7XG59XG5cbmV4cG9ydCB0eXBlIFR5cGVSb2xlU2l6ZSA9ICdsYXJnZScgfCAnbWVkaXVtJyB8ICdzbWFsbCc7XG5cbi8qKiBNYXRlcmlhbC1pbnNwaXJlZCB0eXBlIHJvbGVzOiBkaXNwbGF5LCBoZWFkbGluZSwgdGl0bGUsIGJvZHksIGxhYmVsLiAqL1xuZXhwb3J0IGludGVyZmFjZSBUeXBvZ3JhcGh5U2NhbGUge1xuICBkaXNwbGF5OiBSZWNvcmQ8VHlwZVJvbGVTaXplLCBUeXBlU3R5bGU+O1xuICBoZWFkbGluZTogUmVjb3JkPFR5cGVSb2xlU2l6ZSwgVHlwZVN0eWxlPjtcbiAgdGl0bGU6IFJlY29yZDxUeXBlUm9sZVNpemUsIFR5cGVTdHlsZT47XG4gIGJvZHk6IFJlY29yZDxUeXBlUm9sZVNpemUsIFR5cGVTdHlsZT47XG4gIGxhYmVsOiBSZWNvcmQ8VHlwZVJvbGVTaXplLCBUeXBlU3R5bGU+O1xufVxuXG5leHBvcnQgdHlwZSBEYXJrTW9kZVN0cmF0ZWd5ID0gJ2NsYXNzJyB8ICdtZWRpYScgfCAnc3lzdGVtJztcblxuZXhwb3J0IHR5cGUgUmFkaXVzUHJlc2V0ID0gJ25vbmUnIHwgJ3NtJyB8ICdtZCcgfCAnbGcnIHwgJ3hsJztcblxuLyoqIFVzZXItZmFjaW5nIHRoZW1lIGNvbmZpZ3VyYXRpb24uIEV2ZXJ5dGhpbmcgZXhjZXB0IGBicmFuZGAgaXMgb3B0aW9uYWwuICovXG5leHBvcnQgaW50ZXJmYWNlIFRoZW1lQ29uZmlnIHtcbiAgLyoqIElkZW50aWZpZXIgdXNlZCB3aGVuIHJlZ2lzdGVyaW5nIG11bHRpcGxlIHRoZW1lcy4gKi9cbiAgbmFtZT86IHN0cmluZztcbiAgYnJhbmQ6IHtcbiAgICAvKiogQnJhbmQgY29sb3IgYXMgaGV4IChlLmcuIGAjN0MzQUVEYCkuIEEgZnVsbCA1MOKAkzk1MCBzY2FsZSBpcyBkZXJpdmVkLiAqL1xuICAgIHByaW1hcnk6IHN0cmluZztcbiAgICAvKiogT3B0aW9uYWwgcHJlLWJ1aWx0IHNjYWxlOyBvdmVycmlkZXMgZGVyaXZhdGlvbiBmcm9tIGBwcmltYXJ5YC4gKi9cbiAgICBwcmltYXJ5U2NhbGU/OiBDb2xvclNjYWxlO1xuICAgIC8qKiBTZWNvbmRhcnkgYnJhbmQgY29sb3IgYXMgaGV4LiBBIGZ1bGwgNTDigJM5NTAgc2NhbGUgaXMgZGVyaXZlZC4gKi9cbiAgICBzZWNvbmRhcnk/OiBzdHJpbmc7XG4gICAgLyoqIE9wdGlvbmFsIHByZS1idWlsdCBzZWNvbmRhcnkgc2NhbGUuICovXG4gICAgc2Vjb25kYXJ5U2NhbGU/OiBDb2xvclNjYWxlO1xuICB9O1xuICAvKiogTmV1dHJhbCAoZ3JheSkgc2NhbGUuIERlZmF1bHRzIHRvIGEgYmFsYW5jZWQgemluYy1saWtlIHNjYWxlLiAqL1xuICBuZXV0cmFsPzogQ29sb3JTY2FsZTtcbiAgc2VtYW50aWM/OiBQYXJ0aWFsPFNlbWFudGljQ29sb3JzPjtcbiAgdHlwb2dyYXBoeT86IHtcbiAgICBmb250RmFtaWx5PzogUGFydGlhbDxGb250RmFtaWxpZXM+O1xuICB9O1xuICAvKiogR2xvYmFsIGNvcm5lciByb3VuZGluZyBjaGFyYWN0ZXIgb2YgdGhlIHRoZW1lLiBEZWZhdWx0IGBtZGAuICovXG4gIGJvcmRlclJhZGl1cz86IFJhZGl1c1ByZXNldDtcbiAgLyoqIEhvdyBkYXJrIG1vZGUgaXMgYWN0aXZhdGVkLiBEZWZhdWx0OiBgY2xhc3NgIChhIGAuZGFya2AgY2xhc3Mgb24gYDxodG1sPmApLiAqL1xuICBkYXJrTW9kZT86IHtcbiAgICBzdHJhdGVneT86IERhcmtNb2RlU3RyYXRlZ3k7XG4gICAgLyoqIENsYXNzIG5hbWUgdXNlZCBieSB0aGUgYGNsYXNzYCBzdHJhdGVneS4gRGVmYXVsdCBgZGFya2AuICovXG4gICAgY2xhc3NOYW1lPzogc3RyaW5nO1xuICB9O1xuICAvKipcbiAgICogUmF3IHNlbWFudGljLXJvbGUgdG9rZW4gb3ZlcnJpZGVzIG1lcmdlZCBpbnRvIHRoZSBnZW5lcmF0ZWQgb3V0cHV0LFxuICAgKiBlLmcuIGB7IGRhcms6IHsgJy0tbmd4c21rLWNvbG9yLXByaW1hcnknOiAnI0ZBRkFGQScgfSB9YC5cbiAgICovXG4gIG92ZXJyaWRlcz86IHtcbiAgICBsaWdodD86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gICAgZGFyaz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIH07XG59XG5cbi8qKiBBIGZ1bGx5IHJlc29sdmVkIHRoZW1lOiBjb25maWcgbWVyZ2VkIHdpdGggZGVmYXVsdHMsIHNjYWxlcyBkZXJpdmVkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZFRoZW1lIHtcbiAgbmFtZTogc3RyaW5nO1xuICAvKiogVGhlIGV4YWN0IGJyYW5kIGNvbG9yIGZyb20gdGhlIGNvbmZpZyDigJQgbGlnaHQtbW9kZSBwcmltYXJ5LiAqL1xuICBicmFuZEJhc2U6IHN0cmluZztcbiAgYnJhbmQ6IENvbG9yU2NhbGU7XG4gIHNlY29uZGFyeUJhc2U6IHN0cmluZztcbiAgc2Vjb25kYXJ5OiBDb2xvclNjYWxlO1xuICBuZXV0cmFsOiBDb2xvclNjYWxlO1xuICBzZW1hbnRpYzogU2VtYW50aWNDb2xvcnM7XG4gIGZvbnRGYW1pbHk6IEZvbnRGYW1pbGllcztcbiAgdHlwb2dyYXBoeTogVHlwb2dyYXBoeVNjYWxlO1xuICBzcGFjaW5nOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICByYWRpdXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIHJhZGl1c0Jhc2U6IFJhZGl1c1ByZXNldDtcbiAgc2hhZG93OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICBkdXJhdGlvbjogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgZWFzaW5nOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAvKiogU3RhY2tpbmcgbGF5ZXJzIGVtaXR0ZWQgYXMgYC0tbmd4c21rLXotKmA7IG92ZXJsYXlzIG11c3Qgc2hhcmUgdGhpcyBsYWRkZXIuICovXG4gIHpJbmRleDogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgZGFya01vZGU6IHsgc3RyYXRlZ3k6IERhcmtNb2RlU3RyYXRlZ3k7IGNsYXNzTmFtZTogc3RyaW5nIH07XG4gIG92ZXJyaWRlczoge1xuICAgIGxpZ2h0OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAgIGRhcms6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIH07XG59XG4iXX0=
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './public-api';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4c21rLXRoZW1lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcGFja2FnZXMvdGhlbWUvc3JjL25neHNtay10aGVtZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsY0FBYyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL3B1YmxpYy1hcGknO1xuIl19
@@ -0,0 +1,11 @@
1
+ /*
2
+ * Public API Surface of @ngxsmk/theme
3
+ */
4
+ export * from './lib/types';
5
+ export * from './lib/color';
6
+ export * from './lib/tokens';
7
+ export * from './lib/define-config';
8
+ export * from './lib/css';
9
+ export * from './lib/presets';
10
+ export * from './lib/theme.service';
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3BhY2thZ2VzL3RoZW1lL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLFdBQVcsQ0FBQztBQUMxQixjQUFjLGVBQWUsQ0FBQztBQUM5QixjQUFjLHFCQUFxQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIFB1YmxpYyBBUEkgU3VyZmFjZSBvZiBAbmd4c21rL3RoZW1lXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9saWIvdHlwZXMnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvY29sb3InO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdG9rZW5zJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2RlZmluZS1jb25maWcnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvY3NzJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3ByZXNldHMnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdGhlbWUuc2VydmljZSc7XG4iXX0=
@@ -120,10 +120,7 @@ function deriveScale(baseHex) {
120
120
  const scale = {};
121
121
  for (const [step, stop] of Object.entries(LIGHTNESS_STOPS)) {
122
122
  const key = Number(step);
123
- scale[key] =
124
- key === nearest
125
- ? hslToHex(base)
126
- : hslToHex({ h: base.h, s: base.s, l: stop });
123
+ scale[key] = key === nearest ? hslToHex(base) : hslToHex({ h: base.h, s: base.s, l: stop });
127
124
  }
128
125
  return scale;
129
126
  }
@@ -278,10 +275,13 @@ function defineConfig(config) {
278
275
  }
279
276
  /** Merge a user config with defaults and derive all color scales. */
280
277
  function resolveTheme(config) {
278
+ const secondaryBase = config.brand.secondary ?? rotateHue(config.brand.primary, 60);
281
279
  return {
282
280
  name: config.name ?? 'custom',
283
281
  brandBase: config.brand.primary,
284
282
  brand: config.brand.primaryScale ?? deriveScale(config.brand.primary),
283
+ secondaryBase,
284
+ secondary: config.brand.secondaryScale ?? deriveScale(secondaryBase),
285
285
  neutral: config.neutral ?? DEFAULT_NEUTRAL,
286
286
  semantic: { ...DEFAULT_SEMANTIC, ...config.semantic },
287
287
  fontFamily: { ...DEFAULT_FONT_FAMILY, ...config.typography?.fontFamily },
@@ -315,11 +315,15 @@ function scaleVars(prefix, scale) {
315
315
  function staticVars(theme) {
316
316
  const vars = {
317
317
  ...scaleVars('brand', theme.brand),
318
+ ...scaleVars('secondary', theme.secondary),
318
319
  ...scaleVars('neutral', theme.neutral),
319
320
  '--ngxsmk-font-sans': theme.fontFamily.sans,
320
321
  '--ngxsmk-font-mono': theme.fontFamily.mono,
321
322
  '--ngxsmk-radius-base': theme.radius[theme.radiusBase],
322
323
  '--ngxsmk-control-height': CONTROL_HEIGHT,
324
+ // Motion Tokens
325
+ '--ngxsmk-motion-duration': 'var(--ngxsmk-duration-normal)',
326
+ '--ngxsmk-motion-ease': 'var(--ngxsmk-ease-in-out)',
323
327
  // Component-specific Tokens (Buttons)
324
328
  '--ngxsmk-button-bg': 'var(--ngxsmk-color-primary)',
325
329
  '--ngxsmk-button-color': 'var(--ngxsmk-color-on-primary)',
@@ -394,6 +398,12 @@ function lightVars(theme) {
394
398
  '--ngxsmk-color-primary-active': shiftLightness(theme.brandBase, -14),
395
399
  '--ngxsmk-color-primary-container': theme.brand[100],
396
400
  '--ngxsmk-color-on-primary-container': theme.brand[900],
401
+ '--ngxsmk-color-secondary': theme.secondaryBase,
402
+ '--ngxsmk-color-on-secondary': '#FFFFFF',
403
+ '--ngxsmk-color-secondary-hover': shiftLightness(theme.secondaryBase, -8),
404
+ '--ngxsmk-color-secondary-active': shiftLightness(theme.secondaryBase, -14),
405
+ '--ngxsmk-color-secondary-container': theme.secondary[100],
406
+ '--ngxsmk-color-on-secondary-container': theme.secondary[900],
397
407
  // Astryx: cool-grey body, white cards floating on top, hairline borders.
398
408
  '--ngxsmk-color-background': theme.neutral[50],
399
409
  '--ngxsmk-color-on-background': '#0A1317',
@@ -407,6 +417,12 @@ function lightVars(theme) {
407
417
  '--ngxsmk-color-outline': 'rgb(5 54 89 / 0.1)',
408
418
  '--ngxsmk-color-outline-strong': theme.neutral[200],
409
419
  '--ngxsmk-color-outline-variant': 'rgb(5 54 89 / 0.06)',
420
+ // Elevation ladder
421
+ '--ngxsmk-color-surface-1': '#FFFFFF',
422
+ '--ngxsmk-color-surface-2': theme.neutral[50],
423
+ '--ngxsmk-color-surface-3': theme.neutral[100],
424
+ '--ngxsmk-color-surface-4': theme.neutral[200],
425
+ '--ngxsmk-color-surface-5': theme.neutral[300],
410
426
  '--ngxsmk-color-ring': theme.brandBase,
411
427
  '--ngxsmk-color-backdrop': 'rgb(1 18 40 / 0.4)',
412
428
  '--ngxsmk-shadow-focus': `0 0 0 2px ${theme.brand[100]}, 0 0 0 4px color-mix(in srgb, ${theme.brandBase} 45%, transparent)`,
@@ -435,6 +451,12 @@ function darkVars(theme) {
435
451
  '--ngxsmk-color-primary-active': theme.brand[200],
436
452
  '--ngxsmk-color-primary-container': theme.brand[900],
437
453
  '--ngxsmk-color-on-primary-container': theme.brand[100],
454
+ '--ngxsmk-color-secondary': theme.secondary[400],
455
+ '--ngxsmk-color-on-secondary': '#FFFFFF',
456
+ '--ngxsmk-color-secondary-hover': theme.secondary[300],
457
+ '--ngxsmk-color-secondary-active': theme.secondary[200],
458
+ '--ngxsmk-color-secondary-container': theme.secondary[900],
459
+ '--ngxsmk-color-on-secondary-container': theme.secondary[100],
438
460
  // Astryx dark: near-neutral charcoal body, slightly lighter card,
439
461
  // lighter still for popovers; hairline light-on-dark borders.
440
462
  '--ngxsmk-color-background': '#111112',
@@ -449,6 +471,12 @@ function darkVars(theme) {
449
471
  '--ngxsmk-color-outline': 'rgb(242 244 246 / 0.1)',
450
472
  '--ngxsmk-color-outline-strong': '#494D53',
451
473
  '--ngxsmk-color-outline-variant': 'rgb(242 244 246 / 0.06)',
474
+ // Elevation ladder
475
+ '--ngxsmk-color-surface-1': theme.neutral[800],
476
+ '--ngxsmk-color-surface-2': theme.neutral[700],
477
+ '--ngxsmk-color-surface-3': theme.neutral[600],
478
+ '--ngxsmk-color-surface-4': theme.neutral[500],
479
+ '--ngxsmk-color-surface-5': theme.neutral[400],
452
480
  '--ngxsmk-color-ring': theme.brand[400],
453
481
  '--ngxsmk-color-backdrop': 'rgb(17 17 18 / 0.6)',
454
482
  '--ngxsmk-shadow-focus': `0 0 0 2px color-mix(in srgb, ${theme.brand[400]} 25%, transparent), 0 0 0 4px color-mix(in srgb, ${theme.brand[400]} 45%, transparent)`,
@@ -507,7 +535,8 @@ function buildThemeCss(config) {
507
535
  darkBlock = block(`:root.${cn}, :root.${cn} body, .${cn}`, dark);
508
536
  }
509
537
  }
510
- return `/* Generated by @ngxsmk/theme — do not edit by hand. */\n${root}\n\n${darkBlock}\n`;
538
+ const reducedMotion = `@media (prefers-reduced-motion: reduce) {\n :root {\n --ngxsmk-motion-duration: 0ms;\n }\n}`;
539
+ return `/* Generated by @ngxsmk/theme — do not edit by hand. */\n${root}\n\n${darkBlock}\n\n${reducedMotion}\n`;
511
540
  }
512
541
 
513
542
  /**
@@ -596,16 +625,13 @@ const STYLE_ID = 'ngxsmk-theme';
596
625
  * gracefully when `window`/`matchMedia` are unavailable.
597
626
  */
598
627
  class NgxsmkThemeService {
599
- document = inject(DOCUMENT);
600
- /** User preference: explicit light/dark or follow the OS. */
601
- mode = signal(this.restoreMode(), /* @ts-ignore */
602
- ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
603
- systemDark = signal(this.matchSystemDark(), /* @ts-ignore */
604
- ...(ngDevMode ? [{ debugName: "systemDark" }] : /* istanbul ignore next */ []));
605
- /** Effective darkness after resolving `system` against the OS setting. */
606
- isDark = computed(() => this.mode() === 'system' ? this.systemDark() : this.mode() === 'dark', /* @ts-ignore */
607
- ...(ngDevMode ? [{ debugName: "isDark" }] : /* istanbul ignore next */ []));
608
628
  constructor() {
629
+ // Inject DOCUMENT first so that restoreMode() and matchSystemDark()
630
+ // can safely access it when the signals are initialised below.
631
+ this.document = inject(DOCUMENT);
632
+ this.mode = signal(this.restoreMode());
633
+ this.systemDark = signal(this.matchSystemDark());
634
+ this.isDark = computed(() => this.mode() === 'system' ? this.systemDark() : this.mode() === 'dark');
609
635
  const media = this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)');
610
636
  media?.addEventListener('change', (e) => this.systemDark.set(e.matches));
611
637
  effect(() => {
@@ -655,13 +681,12 @@ class NgxsmkThemeService {
655
681
  return 'system';
656
682
  }
657
683
  matchSystemDark() {
658
- return (this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)')
659
- .matches ?? false);
684
+ return this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
660
685
  }
661
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: NgxsmkThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
662
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: NgxsmkThemeService, providedIn: 'root' });
686
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: NgxsmkThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
687
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: NgxsmkThemeService, providedIn: 'root' }); }
663
688
  }
664
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: NgxsmkThemeService, decorators: [{
689
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.0", ngImport: i0, type: NgxsmkThemeService, decorators: [{
665
690
  type: Injectable,
666
691
  args: [{ providedIn: 'root' }]
667
692
  }], ctorParameters: () => [] });