diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 2f9305e9..51671fa2 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -22,6 +22,7 @@ jobs:
node-version: ${{ matrix.node-version }}
check-latest: true
- run: npm i
+ - run: npx playwright install --with-deps chromium
- name: Run tests
run: |
node_major=$(node -p "process.versions.node.split('.')[0]")
diff --git a/.gitignore b/.gitignore
index 02a8f93e..e293d06a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ package-lock.json
public
coverage
lcov.info
+test-results
.tap
.tmp-*
diff --git a/README.md b/README.md
index 1b04d23d..8a35587c 100644
--- a/README.md
+++ b/README.md
@@ -1846,6 +1846,8 @@ Key changes at a glance:
- **Default layout**: The bundled and ejected `root.layout.js` now uses [`fragtml`][fragtml].
- **Included dependencies**: `domstack --eject` adds `mine.css`, `fragtml`, and `highlight.js`; Preact, HTM, and `preact-render-to-string` are no longer included for the default template.
+- **mine.css v11**: The default styles now use mine.css v11's CSS-only API, browser-controlled color preference, native CSS nesting, and intentional visual changes. Ejected and customized sites must follow the mine.css v11 migration steps.
+- **CSS cascade layers**: DOMStack’s default stylesheet establishes the `mine`, `domstack.global`, `domstack.layout`, and `domstack.page` layer order. Following the same layer pattern in custom global, layout, and page stylesheets is recommended for explicit global → layout → page precedence.
- **JSX runtime**: Client `.jsx` and `.tsx` bundles still work through esbuild, but DOMStack no longer configures Preact as the default runtime. Install React, Preact, or another runtime in your own project and configure it with `esbuild.settings`.
- **Preact examples**: Examples that actually mount Preact in the browser still use Preact and configure it locally.
diff --git a/browser-tests/cascade-layers.spec.js b/browser-tests/cascade-layers.spec.js
new file mode 100644
index 00000000..1f05ea38
--- /dev/null
+++ b/browser-tests/cascade-layers.spec.js
@@ -0,0 +1,26 @@
+import { expect, test } from './support.js'
+
+async function cascadeValue (page) {
+ return page.getByTestId('cascade-layer-fixture').evaluate(element => {
+ return getComputedStyle(element).getPropertyValue('--domstack-cascade-layer').trim()
+ })
+}
+
+test('orders mine, global, layout, and page cascade layers', async ({ page, siteURL }) => {
+ await page.goto(`${siteURL}/`, { waitUntil: 'domcontentloaded' })
+ await page.addStyleTag({
+ content: '@layer mine { .cascade-layer-fixture { --domstack-cascade-layer: mine; } }'
+ })
+
+ await expect(page.getByTestId('cascade-layer-fixture')).toHaveCount(1)
+ await expect.poll(() => cascadeValue(page)).toBe('page')
+
+ await page.locator('link[rel="stylesheet"][href*="style-"]').evaluate(element => element.remove())
+ await expect.poll(() => cascadeValue(page)).toBe('layout')
+
+ await page.locator('link[rel="stylesheet"][href*="root.layout-"]').evaluate(element => element.remove())
+ await expect.poll(() => cascadeValue(page)).toBe('global')
+
+ await page.locator('link[rel="stylesheet"][href*="global-"]').evaluate(element => element.remove())
+ await expect.poll(() => cascadeValue(page)).toBe('mine')
+})
diff --git a/browser-tests/support.js b/browser-tests/support.js
new file mode 100644
index 00000000..8fd7777d
--- /dev/null
+++ b/browser-tests/support.js
@@ -0,0 +1,71 @@
+import { expect, test as base } from '@playwright/test'
+import { readFile } from 'node:fs/promises'
+import { createServer } from 'node:http'
+import { extname, resolve, sep } from 'node:path'
+import { testBuild } from '../index.js'
+
+const fixtureSrc = resolve(import.meta.dirname, '../test-cases/general-features/src')
+const contentTypes = new Map([
+ ['.css', 'text/css; charset=utf-8'],
+ ['.html', 'text/html; charset=utf-8'],
+ ['.js', 'text/javascript; charset=utf-8'],
+ ['.woff2', 'font/woff2']
+])
+
+export const test = base.extend({
+ siteURL: async ({ context }, use) => {
+ const build = await testBuild(fixtureSrc)
+ const publicDir = build.dest
+ const server = createServer(async (request, response) => {
+ try {
+ const url = new URL(request.url ?? '/', 'http://127.0.0.1')
+ const pathname = decodeURIComponent(url.pathname)
+ const relativePath = pathname.endsWith('/')
+ ? `${pathname}index.html`
+ : pathname
+ const filePath = resolve(publicDir, `.${relativePath}`)
+
+ if (filePath !== publicDir && !filePath.startsWith(`${publicDir}${sep}`)) {
+ response.writeHead(403).end('Forbidden')
+ return
+ }
+
+ const body = await readFile(filePath)
+ response.writeHead(200, {
+ 'cache-control': 'no-store',
+ 'content-type': contentTypes.get(extname(filePath)) ?? 'application/octet-stream'
+ })
+ response.end(body)
+ } catch (error) {
+ const status = error?.code === 'ENOENT' ? 404 : 500
+ response.writeHead(status).end(status === 404 ? 'Not found' : 'Server error')
+ }
+ })
+
+ await new Promise((resolve, reject) => {
+ server.once('error', reject)
+ server.listen(0, '127.0.0.1', () => {
+ server.off('error', reject)
+ resolve()
+ })
+ })
+
+ const address = server.address()
+ if (!address || typeof address === 'string') throw new Error('Static server did not bind to a TCP port')
+
+ await context.route(/^https?:\/\/(?!127\.0\.0\.1(?::\d+)?(?:\/|$))/, route => route.abort())
+ await use(`http://127.0.0.1:${address.port}`)
+
+ for (const page of context.pages()) {
+ if (!page.isClosed()) await page.close().catch(() => {})
+ }
+
+ await new Promise((resolve, reject) => {
+ server.close(error => error ? reject(error) : resolve())
+ server.closeAllConnections()
+ })
+ await build.cleanup()
+ }
+})
+
+export { expect }
diff --git a/docs/v12-migration.md b/docs/v12-migration.md
index 89f1f6aa..e6a4923c 100644
--- a/docs/v12-migration.md
+++ b/docs/v12-migration.md
@@ -12,7 +12,8 @@ Then apply the v12 changes below.
3. [Default Layout Uses fragtml](#3-default-layout-uses-fragtml)
4. [Keep Layout Dependencies Explicit](#4-keep-layout-dependencies-explicit)
5. [JSX Runtime Is Opt-In](#5-jsx-runtime-is-opt-in)
-6. [Migration Checklist](#6-migration-checklist)
+6. [mine.css v11 and CSS Cascade Layers](#6-minecss-v11-and-css-cascade-layers)
+7. [Migration Checklist](#7-migration-checklist)
---
@@ -123,7 +124,96 @@ export default async function esbuildSettingsOverride (esbuildSettings) {
---
-## 6. Migration Checklist
+## 6. mine.css v11 and CSS Cascade Layers
+
+DOMStack v12 upgrades its bundled default styles and ejected projects from mine.css v10 to v11.
+This is a downstream breaking change even when your project does not import mine.css directly, because the bundled default layout uses it.
+Review the complete [mine.css v11 migration guide](https://github.com/bcomnes/mine.css/blob/master/MIGRATION.md) before upgrading a customized or ejected site.
+
+mine.css v11 is CSS-only.
+The package root now resolves to the main stylesheet, and the JavaScript theme switcher is no longer published.
+Replace the old deep import with the package root:
+
+```css
+@import 'mine.css';
+```
+
+Remove imports of `mine.css` or `mine.css/dist/theme-switcher.js` from JavaScript, calls to `toggleTheme()`, stored theme state, theme controls, and `.light-mode` or `.dark-mode` rules.
+Add `` to custom root layouts and use `prefers-color-scheme` for application-specific dark styles.
+If you use Highlight.js, load a light theme normally and a dark theme conditionally instead of applying one dark theme in both modes.
+
+The optional mine.css layout remains a separate import.
+DOMStack's default stylesheet imports it explicitly; ejected sites must continue to do the same.
+
+### DOMStack cascade layer order
+
+DOMStack v12's default stylesheet establishes this low-to-high-priority author-layer order:
+
+```css
+@layer mine, domstack.global, domstack.layout, domstack.page;
+```
+
+The order reflects DOMStack's existing stylesheet scopes:
+
+- `mine` contains mine.css framework defaults.
+- `domstack.global` contains site-wide rules and syntax themes.
+- `domstack.layout` contains optional mine.css layout rules and `*.layout.css` rules.
+- `domstack.page` contains page-local `style.css` rules.
+
+Declare the complete order before imports or other layer blocks in the global stylesheet.
+Import mine.css normally because its distributed stylesheet already defines the `mine` layer.
+Do not write `@import 'mine.css' layer(mine)`.
+Optional sidecars and syntax themes are not pre-layered, so assign them to the appropriate DOMStack layer:
+
+```css
+@layer mine, domstack.global, domstack.layout, domstack.page;
+
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
+@import 'highlight.js/styles/github.css' layer(domstack.global);
+@import url('highlight.js/styles/github-dark-dimmed.css') layer(domstack.global) (prefers-color-scheme: dark);
+
+@layer domstack.global {
+ :root {
+ --brand-color: rebeccapurple;
+ }
+}
+```
+
+Following this pattern in custom stylesheets is recommended.
+Scope layout and page rules in their matching files:
+
+```css
+/* article.layout.css */
+@layer domstack.layout {
+ .article-shell {
+ max-inline-size: 72rem;
+ }
+}
+```
+
+```css
+/* style.css */
+@layer domstack.page {
+ .article-introduction {
+ font-size: 1.125em;
+ }
+}
+```
+
+DOMStack loads the global stylesheet first, so its order declaration establishes precedence before layout and page layer blocks are encountered.
+Unlayered author rules outrank every layered normal rule, so existing unlayered overrides will still win but bypass the DOMStack scope contract.
+Move them into the matching layer when you want predictable global → layout → page precedence.
+CSS Modules may remain unlayered when component-local precedence is intentional, or be wrapped in the appropriate scope layer when they participate in this cascade.
+
+mine.css v11 also intentionally changes typography, forms, tables, media framing, motion, focus treatment, and the optional `.mine-layout` width.
+It preserves native table display; wrap wide tables in an accessible, named, keyboard-focusable overflow region rather than restoring `display: block` on the table.
+The distributed CSS uses native CSS nesting, and the package requires Node.js 22 or newer and npm 10 or newer for installation.
+Visually verify representative pages in light and dark browser modes, narrow and wide viewports, reduced-motion mode, and print preview where relevant.
+
+---
+
+## 7. Migration Checklist
- [ ] If you import public types from `@domstack/static`, update those imports to `@domstack/static/types.js`.
- [ ] If you rely on BrowserSync-specific dev-server behavior, test watch mode with `@domstack/sync`.
@@ -133,3 +223,11 @@ export default async function esbuildSettingsOverride (esbuildSettings) {
- [ ] If you want your ejected server-side layout to match the v12 default, migrate its templates to `fragtml` and install `fragtml`.
- [ ] If you use `.jsx` or `.tsx` browser clients, add an `esbuild.settings` file that configures your JSX runtime.
- [ ] If you use Preact browser clients, keep `preact` in your project dependencies.
+- [ ] Read the mine.css v11 migration guide and account for its intentional visual and browser-support changes.
+- [ ] Replace `@import 'mine.css/dist/mine.css'` with `@import 'mine.css'` and keep optional sidecars explicit.
+- [ ] Remove `toggleTheme()`, theme-switcher imports, persisted theme state, theme controls, and light/dark mode classes.
+- [ ] Add `` to custom root layouts and use `prefers-color-scheme` for dark styles.
+- [ ] Declare `@layer mine, domstack.global, domstack.layout, domstack.page;` and scope global, layout, and page rules in their matching layers.
+- [ ] Load light and dark syntax-highlighting themes with matching `prefers-color-scheme` behavior.
+- [ ] Confirm the deployment and install environment uses Node.js 22+ and npm 10+ and that target browsers support native CSS nesting.
+- [ ] Visually and interactively check both color schemes, keyboard focus, reduced motion, forms, wide tables, media, print, and responsive layouts.
diff --git a/examples/basic/package.json b/examples/basic/package.json
index 0c33dec8..1061cbc3 100644
--- a/examples/basic/package.json
+++ b/examples/basic/package.json
@@ -21,7 +21,7 @@
"dependencies": {
"@domstack/static": "file:../../.",
"fragtml": "^0.0.9",
- "mine.css": "^9.0.1",
+ "mine.css": "^11.0.6",
"highlight.js": "^11.9.0"
}
}
diff --git a/examples/basic/src/global.client.ts b/examples/basic/src/global.client.ts
index b840c4d9..dae17c34 100644
--- a/examples/basic/src/global.client.ts
+++ b/examples/basic/src/global.client.ts
@@ -1,15 +1,6 @@
-// @ts-expect-error
-import { toggleTheme } from 'mine.css'
-declare global {
- interface Window {
- toggleTheme: typeof toggleTheme;
- }
-}
-
-window.toggleTheme = toggleTheme
console.log('The global client is loaded on every page.')
// Try to keep this file as small as possible.
-// Use if for things like global theme switchers or analytics scripts
+// Use it for things like analytics scripts or other site-wide behavior
diff --git a/examples/basic/src/global.css b/examples/basic/src/global.css
index 15bc3690..bbe42032 100644
--- a/examples/basic/src/global.css
+++ b/examples/basic/src/global.css
@@ -1,10 +1,15 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
-@import 'highlight.js/styles/github-dark-dimmed.css';
+@layer mine, domstack.global, domstack.layout, domstack.page;
-/* The global.css in the root directory of the site is loaded on every page. */
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
+@import 'highlight.js/styles/github.css' layer(domstack.global);
+@import url('highlight.js/styles/github-dark-dimmed.css') layer(domstack.global) (prefers-color-scheme: dark);
-/* You can import styles out of node_modules by referencing their bare-name */
-/* You can import styles from a relative path as well, though usually that is
-only used in page scpped style.css files */
-/* See https://github.com/postcss/postcss-import for details */
+@layer domstack.global {
+ /* The global.css in the root directory of the site is loaded on every page. */
+
+ /* You can import styles out of node_modules by referencing their bare-name */
+ /* You can import styles from a relative path as well, though usually that is
+ only used in page scpped style.css files */
+ /* See https://github.com/postcss/postcss-import for details */
+}
diff --git a/examples/basic/src/html-page/style.css b/examples/basic/src/html-page/style.css
index 6696adb3..6105abac 100644
--- a/examples/basic/src/html-page/style.css
+++ b/examples/basic/src/html-page/style.css
@@ -1,5 +1,7 @@
-/* html pages can also have their own style bundles */
+@layer domstack.page {
+ /* html pages can also have their own style bundles */
-.html-page-class {
- background-color: red;
+ .html-page-class {
+ background-color: red;
+ }
}
diff --git a/examples/basic/src/js-page/loose-assets/style.css b/examples/basic/src/js-page/loose-assets/style.css
index df552d4d..c2172497 100644
--- a/examples/basic/src/js-page/loose-assets/style.css
+++ b/examples/basic/src/js-page/loose-assets/style.css
@@ -1,2 +1 @@
-@import './local-import.css';
-
+@import './local-import.css' layer(domstack.page);
diff --git a/examples/basic/src/js-page/style.css b/examples/basic/src/js-page/style.css
index c1673966..7b11d9a3 100644
--- a/examples/basic/src/js-page/style.css
+++ b/examples/basic/src/js-page/style.css
@@ -1,74 +1,76 @@
-.js-page-example {
- max-width: 800px;
- margin: 0 auto;
- padding: 1rem;
- font-family: system-ui, -apple-system, sans-serif;
-}
+@layer domstack.page {
+ .js-page-example {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 1rem;
+ font-family: system-ui, -apple-system, sans-serif;
+ }
-.js-page-example h1 {
- color: #333;
- border-bottom: 2px solid #6200ee;
- padding-bottom: 0.5rem;
-}
+ .js-page-example h1 {
+ color: #333;
+ border-bottom: 2px solid #6200ee;
+ padding-bottom: 0.5rem;
+ }
-.js-page-example section {
- margin-bottom: 2rem;
- padding: 1.5rem;
- border-radius: 8px;
- background-color: #f9f9f9;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
+ .js-page-example section {
+ margin-bottom: 2rem;
+ padding: 1.5rem;
+ border-radius: 8px;
+ background-color: #f9f9f9;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ }
-.js-page-example h2 {
- color: #6200ee;
- margin-top: 0;
- margin-bottom: 1rem;
-}
+ .js-page-example h2 {
+ color: #6200ee;
+ margin-top: 0;
+ margin-bottom: 1rem;
+ }
-.js-page-example .code-example {
- background-color: #272822;
- color: #f8f8f2;
- padding: 1rem;
- border-radius: 4px;
- overflow-x: auto;
-}
+ .js-page-example .code-example {
+ background-color: #272822;
+ color: #f8f8f2;
+ padding: 1rem;
+ border-radius: 4px;
+ overflow-x: auto;
+ }
-.js-page-example .code-example pre {
- margin: 0;
-}
+ .js-page-example .code-example pre {
+ margin: 0;
+ }
-.js-page-example code {
- background-color: #eee;
- padding: 0.2rem 0.4rem;
- border-radius: 3px;
- font-family: monospace;
- font-size: 0.9em;
-}
+ .js-page-example code {
+ background-color: #eee;
+ padding: 0.2rem 0.4rem;
+ border-radius: 3px;
+ font-family: monospace;
+ font-size: 0.9em;
+ }
-.js-page-example .code-example code {
- background-color: transparent;
- padding: 0;
-}
+ .js-page-example .code-example code {
+ background-color: transparent;
+ padding: 0;
+ }
-.js-page-example .variable-display {
- background-color: #fff;
- border: 1px solid #ddd;
- padding: 1rem;
- border-radius: 4px;
- margin-top: 1rem;
-}
+ .js-page-example .variable-display {
+ background-color: #fff;
+ border: 1px solid #ddd;
+ padding: 1rem;
+ border-radius: 4px;
+ margin-top: 1rem;
+ }
-.js-page-example .back-link {
- display: inline-block;
- margin-top: 1rem;
- padding: 0.5rem 1rem;
- background-color: #6200ee;
- color: white;
- text-decoration: none;
- border-radius: 4px;
- transition: background-color 0.2s;
-}
+ .js-page-example .back-link {
+ display: inline-block;
+ margin-top: 1rem;
+ padding: 0.5rem 1rem;
+ background-color: #6200ee;
+ color: white;
+ text-decoration: none;
+ border-radius: 4px;
+ transition: background-color 0.2s;
+ }
-.js-page-example .back-link:hover {
- background-color: #3700b3;
+ .js-page-example .back-link:hover {
+ background-color: #3700b3;
+ }
}
diff --git a/examples/basic/src/layouts/root.layout.ts b/examples/basic/src/layouts/root.layout.ts
index a2da1624..c7da72fe 100644
--- a/examples/basic/src/layouts/root.layout.ts
+++ b/examples/basic/src/layouts/root.layout.ts
@@ -34,6 +34,7 @@ const RootLayout: LayoutFunction = async
${siteName}${title ? ` | ${title}` : ''}
+
${scripts
? scripts.map(script => html``)
: null}
diff --git a/examples/basic/src/md-page/style.css b/examples/basic/src/md-page/style.css
index 05536d35..a30da591 100644
--- a/examples/basic/src/md-page/style.css
+++ b/examples/basic/src/md-page/style.css
@@ -1,4 +1,6 @@
-/* This style file only loads in the md-page page */
-.page-scoped-selector {
- background-color: blue;
+@layer domstack.page {
+ /* This style file only loads in the md-page page */
+ .page-scoped-selector {
+ background-color: blue;
+ }
}
diff --git a/examples/basic/src/style.css b/examples/basic/src/style.css
index 702d9eeb..4c3d043f 100644
--- a/examples/basic/src/style.css
+++ b/examples/basic/src/style.css
@@ -1,5 +1,7 @@
-/* This style.css bundle only loads on the root page. */
+@layer domstack.page {
+ /* This style.css bundle only loads on the root page. */
-.some-class {
- color: blue;
+ .some-class {
+ color: blue;
+ }
}
diff --git a/examples/blog/package.json b/examples/blog/package.json
index 468ec337..039bf160 100644
--- a/examples/blog/package.json
+++ b/examples/blog/package.json
@@ -20,6 +20,6 @@
"dependencies": {
"@domstack/static": "file:../../.",
"fragtml": "^0.0.9",
- "mine.css": "^10.0.0"
+ "mine.css": "^11.0.6"
}
}
diff --git a/examples/blog/src/global.client.ts b/examples/blog/src/global.client.ts
deleted file mode 100644
index c8f25844..00000000
--- a/examples/blog/src/global.client.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// @ts-ignore
-import { toggleTheme } from 'mine.css'
-
-// Expose theme toggle globally for the nav button
-// @ts-ignore
-window.toggleTheme = toggleTheme
diff --git a/examples/blog/src/global.css b/examples/blog/src/global.css
index 443bcd17..86dbf6f7 100644
--- a/examples/blog/src/global.css
+++ b/examples/blog/src/global.css
@@ -1,39 +1,43 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
+@layer mine, domstack.global, domstack.layout, domstack.page;
-/* ── Site-wide ── */
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
-.site-header {
- border-bottom: 1px solid var(--border);
- padding: 1rem 0;
- margin-bottom: 2rem;
-}
+@layer domstack.global {
+ /* ── Site-wide ── */
-.site-header-inner {
- display: flex;
- align-items: baseline;
- gap: 1.5rem;
-}
+ .site-header {
+ border-bottom: 1px solid var(--border);
+ padding: 1rem 0;
+ margin-bottom: 2rem;
+ }
-.site-title {
- font-size: 1.4rem;
- font-weight: 700;
- text-decoration: none;
- color: inherit;
-}
+ .site-header-inner {
+ display: flex;
+ align-items: baseline;
+ gap: 1.5rem;
+ }
-.site-nav {
- display: flex;
- gap: 1rem;
- list-style: none;
- margin: 0;
- padding: 0;
-}
+ .site-title {
+ font-size: 1.4rem;
+ font-weight: 700;
+ text-decoration: none;
+ color: inherit;
+ }
+
+ .site-nav {
+ display: flex;
+ gap: 1rem;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
-.site-footer {
- border-top: 1px solid var(--border);
- margin-top: 3rem;
- padding: 1.5rem 0;
- font-size: 0.875rem;
- color: var(--text-2);
+ .site-footer {
+ border-top: 1px solid var(--border);
+ margin-top: 3rem;
+ padding: 1.5rem 0;
+ font-size: 0.875rem;
+ color: var(--text-2);
+ }
}
diff --git a/examples/blog/src/layouts/post.layout.css b/examples/blog/src/layouts/post.layout.css
index 446b2530..a6108603 100644
--- a/examples/blog/src/layouts/post.layout.css
+++ b/examples/blog/src/layouts/post.layout.css
@@ -1,86 +1,88 @@
-@import './root.layout.css';
+@import './root.layout.css' layer(domstack.layout);
-/* ── Post layout ── */
+@layer domstack.layout {
+ /* ── Post layout ── */
-.post-header {
- margin-bottom: 2rem;
-}
+ .post-header {
+ margin-bottom: 2rem;
+ }
-.post-title {
- font-size: 2rem;
- line-height: 1.2;
- margin-bottom: 0.75rem;
-}
+ .post-title {
+ font-size: 2rem;
+ line-height: 1.2;
+ margin-bottom: 0.75rem;
+ }
-.post-meta {
- display: flex;
- flex-wrap: wrap;
- align-items: baseline;
- gap: 0.75rem 1.5rem;
- font-size: 0.875rem;
- color: var(--text-2);
- border-top: 1px solid var(--border);
- border-bottom: 1px solid var(--border);
- padding: 0.625rem 0;
- margin-bottom: 1.5rem;
-}
+ .post-meta {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: baseline;
+ gap: 0.75rem 1.5rem;
+ font-size: 0.875rem;
+ color: var(--text-2);
+ border-top: 1px solid var(--border);
+ border-bottom: 1px solid var(--border);
+ padding: 0.625rem 0;
+ margin-bottom: 1.5rem;
+ }
-.author-card {
- font-style: normal;
-}
+ .author-card {
+ font-style: normal;
+ }
-.author-name {
- font-weight: 600;
-}
+ .author-name {
+ font-weight: 600;
+ }
-.author-bio {
- display: block;
- font-size: 0.8rem;
- color: var(--text-2);
- margin-top: 0.125rem;
-}
+ .author-bio {
+ display: block;
+ font-size: 0.8rem;
+ color: var(--text-2);
+ margin-top: 0.125rem;
+ }
-.post-date,
-.post-updated {
- white-space: nowrap;
-}
+ .post-date,
+ .post-updated {
+ white-space: nowrap;
+ }
-.post-tags {
- display: flex;
- flex-wrap: wrap;
- gap: 0.375rem;
- list-style: none;
- margin: 0;
- padding: 0;
-}
+ .post-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.375rem;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
-.post-tag {
- background: var(--surface-2);
- border-radius: 0.25rem;
- padding: 0.125rem 0.5rem;
- font-size: 0.8rem;
-}
+ .post-tag {
+ background: var(--surface-2);
+ border-radius: 0.25rem;
+ padding: 0.125rem 0.5rem;
+ font-size: 0.8rem;
+ }
-.post-body {
- line-height: 1.7;
-}
+ .post-body {
+ line-height: 1.7;
+ }
-.post-body :is(h2, h3, h4) {
- margin-top: 2rem;
-}
+ .post-body :is(h2, h3, h4) {
+ margin-top: 2rem;
+ }
-.post-body pre {
- overflow-x: auto;
-}
+ .post-body pre {
+ overflow-x: auto;
+ }
-.post-footer {
- margin-top: 2.5rem;
- padding-top: 1rem;
- border-top: 1px solid var(--border);
- font-size: 0.875rem;
- color: var(--text-2);
-}
+ .post-footer {
+ margin-top: 2.5rem;
+ padding-top: 1rem;
+ border-top: 1px solid var(--border);
+ font-size: 0.875rem;
+ color: var(--text-2);
+ }
-.post-footer-note {
- margin: 0;
+ .post-footer-note {
+ margin: 0;
+ }
}
diff --git a/examples/blog/src/layouts/root.layout.css b/examples/blog/src/layouts/root.layout.css
index 21595dfc..d48fce96 100644
--- a/examples/blog/src/layouts/root.layout.css
+++ b/examples/blog/src/layouts/root.layout.css
@@ -1,45 +1,47 @@
-/* Base layout styles shared by all layout variants */
-
-/* ── Post index list (used by home + /blog/) ── */
-
-.post-list {
- list-style: none;
- margin: 0;
- padding: 0;
- display: flex;
- flex-direction: column;
- gap: 1.5rem;
-}
-
-.post-list-item {
- border-bottom: 1px solid var(--border);
- padding-bottom: 1.5rem;
-}
-
-.post-list-item:last-child {
- border-bottom: none;
-}
-
-.post-list-title {
- font-size: 1.25rem;
- margin: 0 0 0.25rem;
-}
-
-.post-list-title a {
- text-decoration: none;
-}
-
-.post-list-title a:hover {
- text-decoration: underline;
-}
-
-.post-list-meta {
- font-size: 0.8rem;
- color: var(--text-2);
- margin: 0 0 0.5rem;
-}
-
-.post-list-description {
- margin: 0;
- color: var(--text-2);
+@layer domstack.layout {
+ /* Base layout styles shared by all layout variants */
+
+ /* ── Post index list (used by home + /blog/) ── */
+
+ .post-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 1.5rem;
+ }
+
+ .post-list-item {
+ border-bottom: 1px solid var(--border);
+ padding-bottom: 1.5rem;
+ }
+
+ .post-list-item:last-child {
+ border-bottom: none;
+ }
+
+ .post-list-title {
+ font-size: 1.25rem;
+ margin: 0 0 0.25rem;
+ }
+
+ .post-list-title a {
+ text-decoration: none;
+ }
+
+ .post-list-title a:hover {
+ text-decoration: underline;
+ }
+
+ .post-list-meta {
+ font-size: 0.8rem;
+ color: var(--text-2);
+ margin: 0 0 0.5rem;
+ }
+
+ .post-list-description {
+ margin: 0;
+ color: var(--text-2);
+ }
}
diff --git a/examples/blog/src/layouts/root.layout.ts b/examples/blog/src/layouts/root.layout.ts
index 8fa620cb..69c376d2 100644
--- a/examples/blog/src/layouts/root.layout.ts
+++ b/examples/blog/src/layouts/root.layout.ts
@@ -22,6 +22,7 @@ const rootLayout: LayoutFunction = ({
${pageTitle}
+
${styles?.map(s => html``)}
${scripts?.map(s => html``)}
@@ -36,7 +37,7 @@ const rootLayout: LayoutFunction = ({
Blog
About
Feed
-
+
diff --git a/examples/css-modules/package.json b/examples/css-modules/package.json
index 7a9b8ebb..c2a5e24b 100644
--- a/examples/css-modules/package.json
+++ b/examples/css-modules/package.json
@@ -14,7 +14,7 @@
"@preact/signals": "^2.0.0",
"highlight.js": "^11.9.0",
"htm": "^3.1.1",
- "mine.css": "^9.0.1",
+ "mine.css": "^11.0.6",
"preact": "^10.24.0",
"preact-render-to-string": "^6.5.11",
"@domstack/static": "file:../../."
diff --git a/examples/css-modules/src/globals/global.client.js b/examples/css-modules/src/globals/global.client.js
deleted file mode 100644
index 20121a79..00000000
--- a/examples/css-modules/src/globals/global.client.js
+++ /dev/null
@@ -1,2 +0,0 @@
-import { toggleTheme } from 'mine.css'
-window.toggleTheme = toggleTheme
diff --git a/examples/css-modules/src/globals/global.css b/examples/css-modules/src/globals/global.css
index 84d5e65b..e1ca9f76 100644
--- a/examples/css-modules/src/globals/global.css
+++ b/examples/css-modules/src/globals/global.css
@@ -1,3 +1,6 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
-@import 'highlight.js/styles/github-dark-dimmed.css';
+@layer mine, domstack.global, domstack.layout, domstack.page;
+
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
+@import 'highlight.js/styles/github.css' layer(domstack.global);
+@import url('highlight.js/styles/github-dark-dimmed.css') layer(domstack.global) (prefers-color-scheme: dark);
diff --git a/examples/css-modules/src/layouts/root.layout.js b/examples/css-modules/src/layouts/root.layout.js
index 4410e8b3..2427da6d 100644
--- a/examples/css-modules/src/layouts/root.layout.js
+++ b/examples/css-modules/src/layouts/root.layout.js
@@ -34,6 +34,7 @@ export default async function RootLayout ({
${siteName}${title ? ` | ${title}` : ''}
+
${scripts
? scripts.map(script => html``)
: null}
diff --git a/examples/css-modules/src/modules/style.css b/examples/css-modules/src/modules/style.css
index 76679dc3..d40851de 100644
--- a/examples/css-modules/src/modules/style.css
+++ b/examples/css-modules/src/modules/style.css
@@ -1 +1 @@
-@import './app.module.css';
+@import './app.module.css' layer(domstack.page);
diff --git a/examples/markdown-settings/src/global.style.css b/examples/markdown-settings/src/global.style.css
index 60512db1..2703372b 100644
--- a/examples/markdown-settings/src/global.style.css
+++ b/examples/markdown-settings/src/global.style.css
@@ -1,262 +1,268 @@
-@import 'highlight.js/styles/github-dark-dimmed.css';
-/**
- * Markdown-it Custom Styling
- *
- * This stylesheet provides custom styling for the enhanced markdown-it features
- * configured in markdown-it.settings.js.
- */
-
-/* =============================================
- CUSTOM CONTAINERS
- ============================================= */
-
-/* Custom warning container */
-.custom-warning {
- border: 2px solid #ff9800;
- border-radius: 8px;
- margin: 1.5rem 0;
- overflow: hidden;
- background-color: #fff3e0;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- transition: transform 0.2s, box-shadow 0.2s;
-}
+@layer mine, domstack.global, domstack.layout, domstack.page;
+
+@import 'highlight.js/styles/github.css' layer(domstack.global);
+@import url('highlight.js/styles/github-dark-dimmed.css') layer(domstack.global) (prefers-color-scheme: dark);
+
+@layer domstack.global {
+ /**
+ * Markdown-it Custom Styling
+ *
+ * This stylesheet provides custom styling for the enhanced markdown-it features
+ * configured in markdown-it.settings.js.
+ */
+
+ /* =============================================
+ CUSTOM CONTAINERS
+ ============================================= */
+
+ /* Custom warning container */
+ .custom-warning {
+ border: 2px solid #ff9800;
+ border-radius: 8px;
+ margin: 1.5rem 0;
+ overflow: hidden;
+ background-color: #fff3e0;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ transition: transform 0.2s, box-shadow 0.2s;
+ }
-.custom-warning:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
-}
+ .custom-warning:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+ }
-.custom-warning .warning-title {
- background-color: #ff9800;
- color: white;
- padding: 0.75rem 1rem;
- font-weight: bold;
- font-size: 1.1rem;
-}
+ .custom-warning .warning-title {
+ background-color: #ff9800;
+ color: white;
+ padding: 0.75rem 1rem;
+ font-weight: bold;
+ font-size: 1.1rem;
+ }
-.custom-warning .warning-content {
- padding: 1rem;
- color: #e65100;
-}
+ .custom-warning .warning-content {
+ padding: 1rem;
+ color: #e65100;
+ }
-/* Custom info container */
-.custom-info {
- border: 2px solid #2196f3;
- border-radius: 8px;
- margin: 1.5rem 0;
- overflow: hidden;
- background-color: #e3f2fd;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- transition: transform 0.2s, box-shadow 0.2s;
-}
+ /* Custom info container */
+ .custom-info {
+ border: 2px solid #2196f3;
+ border-radius: 8px;
+ margin: 1.5rem 0;
+ overflow: hidden;
+ background-color: #e3f2fd;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ transition: transform 0.2s, box-shadow 0.2s;
+ }
-.custom-info:hover {
- transform: translateY(-2px);
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
-}
+ .custom-info:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+ }
-.custom-info .info-title {
- background-color: #2196f3;
- color: white;
- padding: 0.75rem 1rem;
- font-weight: bold;
- font-size: 1.1rem;
-}
+ .custom-info .info-title {
+ background-color: #2196f3;
+ color: white;
+ padding: 0.75rem 1rem;
+ font-weight: bold;
+ font-size: 1.1rem;
+ }
-.custom-info .info-content {
- padding: 1rem;
- color: #0d47a1;
-}
+ .custom-info .info-content {
+ padding: 1rem;
+ color: #0d47a1;
+ }
-/* =============================================
- COLLAPSIBLE DETAILS CONTAINER
- ============================================= */
-
-/* Custom details container */
-details {
- border: 1px solid #ddd;
- border-radius: 8px;
- margin: 1.5rem 0;
- padding: 0;
- background-color: #f5f5f5;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
- transition: box-shadow 0.2s;
-}
+ /* =============================================
+ COLLAPSIBLE DETAILS CONTAINER
+ ============================================= */
-details:hover {
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
-}
+ /* Custom details container */
+ details {
+ border: 1px solid #ddd;
+ border-radius: 8px;
+ margin: 1.5rem 0;
+ padding: 0;
+ background-color: #f5f5f5;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+ transition: box-shadow 0.2s;
+ }
-details summary {
- padding: 1rem;
- cursor: pointer;
- font-weight: bold;
- background-color: #e0e0e0;
- border-radius: 8px 8px 0 0;
- user-select: none;
- position: relative;
- outline: none;
-}
+ details:hover {
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ }
-details summary::after {
- content: "▼";
- position: absolute;
- right: 1rem;
- top: 50%;
- transform: translateY(-50%);
- transition: transform 0.3s;
- font-size: 0.8rem;
- color: #666;
-}
+ details summary {
+ padding: 1rem;
+ cursor: pointer;
+ font-weight: bold;
+ background-color: #e0e0e0;
+ border-radius: 8px 8px 0 0;
+ user-select: none;
+ position: relative;
+ outline: none;
+ }
-details[open] summary::after {
- transform: translateY(-50%) rotate(180deg);
-}
+ details summary::after {
+ content: "▼";
+ position: absolute;
+ right: 1rem;
+ top: 50%;
+ transform: translateY(-50%);
+ transition: transform 0.3s;
+ font-size: 0.8rem;
+ color: #666;
+ }
-details[open] summary {
- border-bottom: 1px solid #ddd;
-}
+ details[open] summary::after {
+ transform: translateY(-50%) rotate(180deg);
+ }
-details .details-content {
- padding: 1rem;
- background-color: white;
- border-radius: 0 0 8px 8px;
-}
+ details[open] summary {
+ border-bottom: 1px solid #ddd;
+ }
-/* =============================================
- CODE BLOCK STYLING
- ============================================= */
-
-/* Custom code blocks */
-.custom-code-block {
- background-color: #1e1e1e;
- border: 1px solid #333;
- border-radius: 6px;
- padding: 1rem;
- margin: 1rem 0;
- overflow-x: auto;
- position: relative;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
-}
+ details .details-content {
+ padding: 1rem;
+ background-color: white;
+ border-radius: 0 0 8px 8px;
+ }
-.custom-code-block::before {
- content: attr(data-language);
- position: absolute;
- top: 0;
- right: 0;
- padding: 0.25rem 0.75rem;
- background-color: #333;
- border-radius: 0 6px 0 6px;
- font-size: 0.8rem;
- color: #fff;
- opacity: 0.8;
-}
+ /* =============================================
+ CODE BLOCK STYLING
+ ============================================= */
+
+ /* Custom code blocks */
+ .custom-code-block {
+ background-color: #1e1e1e;
+ border: 1px solid #333;
+ border-radius: 6px;
+ padding: 1rem;
+ margin: 1rem 0;
+ overflow-x: auto;
+ position: relative;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ }
-.custom-code-block code {
- background: none;
- padding: 0;
- font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
- font-size: 0.9rem;
- line-height: 1.5;
- color: #f8f8f2;
-}
+ .custom-code-block::before {
+ content: attr(data-language);
+ position: absolute;
+ top: 0;
+ right: 0;
+ padding: 0.25rem 0.75rem;
+ background-color: #333;
+ border-radius: 0 6px 0 6px;
+ font-size: 0.8rem;
+ color: #fff;
+ opacity: 0.8;
+ }
-/* Syntax highlighting classes */
-.custom-code-block .keyword { color: #ff79c6; }
-.custom-code-block .string { color: #f1fa8c; }
-.custom-code-block .comment { color: #6272a4; }
-.custom-code-block .function { color: #50fa7b; }
-.custom-code-block .number { color: #bd93f9; }
-.custom-code-block .operator { color: #ff79c6; }
-
-/* =============================================
- GENERAL PAGE STYLING
- ============================================= */
-
-/* Base page layout */
-body {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
- line-height: 1.6;
- color: #333;
- max-width: 800px;
- margin: 0 auto;
- padding: 2rem;
- background-color: #fafafa;
-}
+ .custom-code-block code {
+ background: none;
+ padding: 0;
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
+ font-size: 0.9rem;
+ line-height: 1.5;
+ color: #f8f8f2;
+ }
-/* Typography */
-h1, h2, h3 {
- color: #2c3e50;
- margin-top: 2rem;
- font-weight: 600;
-}
+ /* Syntax highlighting classes */
+ .custom-code-block .keyword { color: #ff79c6; }
+ .custom-code-block .string { color: #f1fa8c; }
+ .custom-code-block .comment { color: #6272a4; }
+ .custom-code-block .function { color: #50fa7b; }
+ .custom-code-block .number { color: #bd93f9; }
+ .custom-code-block .operator { color: #ff79c6; }
-h1 {
- border-bottom: 2px solid #2c3e50;
- padding-bottom: 0.5rem;
- font-size: 2.2rem;
-}
+ /* =============================================
+ GENERAL PAGE STYLING
+ ============================================= */
-h2 {
- font-size: 1.8rem;
- border-bottom: 1px solid #eaecef;
- padding-bottom: 0.3rem;
-}
+ /* Base page layout */
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+ line-height: 1.6;
+ color: #333;
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 2rem;
+ background-color: #fafafa;
+ }
-h3 {
- font-size: 1.4rem;
-}
+ /* Typography */
+ h1, h2, h3 {
+ color: #2c3e50;
+ margin-top: 2rem;
+ font-weight: 600;
+ }
-p {
- margin: 1rem 0;
-}
+ h1 {
+ border-bottom: 2px solid #2c3e50;
+ padding-bottom: 0.5rem;
+ font-size: 2.2rem;
+ }
-/* Inline code */
-code {
- background-color: #f0f0f0;
- padding: 0.2rem 0.4rem;
- border-radius: 3px;
- font-size: 0.9em;
- border: 1px solid #e0e0e0;
- color: #e53935;
-}
+ h2 {
+ font-size: 1.8rem;
+ border-bottom: 1px solid #eaecef;
+ padding-bottom: 0.3rem;
+ }
-/* Links */
-a {
- color: #2196f3;
- text-decoration: none;
- transition: color 0.2s;
-}
+ h3 {
+ font-size: 1.4rem;
+ }
-a:hover {
- color: #0d47a1;
- text-decoration: underline;
-}
+ p {
+ margin: 1rem 0;
+ }
-/* Lists */
-ul, ol {
- padding-left: 1.5rem;
-}
+ /* Inline code */
+ code {
+ background-color: #f0f0f0;
+ padding: 0.2rem 0.4rem;
+ border-radius: 3px;
+ font-size: 0.9em;
+ border: 1px solid #e0e0e0;
+ color: #e53935;
+ }
-li {
- margin: 0.5rem 0;
-}
+ /* Links */
+ a {
+ color: #2196f3;
+ text-decoration: none;
+ transition: color 0.2s;
+ }
-/* Horizontal rule */
-hr {
- border: 0;
- border-top: 1px solid #eaecef;
- margin: 2rem 0;
-}
+ a:hover {
+ color: #0d47a1;
+ text-decoration: underline;
+ }
-/* Print styles */
-@media print {
- body {
- padding: 0;
- background: white;
+ /* Lists */
+ ul, ol {
+ padding-left: 1.5rem;
+ }
+
+ li {
+ margin: 0.5rem 0;
+ }
+
+ /* Horizontal rule */
+ hr {
+ border: 0;
+ border-top: 1px solid #eaecef;
+ margin: 2rem 0;
}
- .custom-warning, .custom-info, details {
- break-inside: avoid;
+ /* Print styles */
+ @media print {
+ body {
+ padding: 0;
+ background: white;
+ }
+
+ .custom-warning, .custom-info, details {
+ break-inside: avoid;
+ }
}
}
diff --git a/examples/markdown-settings/src/root.layout.js b/examples/markdown-settings/src/root.layout.js
index d7a3d12d..dc2f9d85 100644
--- a/examples/markdown-settings/src/root.layout.js
+++ b/examples/markdown-settings/src/root.layout.js
@@ -4,6 +4,7 @@ export default function rootLayout ({ title, styles, scripts, children }) {
+
${title || 'Markdown-it Settings Example'}
${styles.map(style => ``).join('\n ')}
diff --git a/examples/nested-dest/global.css b/examples/nested-dest/global.css
index f897c317..d39695d6 100644
--- a/examples/nested-dest/global.css
+++ b/examples/nested-dest/global.css
@@ -1,4 +1,8 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
+@layer mine, domstack.global, domstack.layout, domstack.page;
-/* Just consuming some dependencies for the nested example */
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
+
+@layer domstack.global {
+ /* Just consuming some dependencies for the nested example */
+}
diff --git a/examples/nested-dest/package.json b/examples/nested-dest/package.json
index 5b42a6ae..f2a819e4 100644
--- a/examples/nested-dest/package.json
+++ b/examples/nested-dest/package.json
@@ -15,7 +15,7 @@
"license": "MIT",
"dependencies": {
"@domstack/static": "file:../../.",
- "mine.css": "^9.0.1"
+ "mine.css": "^11.0.6"
},
"devDependencies": {
"npm-run-all2": "^6.0.0"
diff --git a/examples/preact-isomorphic/package.json b/examples/preact-isomorphic/package.json
index f5ce3582..0ef756aa 100644
--- a/examples/preact-isomorphic/package.json
+++ b/examples/preact-isomorphic/package.json
@@ -14,7 +14,7 @@
"@preact/signals": "^2.0.0",
"highlight.js": "^11.9.0",
"htm": "^3.1.1",
- "mine.css": "^9.0.1",
+ "mine.css": "^11.0.6",
"preact": "^10.24.0",
"preact-render-to-string": "^6.5.11",
"@domstack/static": "file:../../."
diff --git a/examples/preact-isomorphic/src/globals/global.client.ts b/examples/preact-isomorphic/src/globals/global.client.ts
deleted file mode 100644
index 20121a79..00000000
--- a/examples/preact-isomorphic/src/globals/global.client.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { toggleTheme } from 'mine.css'
-window.toggleTheme = toggleTheme
diff --git a/examples/preact-isomorphic/src/globals/global.css b/examples/preact-isomorphic/src/globals/global.css
index 84d5e65b..e1ca9f76 100644
--- a/examples/preact-isomorphic/src/globals/global.css
+++ b/examples/preact-isomorphic/src/globals/global.css
@@ -1,3 +1,6 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
-@import 'highlight.js/styles/github-dark-dimmed.css';
+@layer mine, domstack.global, domstack.layout, domstack.page;
+
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
+@import 'highlight.js/styles/github.css' layer(domstack.global);
+@import url('highlight.js/styles/github-dark-dimmed.css') layer(domstack.global) (prefers-color-scheme: dark);
diff --git a/examples/preact-isomorphic/src/isomorphic/style.css b/examples/preact-isomorphic/src/isomorphic/style.css
index f3c7d43e..bd12c920 100644
--- a/examples/preact-isomorphic/src/isomorphic/style.css
+++ b/examples/preact-isomorphic/src/isomorphic/style.css
@@ -1,167 +1,169 @@
-/* ===== Isomorphic Example Styles ===== */
-
-.isomorphic-container {
- max-width: 800px;
- margin: 0 auto;
- padding: 1rem;
-}
-
-.app-header {
- margin-bottom: 1.5rem;
- padding-bottom: 0.5rem;
- border-bottom: 2px solid var(--accent-midground);
-}
-
-.app-header h1 {
- margin-bottom: 0.5rem;
-}
-
-.app-header .subtitle {
- font-style: italic;
-}
-
-.todo-app {
- background-color: var(--layer-background);
- border-radius: 8px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
- padding: 1.5rem;
- margin-bottom: 2rem;
-}
-
-.todo-form {
- display: flex;
- margin-bottom: 1rem;
-}
-
-.todo-form input {
- flex: 1;
- padding: 0.5rem;
- border: 1px solid var(--accent-midground);
- border-radius: 4px 0 0 4px;
- background-color: var(--background);
- color: var(--text);
-}
-
-.todo-form button {
- padding: 0.5rem 1rem;
- background-color: #4a8fe7;
- color: white;
- border: none;
- border-radius: 0 4px 4px 0;
- cursor: pointer;
-}
-
-.todo-form button:hover {
- background-color: #3a7fd7;
-}
-
-.todo-list {
- list-style: none;
- padding: 0;
- margin: 0 0 1rem 0;
-}
-
-.todo-item {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0.75rem;
- border-bottom: 1px solid var(--accent-midground);
-}
-
-.todo-item:last-child {
- border-bottom: none;
-}
-
-.todo-item.completed .todo-text {
- text-decoration: line-through;
- opacity: 0.6;
-}
-
-.todo-label {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- flex: 1;
-}
-
-.delete-btn {
- background-color: #ff5252;
- color: white;
- border: none;
- border-radius: 4px;
- padding: 0.25rem 0.5rem;
- font-size: 0.8rem;
- cursor: pointer;
-}
-
-.delete-btn:hover {
- background-color: #ff0000;
-}
-
-.todo-stats {
- font-size: 0.9rem;
- margin-bottom: 1rem;
-}
-
-.counter-widget {
- background-color: var(--accent-background);
- border-radius: 6px;
- padding: 1rem;
- margin-top: 1rem;
-}
-
-.counter-widget h3 {
- margin-top: 0;
- margin-bottom: 0.5rem;
- font-size: 1.1rem;
-}
-
-.counter-display {
- display: flex;
- justify-content: space-between;
- padding: 0.5rem;
- margin-bottom: 0.5rem;
- background-color: var(--background);
- border-radius: 4px;
- transition: background-color 0.2s;
-}
-
-.counter-display.even {
- background-color: rgba(173, 216, 230, 0.2);
-}
-
-.counter-display.odd {
- background-color: rgba(255, 228, 181, 0.2);
-}
-
-.counter-controls {
- display: flex;
- gap: 0.5rem;
-}
-
-.counter-controls button {
- flex: 1;
- padding: 0.5rem;
- border: none;
- border-radius: 4px;
- background-color: #4a8fe7;
- color: white;
- cursor: pointer;
-}
-
-.counter-controls button:hover {
- background-color: #3a7fd7;
-}
-
-.info-panel {
- background-color: var(--accent-background);
- border-left: 4px solid #4a8fe7;
- padding: 1rem;
- border-radius: 0 4px 4px 0;
-}
-
-.info-panel h2 {
- margin-top: 0;
- font-size: 1.2rem;
+@layer domstack.page {
+ /* ===== Isomorphic Example Styles ===== */
+
+ .isomorphic-container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 1rem;
+ }
+
+ .app-header {
+ margin-bottom: 1.5rem;
+ padding-bottom: 0.5rem;
+ border-bottom: 2px solid var(--accent-midground);
+ }
+
+ .app-header h1 {
+ margin-bottom: 0.5rem;
+ }
+
+ .app-header .subtitle {
+ font-style: italic;
+ }
+
+ .todo-app {
+ background-color: var(--layer-background);
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+ padding: 1.5rem;
+ margin-bottom: 2rem;
+ }
+
+ .todo-form {
+ display: flex;
+ margin-bottom: 1rem;
+ }
+
+ .todo-form input {
+ flex: 1;
+ padding: 0.5rem;
+ border: 1px solid var(--accent-midground);
+ border-radius: 4px 0 0 4px;
+ background-color: var(--background);
+ color: var(--text);
+ }
+
+ .todo-form button {
+ padding: 0.5rem 1rem;
+ background-color: #4a8fe7;
+ color: white;
+ border: none;
+ border-radius: 0 4px 4px 0;
+ cursor: pointer;
+ }
+
+ .todo-form button:hover {
+ background-color: #3a7fd7;
+ }
+
+ .todo-list {
+ list-style: none;
+ padding: 0;
+ margin: 0 0 1rem 0;
+ }
+
+ .todo-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.75rem;
+ border-bottom: 1px solid var(--accent-midground);
+ }
+
+ .todo-item:last-child {
+ border-bottom: none;
+ }
+
+ .todo-item.completed .todo-text {
+ text-decoration: line-through;
+ opacity: 0.6;
+ }
+
+ .todo-label {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ flex: 1;
+ }
+
+ .delete-btn {
+ background-color: #ff5252;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ padding: 0.25rem 0.5rem;
+ font-size: 0.8rem;
+ cursor: pointer;
+ }
+
+ .delete-btn:hover {
+ background-color: #ff0000;
+ }
+
+ .todo-stats {
+ font-size: 0.9rem;
+ margin-bottom: 1rem;
+ }
+
+ .counter-widget {
+ background-color: var(--accent-background);
+ border-radius: 6px;
+ padding: 1rem;
+ margin-top: 1rem;
+ }
+
+ .counter-widget h3 {
+ margin-top: 0;
+ margin-bottom: 0.5rem;
+ font-size: 1.1rem;
+ }
+
+ .counter-display {
+ display: flex;
+ justify-content: space-between;
+ padding: 0.5rem;
+ margin-bottom: 0.5rem;
+ background-color: var(--background);
+ border-radius: 4px;
+ transition: background-color 0.2s;
+ }
+
+ .counter-display.even {
+ background-color: rgba(173, 216, 230, 0.2);
+ }
+
+ .counter-display.odd {
+ background-color: rgba(255, 228, 181, 0.2);
+ }
+
+ .counter-controls {
+ display: flex;
+ gap: 0.5rem;
+ }
+
+ .counter-controls button {
+ flex: 1;
+ padding: 0.5rem;
+ border: none;
+ border-radius: 4px;
+ background-color: #4a8fe7;
+ color: white;
+ cursor: pointer;
+ }
+
+ .counter-controls button:hover {
+ background-color: #3a7fd7;
+ }
+
+ .info-panel {
+ background-color: var(--accent-background);
+ border-left: 4px solid #4a8fe7;
+ padding: 1rem;
+ border-radius: 0 4px 4px 0;
+ }
+
+ .info-panel h2 {
+ margin-top: 0;
+ font-size: 1.2rem;
+ }
}
diff --git a/examples/preact-isomorphic/src/jsx-page/style.css b/examples/preact-isomorphic/src/jsx-page/style.css
index 08e2a6b6..c9df75e9 100644
--- a/examples/preact-isomorphic/src/jsx-page/style.css
+++ b/examples/preact-isomorphic/src/jsx-page/style.css
@@ -1,234 +1,236 @@
-/* ===== JSX Page Styles ===== */
-
-.jsx-page-container {
- max-width: 800px;
- margin: 0 auto;
- padding: 1rem;
-}
-
-.explanation-section,
-.demo-section,
-.code-reference {
- margin-bottom: 2rem;
-}
-
-.key-points {
- background-color: var(--accent-background);
- padding: 1rem;
- border-radius: 6px;
- margin: 1rem 0;
-}
-
-.key-points h3 {
- margin-top: 0;
-}
-
-.key-points ul {
- margin-bottom: 0;
-}
-
-.jsx-demo {
- background-color: var(--layer-background);
- border-radius: 8px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
- padding: 1.5rem;
- transition: background-color 0.3s, color 0.3s;
-}
-
-/* Custom dark theme for the demo component - separate from the system dark mode */
-.jsx-demo.dark-theme {
- background-color: #222;
- color: #eee;
-}
-
-.theme-toggle {
- margin-bottom: 1.5rem;
- text-align: right;
-}
-
-.theme-toggle button {
- background-color: #4a8fe7;
- color: white;
- border: none;
- border-radius: 4px;
- padding: 0.5rem 1rem;
- cursor: pointer;
- font-weight: 500;
- transition: all 0.2s ease;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
-.theme-toggle button:hover {
- background-color: #3a7fd7;
- transform: translateY(-1px);
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
-}
-
-.theme-toggle button:active {
- transform: translateY(1px);
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
-}
-
-.jsx-demo.dark-theme .theme-toggle button {
- background-color: #f1c40f;
- color: #222;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
-}
-
-.jsx-demo.dark-theme .theme-toggle button:hover {
- background-color: #f4d03f;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
-}
-
-/* Counter section button styles */
-.counter-section .counter-controls {
- display: flex;
- gap: 0.75rem;
- margin-top: 1rem;
-}
-
-.counter-section .counter-controls button {
- padding: 0.5rem 1rem;
- background-color: #4a8fe7;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- font-weight: 500;
- transition: all 0.2s ease;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- flex: 1;
-}
-
-.counter-section .counter-controls button:hover:not([disabled]) {
- background-color: #3a7fd7;
- transform: translateY(-1px);
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
-}
-
-.counter-section .counter-controls button:active:not([disabled]) {
- transform: translateY(1px);
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
-}
-
-.counter-section .counter-controls button:disabled {
- background-color: var(--accent-midground);
- cursor: not-allowed;
- opacity: 0.7;
-}
-
-.jsx-demo.dark-theme .counter-section .counter-controls button {
- background-color: #4a8fe7;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
- color: white;
-}
-
-.jsx-demo.dark-theme .counter-section .counter-controls button:hover:not([disabled]) {
- background-color: #3a7fd7;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
-}
-
-.jsx-demo.dark-theme .counter-section .counter-controls button:disabled {
- background-color: #555;
-}
-
-.counter-section,
-.profiles-section,
-.explanation {
- margin-bottom: 2rem;
- padding-bottom: 1.5rem;
- border-bottom: 1px solid var(--accent-midground);
-}
-
-.jsx-demo.dark-theme .counter-section,
-.jsx-demo.dark-theme .profiles-section,
-.jsx-demo.dark-theme .explanation {
- border-bottom-color: #444;
-}
-
-.counter-section h3,
-.profiles-section h3,
-.explanation h3 {
- margin-top: 0;
- margin-bottom: 1rem;
- font-weight: 600;
-}
-
-.profiles-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
- gap: 1rem;
- margin-top: 1rem;
-}
-
-.profile-card {
- background-color: var(--accent-background);
- border-radius: 8px;
- overflow: hidden;
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
- cursor: pointer;
- transition: transform 0.2s, box-shadow 0.2s;
- margin-bottom: 0.5rem;
- height: 100%;
-}
-
-.jsx-demo.dark-theme .profile-card {
- background-color: #333;
-}
-
-.profile-card:hover {
- transform: translateY(-3px);
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
-}
-
-.profile-header {
- padding: 1rem;
- position: relative;
- display: flex;
- justify-content: center;
- background-color: var(--accent-midground);
-}
-
-.jsx-demo.dark-theme .profile-header {
- background-color: #444;
-}
-
-.avatar {
- width: 64px;
- height: 64px;
- border-radius: 50%;
- object-fit: cover;
-}
-
-.status-indicator {
- position: absolute;
- bottom: 1rem;
- right: calc(50% - 40px);
- width: 12px;
- height: 12px;
- border-radius: 50%;
- border: 2px solid var(--background);
-}
-
-.status-indicator.active {
- background-color: #4caf50;
-}
-
-.status-indicator.inactive {
- background-color: #ccc;
-}
-
-.profile-info {
- padding: 1rem;
- text-align: center;
-}
-
-.profile-info h3 {
- margin: 0 0 0.25rem 0;
- font-size: 1.1rem;
-}
-
-.profile-info .role {
- margin: 0;
- font-size: 0.9rem;
+@layer domstack.page {
+ /* ===== JSX Page Styles ===== */
+
+ .jsx-page-container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 1rem;
+ }
+
+ .explanation-section,
+ .demo-section,
+ .code-reference {
+ margin-bottom: 2rem;
+ }
+
+ .key-points {
+ background-color: var(--accent-background);
+ padding: 1rem;
+ border-radius: 6px;
+ margin: 1rem 0;
+ }
+
+ .key-points h3 {
+ margin-top: 0;
+ }
+
+ .key-points ul {
+ margin-bottom: 0;
+ }
+
+ .jsx-demo {
+ background-color: var(--layer-background);
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+ padding: 1.5rem;
+ transition: background-color 0.3s, color 0.3s;
+ }
+
+ /* Custom dark theme for the demo component - separate from the system dark mode */
+ .jsx-demo.dark-theme {
+ background-color: #222;
+ color: #eee;
+ }
+
+ .theme-toggle {
+ margin-bottom: 1.5rem;
+ text-align: right;
+ }
+
+ .theme-toggle button {
+ background-color: #4a8fe7;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ padding: 0.5rem 1rem;
+ cursor: pointer;
+ font-weight: 500;
+ transition: all 0.2s ease;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ }
+
+ .theme-toggle button:hover {
+ background-color: #3a7fd7;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+ }
+
+ .theme-toggle button:active {
+ transform: translateY(1px);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+ }
+
+ .jsx-demo.dark-theme .theme-toggle button {
+ background-color: #f1c40f;
+ color: #222;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
+ }
+
+ .jsx-demo.dark-theme .theme-toggle button:hover {
+ background-color: #f4d03f;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
+ }
+
+ /* Counter section button styles */
+ .counter-section .counter-controls {
+ display: flex;
+ gap: 0.75rem;
+ margin-top: 1rem;
+ }
+
+ .counter-section .counter-controls button {
+ padding: 0.5rem 1rem;
+ background-color: #4a8fe7;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ font-weight: 500;
+ transition: all 0.2s ease;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ flex: 1;
+ }
+
+ .counter-section .counter-controls button:hover:not([disabled]) {
+ background-color: #3a7fd7;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+ }
+
+ .counter-section .counter-controls button:active:not([disabled]) {
+ transform: translateY(1px);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+ }
+
+ .counter-section .counter-controls button:disabled {
+ background-color: var(--accent-midground);
+ cursor: not-allowed;
+ opacity: 0.7;
+ }
+
+ .jsx-demo.dark-theme .counter-section .counter-controls button {
+ background-color: #4a8fe7;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
+ color: white;
+ }
+
+ .jsx-demo.dark-theme .counter-section .counter-controls button:hover:not([disabled]) {
+ background-color: #3a7fd7;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
+ }
+
+ .jsx-demo.dark-theme .counter-section .counter-controls button:disabled {
+ background-color: #555;
+ }
+
+ .counter-section,
+ .profiles-section,
+ .explanation {
+ margin-bottom: 2rem;
+ padding-bottom: 1.5rem;
+ border-bottom: 1px solid var(--accent-midground);
+ }
+
+ .jsx-demo.dark-theme .counter-section,
+ .jsx-demo.dark-theme .profiles-section,
+ .jsx-demo.dark-theme .explanation {
+ border-bottom-color: #444;
+ }
+
+ .counter-section h3,
+ .profiles-section h3,
+ .explanation h3 {
+ margin-top: 0;
+ margin-bottom: 1rem;
+ font-weight: 600;
+ }
+
+ .profiles-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
+ gap: 1rem;
+ margin-top: 1rem;
+ }
+
+ .profile-card {
+ background-color: var(--accent-background);
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
+ cursor: pointer;
+ transition: transform 0.2s, box-shadow 0.2s;
+ margin-bottom: 0.5rem;
+ height: 100%;
+ }
+
+ .jsx-demo.dark-theme .profile-card {
+ background-color: #333;
+ }
+
+ .profile-card:hover {
+ transform: translateY(-3px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+ }
+
+ .profile-header {
+ padding: 1rem;
+ position: relative;
+ display: flex;
+ justify-content: center;
+ background-color: var(--accent-midground);
+ }
+
+ .jsx-demo.dark-theme .profile-header {
+ background-color: #444;
+ }
+
+ .avatar {
+ width: 64px;
+ height: 64px;
+ border-radius: 50%;
+ object-fit: cover;
+ }
+
+ .status-indicator {
+ position: absolute;
+ bottom: 1rem;
+ right: calc(50% - 40px);
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ border: 2px solid var(--background);
+ }
+
+ .status-indicator.active {
+ background-color: #4caf50;
+ }
+
+ .status-indicator.inactive {
+ background-color: #ccc;
+ }
+
+ .profile-info {
+ padding: 1rem;
+ text-align: center;
+ }
+
+ .profile-info h3 {
+ margin: 0 0 0.25rem 0;
+ font-size: 1.1rem;
+ }
+
+ .profile-info .role {
+ margin: 0;
+ font-size: 0.9rem;
+ }
}
diff --git a/examples/preact-isomorphic/src/layouts/root.layout.ts b/examples/preact-isomorphic/src/layouts/root.layout.ts
index e4a03d6a..75cf3fc7 100644
--- a/examples/preact-isomorphic/src/layouts/root.layout.ts
+++ b/examples/preact-isomorphic/src/layouts/root.layout.ts
@@ -53,6 +53,7 @@ export default function defaultRootLayout({
${title ? `${title}` : ''}${title && siteName ? ' | ' : ''}${siteName}
+
${scripts
? scripts.map(script => html``)
: null}
diff --git a/examples/react/package.json b/examples/react/package.json
index a4d06664..70cd5a86 100644
--- a/examples/react/package.json
+++ b/examples/react/package.json
@@ -14,7 +14,7 @@
"dependencies": {
"@domstack/static": "file:../../.",
"htm": "^3.1.1",
- "mine.css": "^9.0.1",
+ "mine.css": "^11.0.6",
"react": "^19.1.1"
},
"devDependencies": {
diff --git a/examples/react/src/globals/global.client.ts b/examples/react/src/globals/global.client.ts
index 782a44d7..3e0839b4 100644
--- a/examples/react/src/globals/global.client.ts
+++ b/examples/react/src/globals/global.client.ts
@@ -53,20 +53,7 @@ window.domstackUtils = {
}
};
-// Add dark mode detection
-const prefersDarkMode: MediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');
-if (prefersDarkMode.matches) {
- document.body.classList.add('dark-mode-preferred');
-}
-// Listen for dark mode changes
-prefersDarkMode.addEventListener('change', (e: MediaQueryListEvent): void => {
- if (e.matches) {
- document.body.classList.add('dark-mode-preferred');
- } else {
- document.body.classList.remove('dark-mode-preferred');
- }
-});
// Example of measuring and logging performance
const pageLoadTime: number = performance.now();
diff --git a/examples/react/src/globals/global.css b/examples/react/src/globals/global.css
index 06985a02..dba7649c 100644
--- a/examples/react/src/globals/global.css
+++ b/examples/react/src/globals/global.css
@@ -1,120 +1,125 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
-@import 'highlight.js/styles/github-dark-dimmed.css';
-
-/* Custom React Example Styles */
-:root {
- --primary-color: #61dafb;
- --secondary-color: #282c34;
- --text-color: #333;
- --background-color: #f5f5f5;
- --card-background: #fff;
- --success-color: #4caf50;
- --warning-color: #ff9800;
- --error-color: #f44336;
-}
-
-body {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
- Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
- color: var(--text-color);
- background-color: var(--background-color);
- line-height: 1.6;
-}
+@layer mine, domstack.global, domstack.layout, domstack.page;
+
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
+@import 'highlight.js/styles/github.css' layer(domstack.global);
+@import url('highlight.js/styles/github-dark-dimmed.css') layer(domstack.global) (prefers-color-scheme: dark);
+
+@layer domstack.global {
+ /* Custom React Example Styles */
+ :root {
+ --primary-color: #61dafb;
+ --secondary-color: #282c34;
+ --text-color: #333;
+ --background-color: #f5f5f5;
+ --card-background: #fff;
+ --success-color: #4caf50;
+ --warning-color: #ff9800;
+ --error-color: #f44336;
+ }
-.app-container {
- max-width: 800px;
- margin: 0 auto;
- padding: 2rem;
-}
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
+ Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+ color: var(--text-color);
+ background-color: var(--background-color);
+ line-height: 1.6;
+ }
-.react-demo {
- background-color: var(--card-background);
- border-radius: 8px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
- padding: 1.5rem;
- margin-bottom: 2rem;
-}
+ .app-container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 2rem;
+ }
-.react-header {
- display: flex;
- align-items: center;
- margin-bottom: 1.5rem;
-}
+ .react-demo {
+ background-color: var(--card-background);
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+ padding: 1.5rem;
+ margin-bottom: 2rem;
+ }
-.react-logo {
- animation: spin 10s linear infinite;
- height: 40px;
- margin-right: 1rem;
-}
+ .react-header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 1.5rem;
+ }
-@keyframes spin {
- from {
- transform: rotate(0deg);
+ .react-logo {
+ animation: spin 10s linear infinite;
+ height: 40px;
+ margin-right: 1rem;
}
- to {
- transform: rotate(360deg);
+
+ @keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
}
-}
-.button {
- background-color: var(--primary-color);
- color: var(--secondary-color);
- border: none;
- border-radius: 4px;
- padding: 0.5rem 1rem;
- font-size: 1rem;
- cursor: pointer;
- transition: background-color 0.2s, transform 0.1s;
-}
+ .button {
+ background-color: var(--primary-color);
+ color: var(--secondary-color);
+ border: none;
+ border-radius: 4px;
+ padding: 0.5rem 1rem;
+ font-size: 1rem;
+ cursor: pointer;
+ transition: background-color 0.2s, transform 0.1s;
+ }
-.button:hover {
- background-color: #4ac0e0;
- transform: translateY(-1px);
-}
+ .button:hover {
+ background-color: #4ac0e0;
+ transform: translateY(-1px);
+ }
-.button:active {
- transform: translateY(1px);
-}
+ .button:active {
+ transform: translateY(1px);
+ }
-.button-group {
- display: flex;
- gap: 0.5rem;
- margin: 1rem 0;
-}
+ .button-group {
+ display: flex;
+ gap: 0.5rem;
+ margin: 1rem 0;
+ }
-.card {
- border-radius: 6px;
- border: 1px solid #eee;
- padding: 1rem;
- margin-bottom: 1rem;
- transition: box-shadow 0.2s;
-}
+ .card {
+ border-radius: 6px;
+ border: 1px solid #eee;
+ padding: 1rem;
+ margin-bottom: 1rem;
+ transition: box-shadow 0.2s;
+ }
-.card:hover {
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
-}
+ .card:hover {
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ }
-.info-panel {
- background-color: rgba(97, 218, 251, 0.1);
- border-left: 4px solid var(--primary-color);
- padding: 1rem;
- margin: 1rem 0;
- border-radius: 0 4px 4px 0;
-}
+ .info-panel {
+ background-color: rgba(97, 218, 251, 0.1);
+ border-left: 4px solid var(--primary-color);
+ padding: 1rem;
+ margin: 1rem 0;
+ border-radius: 0 4px 4px 0;
+ }
-/* Form elements */
-input, select, textarea {
- padding: 0.5rem;
- border: 1px solid #ddd;
- border-radius: 4px;
- font-size: 1rem;
- width: 100%;
- margin-bottom: 1rem;
-}
+ /* Form elements */
+ input, select, textarea {
+ padding: 0.5rem;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 1rem;
+ width: 100%;
+ margin-bottom: 1rem;
+ }
-input:focus, select:focus, textarea:focus {
- outline: none;
- border-color: var(--primary-color);
- box-shadow: 0 0 0 2px rgba(97, 218, 251, 0.2);
+ input:focus, select:focus, textarea:focus {
+ outline: none;
+ border-color: var(--primary-color);
+ box-shadow: 0 0 0 2px rgba(97, 218, 251, 0.2);
+ }
}
diff --git a/examples/react/src/layouts/root.layout.ts b/examples/react/src/layouts/root.layout.ts
index a06208eb..a5a58d0f 100644
--- a/examples/react/src/layouts/root.layout.ts
+++ b/examples/react/src/layouts/root.layout.ts
@@ -40,6 +40,7 @@ export default function rootLayout({
${`${title ? `${title}` : ''}${title && siteName ? ' | ' : ''}${siteName}`}
+
${scripts
? scripts.map(script => html``)
diff --git a/examples/string-layouts/src/root.layout.js b/examples/string-layouts/src/root.layout.js
index b82e3192..0c6a560a 100644
--- a/examples/string-layouts/src/root.layout.js
+++ b/examples/string-layouts/src/root.layout.js
@@ -18,6 +18,7 @@ export default async function RootLayout ({
${siteName || ''}${title ? ` | ${title}` : ''}
+
${scripts
? scripts.map(script => /* html */``).join('\n ')
: ''}
diff --git a/examples/tailwind/src/globals/global.css b/examples/tailwind/src/globals/global.css
index 3fbea23b..7e8bd119 100644
--- a/examples/tailwind/src/globals/global.css
+++ b/examples/tailwind/src/globals/global.css
@@ -1,3 +1,4 @@
+@layer mine, domstack.global, domstack.layout, domstack.page;
@import "tailwindcss";
@plugin "@tailwindcss/typography";
diff --git a/examples/tailwind/src/layouts/root.layout.js b/examples/tailwind/src/layouts/root.layout.js
index 76167838..6785257f 100644
--- a/examples/tailwind/src/layouts/root.layout.js
+++ b/examples/tailwind/src/layouts/root.layout.js
@@ -35,6 +35,7 @@ export default function defaultRootLayout ({
${title ? `${title}` : ''}${title && siteName ? ' | ' : ''}${siteName}
+
${scripts
? scripts.map(script => html``)
: null}
diff --git a/examples/type-stripping/package.json b/examples/type-stripping/package.json
index f5ce3582..0ef756aa 100644
--- a/examples/type-stripping/package.json
+++ b/examples/type-stripping/package.json
@@ -14,7 +14,7 @@
"@preact/signals": "^2.0.0",
"highlight.js": "^11.9.0",
"htm": "^3.1.1",
- "mine.css": "^9.0.1",
+ "mine.css": "^11.0.6",
"preact": "^10.24.0",
"preact-render-to-string": "^6.5.11",
"@domstack/static": "file:../../."
diff --git a/examples/type-stripping/src/globals/global.client.ts b/examples/type-stripping/src/globals/global.client.ts
deleted file mode 100644
index 63290d7e..00000000
--- a/examples/type-stripping/src/globals/global.client.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { toggleTheme } from 'mine.css'
-// @ts-ignore
-window.toggleTheme = toggleTheme
diff --git a/examples/type-stripping/src/globals/global.css b/examples/type-stripping/src/globals/global.css
index 84d5e65b..e1ca9f76 100644
--- a/examples/type-stripping/src/globals/global.css
+++ b/examples/type-stripping/src/globals/global.css
@@ -1,3 +1,6 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
-@import 'highlight.js/styles/github-dark-dimmed.css';
+@layer mine, domstack.global, domstack.layout, domstack.page;
+
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
+@import 'highlight.js/styles/github.css' layer(domstack.global);
+@import url('highlight.js/styles/github-dark-dimmed.css') layer(domstack.global) (prefers-color-scheme: dark);
diff --git a/examples/type-stripping/src/isomorphic/style.css b/examples/type-stripping/src/isomorphic/style.css
index 8d1715c7..f2a2955e 100644
--- a/examples/type-stripping/src/isomorphic/style.css
+++ b/examples/type-stripping/src/isomorphic/style.css
@@ -1,275 +1,277 @@
-/* Isomorphic Task Manager Styles */
-
-.task-manager {
- max-width: 800px;
- margin: 0 auto;
- padding: 2rem;
- font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
-}
-
-.app-header {
- text-align: center;
- margin-bottom: 2rem;
- padding-bottom: 1rem;
- border-bottom: 1px solid #eaeaea;
-}
-
-.app-header h1 {
- margin: 0 0 0.5rem;
- color: #333;
-}
-
-.app-header p {
- margin: 0;
- color: #666;
- font-size: 1rem;
-}
-
-/* Task Form */
-.task-form {
- margin-bottom: 2rem;
-}
+@layer domstack.page {
+ /* Isomorphic Task Manager Styles */
+
+ .task-manager {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 2rem;
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+ }
-.form-group {
- display: flex;
- gap: 0.5rem;
-}
+ .app-header {
+ text-align: center;
+ margin-bottom: 2rem;
+ padding-bottom: 1rem;
+ border-bottom: 1px solid #eaeaea;
+ }
-.task-form input {
- flex: 1;
- padding: 0.75rem;
- border: 1px solid #ddd;
- border-radius: 4px;
- font-size: 1rem;
-}
+ .app-header h1 {
+ margin: 0 0 0.5rem;
+ color: #333;
+ }
-.task-form input.error {
- border-color: #e74c3c;
-}
+ .app-header p {
+ margin: 0;
+ color: #666;
+ font-size: 1rem;
+ }
-.task-form select {
- width: 150px;
- padding: 0.75rem;
- border: 1px solid #ddd;
- border-radius: 4px;
- background-color: white;
-}
+ /* Task Form */
+ .task-form {
+ margin-bottom: 2rem;
+ }
-.task-form button {
- background-color: #3498db;
- color: white;
- border: none;
- border-radius: 4px;
- padding: 0.75rem 1.5rem;
- cursor: pointer;
- font-weight: 600;
-}
+ .form-group {
+ display: flex;
+ gap: 0.5rem;
+ }
-.task-form button:hover {
- background-color: #2980b9;
-}
+ .task-form input {
+ flex: 1;
+ padding: 0.75rem;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 1rem;
+ }
-.task-form button:disabled {
- background-color: #95a5a6;
- cursor: not-allowed;
-}
+ .task-form input.error {
+ border-color: #e74c3c;
+ }
-.error-message {
- color: #e74c3c;
- margin-top: 0.5rem;
- font-size: 0.875rem;
-}
+ .task-form select {
+ width: 150px;
+ padding: 0.75rem;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ background-color: white;
+ }
-/* Task Filters */
-.task-filters {
- margin-bottom: 2rem;
- display: flex;
- gap: 2rem;
- flex-wrap: wrap;
-}
+ .task-form button {
+ background-color: #3498db;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ padding: 0.75rem 1.5rem;
+ cursor: pointer;
+ font-weight: 600;
+ }
-.filter-group h3 {
- font-size: 1rem;
- margin-top: 0;
- margin-bottom: 0.5rem;
- color: #555;
-}
+ .task-form button:hover {
+ background-color: #2980b9;
+ }
-.btn-group {
- display: flex;
- gap: 0.5rem;
-}
+ .task-form button:disabled {
+ background-color: #95a5a6;
+ cursor: not-allowed;
+ }
-.btn-group button {
- background-color: #f1f1f1;
- border: 1px solid #ddd;
- border-radius: 4px;
- padding: 0.5rem 1rem;
- cursor: pointer;
- font-size: 0.875rem;
-}
+ .error-message {
+ color: #e74c3c;
+ margin-top: 0.5rem;
+ font-size: 0.875rem;
+ }
-.btn-group button:hover {
- background-color: #e7e7e7;
-}
+ /* Task Filters */
+ .task-filters {
+ margin-bottom: 2rem;
+ display: flex;
+ gap: 2rem;
+ flex-wrap: wrap;
+ }
-.btn-group button.active {
- background-color: #2c3e50;
- color: white;
- border-color: #2c3e50;
-}
+ .filter-group h3 {
+ font-size: 1rem;
+ margin-top: 0;
+ margin-bottom: 0.5rem;
+ color: #555;
+ }
-/* Task List */
-.task-list {
- list-style: none;
- padding: 0;
- margin: 0 0 2rem;
-}
+ .btn-group {
+ display: flex;
+ gap: 0.5rem;
+ }
-.task-item {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 1rem;
- border: 1px solid #eee;
- border-radius: 4px;
- margin-bottom: 0.5rem;
- transition: all 0.2s ease;
-}
+ .btn-group button {
+ background-color: #f1f1f1;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ padding: 0.5rem 1rem;
+ cursor: pointer;
+ font-size: 0.875rem;
+ }
-.task-item:hover {
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
-}
+ .btn-group button:hover {
+ background-color: #e7e7e7;
+ }
-.task-item.completed {
- background-color: #f9f9f9;
- opacity: 0.8;
-}
+ .btn-group button.active {
+ background-color: #2c3e50;
+ color: white;
+ border-color: #2c3e50;
+ }
-.task-item.completed .task-title {
- text-decoration: line-through;
- color: #7f8c8d;
-}
+ /* Task List */
+ .task-list {
+ list-style: none;
+ padding: 0;
+ margin: 0 0 2rem;
+ }
-.task-content {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- flex: 1;
-}
+ .task-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 1rem;
+ border: 1px solid #eee;
+ border-radius: 4px;
+ margin-bottom: 0.5rem;
+ transition: all 0.2s ease;
+ }
-.task-title {
- font-size: 1rem;
- margin-right: 1rem;
-}
+ .task-item:hover {
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
+ }
-.task-priority {
- font-size: 0.75rem;
- padding: 0.25rem 0.5rem;
- border-radius: 3px;
- font-weight: 600;
- text-transform: uppercase;
-}
+ .task-item.completed {
+ background-color: #f9f9f9;
+ opacity: 0.8;
+ }
-.task-priority-high {
- border-left: 4px solid #e74c3c;
-}
+ .task-item.completed .task-title {
+ text-decoration: line-through;
+ color: #7f8c8d;
+ }
-.task-priority-high .task-priority {
- background-color: #fdedec;
- color: #e74c3c;
-}
+ .task-content {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ flex: 1;
+ }
-.task-priority-medium {
- border-left: 4px solid #f39c12;
-}
+ .task-title {
+ font-size: 1rem;
+ margin-right: 1rem;
+ }
-.task-priority-medium .task-priority {
- background-color: #fef5e7;
- color: #f39c12;
-}
+ .task-priority {
+ font-size: 0.75rem;
+ padding: 0.25rem 0.5rem;
+ border-radius: 3px;
+ font-weight: 600;
+ text-transform: uppercase;
+ }
-.task-priority-low {
- border-left: 4px solid #3498db;
-}
+ .task-priority-high {
+ border-left: 4px solid #e74c3c;
+ }
-.task-priority-low .task-priority {
- background-color: #ebf5fb;
- color: #3498db;
-}
+ .task-priority-high .task-priority {
+ background-color: #fdedec;
+ color: #e74c3c;
+ }
-.delete-btn {
- background-color: transparent;
- color: #7f8c8d;
- border: 1px solid #ddd;
- border-radius: 4px;
- padding: 0.375rem 0.75rem;
- cursor: pointer;
- font-size: 0.875rem;
-}
+ .task-priority-medium {
+ border-left: 4px solid #f39c12;
+ }
-.delete-btn:hover {
- background-color: #e74c3c;
- color: white;
- border-color: #e74c3c;
-}
+ .task-priority-medium .task-priority {
+ background-color: #fef5e7;
+ color: #f39c12;
+ }
-.no-tasks {
- text-align: center;
- color: #7f8c8d;
- font-style: italic;
- padding: 2rem;
- border: 1px dashed #ddd;
- border-radius: 4px;
-}
+ .task-priority-low {
+ border-left: 4px solid #3498db;
+ }
-/* Actions */
-.actions {
- display: flex;
- justify-content: center;
-}
+ .task-priority-low .task-priority {
+ background-color: #ebf5fb;
+ color: #3498db;
+ }
-.clear-completed {
- background-color: #ecf0f1;
- color: #34495e;
- border: none;
- border-radius: 4px;
- padding: 0.75rem 1.5rem;
- cursor: pointer;
- font-weight: 600;
-}
+ .delete-btn {
+ background-color: transparent;
+ color: #7f8c8d;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ padding: 0.375rem 0.75rem;
+ cursor: pointer;
+ font-size: 0.875rem;
+ }
-.clear-completed:hover:not(:disabled) {
- background-color: #bdc3c7;
-}
+ .delete-btn:hover {
+ background-color: #e74c3c;
+ color: white;
+ border-color: #e74c3c;
+ }
-.clear-completed:disabled {
- opacity: 0.5;
- cursor: not-allowed;
-}
+ .no-tasks {
+ text-align: center;
+ color: #7f8c8d;
+ font-style: italic;
+ padding: 2rem;
+ border: 1px dashed #ddd;
+ border-radius: 4px;
+ }
-/* Responsive adjustments */
-@media (max-width: 600px) {
- .form-group {
- flex-direction: column;
+ /* Actions */
+ .actions {
+ display: flex;
+ justify-content: center;
}
- .task-filters {
- flex-direction: column;
- gap: 1rem;
+ .clear-completed {
+ background-color: #ecf0f1;
+ color: #34495e;
+ border: none;
+ border-radius: 4px;
+ padding: 0.75rem 1.5rem;
+ cursor: pointer;
+ font-weight: 600;
}
- .task-item {
- flex-direction: column;
- align-items: flex-start;
+ .clear-completed:hover:not(:disabled) {
+ background-color: #bdc3c7;
}
- .task-content {
- margin-bottom: 0.5rem;
- width: 100%;
+ .clear-completed:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
}
- .delete-btn {
- align-self: flex-end;
+ /* Responsive adjustments */
+ @media (max-width: 600px) {
+ .form-group {
+ flex-direction: column;
+ }
+
+ .task-filters {
+ flex-direction: column;
+ gap: 1rem;
+ }
+
+ .task-item {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ .task-content {
+ margin-bottom: 0.5rem;
+ width: 100%;
+ }
+
+ .delete-btn {
+ align-self: flex-end;
+ }
}
}
diff --git a/examples/type-stripping/src/layouts/root.layout.ts b/examples/type-stripping/src/layouts/root.layout.ts
index 95d68fd5..55c9672e 100644
--- a/examples/type-stripping/src/layouts/root.layout.ts
+++ b/examples/type-stripping/src/layouts/root.layout.ts
@@ -29,6 +29,7 @@ const defaultRootLayout: DefaultRootLayout = ({
${title ? `${title}` : ''}${title && siteName ? ' | ' : ''}${siteName}
+
${scripts
? scripts.map(script => html``)
: null}
diff --git a/examples/uhtml-isomorphic/package.json b/examples/uhtml-isomorphic/package.json
index 51826e5f..aab92988 100644
--- a/examples/uhtml-isomorphic/package.json
+++ b/examples/uhtml-isomorphic/package.json
@@ -12,7 +12,7 @@
"license": "MIT",
"dependencies": {
"highlight.js": "^11.9.0",
- "mine.css": "^9.0.1",
+ "mine.css": "^11.0.6",
"uhtml-isomorphic": "^2.1.0",
"@domstack/static": "../../."
},
diff --git a/examples/uhtml-isomorphic/src/globals/global.client.js b/examples/uhtml-isomorphic/src/globals/global.client.js
deleted file mode 100644
index 4000282b..00000000
--- a/examples/uhtml-isomorphic/src/globals/global.client.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// @ts-ignore
-import { toggleTheme } from 'mine.css'
-// @ts-ignore
-window.toggleTheme = toggleTheme
diff --git a/examples/uhtml-isomorphic/src/globals/global.css b/examples/uhtml-isomorphic/src/globals/global.css
index 84d5e65b..e1ca9f76 100644
--- a/examples/uhtml-isomorphic/src/globals/global.css
+++ b/examples/uhtml-isomorphic/src/globals/global.css
@@ -1,3 +1,6 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
-@import 'highlight.js/styles/github-dark-dimmed.css';
+@layer mine, domstack.global, domstack.layout, domstack.page;
+
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
+@import 'highlight.js/styles/github.css' layer(domstack.global);
+@import url('highlight.js/styles/github-dark-dimmed.css') layer(domstack.global) (prefers-color-scheme: dark);
diff --git a/examples/uhtml-isomorphic/src/layouts/root.layout.js b/examples/uhtml-isomorphic/src/layouts/root.layout.js
index 72cf92a3..29d9725c 100644
--- a/examples/uhtml-isomorphic/src/layouts/root.layout.js
+++ b/examples/uhtml-isomorphic/src/layouts/root.layout.js
@@ -35,6 +35,7 @@ export default function defaultRootLayout ({
${title ? `${title}` : ''}${title && siteName ? ' | ' : ''}${siteName}
+
${scripts
? scripts.map(script => html``)
: null}
diff --git a/examples/worker-example/package.json b/examples/worker-example/package.json
index 44d8b27f..b6f6ad27 100644
--- a/examples/worker-example/package.json
+++ b/examples/worker-example/package.json
@@ -13,7 +13,7 @@
"author": "",
"license": "MIT",
"dependencies": {
- "mine.css": "^9.0.1",
+ "mine.css": "^11.0.6",
"@domstack/static": "file:../../."
},
"devDependencies": {
diff --git a/examples/worker-example/src/globals/global.css b/examples/worker-example/src/globals/global.css
index ddd247b0..298e3fd2 100644
--- a/examples/worker-example/src/globals/global.css
+++ b/examples/worker-example/src/globals/global.css
@@ -1,68 +1,72 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
+@layer mine, domstack.global, domstack.layout, domstack.page;
-/* Global styles for the worker example */
-body {
- font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
- Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
- line-height: 1.6;
- color: #333;
- background-color: #f8f9fa;
-}
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
-h1, h2, h3 {
- color: #0d6efd;
- margin-top: 1rem;
- margin-bottom: 1rem;
-}
+@layer domstack.global {
+ /* Global styles for the worker example */
+ body {
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
+ Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+ line-height: 1.6;
+ color: #333;
+ background-color: #f8f9fa;
+ }
-button {
- background-color: #0d6efd;
- color: white;
- border: none;
- padding: 0.5rem 1rem;
- border-radius: 0.25rem;
- cursor: pointer;
- font-size: 1rem;
- transition: background-color 0.2s;
-}
+ h1, h2, h3 {
+ color: #0d6efd;
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+ }
-button:hover {
- background-color: #0b5ed7;
-}
+ button {
+ background-color: #0d6efd;
+ color: white;
+ border: none;
+ padding: 0.5rem 1rem;
+ border-radius: 0.25rem;
+ cursor: pointer;
+ font-size: 1rem;
+ transition: background-color 0.2s;
+ }
-button:disabled {
- background-color: #6c757d;
- cursor: not-allowed;
-}
+ button:hover {
+ background-color: #0b5ed7;
+ }
-.mine-layout {
- padding: 2rem;
- max-width: 1000px;
- margin: 0 auto;
-}
+ button:disabled {
+ background-color: #6c757d;
+ cursor: not-allowed;
+ }
-a {
- color: #0d6efd;
- text-decoration: none;
-}
+ .mine-layout {
+ padding: 2rem;
+ max-width: 1000px;
+ margin: 0 auto;
+ }
-a:hover {
- text-decoration: underline;
-}
+ a {
+ color: #0d6efd;
+ text-decoration: none;
+ }
-.navigation {
- margin-bottom: 2rem;
-}
+ a:hover {
+ text-decoration: underline;
+ }
-.navigation a {
- margin-right: 1rem;
-}
+ .navigation {
+ margin-bottom: 2rem;
+ }
+
+ .navigation a {
+ margin-right: 1rem;
+ }
-.footer {
- margin-top: 3rem;
- padding-top: 1rem;
- border-top: 1px solid #dee2e6;
- text-align: center;
- color: #6c757d;
-}
\ No newline at end of file
+ .footer {
+ margin-top: 3rem;
+ padding-top: 1rem;
+ border-top: 1px solid #dee2e6;
+ text-align: center;
+ color: #6c757d;
+ }
+}
diff --git a/examples/worker-example/src/layouts/root.layout.js b/examples/worker-example/src/layouts/root.layout.js
index afe650e3..575a3430 100644
--- a/examples/worker-example/src/layouts/root.layout.js
+++ b/examples/worker-example/src/layouts/root.layout.js
@@ -19,6 +19,7 @@ export default function rootLayout ({
+
${title ? `${title} | ${siteName}` : siteName}
${styles.map(style => ``).join('\n ')}
diff --git a/examples/worker-example/src/style.css b/examples/worker-example/src/style.css
index 7b1af512..64e4dd9c 100644
--- a/examples/worker-example/src/style.css
+++ b/examples/worker-example/src/style.css
@@ -1,100 +1,102 @@
-/* Styles for the home page */
-h1 {
- color: #0d6efd;
- border-bottom: 2px solid #0d6efd;
- padding-bottom: 0.5rem;
- margin-bottom: 1.5rem;
-}
+@layer domstack.page {
+ /* Styles for the home page */
+ h1 {
+ color: #0d6efd;
+ border-bottom: 2px solid #0d6efd;
+ padding-bottom: 0.5rem;
+ margin-bottom: 1.5rem;
+ }
-h2 {
- margin-top: 2rem;
- color: #495057;
-}
+ h2 {
+ margin-top: 2rem;
+ color: #495057;
+ }
-ul {
- margin-left: 1.5rem;
- line-height: 1.6;
-}
+ ul {
+ margin-left: 1.5rem;
+ line-height: 1.6;
+ }
-code {
- background-color: #f8f9fa;
- padding: 0.2rem 0.4rem;
- border-radius: 3px;
- font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
- border: 1px solid #e9ecef;
- color: #dc3545;
-}
+ code {
+ background-color: #f8f9fa;
+ padding: 0.2rem 0.4rem;
+ border-radius: 3px;
+ font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ border: 1px solid #e9ecef;
+ color: #dc3545;
+ }
-pre {
- background-color: #f8f9fa;
- padding: 1rem;
- border-radius: 4px;
- border: 1px solid #dee2e6;
- overflow-x: auto;
- margin: 1.5rem 0;
-}
+ pre {
+ background-color: #f8f9fa;
+ padding: 1rem;
+ border-radius: 4px;
+ border: 1px solid #dee2e6;
+ overflow-x: auto;
+ margin: 1.5rem 0;
+ }
-pre code {
- background-color: transparent;
- padding: 0;
- border: none;
- color: #212529;
-}
+ pre code {
+ background-color: transparent;
+ padding: 0;
+ border: none;
+ color: #212529;
+ }
-.features {
- margin: 2rem 0;
-}
+ .features {
+ margin: 2rem 0;
+ }
-.example-link {
- display: inline-block;
- margin: 1rem 0;
- background-color: #0d6efd;
- color: white;
- padding: 0.75rem 1.5rem;
- border-radius: 4px;
- font-weight: bold;
- text-decoration: none;
- transition: background-color 0.2s;
-}
+ .example-link {
+ display: inline-block;
+ margin: 1rem 0;
+ background-color: #0d6efd;
+ color: white;
+ padding: 0.75rem 1.5rem;
+ border-radius: 4px;
+ font-weight: bold;
+ text-decoration: none;
+ transition: background-color 0.2s;
+ }
-.example-link:hover {
- background-color: #0b5ed7;
- text-decoration: none;
-}
+ .example-link:hover {
+ background-color: #0b5ed7;
+ text-decoration: none;
+ }
-.code-block {
- position: relative;
- margin: 2rem 0;
-}
+ .code-block {
+ position: relative;
+ margin: 2rem 0;
+ }
-.code-block::before {
- content: attr(data-title);
- position: absolute;
- top: -12px;
- left: 10px;
- background-color: #fff;
- padding: 0 0.5rem;
- font-size: 0.85rem;
- color: #6c757d;
- border: 1px solid #dee2e6;
- border-radius: 3px;
-}
+ .code-block::before {
+ content: attr(data-title);
+ position: absolute;
+ top: -12px;
+ left: 10px;
+ background-color: #fff;
+ padding: 0 0.5rem;
+ font-size: 0.85rem;
+ color: #6c757d;
+ border: 1px solid #dee2e6;
+ border-radius: 3px;
+ }
-.file-structure {
- font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
- font-size: 0.9rem;
- line-height: 1.5;
- margin: 1.5rem 0;
-}
+ .file-structure {
+ font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ font-size: 0.9rem;
+ line-height: 1.5;
+ margin: 1.5rem 0;
+ }
-.technical-details {
- background-color: #f8f9fa;
- padding: 1.5rem;
- border-radius: 8px;
- border: 1px solid #e9ecef;
- margin: 2rem 0;
-}
+ .technical-details {
+ background-color: #f8f9fa;
+ padding: 1.5rem;
+ border-radius: 8px;
+ border: 1px solid #e9ecef;
+ margin: 2rem 0;
+ }
-.technical-details h2 {
- margin-top: 0;
-}
\ No newline at end of file
+ .technical-details h2 {
+ margin-top: 0;
+ }
+}
diff --git a/examples/worker-example/src/worker-page/style.css b/examples/worker-example/src/worker-page/style.css
index 032ef514..8fd98945 100644
--- a/examples/worker-example/src/worker-page/style.css
+++ b/examples/worker-example/src/worker-page/style.css
@@ -1,109 +1,111 @@
-/* Worker example page styles */
-.worker-example {
- background-color: white;
- border-radius: 8px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
- padding: 2rem;
- margin-bottom: 2rem;
+@layer domstack.page {
+ /* Worker example page styles */
+ .worker-example {
+ background-color: white;
+ border-radius: 8px;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
+ padding: 2rem;
+ margin-bottom: 2rem;
+ }
+
+ .worker-example h1 {
+ color: #0d6efd;
+ border-bottom: 2px solid #0d6efd;
+ padding-bottom: 0.5rem;
+ margin-bottom: 1.5rem;
+ }
+
+ .worker-example h2 {
+ color: #495057;
+ margin-top: 1.5rem;
+ margin-bottom: 1rem;
+ }
+
+ .explanation {
+ margin-bottom: 2rem;
+ }
+
+ .explanation ul {
+ margin-left: 1.5rem;
+ }
+
+ .demo-section {
+ background-color: #f8f9fa;
+ border-radius: 8px;
+ padding: 1.5rem;
+ margin: 2rem 0;
+ border: 1px solid #e9ecef;
+ }
+
+ .demo-container {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ }
+
+ .counter-display, .result {
+ background-color: white;
+ padding: 1rem;
+ border-radius: 4px;
+ border: 1px solid #dee2e6;
+ position: relative;
+ }
+
+ .input-group {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+ }
+
+ .controls {
+ display: flex;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+ margin-bottom: 0.5rem;
+ }
+
+ .computation-time {
+ font-size: 0.9rem;
+ color: #6c757d;
+ margin-top: 0.5rem;
+ }
+
+ input {
+ padding: 0.5rem;
+ border: 1px solid #ced4da;
+ border-radius: 4px;
+ font-size: 1rem;
+ width: 80px;
+ }
+
+ #counter, #fibResult {
+ font-weight: bold;
+ color: #0d6efd;
+ font-size: 1.2rem;
+ }
+
+ .last-operation {
+ font-size: 0.85rem;
+ color: #6c757d;
+ margin-top: 0.5rem;
+ font-style: italic;
+ }
+
+ .code-example {
+ margin: 2rem 0;
+ }
+
+ .code-example pre {
+ background-color: #f8f9fa;
+ padding: 1rem;
+ border-radius: 4px;
+ border: 1px solid #dee2e6;
+ overflow-x: auto;
+ margin-bottom: 1.5rem;
+ }
+
+ .code-example code {
+ font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ }
}
-
-.worker-example h1 {
- color: #0d6efd;
- border-bottom: 2px solid #0d6efd;
- padding-bottom: 0.5rem;
- margin-bottom: 1.5rem;
-}
-
-.worker-example h2 {
- color: #495057;
- margin-top: 1.5rem;
- margin-bottom: 1rem;
-}
-
-.explanation {
- margin-bottom: 2rem;
-}
-
-.explanation ul {
- margin-left: 1.5rem;
-}
-
-.demo-section {
- background-color: #f8f9fa;
- border-radius: 8px;
- padding: 1.5rem;
- margin: 2rem 0;
- border: 1px solid #e9ecef;
-}
-
-.demo-container {
- display: flex;
- flex-direction: column;
- gap: 1rem;
-}
-
-.counter-display, .result {
- background-color: white;
- padding: 1rem;
- border-radius: 4px;
- border: 1px solid #dee2e6;
- position: relative;
-}
-
-.input-group {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- flex-wrap: wrap;
-}
-
-.controls {
- display: flex;
- gap: 0.5rem;
- flex-wrap: wrap;
- margin-bottom: 0.5rem;
-}
-
-.computation-time {
- font-size: 0.9rem;
- color: #6c757d;
- margin-top: 0.5rem;
-}
-
-input {
- padding: 0.5rem;
- border: 1px solid #ced4da;
- border-radius: 4px;
- font-size: 1rem;
- width: 80px;
-}
-
-#counter, #fibResult {
- font-weight: bold;
- color: #0d6efd;
- font-size: 1.2rem;
-}
-
-.last-operation {
- font-size: 0.85rem;
- color: #6c757d;
- margin-top: 0.5rem;
- font-style: italic;
-}
-
-.code-example {
- margin: 2rem 0;
-}
-
-.code-example pre {
- background-color: #f8f9fa;
- padding: 1rem;
- border-radius: 4px;
- border: 1px solid #dee2e6;
- overflow-x: auto;
- margin-bottom: 1.5rem;
-}
-
-.code-example code {
- font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
-}
\ No newline at end of file
diff --git a/global.css b/global.css
index 80a69162..ebe93617 100644
--- a/global.css
+++ b/global.css
@@ -1,10 +1,14 @@
-/* Global styles applied to every page */
+@layer mine, domstack.global, domstack.layout, domstack.page;
-@font-face {
+@layer domstack.global {
+ /* Global styles applied to every page */
+
+ @font-face {
font-family: 'DSWeiss-Gotisch';
src: url('./fonts/ds-weiss-gotisch/DSWeiss-Gotisch.ttf') format('truetype');
-}
+ }
-h1, h2, h3, h4, h5, h6 {
+ h1, h2, h3, h4, h5, h6 {
font-family: 'DSWeiss-Gotisch', serif;
+ }
}
diff --git a/lib/defaults/default.client.js b/lib/defaults/default.client.js
index e2babe95..0b6af0b8 100644
--- a/lib/defaults/default.client.js
+++ b/lib/defaults/default.client.js
@@ -1,4 +1 @@
-// @ts-expect-error
-import { toggleTheme } from 'mine.css'
-// @ts-expect-error
-window.toggleTheme = toggleTheme
+// mine.css follows the browser's color preference and needs no theme JavaScript.
diff --git a/lib/defaults/default.root.layout.js b/lib/defaults/default.root.layout.js
index 4b53a76c..10646f12 100644
--- a/lib/defaults/default.root.layout.js
+++ b/lib/defaults/default.root.layout.js
@@ -38,6 +38,7 @@ export default function defaultRootLayout ({
${title ? `${title}` : ''}${title && siteName ? ' | ' : ''}${siteName}
+
${scripts
? scripts.map(script => html``)
: null}
diff --git a/lib/defaults/default.style.css b/lib/defaults/default.style.css
index 84d5e65b..e1ca9f76 100644
--- a/lib/defaults/default.style.css
+++ b/lib/defaults/default.style.css
@@ -1,3 +1,6 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
-@import 'highlight.js/styles/github-dark-dimmed.css';
+@layer mine, domstack.global, domstack.layout, domstack.page;
+
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
+@import 'highlight.js/styles/github.css' layer(domstack.global);
+@import url('highlight.js/styles/github-dark-dimmed.css') layer(domstack.global) (prefers-color-scheme: dark);
diff --git a/package.json b/package.json
index 14bc9cea..fbcc254c 100644
--- a/package.json
+++ b/package.json
@@ -51,7 +51,7 @@
"markdown-it-sup": "^2.0.0",
"markdown-it-table-of-contents": "^1.1.0",
"markdown-it-task-lists": "^2.1.1",
- "mine.css": "^10.0.0",
+ "mine.css": "^11.0.6",
"p-map": "^7.0.2",
"package-directory": "^8.1.0",
"package-json": "^10.0.0",
@@ -63,6 +63,7 @@
"write-package": "^7.0.1"
},
"devDependencies": {
+ "@playwright/test": "^1.61.1",
"@types/markdown-it": "^14.1.1",
"@types/markdown-it-footnote": "^3.0.4",
"@types/node": "^26.0.1",
@@ -92,6 +93,7 @@
"test:installed-check": "installed-check --ignore-dev",
"test:neostandard": "eslint . --ignore-pattern 'test-cases/build-errors/src/**/*.js' --ignore-pattern 'test-cases/page-build-errors/src/**/*.js'",
"test:node-test": "node --test --experimental-test-coverage --test-reporter=dot --test-reporter=lcov --test-reporter-destination=stdout --test-reporter-destination=lcov.info",
+ "test:playwright": "playwright test",
"test:tsc": "tsc",
"build-examples": "run-p example:*",
"clean": "run-p clean:*",
diff --git a/playwright.config.js b/playwright.config.js
new file mode 100644
index 00000000..1a62dbbb
--- /dev/null
+++ b/playwright.config.js
@@ -0,0 +1,24 @@
+import { defineConfig, devices } from '@playwright/test'
+
+export default defineConfig({
+ testDir: './browser-tests',
+ timeout: 10_000,
+ globalTimeout: 120_000,
+ expect: {
+ timeout: 5_000
+ },
+ fullyParallel: false,
+ workers: 1,
+ reporter: 'list',
+ outputDir: 'test-results/playwright',
+ use: {
+ trace: 'on-first-retry',
+ screenshot: 'only-on-failure'
+ },
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] }
+ }
+ ]
+})
diff --git a/style.css b/style.css
index 87b60892..fe1ba5fa 100644
--- a/style.css
+++ b/style.css
@@ -1 +1,3 @@
-/* Styles go here */
+@layer domstack.page {
+ /* Styles go here */
+}
diff --git a/test-cases/build-errors/src/style.css b/test-cases/build-errors/src/style.css
index 629fe3a2..9c4e4c24 100644
--- a/test-cases/build-errors/src/style.css
+++ b/test-cases/build-errors/src/style.css
@@ -1,7 +1,9 @@
-.some-class {
- background: blue;
+@layer domstack.page {
+ .some-class {
+ background: blue;
- /* And some garbled CSS */
+ /* And some garbled CSS */
- fdskahfjla; jfk jkl;dfjsla;fjdls943rjn
+ fdskahfjla; jfk jkl;dfjsla;fjdls943rjn
+ }
}
diff --git a/test-cases/default-layout/src/global.css b/test-cases/default-layout/src/global.css
index c81052b4..0434dc2c 100644
--- a/test-cases/default-layout/src/global.css
+++ b/test-cases/default-layout/src/global.css
@@ -1,3 +1,7 @@
-.global-class {
- color: blue;
+@layer mine, domstack.global, domstack.layout, domstack.page;
+
+@layer domstack.global {
+ .global-class {
+ color: blue;
+ }
}
diff --git a/test-cases/default-layout/src/style.css b/test-cases/default-layout/src/style.css
index c63ffb86..0ae629de 100644
--- a/test-cases/default-layout/src/style.css
+++ b/test-cases/default-layout/src/style.css
@@ -1,4 +1,6 @@
-/* You can still do page styles and get the default layout. */
-.root-page-style {
- background: blue;
+@layer domstack.page {
+ /* You can still do page styles and get the default layout. */
+ .root-page-style {
+ background: blue;
+ }
}
diff --git a/test-cases/general-features/src/README.md b/test-cases/general-features/src/README.md
index f86c5632..26ba9b3c 100644
--- a/test-cases/general-features/src/README.md
+++ b/test-cases/general-features/src/README.md
@@ -5,4 +5,6 @@ testVar: frontmatter var
This is a README.md in the root of the site.
+Cascade layer fixture
+
{{{ vars.blogPostsHtml }}}
diff --git a/test-cases/general-features/src/blog/2023/a-draft-from-2023/style.css b/test-cases/general-features/src/blog/2023/a-draft-from-2023/style.css
index 34c7c797..c5deeb2f 100644
--- a/test-cases/general-features/src/blog/2023/a-draft-from-2023/style.css
+++ b/test-cases/general-features/src/blog/2023/a-draft-from-2023/style.css
@@ -1,3 +1,5 @@
-.a-blog-post-css {
- color: blue;
+@layer domstack.page {
+ .a-blog-post-css {
+ color: blue;
+ }
}
diff --git a/test-cases/general-features/src/blog/2023/the-first-blog-post-from-2023/style.css b/test-cases/general-features/src/blog/2023/the-first-blog-post-from-2023/style.css
index 34c7c797..c5deeb2f 100644
--- a/test-cases/general-features/src/blog/2023/the-first-blog-post-from-2023/style.css
+++ b/test-cases/general-features/src/blog/2023/the-first-blog-post-from-2023/style.css
@@ -1,3 +1,5 @@
-.a-blog-post-css {
- color: blue;
+@layer domstack.page {
+ .a-blog-post-css {
+ color: blue;
+ }
}
diff --git a/test-cases/general-features/src/globals/global.client.js b/test-cases/general-features/src/globals/global.client.js
index b6455a6f..8edeb4d7 100644
--- a/test-cases/general-features/src/globals/global.client.js
+++ b/test-cases/general-features/src/globals/global.client.js
@@ -1,8 +1,3 @@
-// @ts-ignore
-import { toggleTheme } from 'mine.css'
console.log('This runs on every page')
export default 'global.client.js'
-
-// @ts-ignore
-window.toggleTheme = toggleTheme
diff --git a/test-cases/general-features/src/globals/global.css b/test-cases/general-features/src/globals/global.css
index 45e5274e..8ef024c5 100644
--- a/test-cases/general-features/src/globals/global.css
+++ b/test-cases/general-features/src/globals/global.css
@@ -1,5 +1,10 @@
-@import 'mine.css/dist/mine.css';
-@import 'mine.css/dist/layout.css';
+@layer mine, domstack.global, domstack.layout, domstack.page;
-.test-asset-icon { background-image: url('./test-icon.gif'); }
-@font-face { font-family: 'TestFont'; src: url('./test-font.woff2'); }
+@import 'mine.css';
+@import 'mine.css/dist/layout.css' layer(domstack.layout);
+
+@layer domstack.global {
+ .test-asset-icon { background-image: url('./test-icon.gif'); }
+ @font-face { font-family: 'TestFont'; src: url('./test-font.woff2'); }
+ .cascade-layer-fixture { --domstack-cascade-layer: global; }
+}
diff --git a/test-cases/general-features/src/html-page/style.css b/test-cases/general-features/src/html-page/style.css
index f62d0e5f..42e3fbd6 100644
--- a/test-cases/general-features/src/html-page/style.css
+++ b/test-cases/general-features/src/html-page/style.css
@@ -1,3 +1,5 @@
-.htnl-page-style {
- background: blue;
+@layer domstack.page {
+ .htnl-page-style {
+ background: blue;
+ }
}
diff --git a/test-cases/general-features/src/js-page/style.css b/test-cases/general-features/src/js-page/style.css
index e5c571c5..a50e29e8 100644
--- a/test-cases/general-features/src/js-page/style.css
+++ b/test-cases/general-features/src/js-page/style.css
@@ -1,3 +1,5 @@
-.js-page-style {
- background: purple;
+@layer domstack.page {
+ .js-page-style {
+ background: purple;
+ }
}
diff --git a/test-cases/general-features/src/layouts/blog.layout.css b/test-cases/general-features/src/layouts/blog.layout.css
index da49c7ab..4d0df864 100644
--- a/test-cases/general-features/src/layouts/blog.layout.css
+++ b/test-cases/general-features/src/layouts/blog.layout.css
@@ -1,5 +1,7 @@
-@import "./root.layout.css";
+@import "./root.layout.css" layer(domstack.layout);
-.some-blog-class {
- color: purple;
+@layer domstack.layout {
+ .some-blog-class {
+ color: purple;
+ }
}
diff --git a/test-cases/general-features/src/layouts/root.layout.css b/test-cases/general-features/src/layouts/root.layout.css
index be7e6ff1..ff3881aa 100644
--- a/test-cases/general-features/src/layouts/root.layout.css
+++ b/test-cases/general-features/src/layouts/root.layout.css
@@ -1,3 +1,6 @@
-.some-root-layout-class {
- color: green;
+@layer domstack.layout {
+ .cascade-layer-fixture { --domstack-cascade-layer: layout; }
+ .some-root-layout-class {
+ color: green;
+ }
}
diff --git a/test-cases/general-features/src/md-page/style.css b/test-cases/general-features/src/md-page/style.css
index 4d55f5ee..9e64847a 100644
--- a/test-cases/general-features/src/md-page/style.css
+++ b/test-cases/general-features/src/md-page/style.css
@@ -1,45 +1,47 @@
-.md-page-style {
- background: yellow;
-}
+@layer domstack.page {
+ .md-page-style {
+ background: yellow;
+ }
-/* Style for the custom test-box container */
-.test-box {
- border: 2px solid #3498db;
- border-radius: 5px;
- padding: 15px;
- margin: 20px 0;
- background-color: #eaf7ff;
- position: relative;
-}
+ /* Style for the custom test-box container */
+ .test-box {
+ border: 2px solid #3498db;
+ border-radius: 5px;
+ padding: 15px;
+ margin: 20px 0;
+ background-color: #eaf7ff;
+ position: relative;
+ }
-.test-box::before {
- content: "Test Box";
- position: absolute;
- top: -12px;
- left: 10px;
- background-color: white;
- padding: 0 10px;
- color: #3498db;
- font-weight: bold;
-}
+ .test-box::before {
+ content: "Test Box";
+ position: absolute;
+ top: -12px;
+ left: 10px;
+ background-color: white;
+ padding: 0 10px;
+ color: #3498db;
+ font-weight: bold;
+ }
-/* Style for the custom test-box container */
-.test-box {
- border: 2px solid #3498db;
- border-radius: 5px;
- padding: 15px;
- margin: 20px 0;
- background-color: #eaf7ff;
- position: relative;
-}
+ /* Style for the custom test-box container */
+ .test-box {
+ border: 2px solid #3498db;
+ border-radius: 5px;
+ padding: 15px;
+ margin: 20px 0;
+ background-color: #eaf7ff;
+ position: relative;
+ }
-.test-box::before {
- content: "Test Box";
- position: absolute;
- top: -12px;
- left: 10px;
- background-color: white;
- padding: 0 10px;
- color: #3498db;
- font-weight: bold;
+ .test-box::before {
+ content: "Test Box";
+ position: absolute;
+ top: -12px;
+ left: 10px;
+ background-color: white;
+ padding: 0 10px;
+ color: #3498db;
+ font-weight: bold;
+ }
}
diff --git a/test-cases/general-features/src/style.css b/test-cases/general-features/src/style.css
index e27b8523..a9f2311d 100644
--- a/test-cases/general-features/src/style.css
+++ b/test-cases/general-features/src/style.css
@@ -1,3 +1,6 @@
-.root-page-style {
- background: blue;
+@layer domstack.page {
+ .cascade-layer-fixture { --domstack-cascade-layer: page; }
+ .root-page-style {
+ background: blue;
+ }
}
diff --git a/test-cases/general-features/src/worker-page/style.css b/test-cases/general-features/src/worker-page/style.css
index 0ffc6688..dfe4838b 100644
--- a/test-cases/general-features/src/worker-page/style.css
+++ b/test-cases/general-features/src/worker-page/style.css
@@ -1,45 +1,47 @@
-.worker-test {
- max-width: 800px;
- margin: 0 auto;
- padding: 1rem;
-}
+@layer domstack.page {
+ .worker-test {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 1rem;
+ }
-.worker-component {
- margin-top: 2rem;
- padding: 1.5rem;
- border: 1px solid #ccc;
- border-radius: 8px;
- background-color: #f9f9f9;
-}
+ .worker-component {
+ margin-top: 2rem;
+ padding: 1.5rem;
+ border: 1px solid #ccc;
+ border-radius: 8px;
+ background-color: #f9f9f9;
+ }
-.counter-display {
- margin-bottom: 1rem;
- font-size: 1.2rem;
-}
+ .counter-display {
+ margin-bottom: 1rem;
+ font-size: 1.2rem;
+ }
-#counter {
- font-weight: bold;
- color: #0066cc;
-}
+ #counter {
+ font-weight: bold;
+ color: #0066cc;
+ }
-.controls {
- display: flex;
- gap: 0.5rem;
-}
+ .controls {
+ display: flex;
+ gap: 0.5rem;
+ }
-button {
- padding: 0.5rem 1rem;
- background-color: #0066cc;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
-}
+ button {
+ padding: 0.5rem 1rem;
+ background-color: #0066cc;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ }
-button:hover {
- background-color: #0055aa;
-}
+ button:hover {
+ background-color: #0055aa;
+ }
-button:active {
- background-color: #004488;
-}
\ No newline at end of file
+ button:active {
+ background-color: #004488;
+ }
+}
diff --git a/test-cases/nested-dest/md-page/style.css b/test-cases/nested-dest/md-page/style.css
index 87b51d5f..f923ec3e 100644
--- a/test-cases/nested-dest/md-page/style.css
+++ b/test-cases/nested-dest/md-page/style.css
@@ -1,3 +1,5 @@
-.md-page-style {
- background: yellow;
+@layer domstack.page {
+ .md-page-style {
+ background: yellow;
+ }
}
diff --git a/test-cases/nested-dest/style.css b/test-cases/nested-dest/style.css
index c63ffb86..0ae629de 100644
--- a/test-cases/nested-dest/style.css
+++ b/test-cases/nested-dest/style.css
@@ -1,4 +1,6 @@
-/* You can still do page styles and get the default layout. */
-.root-page-style {
- background: blue;
+@layer domstack.page {
+ /* You can still do page styles and get the default layout. */
+ .root-page-style {
+ background: blue;
+ }
}
diff --git a/test-cases/page-build-errors/src/style.css b/test-cases/page-build-errors/src/style.css
index 460b8541..0651c6bc 100644
--- a/test-cases/page-build-errors/src/style.css
+++ b/test-cases/page-build-errors/src/style.css
@@ -1,3 +1,5 @@
-.some-class {
- background: blue;
+@layer domstack.page {
+ .some-class {
+ background: blue;
+ }
}