@pipelex/mthds-form 0.15.0 → 0.16.0

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.
@@ -190,6 +190,7 @@ declare const brandProvenanceSchema: z.ZodObject<{
190
190
  }, z.core.$strict>>;
191
191
  }, z.core.$strict>>;
192
192
  siteFacts: z.ZodOptional<z.ZodString>;
193
+ siteFactsHash: z.ZodOptional<z.ZodString>;
193
194
  rounds: z.ZodOptional<z.ZodNumber>;
194
195
  }, z.core.$strict>;
195
196
  type BrandProvenance = z.infer<typeof brandProvenanceSchema>;
@@ -214,10 +215,11 @@ declare function brandScope(brand: string, producerId: string): string;
214
215
  * This is the verdict on whether a brand is VALID under the contract as it is
215
216
  * now: the manifest, the tokens with their contrast, and the facts the person
216
217
  * stated. It is a hard verdict, and a brand that fails it is not compiled.
217
- * Whether a brand was produced against the current brief is a different
218
- * question and never a reason to refuse one - an older brand stays a valid
219
- * brand - so the provenance's contract hash is recorded here and judged by
220
- * the producer, not by this function.
218
+ * Whether a brand was produced against the current brief, and from the facts
219
+ * its recording holds now, is a different question and never a reason to
220
+ * refuse one - an older brand stays a valid brand - so the provenance's
221
+ * contract hash and facts hash are recorded here and judged by the producer,
222
+ * not by this function.
221
223
  *
222
224
  * The problems come in the order a producer would want to be told: the
223
225
  * manifest and the provenance first, because they are cheap and their errors
@@ -319,6 +319,7 @@ var BRAND_PRODUCERS = [
319
319
  /** A Claude Code session reading the site and writing the files by hand. */
320
320
  "claude-code-session"
321
321
  ];
