@tryvitris/website-harness 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/graph.yaml +16 -8
- package/agent/refs/browser.md +2 -0
- package/agent/refs/compose.md +2 -0
- package/agent/refs/design-quality.md +2 -0
- package/agent/refs/direction.md +2 -0
- package/agent/refs/implement.md +2 -0
- package/agent/refs/template-adaptation.md +2 -0
- package/agent/refs/template-library.md +2 -0
- package/agent/refs/typography.md +15 -0
- package/bin/api/agent/evaluate.js +7 -6
- package/bin/api/agent/grade.js +7 -6
- package/bin/api/cli/api.js +15 -14
- package/bin/api/cli.js +17 -16
- package/bin/api/engine.js +8 -7
- package/bin/api/hosting.js +9 -8
- package/bin/api/index.js +4 -3
- package/bin/api/render.js +2 -1
- package/bin/api/theme.js +2 -1
- package/bin/chunks/{chunk-JBSGJR7X.js → chunk-ATPI2YRF.js} +2 -2
- package/bin/chunks/{chunk-KIWEFRNG.js → chunk-BMD5GVUT.js} +6 -6
- package/bin/chunks/{chunk-AUO5I56E.js → chunk-C3F7XQD2.js} +194 -1
- package/bin/chunks/{chunk-UR4NWYVW.js → chunk-CPQQQ5YB.js} +3 -3
- package/bin/chunks/{chunk-LKN75JGA.js → chunk-GE6UUEG2.js} +13 -8
- package/bin/chunks/{chunk-445FZZEC.js → chunk-GM57SNLL.js} +9 -9
- package/bin/chunks/{chunk-RE4GOHSU.js → chunk-GO3XEQBA.js} +3 -3
- package/bin/chunks/{chunk-GQPUILFR.js → chunk-JPQCUN2J.js} +1301 -1252
- package/bin/chunks/{chunk-37F7XIMH.js → chunk-JTXFTNEA.js} +6 -1
- package/bin/chunks/{chunk-L44ZTNDM.js → chunk-NMTFSWPK.js} +6 -6
- package/bin/chunks/{chunk-VKU5TY5C.js → chunk-OQGUEQ6F.js} +1 -1
- package/bin/chunks/{chunk-M72KKZIB.js → chunk-Q6FLOYHS.js} +4 -3
- package/bin/chunks/{chunk-H3BS2EBR.js → chunk-QRIYA3GJ.js} +3 -3
- package/bin/chunks/chunk-S2XVNTQP.js +90 -0
- package/bin/chunks/{chunk-54QPYUM2.js → chunk-XJTAR7KM.js} +1 -1
- package/bin/chunks/{chunk-72Y4YMTV.js → chunk-YYK6367V.js} +2 -2
- package/bin/chunks/{chunk-65LRZIBP.js → chunk-YYYPSFFZ.js} +2 -2
- package/bin/chunks/{design-context-store-ETVS4N6W.js → design-context-store-BDYBQQCO.js} +7 -6
- package/bin/chunks/{packets-XFXKHSEY.js → packets-RXFWDCK2.js} +7 -6
- package/bin/chunks/{preparation-3OR7LVPQ.js → preparation-ETEEMB5H.js} +7 -6
- package/bin/cloudflare/backend.js +90 -11
- package/bin/types/src/agent/browser-typography.d.ts +33 -0
- package/bin/types/src/agent/theme-suite-identity.d.ts +1 -0
- package/bin/types/src/agent/typography-policy.d.ts +6 -0
- package/bin/types/src/compile/site.d.ts +1 -1
- package/bin/types/src/theme.d.ts +3 -1
- package/bin/types/src/types.d.ts +6 -1
- package/bin/types/src/typography.d.ts +27 -0
- package/bin/vitris-art.js +7 -6
- package/bin/vitris-build.js +5 -4
- package/bin/vitris-create-site.js +9 -8
- package/bin/vitris-cursor-hook.js +7 -6
- package/bin/vitris-eval.js +9 -8
- package/bin/vitris-go.js +9 -8
- package/bin/vitris-harvest.js +8 -7
- package/bin/vitris-knowledge.js +8 -7
- package/bin/vitris-launch-preflight.js +7 -6
- package/bin/vitris-motion-view.js +7 -6
- package/bin/vitris-references.js +5 -4
- package/bin/vitris-refresh.js +8 -7
- package/bin/vitris-stock.js +1 -1
- package/bin/vitris-templates.js +91 -1
- package/bin/vitris-themes.js +7 -6
- package/bin/vitris-upgrade.js +8 -7
- package/bin/vitris-verify-browser.js +33 -8
- package/bin/vitris-verify-performance.js +5 -4
- package/bin/vitris.js +17 -16
- package/design-system/MASTER.md +4 -0
- package/docs/CLI.md +4 -0
- package/package.json +2 -2
- package/templates/site/site.json +1 -0
- package/templates/site/theme/defaults.json +78 -17
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
typographyCss,
|
|
3
|
+
typographyEnabled
|
|
4
|
+
} from "./chunk-S2XVNTQP.js";
|
|
1
5
|
import {
|
|
2
6
|
iconCss,
|
|
3
7
|
renderIcon
|
|
@@ -2573,8 +2577,9 @@ function usedComponents(pages) {
|
|
|
2573
2577
|
}
|
|
2574
2578
|
return [...names];
|
|
2575
2579
|
}
|
|
2576
|
-
function siteCss(pages, catalog) {
|
|
2580
|
+
function siteCss(pages, catalog, site) {
|
|
2577
2581
|
const chunks = [baseCss, primitivesCss];
|
|
2582
|
+
if (typographyEnabled(site)) chunks.push(typographyCss());
|
|
2578
2583
|
if (pages.some((page) => page.bodyHtml.includes("data-vitris-icon="))) chunks.push(iconCss);
|
|
2579
2584
|
for (const name of usedComponents(pages)) {
|
|
2580
2585
|
const css = catalog[name]?.css;
|
|
@@ -12,11 +12,11 @@ import {
|
|
|
12
12
|
siteCss,
|
|
13
13
|
siteIslands,
|
|
14
14
|
sitemapXml
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-JTXFTNEA.js";
|
|
16
16
|
import {
|
|
17
17
|
mergeTheme,
|
|
18
18
|
themeCss
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-GE6UUEG2.js";
|
|
20
20
|
import {
|
|
21
21
|
escapeHtml
|
|
22
22
|
} from "./chunk-7FS67SRF.js";
|
|
@@ -256,9 +256,9 @@ async function buildSite(input) {
|
|
|
256
256
|
};
|
|
257
257
|
for (const page of compiled) {
|
|
258
258
|
const js = siteIslands([page], input.catalog);
|
|
259
|
-
pageAssets[page.path] = { css: asset(siteCss([page], input.catalog), "css"), js: js ? asset(js, "js") : null };
|
|
259
|
+
pageAssets[page.path] = { css: asset(siteCss([page], input.catalog, site), "css"), js: js ? asset(js, "js") : null };
|
|
260
260
|
}
|
|
261
|
-
if (backendOrigin) pageAssets[COOKIE_COMPLIANCE_PATH] = { css: asset(siteCss([], input.catalog), "css"), js: null };
|
|
261
|
+
if (backendOrigin) pageAssets[COOKIE_COMPLIANCE_PATH] = { css: asset(siteCss([], input.catalog, site), "css"), js: null };
|
|
262
262
|
const files = compileSite({
|
|
263
263
|
site,
|
|
264
264
|
pages: input.pages,
|
|
@@ -283,8 +283,8 @@ async function buildSite(input) {
|
|
|
283
283
|
await writeFile(dest, connectForms(file.html, backendOrigin, file.path, input.forms || []), "utf8");
|
|
284
284
|
written.push(rel);
|
|
285
285
|
}
|
|
286
|
-
await writeFile(join(input.outDir, "site.css"), siteCss(compiled, input.catalog), "utf8");
|
|
287
|
-
await writeFile(join(input.outDir, "theme.css"), themeCss(theme), "utf8");
|
|
286
|
+
await writeFile(join(input.outDir, "site.css"), siteCss(compiled, input.catalog, site), "utf8");
|
|
287
|
+
await writeFile(join(input.outDir, "theme.css"), themeCss(theme, site.typography), "utf8");
|
|
288
288
|
if (backendOrigin) {
|
|
289
289
|
await writeFile(join(input.outDir, "beacon.js"), beaconJs, "utf8");
|
|
290
290
|
written.push("beacon.js");
|
|
@@ -7,19 +7,19 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
gatherBlankOnboard,
|
|
9
9
|
persistOnboard
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-XJTAR7KM.js";
|
|
11
11
|
import {
|
|
12
12
|
persistSiteInputs,
|
|
13
13
|
recordManagedKit,
|
|
14
14
|
resolveSiteInputsLive
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-JPQCUN2J.js";
|
|
16
16
|
import {
|
|
17
17
|
initialState,
|
|
18
18
|
parseGraphYaml
|
|
19
19
|
} from "./chunk-BBV7PMFC.js";
|
|
20
20
|
import {
|
|
21
21
|
findHarnessRoot
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-QRIYA3GJ.js";
|
|
23
23
|
import {
|
|
24
24
|
save
|
|
25
25
|
} from "./chunk-T6PE4KN4.js";
|
|
@@ -115,6 +115,7 @@ async function createSite(opts) {
|
|
|
115
115
|
const site = JSON.parse(readFileSync(p, "utf8"));
|
|
116
116
|
site.slug = slug;
|
|
117
117
|
site.name = name;
|
|
118
|
+
if (mode === "preserve") delete site.typography;
|
|
118
119
|
site.siteId = site.siteId || randomUUID();
|
|
119
120
|
site.sourceFormatVersion = 1;
|
|
120
121
|
site.capabilities = backendOrigin ? ["analytics"] : [];
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
buildSite,
|
|
3
3
|
connectForms,
|
|
4
4
|
loadSiteDir
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-NMTFSWPK.js";
|
|
6
6
|
import {
|
|
7
7
|
leadsJs
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-JTXFTNEA.js";
|
|
9
9
|
import {
|
|
10
10
|
acquirePathLock,
|
|
11
11
|
files,
|
|
@@ -734,7 +734,7 @@ ${from} ${route.target} 301`;
|
|
|
734
734
|
save(join8(stage, "package-manifest.json"), { slug: local.site.slug || "", site: local.site });
|
|
735
735
|
const kernelParent = resolve3(import.meta.dirname, "..");
|
|
736
736
|
const kernelSource = existsSync8(join8(kernelParent, "compile")) ? kernelParent : join8(kernelParent, "src");
|
|
737
|
-
save(join8(stage, "build-evidence.json"), { version: 2, sourceHash: sourceHash(root), compilerHash: fingerprint(kernelSource, ["compile", "build", "runtime", "forms", "theme.ts"]) });
|
|
737
|
+
save(join8(stage, "build-evidence.json"), { version: 2, sourceHash: sourceHash(root), compilerHash: fingerprint(kernelSource, ["compile", "build", "runtime", "forms", "theme.ts", "typography.ts"]) });
|
|
738
738
|
const previous = out + `.previous-${Date.now()}-${process.pid}`;
|
|
739
739
|
if (existsSync8(out)) replacePath(out, previous);
|
|
740
740
|
try {
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// src/typography.ts
|
|
2
|
+
var TYPE_ROLES = ["display", "section", "subheading", "card-title", "body", "ui", "caption", "label"];
|
|
3
|
+
var MINIMUM_TYPE_PX = 12;
|
|
4
|
+
var DEFAULT_TYPE_ROLES = {
|
|
5
|
+
display: { size: "clamp(2.75rem, 1.8rem + 4vw, 5rem)", weight: 600, lineHeight: "1.08", tracking: "-0.03em", font: "display" },
|
|
6
|
+
section: { size: "clamp(2rem, 1.5rem + 2vw, 3.5rem)", weight: 600, lineHeight: "1.15", tracking: "-0.025em", font: "display" },
|
|
7
|
+
subheading: { size: "clamp(1.5rem, 1.3rem + 0.8vw, 2rem)", weight: 600, lineHeight: "1.25", tracking: "-0.015em", font: "display" },
|
|
8
|
+
"card-title": { size: "1.5rem", weight: 600, lineHeight: "1.3", tracking: "-0.01em", font: "display" },
|
|
9
|
+
body: { size: "1.125rem", weight: 400, lineHeight: "1.6", tracking: "normal", font: "body" },
|
|
10
|
+
ui: { size: "1rem", weight: 600, lineHeight: "1.5", tracking: "normal", font: "body" },
|
|
11
|
+
caption: { size: "0.875rem", weight: 400, lineHeight: "1.5", tracking: "normal", font: "body" },
|
|
12
|
+
label: { size: "0.875rem", weight: 600, lineHeight: "1.5", tracking: "0.02em", font: "body" }
|
|
13
|
+
};
|
|
14
|
+
var TYPE_SELECTORS = {
|
|
15
|
+
display: ["h1"],
|
|
16
|
+
section: ["h2", ".stat__value", ".stat--sm .stat__value", ".price__amount"],
|
|
17
|
+
subheading: ["h3", ".card__body > h3"],
|
|
18
|
+
"card-title": ["h4", ".card__body > h4", ".brand", ".quote", ".quote--lg", ".quote--card"],
|
|
19
|
+
body: ["body", ".lede", ".section__head .lede", ".lede--lg", ".list-check li", ".rating"],
|
|
20
|
+
ui: ["h5", "h6", "button", "input", "select", "textarea", "nav a", ".nav-links a", "summary", ".accordion summary", ".btn", ".btn-outline", ".btn-ghost", ".btn-arrow", ".skip-link", ".c-cookie-banner__title", ".c-cookie-banner__more", ".announcement a"],
|
|
21
|
+
caption: ["small", "figcaption", "sub", "sup", ".stat__label", ".price__period", ".byline", ".quote cite", ".quote footer", ".announcement", ".c-cookie-banner__text"],
|
|
22
|
+
label: ["label", ".eyebrow", ".badge", ".table th", ".chips > legend", ".chips__label", ".chips span"]
|
|
23
|
+
};
|
|
24
|
+
function typographyEnabled(site) {
|
|
25
|
+
if (site?.typography && site.typography.version !== 1) throw Error("Unsupported typography policy version");
|
|
26
|
+
return site?.typography?.version === 1;
|
|
27
|
+
}
|
|
28
|
+
function resolvedTypography(theme = {}) {
|
|
29
|
+
return Object.fromEntries(TYPE_ROLES.map((role) => [role, { ...DEFAULT_TYPE_ROLES[role], ...theme.typography?.roles?.[role] }]));
|
|
30
|
+
}
|
|
31
|
+
function validateTypography(value, requireRoles = false) {
|
|
32
|
+
const errors = [];
|
|
33
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return ["Typography requires a shared roles object in theme/defaults.json"];
|
|
34
|
+
const system = value;
|
|
35
|
+
if (!system.roles || typeof system.roles !== "object" || Array.isArray(system.roles)) return ["Typography roles must be an object"];
|
|
36
|
+
if (requireRoles) {
|
|
37
|
+
for (const role of TYPE_ROLES) if (!system.roles[role] || typeof system.roles[role] !== "object" || Object.keys(DEFAULT_TYPE_ROLES[role]).some((key) => !(key in system.roles[role]))) errors.push(`Typography role ${role} must declare size, weight, lineHeight, tracking and font`);
|
|
38
|
+
}
|
|
39
|
+
const check = (style, name) => {
|
|
40
|
+
if (!style || typeof style !== "object" || Array.isArray(style)) {
|
|
41
|
+
errors.push(`Invalid typography style: ${name}`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
for (const key of ["size", "lineHeight", "tracking"]) if (style[key] !== void 0 && (typeof style[key] !== "string" || !style[key].trim() || /[;{}<>]/.test(style[key]))) errors.push(`Invalid typography ${name}.${key}`);
|
|
45
|
+
if (style.weight !== void 0 && (!Number.isFinite(style.weight) || style.weight < 1 || style.weight > 1e3)) errors.push(`Invalid typography ${name}.weight`);
|
|
46
|
+
if (style.font !== void 0 && !["body", "display"].includes(style.font)) errors.push(`Invalid typography ${name}.font`);
|
|
47
|
+
for (const key of Object.keys(style)) if (!["size", "weight", "lineHeight", "tracking", "font", "role", "reason"].includes(key)) errors.push(`Unknown typography property ${name}.${key}`);
|
|
48
|
+
};
|
|
49
|
+
for (const [role, style] of Object.entries(system.roles)) {
|
|
50
|
+
if (!TYPE_ROLES.includes(role)) errors.push(`Unknown typography role: ${role}`);
|
|
51
|
+
check(style, role);
|
|
52
|
+
}
|
|
53
|
+
if (system.variants !== void 0 && (!system.variants || typeof system.variants !== "object" || Array.isArray(system.variants))) errors.push("Typography variants must be an object");
|
|
54
|
+
else for (const [name, variant] of Object.entries(system.variants || {})) {
|
|
55
|
+
if (!/^[a-z][a-z0-9-]*$/.test(name) || !variant || !TYPE_ROLES.includes(variant.role) || typeof variant.reason !== "string" || !variant.reason.trim()) errors.push(`Typography variant ${name} needs a known role and reason`);
|
|
56
|
+
check(variant, name);
|
|
57
|
+
}
|
|
58
|
+
return errors;
|
|
59
|
+
}
|
|
60
|
+
function typographyVariables(theme) {
|
|
61
|
+
const errors = theme.typography ? validateTypography(theme.typography) : [];
|
|
62
|
+
if (errors.length) throw Error(errors.join("\n"));
|
|
63
|
+
const roles = resolvedTypography(theme);
|
|
64
|
+
const values = (prefix, style) => ` --type-${prefix}-size: ${style.size};
|
|
65
|
+
--type-${prefix}-weight: ${style.weight};
|
|
66
|
+
--type-${prefix}-leading: ${style.lineHeight};
|
|
67
|
+
--type-${prefix}-tracking: ${style.tracking};
|
|
68
|
+
--type-${prefix}-font: var(--font-${style.font});`;
|
|
69
|
+
return [...TYPE_ROLES.map((role) => values(role, roles[role])), ...Object.entries(theme.typography?.variants || {}).map(([name, variant]) => values(`variant-${name}`, { ...roles[variant.role], ...variant }))].join("\n");
|
|
70
|
+
}
|
|
71
|
+
function typographyCss() {
|
|
72
|
+
const declarations = (name) => `font-size:var(--type-${name}-size);font-weight:var(--type-${name}-weight);line-height:var(--type-${name}-leading);letter-spacing:var(--type-${name}-tracking);font-family:var(--type-${name}-font);font-synthesis:none`;
|
|
73
|
+
return [...TYPE_ROLES.map((role) => `${TYPE_SELECTORS[role].join(",")}{${declarations(role)}}`), ...TYPE_ROLES.map((role) => `[data-type-role="${role}"][data-type-role]{${declarations(role)}}`)].join("\n");
|
|
74
|
+
}
|
|
75
|
+
function typographyVariantCss(theme) {
|
|
76
|
+
return Object.keys(theme.typography?.variants || {}).map((name) => `[data-type-variant="${name}"][data-type-variant][data-type-variant]{font-size:var(--type-variant-${name}-size);font-weight:var(--type-variant-${name}-weight);line-height:var(--type-variant-${name}-leading);letter-spacing:var(--type-variant-${name}-tracking);font-family:var(--type-variant-${name}-font)}`).join("\n");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
TYPE_ROLES,
|
|
81
|
+
MINIMUM_TYPE_PX,
|
|
82
|
+
DEFAULT_TYPE_ROLES,
|
|
83
|
+
TYPE_SELECTORS,
|
|
84
|
+
typographyEnabled,
|
|
85
|
+
resolvedTypography,
|
|
86
|
+
validateTypography,
|
|
87
|
+
typographyVariables,
|
|
88
|
+
typographyCss,
|
|
89
|
+
typographyVariantCss
|
|
90
|
+
};
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
sourceRevision,
|
|
8
8
|
verifyRefine,
|
|
9
9
|
withMutationLock
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-JPQCUN2J.js";
|
|
11
11
|
import {
|
|
12
12
|
assertRequestId,
|
|
13
13
|
parseChangePlan,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import {
|
|
18
18
|
buildVerified,
|
|
19
19
|
findHarnessRoot
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-QRIYA3GJ.js";
|
|
21
21
|
import {
|
|
22
22
|
files,
|
|
23
23
|
fingerprint,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-XL2DRAYI.js";
|
|
4
4
|
import {
|
|
5
5
|
sourceRevision
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JPQCUN2J.js";
|
|
7
7
|
import {
|
|
8
8
|
previewServer
|
|
9
9
|
} from "./chunk-WEFDVXFX.js";
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
providerConsoleWarning,
|
|
23
23
|
readOnlyEmbedProvider,
|
|
24
24
|
unresolvedCaptureBlockers
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-QRIYA3GJ.js";
|
|
26
26
|
import {
|
|
27
27
|
save,
|
|
28
28
|
within
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
loadPersistedDesignContextPacket,
|
|
4
4
|
persistDesignContextArtifacts,
|
|
5
5
|
resolveDesignContextExpansion
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JPQCUN2J.js";
|
|
7
7
|
import "./chunk-KVMZSQ3D.js";
|
|
8
8
|
import "./chunk-WOORR67N.js";
|
|
9
9
|
import "./chunk-PRLL7B63.js";
|
|
@@ -13,15 +13,16 @@ import "./chunk-M4LNHYYR.js";
|
|
|
13
13
|
import "./chunk-TY33XMHW.js";
|
|
14
14
|
import "./chunk-HL6JVA4A.js";
|
|
15
15
|
import "./chunk-M2ETYSVJ.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-C3F7XQD2.js";
|
|
17
17
|
import "./chunk-BIEDSEL2.js";
|
|
18
18
|
import "./chunk-IKNMBGGD.js";
|
|
19
19
|
import "./chunk-WEFDVXFX.js";
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
20
|
+
import "./chunk-QRIYA3GJ.js";
|
|
21
|
+
import "./chunk-NMTFSWPK.js";
|
|
22
|
+
import "./chunk-JTXFTNEA.js";
|
|
23
|
+
import "./chunk-GE6UUEG2.js";
|
|
24
24
|
import "./chunk-YYPYYOEV.js";
|
|
25
|
+
import "./chunk-S2XVNTQP.js";
|
|
25
26
|
import "./chunk-GZDLXYZV.js";
|
|
26
27
|
import "./chunk-G7MNMULR.js";
|
|
27
28
|
import "./chunk-T6PE4KN4.js";
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
partitionByObligation,
|
|
11
11
|
rankEvidenceRelevance,
|
|
12
12
|
selectDiverseEvidence
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-JPQCUN2J.js";
|
|
14
14
|
import "./chunk-KVMZSQ3D.js";
|
|
15
15
|
import "./chunk-WOORR67N.js";
|
|
16
16
|
import "./chunk-PRLL7B63.js";
|
|
@@ -20,15 +20,16 @@ import "./chunk-M4LNHYYR.js";
|
|
|
20
20
|
import "./chunk-TY33XMHW.js";
|
|
21
21
|
import "./chunk-HL6JVA4A.js";
|
|
22
22
|
import "./chunk-M2ETYSVJ.js";
|
|
23
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-C3F7XQD2.js";
|
|
24
24
|
import "./chunk-BIEDSEL2.js";
|
|
25
25
|
import "./chunk-IKNMBGGD.js";
|
|
26
26
|
import "./chunk-WEFDVXFX.js";
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
29
|
-
import "./chunk-
|
|
30
|
-
import "./chunk-
|
|
27
|
+
import "./chunk-QRIYA3GJ.js";
|
|
28
|
+
import "./chunk-NMTFSWPK.js";
|
|
29
|
+
import "./chunk-JTXFTNEA.js";
|
|
30
|
+
import "./chunk-GE6UUEG2.js";
|
|
31
31
|
import "./chunk-YYPYYOEV.js";
|
|
32
|
+
import "./chunk-S2XVNTQP.js";
|
|
32
33
|
import "./chunk-GZDLXYZV.js";
|
|
33
34
|
import "./chunk-G7MNMULR.js";
|
|
34
35
|
import "./chunk-T6PE4KN4.js";
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
withMutationLock,
|
|
31
31
|
withMutationLockAsync,
|
|
32
32
|
writeCommitJournal
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-JPQCUN2J.js";
|
|
34
34
|
import "./chunk-KVMZSQ3D.js";
|
|
35
35
|
import "./chunk-WOORR67N.js";
|
|
36
36
|
import "./chunk-PRLL7B63.js";
|
|
@@ -40,15 +40,16 @@ import "./chunk-M4LNHYYR.js";
|
|
|
40
40
|
import "./chunk-TY33XMHW.js";
|
|
41
41
|
import "./chunk-HL6JVA4A.js";
|
|
42
42
|
import "./chunk-M2ETYSVJ.js";
|
|
43
|
-
import "./chunk-
|
|
43
|
+
import "./chunk-C3F7XQD2.js";
|
|
44
44
|
import "./chunk-BIEDSEL2.js";
|
|
45
45
|
import "./chunk-IKNMBGGD.js";
|
|
46
46
|
import "./chunk-WEFDVXFX.js";
|
|
47
|
-
import "./chunk-
|
|
48
|
-
import "./chunk-
|
|
49
|
-
import "./chunk-
|
|
50
|
-
import "./chunk-
|
|
47
|
+
import "./chunk-QRIYA3GJ.js";
|
|
48
|
+
import "./chunk-NMTFSWPK.js";
|
|
49
|
+
import "./chunk-JTXFTNEA.js";
|
|
50
|
+
import "./chunk-GE6UUEG2.js";
|
|
51
51
|
import "./chunk-YYPYYOEV.js";
|
|
52
|
+
import "./chunk-S2XVNTQP.js";
|
|
52
53
|
import "./chunk-GZDLXYZV.js";
|
|
53
54
|
import "./chunk-G7MNMULR.js";
|
|
54
55
|
import "./chunk-T6PE4KN4.js";
|
|
@@ -14997,6 +14997,83 @@ function compileIcons(html2, route2 = "/") {
|
|
|
14997
14997
|
return html2;
|
|
14998
14998
|
}
|
|
14999
14999
|
|
|
15000
|
+
// src/typography.ts
|
|
15001
|
+
var TYPE_ROLES = ["display", "section", "subheading", "card-title", "body", "ui", "caption", "label"];
|
|
15002
|
+
var DEFAULT_TYPE_ROLES = {
|
|
15003
|
+
display: { size: "clamp(2.75rem, 1.8rem + 4vw, 5rem)", weight: 600, lineHeight: "1.08", tracking: "-0.03em", font: "display" },
|
|
15004
|
+
section: { size: "clamp(2rem, 1.5rem + 2vw, 3.5rem)", weight: 600, lineHeight: "1.15", tracking: "-0.025em", font: "display" },
|
|
15005
|
+
subheading: { size: "clamp(1.5rem, 1.3rem + 0.8vw, 2rem)", weight: 600, lineHeight: "1.25", tracking: "-0.015em", font: "display" },
|
|
15006
|
+
"card-title": { size: "1.5rem", weight: 600, lineHeight: "1.3", tracking: "-0.01em", font: "display" },
|
|
15007
|
+
body: { size: "1.125rem", weight: 400, lineHeight: "1.6", tracking: "normal", font: "body" },
|
|
15008
|
+
ui: { size: "1rem", weight: 600, lineHeight: "1.5", tracking: "normal", font: "body" },
|
|
15009
|
+
caption: { size: "0.875rem", weight: 400, lineHeight: "1.5", tracking: "normal", font: "body" },
|
|
15010
|
+
label: { size: "0.875rem", weight: 600, lineHeight: "1.5", tracking: "0.02em", font: "body" }
|
|
15011
|
+
};
|
|
15012
|
+
var TYPE_SELECTORS = {
|
|
15013
|
+
display: ["h1"],
|
|
15014
|
+
section: ["h2", ".stat__value", ".stat--sm .stat__value", ".price__amount"],
|
|
15015
|
+
subheading: ["h3", ".card__body > h3"],
|
|
15016
|
+
"card-title": ["h4", ".card__body > h4", ".brand", ".quote", ".quote--lg", ".quote--card"],
|
|
15017
|
+
body: ["body", ".lede", ".section__head .lede", ".lede--lg", ".list-check li", ".rating"],
|
|
15018
|
+
ui: ["h5", "h6", "button", "input", "select", "textarea", "nav a", ".nav-links a", "summary", ".accordion summary", ".btn", ".btn-outline", ".btn-ghost", ".btn-arrow", ".skip-link", ".c-cookie-banner__title", ".c-cookie-banner__more", ".announcement a"],
|
|
15019
|
+
caption: ["small", "figcaption", "sub", "sup", ".stat__label", ".price__period", ".byline", ".quote cite", ".quote footer", ".announcement", ".c-cookie-banner__text"],
|
|
15020
|
+
label: ["label", ".eyebrow", ".badge", ".table th", ".chips > legend", ".chips__label", ".chips span"]
|
|
15021
|
+
};
|
|
15022
|
+
function typographyEnabled(site) {
|
|
15023
|
+
if (site?.typography && site.typography.version !== 1) throw Error("Unsupported typography policy version");
|
|
15024
|
+
return site?.typography?.version === 1;
|
|
15025
|
+
}
|
|
15026
|
+
function resolvedTypography(theme = {}) {
|
|
15027
|
+
return Object.fromEntries(TYPE_ROLES.map((role) => [role, { ...DEFAULT_TYPE_ROLES[role], ...theme.typography?.roles?.[role] }]));
|
|
15028
|
+
}
|
|
15029
|
+
function validateTypography(value, requireRoles = false) {
|
|
15030
|
+
const errors = [];
|
|
15031
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return ["Typography requires a shared roles object in theme/defaults.json"];
|
|
15032
|
+
const system = value;
|
|
15033
|
+
if (!system.roles || typeof system.roles !== "object" || Array.isArray(system.roles)) return ["Typography roles must be an object"];
|
|
15034
|
+
if (requireRoles) {
|
|
15035
|
+
for (const role of TYPE_ROLES) if (!system.roles[role] || typeof system.roles[role] !== "object" || Object.keys(DEFAULT_TYPE_ROLES[role]).some((key2) => !(key2 in system.roles[role]))) errors.push(`Typography role ${role} must declare size, weight, lineHeight, tracking and font`);
|
|
15036
|
+
}
|
|
15037
|
+
const check = (style, name) => {
|
|
15038
|
+
if (!style || typeof style !== "object" || Array.isArray(style)) {
|
|
15039
|
+
errors.push(`Invalid typography style: ${name}`);
|
|
15040
|
+
return;
|
|
15041
|
+
}
|
|
15042
|
+
for (const key2 of ["size", "lineHeight", "tracking"]) if (style[key2] !== void 0 && (typeof style[key2] !== "string" || !style[key2].trim() || /[;{}<>]/.test(style[key2]))) errors.push(`Invalid typography ${name}.${key2}`);
|
|
15043
|
+
if (style.weight !== void 0 && (!Number.isFinite(style.weight) || style.weight < 1 || style.weight > 1e3)) errors.push(`Invalid typography ${name}.weight`);
|
|
15044
|
+
if (style.font !== void 0 && !["body", "display"].includes(style.font)) errors.push(`Invalid typography ${name}.font`);
|
|
15045
|
+
for (const key2 of Object.keys(style)) if (!["size", "weight", "lineHeight", "tracking", "font", "role", "reason"].includes(key2)) errors.push(`Unknown typography property ${name}.${key2}`);
|
|
15046
|
+
};
|
|
15047
|
+
for (const [role, style] of Object.entries(system.roles)) {
|
|
15048
|
+
if (!TYPE_ROLES.includes(role)) errors.push(`Unknown typography role: ${role}`);
|
|
15049
|
+
check(style, role);
|
|
15050
|
+
}
|
|
15051
|
+
if (system.variants !== void 0 && (!system.variants || typeof system.variants !== "object" || Array.isArray(system.variants))) errors.push("Typography variants must be an object");
|
|
15052
|
+
else for (const [name, variant] of Object.entries(system.variants || {})) {
|
|
15053
|
+
if (!/^[a-z][a-z0-9-]*$/.test(name) || !variant || !TYPE_ROLES.includes(variant.role) || typeof variant.reason !== "string" || !variant.reason.trim()) errors.push(`Typography variant ${name} needs a known role and reason`);
|
|
15054
|
+
check(variant, name);
|
|
15055
|
+
}
|
|
15056
|
+
return errors;
|
|
15057
|
+
}
|
|
15058
|
+
function typographyVariables(theme) {
|
|
15059
|
+
const errors = theme.typography ? validateTypography(theme.typography) : [];
|
|
15060
|
+
if (errors.length) throw Error(errors.join("\n"));
|
|
15061
|
+
const roles = resolvedTypography(theme);
|
|
15062
|
+
const values = (prefix, style) => ` --type-${prefix}-size: ${style.size};
|
|
15063
|
+
--type-${prefix}-weight: ${style.weight};
|
|
15064
|
+
--type-${prefix}-leading: ${style.lineHeight};
|
|
15065
|
+
--type-${prefix}-tracking: ${style.tracking};
|
|
15066
|
+
--type-${prefix}-font: var(--font-${style.font});`;
|
|
15067
|
+
return [...TYPE_ROLES.map((role) => values(role, roles[role])), ...Object.entries(theme.typography?.variants || {}).map(([name, variant]) => values(`variant-${name}`, { ...roles[variant.role], ...variant }))].join("\n");
|
|
15068
|
+
}
|
|
15069
|
+
function typographyCss() {
|
|
15070
|
+
const declarations = (name) => `font-size:var(--type-${name}-size);font-weight:var(--type-${name}-weight);line-height:var(--type-${name}-leading);letter-spacing:var(--type-${name}-tracking);font-family:var(--type-${name}-font);font-synthesis:none`;
|
|
15071
|
+
return [...TYPE_ROLES.map((role) => `${TYPE_SELECTORS[role].join(",")}{${declarations(role)}}`), ...TYPE_ROLES.map((role) => `[data-type-role="${role}"][data-type-role]{${declarations(role)}}`)].join("\n");
|
|
15072
|
+
}
|
|
15073
|
+
function typographyVariantCss(theme) {
|
|
15074
|
+
return Object.keys(theme.typography?.variants || {}).map((name) => `[data-type-variant="${name}"][data-type-variant][data-type-variant]{font-size:var(--type-variant-${name}-size);font-weight:var(--type-variant-${name}-weight);line-height:var(--type-variant-${name}-leading);letter-spacing:var(--type-variant-${name}-tracking);font-family:var(--type-variant-${name}-font)}`).join("\n");
|
|
15075
|
+
}
|
|
15076
|
+
|
|
15000
15077
|
// src/compile/site.ts
|
|
15001
15078
|
var baseCss = `*, *::before, *::after { box-sizing: border-box; }
|
|
15002
15079
|
html {
|
|
@@ -15336,8 +15413,9 @@ function usedComponents(pages) {
|
|
|
15336
15413
|
}
|
|
15337
15414
|
return [...names];
|
|
15338
15415
|
}
|
|
15339
|
-
function siteCss(pages, catalog) {
|
|
15416
|
+
function siteCss(pages, catalog, site) {
|
|
15340
15417
|
const chunks = [baseCss, primitivesCss];
|
|
15418
|
+
if (typographyEnabled(site)) chunks.push(typographyCss());
|
|
15341
15419
|
if (pages.some((page2) => page2.bodyHtml.includes("data-vitris-icon="))) chunks.push(iconCss);
|
|
15342
15420
|
for (const name of usedComponents(pages)) {
|
|
15343
15421
|
const css = catalog[name]?.css;
|
|
@@ -15480,8 +15558,9 @@ function mergeTheme(partial) {
|
|
|
15480
15558
|
if (!partial?.radiusLg) merged.radiusLg = partial?.radiusLg || defaultTheme.radiusLg;
|
|
15481
15559
|
return merged;
|
|
15482
15560
|
}
|
|
15483
|
-
function themeCss(tokens) {
|
|
15561
|
+
function themeCss(tokens, typography) {
|
|
15484
15562
|
const t = mergeTheme(tokens);
|
|
15563
|
+
const sharedType = typography?.version === 1;
|
|
15485
15564
|
return `:root {
|
|
15486
15565
|
--color-bg: ${t.colorBg};
|
|
15487
15566
|
--color-text: ${t.colorText};
|
|
@@ -15507,12 +15586,12 @@ function themeCss(tokens) {
|
|
|
15507
15586
|
--space-7: 3rem;
|
|
15508
15587
|
--space-8: 4.5rem;
|
|
15509
15588
|
--space-9: 6rem;
|
|
15510
|
-
--step-0: ${t.typeStep0 || "clamp(0.9rem, 0.85rem + 0.2vw, 1rem)"};
|
|
15511
|
-
--step-1: ${t.typeStep1 || "clamp(1rem, 0.95rem + 0.3vw, 1.125rem)"};
|
|
15512
|
-
--step-2: ${t.typeStep2 || "clamp(1.2rem, 1.05rem + 0.6vw, 1.5rem)"};
|
|
15513
|
-
--step-3: ${t.typeStep3 || "clamp(1.6rem, 1.25rem + 1.2vw, 2.25rem)"};
|
|
15589
|
+
--step-0: ${sharedType ? "var(--type-caption-size)" : t.typeStep0 || "clamp(0.9rem, 0.85rem + 0.2vw, 1rem)"};
|
|
15590
|
+
--step-1: ${sharedType ? "var(--type-body-size)" : t.typeStep1 || "clamp(1rem, 0.95rem + 0.3vw, 1.125rem)"};
|
|
15591
|
+
--step-2: ${sharedType ? "var(--type-subheading-size)" : t.typeStep2 || "clamp(1.2rem, 1.05rem + 0.6vw, 1.5rem)"};
|
|
15592
|
+
--step-3: ${sharedType ? "var(--type-section-size)" : t.typeStep3 || "clamp(1.6rem, 1.25rem + 1.2vw, 2.25rem)"};
|
|
15514
15593
|
--step-4: ${t.typeStep4 || "clamp(2.1rem, 1.5rem + 2.2vw, 3.5rem)"};
|
|
15515
|
-
--step-5: ${t.typeStep5 || "clamp(2.6rem, 1.7rem + 3.4vw, 4.75rem)"};
|
|
15594
|
+
--step-5: ${sharedType ? "var(--type-display-size)" : t.typeStep5 || "clamp(2.6rem, 1.7rem + 3.4vw, 4.75rem)"};
|
|
15516
15595
|
--tap-min: 44px;
|
|
15517
15596
|
--header-h: 4.75rem;
|
|
15518
15597
|
--section-y: ${t.sectionY || "clamp(3.5rem, 3rem + 3vw, 6rem)"};
|
|
@@ -15521,8 +15600,8 @@ function themeCss(tokens) {
|
|
|
15521
15600
|
--shadow-2: 0 8px 24px color-mix(in srgb, var(--color-text) 8%, transparent);
|
|
15522
15601
|
--shadow-3: 0 20px 48px color-mix(in srgb, var(--color-text) 12%, transparent);
|
|
15523
15602
|
--ring: 0 0 0 3px color-mix(in srgb, var(--color-focus) 35%, transparent);
|
|
15524
|
-
}
|
|
15525
|
-
`;
|
|
15603
|
+
${sharedType ? typographyVariables(t) + "\n" : ""}}
|
|
15604
|
+
${sharedType ? typographyVariantCss(t) + "\n" : ""}`;
|
|
15526
15605
|
}
|
|
15527
15606
|
|
|
15528
15607
|
// src/worker/github.ts
|
|
@@ -23629,12 +23708,12 @@ async function renderPreview(env, request) {
|
|
|
23629
23708
|
const compiled = compileAllPages(bundle.site, bundle.pages, bundle.catalog, origin);
|
|
23630
23709
|
if (rest === motionAssetHref.slice(1)) return compiled.some((page3) => page3.usesMotion) ? new Response(motionJs, { headers: { "content-type": "text/javascript; charset=utf-8", "cache-control": "public, max-age=31536000, immutable" } }) : text("Not found", 404);
|
|
23631
23710
|
if (rest === "site.css") {
|
|
23632
|
-
return new Response(siteCss(compiled, bundle.catalog), {
|
|
23711
|
+
return new Response(siteCss(compiled, bundle.catalog, bundle.site), {
|
|
23633
23712
|
headers: { "content-type": "text/css; charset=utf-8" }
|
|
23634
23713
|
});
|
|
23635
23714
|
}
|
|
23636
23715
|
if (rest === "theme.css") {
|
|
23637
|
-
return new Response(themeCss(bundle.theme), {
|
|
23716
|
+
return new Response(themeCss(bundle.theme, bundle.site.typography), {
|
|
23638
23717
|
headers: { "content-type": "text/css; charset=utf-8" }
|
|
23639
23718
|
});
|
|
23640
23719
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
import type { ThemeTokens } from '../types.ts';
|
|
3
|
+
export declare const TYPOGRAPHY_SCENARIO = "typography-v1-2026-10-28";
|
|
4
|
+
export type TypeObservation = {
|
|
5
|
+
selector: string;
|
|
6
|
+
text: string;
|
|
7
|
+
role: string;
|
|
8
|
+
variant?: string;
|
|
9
|
+
size: number;
|
|
10
|
+
renderedSize: number;
|
|
11
|
+
weight: string;
|
|
12
|
+
lineHeight: string;
|
|
13
|
+
tracking: string;
|
|
14
|
+
family: string;
|
|
15
|
+
};
|
|
16
|
+
export type TypographyCapture = {
|
|
17
|
+
path: string;
|
|
18
|
+
width: number;
|
|
19
|
+
state: string;
|
|
20
|
+
scenario: string;
|
|
21
|
+
observations: TypeObservation[];
|
|
22
|
+
failures: string[];
|
|
23
|
+
};
|
|
24
|
+
/** A serialized callback keeps browser DOM types out of the Worker/compiler TS program. */
|
|
25
|
+
export declare function captureTypography(page: Page, theme: Partial<ThemeTokens>, path: string, width: number, state: string): Promise<TypographyCapture>;
|
|
26
|
+
export declare function typographyConsistencyFailures(captures: TypographyCapture[]): string[];
|
|
27
|
+
export declare function typographyEvidenceFailures(report: {
|
|
28
|
+
scenario: string;
|
|
29
|
+
captures: TypographyCapture[];
|
|
30
|
+
failures: string[];
|
|
31
|
+
} | undefined, routes: string[]): string[];
|
|
32
|
+
/** Exercise ordinary local disclosure states without submitting forms or following links. */
|
|
33
|
+
export declare function captureTypographyStates(page: Page, theme: Partial<ThemeTokens>, path: string, width: number): Promise<TypographyCapture[]>;
|
|
@@ -4,7 +4,7 @@ export { beaconJs };
|
|
|
4
4
|
export declare const baseCss = "*, *::before, *::after { box-sizing: border-box; }\nhtml {\n -webkit-text-size-adjust: 100%;\n scroll-padding-top: calc(var(--header-h) + var(--space-3));\n}\nbody {\n margin: 0;\n font-family: var(--font-body);\n font-size: var(--step-1);\n background: var(--color-bg);\n color: var(--color-text);\n line-height: 1.6;\n}\nh1, h2, h3, h4 {\n font-family: var(--font-display);\n font-weight: 600;\n margin: 0;\n text-wrap: balance;\n overflow-wrap: anywhere;\n}\nh1 { font-size: var(--step-5); line-height: 1.05; letter-spacing: -0.03em; }\nh2 { font-size: var(--step-3); line-height: 1.15; letter-spacing: -0.025em; }\nh3 { font-size: var(--step-2); line-height: 1.25; letter-spacing: -0.015em; }\nh4 { font-size: var(--step-1); line-height: 1.3; letter-spacing: -0.01em; }\np { margin: 0 0 var(--space-4); text-wrap: pretty; }\np:last-child { margin-bottom: 0; }\na { color: inherit; }\na:hover { text-decoration-color: var(--color-accent); }\nimg { max-width: 100%; height: auto; display: block; }\nsvg { display: inline-block; vertical-align: middle; }\nul, ol { margin: 0 0 var(--space-4); padding-inline-start: 1.25rem; }\nul:last-child, ol:last-child { margin-bottom: 0; }\nsmall { font-size: var(--step-0); }\n:focus-visible {\n outline: 2px solid var(--color-focus);\n outline-offset: 3px;\n}\n.skip-link {\n position: absolute;\n left: var(--space-4);\n top: var(--space-4);\n z-index: 100;\n padding: var(--space-3) var(--space-4);\n background: var(--color-surface);\n color: var(--color-text);\n border: 1px solid var(--color-border);\n border-radius: var(--radius);\n text-decoration: none;\n font-weight: 600;\n transform: translateY(-160%);\n transition: transform 160ms ease;\n}\n.skip-link:focus {\n transform: translateY(0);\n}\n.visually-hidden {\n position: absolute !important;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n.wrap {\n width: min(var(--max-width), calc(100% - 2rem));\n margin-inline: auto;\n}\n@media (min-width: 720px) {\n .wrap { width: min(var(--max-width), calc(100% - 2.5rem)); }\n}\n.btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n min-height: var(--tap-min);\n padding: 0.75rem 1.5rem;\n line-height: 1.2;\n white-space: nowrap;\n background: var(--color-accent);\n color: var(--color-accent-text);\n text-decoration: none;\n border: 1px solid transparent;\n border-radius: var(--radius-pill);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 180ms ease, color 180ms ease, border-color 180ms ease;\n}\n.btn:hover {\n background: color-mix(in srgb, var(--color-accent) 88%, var(--color-text));\n}\n.btn-outline {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n min-height: var(--tap-min);\n padding: 0.75rem 1.5rem;\n line-height: 1.2;\n white-space: nowrap;\n background: transparent;\n color: var(--color-text);\n text-decoration: none;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-pill);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 180ms ease, color 180ms ease, border-color 180ms ease;\n}\n.btn-outline:hover {\n border-color: var(--color-text);\n background: color-mix(in srgb, var(--color-text) 6%, transparent);\n}\n.btn-arrow {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n min-height: var(--tap-min);\n white-space: nowrap;\n font-weight: 600;\n text-decoration: none;\n color: var(--color-text);\n transition: color 180ms ease;\n}\n.btn-arrow::after {\n content: \"\u2192\";\n transition: transform 180ms ease;\n}\n.btn-arrow:hover {\n color: var(--color-accent);\n}\n.btn-arrow:hover::after { transform: translateX(3px); }\n.btn-ghost {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n min-height: var(--tap-min);\n padding: 0.75rem 1.5rem;\n line-height: 1.2;\n white-space: nowrap;\n background: transparent;\n color: var(--color-text);\n text-decoration: none;\n border: 1px solid transparent;\n border-radius: var(--radius-pill);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n transition: border-color 180ms ease, color 180ms ease, background-color 180ms ease;\n}\n.btn-ghost:hover {\n background: color-mix(in srgb, var(--color-text) 6%, transparent);\n}\n.c-cookie-banner {\n position: fixed;\n inset-inline: 0;\n bottom: 0;\n z-index: 200;\n padding: var(--space-4) 0 calc(var(--space-4) + env(safe-area-inset-bottom, 0px));\n background: var(--color-surface);\n color: var(--color-text);\n border-top: 1px solid var(--color-border);\n box-shadow: 0 -8px 24px color-mix(in srgb, var(--color-text) 8%, transparent);\n}\n.c-cookie-banner__inner {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n}\n.c-cookie-banner__title {\n margin: 0 0 var(--space-2);\n font-family: var(--font-display);\n font-size: var(--step-1);\n font-weight: 600;\n letter-spacing: -0.02em;\n line-height: 1.25;\n}\n.c-cookie-banner__text {\n margin: 0;\n font-size: var(--step-0);\n color: var(--color-muted);\n max-width: 42rem;\n}\n.c-cookie-banner__actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-3);\n}\n.c-cookie-banner__more {\n min-height: var(--tap-min);\n display: inline-flex;\n align-items: center;\n font-weight: 600;\n font-size: var(--step-0);\n color: var(--color-text);\n text-decoration: underline;\n text-underline-offset: 0.15em;\n cursor: pointer;\n}\n.c-cookie-banner__more:hover { color: var(--color-accent); }\n@media (max-width: 719px) {\n .c-cookie-banner {\n /* A delayed first-visit beacon must not insert a banner into document flow. */\n max-height: 50dvh;\n overflow-y: auto;\n overscroll-behavior: contain;\n }\n}\n@media (min-width: 720px) {\n .c-cookie-banner__inner {\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-5);\n }\n .c-cookie-banner__actions { flex-shrink: 0; }\n}\n.c-lead-ok {\n background: var(--color-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius);\n padding: var(--space-3) var(--space-4);\n margin: 0 0 var(--space-4);\n color: var(--color-text);\n}\n.c-lead-hp {\n position: absolute;\n left: -9999px;\n width: 1px;\n height: 1px;\n overflow: hidden;\n}\n.c-cookie-page {\n padding: var(--space-7) 0 var(--space-8);\n}\n.c-cookie-page h1 {\n margin-bottom: var(--space-3);\n}\n.c-cookie-page h2 {\n margin: var(--space-6) 0 var(--space-3);\n}\n.c-cookie-page .wrap { max-width: 42rem; }\n.c-cookie-page p { color: var(--color-muted); }\n.c-cookie-page__actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-3);\n margin-top: var(--space-5);\n}\n\n/* Scroll reveal \u2014 armed only after islands mark above-fold .is-in */\n[data-reveal] {\n --reveal-x: 0;\n --reveal-y: var(--reveal-dist, 16px);\n}\n[data-reveal-strength=\"whisper\"] {\n --reveal-dist: 8px;\n --reveal-dur: 400ms;\n --reveal-ease: cubic-bezier(0.22, 1, 0.36, 1);\n}\n[data-reveal-strength=\"editorial\"] {\n --reveal-dist: 16px;\n --reveal-dur: 550ms;\n --reveal-ease: cubic-bezier(0.22, 1, 0.36, 1);\n}\n[data-reveal-strength=\"noticeable\"] {\n --reveal-dist: 24px;\n --reveal-dur: 650ms;\n --reveal-ease: cubic-bezier(0.22, 1, 0.36, 1);\n}\n[data-reveal-from=\"up\"] { --reveal-x: 0; --reveal-y: var(--reveal-dist, 16px); }\n[data-reveal-from=\"down\"] { --reveal-x: 0; --reveal-y: calc(var(--reveal-dist, 16px) * -1); }\n[data-reveal-from=\"left\"] { --reveal-x: calc(var(--reveal-dist, 16px) * -1); --reveal-y: 0; }\n[data-reveal-from=\"right\"] { --reveal-x: var(--reveal-dist, 16px); --reveal-y: 0; }\n[data-reveal-child][data-reveal-from=\"up\"] {\n --reveal-child-x: 0;\n --reveal-child-y: var(--reveal-dist, 16px);\n}\n[data-reveal-child][data-reveal-from=\"down\"] {\n --reveal-child-x: 0;\n --reveal-child-y: calc(var(--reveal-dist, 16px) * -1);\n}\n[data-reveal-child][data-reveal-from=\"left\"] {\n --reveal-child-x: calc(var(--reveal-dist, 16px) * -1);\n --reveal-child-y: 0;\n}\n[data-reveal-child][data-reveal-from=\"right\"] {\n --reveal-child-x: var(--reveal-dist, 16px);\n --reveal-child-y: 0;\n}\n@media (prefers-reduced-motion: reduce) {\n *, *::before, *::after { animation: none !important; transition: none !important; }\n}\n";
|
|
5
5
|
export declare function compilePage(page: PageSource, catalog: Catalog, site: SiteConfig, kernelOrigin: string): CompiledPage;
|
|
6
6
|
export declare function usedComponents(pages: CompiledPage[]): string[];
|
|
7
|
-
export declare function siteCss(pages: CompiledPage[], catalog: Catalog): string;
|
|
7
|
+
export declare function siteCss(pages: CompiledPage[], catalog: Catalog, site?: SiteConfig): string;
|
|
8
8
|
export declare function siteIslands(pages: CompiledPage[], catalog: Catalog): string;
|
|
9
9
|
export declare function renderDocument(opts: {
|
|
10
10
|
site: SiteConfig;
|
package/bin/types/src/theme.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { ThemeTokens } from "./types.ts";
|
|
2
2
|
export declare function mergeTheme(partial?: Partial<ThemeTokens> | null): ThemeTokens;
|
|
3
|
-
export declare function themeCss(tokens: ThemeTokens
|
|
3
|
+
export declare function themeCss(tokens: ThemeTokens, typography?: {
|
|
4
|
+
version: 1;
|
|
5
|
+
}): string;
|
package/bin/types/src/types.d.ts
CHANGED
|
@@ -26,6 +26,10 @@ export type SiteConfig = {
|
|
|
26
26
|
version: 2;
|
|
27
27
|
routes: "all-authored" | string[];
|
|
28
28
|
};
|
|
29
|
+
/** Shared type roles and rendered acceptance; omitted on historical sites. */
|
|
30
|
+
typography?: {
|
|
31
|
+
version: 1;
|
|
32
|
+
};
|
|
29
33
|
/** Design-run instrumentation; omitted from ordinary single-site authoring. */
|
|
30
34
|
designRun?: {
|
|
31
35
|
runId?: string;
|
|
@@ -61,13 +65,14 @@ export type ThemeTokens = {
|
|
|
61
65
|
/** Pill radius for `.btn` / `.btn-outline`. Cards keep `radius`. */
|
|
62
66
|
radiusPill: string;
|
|
63
67
|
maxWidth: string;
|
|
64
|
-
/**
|
|
68
|
+
/** Legacy scale and rhythm. Typography v1 resolves steps 0–3/5 from shared roles instead. */
|
|
65
69
|
typeStep0?: string;
|
|
66
70
|
typeStep1?: string;
|
|
67
71
|
typeStep2?: string;
|
|
68
72
|
typeStep3?: string;
|
|
69
73
|
typeStep4?: string;
|
|
70
74
|
typeStep5?: string;
|
|
75
|
+
typography?: import('./typography.ts').TypographySystem;
|
|
71
76
|
sectionY?: string;
|
|
72
77
|
};
|
|
73
78
|
/** @deprecated Editor-era content tree — dormant patch/workflow only. */
|