diff --git a/CLAUDE.md b/CLAUDE.md
index 1e6729f9..788e6efd 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -51,9 +51,21 @@ requires a rebuild+redeploy, not just a file edit.
| `npm run version-sync` | Sync all version references to root `package.json` |
| `npm run check:version` | Verify all version references match (CI gate — run before every commit that touches versions) |
| `npm run check:llm-guide` | Verify `docs/llm-guide.md` only references live tokens (CI gate) |
+| `npm run check:macros` | Verify `.sf-*` macro classes match `docs/macros.md` (not currently wired into CI — run manually before committing macro changes) |
+| `npm run check:registry` | Verify `token-registry.json` is in sync with source (CI gate) |
+| `npm run audit:check` | Verify `docs/registry.json` matches source without writing (CI gate) |
+| `npm run lint:css` | Lint all CSS source with stylelint (CI gate) |
+| `npm run lint:css:fix` | Lint CSS source and auto-fix violations |
| `npm run docs` | Regenerate docs and sync configurator API index |
+| `npm run docs:tokens` | Regenerate `docs/tokens.md` only |
+| `npm run docs:index` | Regenerate `docs/token-index.md` + `.json` only |
+| `npm run docs:api` | Regenerate `docs/api-index.md` + `.json` only |
+| `npm run docs:classes` | Regenerate `docs/classes.md` only |
+| `npm run gen:registry` | Regenerate `token-registry.json` (stable id assignments) |
| `npm run configurator:sync` | Push `docs/api-index.json` → `configurator/src/data/api-index.generated.json` |
-| `npm run audit` | Audit CSS tokens for consistency |
+| `npm run audit` | Audit CSS tokens for consistency, writing `docs/registry.json` |
+| `npm run watch` | Rebuild CSS bundles on file change (dev watch mode) |
+| `npm run test:unit` | Run the Node `--test` unit suite only, without the Playwright e2e build. Some tests read from `badges/` — run `npm run build` first on a clean checkout (CI instead downloads the `badges` artifact from the `build` job before this step) |
| `npm test` | Full suite: build → unit → Playwright e2e |
## Release process
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ca714b40..10190440 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -46,7 +46,7 @@ and `badges/` must be rebuilt and committed.
## Tests & demo coverage
- Any new `.sf-*` or `.is-*` class in `core/*.css` must appear in `docs/demo.html`
- (`tests/coverage.spec.js`).
+ (`tests/coverage.test.js`).
- Any new token must resolve in both themes (`tests/tokens.spec.js`); tokens whose
value is `inherit` go in that file's `EXPECTED_EMPTY` allowlist.
- Add a focused assertion when you fix a bug.
diff --git a/README.md b/README.md
index 82916404..c62dbbf7 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,9 @@ Use a pre-built bundle (see [Releases](https://github.com/codeslash-dev/SLASHED/
```
À la carte is also supported. When wiring up individual files, `core/layers.css`
-must load **first**. `optional/legacy.css` is not bundled by default — add it
+must load **first** — it declares the `@layer` order once, and that order (not
+`` order) controls the cascade, so the snippet below simply mirrors it
+for readability. `optional/legacy.css` is not bundled by default — add it
explicitly if you need back-compat shims and load it **last**:
```html
@@ -44,10 +46,10 @@ explicitly if you need back-compat shims and load it **last**:
-
+
diff --git a/configurator/package-lock.json b/configurator/package-lock.json
index 74b5030a..ed74bc86 100644
--- a/configurator/package-lock.json
+++ b/configurator/package-lock.json
@@ -8,9 +8,8 @@
"name": "slashed-configurator",
"version": "0.6.33",
"dependencies": {
- "fflate": "^0.8.3",
- "lucide-svelte": "^0.468.0",
- "motion": "^12.23.24"
+ "@lucide/svelte": "^1.23.0",
+ "fflate": "^0.8.3"
},
"devDependencies": {
"@playwright/test": "^1.60.0",
@@ -686,6 +685,15 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@lucide/svelte": {
+ "version": "1.23.0",
+ "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-1.23.0.tgz",
+ "integrity": "sha512-3LQbKXx9vId6Nx4E2Nu2qwgJfdmr5+CVeVJbxe5cy+HcnCRd9QVVtZXqvgBYAV1OJrPmQAf9/3gJWLCpASC/Ng==",
+ "license": "ISC",
+ "peerDependencies": {
+ "svelte": "^5"
+ }
+ },
"node_modules/@playwright/test": {
"version": "1.61.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz",
@@ -2165,33 +2173,6 @@
"node": ">= 6"
}
},
- "node_modules/framer-motion": {
- "version": "12.42.0",
- "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.42.0.tgz",
- "integrity": "sha512-wp7EJnfWaaEScVygKv3e20udoRz+LbtxScsuTkakAxfXmt+ReC6WyPW2nINRAGvd+hG9odwcjBLyOTPjH5pBRA==",
- "license": "MIT",
- "dependencies": {
- "motion-dom": "^12.42.0",
- "motion-utils": "^12.39.0",
- "tslib": "^2.4.0"
- },
- "peerDependencies": {
- "@emotion/is-prop-valid": "*",
- "react": "^18.0.0 || ^19.0.0",
- "react-dom": "^18.0.0 || ^19.0.0"
- },
- "peerDependenciesMeta": {
- "@emotion/is-prop-valid": {
- "optional": true
- },
- "react": {
- "optional": true
- },
- "react-dom": {
- "optional": true
- }
- }
- },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -2747,16 +2728,6 @@
"dev": true,
"license": "ISC"
},
- "node_modules/lucide-svelte": {
- "version": "0.468.0",
- "resolved": "https://registry.npmjs.org/lucide-svelte/-/lucide-svelte-0.468.0.tgz",
- "integrity": "sha512-n0ecAFtCY5LEeL+PJ1Xj4n3c2gzj8tMpak0KMGnvoSJEjCsCnRB0mekBtJZAo7beyynW9Qj5Um1KfMBAeTNplw==",
- "deprecated": "Package deprecated. Please use @lucide/svelte instead.",
- "license": "ISC",
- "peerDependencies": {
- "svelte": "^3 || ^4 || ^5.0.0-next.42"
- }
- },
"node_modules/lz-string": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
@@ -2819,47 +2790,6 @@
"node": ">=4"
}
},
- "node_modules/motion": {
- "version": "12.42.0",
- "resolved": "https://registry.npmjs.org/motion/-/motion-12.42.0.tgz",
- "integrity": "sha512-Qhwvu9sVl5/URSq5CNzwMCpSKK8Uhnrwb6VO977kZyj/wOCS7mWebJUnBoHx5cZU1Zv8a9BD5CSICWKAlrLJgA==",
- "license": "MIT",
- "dependencies": {
- "framer-motion": "^12.42.0",
- "tslib": "^2.4.0"
- },
- "peerDependencies": {
- "@emotion/is-prop-valid": "*",
- "react": "^18.0.0 || ^19.0.0",
- "react-dom": "^18.0.0 || ^19.0.0"
- },
- "peerDependenciesMeta": {
- "@emotion/is-prop-valid": {
- "optional": true
- },
- "react": {
- "optional": true
- },
- "react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/motion-dom": {
- "version": "12.42.0",
- "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.42.0.tgz",
- "integrity": "sha512-M63h4n8R+quJdNhBwuLlgxM+OLYa9+I/T2pzDRboB9fLXRdbou+Gw7Zury+SkpaCyACP1JHSjHgZ1EgTkBr30w==",
- "license": "MIT",
- "dependencies": {
- "motion-utils": "^12.39.0"
- }
- },
- "node_modules/motion-utils": {
- "version": "12.39.0",
- "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz",
- "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==",
- "license": "MIT"
- },
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
@@ -3429,7 +3359,9 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "license": "0BSD"
+ "dev": true,
+ "license": "0BSD",
+ "optional": true
},
"node_modules/typescript": {
"version": "5.8.3",
diff --git a/configurator/package.json b/configurator/package.json
index 45e312e8..ac9ba6b8 100644
--- a/configurator/package.json
+++ b/configurator/package.json
@@ -21,9 +21,8 @@
"test:e2e": "playwright test"
},
"dependencies": {
- "fflate": "^0.8.3",
- "lucide-svelte": "^0.468.0",
- "motion": "^12.23.24"
+ "@lucide/svelte": "^1.23.0",
+ "fflate": "^0.8.3"
},
"devDependencies": {
"@playwright/test": "^1.60.0",
diff --git a/configurator/src/App.svelte b/configurator/src/App.svelte
index 6b5d3b7d..9a256f18 100644
--- a/configurator/src/App.svelte
+++ b/configurator/src/App.svelte
@@ -1,19 +1,19 @@