stylegallery 0.1.0 → 0.1.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.
Files changed (230) hide show
  1. package/AGENTS.md +4 -1
  2. package/DOMAINS.md +2 -6
  3. package/GOVERNANCE.md +10 -9
  4. package/README.md +29 -127
  5. package/consumer-reference/agent-native/v2/admission-policy.json +646 -0
  6. package/consumer-reference/agent-native/v2/material-registry.json +1 -0
  7. package/consumer-reference/agent-native/v2/schema/admission-policy.schema.json +50 -0
  8. package/consumer-reference/agent-native/v2/schema/material-manifest.schema.json +17 -0
  9. package/consumer-reference/agent-native/v2/schema/material-record.schema.json +20 -0
  10. package/consumer-reference/contract.md +1 -1
  11. package/consumer-reference/index.md +5 -3
  12. package/layout/index.md +124 -0
  13. package/log.md +57 -0
  14. package/package.json +183 -22
  15. package/scripts/agent-native/v2/experimental-extension-registry.mjs +143 -0
  16. package/scripts/agent-native/v2/extensions/a2a-projection.mjs +264 -0
  17. package/scripts/agent-native/v2/extensions/agui-projection.mjs +191 -0
  18. package/scripts/agent-native/v2/material-admission.mjs +295 -0
  19. package/scripts/agent-native/v2/material-cli-adapter.mjs +134 -0
  20. package/scripts/agent-native/v2/material-context.mjs +251 -0
  21. package/scripts/agent-native/v2/material-identity.mjs +71 -0
  22. package/scripts/agent-native/v2/material-mcp-adapter.mjs +253 -0
  23. package/scripts/agent-native/v2/material-operation-registry.mjs +123 -0
  24. package/scripts/agent-native/v2/material-queries.mjs +398 -0
  25. package/scripts/agent-native/v2/material-registry.mjs +319 -0
  26. package/scripts/sg-material-mcp.mjs +98 -0
  27. package/scripts/sg-material.mjs +27 -0
  28. package/consumer-reference/adapters/style-dictionary.config.mjs +0 -36
  29. package/consumer-reference/baselines/calibration.json +0 -260
  30. package/consumer-reference/baselines/manifest.json +0 -21
  31. package/consumer-reference/fixtures/consumer-conformance/e2e-fixture.mjs +0 -282
  32. package/consumer-reference/fixtures/consumer-conformance/manifest.json +0 -102
  33. package/consumer-reference/fixtures/consumer-conformance/runtime-proof.mjs +0 -32
  34. package/consumer-reference/fixtures/consumer-conformance/valid-migration-result.json +0 -18
  35. package/consumer-reference/fixtures/consumer-conformance/valid-migration.json +0 -142
  36. package/consumer-reference/fixtures/invalid-stable-ended-support.json +0 -19
  37. package/consumer-reference/fixtures/promotion/invalid-blocking-evidence.json +0 -26
  38. package/consumer-reference/fixtures/promotion/invalid-count-only.json +0 -29
  39. package/consumer-reference/fixtures/promotion/invalid-missing-owner-migration.json +0 -25
  40. package/consumer-reference/fixtures/promotion/invalid-normative-bypass-no-regression.json +0 -25
  41. package/consumer-reference/fixtures/promotion/invalid-related-counted-independent.json +0 -45
  42. package/consumer-reference/fixtures/promotion/invalid-stable-ended-support.json +0 -26
  43. package/consumer-reference/fixtures/promotion/manifest.json +0 -15
  44. package/consumer-reference/fixtures/promotion/valid-deferred-example.json +0 -67
  45. package/consumer-reference/fixtures/promotion/valid-normative-bypass.json +0 -67
  46. package/consumer-reference/fixtures/token-portability/invalid-cycle.json +0 -7
  47. package/consumer-reference/fixtures/token-portability/invalid-dangling-alias.json +0 -6
  48. package/consumer-reference/fixtures/token-portability/invalid-extends.json +0 -4
  49. package/consumer-reference/fixtures/token-portability/invalid-json-pointer.json +0 -7
  50. package/consumer-reference/fixtures/token-portability/invalid-resolver.json +0 -9
  51. package/consumer-reference/fixtures/token-portability/invalid-type-mismatch.json +0 -10
  52. package/consumer-reference/fixtures/token-portability/invalid-unknown-reserved.json +0 -6
  53. package/consumer-reference/fixtures/token-portability/invalid-untested-type.json +0 -6
  54. package/consumer-reference/fixtures/token-portability/valid-border.json +0 -14
  55. package/consumer-reference/fixtures/token-portability/valid-reference.json +0 -32
  56. package/consumer-reference/fixtures/token-portability/valid-whole-alias.json +0 -7
  57. package/consumer-reference/fixtures/valid-deprecated.json +0 -21
  58. package/consumer-reference/fixtures/valid-experimental.json +0 -19
  59. package/consumer-reference/generated/manifest.json +0 -40
  60. package/consumer-reference/generated/tokens.css +0 -12
  61. package/consumer-reference/policies/shared-experimental.json +0 -37
  62. package/consumer-reference/schema/ax-evidence.schema.json +0 -30
  63. package/consumer-reference/schema/baseline-manifest.schema.json +0 -55
  64. package/consumer-reference/schema/calibration-record.schema.json +0 -190
  65. package/consumer-reference/schema/capture-session.schema.json +0 -161
  66. package/consumer-reference/schema/component-state.schema.json +0 -150
  67. package/consumer-reference/schema/consumer-conformance-record.schema.json +0 -365
  68. package/consumer-reference/schema/dom-evidence.schema.json +0 -38
  69. package/consumer-reference/schema/evidence-record.schema.json +0 -81
  70. package/consumer-reference/schema/fixture-manifest.schema.json +0 -32
  71. package/consumer-reference/schema/item.schema.json +0 -188
  72. package/consumer-reference/schema/page-evidence-manifest.schema.json +0 -216
  73. package/consumer-reference/schema/page-evidence-session.schema.json +0 -119
  74. package/consumer-reference/schema/portable-tokens.schema.json +0 -104
  75. package/consumer-reference/schema/promotion-rfc.schema.json +0 -219
  76. package/consumer-reference/schema/runtime-evidence-manifest.schema.json +0 -33
  77. package/consumer-reference/schema/visual-evidence.schema.json +0 -31
  78. package/design-engineering/consumer-migration-readiness.md +0 -124
  79. package/design-engineering/interface-craft.md +0 -107
  80. package/design-engineering/reference-profiles/external-adaptation/index.md +0 -12
  81. package/design-engineering/reference-profiles/governed-local/editorial/components/button.component.json +0 -125
  82. package/design-engineering/reference-profiles/governed-local/editorial/evidence/button.evidence.json +0 -3504
  83. package/design-engineering/reference-profiles/governed-local/editorial/fixtures/button.fixture.json +0 -65
  84. package/design-engineering/reference-profiles/governed-local/editorial/generated/evidence-coverage.md +0 -23
  85. package/design-engineering/reference-profiles/governed-local/editorial/generated/keyboard-matrix.md +0 -19
  86. package/design-engineering/reference-profiles/governed-local/editorial/generated/state-matrix.md +0 -21
  87. package/design-engineering/reference-profiles/governed-local/editorial/local-foundations.json +0 -12
  88. package/design-engineering/reference-profiles/governed-local/editorial/states/button.states.json +0 -195
  89. package/design-engineering/reference-profiles/governed-local/editorial/tokens.dtcg.json +0 -17
  90. package/design-engineering/reference-profiles/governed-local/terminal/components/button.component.json +0 -125
  91. package/design-engineering/reference-profiles/governed-local/terminal/evidence/button.evidence.json +0 -3504
  92. package/design-engineering/reference-profiles/governed-local/terminal/fixtures/button.fixture.json +0 -65
  93. package/design-engineering/reference-profiles/governed-local/terminal/generated/evidence-coverage.md +0 -23
  94. package/design-engineering/reference-profiles/governed-local/terminal/generated/keyboard-matrix.md +0 -19
  95. package/design-engineering/reference-profiles/governed-local/terminal/generated/state-matrix.md +0 -21
  96. package/design-engineering/reference-profiles/governed-local/terminal/local-foundations.json +0 -12
  97. package/design-engineering/reference-profiles/governed-local/terminal/profile.json +0 -43
  98. package/design-engineering/reference-profiles/governed-local/terminal/states/button.states.json +0 -195
  99. package/design-engineering/reference-profiles/governed-local/terminal/tokens.dtcg.json +0 -17
  100. package/game-ui/classification.md +0 -82
  101. package/game-ui/reference-record.md +0 -62
  102. package/game-ui/screen-hierarchy.md +0 -107
  103. package/game-ui/unity/architecture.md +0 -166
  104. package/game-ui/unity/cli-loop.md +0 -84
  105. package/game-ui/unity/data/unity-technologies-public-repositories.json +0 -26654
  106. package/game-ui/unity/org-wiki.md +0 -146
  107. package/game-ui/unity/repository-map.md +0 -102
  108. package/game-ui/unity/ui-systems.md +0 -85
  109. package/motion/practice-reference.md +0 -145
  110. package/motion/review-workflow.md +0 -86
  111. package/motion/vocabulary.md +0 -82
  112. package/platform-guides/apple-interaction.md +0 -89
  113. package/scripts/agent-native/events.mjs +0 -113
  114. package/scripts/agent-native/immutable-store.mjs +0 -102
  115. package/scripts/artifact-metadata.mjs +0 -20
  116. package/scripts/audit-evidence-freshness.mjs +0 -308
  117. package/scripts/baseline-contract.mjs +0 -189
  118. package/scripts/baseline-schema-parity.mjs +0 -40
  119. package/scripts/build-reference-artifacts.mjs +0 -127
  120. package/scripts/calibration-raw-contract.mjs +0 -172
  121. package/scripts/capture-session-contract.mjs +0 -187
  122. package/scripts/component-state-artifact-fixture.mjs +0 -44
  123. package/scripts/component-state-contract.mjs +0 -99
  124. package/scripts/component-state-semantics.mjs +0 -128
  125. package/scripts/component-state-workflow-contract.mjs +0 -67
  126. package/scripts/component-state-workflow-negative-cases.mjs +0 -64
  127. package/scripts/consumer-conformance-contract.mjs +0 -198
  128. package/scripts/consumer-evidence-governance-contract.mjs +0 -210
  129. package/scripts/consumer-reference-case-runner.mjs +0 -93
  130. package/scripts/consumer-reference-schema.mjs +0 -155
  131. package/scripts/create-component-state-session.mjs +0 -100
  132. package/scripts/create-page-evidence-session.mjs +0 -139
  133. package/scripts/domain-document-boundaries.mjs +0 -40
  134. package/scripts/domain-validation-checks.mjs +0 -141
  135. package/scripts/evidence-artifact-contract.mjs +0 -191
  136. package/scripts/finalize-component-state-evidence.mjs +0 -165
  137. package/scripts/finalize-page-evidence.mjs +0 -197
  138. package/scripts/generate-consumer-reference-evidence.mjs +0 -154
  139. package/scripts/generate-patterns.mjs +0 -218
  140. package/scripts/governance-matrix-contract.mjs +0 -73
  141. package/scripts/governance-matrix-negative-cases.mjs +0 -114
  142. package/scripts/governance-policy-contract.mjs +0 -49
  143. package/scripts/governance-test-fixture.mjs +0 -321
  144. package/scripts/governance-workflow-negative-cases.mjs +0 -241
  145. package/scripts/governed-profile-registry.mjs +0 -125
  146. package/scripts/json-schema-formats.mjs +0 -31
  147. package/scripts/markdown-structure.mjs +0 -45
  148. package/scripts/page-artifact-metadata.mjs +0 -124
  149. package/scripts/page-evidence-contract.mjs +0 -297
  150. package/scripts/page-evidence-fixture.mjs +0 -271
  151. package/scripts/pattern-data.mjs +0 -325
  152. package/scripts/profile-record-contract.mjs +0 -140
  153. package/scripts/promotion-attestation-contract.mjs +0 -91
  154. package/scripts/promotion-boundary-test-contract.mjs +0 -92
  155. package/scripts/promotion-fixture-inventory.mjs +0 -109
  156. package/scripts/promotion-governance-contract.mjs +0 -28
  157. package/scripts/reference-artifact-path-contract.mjs +0 -28
  158. package/scripts/reference-profile-contract.mjs +0 -114
  159. package/scripts/reference-token-contract.mjs +0 -156
  160. package/scripts/run-consumer-page-evidence-ci.mjs +0 -170
  161. package/scripts/summarize-sentinel-calibration.mjs +0 -98
  162. package/scripts/test-agent-adapter-conformance.mjs +0 -250
  163. package/scripts/test-agent-conformance-receipt.mjs +0 -106
  164. package/scripts/test-agent-events.mjs +0 -81
  165. package/scripts/test-agent-execution-effects.mjs +0 -114
  166. package/scripts/test-agent-execution-fixtures.mjs +0 -140
  167. package/scripts/test-agent-execution-kernel.mjs +0 -39
  168. package/scripts/test-agent-execution-learning.mjs +0 -130
  169. package/scripts/test-agent-execution-lifecycle.mjs +0 -143
  170. package/scripts/test-agent-execution-safety.mjs +0 -158
  171. package/scripts/test-agent-execution-views.mjs +0 -117
  172. package/scripts/test-agent-identity-integrity-cases.mjs +0 -160
  173. package/scripts/test-agent-knowledge-kernel.mjs +0 -183
  174. package/scripts/test-agent-learning.mjs +0 -246
  175. package/scripts/test-agent-mcp.mjs +0 -246
  176. package/scripts/test-agent-native-schemas.mjs +0 -215
  177. package/scripts/test-agent-projections.mjs +0 -249
  178. package/scripts/test-agent-registry-mcp-integrity.mjs +0 -215
  179. package/scripts/test-agent-registry-mutations.mjs +0 -110
  180. package/scripts/test-audit-evidence-freshness.mjs +0 -177
  181. package/scripts/test-component-state-sentinel.mjs +0 -35
  182. package/scripts/test-component-state-source-contract.mjs +0 -83
  183. package/scripts/test-consumer-conformance-sentinel.mjs +0 -165
  184. package/scripts/test-consumer-reference-sentinel.mjs +0 -31
  185. package/scripts/test-generate-consumer-reference-evidence.mjs +0 -124
  186. package/scripts/test-json-cli-output.mjs +0 -151
  187. package/scripts/test-json-schema-formats.mjs +0 -40
  188. package/scripts/test-reference-adapters.mjs +0 -199
  189. package/scripts/test-renderer-purity.mjs +0 -34
  190. package/scripts/test-sg-cli.mjs +0 -129
  191. package/scripts/test-summarize-sentinel-calibration.mjs +0 -226
  192. package/scripts/test-validate-baseline-manifest.mjs +0 -234
  193. package/scripts/test-validate-component-state-artifacts.mjs +0 -243
  194. package/scripts/test-validate-component-state.mjs +0 -106
  195. package/scripts/test-validate-consumer-conformance.mjs +0 -427
  196. package/scripts/test-validate-consumer-reference-cli.mjs +0 -69
  197. package/scripts/test-validate-consumer-reference.mjs +0 -263
  198. package/scripts/test-validate-domains.mjs +0 -357
  199. package/scripts/test-validate-governance.mjs +0 -292
  200. package/scripts/test-validate-ia.mjs +0 -262
  201. package/scripts/test-validate-okf.mjs +0 -73
  202. package/scripts/test-validate-page-evidence.mjs +0 -302
  203. package/scripts/test-validate-patterns.mjs +0 -157
  204. package/scripts/test-validate-promotion-rfc.mjs +0 -250
  205. package/scripts/test-validate-reference-profiles.mjs +0 -170
  206. package/scripts/test-validate-unity-org-wiki.mjs +0 -57
  207. package/scripts/test-validate-unity-source-contracts.mjs +0 -67
  208. package/scripts/test-validate-vocabulary.mjs +0 -174
  209. package/scripts/test-validate-webpage-workflow.mjs +0 -293
  210. package/scripts/validate-baseline-manifest.mjs +0 -44
  211. package/scripts/validate-catalog.mjs +0 -65
  212. package/scripts/validate-component-state.mjs +0 -141
  213. package/scripts/validate-consumer-conformance.mjs +0 -477
  214. package/scripts/validate-consumer-reference.mjs +0 -288
  215. package/scripts/validate-domains.mjs +0 -237
  216. package/scripts/validate-governance.mjs +0 -248
  217. package/scripts/validate-ia.mjs +0 -136
  218. package/scripts/validate-links.mjs +0 -66
  219. package/scripts/validate-okf.mjs +0 -104
  220. package/scripts/validate-page-evidence.mjs +0 -191
  221. package/scripts/validate-patterns.mjs +0 -246
  222. package/scripts/validate-promotion-rfc.mjs +0 -224
  223. package/scripts/validate-reference-artifacts.mjs +0 -125
  224. package/scripts/validate-renderer-purity.mjs +0 -56
  225. package/scripts/validate-unity-org-wiki.mjs +0 -146
  226. package/scripts/validate-unity-source-contracts.mjs +0 -107
  227. package/scripts/validate-vocabulary.mjs +0 -115
  228. package/scripts/validate-webpage-workflow.mjs +0 -254
  229. package/scripts/visual-expectation-contract.mjs +0 -20
  230. package/scripts/workflow-action-contract.mjs +0 -163
