@adukiorg/anza 0.2.9 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -17,6 +17,23 @@ Versioning follows [Semantic Versioning](https://semver.org/).
17
17
 
18
18
  ---
19
19
 
20
+ ## [0.3.1] — 2026-06-13
21
+
22
+ ### Changed
23
+
24
+ - Soften library README tone — remove sarcastic framework comparisons
25
+ - Update dock() example to use simplified API (no parent parameter)
26
+
27
+ ---
28
+
29
+ ## [0.3.0] — 2026-06-13
30
+
31
+ ### Fixed
32
+
33
+ - Sync `tools/Cargo.toml` version with npm package version (0.2.1 → 0.3.0)
34
+
35
+ ---
36
+
20
37
  ## [0.2.8] — 2026-06-09
21
38
 
22
39
  ### Fixed
package/README.md CHANGED
@@ -12,11 +12,11 @@
12
12
 
13
13
  **This is** a web platform library that treats the browser as the runtime. It gives you reactive state, client-side routing, custom elements, offline sync, and animations — all as plain ES modules the browser resolves directly. No bundler. No virtual DOM. No framework lock-in.
14
14
 
15
- **This is NOT** another React competitor. If you love JSX, useEffect cleanup races, and wondering why your bundle is 400KB, Anza is not for you. We are not trying to replace React. React is fine. React is great. React is for people who enjoy debugging `useMemo` dependency arrays at 2am. We are for people who want to write `.js` files and let the browser do what it was built to do.
15
+ **This is NOT** another React competitor. React is excellent for complex applications with rich ecosystems. Anza is for projects that prefer browser-native APIs and minimal tooling. We're not trying to replace React we're offering a different approach.
16
16
 
17
- **This is NOT** Angular. We do not have a CLI that generates fourteen files to render a button. We have `element('my-button', { template: '<button>Click me</button>' })`. That is the whole API.
17
+ **This is NOT** Angular. Angular provides a comprehensive framework with powerful tooling. Anza focuses on simplicity: `element('my-button', { template: '<button>Click me</button>' })`. That's the whole API.
18
18
 
19
- **This is NOT** Vue. We do not have a template compiler. We do not have a virtual DOM diffing algorithm that runs in JavaScript to figure out what the browser should have already figured out. We write HTML. The browser parses HTML. It has been doing this since 1993. It is pretty good at it.
19
+ **This is NOT** Vue. Vue's template compiler and virtual DOM enable great developer experiences. Anza uses native HTML parsing the browser handles the DOM directly, which works well for many use cases.
20
20
 
21
21
  ---
22
22
 
@@ -99,7 +99,7 @@ No build step. No JSX transform. No virtual DOM reconciliation. The browser pars
99
99
  ```javascript
100
100
  import { page, dock } from '@adukiorg/anza/defs';
101
101
 
102
- dock('main', { parent: 'body' });
102
+ dock('main');
103
103
 
104
104
  page('/', {
105
105
  tag: 'page-home',
@@ -124,7 +124,7 @@ store.subscribe('count', () => {
124
124
  store.set('count', 1);
125
125
  ```
126
126
 
127
- Proxy-based reactivity. Batched updates. Cross-tab sync via `BroadcastChannel`. No reducers. No actions. No sagas. Just a store that notifies subscribers when data changes. Revolutionary, we know.
127
+ Proxy-based reactivity. Batched updates. Cross-tab sync via `BroadcastChannel`. No reducers. No actions. No sagas. Just a store that notifies subscribers when data changes.
128
128
 
129
129
  ### Theme Switching (Automatic)
130
130
 
@@ -135,7 +135,7 @@ theme.toggle(); // light ↔ dark
135
135
  theme.set('contrast'); // high-contrast mode
136
136
  ```
137
137
 
138
- No init call needed. It auto-restores from `localStorage` on import. Respects `prefers-color-scheme` if no saved preference exists. Attaches to `window.theme` for devtools access. Because theme toggles are not rocket science.
138
+ No init call needed. It auto-restores from `localStorage` on import. Respects `prefers-color-scheme` if no saved preference exists. Attaches to `window.theme` for devtools access.
139
139
 
140
140
  ---
141
141
 
Binary file
Binary file
Binary file
Binary file
Binary file
package/bin/anza/index.js CHANGED
File without changes
File without changes
package/bin/create/run.js CHANGED
@@ -36,7 +36,9 @@ const HTML = (name) => `<!DOCTYPE html>
36
36
 
37
37
  <script type="module" src="/dist/app.js"></script>
38
38
  </head>
39
- <body></body>
39
+ <body>
40
+ <dock-main id="main"></dock-main>
41
+ </body>
40
42
  </html>
41
43
  `;
42
44
 
@@ -48,10 +50,10 @@ import { dock } from '@adukiorg/anza/ui';
48
50
  import '@adukiorg/anza/theme';
49
51
 
50
52
  // Service Worker
51
- navigator.serviceWorker.register('/dist/sw.js');
53
+ navigator.serviceWorker.register('/dist/sw.js', { type: 'module' });
52
54
 
53
55
  // Layout shell
54
- dock('main', { parent: 'body' });
56
+ dock('main');
55
57
 
56
58
  // Pages
57
59
  import './pages/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adukiorg/anza",
3
- "version": "0.2.9",
3
+ "version": "0.3.1",
4
4
  "description": "Anza web platform library — reactive state, networking, offline, animations, custom elements. Zero build step. Pure browser ESM.",
5
5
  "author": "fescii",
6
6
  "license": "MIT",
@@ -18,6 +18,24 @@ import { prefixes } from './prefixes/index.js';
18
18
  import { events } from './events/index.js';
19
19
  import { cache as apiCache } from './caches/index.js';
20
20
 
21
+ let cache = null;
22
+
23
+ export function sync() {
24
+ if (typeof document === 'undefined') return;
25
+ const el = document.getElementById('anza-state');
26
+ if (el) {
27
+ try {
28
+ cache = JSON.parse(el.textContent);
29
+ } catch (_) {
30
+ cache = null;
31
+ }
32
+ } else {
33
+ cache = null;
34
+ }
35
+ }
36
+
37
+ sync();
38
+
21
39
  // Register global telemetry inbound interceptor to emit requests status/errors events
22
40
  pipeline.inbound((responseOrError) => {
23
41
  const requestId = responseOrError?.requestId;
@@ -58,6 +76,11 @@ pipeline.inbound((responseOrError) => {
58
76
  */
59
77
  async function request(url, method, body, opts = {}) {
60
78
  const resolvedUrl = prefixes.resolve(url);
79
+
80
+ if (method === 'GET' && cache && resolvedUrl in cache) {
81
+ return JSON.parse(JSON.stringify(cache[resolvedUrl]));
82
+ }
83
+
61
84
  const headers = new Headers(opts.headers || {});
62
85
 
63
86
  // Auto-serialize JSON bodies
@@ -133,6 +156,8 @@ async function request(url, method, body, opts = {}) {
133
156
 
134
157
  export const api = {
135
158
  get: (url, opts) => request(url, 'GET', null, opts),
159
+ state: () => cache ? JSON.parse(JSON.stringify(cache.__route || {})) : null,
160
+ sync,
136
161
  post: (url, body, opts) => request(url, 'POST', body, opts),
137
162
  put: (url, body, opts) => request(url, 'PUT', body, opts),
138
163
  patch: (url, body, opts) => request(url, 'PATCH', body, opts),
@@ -153,6 +178,6 @@ export const api = {
153
178
  emit: (event, detail) => events.emit(event, detail)
154
179
  };
155
180
 
156
- export { pipeline, PlatformError, execute, retry, createNDJSONTransform, stream, upload, prefixes, events, apiCache as cache };
181
+ export { pipeline, PlatformError, execute, retry, createNDJSONTransform, stream, upload, prefixes, events, apiCache as cache, sync };
157
182
 
158
183
 
@@ -45,6 +45,7 @@ export function gate(promise) {
45
45
  * there is no body fallback.
46
46
  */
47
47
  function anchor() {
48
+ console.log('[Boot] anchor() started.');
48
49
  const el = document.getElementById('main');
49
50
  if (!el) {
50
51
  throw new Error(
@@ -63,10 +64,12 @@ function anchor() {
63
64
  * @param {() => any | Promise<any>} emitFn - runs the initial match + emit.
64
65
  */
65
66
  export function boot(emitFn) {
67
+ console.log('[Boot] boot() called. booted =', booted);
66
68
  if (booted) return;
67
69
  trigger = emitFn;
68
70
 
69
71
  const launch = async () => {
72
+ console.log('[Boot] launch() started. booted =', booted, 'gates count =', gates.size);
70
73
  if (booted) return;
71
74
 
72
75
  anchor(); // 1. wire main#main into the graph — must be first
@@ -74,19 +77,24 @@ export function boot(emitFn) {
74
77
  // Snapshot current gates; settle them all (failures are non-fatal — a
75
78
  // single element that fails to define must not wedge the whole router).
76
79
  const pending = Array.from(gates);
80
+ console.log('[Boot] pending gates:', pending);
77
81
  if (pending.length) {
78
82
  await Promise.allSettled(pending);
79
83
  }
84
+ console.log('[Boot] all gates settled!');
80
85
  booted = true;
81
86
  const fn = trigger;
82
87
  trigger = null;
83
- if (fn) await fn(); // 3. first match + emit
88
+ if (fn) {
89
+ console.log('[Boot] executing initial match trigger...');
90
+ await fn(); // 3. first match + emit
91
+ }
84
92
  };
85
93
 
86
94
  if (typeof document !== 'undefined' && document.readyState === 'loading') {
87
95
  document.addEventListener('DOMContentLoaded', () => { launch(); }, { once: true });
88
96
  } else {
89
- launch();
97
+ setTimeout(launch, 0);
90
98
  }
91
99
  }
92
100
 
@@ -56,7 +56,7 @@ export function container(tag, spec, base = import.meta.url) {
56
56
  // Strategy 1: Element-scoped transition (Chrome 147+, concurrent-safe)
57
57
  if (typeof this.startViewTransition === 'function') {
58
58
  try {
59
- const vt = this.startViewTransition({ callback: doSwap });
59
+ const vt = this.startViewTransition(doSwap);
60
60
  await vt.ready;
61
61
  } catch (err) {
62
62
  if (err?.name !== 'AbortError') console.warn('[UI Container] Scoped VT aborted:', err);
@@ -1,5 +1,5 @@
1
1
  import { BaseElement } from '../base.js';
2
- import { scheduleFrame } from '../schedule.js';
2
+ import { scheduleFrame, yieldTask } from '../schedule.js';
3
3
  import { router } from '../../router/index.js';
4
4
  import { specRegistry, internalsMap, initializedMap, pendingUpdatesMap, updateScheduledMap } from './state.js';
5
5
  import { preloadResources } from './utils.js';
@@ -84,7 +84,7 @@ export function element(tag, spec, base) {
84
84
  }
85
85
  }
86
86
  };
87
- window.addEventListener('native:hmr:css', hmrHandler);
87
+ window.addEventListener('anza:hmr:css', hmrHandler);
88
88
  }
89
89
  }
90
90
 
@@ -138,6 +138,13 @@ export function element(tag, spec, base) {
138
138
  return;
139
139
  }
140
140
 
141
+ if (typeof document !== 'undefined' && document.readyState === 'loading') {
142
+ await yieldTask();
143
+ if (!this.ctrl || this.ctrl.signal.aborted || !this.isConnected) {
144
+ return;
145
+ }
146
+ }
147
+
141
148
  if (templateNode && this.shadowRoot.childNodes.length === 0) {
142
149
  this.shadowRoot.appendChild(templateNode.cloneNode(true));
143
150
  }
@@ -11,6 +11,7 @@ export function initOrchestrator() {
11
11
  if (typeof window !== 'undefined') {
12
12
  dispose?.();
13
13
  dispose = router.on('found', async ({ tag, params, query, hash, chain, direction }) => {
14
+ console.log('[Orchestrator] FOUND event received for tag:', tag);
14
15
  // Resolve the top-level layout element in the chain
15
16
  const topTag = chain && chain.length > 0 ? chain[0].tag : tag;
16
17
  const topParams = chain && chain.length > 0 ? chain[0].params : params;
@@ -21,16 +22,22 @@ export function initOrchestrator() {
21
22
  }
22
23
 
23
24
  const spec = specRegistry.get(topTag.toLowerCase());
25
+ console.log('[Orchestrator] Resolved spec for tag', topTag, ':', spec);
24
26
  // Resolve the render target: the last container in the `via` chain, or
25
27
  // the legacy single `container`. Without either there is nothing to mount.
26
28
  const target = (Array.isArray(spec?.via) && spec.via.length)
27
29
  ? spec.via[spec.via.length - 1]
28
30
  : spec?.container;
29
- if (!spec || !target) return;
31
+ console.log('[Orchestrator] Target container name:', target);
32
+ if (!spec || !target) {
33
+ console.warn('[Orchestrator] Early return: missing spec or target');
34
+ return;
35
+ }
30
36
 
31
37
  // Use Advanced Container Registry lookup instead of blind DOM query.
32
38
  // The interceptor's cascade has already ensured the chain is mounted.
33
39
  const containerEl = router.getContainer(target);
40
+ console.log('[Orchestrator] containerEl found in registry:', containerEl);
34
41
  if (!containerEl) {
35
42
  console.warn(`Target container "${target}" not found in DOM for element <${topTag}>`);
36
43
  return;
@@ -10,9 +10,9 @@
10
10
  * Source: definations.md §4, tasks.md Phase 6
11
11
  */
12
12
 
13
- import { router } from '../../router/index.js';
14
- import { gate } from '../../router/boot.js';
15
13
  import { element } from '../define/element.js';
14
+ import { gate } from '../../router/boot.js';
15
+ import { router } from '../../router/index.js';
16
16
  import { translate } from './spec.js';
17
17
 
18
18
  // Element-scoped containment so View Transitions are isolated to the dock.
@@ -28,7 +28,7 @@ const CONTAIN = ':host { contain: layout; display: block; }';
28
28
  */
29
29
  export function dock(name, config = {}, base) {
30
30
  const tag = config.tag ?? `dock-${name}`;
31
- const parent = config.parent ?? 'body';
31
+ const parent = config.parent ?? 'main';
32
32
 
33
33
  const spec = translate(config);
34
34
 
@@ -106,7 +106,7 @@ async function swap(el, options = {}) {
106
106
 
107
107
  if (typeof this.startViewTransition === 'function') {
108
108
  try {
109
- this._tx = this.startViewTransition({ callback: go });
109
+ this._tx = this.startViewTransition(go);
110
110
  await this._tx.finished;
111
111
  } catch (err) {
112
112
  if (err?.name !== 'AbortError') console.warn('[Native UI] dock scoped VT aborted:', err);
@@ -67,7 +67,7 @@ ui.element('ui-input', {
67
67
  const input = tags.one('input');
68
68
  input.disabled = disabled;
69
69
  }
70
- };
70
+ }, import.meta.url);
71
71
 
72
72
  function syncAttributes(el, tags) {
73
73
  const input = tags.one('input');
@@ -100,4 +100,3 @@ function validate(el, internals, input) {
100
100
  internals.setValidity({});
101
101
  }
102
102
  }
103
- }, import.meta.url);
@@ -63,4 +63,19 @@
63
63
  outline: 2px solid var(--color-border-focus);
64
64
  outline-offset: 2px;
65
65
  }
66
+
67
+ /* Prevent layout shift of un-upgraded custom elements */
68
+ :not(:defined) {
69
+ display: block;
70
+ opacity: 0;
71
+ }
72
+
73
+ /* Full-page containers reserve viewport height */
74
+ [id="main"]:not(:defined),
75
+ main:not(:defined),
76
+ body > :not(:defined),
77
+ [class*="page"]:not(:defined),
78
+ [class*="dock"]:not(:defined) {
79
+ min-height: 100vh;
80
+ }
66
81
  }
@@ -1,54 +1,71 @@
1
1
  /**
2
2
  * tokens/primitives/colors.css
3
3
  *
4
- * Perceptually uniform brand, neutral, and status color scales using OKLCH.
5
- * Equal numerical differences correspond to equal visual differences.
6
- * Source: doc 26 §3
4
+ * Perceptually uniform color scales using OKLCH.
5
+ * Converted from hex values provided in the design system.
7
6
  */
8
7
 
9
8
  :root {
10
- /* Brand palette12-step perceptual scale in OKLCH */
11
- --color-brand-50: oklch(97% 0.05 250);
12
- --color-brand-100: oklch(92% 0.08 250);
13
- --color-brand-200: oklch(85% 0.12 250);
14
- --color-brand-300: oklch(76% 0.16 250);
15
- --color-brand-400: oklch(66% 0.20 250);
16
- --color-brand-500: oklch(55% 0.22 250);
17
- --color-brand-600: oklch(46% 0.20 250);
18
- --color-brand-700: oklch(38% 0.18 250);
19
- --color-brand-800: oklch(30% 0.14 250);
20
- --color-brand-900: oklch(22% 0.10 250);
21
- --color-brand-950: oklch(14% 0.06 250);
9
+ /* Gray scale11-step perceptual scale */
10
+ --gray-0: oklch(100% 0 0);
11
+ --gray-50: oklch(98% 0.002 264);
12
+ --gray-100: oklch(95% 0.004 264);
13
+ --gray-200: oklch(90% 0.006 264);
14
+ --gray-300: oklch(80% 0.008 264);
15
+ --gray-400: oklch(65% 0.01 264);
16
+ --gray-500: oklch(50% 0.012 264);
17
+ --gray-600: oklch(38% 0.014 264);
18
+ --gray-700: oklch(28% 0.016 264);
19
+ --gray-800: oklch(18% 0.018 264);
20
+ --gray-900: oklch(10% 0.02 264);
21
+ --gray-950: oklch(5% 0.022 264);
22
22
 
23
- /* Neutral palette */
24
- --color-neutral-0: oklch(100% 0 0);
25
- --color-neutral-50: oklch(97% 0 0);
26
- --color-neutral-100: oklch(94% 0 0);
27
- --color-neutral-200: oklch(88% 0 0);
28
- --color-neutral-300: oklch(78% 0 0);
29
- --color-neutral-400: oklch(64% 0 0);
30
- --color-neutral-500: oklch(50% 0 0);
31
- --color-neutral-600: oklch(38% 0 0);
32
- --color-neutral-700: oklch(27% 0 0);
33
- --color-neutral-800: oklch(18% 0 0);
34
- --color-neutral-900: oklch(10% 0 0);
35
- --color-neutral-950: oklch(6% 0 0);
36
- --color-neutral-1000: oklch(0% 0 0);
23
+ /* Brand green palette — based on #07a45f, #09d379 */
24
+ --brand-50: oklch(96% 0.08 155);
25
+ --brand-100: oklch(90% 0.12 155);
26
+ --brand-200: oklch(82% 0.16 155);
27
+ --brand-300: oklch(72% 0.18 155);
28
+ --brand-400: oklch(62% 0.20 155);
29
+ --brand-500: oklch(55% 0.22 155);
30
+ --brand-600: oklch(48% 0.20 155);
31
+ --brand-700: oklch(40% 0.18 155);
32
+ --brand-800: oklch(32% 0.16 155);
33
+ --brand-900: oklch(24% 0.14 155);
34
+ --brand-950: oklch(15% 0.12 155);
37
35
 
38
- /* Status palette */
39
- --color-success-50: oklch(97% 0.02 145);
40
- --color-success-500: oklch(63% 0.19 145);
41
- --color-success-600: oklch(53% 0.17 145);
42
-
43
- --color-warning-50: oklch(98% 0.02 65);
44
- --color-warning-500: oklch(75% 0.18 65);
45
- --color-warning-600: oklch(67% 0.16 65);
46
-
47
- --color-error-50: oklch(96% 0.02 25);
48
- --color-error-500: oklch(58% 0.22 25);
49
- --color-error-600: oklch(48% 0.20 25);
50
-
51
- --color-info-50: oklch(97% 0.02 230);
52
- --color-info-500: oklch(60% 0.18 230);
53
- --color-info-600: oklch(50% 0.16 230);
36
+ /* Success palette — based on #10b981 */
37
+ --success-50: oklch(96% 0.08 155);
38
+ --success-100: oklch(88% 0.12 155);
39
+ --success-200: oklch(78% 0.16 155);
40
+ --success-300: oklch(68% 0.18 155);
41
+ --success-400: oklch(58% 0.20 155);
42
+ --success-500: oklch(52% 0.22 155);
43
+ --success-600: oklch(45% 0.20 155);
44
+
45
+ /* Error palette — based on #ec4b19 */
46
+ --error-50: oklch(96% 0.06 35);
47
+ --error-100: oklch(90% 0.10 35);
48
+ --error-200: oklch(80% 0.14 35);
49
+ --error-300: oklch(70% 0.18 35);
50
+ --error-400: oklch(60% 0.22 35);
51
+ --error-500: oklch(54% 0.24 35);
52
+ --error-600: oklch(47% 0.22 35);
53
+
54
+ /* Warn palette — based on #fa6436 */
55
+ --warn-50: oklch(96% 0.08 45);
56
+ --warn-100: oklch(90% 0.12 45);
57
+ --warn-200: oklch(80% 0.16 45);
58
+ --warn-300: oklch(70% 0.20 45);
59
+ --warn-400: oklch(60% 0.24 45);
60
+ --warn-500: oklch(54% 0.26 45);
61
+ --warn-600: oklch(47% 0.24 45);
62
+
63
+ /* Info palette */
64
+ --info-50: oklch(96% 0.06 240);
65
+ --info-100: oklch(90% 0.10 240);
66
+ --info-200: oklch(80% 0.14 240);
67
+ --info-300: oklch(70% 0.18 240);
68
+ --info-400: oklch(60% 0.22 240);
69
+ --info-500: oklch(54% 0.24 240);
70
+ --info-600: oklch(47% 0.22 240);
54
71
  }
@@ -2,33 +2,25 @@
2
2
  * tokens/primitives/motion.css
3
3
  *
4
4
  * Durations and easing curves for transitions and animations.
5
- * Features central global prefers-reduced-motion token-layer overrides.
6
- * Source: doc 26 §4
7
5
  */
8
6
 
9
7
  :root {
10
8
  /* Durations */
11
- --duration-instant: 50ms;
12
9
  --duration-fast: 100ms;
13
10
  --duration-normal: 200ms;
14
11
  --duration-slow: 300ms;
15
- --duration-slower: 500ms;
16
12
 
17
13
  /* Easing curves */
18
- --ease-default: cubic-bezier(0.4, 0, 0.2, 1);
19
14
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
20
15
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
21
16
  --ease-in-out: cubic-bezier(0.4, 0, 0.6, 1);
22
- --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
23
17
  --ease-linear: linear;
24
18
  }
25
19
 
26
20
  @media (prefers-reduced-motion: reduce) {
27
21
  :root {
28
- --duration-instant: 0ms;
29
22
  --duration-fast: 0ms;
30
23
  --duration-normal: 0ms;
31
24
  --duration-slow: 0ms;
32
- --duration-slower: 0ms;
33
25
  }
34
26
  }
@@ -2,26 +2,18 @@
2
2
  * tokens/primitives/spacing.css
3
3
  *
4
4
  * Fixed spacing scale using rem units based on a 4px increment system.
5
- * Source: doc 26 §4
6
5
  */
7
6
 
8
7
  :root {
9
8
  --space-px: 1px;
10
9
  --space-0: 0px;
11
- --space-0-5: 0.125rem; /* 2px */
12
- --space-1: 0.25rem; /* 4px */
13
- --space-1-5: 0.375rem; /* 6px */
14
- --space-2: 0.5rem; /* 8px */
15
- --space-2-5: 0.625rem; /* 10px */
16
- --space-3: 0.75rem; /* 12px */
17
- --space-4: 1rem; /* 16px */
18
- --space-5: 1.25rem; /* 20px */
19
- --space-6: 1.5rem; /* 24px */
20
- --space-8: 2rem; /* 32px */
21
- --space-10: 2.5rem; /* 40px */
22
- --space-12: 3rem; /* 48px */
23
- --space-16: 4rem; /* 64px */
24
- --space-20: 5rem; /* 80px */
25
- --space-24: 6rem; /* 96px */
26
- --space-32: 8rem; /* 128px */
10
+ --space-xs: 0.25rem; /* 4px */
11
+ --space-sm: 0.5rem; /* 8px */
12
+ --space-md: 1rem; /* 16px */
13
+ --space-lg: 1.5rem; /* 24px */
14
+ --space-xl: 2rem; /* 32px */
15
+ --space-2xl: 3rem; /* 48px */
16
+ --space-3xl: 4rem; /* 64px */
17
+ --space-4xl: 6rem; /* 96px */
18
+ --space-5xl: 8rem; /* 128px */
27
19
  }
@@ -2,45 +2,48 @@
2
2
  * tokens/primitives/typography.css
3
3
  *
4
4
  * Typography scales, weights, line-heights, letter-spacings, and font stacks.
5
- * Source: doc 26 §4
5
+ * Google Fonts: Inter, JetBrains Mono, IBM Plex Sans
6
6
  */
7
7
 
8
+ @import url("https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap");
9
+ @import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap");
10
+ @import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,100..900;1,100..900&display=swap");
11
+
8
12
  :root {
9
13
  /* Modular type scale (1.25 ratio) */
10
- --font-size-xs: 0.75rem; /* 12px */
11
- --font-size-sm: 0.875rem; /* 14px */
12
- --font-size-base: 1rem; /* 16px */
13
- --font-size-md: 1.125rem; /* 18px */
14
- --font-size-lg: 1.25rem; /* 20px */
15
- --font-size-xl: 1.5rem; /* 24px */
16
- --font-size-2xl: 1.875rem; /* 30px */
17
- --font-size-3xl: 2.25rem; /* 36px */
18
- --font-size-4xl: 3rem; /* 48px */
19
- --font-size-5xl: 3.75rem; /* 60px */
14
+ --text-xs: 0.75rem; /* 12px */
15
+ --text-sm: 0.875rem; /* 14px */
16
+ --text-md: 1rem; /* 16px */
17
+ --text-lg: 1.25rem; /* 20px */
18
+ --text-xl: 1.5rem; /* 24px */
19
+ --text-2xl: 1.875rem; /* 30px */
20
+ --text-3xl: 2.25rem; /* 36px */
21
+ --text-4xl: 3rem; /* 48px */
22
+ --text-5xl: 3.75rem; /* 60px */
20
23
 
21
24
  /* Font weights */
22
- --font-weight-light: 300;
23
- --font-weight-regular: 400;
24
- --font-weight-medium: 500;
25
- --font-weight-semibold: 600;
26
- --font-weight-bold: 700;
25
+ --font-light: 300;
26
+ --font-normal: 400;
27
+ --font-medium: 500;
28
+ --font-semibold: 600;
29
+ --font-bold: 700;
27
30
 
28
31
  /* Line heights */
29
- --line-height-tight: 1.25;
30
- --line-height-snug: 1.375;
31
- --line-height-normal: 1.5;
32
- --line-height-relaxed: 1.625;
33
- --line-height-loose: 2;
32
+ --leading-tight: 1.25;
33
+ --leading-snug: 1.375;
34
+ --leading-normal: 1.5;
35
+ --leading-relaxed: 1.625;
36
+ --leading-loose: 2;
34
37
 
35
38
  /* Letter spacing */
36
- --letter-spacing-tight: -0.025em;
37
- --letter-spacing-normal: 0;
38
- --letter-spacing-wide: 0.025em;
39
- --letter-spacing-wider: 0.05em;
40
- --letter-spacing-widest: 0.1em;
39
+ --tracking-tight: -0.025em;
40
+ --tracking-normal: 0;
41
+ --tracking-wide: 0.025em;
42
+ --tracking-wider: 0.05em;
43
+ --tracking-widest: 0.1em;
41
44
 
42
45
  /* Font families */
43
- --font-family-sans: 'Outfit', 'Inter', system-ui, -apple-system, sans-serif;
44
- --font-family-serif: 'Georgia', 'Times New Roman', serif;
45
- --font-family-mono: 'JetBrains Mono', 'Fira Code', monospace;
46
+ --font-sans: 'Inter', system-ui, -apple-system, sans-serif;
47
+ --font-serif: 'IBM Plex Sans', serif;
48
+ --font-mono: 'JetBrains Mono', monospace;
46
49
  }
@@ -9,19 +9,19 @@
9
9
  @property --space-4 {
10
10
  syntax: '<length>';
11
11
  inherits: true;
12
- initial-value: 1rem;
12
+ initial-value: 16px;
13
13
  }
14
14
 
15
15
  @property --radius-md {
16
16
  syntax: '<length>';
17
17
  inherits: true;
18
- initial-value: 0.375rem;
18
+ initial-value: 6px;
19
19
  }
20
20
 
21
21
  @property --font-size-base {
22
22
  syntax: '<length>';
23
23
  inherits: true;
24
- initial-value: 1rem;
24
+ initial-value: 16px;
25
25
  }
26
26
 
27
27
  @property --duration-normal {
@@ -2,124 +2,122 @@
2
2
  * tokens/semantic/components.css
3
3
  *
4
4
  * Semantic component-level design tokens.
5
- * Consolidates recurring component-specific tokens from individual elements
6
- * into a shared semantic layer for consistency across the design system.
7
5
  */
8
6
 
9
7
  :root {
10
8
  /* Form Controls */
11
- --input-bg: var(--color-surface-page);
12
- --input-border: var(--color-border-default);
13
- --input-border-focus: var(--color-border-focus);
9
+ --input-bg: var(--background);
10
+ --input-border: var(--border);
11
+ --input-border-focus: var(--border-focus);
14
12
  --input-radius: var(--radius-md);
15
- --input-font-size: var(--font-size-base);
16
- --input-padding-y: var(--space-2);
17
- --input-padding-x: var(--space-3);
18
- --input-text-color: var(--color-content-primary);
19
-
20
- --textarea-bg: var(--color-surface-page);
21
- --textarea-border: var(--color-border-default);
22
- --textarea-border-focus: var(--color-border-focus);
13
+ --input-font-size: var(--text-md);
14
+ --input-padding-y: var(--space-sm);
15
+ --input-padding-x: var(--space-md);
16
+ --input-text-color: var(--foreground);
17
+
18
+ --textarea-bg: var(--background);
19
+ --textarea-border: var(--border);
20
+ --textarea-border-focus: var(--border-focus);
23
21
  --textarea-radius: var(--radius-md);
24
- --textarea-font-size: var(--font-size-base);
25
- --textarea-padding-y: var(--space-2);
26
- --textarea-padding-x: var(--space-3);
27
- --textarea-text-color: var(--color-content-primary);
28
-
29
- --check-bg: var(--color-surface-page);
30
- --check-bg-checked: var(--color-interactive);
31
- --check-border: var(--color-border-default);
32
- --check-border-focus: var(--color-border-focus);
22
+ --textarea-font-size: var(--text-md);
23
+ --textarea-padding-y: var(--space-sm);
24
+ --textarea-padding-x: var(--space-md);
25
+ --textarea-text-color: var(--foreground);
26
+
27
+ --check-bg: var(--background);
28
+ --check-bg-checked: var(--primary);
29
+ --check-border: var(--border);
30
+ --check-border-focus: var(--border-focus);
33
31
  --check-radius: var(--radius-sm);
34
- --check-size: var(--space-5);
35
- --check-color: var(--color-content-inverse);
32
+ --check-size: var(--space-lg);
33
+ --check-color: var(--primary-foreground);
36
34
 
37
- --radio-bg: var(--color-surface-page);
38
- --radio-bg-checked: var(--color-interactive);
39
- --radio-border: var(--color-border-default);
40
- --radio-border-focus: var(--color-border-focus);
35
+ --radio-bg: var(--background);
36
+ --radio-bg-checked: var(--primary);
37
+ --radio-border: var(--border);
38
+ --radio-border-focus: var(--border-focus);
41
39
  --radio-radius: var(--radius-full);
42
- --radio-size: var(--space-5);
43
- --radio-color: var(--color-content-inverse);
44
-
45
- --switch-bg: var(--color-border-strong);
46
- --switch-bg-on: var(--color-interactive);
47
- --switch-thumb-color: var(--color-content-inverse);
48
- --switch-width: var(--space-10);
49
- --switch-height: var(--space-6);
50
- --switch-thumb-size: calc(var(--switch-height) - var(--space-1));
51
-
52
- --select-bg: var(--color-surface-page);
53
- --select-border: var(--color-border-default);
54
- --select-border-focus: var(--color-border-focus);
40
+ --radio-size: var(--space-lg);
41
+ --radio-color: var(--primary-foreground);
42
+
43
+ --switch-bg: var(--border-strong);
44
+ --switch-bg-on: var(--primary);
45
+ --switch-thumb-color: var(--primary-foreground);
46
+ --switch-width: var(--space-xl);
47
+ --switch-height: var(--space-lg);
48
+ --switch-thumb-size: calc(var(--switch-height) - var(--space-xs));
49
+
50
+ --select-bg: var(--background);
51
+ --select-border: var(--border);
52
+ --select-border-focus: var(--border-focus);
55
53
  --select-radius: var(--radius-md);
56
- --select-font-size: var(--font-size-base);
57
- --select-padding-y: var(--space-2);
58
- --select-padding-x: var(--space-3);
59
- --select-text-color: var(--color-content-primary);
60
-
61
- --upload-bg: var(--color-surface-page);
62
- --upload-border: var(--color-border-default);
63
- --upload-border-focus: var(--color-border-focus);
54
+ --select-font-size: var(--text-md);
55
+ --select-padding-y: var(--space-sm);
56
+ --select-padding-x: var(--space-md);
57
+ --select-text-color: var(--foreground);
58
+
59
+ --upload-bg: var(--background);
60
+ --upload-border: var(--border);
61
+ --upload-border-focus: var(--border-focus);
64
62
  --upload-radius: var(--radius-lg);
65
- --upload-padding: var(--space-8);
66
- --upload-color: var(--color-content-secondary);
63
+ --upload-padding: var(--space-xl);
64
+ --upload-color: var(--foreground-muted);
67
65
 
68
66
  /* Feedback */
69
67
  --alert-radius: var(--radius-md);
70
- --alert-bg: var(--color-surface-elevated);
71
- --alert-color: var(--color-content-primary);
72
- --alert-border: var(--color-border-default);
68
+ --alert-bg: var(--background-elevated);
69
+ --alert-color: var(--foreground);
70
+ --alert-border: var(--border);
73
71
 
74
- --skeleton-bg: var(--color-interactive-disabled);
72
+ --skeleton-bg: var(--foreground-disabled);
75
73
  --skeleton-radius: var(--radius-md);
76
74
  --skeleton-width: 100%;
77
- --skeleton-height: var(--space-4);
75
+ --skeleton-height: var(--space-md);
78
76
 
79
77
  /* Data Display */
80
78
  --card-radius: var(--radius-lg);
81
79
 
82
- --stat-label: var(--font-size-xs);
83
- --stat-value: var(--font-size-3xl);
80
+ --stat-label: var(--text-xs);
81
+ --stat-value: var(--text-3xl);
84
82
 
85
83
  /* Navigation */
86
- --link-color: var(--color-content-link);
87
- --link-color-hover: var(--color-interactive-hover);
88
- --link-color-active: var(--color-interactive-active);
84
+ --link-color: var(--foreground-link);
85
+ --link-color-hover: var(--primary-hover);
86
+ --link-color-active: var(--primary-active);
89
87
 
90
88
  /* Layout */
91
- --stack-gap: var(--space-4);
89
+ --stack-gap: var(--space-md);
92
90
 
93
- --grid-gap: var(--space-4);
91
+ --grid-gap: var(--space-md);
94
92
  --grid-cols: repeat(auto-fit, minmax(250px, 1fr));
95
93
 
96
- --surface-bg: var(--color-surface-page);
94
+ --surface-bg: var(--background);
97
95
  --surface-border: transparent;
98
96
  --surface-shadow: none;
99
97
  --surface-radius: var(--radius-none);
100
98
 
101
99
  /* Overlay */
102
100
  --dialog-radius: var(--radius-lg);
103
- --dialog-shadow: var(--shadow-2xl);
101
+ --dialog-shadow: var(--shadow-xl);
104
102
 
105
- --popover-bg: var(--color-surface-elevated);
106
- --popover-border: var(--color-border-default);
107
- --popover-shadow: var(--shadow-xl);
103
+ --popover-bg: var(--background-elevated);
104
+ --popover-border: var(--border);
105
+ --popover-shadow: var(--shadow-lg);
108
106
  --popover-radius: var(--radius-md);
109
107
 
110
- --tooltip-bg: var(--color-surface-inverse);
111
- --tooltip-color: var(--color-content-inverse);
108
+ --tooltip-bg: var(--background-inverse);
109
+ --tooltip-color: var(--foreground-inverse);
112
110
  --tooltip-radius: var(--radius-sm);
113
111
 
114
- --menu-bg: var(--color-surface-elevated);
115
- --menu-border: var(--color-border-default);
112
+ --menu-bg: var(--background-elevated);
113
+ --menu-border: var(--border);
116
114
  --menu-shadow: var(--shadow-lg);
117
115
  --menu-radius: var(--radius-md);
118
116
 
119
- --drawer-shadow: var(--shadow-2xl);
120
- --drawer-width: min(calc(var(--space-32) * 3), 85vw);
117
+ --drawer-shadow: var(--shadow-xl);
118
+ --drawer-width: min(calc(var(--space-5xl) * 3), 85vw);
121
119
 
122
120
  --sheet-radius: var(--radius-lg);
123
- --sheet-shadow: var(--shadow-2xl);
124
- --sheet-max-width: min(calc(var(--space-32) * 6), 100vw);
121
+ --sheet-shadow: var(--shadow-xl);
122
+ --sheet-max-width: min(calc(var(--space-5xl) * 6), 100vw);
125
123
  }
@@ -2,60 +2,60 @@
2
2
  * tokens/semantic/dark.css
3
3
  *
4
4
  * Semantic design token overrides for the Dark theme.
5
- * Integrates with data-theme attribute and OS media preference (guarded to respect user selection).
6
- * Source: doc 26 §3
7
5
  */
8
6
 
9
7
  [data-theme="dark"] {
10
8
  /* Surfaces */
11
- --color-surface-page: var(--color-neutral-950);
12
- --color-surface-card: var(--color-neutral-900);
13
- --color-surface-elevated: var(--color-neutral-800);
14
- --color-surface-inverse: var(--color-neutral-50);
9
+ --background: var(--gray-950);
10
+ --background-elevated: var(--gray-900);
11
+ --background-inverse: var(--gray-50);
15
12
 
16
13
  /* Content (Text & Icons) */
17
- --color-content-primary: var(--color-neutral-5);
18
- --color-content-secondary: var(--color-neutral-400);
19
- --color-content-disabled: var(--color-neutral-600);
20
- --color-content-inverse: var(--color-neutral-900);
21
- --color-content-link: var(--color-brand-300);
14
+ --foreground: var(--gray-50);
15
+ --foreground-muted: var(--gray-400);
16
+ --foreground-disabled: var(--gray-600);
17
+ --foreground-inverse: var(--gray-900);
18
+ --foreground-link: var(--brand-300);
22
19
 
23
20
  /* Interactive Elements */
24
- --color-interactive: var(--color-brand-400);
25
- --color-interactive-hover: var(--color-brand-300);
26
- --color-interactive-active: var(--color-brand-200);
27
- --color-interactive-disabled: var(--color-neutral-700);
21
+ --primary: var(--brand-400);
22
+ --primary-hover: var(--brand-300);
23
+ --primary-active: var(--brand-200);
24
+ --primary-focus: var(--brand-400);
25
+ --primary-disabled: var(--gray-700);
26
+ --primary-foreground: var(--gray-0);
28
27
 
29
28
  /* Borders */
30
- --color-border-default: var(--color-neutral-800);
31
- --color-border-strong: var(--color-neutral-600);
32
- --color-border-focus: var(--color-brand-400);
29
+ --border: var(--gray-800);
30
+ --border-strong: var(--gray-600);
31
+ --border-focus: var(--brand-400);
33
32
  }
34
33
 
35
34
  @media (prefers-color-scheme: dark) {
36
35
  :root:not([data-theme="light"]) {
37
36
  /* Surfaces */
38
- --color-surface-page: var(--color-neutral-950);
39
- --color-surface-card: var(--color-neutral-900);
40
- --color-surface-elevated: var(--color-neutral-800);
41
- --color-surface-inverse: var(--color-neutral-50);
37
+ --background: var(--gray-950);
38
+ --background-elevated: var(--gray-900);
39
+ --background-inverse: var(--gray-50);
42
40
 
43
41
  /* Content (Text & Icons) */
44
- --color-content-primary: var(--color-neutral-5);
45
- --color-content-secondary: var(--color-neutral-400);
46
- --color-content-disabled: var(--color-neutral-600);
47
- --color-content-inverse: var(--color-neutral-900);
48
- --color-content-link: var(--color-brand-300);
42
+ --foreground: var(--gray-50);
43
+ --foreground-muted: var(--gray-400);
44
+ --foreground-disabled: var(--gray-600);
45
+ --foreground-inverse: var(--gray-900);
46
+ --foreground-link: var(--brand-300);
49
47
 
50
48
  /* Interactive Elements */
51
- --color-interactive: var(--color-brand-400);
52
- --color-interactive-hover: var(--color-brand-300);
53
- --color-interactive-active: var(--color-brand-200);
54
- --color-interactive-disabled: var(--color-neutral-700);
49
+ --primary: var(--brand-400);
50
+ --primary-hover: var(--brand-300);
51
+ --primary-active: var(--brand-200);
52
+ --primary-focus: var(--brand-400);
53
+ --primary-disabled: var(--gray-700);
54
+ --primary-foreground: var(--gray-0);
55
55
 
56
56
  /* Borders */
57
- --color-border-default: var(--color-neutral-800);
58
- --color-border-strong: var(--color-neutral-600);
59
- --color-border-focus: var(--color-brand-400);
57
+ --border: var(--gray-800);
58
+ --border-strong: var(--gray-600);
59
+ --border-focus: var(--brand-400);
60
60
  }
61
61
  }
@@ -2,59 +2,56 @@
2
2
  * tokens/semantic/light.css
3
3
  *
4
4
  * Semantic design token assignments for the default Light theme.
5
- * Standardizes semantic mapping to primitives and sets up GPU-accelerated theme transition rules on :root.
6
- * Source: doc 26 §3, §6
7
5
  */
8
6
 
9
7
  :root {
10
8
  /* Surfaces */
11
- --color-surface-page: var(--color-neutral-50);
12
- --color-surface-card: var(--color-neutral-0);
13
- --color-surface-elevated: var(--color-neutral-0);
14
- --color-surface-inverse: var(--color-neutral-900);
9
+ --background: var(--gray-50);
10
+ --background-elevated: var(--gray-0);
11
+ --background-inverse: var(--gray-900);
15
12
 
16
13
  /* Content (Text & Icons) */
17
- --color-content-primary: var(--color-neutral-900);
18
- --color-content-secondary: var(--color-neutral-600);
19
- --color-content-disabled: var(--color-neutral-400);
20
- --color-content-inverse: var(--color-neutral-50);
21
- --color-content-link: var(--color-brand-600);
14
+ --foreground: var(--gray-900);
15
+ --foreground-muted: var(--gray-600);
16
+ --foreground-disabled: var(--gray-400);
17
+ --foreground-inverse: var(--gray-50);
18
+ --foreground-link: var(--brand-600);
22
19
 
23
20
  /* Interactive Elements */
24
- --color-interactive: var(--color-brand-500);
25
- --color-interactive-hover: var(--color-brand-600);
26
- --color-interactive-active: var(--color-brand-700);
27
- --color-interactive-focus: var(--color-brand-500);
28
- --color-interactive-disabled: var(--color-neutral-300);
21
+ --primary: var(--brand-500);
22
+ --primary-hover: var(--brand-600);
23
+ --primary-active: var(--brand-700);
24
+ --primary-focus: var(--brand-500);
25
+ --primary-disabled: var(--gray-300);
26
+ --primary-foreground: var(--gray-0);
29
27
 
30
28
  /* Feedback Semantics */
31
- --color-feedback-success: var(--color-success-500);
32
- --color-feedback-warning: var(--color-warning-500);
33
- --color-feedback-error: var(--color-error-500);
34
- --color-feedback-info: var(--color-info-500);
29
+ --success: var(--success-500);
30
+ --warn: var(--warn-500);
31
+ --error: var(--error-500);
32
+ --info: var(--info-500);
35
33
 
36
34
  /* Borders */
37
- --color-border-default: var(--color-neutral-200);
38
- --color-border-strong: var(--color-neutral-400);
39
- --color-border-focus: var(--color-brand-500);
35
+ --border: var(--gray-200);
36
+ --border-strong: var(--gray-400);
37
+ --border-focus: var(--brand-500);
40
38
 
41
39
  /* Automatic theme morph configuration */
42
40
  transition:
43
- --color-surface-page 220ms var(--ease-out),
44
- --color-surface-card 220ms var(--ease-out),
45
- --color-surface-elevated 220ms var(--ease-out),
46
- --color-surface-inverse 220ms var(--ease-out),
47
- --color-content-primary 180ms var(--ease-out),
48
- --color-content-secondary 180ms var(--ease-out),
49
- --color-content-disabled 180ms var(--ease-out),
50
- --color-content-inverse 180ms var(--ease-out),
51
- --color-content-link 180ms var(--ease-out),
52
- --color-interactive 180ms var(--ease-out),
53
- --color-interactive-hover 180ms var(--ease-out),
54
- --color-interactive-active 180ms var(--ease-out),
55
- --color-border-default 180ms var(--ease-out),
56
- --color-border-strong 180ms var(--ease-out),
57
- --color-border-focus 180ms var(--ease-out);
41
+ --background 220ms var(--ease-out),
42
+ --background-elevated 220ms var(--ease-out),
43
+ --background-inverse 220ms var(--ease-out),
44
+ --foreground 180ms var(--ease-out),
45
+ --foreground-muted 180ms var(--ease-out),
46
+ --foreground-disabled 180ms var(--ease-out),
47
+ --foreground-inverse 180ms var(--ease-out),
48
+ --foreground-link 180ms var(--ease-out),
49
+ --primary 180ms var(--ease-out),
50
+ --primary-hover 180ms var(--ease-out),
51
+ --primary-active 180ms var(--ease-out),
52
+ --border 180ms var(--ease-out),
53
+ --border-strong 180ms var(--ease-out),
54
+ --border-focus 180ms var(--ease-out);
58
55
  }
59
56
 
60
57
  @media (prefers-reduced-motion: reduce) {