diff --git a/deno.json b/deno.json
index 06f0730d9..0c40cd290 100644
--- a/deno.json
+++ b/deno.json
@@ -48,6 +48,7 @@
"docs:check-version-anchors": "deno run --allow-read tools/check-version-anchors.ts",
"docs:truth": "deno task docs:check-public && deno task docs:check-current && deno task docs:check-strategy && deno task docs:check-version-anchors && deno task release:evidence:check && deno task www:check-current-truth",
"www:check-current-truth": "deno run --allow-read tools/check-www-current-truth.ts",
+ "www:check-theme-tokens": "deno run --allow-read tools/check-www-theme-tokens.ts",
"www:check-artifact-truth": "deno run --allow-read tools/check-www-current-truth.ts --artifacts",
"package-surface:check": "deno run --allow-read --allow-env tools/check-package-surface.ts",
"interface:snapshot": "deno run --allow-read --allow-env tools/check-public-interface-snapshot.ts",
diff --git a/tools/autoflow/policy.ts b/tools/autoflow/policy.ts
index 939609cd3..9cb3860a9 100644
--- a/tools/autoflow/policy.ts
+++ b/tools/autoflow/policy.ts
@@ -126,6 +126,12 @@ export const GATES: readonly GateDefinition[] = [
tiers: ['ci', 'release'],
triggers: [/^docs\//, /^README/, /^www\/app\/routes\//],
},
+ {
+ name: 'www:check-theme-tokens',
+ command: ['deno', 'task', 'www:check-theme-tokens'],
+ tiers: ['dev', 'push', 'ci', 'release'],
+ triggers: [/^www\/app\//, /^www\/vite\.config\.ts$/, /^packages\/ui\/src\/open-props-tokens/],
+ },
{
name: 'docs:check-version-anchors',
command: ['deno', 'task', 'docs:check-version-anchors'],
diff --git a/tools/check-www-theme-tokens.test.ts b/tools/check-www-theme-tokens.test.ts
new file mode 100644
index 000000000..ef4fd21ec
--- /dev/null
+++ b/tools/check-www-theme-tokens.test.ts
@@ -0,0 +1,52 @@
+import { assertEquals } from '@std/assert';
+import { findThemeTokenFailures } from './check-www-theme-tokens.ts';
+
+Deno.test('theme-token gate catches hex, font-family and font-size literals', () => {
+ const lines = [
+ ' .vinyl { background:#18151e; }',
+ ' code { font-family: "JetBrains Mono", monospace; }',
+ ' font-size: 12px;',
+ ' font-size: .75rem;',
+ ];
+ const failures = findThemeTokenFailures('x.tsx', lines);
+ assertEquals(failures.map((f) => f.rule), [
+ 'hex-literal',
+ 'font-family-literal',
+ 'font-size-literal',
+ 'font-size-literal',
+ ]);
+});
+
+Deno.test('theme-token gate catches short hex only in CSS contexts', () => {
+ const violations = findThemeTokenFailures('x.tsx', [
+ 'background: color-mix(in srgb, #fff 18%, transparent);',
+ ]);
+ assertEquals(violations.length, 1);
+ const prose = findThemeTokenFailures('x.tsx', [
+ 'External adopter #390 and continued browser evidence.',
+ '#390',
+ ]);
+ assertEquals(prose.length, 0);
+});
+
+Deno.test('theme-token gate skips generated data files', () => {
+ const failures = findThemeTokenFailures('www/app/data/_generated-blog-data.ts', [
+ '"content": "themeColor: \'#000000\', font-size: 12px;"',
+ ]);
+ // The caller-level exclusion (path filter) keeps generated content out;
+ // the pure function still flags it when asked directly.
+ assertEquals(failures.length > 0, true);
+});
+
+Deno.test('theme-token gate accepts tokens, inherit and fluid clamp()', () => {
+ const failures = findThemeTokenFailures('x.tsx', [
+ 'color: var(--text-primary);',
+ 'background: color-mix(in srgb, var(--violet-5) 18%, transparent);',
+ 'font-family: var(--font-mono);',
+ 'font-family: inherit;',
+ 'font-size: var(--font-size-00);',
+ 'font-size: clamp(4.1rem, 10vw, 10.5rem);',
+ 'font-size: clamp(var(--font-size-7), 10vw, var(--font-size-8));',
+ ]);
+ assertEquals(failures.length, 0);
+});
diff --git a/tools/check-www-theme-tokens.ts b/tools/check-www-theme-tokens.ts
new file mode 100644
index 000000000..6d7c699b2
--- /dev/null
+++ b/tools/check-www-theme-tokens.ts
@@ -0,0 +1,81 @@
+/**
+ * www theme-token gate: theme values in the site must come from open-props
+ * tokens (packages/ui/src/open-props-tokens.css) and the www alias layer
+ * (www/vite.config.ts), never from hardcoded literals.
+ *
+ * Rules for sources under www/app/ and www/islands/:
+ * 1. No hex color literals. 6/8-digit forms always fail; 3/4-digit forms
+ * fail only on lines carrying a CSS property keyword, so issue
+ * references like `#390` in prose stay legal.
+ * 2. No `font-family` declarations that bypass var(); `inherit` is allowed.
+ * 3. No `font-size` literals in px/rem/em outside var(); clamp() fluid
+ * typography is allowed.
+ *
+ * Token definitions belong in www/vite.config.ts (site aliases) or
+ * packages/ui/src/open-props-tokens.css (source of truth).
+ */
+
+import { walk } from '@std/fs/walk';
+
+const SCAN_ROOTS = ['www/app'];
+const SOURCE = /\.(ts|tsx)$/;
+const HEX_LONG = /#(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\b/;
+const HEX_SHORT = /#(?:[0-9a-fA-F]{3,4})\b/;
+const CSS_KEYWORD = /color|background|border|shadow|fill|stroke|gradient|outline/i;
+const FONT_FAMILY = /font-family\s*:\s*([^;]+);/;
+const FONT_SIZE_LITERAL = /font-size\s*:\s*[0-9.]+(?:px|rem|em)\b/;
+
+export interface ThemeTokenFailure {
+ file: string;
+ line: number;
+ rule: string;
+ text: string;
+}
+
+export function findThemeTokenFailures(
+ file: string,
+ lines: string[],
+): ThemeTokenFailure[] {
+ const failures: ThemeTokenFailure[] = [];
+ for (let i = 0; i < lines.length; i++) {
+ const text = lines[i];
+ if (HEX_LONG.test(text) || (HEX_SHORT.test(text) && CSS_KEYWORD.test(text))) {
+ failures.push({ file, line: i + 1, rule: 'hex-literal', text: text.trim() });
+ }
+ const family = FONT_FAMILY.exec(text);
+ if (family && !family[1].includes('var(') && !family[1].includes('inherit')) {
+ failures.push({ file, line: i + 1, rule: 'font-family-literal', text: text.trim() });
+ }
+ if (FONT_SIZE_LITERAL.test(text)) {
+ failures.push({ file, line: i + 1, rule: 'font-size-literal', text: text.trim() });
+ }
+ }
+ return failures;
+}
+
+async function main(): Promise {
+ const failures: ThemeTokenFailure[] = [];
+ for (const root of SCAN_ROOTS) {
+ for await (const entry of walk(root, { exts: ['.ts', '.tsx'] })) {
+ if (!SOURCE.test(entry.path)) continue;
+ if (entry.path.includes('/data/_generated-')) continue;
+ const text = await Deno.readTextFile(entry.path);
+ failures.push(...findThemeTokenFailures(entry.path, text.split('\n')));
+ }
+ }
+ if (failures.length > 0) {
+ console.error('www theme token check failed:');
+ for (const failure of failures) {
+ console.error(`- ${failure.file}:${failure.line} [${failure.rule}] ${failure.text}`);
+ }
+ console.error(
+ 'Theme values must come from open-props tokens or the www/vite.config.ts alias layer.',
+ );
+ Deno.exit(1);
+ }
+ console.log('www theme token check passed.');
+}
+
+if (import.meta.main) {
+ await main();
+}
diff --git a/www/app/routes/404.tsx b/www/app/routes/404.tsx
index 27cab35df..9bcaac639 100644
--- a/www/app/routes/404.tsx
+++ b/www/app/routes/404.tsx
@@ -84,10 +84,10 @@ styles.replaceSync(`
padding: 80px 20px 64px;
}
.title {
- font-size: 64px;
+ font-size: var(--font-size-7);
}
.subtitle {
- font-size: 20px;
+ font-size: var(--font-size-2);
}
}
`);
diff --git a/www/app/routes/architecture/architecture.tsx b/www/app/routes/architecture/architecture.tsx
index 70da9daa1..c0309d25a 100644
--- a/www/app/routes/architecture/architecture.tsx
+++ b/www/app/routes/architecture/architecture.tsx
@@ -4,6 +4,7 @@ export const tagName = 'engine-architecture';
import { OpenElement, StyleSheet } from '@openelement/element';
import '@openelement/ui/open-badge';
import '@openelement/ui/open-card';
+import '@openelement/ui/open-code-block';
import { OPENELEMENT_VERSION } from '../../data/version.ts';
import '@openelement/site-ui/open-section-frame.tsx';
import '@openelement/site-ui/open-page-hero.tsx';
@@ -15,14 +16,14 @@ pageSheet.replaceSync(`
* { box-sizing:border-box; }
.eyebrow { display: flex; flex-wrap: wrap; gap: var(--size-2); margin-bottom: 20px; }
h1 { margin:0; max-width:760px; color:var(--text); font-size:clamp(3.5rem,7vw,7rem); line-height:.88; letter-spacing:-.07em; }
- h2 { margin: 0; color: var(--text); font-size: 34px; line-height: 1.12; letter-spacing: 0; }
+ h2 { margin: 0; color: var(--text); font-size: var(--font-size-display-md); line-height: 1.12; letter-spacing: 0; }
h3 { margin: 0 0 var(--size-2); color: var(--text); }
p { color: var(--text-secondary); line-height: var(--line-height-relaxed); }
.lede { margin: 20px 0 0; font-size: var(--font-size-subhead); max-width: 650px; }
.artifact, .layer-map { border:1px solid color-mix(in srgb,var(--color-border) 72%,var(--brand)); border-radius:var(--radius-2); overflow:hidden; background:color-mix(in srgb,var(--surface-1) 82%,transparent); box-shadow:inset 0 1px 0 var(--edge-highlight),0 28px 90px color-mix(in srgb,var(--violet-10) 24%,transparent); backdrop-filter:blur(18px); }
.artifact-head { display: flex; justify-content: space-between; gap: var(--size-3); padding: 14px var(--size-4); border-bottom: 1px solid var(--color-border); font-size: var(--font-size-0); color: var(--text-muted); }
pre { margin: 0; padding: var(--size-4); overflow-x: auto; background: var(--code-bg); color: var(--code-text); font-size: var(--font-size-0); line-height: 1.65; }
- code { font-family: "JetBrains Mono", monospace; }
+ code { font-family: var(--font-mono); }
.layer { display: grid; grid-template-columns: 170px 1fr 180px; gap: var(--size-4); padding: 14px var(--size-4); border-bottom: 1px solid var(--color-border); align-items: start; }
.layer:last-child { border-bottom: 0; }
.layer strong { color: var(--text); font-size: var(--font-size-1); }
@@ -33,7 +34,7 @@ pageSheet.replaceSync(`
.gate strong { color: var(--color-brand); font-size: var(--font-size-1); }
.gate span { color: var(--text-secondary); font-size: var(--font-size-0); line-height: 1.55; }
.nav-row { display:flex; flex-wrap:wrap; gap:10px; width:min(1180px,calc(100% - 4rem)); margin:var(--size-8) auto 0; }
- @media (max-width: 900px) { .cards, .gate-grid { grid-template-columns: 1fr; } .layer { grid-template-columns: 1fr; gap: var(--size-2); } h1 { font-size: 42px; line-height: 1.06; } h2 { font-size: 28px; } }
+ @media (max-width: 900px) { .cards, .gate-grid { grid-template-columns: 1fr; } .layer { grid-template-columns: 1fr; gap: var(--size-2); } h1 { font-size: var(--font-size-display-lg); line-height: 1.06; } h2 { font-size: var(--font-size-display-sm); } }
@media (max-width: 560px) { .nav-row{width:calc(100% - 2rem)} .gate { grid-template-columns: 1fr; display: grid; } }
`);
@@ -62,7 +63,9 @@ export class ArchitecturePage extends OpenElement {
package graph
{OPENELEMENT_VERSION} published line
- {PACKAGE_GRAPH}
+
+ {PACKAGE_GRAPH}
+
diff --git a/www/app/routes/architecture/islands-deep.tsx b/www/app/routes/architecture/islands-deep.tsx
index b6d220204..2ff59d973 100644
--- a/www/app/routes/architecture/islands-deep.tsx
+++ b/www/app/routes/architecture/islands-deep.tsx
@@ -11,7 +11,7 @@ const routeSheet = new StyleSheet();
routeSheet.replaceSync(
pageStyles + `
.layer-card { padding: 20px var(--size-6); margin: var(--size-4) 0; border-left: 2px solid var(--color-border); background: var(--surface-1); border-radius: 0 3px 3px 0; }
- .layer-card .layer-tag { font-size: 11px; font-weight: var(--font-weight-5); text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem; }
+ .layer-card .layer-tag { font-size: var(--font-size-overline); font-weight: var(--font-weight-5); text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-bottom: 0.25rem; }
.layer-card h3 { margin: 0 0 var(--size-2); }
.strategy-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--size-4); margin: var(--size-4) 0 var(--size-6); }
.strategy-item { padding: var(--size-4) 20px; border: 0.5px solid var(--color-border); border-radius: var(--radius-xs); background: var(--surface-1); }
diff --git a/www/app/routes/blog/[slug].tsx b/www/app/routes/blog/[slug].tsx
index 7667342a4..02ea6109d 100644
--- a/www/app/routes/blog/[slug].tsx
+++ b/www/app/routes/blog/[slug].tsx
@@ -52,7 +52,7 @@ routeSheet.replaceSync(
.blog-tags { display: flex; gap: 0.375rem; flex-wrap: wrap; margin-bottom: var(--size-4); }
.blog-tag { font-size: var(--font-size-00); font-weight: var(--font-weight-6); text-transform: uppercase; letter-spacing: var(--font-letterspacing-2); padding: 0.125rem 0.375rem; border-radius: 2px; background: var(--bg-surface); border: 0.5px solid var(--border); color: var(--text-secondary); }
.blog-content { font-size: var(--font-size-3); line-height: var(--font-lineheight-4); color: var(--text-secondary); }
- .blog-content h2 { margin-top: var(--size-10); color: var(--text-primary); font-size: 1.125rem; font-weight: var(--font-weight-6); }
+ .blog-content h2 { margin-top: var(--size-10); color: var(--text-primary); font-size: var(--font-size-article-title); font-weight: var(--font-weight-6); }
.blog-content h3 { margin-top: var(--size-8); color: var(--text-primary); font-size: var(--font-size-4); font-weight: var(--font-weight-6); }
.blog-content p { margin: var(--size-3) 0; }
.blog-content ul, .blog-content ol { padding-left: var(--size-6); margin: var(--size-3) 0; }
@@ -63,7 +63,7 @@ routeSheet.replaceSync(
.blog-content pre code { background: none; padding: 0; font-size: var(--font-size-0); line-height: 1.6; }
.blog-content table { width: 100%; border-collapse: collapse; margin: var(--size-4) 0; font-size: var(--font-size-1); }
.blog-content th, .blog-content td { padding: var(--size-2) var(--size-3); text-align: left; border-bottom: 0.5px solid var(--border); }
- .blog-content th { background: var(--bg-surface); color: var(--text-secondary); font-weight: var(--font-weight-6); font-size: 0.6875rem; text-transform: uppercase; letter-spacing: var(--font-letterspacing-2); }
+ .blog-content th { background: var(--bg-surface); color: var(--text-secondary); font-weight: var(--font-weight-6); font-size: var(--font-size-overline); text-transform: uppercase; letter-spacing: var(--font-letterspacing-2); }
.blog-content a { color: var(--brand); text-decoration: none; }
.blog-content a:hover { text-decoration: underline; }
.blog-content hr { border: none; border-top: 0.5px solid var(--border); margin: var(--size-8) 0; }
diff --git a/www/app/routes/index/index.tsx b/www/app/routes/index/index.tsx
index 5e65915ca..7755a7327 100644
--- a/www/app/routes/index/index.tsx
+++ b/www/app/routes/index/index.tsx
@@ -24,7 +24,7 @@ sheet.replaceSync(`
.actions { display:flex; flex-wrap:wrap; gap:.8rem; align-items:center; }
.action { display:inline-flex; align-items:center; justify-content:center; min-height:3.25rem; padding:0 1.2rem; border:1px solid color-mix(in srgb,var(--text-primary) 42%,transparent); border-radius:999px; color:var(--text-primary); background:color-mix(in srgb,var(--bg-base) 56%,transparent); font-weight:700; text-decoration:none; transition:transform .22s var(--ease-3),background .22s var(--ease-3),border-color .22s var(--ease-3); }
.action:hover,.action:focus-visible { transform:translateY(-3px); border-color:var(--violet-7); background:color-mix(in srgb,var(--violet-5) 22%,var(--bg-base)); outline:none; }
- .action.primary { border-color:var(--violet-7); background:linear-gradient(120deg,var(--violet-6),var(--violet-4)); color:#fff; box-shadow:0 16px 45px color-mix(in srgb,var(--violet-6) 42%,transparent); }
+ .action.primary { border-color:var(--violet-7); background:linear-gradient(120deg,var(--violet-6),var(--violet-4)); color:var(--vinyl-highlight); box-shadow:0 16px 45px color-mix(in srgb,var(--violet-6) 42%,transparent); }
.version { display:block; margin-block-start:1.1rem; color:var(--text-muted); font-family:var(--font-mono); font-size:var(--font-size-00); }
.aperture-stage { position:relative; aspect-ratio:1; width:min(100%,680px); margin-inline:auto; transform-style:preserve-3d; }
.aperture { position:absolute; inset:10%; display:grid; place-items:center; border:1px solid color-mix(in srgb,var(--violet-7) 66%,transparent); border-radius:50%; background:radial-gradient(circle at 31% 28%,color-mix(in srgb,var(--violet-5) 32%,transparent),transparent 31%),radial-gradient(circle at 68% 70%,color-mix(in srgb,var(--violet-9) 32%,transparent),transparent 45%); box-shadow:inset 0 0 90px color-mix(in srgb,var(--violet-7) 18%,transparent),0 0 120px color-mix(in srgb,var(--violet-7) 22%,transparent); }
@@ -33,9 +33,9 @@ sheet.replaceSync(`
.mark { position:relative; z-index:1; color:var(--text-primary); font-family:var(--font-mono); font-size:clamp(3rem,7vw,6.8rem); font-weight:800; letter-spacing:-.09em; text-shadow:0 0 36px color-mix(in srgb,var(--violet-6) 55%,transparent); }
.mark b { color:var(--violet-8); }
.orbit { position:absolute; inset:0; border:1px dashed color-mix(in srgb,var(--violet-6) 24%,transparent); border-radius:50%; animation:reverse-orbit 20s linear infinite; }
- .node { position:absolute; display:grid; place-items:center; width:3.2rem; aspect-ratio:1; border:1px solid color-mix(in srgb,var(--violet-6) 62%,transparent); border-radius:50%; background:color-mix(in srgb,var(--bg-base) 70%,transparent); color:var(--violet-8); font-family:var(--font-mono); font-size:.72rem; box-shadow:0 0 22px color-mix(in srgb,var(--violet-7) 24%,transparent); }
+ .node { position:absolute; display:grid; place-items:center; width:3.2rem; aspect-ratio:1; border:1px solid color-mix(in srgb,var(--violet-6) 62%,transparent); border-radius:50%; background:color-mix(in srgb,var(--bg-base) 70%,transparent); color:var(--violet-8); font-family:var(--font-mono); font-size:var(--font-size-00); box-shadow:0 0 22px color-mix(in srgb,var(--violet-7) 24%,transparent); }
.node.one { inset:9% auto auto 13%; }.node.two { inset:auto 5% 17% auto; }.node.three { inset:44% auto auto -3%; }
- .scroll-cue { position:absolute; inset:auto 0 1.5rem; z-index:1; display:flex; justify-content:center; gap:.7rem; color:var(--text-muted); font-family:var(--font-mono); font-size:.72rem; letter-spacing:.1em; text-transform:uppercase; }
+ .scroll-cue { position:absolute; inset:auto 0 1.5rem; z-index:1; display:flex; justify-content:center; gap:.7rem; color:var(--text-muted); font-family:var(--font-mono); font-size:var(--font-size-00); letter-spacing:.1em; text-transform:uppercase; }
.scroll-cue::after { content:"↓"; color:var(--violet-8); animation:bob 1.6s ease-in-out infinite; }
.scenes { position:relative; }
.scene { position:relative; display:grid; grid-template-columns:minmax(0,.45fr) minmax(0,.55fr); align-items:center; min-height:100svh; gap:clamp(2rem,8vw,10rem); padding:clamp(4.5rem,12vh,9rem) clamp(1.5rem,8vw,10rem); border-block-end:1px solid color-mix(in srgb,var(--violet-6) 25%,var(--border)); }
@@ -43,21 +43,21 @@ sheet.replaceSync(`
.scene-art { position:relative; min-height:min(62vw,660px); display:grid; place-items:center; perspective:1000px; }
.component-stack { display:grid; width:min(100%,560px); transform:rotateX(8deg) rotateY(-12deg); transform-style:preserve-3d; }
.component { position:relative; display:grid; gap:.8rem; padding:1.4rem; border:1px solid color-mix(in srgb,var(--violet-6) 45%,var(--border)); background:linear-gradient(135deg,color-mix(in srgb,var(--violet-4) 18%,var(--bg-elevated)),color-mix(in srgb,var(--bg-base) 84%,transparent)); box-shadow:0 25px 65px color-mix(in srgb,var(--violet-11) 45%,transparent); font-family:var(--font-mono); transform:translateZ(var(--depth,0)); }
- .component:nth-child(2) { margin:1.4rem 0 0 3rem; --depth:45px; }.component:nth-child(3) { margin:1.4rem 0 0 6rem; --depth:90px; }.component strong { color:var(--violet-8); }.component span { color:var(--text-secondary); font-size:.84rem; }
+ .component:nth-child(2) { margin:1.4rem 0 0 3rem; --depth:45px; }.component:nth-child(3) { margin:1.4rem 0 0 6rem; --depth:90px; }.component strong { color:var(--violet-8); }.component span { color:var(--text-secondary); font-size:var(--font-size-tiny); }
.pulse-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:1rem; width:min(100%,560px); }.island { display:grid; place-items:center; min-height:150px; border:1px solid color-mix(in srgb,var(--violet-6) 42%,var(--border)); border-radius:1.1rem; background:radial-gradient(circle at 50% 50%,color-mix(in srgb,var(--violet-6) 25%,transparent),transparent 60%),var(--bg-elevated); color:var(--text-primary); font-family:var(--font-mono); animation:pulse 3s ease-in-out infinite; }.island:nth-child(2){animation-delay:-1s}.island:nth-child(3){animation-delay:-2s}.island small{color:var(--violet-8)}
- .output { display:grid; grid-template-columns:repeat(3,1fr); gap:1rem; width:min(100%,620px); }.target { min-height:230px; display:grid; align-content:space-between; padding:1.25rem; border:1px solid color-mix(in srgb,var(--violet-6) 43%,var(--border)); background:linear-gradient(145deg,color-mix(in srgb,var(--violet-5) 18%,transparent),var(--bg-elevated)); box-shadow:0 18px 50px color-mix(in srgb,var(--violet-10) 38%,transparent); }.target svg{width:42px;color:var(--violet-8)}.target strong{font-size:1.1rem}.target span{color:var(--text-secondary);font-family:var(--font-mono);font-size:.75rem}
+ .output { display:grid; grid-template-columns:repeat(3,1fr); gap:1rem; width:min(100%,620px); }.target { min-height:230px; display:grid; align-content:space-between; padding:1.25rem; border:1px solid color-mix(in srgb,var(--violet-6) 43%,var(--border)); background:linear-gradient(145deg,color-mix(in srgb,var(--violet-5) 18%,transparent),var(--bg-elevated)); box-shadow:0 18px 50px color-mix(in srgb,var(--violet-10) 38%,transparent); }.target svg{width:42px;color:var(--violet-8)}.target strong{font-size:var(--font-size-lede)}.target span{color:var(--text-secondary);font-family:var(--font-mono);font-size:var(--font-size-00)}
.final { grid-template-columns:1fr; text-align:center; min-height:82svh; }.final .scene-copy { max-width:800px; margin:auto; }.command { display:flex; align-items:center; justify-content:space-between; gap:1rem; width:min(100%,680px); margin:2.5rem auto; padding:1rem 1.1rem 1rem 1.35rem; border:1px solid color-mix(in srgb,var(--violet-6) 52%,var(--border)); border-radius:999px; background:color-mix(in srgb,var(--bg-elevated) 72%,transparent); color:var(--violet-8); font-family:var(--font-mono); text-align:left; }.command code{overflow:auto;white-space:nowrap}.final-actions{justify-content:center}
- .reference { width:min(1180px,calc(100% - 3rem)); margin:0 auto; padding:7rem 0; }.reference header{display:flex;justify-content:space-between;gap:2rem;align-items:end;margin-block-end:2rem}.reference h2{font-size:clamp(2.2rem,4vw,4.5rem);letter-spacing:-.06em;line-height:.92}.reference p{max-width:500px;color:var(--text-secondary);line-height:1.5}.links{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--border)}.links a{display:grid;gap:.6rem;min-height:180px;padding:1.4rem;border-inline-end:1px solid var(--border);color:inherit;text-decoration:none;background:color-mix(in srgb,var(--bg-elevated) 55%,transparent);transition:background .2s ease,transform .2s ease}.links a:last-child{border:0}.links a:hover{background:color-mix(in srgb,var(--violet-5) 18%,var(--bg-elevated));transform:translateY(-4px)}.links span{color:var(--violet-8);font-family:var(--font-mono);font-size:.75rem}.links strong{font-size:1.25rem}.links small{color:var(--text-secondary);line-height:1.4}
+ .reference { width:min(1180px,calc(100% - 3rem)); margin:0 auto; padding:7rem 0; }.reference header{display:flex;justify-content:space-between;gap:2rem;align-items:end;margin-block-end:2rem}.reference h2{font-size:clamp(2.2rem,4vw,4.5rem);letter-spacing:-.06em;line-height:.92}.reference p{max-width:500px;color:var(--text-secondary);line-height:1.5}.links{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--border)}.links a{display:grid;gap:.6rem;min-height:180px;padding:1.4rem;border-inline-end:1px solid var(--border);color:inherit;text-decoration:none;background:color-mix(in srgb,var(--bg-elevated) 55%,transparent);transition:background .2s ease,transform .2s ease}.links a:last-child{border:0}.links a:hover{background:color-mix(in srgb,var(--violet-5) 18%,var(--bg-elevated));transform:translateY(-4px)}.links span{color:var(--violet-8);font-family:var(--font-mono);font-size:var(--font-size-00)}.links strong{font-size:var(--font-size-2)}.links small{color:var(--text-secondary);line-height:1.4}
.cinematic-v2 { --film-progress:0; --scene-progress:0; --pointer-x:0; --pointer-y:0; position:relative; }
.cinematic-v2 .film { position:sticky; top:0; z-index:0; }
.cinematic-v2 .hero > div:first-child { opacity:clamp(0,calc(1 - var(--film-progress) * 3.2),1); transform:translateY(calc(var(--film-progress) * -4vh)); }
.hero-mark-wrap { position:relative; z-index:3; display:grid; place-items:center; width:clamp(15rem,34vw,31rem); aspect-ratio:1; filter:drop-shadow(0 0 70px color-mix(in srgb,var(--violet-6) 48%,transparent)); transform:translate3d(calc(min(calc(var(--film-progress) * 2.4),1) * -48vw + var(--pointer-x) * 8px),calc(min(calc(var(--film-progress) * 2.4),1) * -42vh + var(--pointer-y) * 8px),0) scale(calc(1 - min(calc(var(--film-progress) * 2.4),1) * .82)); transform-origin:center; will-change:transform; }
- .vinyl { position:absolute; inset:0; display:grid; place-items:center; border:1px solid color-mix(in srgb,#fff 18%,transparent); border-radius:50%; background:repeating-radial-gradient(circle at center,transparent 0 5px,color-mix(in srgb,#fff 7%,transparent) 6px,transparent 7px 12px),radial-gradient(circle at 32% 24%,color-mix(in srgb,var(--violet-7) 24%,transparent),transparent 22%),radial-gradient(circle at center,#18151e 0 15%,#09090c 15.5% 62%,#030304 63% 100%); box-shadow:inset 0 0 0 1px color-mix(in srgb,#fff 8%,transparent),inset 0 0 80px #000,0 32px 90px color-mix(in srgb,#000 72%,transparent); transform:rotate(calc(var(--film-progress) * 1080deg)); will-change:transform; }
- .vinyl::before { content:""; position:absolute; inset:3%; border-radius:50%; background:conic-gradient(from 210deg,transparent 0 8%,color-mix(in srgb,#fff 15%,transparent) 10%,transparent 14% 49%,color-mix(in srgb,var(--violet-5) 12%,transparent) 53%,transparent 58% 100%); mix-blend-mode:screen; }
- .vinyl::after { content:""; position:absolute; width:2.2%; aspect-ratio:1; border-radius:50%; background:#050507; border:1px solid color-mix(in srgb,#fff 28%,transparent); box-shadow:0 0 0 4px color-mix(in srgb,#000 55%,transparent); }
- .vinyl-label { position:relative; z-index:1; display:grid; place-items:center; width:31%; aspect-ratio:1; border:1px solid color-mix(in srgb,var(--violet-5) 42%,transparent); border-radius:50%; background:radial-gradient(circle at 35% 28%,color-mix(in srgb,var(--violet-4) 88%,#fff),var(--violet-9) 72%); box-shadow:0 0 0 3px #08070b,0 0 34px color-mix(in srgb,var(--violet-6) 40%,transparent); }
- .vinyl-wordmark { display:inline-flex; align-items:center; color:#fff; font-family:var(--font-mono); font-size:clamp(1rem,2.6vw,2.3rem); font-weight:800; letter-spacing:-.09em; line-height:1; text-shadow:0 1px 10px color-mix(in srgb,#000 55%,transparent); white-space:nowrap; }
- .vinyl-slash { color:color-mix(in srgb,var(--violet-2) 82%,#fff); }
+ .vinyl { position:absolute; inset:0; display:grid; place-items:center; border:1px solid color-mix(in srgb,var(--vinyl-highlight) 18%,transparent); border-radius:50%; background:repeating-radial-gradient(circle at center,transparent 0 5px,color-mix(in srgb,var(--vinyl-highlight) 7%,transparent) 6px,transparent 7px 12px),radial-gradient(circle at 32% 24%,color-mix(in srgb,var(--violet-7) 24%,transparent),transparent 22%),radial-gradient(circle at center,var(--vinyl-ink-3) 0 15%,var(--vinyl-ink-2) 15.5% 62%,var(--vinyl-ink-0) 63% 100%); box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--vinyl-highlight) 8%,transparent),inset 0 0 80px var(--vinyl-shadow),0 32px 90px color-mix(in srgb,var(--vinyl-shadow) 72%,transparent); transform:rotate(calc(var(--film-progress) * 1080deg)); will-change:transform; }
+ .vinyl::before { content:""; position:absolute; inset:3%; border-radius:50%; background:conic-gradient(from 210deg,transparent 0 8%,color-mix(in srgb,var(--vinyl-highlight) 15%,transparent) 10%,transparent 14% 49%,color-mix(in srgb,var(--violet-5) 12%,transparent) 53%,transparent 58% 100%); mix-blend-mode:screen; }
+ .vinyl::after { content:""; position:absolute; width:2.2%; aspect-ratio:1; border-radius:50%; background:var(--vinyl-ink-1); border:1px solid color-mix(in srgb,var(--vinyl-highlight) 28%,transparent); box-shadow:0 0 0 4px color-mix(in srgb,var(--vinyl-shadow) 55%,transparent); }
+ .vinyl-label { position:relative; z-index:1; display:grid; place-items:center; width:31%; aspect-ratio:1; border:1px solid color-mix(in srgb,var(--violet-5) 42%,transparent); border-radius:50%; background:radial-gradient(circle at 35% 28%,color-mix(in srgb,var(--violet-4) 88%,var(--vinyl-highlight)),var(--violet-9) 72%); box-shadow:0 0 0 3px var(--vinyl-ink-4),0 0 34px color-mix(in srgb,var(--violet-6) 40%,transparent); }
+ .vinyl-wordmark { display:inline-flex; align-items:center; color:var(--vinyl-highlight); font-family:var(--font-mono); font-size:clamp(1rem,2.6vw,2.3rem); font-weight:800; letter-spacing:-.09em; line-height:1; text-shadow:0 1px 10px color-mix(in srgb,var(--vinyl-shadow) 55%,transparent); white-space:nowrap; }
+ .vinyl-slash { color:color-mix(in srgb,var(--violet-2) 82%,var(--vinyl-highlight)); }
.cinematic-v2 .scenes { position:relative; z-index:2; margin-block-start:100vh; }
.cinematic-v2 .scene { background:linear-gradient(90deg,color-mix(in srgb,var(--bg-base) 96%,transparent),color-mix(in srgb,var(--bg-base) 72%,transparent)); backdrop-filter:blur(2px); }
.cinematic-v2 .component-stack { transform:rotateX(calc(18deg - var(--film-progress) * 12deg)) rotateY(calc(-24deg + var(--film-progress) * 18deg)) translateZ(calc(var(--film-progress) * 90px)); }
@@ -67,7 +67,7 @@ sheet.replaceSync(`
@keyframes orbit{50%{transform:rotate(12deg) scale(1.035)}} @keyframes reverse-orbit{to{transform:rotate(-360deg)}} @keyframes bob{50%{transform:translateY(5px)}} @keyframes pulse{50%{border-color:var(--violet-8);box-shadow:0 0 38px color-mix(in srgb,var(--violet-6) 36%,transparent)}}
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;scroll-behavior:auto!important}.film,.scene{min-height:auto}.hero{min-height:auto}.scene{padding-block:6rem}.component-stack{transform:none}}
@media (max-width:800px){.hero,.scene{grid-template-columns:1fr;min-height:auto;padding:6rem 1.4rem}.hero{padding-block-start:5rem}.aperture-stage{width:min(92vw,540px)}.scene-art{min-height:420px}.component:nth-child(2){margin-inline-start:1.5rem}.component:nth-child(3){margin-inline-start:3rem}.output{grid-template-columns:1fr 1fr}.target:last-child{grid-column:span 2}.links{grid-template-columns:1fr 1fr}.links a:nth-child(2){border-inline-end:0}.links a:nth-child(-n+2){border-block-end:1px solid var(--border)}}
- @media (max-width:480px){h1{font-size:clamp(3.6rem,18vw,5.6rem)}.pulse-grid{gap:.65rem}.island{min-height:105px;font-size:.72rem}.output{grid-template-columns:1fr}.target:last-child{grid-column:auto;min-height:150px}.command{border-radius:1.1rem;align-items:start;flex-direction:column}.links{grid-template-columns:1fr}.links a{border-inline-end:0;border-block-end:1px solid var(--border)}.links a:last-child{border-block-end:0}.reference header{display:grid}.scene h2{font-size:clamp(2.8rem,13vw,4.4rem)}}
+ @media (max-width:480px){h1{font-size:clamp(3.6rem,18vw,5.6rem)}.pulse-grid{gap:.65rem}.island{min-height:105px;font-size:var(--font-size-00)}.output{grid-template-columns:1fr}.target:last-child{grid-column:auto;min-height:150px}.command{border-radius:1.1rem;align-items:start;flex-direction:column}.links{grid-template-columns:1fr}.links a{border-inline-end:0;border-block-end:1px solid var(--border)}.links a:last-child{border-block-end:0}.reference header{display:grid}.scene h2{font-size:clamp(2.8rem,13vw,4.4rem)}}
`);
const references = [
diff --git a/www/app/site-ui/open-brand-mark.tsx b/www/app/site-ui/open-brand-mark.tsx
index 46a1db4f2..a8e25f70c 100644
--- a/www/app/site-ui/open-brand-mark.tsx
+++ b/www/app/site-ui/open-brand-mark.tsx
@@ -42,7 +42,7 @@ sheet.replaceSync(`
}
.slash {
- color: var(--violet-8, #8b5cf6);
+ color: var(--violet-8);
}
:host { view-transition-name: open-brand-mark; }
diff --git a/www/app/site-ui/open-layout.tsx b/www/app/site-ui/open-layout.tsx
index 744b65976..712093bc4 100644
--- a/www/app/site-ui/open-layout.tsx
+++ b/www/app/site-ui/open-layout.tsx
@@ -261,7 +261,7 @@ sheet.replaceSync(`
max-width: 100%;
color: var(--text-primary);
font-family: var(--font-mono);
- font-size: 12px;
+ font-size: var(--font-size-00);
font-weight: 800;
letter-spacing: -.09em;
line-height: 1;
@@ -334,55 +334,6 @@ sheet.replaceSync(`
margin-left: auto;
}
- /* CTA buttons */
- .btn-secondary {
- display: inline-flex;
- align-items: center;
- gap: var(--size-2);
- color: var(--text-primary);
- text-decoration: none;
- font-size: var(--font-size-button);
- font-weight: var(--font-weight-semibold);
- padding: var(--size-2) var(--size-4);
- border: var(--border-size-1) solid color-mix(in srgb, var(--border) 72%, var(--brand));
- border-radius: var(--radius-round);
- background: color-mix(in srgb, var(--bg-elevated) 76%, transparent);
- box-shadow: inset 0 1px 0 color-mix(in srgb, var(--gray-0) 70%, transparent);
- transition: all 0.15s ease;
- }
- .btn-secondary:hover {
- color: var(--brand-deep);
- border-color: var(--brand-light);
- background: color-mix(in srgb, var(--brand-pale) 42%, var(--bg-elevated));
- }
- .btn-secondary svg { flex-shrink: 0; }
-
- .btn-primary {
- display: inline-flex;
- align-items: center;
- gap: 4px;
- color: var(--on-brand);
- text-decoration: none;
- font-size: var(--font-size-button);
- font-weight: var(--font-weight-semibold);
- padding: var(--size-2) var(--size-4);
- border: var(--border-size-1) solid transparent;
- border-radius: var(--radius-round);
- background: linear-gradient(135deg, var(--brand), var(--brand-light));
- box-shadow: 0 var(--size-2) var(--size-5) var(--brand-glow);
- white-space: nowrap;
- transition: all 0.15s ease;
- }
- .btn-primary:hover {
- background: linear-gradient(135deg, var(--brand-hover), var(--brand-light));
- transform: translateY(calc(var(--border-size-1) * -1));
- }
-
- .header-right .btn-secondary,
- .header-right .btn-primary {
- display: none;
- }
-
.lang-switch {
display: inline-flex;
align-items: center;
@@ -430,7 +381,7 @@ sheet.replaceSync(`
.nav-section { margin-bottom: 1.5rem; }
.nav-section summary {
- font-size: 0.625rem;
+ font-size: var(--font-size-micro);
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.22em;
@@ -452,7 +403,7 @@ sheet.replaceSync(`
display: block;
color: var(--text-muted);
text-decoration: none;
- font-size: 0.85rem;
+ font-size: var(--font-size-tiny);
margin: .12rem .7rem;
padding: .5rem .8rem;
border-left: 2px solid transparent;
@@ -539,8 +490,6 @@ sheet.replaceSync(`
.header-nav {
gap: var(--size-3);
}
-
- .btn-secondary .btn-text { display: none; }
}
@media (max-width: 1040px) {
@@ -551,7 +500,6 @@ sheet.replaceSync(`
.mobile-menu-btn { display: flex; }
.header-inner { padding: 0 var(--size-4); gap: var(--size-2); }
.header-nav { display: none; }
- .btn-secondary .btn-text { display: none; }
.header-right { gap: 4px; }
.docs-sidebar {
@@ -602,7 +550,7 @@ sheet.replaceSync(`
flex: 1; display: flex; flex-direction: column;
align-items: center; justify-content: center; gap: 2px;
color: var(--text-muted);
- text-decoration: none; font-size: 10px; font-weight: 600;
+ text-decoration: none; font-size: var(--font-size-micro); font-weight: 600;
transition: color 0.15s ease;
-webkit-tap-highlight-color: transparent; padding: 4px 0;
}
@@ -616,9 +564,6 @@ sheet.replaceSync(`
.lang-switch { display: none; }
}
@media (max-width: 480px) {
- .btn-primary { display: none; }
- .btn-secondary { padding: 8px; border: none; }
- .btn-secondary .btn-text { display: none; }
.header-inner { padding: 0 var(--size-3); gap: var(--size-1); }
}
`);
diff --git a/www/vite.config.ts b/www/vite.config.ts
index 112ff2760..268f9469e 100644
--- a/www/vite.config.ts
+++ b/www/vite.config.ts
@@ -53,8 +53,23 @@ html[data-theme="light"],
--font-size-button: var(--font-size-0);
--font-size-body-sm: var(--font-size-0);
--font-size-caption: var(--font-size-00);
+ --font-size-micro: 0.625rem;
+ --font-size-tiny: 0.85rem;
+ --font-size-lede: 1.1rem;
+ --font-size-overline: 0.6875rem;
+ --font-size-article-title: 1.125rem;
+ --font-size-display-sm: 1.75rem;
+ --font-size-display-md: 2.125rem;
+ --font-size-display-lg: 2.625rem;
--font-weight-medium: var(--font-weight-5);
--font-weight-semibold: var(--font-weight-7);
+ --vinyl-ink-0: #030304;
+ --vinyl-ink-1: #050507;
+ --vinyl-ink-2: #09090c;
+ --vinyl-ink-3: #18151e;
+ --vinyl-ink-4: #08070b;
+ --vinyl-highlight: #ffffff;
+ --vinyl-shadow: #000000;
}
html[data-theme="dark"],
:host([data-theme="dark"]),