@@ -1,271 +0,0 @@
1
- import fs from "node:fs";
2
- import os from "node:os";
3
- import path from "node:path";
4
- import { execFileSync, spawnSync } from "node:child_process";
5
- import { fileURLToPath } from "node:url";
6
- import { canonicalSourceManifest, digest, metadata } from "./page-evidence-contract.mjs";
7
-
8
- const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
9
- export const creator = path.join(repositoryRoot, "scripts/create-page-evidence-session.mjs");
10
- export const finalizer = path.join(repositoryRoot, "scripts/finalize-page-evidence.mjs");
11
- export const validator = path.join(repositoryRoot, "scripts/validate-page-evidence.mjs");
12
- export const semanticEnvironment = Object.freeze({
13
- browser: "Chromium 140.0.0",
14
- browser_revision: "chromium-1400",
15
- color_scheme: "light",
16
- locale: "en-US",
17
- page_scale_factor: 1,
18
- platform: "linux/amd64",
19
- reduced_motion: "no-preference",
20
- viewport: { height: 720, width: 320 },
21
- });
22
- const png = Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=", "base64");
23
- const crcTable = Uint32Array.from({ length: 256 }, (_, index) => {
24
- let value = index;
25
- for (let bit = 0; bit < 8; bit += 1) value = (value >>> 1) ^ (0xedb88320 & -(value & 1));
26
- return value >>> 0;
27
- });
28
-
29
- function pngChunk(type, data) {
30
- const name = Buffer.from(type, "ascii");
31
- const chunk = Buffer.alloc(12 + data.length);
32
- chunk.writeUInt32BE(data.length, 0);
33
- name.copy(chunk, 4);
34
- data.copy(chunk, 8);
35
- let crc = 0xffffffff;
36
- for (const byte of chunk.subarray(4, 8 + data.length)) crc = crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8);
37
- chunk.writeUInt32BE((crc ^ 0xffffffff) >>> 0, 8 + data.length);
38
- return chunk;
39
- }
40
-
41
- export function truncatedPng() {
42
- return Buffer.from(png.subarray(0, 24));
43
- }
44
-
45
- export function corruptPngCrc() {
46
- const bytes = Buffer.from(png);
47
- bytes[bytes.length - 1] ^= 0xff;
48
- return bytes;
49
- }
50
-
51
- export function pngWithTrailingBytes() {
52
- return Buffer.concat([png, Buffer.from("trailing bytes")]);
53
- }
54
-
55
- export function pngWithInvalidImageData() {
56
- return Buffer.concat([png.subarray(0, 33), pngChunk("IDAT", Buffer.alloc(0)), png.subarray(png.length - 12)]);
57
- }
58
-
59
- export function pngWithTrailingImageData() {
60
- const length = png.readUInt32BE(33);
61
- const data = png.subarray(41, 41 + length);
62
- return Buffer.concat([png.subarray(0, 33), pngChunk("IDAT", Buffer.concat([data, Buffer.from("trailing")])), png.subarray(45 + length)]);
63
- }
64
-
65
- function git(root, ...args) {
66
- return execFileSync("git", ["-c", `safe.directory=${root}`, ...args], { cwd: root, encoding: "utf8" }).trim();
67
- }
68
-
69
- export function writeJson(file, value) {
70
- fs.mkdirSync(path.dirname(file), { recursive: true });
71
- fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
72
- }
73
-
74
- export function runCli(file, args, root, env = {}) {
75
- const fixtureEnv = Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.startsWith("GITHUB_")));
76
- const child = spawnSync(process.execPath, [file, ...args, "--json"], { cwd: repositoryRoot, encoding: "utf8", env: { ...fixtureEnv, ...env } });
77
- let report = { failures: [{ code: "child_output_invalid", message: child.stdout || child.stderr, path: file }], ok: false };
78
- try { report = JSON.parse(child.stdout); } catch (error) { if (!(error instanceof SyntaxError)) throw error; }
79
- return { report, root, status: child.status };
80
- }
81
-
82
- export function initializeConsumer() {
83
- const root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), "stylegallery-page-evidence-")));
84
- execFileSync("git", ["init", "-b", "main"], { cwd: root, stdio: "ignore" });
85
- git(root, "config", "user.email", "fixture@example.com");
86
- git(root, "config", "user.name", "StyleGallery fixture");
87
- git(root, "remote", "add", "origin", "https://github.com/example/consumer.git");
88
- fs.mkdirSync(path.join(root, "src"), { recursive: true });
89
- fs.mkdirSync(path.join(root, "tests"), { recursive: true });
90
- fs.writeFileSync(path.join(root, "src/page.js"), "export const page = 'ready';\n");
91
- fs.writeFileSync(path.join(root, "tests/page.spec.js"), "const scenario = 'responsive-layout';\nvoid scenario;\n");
92
- git(root, "add", "src/page.js", "tests/page.spec.js");
93
- git(root, "commit", "-m", "fixture sources");
94
- return {
95
- relevantSources: ["src/page.js", "tests/page.spec.js"],
96
- repository: "example/consumer",
97
- revision: git(root, "rev-parse", "HEAD"),
98
- root,
99
- };
100
- }
101
-
102
- export function createConformance(fixture, { artifactName = "session-a", recordName = artifactName, runId = `run-${artifactName}`, scenarioId = "responsive-layout", sessionId = `session-${artifactName}` } = {}) {
103
- const sourceFailures = [];
104
- const source = canonicalSourceManifest(fixture.root, fixture.relevantSources, sourceFailures);
105
- if (!source || sourceFailures.length > 0) throw new Error(`fixture source manifest failed: ${JSON.stringify(sourceFailures)}`);
106
- const artifactRoot = path.join(fixture.root, "evidence", artifactName);
107
- const recordFile = path.join(fixture.root, "records", `${recordName}.json`);
108
- writeJson(recordFile, {
109
- claim_boundary: "Synthetic conformance fixture; not product certification.",
110
- consumer: { relevant_sources: fixture.relevantSources, repository: fixture.repository, revision: fixture.revision },
111
- id: `${recordName}-conformance`,
112
- page_evidence: { manifest: path.relative(fixture.root, path.join(artifactRoot, "page-evidence-manifest.json")), status: "applicable" },
113
- record_kind: "consumer_migration_conformance",
114
- scenarios: [{
115
- assertions: ["No document overflow."],
116
- argv: ["node", "tests/page.spec.js"],
117
- evidence_method: "browser",
118
- exit_code: 0,
119
- id: scenarioId,
120
- observable_actions: ["Render the page."],
121
- result_artifact: path.relative(fixture.root, path.join(artifactRoot, "runner", `${scenarioId}.json`)),
122
- run_id: runId,
123
- session_id: sessionId,
124
- source_digest: source.sha256,
125
- }],
126
- schema_version: "1.0",
127
- });
128
- return { artifactRoot, recordFile, runId, scenarioId, sessionId, source };
129
- }
130
-
131
- export function startSession(fixture, session, env = {}) {
132
- return runCli(creator, ["--root", fixture.root, "--record", session.recordFile, "--artifact-root", session.artifactRoot], fixture.root, env);
133
- }
134
-
135
- export function receiptFor(session) {
136
- const file = path.join(session.artifactRoot, "page-evidence-session.json");
137
- const bytes = fs.readFileSync(file);
138
- return { bytes, file, sha256: digest(bytes), value: JSON.parse(bytes) };
139
- }
140
-
141
- export function writeRunner(fixture, session, overrides = {}) {
142
- const receipt = receiptFor(session);
143
- const scenarioId = overrides.scenarioId ?? session.scenarioId;
144
- const runnerReference = `runner/${scenarioId}.json`;
145
- const artifactReference = overrides.artifactPath ?? `captures/${scenarioId}-320.png`;
146
- if (overrides.writeArtifact !== false) {
147
- const artifactFile = path.join(session.artifactRoot, artifactReference);
148
- fs.mkdirSync(path.dirname(artifactFile), { recursive: true });
149
- fs.writeFileSync(artifactFile, overrides.artifactBytes ?? png);
150
- }
151
- const evidence = overrides.evidence ?? (overrides.status === "failed"
152
- ? { kind: "failed", reason: "synthetic runner failure" }
153
- : { artifacts: [{ media_type: "image/png", path: artifactReference }], kind: "captured" });
154
- const runner = {
155
- evidence,
156
- nonce: overrides.nonce ?? receipt.value.nonce,
157
- receipt_sha256: overrides.receiptSha256 ?? receipt.sha256,
158
- recorded_at: overrides.recordedAt ?? receipt.value.started_at,
159
- record_kind: "page_evidence_runner_result",
160
- repository: overrides.repository ?? fixture.repository,
161
- revision: overrides.revision ?? fixture.revision,
162
- run: {
163
- attempt: receipt.value.attempt,
164
- id: overrides.runId ?? session.runId,
165
- repository: overrides.runRepository ?? fixture.repository,
166
- revision: overrides.runRevision ?? fixture.revision,
167
- source: "local",
168
- },
169
- scenario_id: scenarioId,
170
- schema_version: "1.0",
171
- semantic_environment: overrides.semanticEnvironment ?? semanticEnvironment,
172
- session_id: overrides.sessionId ?? session.sessionId,
173
- source_sha256: overrides.sourceSha256 ?? receipt.value.source.sha256,
174
- status: overrides.status ?? "passed",
175
- };
176
- const runnerFile = path.join(session.artifactRoot, runnerReference);
177
- writeJson(runnerFile, runner);
178
- return { artifactReference, runner, runnerFile, runnerReference };
179
- }
180
-
181
- export function declareCapturedArtifact(session, runnerRecord, artifactReference) {
182
- if (runnerRecord.artifactReference !== artifactReference) {
183
- fs.rmSync(path.join(session.artifactRoot, runnerRecord.artifactReference), { force: true });
184
- }
185
- const runner = {
186
- ...runnerRecord.runner,
187
- evidence: { artifacts: [{ media_type: "application/json", path: artifactReference }], kind: "captured" },
188
- };
189
- writeJson(runnerRecord.runnerFile, runner);
190
- return { ...runnerRecord, artifactReference, runner };
191
- }
192
-
193
- export function rewriteCompletedCapture(session, runnerRecord, artifactReference) {
194
- const declared = declareCapturedArtifact(session, runnerRecord, artifactReference);
195
- const manifestFile = path.join(session.artifactRoot, "page-evidence-manifest.json");
196
- const manifest = JSON.parse(fs.readFileSync(manifestFile));
197
- const runnerResult = metadata(fs.readFileSync(declared.runnerFile), "application/json", declared.runnerReference);
198
- const artifact = metadata(fs.readFileSync(path.join(session.artifactRoot, artifactReference)), "application/json", artifactReference);
199
- const [scenario, ...remaining] = manifest.scenarios;
200
- writeJson(manifestFile, {
201
- ...manifest,
202
- scenarios: [{ ...scenario, evidence: { artifacts: [artifact], kind: "captured" }, runner_result: runnerResult }, ...remaining],
203
- });
204
- }
205
-
206
- export function rewriteCompletedArtifact(session, runnerRecord, bytes) {
207
- const artifactFile = path.join(session.artifactRoot, runnerRecord.artifactReference);
208
- fs.writeFileSync(artifactFile, bytes);
209
- const artifact = { ...metadata(bytes, "image/png", runnerRecord.artifactReference), height: 1, width: 1 };
210
- const manifestFile = path.join(session.artifactRoot, "page-evidence-manifest.json");
211
- const manifest = JSON.parse(fs.readFileSync(manifestFile));
212
- const runnerResult = metadata(fs.readFileSync(runnerRecord.runnerFile), "application/json", runnerRecord.runnerReference);
213
- const [scenario, ...remaining] = manifest.scenarios;
214
- writeJson(manifestFile, {
215
- ...manifest,
216
- scenarios: [{ ...scenario, evidence: { artifacts: [artifact], kind: "captured" }, runner_result: runnerResult }, ...remaining],
217
- });
218
- }
219
-
220
- export function finalizeSession(fixture, session, runner, priorManifest) {
221
- const args = ["--root", fixture.root, "--artifact-root", session.artifactRoot, "--runner-result", runner.runnerReference, "--review-by", "2030-01-01T00:00:00Z"];
222
- if (priorManifest) args.push("--prior-manifest", priorManifest);
223
- return runCli(finalizer, args, fixture.root);
224
- }
225
-
226
- export function validateSession(fixture, session, priorManifest) {
227
- const args = ["--root", fixture.root, "--artifact-root", session.artifactRoot];
228
- if (priorManifest) args.push("--prior-manifest", priorManifest);
229
- return runCli(validator, args, fixture.root);
230
- }
231
-
232
- export function completeSession(fixture, session = createConformance(fixture)) {
233
- const start = startSession(fixture, session);
234
- if (start.status !== 0) return { fixture, session, start };
235
- const runner = writeRunner(fixture, session);
236
- const finalize = finalizeSession(fixture, session, runner);
237
- const validate = finalize.status === 0 ? validateSession(fixture, session) : undefined;
238
- return { finalize, fixture, runner, session, start, validate };
239
- }
240
-
241
- export function isolated(run) {
242
- const fixture = initializeConsumer();
243
- try { return run(fixture); }
244
- finally { cleanupFixture(fixture); }
245
- }
246
-
247
- export function started(fixture, options) {
248
- const session = createConformance(fixture, options);
249
- const start = startSession(fixture, session);
250
- if (start.status !== 0) throw new Error(`fixture start failed: ${JSON.stringify(start.report)}`);
251
- return session;
252
- }
253
-
254
- export function reuseSetup(fixture, { beforeCurrent, currentOptions } = {}) {
255
- const prior = completeSession(fixture, createConformance(fixture, { artifactName: "prior" }));
256
- beforeCurrent?.(fixture);
257
- const current = started(fixture, { artifactName: "current", ...currentOptions });
258
- const priorManifest = path.join(prior.session.artifactRoot, "page-evidence-manifest.json");
259
- const evidence = {
260
- kind: "reused",
261
- prior_manifest_sha256: digest(fs.readFileSync(priorManifest)),
262
- prior_run_id: prior.session.runId,
263
- prior_scenario_id: prior.session.scenarioId,
264
- prior_session_id: prior.session.sessionId,
265
- };
266
- return { current, evidence, prior, priorManifest };
267
- }
268
-
269
- export function cleanupFixture(fixture) {
270
- fs.rmSync(fixture.root, { force: true, recursive: true });
271
- }
@@ -1,325 +0,0 @@
1
- // allow: SIZE_OK - explicit 46-pattern sample and rule data table; generation logic stays separate.
2
- export const sources = {
3
- carbonGrid: "https://carbondesignsystem.com/elements/2x-grid/overview/",
4
- everyLayout: "https://every-layout.dev/layouts/",
5
- everySidebar: "https://every-layout.dev/layouts/sidebar/",
6
- everyStack: "https://every-layout.dev/layouts/stack/",
7
- govukLayout: "https://design-system.service.gov.uk/styles/layout/",
8
- materialCanonical: "https://m3.material.io/foundations/adaptive-design/canonical-layouts",
9
- mdnCookbook: "https://developer.mozilla.org/en-US/docs/Web/CSS/How_to/Layout_cookbook",
10
- mdnGrid: "https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/CSS_layout/Grids",
11
- mdnOverflow: "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/overflow",
12
- mdnPosition: "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/position",
13
- webOneLine: "https://web.dev/articles/one-line-layouts",
14
- };
15
-
16
- export const samples = {
17
- "stack": `
18
- <section class="stack" aria-labelledby="stack-heading">
19
- <h2 id="stack-heading">Release checklist</h2>
20
- <p>Review copy, verify forms, and publish the notes in order.</p>
21
- <button>Start review</button>
22
- </section>`,
23
- "box": `
24
- <aside class="box" aria-labelledby="box-heading">
25
- <h2 id="box-heading">Support window</h2>
26
- <p>Responses resume Monday at 09:00.</p>
27
- </aside>`,
28
- "center": `
29
- <article class="center" aria-labelledby="center-heading">
30
- <h2 id="center-heading">Editorial policy</h2>
31
- <p>Long-form guidance stays readable while the page around it remains fluid.</p>
32
- </article>`,
33
- "cluster": `
34
- <nav class="cluster" aria-label="Project actions">
35
- <a href="#">Backlog</a>
36
- <a href="#">Milestones</a>
37
- <a href="#">Roadmap</a>
38
- </nav>`,
39
- "content-limiter": `
40
- <article class="content_limiter" aria-labelledby="limiter-heading">
41
- <h2 id="limiter-heading">Incident summary</h2>
42
- <p>The report keeps a comfortable measure even inside a wide dashboard shell.</p>
43
- </article>`,
44
- "super-center": `
45
- <section class="super_center" aria-labelledby="centered-dialog-title">
46
- <form aria-labelledby="centered-dialog-title">
47
- <h2 id="centered-dialog-title">Confirm archive</h2>
48
- <button>Archive project</button>
49
- </form>
50
- </section>`,
51
- "icon-frame": `
52
- <span class="icon_frame" aria-label="Calendar">
53
- <svg aria-hidden="true" viewBox="0 0 24 24"></svg>
54
- </span>`,
55
- "frame": `
56
- <figure class="frame">
57
- <img alt="Product walkthrough still" class="frame_media">
58
- </figure>`,
59
- "cover": `
60
- <section class="cover" aria-labelledby="cover-title">
61
- <header><p>Step 2 of 4</p></header>
62
- <main><h1 id="cover-title">Choose a billing profile</h1></main>
63
- <footer><button>Continue</button></footer>
64
- </section>`,
65
- "sidebar": `
66
- <section class="sidebar" aria-labelledby="sidebar-title">
67
- <article class="sidebar_primary">
68
- <h2 id="sidebar-title">Quarterly planning notes</h2>
69
- <p>The main article keeps priority when the available inline space changes.</p>
70
- </article>
71
- <aside class="sidebar_secondary">Meeting agenda and owners</aside>
72
- </section>`,
73
- "switcher": `
74
- <section class="switcher" aria-label="Pricing tiers">
75
- <article class="switcher_item">Starter plan</article>
76
- <article class="switcher_item">Team plan</article>
77
- <article class="switcher_item">Enterprise plan</article>
78
- </section>`,
79
- "media-object": `
80
- <article class="media_object">
81
- <figure class="media_object_media"><img alt="Speaker portrait"></figure>
82
- <div class="media_object_content">
83
- <h2>Design systems briefing</h2>
84
- <p>Speaker details align beside the portrait without squeezing the text.</p>
85
- </div>
86
- </article>`,
87
- "split-nav": `
88
- <nav class="split_nav" aria-label="Documentation">
89
- <section class="split_nav_primary"><a href="#">Guides</a><a href="#">API</a></section>
90
- <section class="split_nav_secondary"><a href="#">Sign in</a></section>
91
- </nav>`,
92
- "holy-grail": `
93
- <section class="holy_grail" aria-label="News page">
94
- <header class="holy_grail_header">Daily briefing</header>
95
- <aside class="holy_grail_left">Topic navigation</aside>
96
- <main class="holy_grail_main">Lead story and article stream</main>
97
- <aside class="holy_grail_right">Market snapshot</aside>
98
- <footer class="holy_grail_footer">Edition links</footer>
99
- </section>`,
100
- "sticky-footer": `
101
- <section class="sticky_footer" aria-label="Account setup">
102
- <header>Account setup</header>
103
- <main class="sticky_footer_main">Profile fields and preferences</main>
104
- <footer><button>Save profile</button></footer>
105
- </section>`,
106
- "sticky-header": `
107
- <header class="sticky_header">
108
- <nav aria-label="Repository"><a href="#">Code</a><a href="#">Issues</a><a href="#">Pull requests</a></nav>
109
- </header>`,
110
- "scroll-body-shell": `
111
- <section class="scroll_body_shell" aria-label="Inbox">
112
- <header>Inbox filters</header>
113
- <main class="scroll_body_shell_body">Message list owns vertical scrolling</main>
114
- <footer>Selected message actions</footer>
115
- </section>`,
116
- "fixed-sidenav-shell": `
117
- <section class="fixed_sidenav_shell" aria-label="Settings">
118
- <nav class="fixed_sidenav_shell_list"><a href="#">Profile</a><a href="#">Billing</a></nav>
119
- <main class="fixed_sidenav_shell_main">Editable settings form scrolls independently</main>
120
- </section>`,
121
- "sticky-aside": `
122
- <section class="sticky_aside" aria-label="Long article">
123
- <main class="sticky_aside_main">Article sections continue down the page.</main>
124
- <aside class="sticky_aside_side">Table of contents</aside>
125
- </section>`,
126
- "ram-grid": `
127
- <section class="ram_grid" aria-label="Photo albums">
128
- <article>Spring launch album</article>
129
- <article>Customer meetup album</article>
130
- <article>Workshop album</article>
131
- </section>`,
132
- "card-grid": `
133
- <section class="card_grid" aria-label="Project cards">
134
- <article>Design audit</article>
135
- <article>Analytics migration</article>
136
- <article>Onboarding rewrite</article>
137
- </section>`,
138
- "twelve-span-grid": `
139
- <section class="twelve_span_grid" aria-label="Dashboard modules">
140
- <article class="twelve_span_grid_item">Revenue module</article>
141
- <article class="twelve_span_grid_item">Retention module</article>
142
- <article class="twelve_span_grid_item">Pipeline module</article>
143
- </section>`,
144
- "page-grid": `
145
- <section class="page_grid" aria-label="Article page">
146
- <main class="page_grid_content">Centered article track with fluid outer gutters</main>
147
- </section>`,
148
- "grid-wrapper": `
149
- <section class="grid_wrapper" aria-label="Marketing page">
150
- <main class="grid_wrapper_main">Centered campaign copy</main>
151
- </section>`,
152
- "columns": `
153
- <article class="columns" aria-labelledby="columns-heading">
154
- <h2 id="columns-heading">Release notes</h2>
155
- <p>Several short updates can flow into balanced columns when there is room.</p>
156
- <p>When the container narrows, the same content returns to a single column.</p>
157
- </article>`,
158
- "deconstructed-pancake": `
159
- <section class="deconstructed_pancake" aria-label="Plan comparison">
160
- <article class="deconstructed_pancake_item">Solo plan</article>
161
- <article class="deconstructed_pancake_item">Studio plan</article>
162
- <article class="deconstructed_pancake_item">Agency plan</article>
163
- </section>`,
164
- "line-up": `
165
- <article class="line_up" aria-labelledby="line-up-title">
166
- <section class="line_up_body"><h2 id="line-up-title">Implementation proposal</h2><p>Variable-length summary copy sits above the aligned action row.</p></section>
167
- <footer class="line_up_footer"><button>Review proposal</button></footer>
168
- </article>`,
169
- "clamped-card": `
170
- <article class="clamped_card" aria-labelledby="clamped-title">
171
- <h2 id="clamped-title">Invite teammate</h2>
172
- <p>The card grows with the viewport but stops at the intended reading width.</p>
173
- </article>`,
174
- "fluid-styles": `
175
- <section class="fluid_styles" aria-labelledby="fluid-title">
176
- <h2 id="fluid-title">Operations overview</h2>
177
- <p>The region fills the parent without exceeding the shared page measure.</p>
178
- </section>`,
179
- "split-screen": `
180
- <section class="split_screen" aria-label="Compare documents">
181
- <section class="split_screen_pane">Draft contract</section>
182
- <section class="split_screen_pane">Reviewed contract</section>
183
- </section>`,
184
- "list-detail": `
185
- <section class="list_detail" aria-label="Customer records">
186
- <nav class="list_detail_list"><a href="#">Acme Co.</a><a href="#">Northwind</a></nav>
187
- <section class="list_detail_detail">Selected customer timeline</section>
188
- </section>`,
189
- "supporting-pane": `
190
- <section class="supporting_pane" aria-label="Invoice editor">
191
- <main class="supporting_pane_main">Invoice line-item editor</main>
192
- <aside class="supporting_pane_summary">Payment summary</aside>
193
- </section>`,
194
- "feed": `
195
- <section class="feed" aria-label="Activity feed">
196
- <article>Build completed</article>
197
- <article>Review requested</article>
198
- <article>Deployment approved</article>
199
- </section>`,
200
- "breadcrumb": `
201
- <nav class="breadcrumb" aria-label="Breadcrumb">
202
- <a href="#">Workspace</a>
203
- <a href="#">Projects</a>
204
- <span>Layout gallery</span>
205
- </nav>`,
206
- "pagination": `
207
- <nav class="pagination" aria-label="Search results pages">
208
- <a href="#">Previous</a>
209
- <a href="#">Page 4</a>
210
- <a href="#">Next</a>
211
- </nav>`,
212
- "badge-list": `
213
- <section class="badge_list" aria-label="Repository counts">
214
- <div class="badge_list_item"><span>Open issues</span><span>12</span></div>
215
- <div class="badge_list_item"><span>Pull requests</span><span>4</span></div>
216
- <div class="badge_list_item"><span>Reviews waiting</span><span>7</span></div>
217
- </section>`,
218
- "step-nav": `
219
- <nav class="step_nav" aria-label="Checkout steps">
220
- <a href="#">Shipping address</a>
221
- <a href="#">Payment method</a>
222
- <a href="#">Order review</a>
223
- </nav>`,
224
- "tab-strip": `
225
- <nav class="tab_strip" aria-label="Report views">
226
- <a href="#">Summary</a>
227
- <a href="#">Cohorts</a>
228
- <a href="#">Exports</a>
229
- </nav>`,
230
- "reel": `
231
- <section class="reel" aria-label="Upcoming events">
232
- <article>Design critique</article>
233
- <article>Planning workshop</article>
234
- <article>Launch review</article>
235
- </section>`,
236
- "imposter": `
237
- <section class="imposter_anchor" aria-label="Draft editor">
238
- <p>Draft body text stays in normal document flow.</p>
239
- <section class="imposter" aria-label="Modal placement">
240
- <dialog open>Unsaved changes confirmation</dialog>
241
- </section>
242
- </section>`,
243
- "panel-layout": `
244
- <section class="panel_layout" aria-label="Console workspace">
245
- <main class="panel_layout_main">Query editor</main>
246
- <aside class="panel_layout_side">Execution history</aside>
247
- </section>`,
248
- "overlay-stack": `
249
- <section class="overlay_stack" aria-label="Map with controls">
250
- <figure class="overlay_stack_item">Transit map</figure>
251
- <form class="overlay_stack_item">Route search controls</form>
252
- </section>`,
253
- "wrap-row": `
254
- <form class="wrap_row" aria-label="Filter tickets">
255
- <label>Status <select></select></label>
256
- <label>Owner <select></select></label>
257
- <button>Apply filters</button>
258
- </form>`,
259
- "dense-grid": `
260
- <section class="dense_grid" aria-label="Keyboard shortcuts">
261
- <kbd>Cmd K</kbd>
262
- <kbd>Cmd Shift P</kbd>
263
- <kbd>Esc</kbd>
264
- </section>`,
265
- "masonry-approx": `
266
- <section class="masonry_approx" aria-label="Research notes">
267
- <article>Interview excerpt with a longer observation.</article>
268
- <article>Short survey result.</article>
269
- <article>Workshop synthesis note.</article>
270
- </section>`,
271
- "main-with-rail": `
272
- <section class="main_with_rail" aria-label="Documentation page">
273
- <main class="main_with_rail_main">API reference article</main>
274
- <aside class="main_with_rail_side">On this page links</aside>
275
- </section>`,
276
- };
277
-
278
- export const patterns = [
279
- ["stack", "Stacking", "Create consistent vertical rhythm between direct children.", "block", "fluid", sources.everyStack, [[".stack", { display: "grid", gap: "1rem" }]]],
280
- ["box", "Containment", "Wrap content with predictable internal spacing.", "block", "fixed", sources.everyLayout, [[".box", { "box-sizing": "border-box", display: "block", padding: "1rem" }]]],
281
- ["center", "Centering", "Center a block while respecting a maximum measure.", "inline", "fluid", sources.everyLayout, [[".center", { "margin-inline": "auto", "max-inline-size": "64rem", "padding-inline": "1rem" }]]],
282
- ["cluster", "In-line grouping", "Keep related items together while allowing wrapping.", "inline", "wrap", sources.everyLayout, [[".cluster", { display: "flex", "flex-wrap": "wrap", gap: "0.75rem", "justify-content": "flex-start" }]]],
283
- ["content-limiter", "Containment", "Keep prose width readable inside fluid containers.", "inline", "fluid", sources.govukLayout, [[".content_limiter", { "margin-inline": "auto", "max-inline-size": "70ch", "padding-inline": "1rem" }]]],
284
- ["super-center", "Centering", "Center one region along both axes.", "both", "fluid", sources.webOneLine, [[".super_center", { display: "grid", "min-block-size": "100dvh", "place-items": "center" }]]],
285
- ["icon-frame", "Media / Fit", "Keep an icon aligned inside a fixed square slot.", "both", "fixed", sources.everyLayout, [[".icon_frame", { "block-size": "2.5rem", display: "grid", "inline-size": "2.5rem", "place-items": "center" }]]],
286
- ["frame", "Media / Fit", "Preserve media aspect ratio in a responsive slot.", "both", "fluid", sources.everyLayout, [[".frame", { "aspect-ratio": "16 / 9", display: "grid", "inline-size": "100%", overflow: "clip" }], [".frame_media", { "block-size": "100%", "inline-size": "100%", "min-block-size": "0", "min-inline-size": "0", "object-fit": "cover" }]]],
287
- ["cover", "Viewport / Shell", "Keep a central region balanced between optional header and footer.", "block", "fluid", sources.everyLayout, [[".cover", { display: "grid", gap: "1rem", "grid-template-rows": "auto 1fr auto", "min-block-size": "100dvh", padding: "1rem" }]]],
288
- ["sidebar", "Split / Sidebar", "Let a narrow sidebar and wider content wrap when space is tight.", "inline", "wrap", sources.everySidebar, [[".sidebar", { display: "flex", "flex-wrap": "wrap", gap: "1rem" }], [".sidebar_primary", { "flex-basis": "0", "flex-grow": "999", "min-inline-size": "16rem" }], [".sidebar_secondary", { "flex-basis": "18rem", "flex-grow": "1" }]]],
289
- ["switcher", "Split / Sidebar", "Switch equal regions from row to stack without a viewport breakpoint.", "inline", "wrap", sources.everyLayout, [[".switcher", { display: "flex", "flex-wrap": "wrap", gap: "1rem" }], [".switcher_item", { "flex-basis": "calc((40rem - 100%) * 999)", "flex-grow": "1" }]]],
290
- ["media-object", "Split / Sidebar", "Align media and descriptive content as a stable pair.", "inline", "reflow", sources.mdnCookbook, [[".media_object", { "align-items": "start", display: "flex", "flex-wrap": "wrap", gap: "1rem" }], [".media_object_media", { "flex-basis": "6rem", "flex-grow": "0" }], [".media_object_content", { "flex-basis": "min(20rem, 100%)", "flex-grow": "1", "min-inline-size": "0" }]]],
291
- ["split-nav", "In-line grouping", "Separate primary and secondary nav actions in one row.", "inline", "wrap", sources.mdnCookbook, [[".split_nav", { "align-items": "center", display: "flex", "flex-wrap": "wrap", gap: "0.75rem" }], [".split_nav_primary", { display: "flex", gap: "0.75rem" }], [".split_nav_secondary", { "margin-inline-start": "auto" }]]],
292
- ["holy-grail", "Viewport / Shell", "Place header, footer, sidebars, and main content in a resilient shell.", "both", "breakpointed", sources.webOneLine, [[".holy_grail", { display: "grid", gap: "1rem", "grid-template": '"header header header" auto "left main right" 1fr "footer footer footer" auto / minmax(12rem, auto) 1fr minmax(12rem, auto)', "min-block-size": "100dvh" }], [".holy_grail_header", { "grid-area": "header" }], [".holy_grail_left", { "grid-area": "left" }], [".holy_grail_main", { "grid-area": "main", "min-inline-size": "0" }], [".holy_grail_right", { "grid-area": "right" }], [".holy_grail_footer", { "grid-area": "footer" }]]],
293
- ["sticky-footer", "Viewport / Shell", "Keep footer at the bottom when content is short.", "block", "fluid", sources.mdnCookbook, [[".sticky_footer", { display: "grid", "grid-template-rows": "auto 1fr auto", "min-block-size": "100dvh" }], [".sticky_footer_main", { "min-block-size": "0" }]]],
294
- ["sticky-header", "Viewport / Shell", "Keep a header visible above a scrolling content region.", "block", "fluid", sources.mdnPosition, [[".sticky_header", { "inset-block-start": "0", position: "sticky", "z-index": "1" }]]],
295
- ["scroll-body-shell", "Viewport / Shell", "Keep shell regions fixed while only the body scrolls.", "block", "fluid", sources.mdnOverflow, [[".scroll_body_shell", { display: "grid", "grid-template-rows": "auto minmax(0, 1fr) auto", "max-block-size": "100dvh" }], [".scroll_body_shell_body", { "min-block-size": "0", overflow: "auto" }]], "Pattern owns the named scroll container."],
296
- ["fixed-sidenav-shell", "Viewport / Shell", "Keep side navigation stable while main content scrolls.", "both", "fluid", sources.carbonGrid, [[".fixed_sidenav_shell", { display: "grid", "grid-template-columns": "16rem minmax(0, 1fr)", "grid-template-rows": "minmax(0, 1fr)", "max-block-size": "100dvh" }], [".fixed_sidenav_shell_list", { "min-block-size": "0" }], [".fixed_sidenav_shell_main", { "min-block-size": "0", overflow: "auto" }]], "Pattern owns the named scroll container."],
297
- ["sticky-aside", "Split / Sidebar", "Keep related aside content visible during long reads.", "block", "fluid", sources.mdnPosition, [[".sticky_aside", { "align-items": "start", display: "grid", gap: "1rem", "grid-template-columns": "minmax(0, 1fr) 16rem" }], [".sticky_aside_main", { "min-inline-size": "0" }], [".sticky_aside_side", { "inset-block-start": "1rem", position: "sticky" }]]],
298
- ["ram-grid", "Grid / Repetition", "Repeat items into as many useful columns as space allows.", "both", "fluid", sources.webOneLine, [[".ram_grid", { display: "grid", gap: "1rem", "grid-template-columns": "repeat(auto-fit, minmax(min(16rem, 100%), 1fr))" }]]],
299
- ["card-grid", "Grid / Repetition", "Align repeating cards in rows and columns.", "both", "fluid", sources.mdnCookbook, [[".card_grid", { display: "grid", gap: "1rem", "grid-template-columns": "repeat(auto-fit, minmax(min(18rem, 100%), 1fr))" }]]],
300
- ["twelve-span-grid", "Grid / Repetition", "Provide a twelve-column placement scaffold.", "both", "fluid", sources.webOneLine, [[".twelve_span_grid", { display: "grid", gap: "1rem", "grid-template-columns": "repeat(12, minmax(0, 1fr))" }], [".twelve_span_grid_item", { "grid-column": "span 4" }]]],
301
- ["page-grid", "Grid / Repetition", "Align page content to margins, gutters, and a central track.", "inline", "fluid", sources.carbonGrid, [[".page_grid", { display: "grid", gap: "1rem", "grid-template-columns": "minmax(1rem, 1fr) minmax(0, 72rem) minmax(1rem, 1fr)" }], [".page_grid_content", { "grid-column": "2" }]]],
302
- ["grid-wrapper", "Grid / Repetition", "Center grid tracks while allowing full-width breakout tracks.", "inline", "fluid", sources.mdnCookbook, [[".grid_wrapper", { display: "grid", "grid-template-columns": "1fr minmax(0, 64rem) 1fr" }], [".grid_wrapper_main", { "grid-column": "2" }]]],
303
- ["columns", "Grid / Repetition", "Flow long content into balanced text columns.", "inline", "fluid", sources.mdnCookbook, [[".columns", { "column-gap": "2rem", columns: "18rem" }]]],
304
- ["deconstructed-pancake", "In-line grouping", "Let equal cards stretch in a row and stack naturally when narrow.", "inline", "wrap", sources.webOneLine, [[".deconstructed_pancake", { display: "flex", "flex-wrap": "wrap", gap: "1rem" }], [".deconstructed_pancake_item", { flex: "1 1 16rem" }]]],
305
- ["line-up", "Stacking", "Keep card footer actions aligned at the bottom.", "block", "fluid", sources.webOneLine, [[".line_up", { display: "flex", "flex-direction": "column", gap: "1rem" }], [".line_up_body", { "min-block-size": "0" }], [".line_up_footer", { "margin-block-start": "auto" }]]],
306
- ["clamped-card", "Containment", "Constrain a card to a readable fluid width.", "inline", "fluid", sources.webOneLine, [[".clamped_card", { "inline-size": "clamp(16rem, 50vw, 28rem)", "margin-inline": "auto" }]]],
307
- ["fluid-styles", "Containment", "Let a region fill available width without exceeding a readable max.", "inline", "fluid", sources.carbonGrid, [[".fluid_styles", { "inline-size": "min(100%, 72rem)", "margin-inline": "auto" }]]],
308
- ["split-screen", "Split / Sidebar", "Split a viewport or region into two balanced panes.", "inline", "reflow", sources.materialCanonical, [[".split_screen", { display: "grid", gap: "1rem", "grid-template-columns": "repeat(auto-fit, minmax(min(20rem, 100%), 1fr))", "min-block-size": "100dvh" }], [".split_screen_pane", { "min-inline-size": "0" }]]],
309
- ["list-detail", "Split / Sidebar", "Place an explorable list beside its detail region.", "inline", "reflow", sources.materialCanonical, [[".list_detail", { display: "grid", gap: "1rem", "grid-template-columns": "repeat(auto-fit, minmax(min(18rem, 100%), 1fr))" }], [".list_detail_list", { "min-inline-size": "0" }], [".list_detail_detail", { "min-inline-size": "0" }]]],
310
- ["supporting-pane", "Split / Sidebar", "Keep supplemental information beside a primary task.", "inline", "reflow", sources.materialCanonical, [[".supporting_pane", { display: "grid", gap: "1rem", "grid-template-columns": "repeat(auto-fit, minmax(min(20rem, 100%), 1fr))" }], [".supporting_pane_main", { "min-inline-size": "0" }], [".supporting_pane_summary", { "min-inline-size": "0" }]]],
311
- ["feed", "Stacking", "Stack repeated content items with stable rhythm.", "block", "fluid", sources.materialCanonical, [[".feed", { display: "grid", gap: "1rem", "grid-auto-rows": "minmax(min-content, auto)" }]]],
312
- ["breadcrumb", "In-line grouping", "Lay out hierarchy links compactly with wrapping.", "inline", "wrap", sources.mdnCookbook, [[".breadcrumb", { "align-items": "center", display: "flex", "flex-wrap": "wrap", gap: "0.5rem" }]]],
313
- ["pagination", "In-line grouping", "Lay out page controls as a bounded wrapping row.", "inline", "wrap", sources.mdnCookbook, [[".pagination", { display: "flex", "flex-wrap": "wrap", gap: "0.5rem", "justify-content": "center" }]]],
314
- ["badge-list", "In-line grouping", "Align item labels with trailing counts.", "inline", "fluid", sources.mdnCookbook, [[".badge_list", { display: "grid", gap: "0.5rem" }], [".badge_list_item", { "align-items": "center", display: "flex", gap: "0.75rem", "justify-content": "space-between" }]]],
315
- ["step-nav", "Stacking", "Present sequential steps with consistent vertical rhythm.", "block", "fluid", sources.govukLayout, [[".step_nav", { display: "grid", gap: "0.75rem", "margin-block": "1rem" }]]],
316
- ["tab-strip", "In-line grouping", "Keep peer tabs in one stable row that can wrap.", "inline", "wrap", sources.govukLayout, [[".tab_strip", { display: "flex", "flex-wrap": "wrap", gap: "0.75rem" }]]],
317
- ["reel", "In-line grouping", "Let a row scroll horizontally instead of wrapping.", "inline", "scroll", sources.everyLayout, [[".reel", { display: "grid", gap: "1rem", "grid-auto-columns": "minmax(14rem, 35%)", "grid-auto-flow": "column", "overflow-x": "auto" }]], "Pattern owns the named scroll container."],
318
- ["imposter", "Overlay / Exception", "Place an overlay region over a parent without changing document order.", "both", "fixed", sources.everyLayout, [[".imposter_anchor", { position: "relative" }], [".imposter", { display: "grid", inset: "0", "place-items": "center", position: "absolute", "z-index": "1" }]]],
319
- ["panel-layout", "Viewport / Shell", "Create predictable main and utility panels.", "inline", "reflow", sources.carbonGrid, [[".panel_layout", { display: "grid", gap: "1rem", "grid-template-columns": "repeat(auto-fit, minmax(min(22rem, 100%), 1fr))" }], [".panel_layout_main", { "min-inline-size": "0" }], [".panel_layout_side", { "min-inline-size": "0" }]]],
320
- ["overlay-stack", "Overlay / Exception", "Stack several regions into the same grid cell.", "both", "fluid", sources.webOneLine, [[".overlay_stack", { display: "grid" }], [".overlay_stack_item", { "grid-area": "1 / 1" }]]],
321
- ["wrap-row", "In-line grouping", "Wrap controls into rows with stable gaps.", "inline", "wrap", sources.mdnCookbook, [[".wrap_row", { "align-items": "center", display: "flex", "flex-wrap": "wrap", gap: "0.75rem" }]]],
322
- ["dense-grid", "Grid / Repetition", "Fill a compact grid with repeated small items.", "both", "fluid", sources.mdnGrid, [[".dense_grid", { display: "grid", gap: "0.5rem", "grid-template-columns": "repeat(auto-fill, minmax(8rem, 1fr))" }]]],
323
- ["masonry-approx", "Grid / Repetition", "Approximate staggered content with columns when exact row alignment is not needed.", "block", "fluid", sources.mdnCookbook, [[".masonry_approx", { "column-gap": "1rem", "column-width": "14rem" }]]],
324
- ["main-with-rail", "Split / Sidebar", "Keep primary content dominant with a narrow secondary rail.", "inline", "reflow", sources.govukLayout, [[".main_with_rail", { display: "grid", gap: "1rem", "grid-template-columns": "repeat(auto-fit, minmax(min(18rem, 100%), 1fr))" }], [".main_with_rail_main", { "min-inline-size": "0" }], [".main_with_rail_side", { "min-inline-size": "0" }]]],
325
- ];