322
+ var hash12 = z.string().regex(/^[0-9a-f]{12}$/, "twelve hex digits");
322
323
  var brandProvenanceSchema = z.strictObject({
323
324
  producer: z.enum(BRAND_PRODUCERS),
324
325
  /** The model id: the one the method ran with, or the Claude Code model behind the session. */
@@ -328,16 +329,33 @@ var brandProvenanceSchema = z.strictObject({
328
329
  /** The contract brief it was produced from, as the producer recorded its path. */
329
330
  brief: z.string().min(1),
330
331
  /** The first twelve hex digits of the SHA-256 of the contract brief at the time. */
331
- contractHash: z.string().regex(/^[0-9a-f]{12}$/, "twelve hex digits"),
332
+ contractHash: hash12,
332
333
  /** The creative seed handed over with the brief, verbatim, when one was. */
333
334
  seed: z.string().min(1).optional(),
334
335
  /** What the person stated beside the URL, when they did. */
335
336
  stated: statedFactsSchema.optional(),
336
337
  /** Where the site facts came from: a file, or a sentence for a brand read by hand. */
337
338
  siteFacts: z.string().min(1).optional(),
339
+ /**
340
+ * The first twelve hex digits of the SHA-256 of the file `siteFacts`
341
+ * names, its bytes as the producer read them. A path alone cannot say
342
+ * whether the facts behind it moved since the brand was produced; whatever
343
+ * re-reads them hashes the file again, and a mismatch makes the brand
344
+ * stale, never invalid. The schema refuses one beside no `siteFacts`,
345
+ * but it cannot tell a path from a sentence: a brand read by hand records
346
+ * none by the producer's own rule, and a hash recorded beside a sentence
347
+ * anyway is caught where it is judged, since the sentence names no file.
348
+ */
349
+ siteFactsHash: hash12.optional(),
338
350
  /** How many repair rounds the producer ran before the files validated. */
339
351
  rounds: z.number().int().min(0).optional()
340
- });
352
+ }).refine(
353
+ (provenance) => provenance.siteFactsHash === void 0 || provenance.siteFacts !== void 0,
354
+ {
355
+ path: ["siteFactsHash"],
356
+ message: "no siteFacts names the file it hashes"
357
+ }
358
+ );
341
359
  function brandProducerId(provenance) {
342
360
  return [provenance.producer, provenance.model, provenance.seed ? "seeded" : null].filter((part) => part !== null).join("--");
343
361
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/brand/contract.ts","../../src/brand/tokens.ts","../../src/brand/stated.ts","../../src/brand/provenance.ts","../../src/brand/compile.ts","../../src/brand/assemble.ts"],"names":["z","description"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The brand contract, as data: which token of a brand's `tokens.json` sets\n * which custom property, and what that property paints.\n *\n * It is the theme contract seen from the other side. `src/styles/theme.css`\n * states it as a working default and `docs/theming.md` in prose; this is the\n * same list as a table a build can read, and a brand is exactly these tokens\n * and no others - the validator refuses a file that adds one, because a token\n * nothing consumes is a value with no way to be looked at.\n *\n * The colour and radius rows are not a second list kept beside `theme.css`:\n * they are held to it, by `__tests__/contract.test.ts` over the source and by\n * `scripts/assert-bundle.mjs` over the build. The two typography rows are the\n * exception, and on purpose. `--font-sans` and `--font-mono` are the names of\n * Tailwind's own theme variables, which the prebuilt sheet already declares,\n * so `theme.css` does not define them: it is unlayered, and a value there\n * would override the typeface of every host that loads it. The stock\n * typeface is therefore the host's own, and only a brand's scope sets these\n * two. See docs/brand.md.\n */\n\nexport type ContractTokenType = 'color' | 'dimension' | 'fontFamily';\n\nexport interface ContractToken {\n /** The DTCG token id, `color.background`. */\n id: string;\n /** The custom property it sets, `--background`. */\n variable: string;\n type: ContractTokenType;\n /** What the property paints, in the words a producer is told. */\n paints: string;\n}\n\n/** The colour tokens, in the order `theme.css` states them. */\nexport const COLOR_TOKEN_NAMES = [\n 'background',\n 'foreground',\n 'card',\n 'card-foreground',\n 'popover',\n 'popover-foreground',\n 'primary',\n 'primary-foreground',\n 'secondary',\n 'secondary-foreground',\n 'muted',\n 'muted-foreground',\n 'accent',\n 'accent-foreground',\n 'destructive',\n 'destructive-foreground',\n 'border',\n 'input',\n 'ring',\n] as const;\n\nexport type ColorTokenName = (typeof COLOR_TOKEN_NAMES)[number];\n\nexport function isColorTokenName(name: string): name is ColorTokenName {\n return (COLOR_TOKEN_NAMES as readonly string[]).includes(name);\n}\n\nconst COLOR_PAINTS: Record<ColorTokenName, string> = {\n background: 'The page canvas.',\n foreground: 'Text on the canvas.',\n card: \"A raised surface on the canvas: the rail's panel, a list's rows. May be translucent.\",\n 'card-foreground': 'Text on a card.',\n popover: \"A floating surface: a select's menu, a tooltip. Opaque.\",\n 'popover-foreground': 'Text on a popover.',\n primary: 'The accent: the run button, a selected pill, a section number, a highlight.',\n 'primary-foreground': 'Text on the accent.',\n secondary: 'A quiet filled surface: a secondary button, an unselected segment.',\n 'secondary-foreground': 'Text on a secondary surface.',\n muted: \"A subdued fill: a table's header band, an inactive tab strip.\",\n 'muted-foreground':\n \"Secondary text: descriptions, hints, a summary row's label. Most of the text on the page that is not a heading or a value.\",\n accent: 'A hover fill: a menu item under the pointer.',\n 'accent-foreground': 'Text on an accent fill.',\n destructive: 'The error colour: an invalid mark, a remove button.',\n 'destructive-foreground': 'Text on the destructive colour.',\n border: 'The hairline: every border and divider.',\n input:\n \"The control surface, a field's own fill - a step off the canvas, so fields read as one family.\",\n ring: 'The focus ring.',\n};\n\nexport const BRAND_CONTRACT: readonly ContractToken[] = [\n ...COLOR_TOKEN_NAMES.map((name): ContractToken => ({\n id: `color.${name}`,\n variable: `--${name}`,\n type: 'color',\n paints: COLOR_PAINTS[name],\n })),\n {\n id: 'radius.base',\n variable: '--radius',\n type: 'dimension',\n paints: 'The corner radius of a control; cards take one and a half of it.',\n },\n {\n id: 'font.sans',\n variable: '--font-sans',\n type: 'fontFamily',\n paints: 'The typeface of everything on the page.',\n },\n {\n id: 'font.mono',\n variable: '--font-mono',\n type: 'fontFamily',\n paints: 'Tags, numbers, the receipt.',\n },\n];\n\n/**\n * The pairs that must clear WCAG AA in both modes, as they render: the canvas\n * opaque, the ink blended over it by its alpha.\n */\nexport const CONTRAST_PAIRS: readonly {\n foreground: ColorTokenName;\n background: ColorTokenName;\n}[] = [\n { foreground: 'foreground', background: 'background' },\n { foreground: 'muted-foreground', background: 'background' },\n];\n\n/** The minimum contrast ratio those pairs must reach: WCAG 2 AA for normal text. */\nexport const MIN_CONTRAST = 4.5;\n\nconst byId = new Map(BRAND_CONTRACT.map((token) => [token.id, token]));\n\n/** The custom property a token sets, or a loud failure for a token the contract does not name. */\nexport function contractVariable(id: string): string {\n const token = byId.get(id);\n if (!token) throw new Error(`The brand contract has no token ${id}.`);\n return token.variable;\n}\n","import { z } from 'zod';\nimport {\n COLOR_TOKEN_NAMES,\n type ColorTokenName,\n CONTRAST_PAIRS,\n isColorTokenName,\n MIN_CONTRAST,\n} from './contract';\n\n/**\n * A brand's `tokens.json`, validated against the contract.\n *\n * The file is standard DTCG (the Design Tokens Community Group format, 2025.10),\n * and DTCG is looser than the contract in every direction that matters here: it\n * accepts any token, any colour space, a string colour, and a mode of any name.\n * Each of those is a way for a producer's file to be wrong and a page to be\n * painted anyway. So this holds the contract's own rules - exactly its tokens,\n * object colours in sRGB whose hex agrees with their components, aliases only\n * to contract tokens and never in a cycle, a description on every token, `dark`\n * the only mode and stated on every colour object (an alias may stand for both\n * modes), the contrast pairs in both modes - and a file it accepts is one the\n * compiler can only render. Every problem is named by its path, all at once,\n * so a producer's repair round is handed the whole list.\n */\n\nconst component = z.number().min(0).max(1);\n\nexport const srgbColorSchema = z.strictObject({\n colorSpace: z.literal('srgb'),\n components: z.tuple([component, component, component]),\n alpha: z.number().min(0).max(1),\n hex: z\n .string()\n .regex(/^#[0-9a-f]{6}$/i, 'a hex colour is #rrggbb')\n .optional(),\n});\n\nexport type SrgbColor = z.infer<typeof srgbColorSchema>;\n\nconst colorAliasSchema = z\n .string()\n .regex(/^\\{color\\.[a-z][a-z-]*\\}$/, 'an alias is \"{color.<name>}\"');\n\nconst colorValueSchema = z.union([srgbColorSchema, colorAliasSchema]);\n\nexport type ColorValue = z.infer<typeof colorValueSchema>;\n\nconst description = z.string().min(1, 'every token carries a $description');\n\n/**\n * A C0 control or DEL. Written as a test on the code point rather than a\n * character class, since that range is what a regex may not spell\n * (`no-control-regex`).\n */\nexport function isControlCharacter(char: string): boolean {\n const code = char.codePointAt(0)!;\n return code < 0x20 || code === 0x7f;\n}\n\nconst colorTokenSchema = z\n .strictObject({\n $value: colorValueSchema,\n $description: description,\n $extensions: z\n .strictObject({\n mode: z.strictObject({ dark: colorValueSchema }),\n })\n .optional(),\n })\n .refine((token) => token.$extensions !== undefined || typeof token.$value === 'string', {\n message: 'a colour carries $extensions.mode.dark; only an alias may stand for both modes',\n path: ['$extensions'],\n });\n\nexport type ColorToken = z.infer<typeof colorTokenSchema>;\n\nconst dimensionTokenSchema = z.strictObject({\n $value: z.strictObject({ value: z.number().min(0), unit: z.enum(['rem', 'px']) }),\n $description: description,\n});\n\nexport type DimensionToken = z.infer<typeof dimensionTokenSchema>;\n\nconst fontFamilyTokenSchema = z.strictObject({\n $value: z\n .array(\n z\n .string()\n .min(1)\n // A face's name never holds one, and a form feed ends a CSS string.\n .refine((name) => ![...name].some(isControlCharacter), {\n message: 'a family name holds no control characters',\n }),\n )\n .min(1),\n $description: description,\n});\n\nexport type FontFamilyToken = z.infer<typeof fontFamilyTokenSchema>;\n\n/** The token file, typed: the contract's groups and tokens, nothing else. */\nexport interface BrandTokens {\n color: { $type: 'color' } & Record<ColorTokenName, ColorToken>;\n radius: { $type: 'dimension'; base: DimensionToken };\n font: { $type: 'fontFamily'; sans: FontFamilyToken; mono: FontFamilyToken };\n}\n\nconst brandTokensSchema = z.strictObject({\n color: z.strictObject({\n $type: z.literal('color'),\n ...Object.fromEntries(COLOR_TOKEN_NAMES.map((name) => [name, colorTokenSchema])),\n }),\n radius: z.strictObject({ $type: z.literal('dimension'), base: dimensionTokenSchema }),\n font: z.strictObject({\n $type: z.literal('fontFamily'),\n sans: fontFamilyTokenSchema,\n mono: fontFamilyTokenSchema,\n }),\n});\n\nexport type TokensValidation =\n { ok: true; tokens: BrandTokens } | { ok: false; problems: string[] };\n\nexport type ColorMode = 'light' | 'dark';\n\n/** The name an alias points at, or null for a colour object. */\nexport function aliasTarget(value: ColorValue): string | null {\n return typeof value === 'string' ? value.slice('{color.'.length, -1) : null;\n}\n\n/** A token's dark value: what it states, or - for an alias that states none - the same alias. */\nexport function darkValue(token: ColorToken): ColorValue {\n return token.$extensions?.mode.dark ?? token.$value;\n}\n\n/** A token's value in a mode. */\nexport function modeValue(token: ColorToken, mode: ColorMode): ColorValue {\n return mode === 'light' ? token.$value : darkValue(token);\n}\n\n/** `#rrggbb` for a colour, its alpha dropped: each channel the byte the compiler writes. */\nexport function colorHex(color: SrgbColor): string {\n return `#${color.components\n .map((channel) =>\n Math.round(channel * 255)\n .toString(16)\n .padStart(2, '0'),\n )\n .join('')}`;\n}\n\n/**\n * Whether a colour compiles to the hex. The hex is what a brand ships for the\n * colour, so any slack here would let a stated accent ship as its neighbour.\n */\nexport function colorIsHex(color: SrgbColor, hex: string): boolean {\n return colorHex(color) === hex.toLowerCase();\n}\n\n/**\n * A colour as the compiler writes it: each channel the byte a hex or `rgb()`\n * carries, the alpha to the three decimals `rgb()` is given, and opaque once it\n * rounds to 1. A page renders this colour, not the components it was produced\n * as, so contrast is measured on it: a grey that passes at full precision can\n * round below the bar.\n */\nexport function asWritten(color: SrgbColor): SrgbColor {\n const alpha = Number(Math.min(color.alpha, 1).toFixed(3));\n return {\n colorSpace: 'srgb',\n components: color.components.map((channel) => Math.round(channel * 255) / 255) as [\n number,\n number,\n number,\n ],\n alpha,\n };\n}\n\nfunction checkHexAgreement(name: string, mode: ColorMode, value: ColorValue, problems: string[]) {\n if (typeof value === 'string' || !value.hex) return;\n if (!colorIsHex(value, value.hex)) {\n problems.push(\n `color.${name} (${mode}): hex ${value.hex} does not agree with components [${value.components.join(', ')}]`,\n );\n }\n}\n\nfunction checkAliases(tokens: BrandTokens, mode: ColorMode, problems: string[]) {\n for (const name of COLOR_TOKEN_NAMES) {\n const seen = new Set<string>([name]);\n let current: ColorTokenName = name;\n for (;;) {\n const target = aliasTarget(modeValue(tokens.color[current], mode));\n if (target === null) break;\n if (!isColorTokenName(target)) {\n problems.push(\n `color.${name} (${mode}): aliases {color.${target}}, which the contract has no token for`,\n );\n break;\n }\n if (seen.has(target)) {\n problems.push(`color.${name} (${mode}): alias cycle through {color.${target}}`);\n break;\n }\n seen.add(target);\n current = target;\n }\n }\n}\n\n/** The colour a token resolves to in a mode, through its aliases; null when a chain is broken. */\nexport function resolveColor(\n tokens: BrandTokens,\n name: ColorTokenName,\n mode: ColorMode,\n): SrgbColor | null {\n const seen = new Set<string>();\n let current: ColorTokenName = name;\n for (;;) {\n if (seen.has(current)) return null;\n seen.add(current);\n const value = modeValue(tokens.color[current], mode);\n const target = aliasTarget(value);\n if (target === null) return value as SrgbColor;\n if (!isColorTokenName(target)) return null;\n current = target;\n }\n}\n\nfunction luminance(color: SrgbColor): number {\n const [r, g, b] = color.components.map((channel) =>\n channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4,\n ) as [number, number, number];\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** WCAG 2 contrast ratio between two colours, taken as opaque. */\nexport function contrastRatio(a: SrgbColor, b: SrgbColor): number {\n const la = luminance(a);\n const lb = luminance(b);\n const [light, dark] = la > lb ? [la, lb] : [lb, la];\n return (light + 0.05) / (dark + 0.05);\n}\n\n/** A colour as it renders over an opaque one: the two blended by its alpha, as a browser does. */\nexport function composite(color: SrgbColor, over: SrgbColor): SrgbColor {\n const components = color.components.map(\n (channel, index) => channel * color.alpha + over.components[index]! * (1 - color.alpha),\n ) as [number, number, number];\n return { colorSpace: 'srgb', components, alpha: 1 };\n}\n\n/**\n * Each contrast pair as it renders. The canvas must be opaque, since a\n * translucent one shows whatever the host paints beneath it and its contrast is\n * nobody's to promise; the ink is blended over it, so a translucent ink is\n * measured at the strength it actually has, and a transparent one fails. Both\n * are measured as the compiler writes them, which is what renders.\n */\nfunction checkContrast(tokens: BrandTokens, mode: ColorMode, problems: string[]) {\n for (const pair of CONTRAST_PAIRS) {\n const foreground = resolveColor(tokens, pair.foreground, mode);\n const background = resolveColor(tokens, pair.background, mode);\n if (!foreground || !background) continue;\n if (background.alpha < 1) {\n problems.push(\n `color.${pair.background} (${mode}): alpha ${background.alpha}, but text is measured against it, so it must be opaque (alpha 1)`,\n );\n continue;\n }\n const canvas = asWritten(background);\n const ratio = contrastRatio(composite(asWritten(foreground), canvas), canvas);\n if (ratio < MIN_CONTRAST) {\n problems.push(\n `color.${pair.foreground} on color.${pair.background} (${mode}): contrast ${ratio.toFixed(2)}, expected ${MIN_CONTRAST} (WCAG AA)`,\n );\n }\n }\n}\n\n/** Every problem with the file at once, so a producer's repair round sees the whole list. */\nexport function validateBrandTokens(doc: unknown): TokensValidation {\n const parsed = brandTokensSchema.safeParse(doc);\n if (!parsed.success) {\n return {\n ok: false,\n problems: parsed.error.issues.map((issue) => {\n const where = issue.path.map(String).join('.') || '(root)';\n return `${where}: ${issue.message}`;\n }),\n };\n }\n const tokens = parsed.data as unknown as BrandTokens;\n const problems: string[] = [];\n for (const name of COLOR_TOKEN_NAMES) {\n const token = tokens.color[name];\n checkHexAgreement(name, 'light', token.$value, problems);\n checkHexAgreement(name, 'dark', darkValue(token), problems);\n }\n checkAliases(tokens, 'light', problems);\n checkAliases(tokens, 'dark', problems);\n // Contrast is read through the aliases, so it is only meaningful once every\n // chain resolves.\n if (problems.length === 0) {\n checkContrast(tokens, 'light', problems);\n checkContrast(tokens, 'dark', problems);\n }\n return problems.length === 0 ? { ok: true, tokens } : { ok: false, problems };\n}\n","import { z } from 'zod';\nimport { type BrandManifest, httpUrl } from './manifest';\nimport { type BrandTokens, colorHex, colorIsHex, resolveColor } from './tokens';\n\n/**\n * What a person states beside a site's URL: the things a site does not show and\n * no reading can supply. The accent of a site with no button, per mode when its\n * dark canvas needs another, and the logo for a canvas the site draws none for.\n *\n * A stated fact outranks every reading, which whatever runs a producer tells\n * it, outside this package. Here the brand is held to honour it\n * (`statedFactProblems`), and the provenance records it.\n */\n\nconst statedHex = z.string().regex(/^#[0-9a-f]{6}$/i, 'a stated accent is #rrggbb');\n\nexport const statedFactsSchema = z.strictObject({\n /** The accent per mode, `#rrggbb`: what `color.primary` resolves to in that mode. */\n accent: z\n .strictObject({\n light: statedHex.optional(),\n dark: statedHex.optional(),\n })\n .optional(),\n /**\n * The logo for a canvas: `logo.onLight` or `logo.onDark` in the manifest,\n * which the brand must carry exactly, so it obeys the manifest's rule (http\n * or https) or no brand could ever honour it.\n */\n logo: z\n .strictObject({\n onLight: httpUrl.optional(),\n onDark: httpUrl.optional(),\n })\n .optional(),\n});\n\nexport type StatedFacts = z.infer<typeof statedFactsSchema>;\n\n/**\n * Where the brand does not carry what the person stated, in the words a repair\n * round is told. Only the modes and canvases that were stated are checked.\n */\nexport function statedFactProblems(\n stated: StatedFacts | undefined,\n manifest: BrandManifest,\n tokens: BrandTokens,\n): string[] {\n if (!stated) return [];\n const problems: string[] = [];\n for (const mode of ['light', 'dark'] as const) {\n const accent = stated.accent?.[mode];\n if (!accent) continue;\n const primary = resolveColor(tokens, 'primary', mode);\n if (!primary) continue;\n if (!colorIsHex(primary, accent)) {\n problems.push(\n `tokens.json: color.primary (${mode}) resolves to ${colorHex(primary)}, but the accent for ${mode} mode was stated as ${accent}`,\n );\n }\n // A hex carries no alpha, so the components alone would let a primary\n // nobody can see honour the accent: a stated accent is an opaque colour.\n if (primary.alpha < 1) {\n problems.push(\n `tokens.json: color.primary (${mode}) has alpha ${primary.alpha}, but the accent for ${mode} mode was stated as the opaque ${accent}, so it must be opaque (alpha 1)`,\n );\n }\n }\n for (const canvas of ['onLight', 'onDark'] as const) {\n const url = stated.logo?.[canvas];\n if (url && manifest.logo[canvas] !== url) {\n problems.push(\n `brand.json: logo.${canvas} is ${manifest.logo[canvas]}, but the logo for that canvas was stated as ${url}`,\n );\n }\n }\n return problems;\n}\n","import { z } from 'zod';\nimport { statedFactsSchema } from './stated';\n\n/**\n * A brand's `provenance.json`: who produced it, on which model, from which\n * contract and which facts.\n *\n * A brand follows the rules a captured layout follows: produced by a pass,\n * committed with its provenance, and titled by what made it and by nothing\n * else. The provenance is a record, so it is never rewritten to make a check\n * pass. A brand's directory is named by `brandProducerId`, the same recipe a\n * layout fixture's id uses, so the tree and the record cannot disagree about\n * who made a brand.\n */\n\n/** How a brand came to be. */\nexport const BRAND_PRODUCERS = [\n /** The producer method, run on the hosted API. */\n 'pipelex-method',\n /** A Claude Code subagent in a fresh context, given the contract and the facts and nothing else. */\n 'claude-code-subagent',\n /** A Claude Code session reading the site and writing the files by hand. */\n 'claude-code-session',\n] as const;\n\nexport type BrandProducer = (typeof BRAND_PRODUCERS)[number];\n\nexport const brandProvenanceSchema = z.strictObject({\n producer: z.enum(BRAND_PRODUCERS),\n /** The model id: the one the method ran with, or the Claude Code model behind the session. */\n model: z.string().min(1),\n /** The day it was produced, `YYYY-MM-DD`. */\n date: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n /** The contract brief it was produced from, as the producer recorded its path. */\n brief: z.string().min(1),\n /** The first twelve hex digits of the SHA-256 of the contract brief at the time. */\n contractHash: z.string().regex(/^[0-9a-f]{12}$/, 'twelve hex digits'),\n /** The creative seed handed over with the brief, verbatim, when one was. */\n seed: z.string().min(1).optional(),\n /** What the person stated beside the URL, when they did. */\n stated: statedFactsSchema.optional(),\n /** Where the site facts came from: a file, or a sentence for a brand read by hand. */\n siteFacts: z.string().min(1).optional(),\n /** How many repair rounds the producer ran before the files validated. */\n rounds: z.number().int().min(0).optional(),\n});\n\nexport type BrandProvenance = z.infer<typeof brandProvenanceSchema>;\n\n/** The id a brand's directory is named by: `producer--model[--seeded]`. */\nexport function brandProducerId(\n provenance: Pick<BrandProvenance, 'producer' | 'model' | 'seed'>,\n): string {\n return [provenance.producer, provenance.model, provenance.seed ? 'seeded' : null]\n .filter((part): part is string => part !== null)\n .join('--');\n}\n\n/**\n * The scope class a brand's stylesheet sets its tokens on: `brand-<brand>-<producerId>`,\n * with every character outside `[a-z0-9-]` replaced, because a model id\n * carries dots and a dot ends a class selector.\n *\n * The replacement folds: `claude-4.8-opus` and `claude-4-8-opus` share a\n * scope, and so do two ids that differ only in case. A set of brands loaded on\n * one page must therefore check its scopes are distinct, or the later\n * stylesheet silently takes the earlier brand's place.\n */\nexport function brandScope(brand: string, producerId: string): string {\n return `brand-${brand}-${producerId}`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n}\n","import { BRAND_CONTRACT, COLOR_TOKEN_NAMES, type ColorTokenName } from './contract';\nimport {\n aliasTarget,\n asWritten,\n type BrandTokens,\n colorHex,\n type ColorValue,\n isControlCharacter,\n modeValue,\n type SrgbColor,\n} from './tokens';\n\n/**\n * A validated `tokens.json` in, the brand's stylesheet out.\n *\n * What comes out is exactly the contract, scoped: a `.<scope>` block setting\n * every custom property the contract names, and a `.dark .<scope>` block\n * restating every colour with its dark value. The `.dark` ancestor is the\n * package's own dark-mode convention (`theme.css`, the `dark` variant), so a\n * branded page inside a dark pane picks its dark values up with nothing else\n * to wire.\n *\n * The scope block also sets `font-family: var(--font-sans)`. Tailwind's\n * preflight resolves the page's typeface once, at `<html>`, so a scope that\n * only set `--font-sans` lower in the tree would change no text; declaring the\n * family where the scope is makes the brand's typeface reach everything under\n * it - the produced page and the plain form alike - while a page with no brand\n * keeps the host's own typeface untouched.\n *\n * The contract is closed - a fixed set of tokens, colours in sRGB only, one\n * length, two font stacks - so compiling a file the validator accepted is this\n * function and no dependency. It takes the file as `validateBrandTokens`\n * returned it; anything else is the caller's mistake, and `assembleBrand` is\n * the route that cannot make it. The output stays comparable with what a\n * standard DTCG tool writes for the same file: `__tests__/terrazzo.test.ts`\n * compiles every committed brand through Terrazzo and compares the\n * declarations.\n */\nexport function compileBrand(tokens: BrandTokens, scope: string): string {\n if (!/^[a-z][a-z0-9-]*$/.test(scope)) {\n throw new Error(`compileBrand: \"${scope}\" is not a scope class (see brandScope).`);\n }\n const light: string[] = [];\n const dark: string[] = [];\n for (const name of COLOR_TOKEN_NAMES) {\n const token = tokens.color[name];\n light.push(...declaration(token.$description, `--${name}`, colorCss(name, token.$value)));\n dark.push(\n ...declaration(token.$description, `--${name}`, colorCss(name, modeValue(token, 'dark'))),\n );\n }\n const radius = tokens.radius.base;\n light.push(\n ...declaration(radius.$description, '--radius', `${radius.$value.value}${radius.$value.unit}`),\n );\n for (const key of ['sans', 'mono'] as const) {\n const font = tokens.font[key];\n light.push(...declaration(font.$description, `--font-${key}`, fontStack(font.$value)));\n }\n light.push(\n ' /* The typeface reaches the text here, where the scope is; see compileBrand. */',\n ' font-family: var(--font-sans);',\n );\n return [`.${scope} {`, ...light, '}', '', `.dark .${scope} {`, ...dark, '}', ''].join('\\n');\n}\n\n/** Every custom property a compiled brand sets on its scope, in contract order. */\nexport const BRAND_VARIABLES: readonly string[] = BRAND_CONTRACT.map((token) => token.variable);\n\nfunction declaration(description: string, property: string, value: string): string[] {\n return [` /* ${commentText(description)} */`, ` ${property}: ${value};`];\n}\n\n/**\n * A description as comment text: one line, and nothing that could close the\n * comment, nor the `<style>` element of a host that inlines the stylesheet.\n */\nfunction commentText(text: string): string {\n return text.replace(/\\s+/g, ' ').replace(/\\*\\//g, '* /').replace(/<\\//g, '< /').trim();\n}\n\nfunction colorCss(name: ColorTokenName, value: ColorValue): string {\n const target = aliasTarget(value);\n if (target !== null) {\n // The validator has already refused an alias outside the contract; a\n // stray one here would write a reference to a property nothing sets.\n if (!(COLOR_TOKEN_NAMES as readonly string[]).includes(target)) {\n throw new Error(`compileBrand: color.${name} aliases {color.${target}}.`);\n }\n return `var(--${target})`;\n }\n return srgbCss(value as SrgbColor);\n}\n\n/**\n * An opaque colour as its hex, a translucent one as `rgb()` with its alpha,\n * both as `asWritten` rounds them, which is the colour the validator measured.\n */\nfunction srgbCss(color: SrgbColor): string {\n const { alpha } = asWritten(color);\n if (alpha >= 1) return colorHex(color);\n const [r, g, b] = color.components.map((channel) => Math.round(channel * 255));\n return `rgb(${r} ${g} ${b} / ${alpha})`;\n}\n\n/**\n * The family names CSS reads as keywords rather than as a face's name, which\n * must therefore stay unquoted: quoting `sans-serif` names a font called\n * \"sans-serif\" and loses the generic fallback.\n */\nconst KEYWORD_FAMILIES = new Set([\n 'serif',\n 'sans-serif',\n 'monospace',\n 'cursive',\n 'fantasy',\n 'system-ui',\n 'ui-serif',\n 'ui-sans-serif',\n 'ui-monospace',\n 'ui-rounded',\n 'emoji',\n 'math',\n 'fangsong',\n '-apple-system',\n 'blinkmacsystemfont',\n]);\n\nfunction fontStack(families: readonly string[]): string {\n return families\n .map((family) => (KEYWORD_FAMILIES.has(family.toLowerCase()) ? family : cssString(family)))\n .join(', ');\n}\n\n/**\n * A produced name as a CSS string that cannot end early. The quote and the\n * backslash are escaped; a control character (a form feed ends a string) and\n * `<` (which could close the `<style>` element of a host that inlines the\n * stylesheet) are written as their code points.\n */\nfunction cssString(text: string): string {\n const escaped = [...text.replace(/[\\\\']/g, '\\\\$&')]\n .map((char) =>\n char === '<' || char === '>' || isControlCharacter(char)\n ? `\\\\${char.codePointAt(0)!.toString(16)} `\n : char,\n )\n .join('');\n return `'${escaped}'`;\n}\n","import { compileBrand } from './compile';\nimport { type BrandManifest, brandManifestSchema } from './manifest';\nimport {\n type BrandProvenance,\n brandProducerId,\n brandProvenanceSchema,\n brandScope,\n} from './provenance';\nimport { statedFactProblems } from './stated';\nimport { type BrandTokens, validateBrandTokens } from './tokens';\n\n/**\n * One brand's three files in - the manifest, the tokens, the provenance - and\n * either the brand, validated and compiled, or every problem with it.\n *\n * This is the verdict on whether a brand is VALID under the contract as it is\n * now: the manifest, the tokens with their contrast, and the facts the person\n * stated. It is a hard verdict, and a brand that fails it is not compiled.\n * Whether a brand was produced against the current brief is a different\n * question and never a reason to refuse one - an older brand stays a valid\n * brand - so the provenance's contract hash is recorded here and judged by\n * the producer, not by this function.\n *\n * The problems come in the order a producer would want to be told: the\n * manifest and the provenance first, because they are cheap and their errors\n * exact, then the tokens, then the stated facts, which can only be checked\n * against files that parsed. Each names the file and the path.\n */\n\nexport interface BrandSource {\n /** The brand's directory name: `pipelex`. */\n brand: string;\n /** The producer's directory name under it: `pipelex-method--claude-4.8-opus`. */\n producerId: string;\n manifest: unknown;\n tokens: unknown;\n provenance: unknown;\n}\n\nexport interface AssembledBrand extends BrandProvenance {\n brand: string;\n producerId: string;\n manifest: BrandManifest;\n tokens: BrandTokens;\n /** The class a page root carries; the stylesheet is scoped to it. */\n scope: string;\n /** The compiled stylesheet. */\n css: string;\n}\n\nexport type AssembleResult =\n { ok: true; brand: AssembledBrand } | { ok: false; problems: string[] };\n\nfunction issues(file: string, error: { issues: { path: PropertyKey[]; message: string }[] }) {\n return error.issues.map((issue) => {\n const where = issue.path.map(String).join('.') || '(root)';\n return `${file}: ${where}: ${issue.message}`;\n });\n}\n\nexport function assembleBrand(source: BrandSource): AssembleResult {\n const problems: string[] = [];\n const manifest = brandManifestSchema.safeParse(source.manifest);\n if (!manifest.success) problems.push(...issues('brand.json', manifest.error));\n const provenance = brandProvenanceSchema.safeParse(source.provenance);\n if (!provenance.success) problems.push(...issues('provenance.json', provenance.error));\n else {\n const expected = brandProducerId(provenance.data);\n if (expected !== source.producerId) {\n problems.push(\n `provenance.json: names producer ${expected}, but the brand is filed as ${source.producerId}`,\n );\n }\n }\n const tokens = validateBrandTokens(source.tokens);\n if (!tokens.ok) problems.push(...tokens.problems.map((problem) => `tokens.json: ${problem}`));\n if (!manifest.success || !provenance.success || !tokens.ok) return { ok: false, problems };\n problems.push(...statedFactProblems(provenance.data.stated, manifest.data, tokens.tokens));\n if (problems.length > 0) return { ok: false, problems };\n const scope = brandScope(source.brand, source.producerId);\n return {\n ok: true,\n brand: {\n ...provenance.data,\n brand: source.brand,\n producerId: source.producerId,\n manifest: manifest.data,\n tokens: tokens.tokens,\n scope,\n css: compileBrand(tokens.tokens, scope),\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/brand/contract.ts","../../src/brand/tokens.ts","../../src/brand/stated.ts","../../src/brand/provenance.ts","../../src/brand/compile.ts","../../src/brand/assemble.ts"],"names":["z","description"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The brand contract, as data: which token of a brand's `tokens.json` sets\n * which custom property, and what that property paints.\n *\n * It is the theme contract seen from the other side. `src/styles/theme.css`\n * states it as a working default and `docs/theming.md` in prose; this is the\n * same list as a table a build can read, and a brand is exactly these tokens\n * and no others - the validator refuses a file that adds one, because a token\n * nothing consumes is a value with no way to be looked at.\n *\n * The colour and radius rows are not a second list kept beside `theme.css`:\n * they are held to it, by `__tests__/contract.test.ts` over the source and by\n * `scripts/assert-bundle.mjs` over the build. The two typography rows are the\n * exception, and on purpose. `--font-sans` and `--font-mono` are the names of\n * Tailwind's own theme variables, which the prebuilt sheet already declares,\n * so `theme.css` does not define them: it is unlayered, and a value there\n * would override the typeface of every host that loads it. The stock\n * typeface is therefore the host's own, and only a brand's scope sets these\n * two. See docs/brand.md.\n */\n\nexport type ContractTokenType = 'color' | 'dimension' | 'fontFamily';\n\nexport interface ContractToken {\n /** The DTCG token id, `color.background`. */\n id: string;\n /** The custom property it sets, `--background`. */\n variable: string;\n type: ContractTokenType;\n /** What the property paints, in the words a producer is told. */\n paints: string;\n}\n\n/** The colour tokens, in the order `theme.css` states them. */\nexport const COLOR_TOKEN_NAMES = [\n 'background',\n 'foreground',\n 'card',\n 'card-foreground',\n 'popover',\n 'popover-foreground',\n 'primary',\n 'primary-foreground',\n 'secondary',\n 'secondary-foreground',\n 'muted',\n 'muted-foreground',\n 'accent',\n 'accent-foreground',\n 'destructive',\n 'destructive-foreground',\n 'border',\n 'input',\n 'ring',\n] as const;\n\nexport type ColorTokenName = (typeof COLOR_TOKEN_NAMES)[number];\n\nexport function isColorTokenName(name: string): name is ColorTokenName {\n return (COLOR_TOKEN_NAMES as readonly string[]).includes(name);\n}\n\nconst COLOR_PAINTS: Record<ColorTokenName, string> = {\n background: 'The page canvas.',\n foreground: 'Text on the canvas.',\n card: \"A raised surface on the canvas: the rail's panel, a list's rows. May be translucent.\",\n 'card-foreground': 'Text on a card.',\n popover: \"A floating surface: a select's menu, a tooltip. Opaque.\",\n 'popover-foreground': 'Text on a popover.',\n primary: 'The accent: the run button, a selected pill, a section number, a highlight.',\n 'primary-foreground': 'Text on the accent.',\n secondary: 'A quiet filled surface: a secondary button, an unselected segment.',\n 'secondary-foreground': 'Text on a secondary surface.',\n muted: \"A subdued fill: a table's header band, an inactive tab strip.\",\n 'muted-foreground':\n \"Secondary text: descriptions, hints, a summary row's label. Most of the text on the page that is not a heading or a value.\",\n accent: 'A hover fill: a menu item under the pointer.',\n 'accent-foreground': 'Text on an accent fill.',\n destructive: 'The error colour: an invalid mark, a remove button.',\n 'destructive-foreground': 'Text on the destructive colour.',\n border: 'The hairline: every border and divider.',\n input:\n \"The control surface, a field's own fill - a step off the canvas, so fields read as one family.\",\n ring: 'The focus ring.',\n};\n\nexport const BRAND_CONTRACT: readonly ContractToken[] = [\n ...COLOR_TOKEN_NAMES.map((name): ContractToken => ({\n id: `color.${name}`,\n variable: `--${name}`,\n type: 'color',\n paints: COLOR_PAINTS[name],\n })),\n {\n id: 'radius.base',\n variable: '--radius',\n type: 'dimension',\n paints: 'The corner radius of a control; cards take one and a half of it.',\n },\n {\n id: 'font.sans',\n variable: '--font-sans',\n type: 'fontFamily',\n paints: 'The typeface of everything on the page.',\n },\n {\n id: 'font.mono',\n variable: '--font-mono',\n type: 'fontFamily',\n paints: 'Tags, numbers, the receipt.',\n },\n];\n\n/**\n * The pairs that must clear WCAG AA in both modes, as they render: the canvas\n * opaque, the ink blended over it by its alpha.\n */\nexport const CONTRAST_PAIRS: readonly {\n foreground: ColorTokenName;\n background: ColorTokenName;\n}[] = [\n { foreground: 'foreground', background: 'background' },\n { foreground: 'muted-foreground', background: 'background' },\n];\n\n/** The minimum contrast ratio those pairs must reach: WCAG 2 AA for normal text. */\nexport const MIN_CONTRAST = 4.5;\n\nconst byId = new Map(BRAND_CONTRACT.map((token) => [token.id, token]));\n\n/** The custom property a token sets, or a loud failure for a token the contract does not name. */\nexport function contractVariable(id: string): string {\n const token = byId.get(id);\n if (!token) throw new Error(`The brand contract has no token ${id}.`);\n return token.variable;\n}\n","import { z } from 'zod';\nimport {\n COLOR_TOKEN_NAMES,\n type ColorTokenName,\n CONTRAST_PAIRS,\n isColorTokenName,\n MIN_CONTRAST,\n} from './contract';\n\n/**\n * A brand's `tokens.json`, validated against the contract.\n *\n * The file is standard DTCG (the Design Tokens Community Group format, 2025.10),\n * and DTCG is looser than the contract in every direction that matters here: it\n * accepts any token, any colour space, a string colour, and a mode of any name.\n * Each of those is a way for a producer's file to be wrong and a page to be\n * painted anyway. So this holds the contract's own rules - exactly its tokens,\n * object colours in sRGB whose hex agrees with their components, aliases only\n * to contract tokens and never in a cycle, a description on every token, `dark`\n * the only mode and stated on every colour object (an alias may stand for both\n * modes), the contrast pairs in both modes - and a file it accepts is one the\n * compiler can only render. Every problem is named by its path, all at once,\n * so a producer's repair round is handed the whole list.\n */\n\nconst component = z.number().min(0).max(1);\n\nexport const srgbColorSchema = z.strictObject({\n colorSpace: z.literal('srgb'),\n components: z.tuple([component, component, component]),\n alpha: z.number().min(0).max(1),\n hex: z\n .string()\n .regex(/^#[0-9a-f]{6}$/i, 'a hex colour is #rrggbb')\n .optional(),\n});\n\nexport type SrgbColor = z.infer<typeof srgbColorSchema>;\n\nconst colorAliasSchema = z\n .string()\n .regex(/^\\{color\\.[a-z][a-z-]*\\}$/, 'an alias is \"{color.<name>}\"');\n\nconst colorValueSchema = z.union([srgbColorSchema, colorAliasSchema]);\n\nexport type ColorValue = z.infer<typeof colorValueSchema>;\n\nconst description = z.string().min(1, 'every token carries a $description');\n\n/**\n * A C0 control or DEL. Written as a test on the code point rather than a\n * character class, since that range is what a regex may not spell\n * (`no-control-regex`).\n */\nexport function isControlCharacter(char: string): boolean {\n const code = char.codePointAt(0)!;\n return code < 0x20 || code === 0x7f;\n}\n\nconst colorTokenSchema = z\n .strictObject({\n $value: colorValueSchema,\n $description: description,\n $extensions: z\n .strictObject({\n mode: z.strictObject({ dark: colorValueSchema }),\n })\n .optional(),\n })\n .refine((token) => token.$extensions !== undefined || typeof token.$value === 'string', {\n message: 'a colour carries $extensions.mode.dark; only an alias may stand for both modes',\n path: ['$extensions'],\n });\n\nexport type ColorToken = z.infer<typeof colorTokenSchema>;\n\nconst dimensionTokenSchema = z.strictObject({\n $value: z.strictObject({ value: z.number().min(0), unit: z.enum(['rem', 'px']) }),\n $description: description,\n});\n\nexport type DimensionToken = z.infer<typeof dimensionTokenSchema>;\n\nconst fontFamilyTokenSchema = z.strictObject({\n $value: z\n .array(\n z\n .string()\n .min(1)\n // A face's name never holds one, and a form feed ends a CSS string.\n .refine((name) => ![...name].some(isControlCharacter), {\n message: 'a family name holds no control characters',\n }),\n )\n .min(1),\n $description: description,\n});\n\nexport type FontFamilyToken = z.infer<typeof fontFamilyTokenSchema>;\n\n/** The token file, typed: the contract's groups and tokens, nothing else. */\nexport interface BrandTokens {\n color: { $type: 'color' } & Record<ColorTokenName, ColorToken>;\n radius: { $type: 'dimension'; base: DimensionToken };\n font: { $type: 'fontFamily'; sans: FontFamilyToken; mono: FontFamilyToken };\n}\n\nconst brandTokensSchema = z.strictObject({\n color: z.strictObject({\n $type: z.literal('color'),\n ...Object.fromEntries(COLOR_TOKEN_NAMES.map((name) => [name, colorTokenSchema])),\n }),\n radius: z.strictObject({ $type: z.literal('dimension'), base: dimensionTokenSchema }),\n font: z.strictObject({\n $type: z.literal('fontFamily'),\n sans: fontFamilyTokenSchema,\n mono: fontFamilyTokenSchema,\n }),\n});\n\nexport type TokensValidation =\n { ok: true; tokens: BrandTokens } | { ok: false; problems: string[] };\n\nexport type ColorMode = 'light' | 'dark';\n\n/** The name an alias points at, or null for a colour object. */\nexport function aliasTarget(value: ColorValue): string | null {\n return typeof value === 'string' ? value.slice('{color.'.length, -1) : null;\n}\n\n/** A token's dark value: what it states, or - for an alias that states none - the same alias. */\nexport function darkValue(token: ColorToken): ColorValue {\n return token.$extensions?.mode.dark ?? token.$value;\n}\n\n/** A token's value in a mode. */\nexport function modeValue(token: ColorToken, mode: ColorMode): ColorValue {\n return mode === 'light' ? token.$value : darkValue(token);\n}\n\n/** `#rrggbb` for a colour, its alpha dropped: each channel the byte the compiler writes. */\nexport function colorHex(color: SrgbColor): string {\n return `#${color.components\n .map((channel) =>\n Math.round(channel * 255)\n .toString(16)\n .padStart(2, '0'),\n )\n .join('')}`;\n}\n\n/**\n * Whether a colour compiles to the hex. The hex is what a brand ships for the\n * colour, so any slack here would let a stated accent ship as its neighbour.\n */\nexport function colorIsHex(color: SrgbColor, hex: string): boolean {\n return colorHex(color) === hex.toLowerCase();\n}\n\n/**\n * A colour as the compiler writes it: each channel the byte a hex or `rgb()`\n * carries, the alpha to the three decimals `rgb()` is given, and opaque once it\n * rounds to 1. A page renders this colour, not the components it was produced\n * as, so contrast is measured on it: a grey that passes at full precision can\n * round below the bar.\n */\nexport function asWritten(color: SrgbColor): SrgbColor {\n const alpha = Number(Math.min(color.alpha, 1).toFixed(3));\n return {\n colorSpace: 'srgb',\n components: color.components.map((channel) => Math.round(channel * 255) / 255) as [\n number,\n number,\n number,\n ],\n alpha,\n };\n}\n\nfunction checkHexAgreement(name: string, mode: ColorMode, value: ColorValue, problems: string[]) {\n if (typeof value === 'string' || !value.hex) return;\n if (!colorIsHex(value, value.hex)) {\n problems.push(\n `color.${name} (${mode}): hex ${value.hex} does not agree with components [${value.components.join(', ')}]`,\n );\n }\n}\n\nfunction checkAliases(tokens: BrandTokens, mode: ColorMode, problems: string[]) {\n for (const name of COLOR_TOKEN_NAMES) {\n const seen = new Set<string>([name]);\n let current: ColorTokenName = name;\n for (;;) {\n const target = aliasTarget(modeValue(tokens.color[current], mode));\n if (target === null) break;\n if (!isColorTokenName(target)) {\n problems.push(\n `color.${name} (${mode}): aliases {color.${target}}, which the contract has no token for`,\n );\n break;\n }\n if (seen.has(target)) {\n problems.push(`color.${name} (${mode}): alias cycle through {color.${target}}`);\n break;\n }\n seen.add(target);\n current = target;\n }\n }\n}\n\n/** The colour a token resolves to in a mode, through its aliases; null when a chain is broken. */\nexport function resolveColor(\n tokens: BrandTokens,\n name: ColorTokenName,\n mode: ColorMode,\n): SrgbColor | null {\n const seen = new Set<string>();\n let current: ColorTokenName = name;\n for (;;) {\n if (seen.has(current)) return null;\n seen.add(current);\n const value = modeValue(tokens.color[current], mode);\n const target = aliasTarget(value);\n if (target === null) return value as SrgbColor;\n if (!isColorTokenName(target)) return null;\n current = target;\n }\n}\n\nfunction luminance(color: SrgbColor): number {\n const [r, g, b] = color.components.map((channel) =>\n channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4,\n ) as [number, number, number];\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** WCAG 2 contrast ratio between two colours, taken as opaque. */\nexport function contrastRatio(a: SrgbColor, b: SrgbColor): number {\n const la = luminance(a);\n const lb = luminance(b);\n const [light, dark] = la > lb ? [la, lb] : [lb, la];\n return (light + 0.05) / (dark + 0.05);\n}\n\n/** A colour as it renders over an opaque one: the two blended by its alpha, as a browser does. */\nexport function composite(color: SrgbColor, over: SrgbColor): SrgbColor {\n const components = color.components.map(\n (channel, index) => channel * color.alpha + over.components[index]! * (1 - color.alpha),\n ) as [number, number, number];\n return { colorSpace: 'srgb', components, alpha: 1 };\n}\n\n/**\n * Each contrast pair as it renders. The canvas must be opaque, since a\n * translucent one shows whatever the host paints beneath it and its contrast is\n * nobody's to promise; the ink is blended over it, so a translucent ink is\n * measured at the strength it actually has, and a transparent one fails. Both\n * are measured as the compiler writes them, which is what renders.\n */\nfunction checkContrast(tokens: BrandTokens, mode: ColorMode, problems: string[]) {\n for (const pair of CONTRAST_PAIRS) {\n const foreground = resolveColor(tokens, pair.foreground, mode);\n const background = resolveColor(tokens, pair.background, mode);\n if (!foreground || !background) continue;\n if (background.alpha < 1) {\n problems.push(\n `color.${pair.background} (${mode}): alpha ${background.alpha}, but text is measured against it, so it must be opaque (alpha 1)`,\n );\n continue;\n }\n const canvas = asWritten(background);\n const ratio = contrastRatio(composite(asWritten(foreground), canvas), canvas);\n if (ratio < MIN_CONTRAST) {\n problems.push(\n `color.${pair.foreground} on color.${pair.background} (${mode}): contrast ${ratio.toFixed(2)}, expected ${MIN_CONTRAST} (WCAG AA)`,\n );\n }\n }\n}\n\n/** Every problem with the file at once, so a producer's repair round sees the whole list. */\nexport function validateBrandTokens(doc: unknown): TokensValidation {\n const parsed = brandTokensSchema.safeParse(doc);\n if (!parsed.success) {\n return {\n ok: false,\n problems: parsed.error.issues.map((issue) => {\n const where = issue.path.map(String).join('.') || '(root)';\n return `${where}: ${issue.message}`;\n }),\n };\n }\n const tokens = parsed.data as unknown as BrandTokens;\n const problems: string[] = [];\n for (const name of COLOR_TOKEN_NAMES) {\n const token = tokens.color[name];\n checkHexAgreement(name, 'light', token.$value, problems);\n checkHexAgreement(name, 'dark', darkValue(token), problems);\n }\n checkAliases(tokens, 'light', problems);\n checkAliases(tokens, 'dark', problems);\n // Contrast is read through the aliases, so it is only meaningful once every\n // chain resolves.\n if (problems.length === 0) {\n checkContrast(tokens, 'light', problems);\n checkContrast(tokens, 'dark', problems);\n }\n return problems.length === 0 ? { ok: true, tokens } : { ok: false, problems };\n}\n","import { z } from 'zod';\nimport { type BrandManifest, httpUrl } from './manifest';\nimport { type BrandTokens, colorHex, colorIsHex, resolveColor } from './tokens';\n\n/**\n * What a person states beside a site's URL: the things a site does not show and\n * no reading can supply. The accent of a site with no button, per mode when its\n * dark canvas needs another, and the logo for a canvas the site draws none for.\n *\n * A stated fact outranks every reading, which whatever runs a producer tells\n * it, outside this package. Here the brand is held to honour it\n * (`statedFactProblems`), and the provenance records it.\n */\n\nconst statedHex = z.string().regex(/^#[0-9a-f]{6}$/i, 'a stated accent is #rrggbb');\n\nexport const statedFactsSchema = z.strictObject({\n /** The accent per mode, `#rrggbb`: what `color.primary` resolves to in that mode. */\n accent: z\n .strictObject({\n light: statedHex.optional(),\n dark: statedHex.optional(),\n })\n .optional(),\n /**\n * The logo for a canvas: `logo.onLight` or `logo.onDark` in the manifest,\n * which the brand must carry exactly, so it obeys the manifest's rule (http\n * or https) or no brand could ever honour it.\n */\n logo: z\n .strictObject({\n onLight: httpUrl.optional(),\n onDark: httpUrl.optional(),\n })\n .optional(),\n});\n\nexport type StatedFacts = z.infer<typeof statedFactsSchema>;\n\n/**\n * Where the brand does not carry what the person stated, in the words a repair\n * round is told. Only the modes and canvases that were stated are checked.\n */\nexport function statedFactProblems(\n stated: StatedFacts | undefined,\n manifest: BrandManifest,\n tokens: BrandTokens,\n): string[] {\n if (!stated) return [];\n const problems: string[] = [];\n for (const mode of ['light', 'dark'] as const) {\n const accent = stated.accent?.[mode];\n if (!accent) continue;\n const primary = resolveColor(tokens, 'primary', mode);\n if (!primary) continue;\n if (!colorIsHex(primary, accent)) {\n problems.push(\n `tokens.json: color.primary (${mode}) resolves to ${colorHex(primary)}, but the accent for ${mode} mode was stated as ${accent}`,\n );\n }\n // A hex carries no alpha, so the components alone would let a primary\n // nobody can see honour the accent: a stated accent is an opaque colour.\n if (primary.alpha < 1) {\n problems.push(\n `tokens.json: color.primary (${mode}) has alpha ${primary.alpha}, but the accent for ${mode} mode was stated as the opaque ${accent}, so it must be opaque (alpha 1)`,\n );\n }\n }\n for (const canvas of ['onLight', 'onDark'] as const) {\n const url = stated.logo?.[canvas];\n if (url && manifest.logo[canvas] !== url) {\n problems.push(\n `brand.json: logo.${canvas} is ${manifest.logo[canvas]}, but the logo for that canvas was stated as ${url}`,\n );\n }\n }\n return problems;\n}\n","import { z } from 'zod';\nimport { statedFactsSchema } from './stated';\n\n/**\n * A brand's `provenance.json`: who produced it, on which model, from which\n * contract and which facts.\n *\n * A brand follows the rules a captured layout follows: produced by a pass,\n * committed with its provenance, and titled by what made it and by nothing\n * else. The provenance is a record, so it is never rewritten to make a check\n * pass. A brand's directory is named by `brandProducerId`, the same recipe a\n * layout fixture's id uses, so the tree and the record cannot disagree about\n * who made a brand.\n */\n\n/** How a brand came to be. */\nexport const BRAND_PRODUCERS = [\n /** The producer method, run on the hosted API. */\n 'pipelex-method',\n /** A Claude Code subagent in a fresh context, given the contract and the facts and nothing else. */\n 'claude-code-subagent',\n /** A Claude Code session reading the site and writing the files by hand. */\n 'claude-code-session',\n] as const;\n\nexport type BrandProducer = (typeof BRAND_PRODUCERS)[number];\n\n/** The first twelve hex digits of a SHA-256: how the provenance names a text it was produced from. */\nconst hash12 = z.string().regex(/^[0-9a-f]{12}$/, 'twelve hex digits');\n\nexport const brandProvenanceSchema = z\n .strictObject({\n producer: z.enum(BRAND_PRODUCERS),\n /** The model id: the one the method ran with, or the Claude Code model behind the session. */\n model: z.string().min(1),\n /** The day it was produced, `YYYY-MM-DD`. */\n date: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n /** The contract brief it was produced from, as the producer recorded its path. */\n brief: z.string().min(1),\n /** The first twelve hex digits of the SHA-256 of the contract brief at the time. */\n contractHash: hash12,\n /** The creative seed handed over with the brief, verbatim, when one was. */\n seed: z.string().min(1).optional(),\n /** What the person stated beside the URL, when they did. */\n stated: statedFactsSchema.optional(),\n /** Where the site facts came from: a file, or a sentence for a brand read by hand. */\n siteFacts: z.string().min(1).optional(),\n /**\n * The first twelve hex digits of the SHA-256 of the file `siteFacts`\n * names, its bytes as the producer read them. A path alone cannot say\n * whether the facts behind it moved since the brand was produced; whatever\n * re-reads them hashes the file again, and a mismatch makes the brand\n * stale, never invalid. The schema refuses one beside no `siteFacts`,\n * but it cannot tell a path from a sentence: a brand read by hand records\n * none by the producer's own rule, and a hash recorded beside a sentence\n * anyway is caught where it is judged, since the sentence names no file.\n */\n siteFactsHash: hash12.optional(),\n /** How many repair rounds the producer ran before the files validated. */\n rounds: z.number().int().min(0).optional(),\n })\n .refine(\n (provenance) => provenance.siteFactsHash === undefined || provenance.siteFacts !== undefined,\n {\n path: ['siteFactsHash'],\n message: 'no siteFacts names the file it hashes',\n },\n );\n\nexport type BrandProvenance = z.infer<typeof brandProvenanceSchema>;\n\n/** The id a brand's directory is named by: `producer--model[--seeded]`. */\nexport function brandProducerId(\n provenance: Pick<BrandProvenance, 'producer' | 'model' | 'seed'>,\n): string {\n return [provenance.producer, provenance.model, provenance.seed ? 'seeded' : null]\n .filter((part): part is string => part !== null)\n .join('--');\n}\n\n/**\n * The scope class a brand's stylesheet sets its tokens on: `brand-<brand>-<producerId>`,\n * with every character outside `[a-z0-9-]` replaced, because a model id\n * carries dots and a dot ends a class selector.\n *\n * The replacement folds: `claude-4.8-opus` and `claude-4-8-opus` share a\n * scope, and so do two ids that differ only in case. A set of brands loaded on\n * one page must therefore check its scopes are distinct, or the later\n * stylesheet silently takes the earlier brand's place.\n */\nexport function brandScope(brand: string, producerId: string): string {\n return `brand-${brand}-${producerId}`.toLowerCase().replace(/[^a-z0-9-]/g, '-');\n}\n","import { BRAND_CONTRACT, COLOR_TOKEN_NAMES, type ColorTokenName } from './contract';\nimport {\n aliasTarget,\n asWritten,\n type BrandTokens,\n colorHex,\n type ColorValue,\n isControlCharacter,\n modeValue,\n type SrgbColor,\n} from './tokens';\n\n/**\n * A validated `tokens.json` in, the brand's stylesheet out.\n *\n * What comes out is exactly the contract, scoped: a `.<scope>` block setting\n * every custom property the contract names, and a `.dark .<scope>` block\n * restating every colour with its dark value. The `.dark` ancestor is the\n * package's own dark-mode convention (`theme.css`, the `dark` variant), so a\n * branded page inside a dark pane picks its dark values up with nothing else\n * to wire.\n *\n * The scope block also sets `font-family: var(--font-sans)`. Tailwind's\n * preflight resolves the page's typeface once, at `<html>`, so a scope that\n * only set `--font-sans` lower in the tree would change no text; declaring the\n * family where the scope is makes the brand's typeface reach everything under\n * it - the produced page and the plain form alike - while a page with no brand\n * keeps the host's own typeface untouched.\n *\n * The contract is closed - a fixed set of tokens, colours in sRGB only, one\n * length, two font stacks - so compiling a file the validator accepted is this\n * function and no dependency. It takes the file as `validateBrandTokens`\n * returned it; anything else is the caller's mistake, and `assembleBrand` is\n * the route that cannot make it. The output stays comparable with what a\n * standard DTCG tool writes for the same file: `__tests__/terrazzo.test.ts`\n * compiles every committed brand through Terrazzo and compares the\n * declarations.\n */\nexport function compileBrand(tokens: BrandTokens, scope: string): string {\n if (!/^[a-z][a-z0-9-]*$/.test(scope)) {\n throw new Error(`compileBrand: \"${scope}\" is not a scope class (see brandScope).`);\n }\n const light: string[] = [];\n const dark: string[] = [];\n for (const name of COLOR_TOKEN_NAMES) {\n const token = tokens.color[name];\n light.push(...declaration(token.$description, `--${name}`, colorCss(name, token.$value)));\n dark.push(\n ...declaration(token.$description, `--${name}`, colorCss(name, modeValue(token, 'dark'))),\n );\n }\n const radius = tokens.radius.base;\n light.push(\n ...declaration(radius.$description, '--radius', `${radius.$value.value}${radius.$value.unit}`),\n );\n for (const key of ['sans', 'mono'] as const) {\n const font = tokens.font[key];\n light.push(...declaration(font.$description, `--font-${key}`, fontStack(font.$value)));\n }\n light.push(\n ' /* The typeface reaches the text here, where the scope is; see compileBrand. */',\n ' font-family: var(--font-sans);',\n );\n return [`.${scope} {`, ...light, '}', '', `.dark .${scope} {`, ...dark, '}', ''].join('\\n');\n}\n\n/** Every custom property a compiled brand sets on its scope, in contract order. */\nexport const BRAND_VARIABLES: readonly string[] = BRAND_CONTRACT.map((token) => token.variable);\n\nfunction declaration(description: string, property: string, value: string): string[] {\n return [` /* ${commentText(description)} */`, ` ${property}: ${value};`];\n}\n\n/**\n * A description as comment text: one line, and nothing that could close the\n * comment, nor the `<style>` element of a host that inlines the stylesheet.\n */\nfunction commentText(text: string): string {\n return text.replace(/\\s+/g, ' ').replace(/\\*\\//g, '* /').replace(/<\\//g, '< /').trim();\n}\n\nfunction colorCss(name: ColorTokenName, value: ColorValue): string {\n const target = aliasTarget(value);\n if (target !== null) {\n // The validator has already refused an alias outside the contract; a\n // stray one here would write a reference to a property nothing sets.\n if (!(COLOR_TOKEN_NAMES as readonly string[]).includes(target)) {\n throw new Error(`compileBrand: color.${name} aliases {color.${target}}.`);\n }\n return `var(--${target})`;\n }\n return srgbCss(value as SrgbColor);\n}\n\n/**\n * An opaque colour as its hex, a translucent one as `rgb()` with its alpha,\n * both as `asWritten` rounds them, which is the colour the validator measured.\n */\nfunction srgbCss(color: SrgbColor): string {\n const { alpha } = asWritten(color);\n if (alpha >= 1) return colorHex(color);\n const [r, g, b] = color.components.map((channel) => Math.round(channel * 255));\n return `rgb(${r} ${g} ${b} / ${alpha})`;\n}\n\n/**\n * The family names CSS reads as keywords rather than as a face's name, which\n * must therefore stay unquoted: quoting `sans-serif` names a font called\n * \"sans-serif\" and loses the generic fallback.\n */\nconst KEYWORD_FAMILIES = new Set([\n 'serif',\n 'sans-serif',\n 'monospace',\n 'cursive',\n 'fantasy',\n 'system-ui',\n 'ui-serif',\n 'ui-sans-serif',\n 'ui-monospace',\n 'ui-rounded',\n 'emoji',\n 'math',\n 'fangsong',\n '-apple-system',\n 'blinkmacsystemfont',\n]);\n\nfunction fontStack(families: readonly string[]): string {\n return families\n .map((family) => (KEYWORD_FAMILIES.has(family.toLowerCase()) ? family : cssString(family)))\n .join(', ');\n}\n\n/**\n * A produced name as a CSS string that cannot end early. The quote and the\n * backslash are escaped; a control character (a form feed ends a string) and\n * `<` (which could close the `<style>` element of a host that inlines the\n * stylesheet) are written as their code points.\n */\nfunction cssString(text: string): string {\n const escaped = [...text.replace(/[\\\\']/g, '\\\\$&')]\n .map((char) =>\n char === '<' || char === '>' || isControlCharacter(char)\n ? `\\\\${char.codePointAt(0)!.toString(16)} `\n : char,\n )\n .join('');\n return `'${escaped}'`;\n}\n","import { compileBrand } from './compile';\nimport { type BrandManifest, brandManifestSchema } from './manifest';\nimport {\n type BrandProvenance,\n brandProducerId,\n brandProvenanceSchema,\n brandScope,\n} from './provenance';\nimport { statedFactProblems } from './stated';\nimport { type BrandTokens, validateBrandTokens } from './tokens';\n\n/**\n * One brand's three files in - the manifest, the tokens, the provenance - and\n * either the brand, validated and compiled, or every problem with it.\n *\n * This is the verdict on whether a brand is VALID under the contract as it is\n * now: the manifest, the tokens with their contrast, and the facts the person\n * stated. It is a hard verdict, and a brand that fails it is not compiled.\n * Whether a brand was produced against the current brief, and from the facts\n * its recording holds now, is a different question and never a reason to\n * refuse one - an older brand stays a valid brand - so the provenance's\n * contract hash and facts hash are recorded here and judged by the producer,\n * not by this function.\n *\n * The problems come in the order a producer would want to be told: the\n * manifest and the provenance first, because they are cheap and their errors\n * exact, then the tokens, then the stated facts, which can only be checked\n * against files that parsed. Each names the file and the path.\n */\n\nexport interface BrandSource {\n /** The brand's directory name: `pipelex`. */\n brand: string;\n /** The producer's directory name under it: `pipelex-method--claude-4.8-opus`. */\n producerId: string;\n manifest: unknown;\n tokens: unknown;\n provenance: unknown;\n}\n\nexport interface AssembledBrand extends BrandProvenance {\n brand: string;\n producerId: string;\n manifest: BrandManifest;\n tokens: BrandTokens;\n /** The class a page root carries; the stylesheet is scoped to it. */\n scope: string;\n /** The compiled stylesheet. */\n css: string;\n}\n\nexport type AssembleResult =\n { ok: true; brand: AssembledBrand } | { ok: false; problems: string[] };\n\nfunction issues(file: string, error: { issues: { path: PropertyKey[]; message: string }[] }) {\n return error.issues.map((issue) => {\n const where = issue.path.map(String).join('.') || '(root)';\n return `${file}: ${where}: ${issue.message}`;\n });\n}\n\nexport function assembleBrand(source: BrandSource): AssembleResult {\n const problems: string[] = [];\n const manifest = brandManifestSchema.safeParse(source.manifest);\n if (!manifest.success) problems.push(...issues('brand.json', manifest.error));\n const provenance = brandProvenanceSchema.safeParse(source.provenance);\n if (!provenance.success) problems.push(...issues('provenance.json', provenance.error));\n else {\n const expected = brandProducerId(provenance.data);\n if (expected !== source.producerId) {\n problems.push(\n `provenance.json: names producer ${expected}, but the brand is filed as ${source.producerId}`,\n );\n }\n }\n const tokens = validateBrandTokens(source.tokens);\n if (!tokens.ok) problems.push(...tokens.problems.map((problem) => `tokens.json: ${problem}`));\n if (!manifest.success || !provenance.success || !tokens.ok) return { ok: false, problems };\n problems.push(...statedFactProblems(provenance.data.stated, manifest.data, tokens.tokens));\n if (problems.length > 0) return { ok: false, problems };\n const scope = brandScope(source.brand, source.producerId);\n return {\n ok: true,\n brand: {\n ...provenance.data,\n brand: source.brand,\n producerId: source.producerId,\n manifest: manifest.data,\n tokens: tokens.tokens,\n scope,\n css: compileBrand(tokens.tokens, scope),\n },\n };\n}\n"]}
@@ -4680,5 +4680,5 @@ function pdfFileName(field, value, baseName) {
4680
4680
  }
4681
4681
 
4682
4682
  export { BooleanField, ConceptPill, DEFAULT_FIELD_STRINGS, DateField, DocumentField, EN_FIELD_STRINGS, EnumField, FIELD_STRINGS_BY_LOCALE, FR_FIELD_STRINGS, FieldDomIdProvider, FieldPresentationProvider, FieldRenderer, FieldShell, FieldStringsProvider, HtmlPreview, ImageField, JsonView, ListField, Markdown, MethodForm, NumberField, ObjectField, OptionalToggle, PdfDownloadButton, ProseField, ResultEnvProvider, ResultField, ResultRoot, SUPPORTED_LOCALES, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, StuffViewer, Switch, TextField, ToggleGroup, ToggleGroupItem, UnknownField, cn, fieldControlClass, fieldStringsFor, humanizeFieldName, renderHtmlPdf, resolveHtmlStorageUrls, saveInBrowser, useFieldDomId, useFieldPresentation, useFieldStrings, useMethodForm, useProseImages, useResolveShareUrl, useResolveUrl, useResolvedUrl };
4683
- //# sourceMappingURL=chunk-AMBQ6PQR.js.map
4684
- //# sourceMappingURL=chunk-AMBQ6PQR.js.map
4683
+ //# sourceMappingURL=chunk-3KK2DO7T.js.map
4684
+ //# sourceMappingURL=chunk-3KK2DO7T.js.map