@getvitops/generator 8.2.0 → 8.3.0-alpha.1

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 (39) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/assets/css/index.css +8 -0
  3. package/assets/css/patterns/callout.css +39 -0
  4. package/assets/css/patterns/embed.css +39 -0
  5. package/assets/css/patterns/forms.css +14 -0
  6. package/assets/css/patterns/logos.css +45 -0
  7. package/assets/css/patterns/section.css +61 -0
  8. package/assets/css/patterns/sitenav.css +262 -0
  9. package/assets/css/patterns/stats.css +61 -0
  10. package/assets/css/patterns/steps.css +98 -0
  11. package/assets/css/patterns/tone.css +38 -0
  12. package/assets/css/patterns/widget-area.css +22 -0
  13. package/assets/js/elements.js +3 -3
  14. package/config.schema.json +126 -10
  15. package/dist/{config-BfcWKH-5.mjs → config-D5xuz8--.mjs} +79 -15
  16. package/dist/config-D5xuz8--.mjs.map +1 -0
  17. package/dist/config.d.mts +77 -18
  18. package/dist/config.d.mts.map +1 -1
  19. package/dist/config.mjs +1 -1
  20. package/dist/index.d.mts +40 -3
  21. package/dist/index.d.mts.map +1 -1
  22. package/dist/index.mjs +574 -42
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/{schema-BV2n2phj.d.mts → schema-C-P9dF9F.d.mts} +49 -3
  25. package/dist/schema-C-P9dF9F.d.mts.map +1 -0
  26. package/dist/{tokens-C1RJwFeG.mjs → tokens-CaIGQQLk.mjs} +56 -11
  27. package/dist/tokens-CaIGQQLk.mjs.map +1 -0
  28. package/dist/{tokens-BzBbTeTi.d.mts → tokens-DH5cpvKd.d.mts} +24 -7
  29. package/dist/tokens-DH5cpvKd.d.mts.map +1 -0
  30. package/dist/tokens.d.mts +1 -1
  31. package/dist/tokens.mjs +1 -1
  32. package/package.json +4 -4
  33. package/schema.json +95 -5
  34. package/dist/config-BfcWKH-5.mjs.map +0 -1
  35. package/dist/config-Bhg3Xv3D.mjs +0 -1774
  36. package/dist/config-Bhg3Xv3D.mjs.map +0 -1
  37. package/dist/schema-BV2n2phj.d.mts.map +0 -1
  38. package/dist/tokens-BzBbTeTi.d.mts.map +0 -1
  39. package/dist/tokens-C1RJwFeG.mjs.map +0 -1
package/schema.json CHANGED
@@ -48,6 +48,10 @@
48
48
  "type": "string"
49
49
  },
50
50
  "description": "Step → colour overrides (hex or oklch()) pinned VERBATIM at those steps. Every other step takes its lightness from the shared ladder, with chroma and hue interpolated between the anchors — so an anchor is reproduced exactly and is the only step allowed off the ladder. An explicit anchor overrides the seed at that step; two anchors that resolve to the same step are an error."
51
+ },
52
+ "acknowledgeOffLadder": {
53
+ "type": "boolean",
54
+ "description": "Acknowledge that this hue deliberately pins colours off the shared lightness ladder (typically to match an existing brand palette exactly). Silences the per-step \"off the ladder\" build warnings for THIS hue only; the monotonicity and contrast checks still run."
51
55
  }
52
56
  },
53
57
  "required": [
@@ -78,6 +82,10 @@
78
82
  }
79
83
  ],
80
84
  "description": "Fixed brand kit: authored tones placed verbatim at their nearest steps plus tinted off-white/off-black endpoints; no interpolation. Either an ordered light → dark array or a step → colour map."
85
+ },
86
+ "acknowledgeOffLadder": {
87
+ "type": "boolean",
88
+ "description": "Acknowledge that this hue deliberately pins colours off the shared lightness ladder (typically to match an existing brand palette exactly). Silences the per-step \"off the ladder\" build warnings for THIS hue only; the monotonicity and contrast checks still run."
81
89
  }
82
90
  },
83
91
  "required": [
@@ -116,6 +124,21 @@
116
124
  "chromatic"
117
125
  ],
118
126
  "description": "`surface` — a page/panel colour: gets a bare `bg-<role>` plus the full emphasis range and text scale. `chromatic` (default) — a signal colour: tints and solids only, no bare `bg-<role>`."
127
+ },
128
+ "solid": {
129
+ "description": "Ramp step (100…900) the role's solid family starts from; default 600. `bg-<role>-solid` is this step and `-solid-bold` / `-solid-x-bold` walk one and two rungs DARKER, so `solid: 400` gives 400 → 500 → 600. Use it when the brand colour is bright and lives lower on the ramp (a yellow at 400) instead of reaching for raw `bg-<hue>-<step>` classes. Like the default family it is the same in light and dark. The contrast check still runs on the pair this produces.",
130
+ "type": [
131
+ "number",
132
+ "string"
133
+ ]
134
+ },
135
+ "foreground": {
136
+ "type": "string",
137
+ "enum": [
138
+ "light",
139
+ "dark"
140
+ ],
141
+ "description": "Polarity of `text-on-<role>`, the foreground for a filled surface. Default is whichever of near-white / near-black has more contrast on the solid. Set `\"dark\"` so a bright fill carries dark text (or `\"light\"` for the reverse). The build still fails if the forced pair is below APCA Lc 60."
119
142
  }
120
143
  },
121
144
  "required": [
@@ -125,7 +148,7 @@
125
148
  }
126
149
  ]
127
150
  },
128
- "description": "Maps semantic role names onto palette hues. Role names are ARBITRARY — add a key and the generator emits that role's token set (`--color-<target>-<role>[-<variant>]` for target bg/text/icon/border), its dark-mode flip and its utility classes.\n\nA value is either a hue name (`\"danger\": \"rust\"`) or `{ \"hue\": …, \"kind\": \"surface\" | \"chromatic\" }`. **The kind decides the shape of the token set.** `chromatic` (the default, and what the bare-string form means) is a signal colour: its backgrounds split into tints (`bg-<role>-x-muted`/`-muted`) and solids (`bg-<role>-solid[-bold|-x-bold]`), with deliberately **no bare `bg-<role>`** — \"how loud?\" is a question the author answers. `surface` is a page/panel colour: it has a bare `bg-<role>` plus the full emphasis range and text scale.\n\nDark mode flips automatically; there is no per-appearance scheme grammar. The solid family and its computed `text-on-<role>` foreground stay mode-stable so a filled button keeps its identity. Six roles are a required core, because the shipped framework CSS references them with no fallback: brand-primary, danger, neutral, surface, ui-primary, warning. Conventional additions are ui-secondary/accent, brand-secondary, info and success."
151
+ "description": "Maps semantic role names onto palette hues. Role names are ARBITRARY — add a key and the generator emits that role's token set (`--color-<target>-<role>[-<variant>]` for target bg/text/icon/border), its dark-mode flip and its utility classes.\n\nA value is either a hue name (`\"danger\": \"rust\"`) or `{ \"hue\": …, \"kind\": \"surface\" | \"chromatic\" }`. **The kind decides the shape of the token set.** `chromatic` (the default, and what the bare-string form means) is a signal colour: its backgrounds split into tints (`bg-<role>-x-muted`/`-muted`) and solids (`bg-<role>-solid[-bold|-x-bold]`), with deliberately **no bare `bg-<role>`** — \"how loud?\" is a question the author answers. `surface` is a page/panel colour: it has a bare `bg-<role>` plus the full emphasis range and text scale.\n\nDark mode flips automatically; there is no per-appearance scheme grammar. The solid family and its computed `text-on-<role>` foreground stay mode-stable so a filled button keeps its identity. \n\n**Contrast is enforced at build time, in both appearances** (APCA Lc): body text ≥ 75, secondary and muted text (`text-muted`) ≥ **60 against the page plane** it sits on, icons and guaranteed boundaries ≥ 45, and `text-on-<role>` ≥ 60 on the role's solid. So a mockup's muted grey that lands near Lc 57 fails the build — lighten the anchor on a dark page (or darken it on a light one) until it clears 60. `text-x-muted`/`text-xx-muted` are exempt (placeholders, disabled). A role can move its fill off the default step 600 with `solid`, and pin the polarity of its on-colour with `foreground`; a dark-only site (`defaultColorScheme: \"dark\"`) is only checked in dark. Six roles are a required core, because the shipped framework CSS references them with no fallback: brand-primary, danger, neutral, surface, ui-primary, warning. Conventional additions are ui-secondary/accent, brand-secondary, info and success."
129
152
  },
130
153
  "utilities": {
131
154
  "type": "array",
@@ -152,13 +175,31 @@
152
175
  "description": "The colour system (the only required section): `palette` hues become generated OKLCH scales; `roles` map semantic roles onto those hues, from which all role tokens and dark mode derive."
153
176
  },
154
177
  "shadows": {
155
- "description": "Named shadows → `--shadow-<name>` tokens and `.drop-shadow-<name>` utilities. Values are shadow parameter lists (offset/blur/colour). Each token feeds two consumers with different grammars — `box-shadow` (pattern geometry, via the `--ds-*` group aliases) and `filter: drop-shadow(…)` (the utilities and the `shadow:` state shortcut) — so values must stay in the intersection: **one layer, no spread radius, no `inset`**. `drop-shadow()` rejects all three, and rejecting them invalidates the whole filter, so the shadow vanishes rather than degrading.",
178
+ "description": "Named shadows → `--shadow-<name>` tokens and `.drop-shadow-<name>` utilities. A value is either a string (below) or `{ \"box\"?: string, \"drop\"?: string }` for a shadow that needs the two grammars to differ: `box` is what `--shadow-<name>` holds and what `box-shadow` consumers (pattern geometry, `--ds-*`) read, so it MAY use spread, `inset` and several layers; `drop` is emitted as `--shadow-<name>-drop` and is what `.drop-shadow-<name>` and the `shadow:` state shortcut read, so it must obey the drop-shadow() limits. Omit `drop` and no drop-shadow utility is emitted for that name; omit `box` and `--shadow-<name>` takes the `drop` value. The plain string form keeps working and feeds both consumers from one value. For that string form: each token feeds two consumers with different grammars — `box-shadow` (pattern geometry, via the `--ds-*` group aliases) and `filter: drop-shadow(…)` (the utilities and the `shadow:` state shortcut) — so values must stay in the intersection: **one layer, no spread radius, no `inset`**. `drop-shadow()` rejects all three, and rejecting them invalidates the whole filter, so the shadow vanishes rather than degrading.",
156
179
  "type": "object",
157
180
  "propertyNames": {
158
181
  "type": "string"
159
182
  },
160
183
  "additionalProperties": {
161
- "type": "string"
184
+ "anyOf": [
185
+ {
186
+ "type": "string"
187
+ },
188
+ {
189
+ "type": "object",
190
+ "properties": {
191
+ "box": {
192
+ "type": "string",
193
+ "description": "`box-shadow` value: spread, `inset` and multiple layers allowed."
194
+ },
195
+ "drop": {
196
+ "type": "string",
197
+ "description": "`drop-shadow()` value: one layer, at most three lengths, no `inset`."
198
+ }
199
+ },
200
+ "additionalProperties": false
201
+ }
202
+ ]
162
203
  }
163
204
  },
164
205
  "fonts": {
@@ -172,7 +213,7 @@
172
213
  }
173
214
  },
174
215
  "typeScale": {
175
- "description": "Fluid modular TYPE scale → `--text-<name>` tokens, consumed by typography roles and text-size utilities.",
216
+ "description": "Fluid modular TYPE scale → `--text-<name>` tokens, consumed by typography roles and text-size utilities.\n\n**Recipe for marketing headings:** one ratio cannot serve both a ~16px body and a ~76px hero — a ratio big enough for the hero collapses the small end to unreadable. Extend `names` upward instead of raising the ratio: keep `base` ≈ \"1rem\" at the body step, `ratio` ≈ 1.2 at `maxVw` (≈ 1.125–1.15 `minRatio` at `minVw` so headings tame on phones), and add names (`4xl`, `5xl`) for the display sizes — the steps above `baseStep` are what headings read, the steps below it only need `xs`/`sm`. Aim the largest named step at your hero (≈ 4.5–5rem at `maxVw`), then point the `display`/`title` roles at those steps rather than hand-writing `clamp()` in a role. If a step still needs its own value, set that role's `size` literally — roles may bypass the scale.",
176
217
  "type": "object",
177
218
  "properties": {
178
219
  "base": {
@@ -233,6 +274,55 @@
233
274
  ],
234
275
  "additionalProperties": false
235
276
  },
277
+ "layout": {
278
+ "type": "object",
279
+ "properties": {
280
+ "widths": {
281
+ "type": "object",
282
+ "properties": {
283
+ "measure": {
284
+ "type": "string",
285
+ "description": "Reading column → `--width-measure` (framework default 65ch)."
286
+ },
287
+ "breakout": {
288
+ "type": "string",
289
+ "description": "`.breakout` track → `--width-breakout` (default 90ch)."
290
+ },
291
+ "spotlight": {
292
+ "type": "string",
293
+ "description": "`.spotlight` track → `--width-spotlight` (default 120ch)."
294
+ },
295
+ "nav": {
296
+ "type": "string",
297
+ "description": "Navigation column beside content → `--width-nav` (default 16rem)."
298
+ }
299
+ },
300
+ "additionalProperties": false,
301
+ "description": "Content track widths for `.centered`. In `ch` so the reading measure stays character-based; keep measure ≤ breakout ≤ spotlight."
302
+ },
303
+ "regionSpace": {
304
+ "type": "object",
305
+ "properties": {
306
+ "min": {
307
+ "type": "string",
308
+ "description": "Floor → `--region-space-min` (default 3rem)."
309
+ },
310
+ "preferred": {
311
+ "type": "string",
312
+ "description": "Preferred value → `--region-space` (default 8vh)."
313
+ },
314
+ "max": {
315
+ "type": "string",
316
+ "description": "Ceiling → `--region-space-max` (default 8rem)."
317
+ }
318
+ },
319
+ "additionalProperties": false,
320
+ "description": "Vertical padding of `.region`: `padding-block: clamp(min, preferred, max)`."
321
+ }
322
+ },
323
+ "additionalProperties": false,
324
+ "description": "Optional layout tokens. Each key you set is emitted as a `:root` custom property (css, bricks and tailwind formats); each you omit keeps the framework default. Lets the live editor tune widths and region spacing instead of a hand-written override stylesheet."
325
+ },
236
326
  "spaceScale": {
237
327
  "description": "Fluid modular SPACE scale → `--space-<name>` tokens, consumed by spacing/gap utilities and vertical rhythm.",
238
328
  "type": "object",
@@ -454,7 +544,7 @@
454
544
  "number"
455
545
  ]
456
546
  },
457
- "description": "A bag of CSS-ish keys, each mapped to a declaration plus a `--<role>-<sfx>` override hook. The recognised set is **closed**: `family`, `size`, `weight`, `style`, `line-height`, `tracking` (→ `letter-spacing`), `text-transform`, `text-decoration`, `text-wrap`, `color`. Note the last four are spelled with their full CSS property names — `transform` and `decoration` are NOT accepted. Anything unrecognised is **ignored**, not passed through, so the generator warns rather than emitting it: a silently-dropped `transform: uppercase` is how title-case navigation reaches production. Note also that `style`, `text-transform`, `text-decoration` and `text-wrap` are emitted on **every** role at their identity value (`normal`/`none`/`none`/`wrap`) whether declared or not, so applying one role class over another fully resets it — which means **omitting `text-wrap` is not \"inherit\"**: it emits `text-wrap: wrap` and cancels the `pretty` the role would otherwise inherit from a `pretty` ancestor such as a `body`-mapped role. Declare it on every role — `balance` for heading-like roles, `pretty` for copy, `wrap` for short single-line labels."
547
+ "description": "A bag of CSS-ish keys, each mapped to a declaration plus a `--<role>-<sfx>` override hook. The recognised set is **closed**: `family`, `size`, `weight`, `style`, `line-height`, `tracking` (→ `letter-spacing`), `text-transform`, `text-decoration`, `text-wrap`, `color`. The canonical spellings of the last four are their full CSS property names (`text-transform`, `text-decoration`, …); `transform` and `decoration` are accepted as aliases of the first two and normalised to them. Anything unrecognised is **ignored**, not passed through, so the generator warns rather than emitting it: a silently-dropped key (a typo for `text-transform`, say) is how title-case navigation reaches production. Note also that `style`, `text-transform`, `text-decoration` and `text-wrap` are emitted on **every** role at their identity value (`normal`/`none`/`none`/`wrap`) whether declared or not, so applying one role class over another fully resets it — which means **omitting `text-wrap` is not \"inherit\"**: it emits `text-wrap: wrap` and cancels the `pretty` the role would otherwise inherit from a `pretty` ancestor such as a `body`-mapped role. Declare it on every role — `balance` for heading-like roles, `pretty` for copy, `wrap` for short single-line labels."
458
548
  }
459
549
  },
460
550
  "headings": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-BfcWKH-5.mjs","names":[],"sources":["../src/token-refs.ts","../src/schema.ts","../src/config.ts"],"sourcesContent":["/**\n * Cross-layer check: does every `var(--…)` a config authors resolve to a token\n * the generator actually emits?\n *\n * A `patterns` value is a string the schema deliberately does not interpret\n * (see `CssDecls` in `schema.ts`), so a reference to a token that does not exist\n * parses, generates, minifies and ships. The declaration then resolves to\n * `inherit`/`unset` in the browser and nothing anywhere says so. Downstream this\n * shipped a `.cta` whose `color` fell back to `inherit` on a brand fill —\n * unreadable text on every filled button — and two of the four dead references\n * in that config had been dead for several versions.\n *\n * **The check is anchored to namespaces the generator owns**, exactly as\n * `vitops lint` is anchored to classes derived from the consumer's own config.\n * A pattern may legitimately reference a framework token defined in\n * `@getvitops/core`'s hand-written CSS (`--icon-size`, `--animation-duration`,\n * a consumer's own hook), and `validate()` is a pure function that must not read\n * the filesystem to find out. Enumerating \"every valid token\" would therefore\n * turn every such reference into a false positive. Enumerating only what the\n * generator emits — the colour layer, shadows, z-tiers — is a set it can compute\n * from the config alone, and it is where the dangling references actually occur.\n *\n * `FRAMEWORK_OWNED` is the one leak in that reasoning: a token that sits inside\n * an owned prefix but is defined by core's CSS instead. `token-refs.test.ts`\n * greps the shipped partials and fails if a new one appears, so the allowlist\n * cannot silently go stale.\n *\n * A reference carrying a fallback (`var(--x, 0.25rem)`) is **never** flagged: the\n * fallback is the author stating what happens when the token is absent, which is\n * the whole difference between a considered default and an accident.\n */\nimport { REQUIRED_ROLES, ROLE_TOKEN_KEYS, type RoleSpec, roleHue, roleKind } from './shared.ts';\nimport { expandPalette, functionalRole, tokenVar } from './tokens.ts';\n\n/**\n * Prefixes whose entire contents the generator emits. A `var()` inside one of\n * these either resolves to something the colour/shadow/z layer defines, or it\n * resolves to nothing — there is no third possibility, which is what makes an\n * error (rather than a warning) the right severity.\n */\nconst OWNED_PREFIXES = ['--color-', '--shadow-', '--z-tier-'] as const;\n\n/** Singleton tokens the colour layer emits, checked by exact name. */\nconst OWNED_EXACT = new Set(['--surface-glass', '--overlay']);\n\n/**\n * Tokens inside an owned prefix that `@getvitops/core`'s hand-written CSS\n * defines rather than the generator. Drift-guarded by `token-refs.test.ts`.\n */\nexport const FRAMEWORK_OWNED = new Set(['--color-swatch-size']);\n\n/**\n * Roles whose name says \"this is a surface\" while the bare-string shorthand\n * says `chromatic`. The two kinds emit *different token sets* — a chromatic role\n * has no bare `bg`, so `--color-bg-surface` and every `.bg-surface` utility\n * simply cease to exist, taking 36 references in the framework's own CSS with\n * them. Naming one of these and getting the chromatic set is almost always a\n * mistake, and it is the exact one a downstream config made.\n */\nconst SURFACE_SHAPED = new Set(['surface', 'neutral', 'background', 'page', 'canvas']);\n\n/**\n * The 1.0 colour-grammar rename, as data.\n *\n * Old suffix (on `--<role>-<suffix>`) → new token key (fed through `tokenVar`).\n * Transcribed from the migration table in the 1.0 changelog; `surface` rotates\n * separately below because its rename is value-preserving rather than\n * mechanical. `--color-<role>-<variant>` \"stops\" are deliberately absent — the\n * changelog says to judge those by use, and they already land in the owned\n * `--color-` namespace, so the generic check catches them with a near-miss hint.\n */\nconst MOVED_SUFFIXES: Record<string, string> = {\n bg: 'bg-x-muted',\n 'bg-muted': 'bg-muted',\n solid: 'bg-solid',\n 'solid-bold': 'bg-solid-bold',\n 'solid-x-bold': 'bg-solid-x-bold',\n 'on-solid': 'text-on',\n 'on-solid-bold': 'text-on-bold',\n text: 'text',\n 'text-muted': 'text-muted',\n 'text-x-muted': 'text-x-muted',\n 'text-xx-muted': 'text-xx-muted',\n 'text-bold': 'text-bold',\n icon: 'icon',\n 'icon-muted': 'icon-muted',\n border: 'border',\n 'border-muted': 'border-muted',\n 'border-bold': 'border-bold',\n};\n\n/**\n * `surface`'s background names rotate rather than map: what was `--surface-bg`\n * (the page) is now `--color-bg-surface-muted`, and what was `--surface-bg-bold`\n * (raised) is now `--color-bg-surface`. Applying the chromatic rule to it would\n * silently move the page background two rungs.\n */\nconst SURFACE_BG_ROTATION: Record<string, string> = {\n bg: 'bg-muted',\n 'bg-bold': 'bg',\n 'bg-muted': 'bg-x-muted',\n};\n\n/**\n * Old-grammar token name → its 1.0 replacement, for the roles this config\n * declares.\n *\n * Built per-config rather than as a static table because the old names embed\n * the *consumer's own* role names — there is no fixed list to hard-code, which\n * is why nothing detected these before.\n */\nexport function movedTokens(roles: Record<string, RoleSpec>): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [role, spec] of Object.entries(roles)) {\n const rotate = roleKind(spec) === 'surface';\n for (const [old, key] of Object.entries(MOVED_SUFFIXES))\n out[`--${role}-${old}`] = tokenVar(role, (rotate && SURFACE_BG_ROTATION[old]) || key);\n if (rotate)\n for (const [old, key] of Object.entries(SURFACE_BG_ROTATION))\n out[`--${role}-${old}`] = tokenVar(role, key);\n }\n return out;\n}\n\n/** A `var()` reference found in an authored value. */\nexport interface VarRef {\n /** Dotted config path of the declaration holding it. */\n path: string;\n /** The custom-property name, including the leading `--`. */\n name: string;\n /** Whether the reference supplies a fallback. */\n fallback: boolean;\n}\n\n/**\n * Extract every `var(--name[, fallback])` from a CSS value.\n *\n * Hand-rolled rather than a regex because the fallback has to be detected at the\n * reference's *own* paren depth: in `var(--a, var(--b))` the outer reference has\n * a fallback and the inner one does not, and a regex that stops at the first `)`\n * gets both wrong.\n */\nexport function extractVarRefs(value: string, path: string): VarRef[] {\n const out: VarRef[] = [];\n for (let i = value.indexOf('var('); i !== -1; i = value.indexOf('var(', i + 1)) {\n let j = i + 4;\n while (j < value.length && /\\s/.test(value[j] as string)) j++;\n const start = j;\n while (j < value.length && /[\\w-]/.test(value[j] as string)) j++;\n const name = value.slice(start, j);\n if (!name.startsWith('--')) continue;\n // Walk to this reference's own closing paren, tracking nesting, and note\n // whether a comma appears at depth 0 on the way.\n let depth = 0;\n let fallback = false;\n for (let k = j; k < value.length; k++) {\n const c = value[k];\n if (c === '(') depth++;\n else if (c === ')') {\n if (depth === 0) break;\n depth--;\n } else if (c === ',' && depth === 0) fallback = true;\n }\n out.push({ path, name, fallback });\n }\n return out;\n}\n\n/** Recursively collect refs from a value that may be a string or a nested map. */\nconst walkValue = (value: unknown, path: string, out: VarRef[]): void => {\n if (typeof value === 'string') out.push(...extractVarRefs(value, path));\n else if (value != null && typeof value === 'object' && !Array.isArray(value))\n for (const [k, v] of Object.entries(value as Record<string, unknown>))\n walkValue(v, `${path}.${k}`, out);\n};\n\n/**\n * Every authored declaration that can hold a `var()`.\n *\n * `patterns` is where the reported failures were, but `typography.roles.*.color`\n * and a `shadows` entry are authored the same way and fail the same way, so the\n * same walk covers them. `patterns.items.*.states` is walked recursively — a\n * state's `css` shortcut is a nested declaration map.\n */\nfunction collectVarRefs(ds: {\n patterns?: unknown;\n typography?: unknown;\n shadows?: unknown;\n}): VarRef[] {\n const out: VarRef[] = [];\n const p = (ds.patterns ?? {}) as Record<string, unknown>;\n walkValue(p['defaults'], 'patterns.defaults', out);\n walkValue(p['radii'], 'patterns.radii', out);\n walkValue(p['groups'], 'patterns.groups', out);\n for (const [name, item] of Object.entries((p['items'] ?? {}) as Record<string, unknown>)) {\n const it = (item ?? {}) as Record<string, unknown>;\n walkValue(it['base'], `patterns.items.${name}.base`, out);\n walkValue(it['overrides'], `patterns.items.${name}.overrides`, out);\n walkValue(it['states'], `patterns.items.${name}.states`, out);\n }\n walkValue((ds.typography as Record<string, unknown>)?.['roles'], 'typography.roles', out);\n walkValue(ds.shadows, 'shadows', out);\n return out;\n}\n\n/**\n * The custom properties the generator emits, as names.\n *\n * Derived from the same functions the emitter uses — `expandPalette` for the\n * ramps and `functionalRole` + `tokenVar` for the role set — so the check cannot\n * disagree with the output about what exists. Both appearances are unioned: a\n * token that only appears in the dark block is still defined.\n */\nexport function emittedTokens(ds: {\n colors: { palette: Record<string, unknown>; roles: Record<string, RoleSpec> };\n shadows?: Record<string, string> | undefined;\n patterns?: { z?: Record<string, number> | undefined } | undefined;\n}): Set<string> {\n const defined = new Set<string>();\n const palette = expandPalette(ds.colors.palette);\n for (const [hueName, hue] of Object.entries(palette))\n for (const n of Object.keys(hue.numeric)) defined.add(`--color-${hueName}-${n}`);\n let hasSurface = false;\n for (const [role, spec] of Object.entries(ds.colors.roles)) {\n const hueName = roleHue(spec);\n const hue = palette[hueName];\n if (hue == null) continue; // reported separately, as an error\n const kind = roleKind(spec);\n if (role === 'surface' && kind === 'surface') hasSurface = true;\n const fr = functionalRole(role, hueName, hue, kind);\n for (const key of new Set([...Object.keys(fr.light), ...Object.keys(fr.dark)]))\n defined.add(tokenVar(role, key));\n }\n if (Object.keys(ds.colors.roles).length) defined.add('--color-border-focus');\n if (hasSurface) {\n defined.add('--surface-glass');\n defined.add('--overlay');\n }\n for (const name of Object.keys(ds.shadows ?? {})) defined.add(`--shadow-${name}`);\n for (const name of Object.keys(ds.patterns?.z ?? {})) defined.add(`--z-tier-${name}`);\n return defined;\n}\n\n/** Whether this check has an opinion about a given custom property. */\nconst isOwned = (name: string): boolean =>\n !FRAMEWORK_OWNED.has(name) &&\n (OWNED_EXACT.has(name) || OWNED_PREFIXES.some((p) => name.startsWith(p)));\n\n/**\n * Suggest a near-miss from the emitted set, so the message names the fix rather\n * than only the failure. Cheap edit-distance-ish heuristic: same prefix, or a\n * one-segment difference.\n */\nconst nearest = (name: string, defined: Set<string>): string | undefined => {\n const segs = name.split('-').filter(Boolean);\n let best: string | undefined;\n let bestScore = 0;\n for (const cand of defined) {\n const cs = cand.split('-').filter(Boolean);\n const shared = cs.filter((s) => segs.includes(s)).length;\n const score = shared - Math.abs(cs.length - segs.length) * 0.5;\n if (score > bestScore) {\n bestScore = score;\n best = cand;\n }\n }\n return bestScore >= Math.max(2, segs.length - 1) ? best : undefined;\n};\n\n/** A dangling reference, with the config path that holds it. */\nexport interface TokenRefError {\n /** Config path, split for a `$ZodIssue.path`. */\n path: string[];\n message: string;\n}\n\nexport interface TokenRefIssues {\n errors: TokenRefError[];\n warnings: string[];\n}\n\n/**\n * Check a parsed design system's authored `var()` references, plus the\n * role-kind heuristic that produces most of them.\n *\n * Returns messages rather than issues so `validate()` owns the `$ZodIssue`\n * shaping, and so the same check can be reported by `generate()` without\n * inventing a second vocabulary.\n */\nexport function tokenRefIssues(ds: {\n colors: { palette: Record<string, unknown>; roles: Record<string, RoleSpec> };\n patterns?: unknown;\n typography?: unknown;\n shadows?: unknown;\n}): TokenRefIssues {\n const errors: TokenRefError[] = [];\n const warnings: string[] = [];\n\n // A role whose NAME says surface while its authoring says chromatic. Warn\n // before the ref check, because it is usually the cause of what follows.\n for (const [role, spec] of Object.entries(ds.colors.roles))\n if (SURFACE_SHAPED.has(role) && roleKind(spec) === 'chromatic')\n warnings.push(\n `colors.roles.${role} is declared chromatic (a bare hue string is shorthand for ` +\n `\\`kind: \"chromatic\"\\`), but the name reads as a surface. A chromatic role emits no ` +\n `bare \\`--color-bg-${role}\\` and no \\`.bg-${role}\\` utility` +\n (REQUIRED_ROLES.includes(role)\n ? `, and the framework's own component CSS references those with no fallback`\n : '') +\n `. Write \\`\"${role}\": { \"hue\": \"${roleHue(spec)}\", \"kind\": \"surface\" }\\` if you meant a surface.`,\n );\n\n let defined: Set<string>;\n try {\n defined = emittedTokens(\n ds as Parameters<typeof emittedTokens>[0] & {\n colors: { palette: Record<string, unknown>; roles: Record<string, RoleSpec> };\n },\n );\n } catch {\n // A palette this malformed fails with a better message elsewhere; a\n // half-built token set would only produce noise on top of it.\n return { errors, warnings };\n }\n\n // Dedupe by (name, path) — the same dead token in ten declarations is one\n // mistake, and ten copies of the message buries the other nine findings.\n const seen = new Set<string>();\n // Old-grammar references are collected separately and reported as ONE\n // enumerated rename table, following `migrationIssues()` in `config.ts`. A\n // config written against the pre-1.0 grammar carries dozens, and a dozen\n // individual \"no such token\" errors teaches nobody that a rename happened —\n // which is precisely the feedback that made that detector worth copying.\n const renames = movedTokens(ds.colors.roles);\n const moved = new Map<string, string>();\n\n // Dropping a required role is a WARNING by long-standing contract (the tokens\n // for the roles you do define are all emitted fine, and roles are extensible),\n // and that warning already names the role above. Every reference to the\n // dropped role's tokens is a consequence of it, so re-reporting them here as\n // errors would escalate a documented warning into a build failure and bury\n // the one message that explains it. `ROLE_TOKEN_KEYS` is exactly \"every token\n // key a role can resolve to\", which is what makes this excusal total.\n const excused = new Set<string>();\n for (const role of REQUIRED_ROLES)\n if (ds.colors.roles[role] == null)\n for (const key of ROLE_TOKEN_KEYS) excused.add(tokenVar(role, key));\n for (const ref of collectVarRefs(ds)) {\n if (ref.fallback || defined.has(ref.name) || excused.has(ref.name)) continue;\n const moveTo = renames[ref.name];\n if (moveTo != null) {\n moved.set(ref.name, moveTo);\n continue;\n }\n if (!isOwned(ref.name)) continue;\n const key = `${ref.name} ${ref.path}`;\n if (seen.has(key)) continue;\n seen.add(key);\n const hint = nearest(ref.name, defined);\n errors.push({\n path: ref.path.split('.'),\n message:\n `${ref.path} references \\`var(${ref.name})\\`, which this config emits no token for — ` +\n `the declaration will resolve to nothing at runtime.` +\n (hint ? ` Did you mean \\`var(${hint})\\`?` : '') +\n ` (Give it a fallback — \\`var(${ref.name}, <value>)\\` — if the absence is intentional.)`,\n });\n }\n\n if (moved.size)\n errors.unshift({\n path: ['colors'],\n message:\n `${moved.size} token reference${moved.size === 1 ? ' uses' : 's use'} the pre-1.0 colour ` +\n `grammar. The role moved into the middle of the property name, after its target ` +\n `(\\`--color-<target>-<role>[-<variant>]\\`):\\n` +\n [...moved].map(([old, next]) => ` ${old} → ${next}`).join('\\n') +\n `\\n\\nApply these simultaneously, not one at a time — several renames are cyclic ` +\n `(a surface role's backgrounds rotate), so sequential replacement compounds them. ` +\n `\\`vitops lint <src> --fix\\` does this for markup and CSS.`,\n });\n\n return { errors, warnings };\n}\n","/**\n * Canonical `design-system.json` schema — the single source of truth.\n *\n * Authored with `@zod/mini` (tree-shakeable Zod v4's mini API, as its own\n * lockstep-versioned package since zod 4.5 — was the `zod/mini` subpath\n * import prior to that; same API, no rewrite needed beyond the import\n * itself). Everything else derives from it:\n * • the `DesignSystem` TS type (`z.infer`), used throughout the generator,\n * • the published JSON Schema (`toJSONSchema`), emitted to `schema.json` for `$schema` refs,\n * • runtime validation (`validate`) for the CLI and to gate `generate`,\n * • the generated `authoring.md` reference doc (walks `jsonSchema`'s descriptions).\n */\nimport { desc } from '@getvitops/config';\nimport * as z from '@zod/mini';\nimport { REQUIRED_ROLES, type RoleSpec, roleHue } from './shared.ts';\nimport { tokenRefIssues } from './token-refs.ts';\n\n/**\n * Attach a JSON-Schema `description`. zod/mini has no `.describe()` method; the\n * mini-API equivalent is `.check(z.describe(…))`, and `.check()` clones — so a\n * shared sub-schema (`Scale`, `CssDecls`, …) can carry a different description\n * per use-site without mutating the original.\n */\nexport { desc };\n\nconst CssDecls = desc(\n z.record(z.string(), z.string()),\n 'A CSS declaration block: property → value. Values stay strings (they can be hex, var(), clamp(), keywords, …); the generator, not the schema, interprets them.',\n);\nconst Scalar = z.union([z.string(), z.number()]);\nconst VarMap = z.record(z.string(), Scalar);\n\n// ── colors ──────────────────────────────────────────────────────────────────\nconst SeededRamp = desc(\n z.strictObject({\n seed: desc(\n z.string(),\n 'Seed colour (hex or oklch()). An 11-step numeric scale (50…950, tinted near-white → tinted near-black) is generated in OKLCH from it; the seed is preserved at its natural step.',\n ),\n anchors: z.optional(\n desc(\n z.record(z.string(), z.string()),\n 'Step → colour overrides (hex or oklch()) pinned VERBATIM at those steps. Every other step takes its lightness from the shared ladder, with chroma and hue interpolated between the anchors — so an anchor is reproduced exactly and is the only step allowed off the ladder. An explicit anchor overrides the seed at that step; two anchors that resolve to the same step are an error.',\n ),\n ),\n }),\n 'Seeded hue: the 11-step scale is GENERATED in OKLCH from `seed` (anchors pin specific steps).',\n);\nconst FixedRamp = desc(\n z.strictObject({\n tones: desc(\n z.union([z.array(z.string()), z.record(z.string(), z.string())]),\n 'Fixed brand kit: authored tones placed verbatim at their nearest steps plus tinted off-white/off-black endpoints; no interpolation. Either an ordered light → dark array or a step → colour map.',\n ),\n }),\n 'Fixed hue: authored brand tones used verbatim; no generation.',\n);\nconst Ramp = desc(\n z.union([SeededRamp, FixedRamp]),\n 'A palette hue, authored one of two ways: `{ seed, anchors? }` generates an 11-step numeric OKLCH scale (50…950) from the seed, or `{ tones }` supplies a fixed brand kit used verbatim.',\n);\n\n/**\n * A role points at a hue, and optionally declares its kind. The bare-string form\n * is the shorthand for a chromatic role — signal colours are the common case,\n * and the two or three surfaces are worth naming explicitly.\n */\nconst RoleSpecSchema = z.union([\n desc(z.string(), 'A palette hue name. Shorthand for `{ hue, kind: \"chromatic\" }`.'),\n z.strictObject({\n hue: desc(z.string(), 'The palette hue this role resolves to.'),\n kind: z.optional(\n desc(\n z.enum(['surface', 'chromatic']),\n '`surface` — a page/panel colour: gets a bare `bg-<role>` plus the full emphasis range and text scale. `chromatic` (default) — a signal colour: tints and solids only, no bare `bg-<role>`.',\n ),\n ),\n }),\n]);\n\nconst UtilityName = z.enum(['bg', 'text', 'icon', 'border', 'outline', 'fill', 'stroke']);\n\nconst Colors = desc(\n z.strictObject({\n palette: desc(\n z.record(z.string(), Ramp),\n 'Palette hues by name. Each becomes an 11-step numeric OKLCH scale (`--color-<hue>-50…950`). Every ramp shares one fixed lightness ladder, so a step means the same lightness in every hue; only chroma and hue vary. Beyond the outermost authored colour the chroma decays towards a small endpoint value (0.008 light / 0.015 dark) so the near-white and near-black ends keep a whisper of the hue — but that is a **ceiling**, not a target, so a low-chroma seed stays low and **a chroma-0 seed gives a true neutral** rather than a tinted one. The ladder is also enforced: if pinned colours leave a ramp non-monotonic (some step darker than the one below it), the build fails rather than shipping a scale whose hover states run backwards.',\n ),\n roles: desc(\n z.record(z.string(), RoleSpecSchema),\n `Maps semantic role names onto palette hues. Role names are ARBITRARY — add a key and the generator emits that role's token set (\\`--color-<target>-<role>[-<variant>]\\` for target bg/text/icon/border), its dark-mode flip and its utility classes.\\n\\nA value is either a hue name (\\`\"danger\": \"rust\"\\`) or \\`{ \"hue\": …, \"kind\": \"surface\" | \"chromatic\" }\\`. **The kind decides the shape of the token set.** \\`chromatic\\` (the default, and what the bare-string form means) is a signal colour: its backgrounds split into tints (\\`bg-<role>-x-muted\\`/\\`-muted\\`) and solids (\\`bg-<role>-solid[-bold|-x-bold]\\`), with deliberately **no bare \\`bg-<role>\\`** — \"how loud?\" is a question the author answers. \\`surface\\` is a page/panel colour: it has a bare \\`bg-<role>\\` plus the full emphasis range and text scale.\\n\\nDark mode flips automatically; there is no per-appearance scheme grammar. The solid family and its computed \\`text-on-<role>\\` foreground stay mode-stable so a filled button keeps its identity. Six roles are a required core, because the shipped framework CSS references them with no fallback: ${REQUIRED_ROLES.join(', ')}. Conventional additions are ui-secondary/accent, brand-secondary, info and success.`,\n ),\n utilities: z.optional(\n desc(\n z.array(UtilityName),\n 'Which colour utility-class families to emit (`bg-*`, `text-*`, `icon-*`, `border-*`, `outline-*`, `fill-*`, `stroke-*`). Defaults to bg, text, icon, border. `icon` is a separate non-text tier (a glyph may run more vivid than text); `outline`/`fill`/`stroke` have no tokens of their own and alias the border and icon tiers.',\n ),\n ),\n }),\n 'The colour system (the only required section): `palette` hues become generated OKLCH scales; `roles` map semantic roles onto those hues, from which all role tokens and dark mode derive.',\n);\n\n// ── fluid modular scale (type + space) ──────────────────────────────────────\nconst Scale = z.strictObject({\n base: desc(z.string(), 'Anchor size (a CSS length, e.g. \"1rem\") — the value at `baseStep`.'),\n ratio: desc(z.number(), 'Modular ratio between adjacent steps at large viewports.'),\n steps: desc(\n z.optional(z.number()),\n 'Token count when `names` is absent (steps are then named 1..steps).',\n ),\n names: desc(\n z.optional(z.array(z.string())),\n 'Step names, smallest → largest (e.g. [\"xs\",\"sm\",\"md\",…]); each becomes a token suffix.',\n ),\n baseStep: desc(z.optional(z.number()), '1-based index of the step whose value is `base`.'),\n baseline: desc(\n z.optional(z.string()),\n 'Named step used as the fluid pivot / GUI scale centre (defaults to `baseStep`).',\n ),\n fluid: desc(\n z.optional(\n z.strictObject({\n minVw: desc(z.string(), 'Viewport width (CSS length) where fluid scaling bottoms out.'),\n maxVw: desc(z.string(), 'Viewport width (CSS length) where fluid scaling tops out.'),\n minRatio: desc(z.number(), 'Modular ratio at/below `minVw` (usually < `ratio`).'),\n }),\n ),\n 'Makes the scale fluid: each step compiles to a clamp() that interpolates from `minRatio` at `minVw` to `ratio` at `maxVw`.',\n ),\n});\n\n// ── patterns ────────────────────────────────────────────────────────────────\nconst Pattern = desc(\n z.strictObject({\n group: desc(\n z.optional(z.string()),\n 'Token-cascade group this pattern belongs to (e.g. tag / control / panel); base declarations resolve through `--<prop>-<group>` before `--<prop>-default`.',\n ),\n overrides: z.optional(\n desc(CssDecls, 'Per-pattern token overrides, emitted as `--<prop>-<name>-group` values.'),\n ),\n element: desc(\n z.optional(z.string()),\n 'Style at element level via zero-specificity `:where(<element>)` (instead of, or alongside, a class).',\n ),\n class: desc(\n z.optional(z.string()),\n \"Class name to emit (defaults to the pattern's key when no `element` is set). Combined with `element`, the pattern emits one zero-specificity `:where(<element>, .<class>)` rule so the class works on any tag and any explicit class overrides it.\",\n ),\n fill: desc(\n z.optional(z.boolean()),\n 'Whether this pattern is colour-filled (states/roles drive `background-color` + `on-solid` text) or text-coloured (they drive `color`). Defaults to true when `base` declares a background.',\n ),\n default_role: desc(\n z.optional(z.string()),\n 'Semantic colour role applied to the bare/default variant.',\n ),\n base: z.optional(\n desc(\n CssDecls,\n 'Base CSS declarations. Geometry properties (padding, border-radius, border, box-shadow, font-size) are wrapped in per-pattern override hooks (`--p-<name>`, `--br-<name>`, `--b-<name>`, `--ds-<name>`, `--fs-<name>`) so consumers can restyle one pattern by setting one variable.',\n ),\n ),\n states: desc(\n z.optional(z.record(z.string(), z.record(z.string(), z.unknown()))),\n 'Interaction states (hover / active / focus-visible), each a map of shortcuts: `step` (intensify the fill or text by n rungs — `bg-<role>-solid` → `-solid-bold`, `text-<role>` → `-bold`), `scale` (transform scale), `lift` (translateY + shadow), `shadow` (a shadow name → drop-shadow(var(--shadow-<name>)), or true → lift shadow), `ring` (focus ring), or raw `css` declarations. Hover rules are wrapped in `@media (hover: hover)`.',\n ),\n roles: desc(\n z.optional(z.array(z.string())),\n 'Semantic colour role variants to emit as `<pattern>-<role>` classes (fills use the role solid / on-solid tokens).',\n ),\n }),\n 'One component pattern (button, link, badge, card, …): base declarations + interaction states + semantic role variants, resolved through the pattern token cascade.',\n);\n\nconst Patterns = desc(\n z.strictObject({\n defaults: z.optional(\n desc(CssDecls, 'Cascade-wide fallback tokens, emitted as `--<prop>-default`.'),\n ),\n radii: z.optional(\n desc(CssDecls, 'Shape primitives, emitted as `--br-<name>` (referenced by pattern bases).'),\n ),\n groups: desc(\n z.optional(z.record(z.string(), CssDecls)),\n 'Group-level tokens, emitted as `--<prop>-<group>`; patterns opt in via their `group` key.',\n ),\n z: desc(z.optional(z.record(z.string(), z.number())), 'Z-index tiers → `--z-tier-<name>`.'),\n items: desc(\n z.optional(z.record(z.string(), Pattern)),\n 'The component patterns to emit, keyed by name.',\n ),\n }),\n 'Component patterns and their token cascade: `defaults` → `groups` → per-pattern `overrides`, plus shape (`radii`) and z-index primitives.',\n);\n\n// ── typography ──────────────────────────────────────────────────────────────\nconst TypographyRole = desc(\n z.record(z.string(), Scalar),\n 'A bag of CSS-ish keys, each mapped to a declaration plus a `--<role>-<sfx>` override hook. The recognised set is **closed**: `family`, `size`, `weight`, `style`, `line-height`, `tracking` (→ `letter-spacing`), `text-transform`, `text-decoration`, `text-wrap`, `color`. Note the last four are spelled with their full CSS property names — `transform` and `decoration` are NOT accepted. Anything unrecognised is **ignored**, not passed through, so the generator warns rather than emitting it: a silently-dropped `transform: uppercase` is how title-case navigation reaches production. Note also that `style`, `text-transform`, `text-decoration` and `text-wrap` are emitted on **every** role at their identity value (`normal`/`none`/`none`/`wrap`) whether declared or not, so applying one role class over another fully resets it — which means **omitting `text-wrap` is not \"inherit\"**: it emits `text-wrap: wrap` and cancels the `pretty` the role would otherwise inherit from a `pretty` ancestor such as a `body`-mapped role. Declare it on every role — `balance` for heading-like roles, `pretty` for copy, `wrap` for short single-line labels.',\n);\nconst Typography = desc(\n z.strictObject({\n families: desc(\n z.optional(z.record(z.string(), z.string())),\n 'Role-facing family aliases → CSS font values, usually referencing the top-level `fonts` tokens (e.g. \"var(--font-display)\").',\n ),\n roles: desc(\n z.optional(z.record(z.string(), TypographyRole)),\n 'Semantic type roles (display, title, heading, body, quote, caption, eyebrow, code, lead, footnote, tag, …), each emitted as a `font-<role>` class.',\n ),\n headings: desc(\n z.optional(z.record(z.string(), z.string())),\n 'Maps bare elements to type roles so unclassed markup picks up role styling — `{ \"h1\": \"display\", \"h2\": \"heading\" }`. The key is used verbatim as a selector, so it is not limited to h1…h6: **map `\"body\"` to your prose role** to bind base page typography to the role rather than hand-writing it. That binding is what makes the role editable — a stylesheet that re-states `font-family`/`line-height` as literals on `body` shadows `--<role>-ff`/`--<role>-lh`, and the live theme editor then appears to do nothing.',\n ),\n }),\n 'Typography: family aliases, semantic type roles (→ `font-<role>` classes), and the bare-element → role mapping.',\n);\n\n// ── animations ──────────────────────────────────────────────────────────────\nconst AnimEffect = desc(\n z.strictObject({\n kf: desc(\n z.string(),\n 'Keyframe family driving the effect: composite (transform/opacity), paint, or layout.',\n ),\n css: z.optional(desc(VarMap, 'Extra literal declarations merged into the effect class as-is.')),\n vars: z.optional(\n desc(\n VarMap,\n 'Effect endpoint variables (`--<key>: <value>`, e.g. opacity-from, translate-y-to) that override the keyframe defaults.',\n ),\n ),\n }),\n 'A named animation effect class — a pure value layer (`--_anim` + `--<prop>-from/-to`) over the static keyframe engine.',\n);\nconst Animations = desc(\n z.strictObject({\n effects: desc(\n z.optional(z.record(z.string(), AnimEffect)),\n 'Effect classes to emit (`.fade-in`, `.reveal-left`, …), keyed by class name.',\n ),\n journeys: desc(\n z.optional(\n z.strictObject({\n base: desc(\n z.optional(z.record(z.string(), VarMap)),\n 'Named journey building blocks: part name → var map.',\n ),\n compose: desc(\n z.optional(z.array(z.array(z.string()))),\n 'Combinations of base parts, each emitted as a `.<parts>-journey` class.',\n ),\n }),\n ),\n 'Multi-part journey classes composed from `base` building blocks.',\n ),\n }),\n 'Animation effect + journey classes (pure value layers). The animation engine itself — keyframes, drivers, floats, utilities — is static framework CSS, not configured here.',\n);\n\n// ── the design system ───────────────────────────────────────────────────────\nexport const DesignSystemSchema = z.strictObject({\n $schema: desc(\n z.optional(z.string()),\n 'URL of the published JSON Schema (stamped by `vitops init`) so editors provide autocomplete + validation.',\n ),\n meta: desc(\n z.optional(\n z.strictObject({\n name: desc(\n z.optional(z.string()),\n 'Brand/system name. Used as the `name` field and `<h1>` of the `design` format\\'s `DESIGN.md`. Defaults to \"Design System\".',\n ),\n description: desc(\n z.optional(z.string()),\n \"One or two sentences on the brand personality and the feeling the UI should evoke — what an agent needs when no token answers the question. Becomes the DESIGN.md `description` field and opens its Overview section; if omitted, a generic description of the system's mechanics is used instead.\",\n ),\n }),\n ),\n 'Brand identity for agent-facing output. Consumed only by the `design` format (`DESIGN.md`); it emits no CSS and no tokens.',\n ),\n colors: Colors,\n shadows: desc(\n z.optional(z.record(z.string(), z.string())),\n 'Named shadows → `--shadow-<name>` tokens and `.drop-shadow-<name>` utilities. Values are shadow parameter lists (offset/blur/colour). Each token feeds two consumers with different grammars — `box-shadow` (pattern geometry, via the `--ds-*` group aliases) and `filter: drop-shadow(…)` (the utilities and the `shadow:` state shortcut) — so values must stay in the intersection: **one layer, no spread radius, no `inset`**. `drop-shadow()` rejects all three, and rejecting them invalidates the whole filter, so the shadow vanishes rather than degrading.',\n ),\n fonts: desc(\n z.optional(z.record(z.string(), z.string())),\n 'Raw font stacks by name, emitted as `--font-<name>` tokens (referenced by `typography.families`). **Stacks only — vitops does not load webfonts.** A value here is a `font-family` list and nothing more: it emits no `@font-face`, no preload, and no metrics-matched fallback. If a family needs loading, declare it in Astro\\'s `fonts:` config (`astro.config`, or the site config\\'s `fonts` array) and point the token at the family\\'s `cssVariable` — `\"display\": \"var(--font-league-spartan), sans-serif\"`. Installing a `@fontsource*` package and importing its CSS also works but gives up subsetting, preload and `size-adjust`/`ascent-override` fallbacks, so it regresses CLS.',\n ),\n typeScale: desc(\n z.optional(Scale),\n 'Fluid modular TYPE scale → `--text-<name>` tokens, consumed by typography roles and text-size utilities.',\n ),\n spaceScale: desc(\n z.optional(Scale),\n 'Fluid modular SPACE scale → `--space-<name>` tokens, consumed by spacing/gap utilities and vertical rhythm.',\n ),\n patterns: z.optional(Patterns),\n typography: z.optional(Typography),\n animations: z.optional(Animations),\n});\n\nexport type DesignSystem = z.infer<typeof DesignSystemSchema>;\n\n// A deep-partial view used for theme deltas: an `extends` patch supplies only\n// what it overrides, so every field is optional — including one level down\n// through `colors` into palette / roles / utilities. Reuses the same leaf\n// schemas, so there's no second source of truth. Completeness is enforced after\n// merge (validate the resolved theme against `DesignSystemSchema`).\n//\n// Note this is NOT a per-appearance grammar. Light/dark is derived inside a\n// single design system by re-pointing which ramp step each token reads; the old\n// `schemes` layer this comment used to describe was removed with that redesign.\nconst ColorsPatch = z.strictObject({\n palette: z.optional(z.record(z.string(), Ramp)),\n roles: z.optional(z.record(z.string(), RoleSpecSchema)),\n utilities: z.optional(z.array(UtilityName)),\n});\nexport const DesignSystemPatchSchema = z.extend(z.partial(DesignSystemSchema), {\n colors: z.optional(ColorsPatch),\n});\nexport type DesignSystemPatch = z.infer<typeof DesignSystemPatchSchema>;\n\n/**\n * Stable URL of the published JSON Schema. Resolves once `@getvitops/generator` is on\n * npm (unpkg serves the packaged `schema.json`); `vitops init` stamps this into a\n * scaffolded config's `$schema` so editors light up autocomplete + validation.\n */\nexport const SCHEMA_URL = 'https://unpkg.com/@getvitops/generator/schema.json';\n\n/**\n * What `vitops init` actually stamps into a scaffolded config's `$schema`.\n *\n * A **local** path, following wrangler's `node_modules/wrangler/config-schema.json`.\n * `SCHEMA_URL` has no version in it, so unpkg resolves it to whatever is newest\n * — an editor validating a project pinned to generator 2.x silently checks it\n * against the 3.x schema, reporting errors for valid config and accepting\n * fields that do not exist yet. The installed copy is by definition the one\n * that matches the toolchain doing the building.\n *\n * `SCHEMA_URL` remains the schema's `$id`, which is what it is for.\n */\nexport const SCHEMA_LOCAL_PATH = './node_modules/@getvitops/generator/schema.json';\n\n/** The published JSON Schema (draft-2020-12), derived from the zod schema. */\nexport const jsonSchema = {\n $id: SCHEMA_URL,\n ...z.toJSONSchema(DesignSystemSchema, { target: 'draft-2020-12' }),\n};\n\n/** Split a CSS value on top-level commas, ignoring commas nested in `rgba(…)` etc. */\nconst splitLayers = (value: string): string[] => {\n const out: string[] = [];\n let depth = 0;\n let start = 0;\n for (let i = 0; i < value.length; i++) {\n const c = value[i];\n if (c === '(') depth++;\n else if (c === ')') depth--;\n else if (c === ',' && depth === 0) {\n out.push(value.slice(start, i));\n start = i + 1;\n }\n }\n out.push(value.slice(start));\n return out.map((s) => s.trim()).filter(Boolean);\n};\n\nconst LENGTH = /^[+-]?(\\d+\\.?\\d*|\\.\\d+)(px|rem|em|ch|ex|vh|vw|vmin|vmax|cm|mm|in|pt|pc|q)?$/i;\n\n/**\n * Why a shadow can be *valid CSS* and still render nothing: a `--shadow-<name>`\n * token is consumed both as a `box-shadow` (pattern geometry) and inside\n * `filter: drop-shadow(…)` (the `.drop-shadow-<name>` utilities, the `shadow:`\n * state shortcut). `drop-shadow()` accepts a *single* layer of at most three\n * lengths and no `inset` — a spread radius, a second comma-separated layer or an\n * inset keyword makes the function invalid, which drops the entire `filter`\n * declaration. `box-shadow` accepts all three happily, so the value looks fine\n * everywhere it is authored and only the utility silently goes blank.\n */\nconst dropShadowIssue = (value: string): string | undefined => {\n const layers = splitLayers(value);\n if (layers.length > 1) return `${layers.length} comma-separated layers`;\n const layer = layers[0] ?? '';\n if (/(^|\\s)inset(\\s|$)/i.test(layer)) return 'an `inset` keyword';\n // Drop function calls (`rgb(0 0 0 / .5)`, `color-mix(…)`) so their numbers\n // aren't miscounted as lengths, then count what's left.\n const lengths = layer\n .replaceAll(/[\\w-]*\\([^()]*\\)/g, ' ')\n .split(/\\s+/)\n .filter((t) => LENGTH.test(t));\n if (lengths.length > 3) return `a spread radius (${lengths.length} lengths)`;\n return undefined;\n};\n\nexport type ValidationResult =\n | { ok: true; data: DesignSystem; errors: []; warnings: string[] }\n | { ok: false; data: undefined; errors: z.core.$ZodIssue[]; warnings: string[] };\n\nconst RAMP_KEYS = new Set(['seed', 'anchors', 'tones']);\n\n/**\n * Replace the bare \"Invalid input\" a failed union produces with the reason.\n *\n * `Ramp` is `SeededRamp | FixedRamp`, and both branches are closed — so `{ seed,\n * tones }` or a stray key fails *both* and zod reports only that the union didn't\n * match. That message sends you reading the schema rather than looking at the two\n * keys in front of you, and the config that produced it is one whose `tones` were\n * being silently discarded at generate time.\n */\nconst explainRamp =\n (input: unknown) =>\n (issue: z.core.$ZodIssue): z.core.$ZodIssue => {\n // A closed object reports the offending keys on the issue but renders them as\n // a bare \"Invalid input\", which names the parent and not the typo.\n if (issue.code === 'unrecognized_keys') {\n const keys = (issue as { keys?: string[] }).keys ?? [];\n if (keys.length)\n return {\n ...issue,\n message: `unknown key${keys.length > 1 ? 's' : ''} ${keys.map((k) => `\"${k}\"`).join(', ')} — not part of the schema, so ignored at generate time.`,\n };\n }\n if (issue.path.length !== 3 || issue.path[0] !== 'colors' || issue.path[1] !== 'palette')\n return issue;\n const hue = (input as { colors?: { palette?: Record<string, unknown> } })?.colors?.palette?.[\n String(issue.path[2])\n ];\n if (hue == null || typeof hue !== 'object') return issue;\n const keys = Object.keys(hue);\n const unknown = keys.filter((k) => !RAMP_KEYS.has(k));\n const message =\n 'seed' in hue && 'tones' in hue\n ? 'a hue is either seeded (`seed`, with optional `anchors`) or fixed (`tones`) — not both. ' +\n 'Drop one: with both present the `tones` are ignored at generate time.'\n : unknown.length\n ? `unknown key${unknown.length > 1 ? 's' : ''} ${unknown.map((k) => `\"${k}\"`).join(', ')}. ` +\n 'A hue takes `seed` + optional `anchors`, or `tones`.'\n : keys.length === 0\n ? 'a hue needs `seed` (+ optional `anchors`) or `tones`.'\n : null;\n return message ? { ...issue, message } : issue;\n };\n\n/**\n * Validate an unknown value against the design-system schema.\n *\n * `warnings` are configurations that parse and generate, but produce output that\n * won't behave as authored — currently only the token-namespace collisions the\n * flat `--<prop>-<name>` grammar makes possible.\n */\nexport function validate(input: unknown): ValidationResult {\n const result = z.safeParse(DesignSystemSchema, input);\n if (!result.success)\n return {\n ok: false,\n data: undefined,\n errors: result.error.issues.map(explainRamp(input)),\n warnings: [],\n };\n // Every role must point at a palette hue that exists.\n const { palette, roles } = result.data.colors;\n for (const [role, spec] of Object.entries(roles)) {\n const hue = roleHue(spec as RoleSpec);\n if (palette[hue] == null) {\n return {\n ok: false,\n data: undefined,\n errors: [\n {\n code: 'custom',\n path: ['colors', 'roles', role],\n message: `role \"${role}\" references unknown palette hue \"${hue}\"`,\n } as z.core.$ZodIssue,\n ],\n warnings: [],\n };\n }\n }\n const warnings: string[] = [];\n // Role names are arbitrary — but the shipped component CSS is written against\n // a core set, and references them with no fallback. Omitting one doesn't fail\n // validation (the tokens for the roles you DO define are all emitted fine); it\n // silently strips colour from whichever components depended on it, which is\n // far harder to diagnose than a warning here.\n const missing = REQUIRED_ROLES.filter((r) => roles[r] == null);\n if (missing.length)\n warnings.push(\n `colors.roles is missing ${missing.map((r) => `\"${r}\"`).join(', ')} — ` +\n `the framework's own component CSS references ${missing.length === 1 ? 'it' : 'them'} ` +\n `with no fallback, so those components will render uncoloured. ` +\n `Add any role you like, but keep these defined.`,\n );\n // A radius named after a pattern collides on `--br-<name>`: the radius token and\n // the pattern's own override hook are the same var, so whichever the generator\n // emits last silently wins. Same class of clash as a pattern keyed like its\n // group (see the `tag`/`label` note in AGENTS.md). The pattern hook takes it.\n const radii = Object.keys(result.data.patterns?.radii ?? {});\n const items = new Set(Object.keys(result.data.patterns?.items ?? {}));\n for (const name of radii)\n if (items.has(name))\n warnings.push(\n `patterns.radii.${name} collides with the \"${name}\" pattern on --br-${name}; ` +\n `the pattern's override hook wins — rename the radius`,\n );\n for (const [name, value] of Object.entries(result.data.shadows ?? {})) {\n const issue = dropShadowIssue(value);\n if (issue)\n warnings.push(\n `shadows.${name} carries ${issue}, which \\`filter: drop-shadow()\\` rejects — ` +\n `\\`.drop-shadow-${name}\\` will render no shadow at all (the token still works ` +\n `as a \\`box-shadow\\`). Use one layer of at most three lengths.`,\n );\n }\n // Cross-layer: every `var()` an authored declaration points at must resolve to\n // a token this config emits. Anchored to the namespaces the generator owns —\n // see `token-refs.ts` for why enumerating \"all valid tokens\" would be wrong.\n // These are errors: unlike the warnings above, the output is not merely\n // surprising, it is inert, and it fails silently in the browser.\n const refs = tokenRefIssues(result.data);\n warnings.push(...refs.warnings);\n if (refs.errors.length)\n return {\n ok: false,\n data: undefined,\n errors: refs.errors.map((e) => ({ code: 'custom', ...e }) as z.core.$ZodIssue),\n warnings,\n };\n return { ok: true, data: result.data, errors: [], warnings };\n}\n","/**\n * The top-level configuration schema — the umbrella around a\n * `design-system.json`-compliant `designSystem`.\n *\n * **Three sections, one document.** A config is `{ designSystem, organization,\n * site }`:\n *\n * - `designSystem` — the token set (named themes + which theme/appearance).\n * - `organization` — the company: who it is, where it is, how to reach it, what\n * it sells. Facts that stay true if the site is rebuilt from scratch.\n * - `site` — this published site: locales, domains, environments, SEO,\n * analytics, legal, icons, deployment. Facts about *a* presentation of the\n * organization.\n *\n * The split is not cosmetic. The flat predecessor (`SiteConfig`) held the company\n * and the deployment as peers, so no single noun described it — and the\n * multi-site case was inexpressible. With three sections, several sites can share\n * one `organization` and override only `site`.\n *\n * Authored with `@zod/mini` (same instance the design-system schema uses), so the\n * two compose: `DesignSystemSchema` is embedded as `designSystem.themes.<theme>` and the\n * whole thing serialises to one JSON Schema via `z.toJSONSchema`. Everything a\n * generator needs derives from here: the `Config` type (`z.infer`), the\n * published JSON Schema (`configJsonSchema`), and runtime validation (`validateConfig`).\n *\n * Pure: no YAML/env/fs. `resolveConfig` takes an already-parsed object; a\n * thin loader (reading YAML, injecting `SITE_ENV`) lives outside this module.\n *\n * **This module is also its own package entry**, published as\n * `@getvitops/generator/config` (see `vite.config.ts`'s `pack.entry`) — the\n * `Config` schema, validator and resolvers on their own, importable without\n * pulling in `generate.ts`/`docs.ts`/`legal/`'s `node:fs`/`node:crypto`/\n * lightningcss, which `src/index.ts` (the main entry) also re-exports. This is\n * what makes `Config` bundleable in a Worker — an EmDash plugin's own admin\n * route, or anywhere else — without dragging in code that only ever runs at\n * build time. Keep this module's own import graph clean of those Node\n * builtins; that guarantee is the entire point of it existing separately.\n */\nimport * as z from '@zod/mini';\n// The ad-platform capability table. Imported rather than mirrored: this direction is\n// the allowed one (the generator already depends on utils; utils may never import\n// the generator), and what a platform can do is one fact, not two.\nimport { AD_PLATFORMS } from '@getvitops/utils/ads';\nimport { TRACKED_PARAMS } from '@getvitops/utils/tracking';\nimport {\n AD_PROVIDERS,\n AdPropertySchema,\n AdProviderSchema,\n BIGIN_DATA_CENTERS,\n CRM_PROVIDERS,\n CrmProviderSchema,\n CrmSchema,\n DeploymentSchema,\n IndexNowSchema,\n IndexingSchema,\n LocalizableSchema,\n NotificationsSchema,\n ReviewLocationSchema,\n ReviewsSchema,\n SearchConsoleSchema,\n SearchConsoleSetupSchema,\n SecuritySchema,\n SeoSchema,\n TrackingSchema,\n type AdProvider,\n type CrmProviderConfig,\n} from '@getvitops/config';\nimport { desc, DesignSystemPatchSchema, type DesignSystem } from './schema.ts';\n\n// Re-exported so the generator's public API is unchanged: these moved to `@getvitops/config`.\nexport { AD_PROVIDERS, BIGIN_DATA_CENTERS, CRM_PROVIDERS };\nexport type { AdProvider, CrmProviderConfig };\n\n// ── Primitives ────────────────────────────────────────────────────────────────\n\nconst ImageRefSchema = z.union([\n z.string(),\n z.strictObject({\n src: z.string(),\n alt: z.string(),\n width: z.optional(z.number()),\n height: z.optional(z.number()),\n }),\n]);\n\n// Attribute bags on generated HTML — constrained to serialisable scalars so the\n// exported JSON Schema still offers validation (vs. an opaque `unknown`).\nconst AttrValue = z.union([z.string(), z.number(), z.boolean()]);\nconst AttrsSchema = z.optional(z.record(z.string(), AttrValue));\n\nconst IsoDate = z.string().check(z.regex(/^\\d{4}-\\d{2}-\\d{2}$/)); // YYYY-MM-DD\nconst Iso4217 = z.string().check(z.regex(/^[A-Z]{3}$/)); // currency code\nconst DayOfWeek = z.enum([\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n 'Sunday',\n]);\n\n// ── Design system ───────────────────────────────────────────────────────────────\n// Each `themes` entry is a full `DesignSystem` plus a localised `displayName` and\n// an optional `extends` (another entry's key). Entries are lenient (all top-level\n// fields optional) so an extending entry can be a partial patch; the resolved\n// theme is validated against the full `DesignSystemSchema` by `resolveTheme`.\n\nconst DesignSystemEntry = z.extend(DesignSystemPatchSchema, {\n displayName: desc(\n z.optional(LocalizableSchema),\n 'Human-readable theme name (localisable). The label a theme picker would show — nothing reads it yet, because nothing builds more than one theme (see `themes`).',\n ),\n extends: desc(\n z.optional(z.string()),\n 'Another `themes` key to inherit from; this entry then only supplies what it overrides.',\n ),\n});\n\n/**\n * The design system as a whole: the named themes plus the facts that describe the\n * system rather than any one theme.\n *\n * `themes` is nested rather than being the block itself because the block used to\n * BE the map — every key was a theme name, so there was nowhere to put\n * system-wide metadata without it colliding with a theme of that name.\n *\n * Note the two axes here are independent, and deliberately so. `defaultTheme`\n * picks a *theme* (an authored design system); `defaultColorScheme` picks an\n * *appearance* (light/dark), which every theme already has because the flip is\n * derived from one ramp rather than authored. \"Theme `elegant`, appearance\n * follows the OS\" has to be sayable, and a single union could not express it.\n */\nconst DesignSystemBlock = desc(\n z.strictObject({\n themes: desc(\n z.record(z.string(), DesignSystemEntry),\n 'Named themes. `default` is the base; others may `extends` another and supply a partial patch. Light/dark is NOT a theme — the functional tokens flip per appearance within each one, so `default` already has both. Only the default theme is built today; multi-theme output and a picker are not wired yet.',\n ),\n defaultTheme: desc(\n z.optional(z.string()),\n 'Which `themes` entry to use (convention: \"default\"). Validated against the map; selecting a non-default theme is not wired yet.',\n ),\n defaultColorScheme: desc(\n z.optional(z.enum(['light', 'dark', 'system'])),\n 'Initial appearance. `\"system\"` follows the OS via `prefers-color-scheme` and is what makes `<wc-color-scheme-toggle>`\\'s \"System\" position resolve to anything — it removes the theme attribute, so without this the page falls through to light. It also gives a no-JS page the OS appearance. Defaults to `\"light\"`, because switching an existing site to `\"system\"` visibly flips it dark for dark-OS visitors.',\n ),\n }),\n 'The design system: named themes plus the system-wide facts (which theme, which appearance). A bare design system, or a bare theme map, is accepted as shorthand for `{ themes: … }`.',\n);\n\n// ── Locales ─────────────────────────────────────────────────────────────────────\n\nconst LocaleSchema = z.strictObject({\n name: desc(z.string(), 'Display name of the locale (e.g. \"English\").'),\n tagline: desc(z.optional(z.string()), 'Site tagline in this locale.'),\n basePath: desc(z.optional(z.string()), 'URL prefix for this locale (e.g. \"/fr\").'),\n});\n\n// ── Domains ─────────────────────────────────────────────────────────────────────\n\nconst HttpRedirect = z.union([z.literal(301), z.literal(302), z.literal(307), z.literal(308)]);\n\nconst DomainAliasSchema = z.strictObject({\n domain: z.string(),\n redirectType: HttpRedirect,\n redirectTo: z.string(),\n environment: z.optional(z.string()),\n});\n\n// ── Contact / address (schema.org-aligned) ──────────────────────────────────────\n\nconst PostalAddressSchema = desc(\n z.strictObject({\n streetAddress: z.string(),\n addressLocality: desc(z.string(), 'City.'),\n addressRegion: desc(z.optional(z.string()), 'State / province.'),\n postalCode: z.optional(z.string()),\n addressCountry: desc(z.string(), 'Country (ISO 3166-1 alpha-2 preferred).'),\n }),\n 'schema.org `PostalAddress` field names, so JSON-LD generation is lossless.',\n);\n\nconst ContactObjectSchema = z.strictObject({\n name: z.optional(z.string()),\n email: z.optional(z.email()),\n phone: z.optional(z.string()),\n address: z.optional(PostalAddressSchema),\n});\n\n// contact is either a string (location key reference) or an inline object\nconst ContactConfigSchema = z.union([z.string(), ContactObjectSchema]);\n\nexport type PostalAddress = z.infer<typeof PostalAddressSchema>;\nexport type ContactObject = z.infer<typeof ContactObjectSchema>;\n\n// ── Locations (schema.org LocalBusiness) ────────────────────────────────────────\n\nconst GeoSchema = z.strictObject({\n latitude: z.number().check(z.gte(-90), z.lte(90)),\n longitude: z.number().check(z.gte(-180), z.lte(180)),\n});\n\n/** schema.org `OpeningHoursSpecification` — per-day open/close (24h `HH:MM`). */\nconst OpeningHoursSchema = z.strictObject({\n dayOfWeek: z.array(DayOfWeek),\n opens: z.string().check(z.regex(/^\\d{2}:\\d{2}$/)),\n closes: z.string().check(z.regex(/^\\d{2}:\\d{2}$/)),\n});\n\n/**\n * A dated deviation from the recurring `hours` — holiday hours, a one-off\n * closure, a temporary schedule. Same schema.org shape\n * (`OpeningHoursSpecification`), distinguished by carrying `validFrom`. A\n * full closure omits `opens`/`closes` rather than encoding an open interval.\n */\nconst SpecialHoursSchema = z.strictObject({\n validFrom: IsoDate,\n validThrough: z.optional(IsoDate),\n opens: z.optional(z.string().check(z.regex(/^\\d{2}:\\d{2}$/))),\n closes: z.optional(z.string().check(z.regex(/^\\d{2}:\\d{2}$/))),\n});\n\n// Common schema.org LocalBusiness subtypes (extend as needed).\nconst LocalBusinessType = z.enum([\n 'LocalBusiness',\n 'Store',\n 'Restaurant',\n 'CafeOrCoffeeShop',\n 'ProfessionalService',\n 'MedicalBusiness',\n 'HealthAndBeautyBusiness',\n 'HomeAndConstructionBusiness',\n 'AutomotiveBusiness',\n 'FinancialService',\n 'LegalService',\n 'RealEstateAgent',\n 'Organization',\n]);\n\n// Platforms a location's listing can be pinned against. Mirrors the\n// record-keyed-by-platform shape of `site.searchConsole`/`site.ads`.\nconst ListingPlatform = z.enum(['google', 'bing', 'apple']);\n\nconst LocationSchema = z.strictObject({\n slug: z.optional(LocalizableSchema),\n name: LocalizableSchema,\n email: z.optional(z.email()),\n phone: z.optional(z.string()),\n address: z.optional(PostalAddressSchema),\n geo: z.optional(GeoSchema),\n hours: z.optional(z.array(OpeningHoursSchema)),\n hoursSpecial: desc(\n z.optional(z.array(SpecialHoursSchema)),\n 'Holiday/temporary hours, as dated deviations from the recurring `hours` — distinct from it because these carry a date range rather than a weekday.',\n ),\n type: z.optional(LocalBusinessType),\n description: z.optional(LocalizableSchema),\n areaServed: z.optional(z.array(z.string())),\n priceRange: z.optional(z.string()),\n paymentAccepted: z.optional(z.array(z.string())),\n currenciesAccepted: z.optional(Iso4217),\n knowsLanguage: z.optional(z.array(z.string())),\n photos: desc(\n z.optional(z.array(ImageRefSchema)),\n 'Location photos (logo, storefront, interior, …) → JSON-LD `image`. Every listing platform (GBP, Bing Places, Apple Business Connect) wants these; none can derive them.',\n ),\n sameAs: desc(\n z.optional(z.array(z.url())),\n \"This location's own profile URLs (its Google Business Profile, Bing Places listing, Apple Business Connect location, Facebook page, …) → JSON-LD `sameAs`. Distinct from `organization.sameAs`, which is the company overall — a multi-location org's locations do not share one GBP listing.\",\n ),\n listings: desc(\n z.optional(z.partialRecord(ListingPlatform, z.string())),\n 'External listing IDs for this location, keyed by platform — the Google Business Profile location id, the Bing Places business id, the Apple Business Connect location id. Not consumed by the generator today; recorded here so a future sync has a stable id to match against instead of risking a duplicate listing.',\n ),\n});\n\n// ── Organization (schema.org Organization) ──────────────────────────────────────\n\nconst OrganizationSchema = z.strictObject({\n name: desc(\n z.optional(LocalizableSchema),\n 'Trading name, as a reader would recognise it (e.g. \"Acme\"). Localisable.',\n ),\n legalName: desc(\n z.optional(z.string()),\n 'Registered legal name (e.g. \"Acme Widgets Inc.\"). The generated legal documents prefer this over `name` — a policy is a statement by the legal entity.',\n ),\n foundingDate: desc(z.optional(IsoDate), 'Date the organization was founded (YYYY-MM-DD).'),\n logo: desc(z.optional(ImageRefSchema), 'Organization logo → JSON-LD `logo`.'),\n email: desc(\n z.optional(z.email()),\n 'General contact address. Also the last fallback for privacy requests — see `contact`.',\n ),\n phone: desc(z.optional(z.string()), 'General contact telephone number.'),\n address: desc(\n z.optional(PostalAddressSchema),\n 'Registered/mailing address. Its `addressRegion` and `addressCountry` are what the governing-law clause of the generated terms of service defaults to.',\n ),\n taxID: desc(z.optional(z.string()), 'Tax identification number.'),\n vatID: desc(z.optional(z.string()), 'VAT identification number.'),\n sameAs: desc(z.optional(z.array(z.url())), 'Profile URLs → JSON-LD `sameAs` (mirrors `links`).'),\n});\n\n// ── DNS ──────────────────────────────────────────────────────────────────────\n\nconst DnsRecordType = z.enum(['A', 'AAAA', 'CNAME', 'TXT', 'MX', 'NS', 'SRV', 'CAA', 'PTR', 'SOA']);\n\nconst DnsRecordSchema = z.strictObject({\n type: DnsRecordType,\n name: z.optional(z.string()),\n value: z.string(),\n ttl: z.optional(z.number().check(z.int(), z.positive())),\n proxied: z.optional(z.boolean()),\n});\n\nconst DnsDomainSchema = z.strictObject({\n provider: z.optional(z.string()),\n nameservers: z.optional(z.array(z.string())),\n records: z.optional(z.array(DnsRecordSchema)),\n});\n\n// ── Environments ──────────────────────────────────────────────────────────────\n\nconst RobotsSchema = z.string(); // e.g. \"index,follow\" / \"noindex,nofollow\"\n\nconst EnvironmentSchema = z.strictObject({\n url: desc(z.url(), 'Public origin of this environment.'),\n api: desc(z.optional(z.url()), 'API origin, when different from `url`.'),\n analytics: desc(z.optional(z.boolean()), 'Whether analytics fire in this environment.'),\n ads: desc(\n z.optional(z.boolean()),\n 'Whether `site.ads` pixels fire in this environment. Defaults to `analytics`, then true — a preview deployment sending pageviews is survivable, one firing conversion pixels is not, so this can be turned off on its own.',\n ),\n robots: desc(z.optional(RobotsSchema), 'Robots policy (e.g. \"noindex,nofollow\" for dev).'),\n variant: desc(z.optional(z.string()), 'Active `abTesting.variants` key for this environment.'),\n});\n\n// ── A/B testing ─────────────────────────────────────────────────────────────────\n\nconst AbVariantSchema = z.strictObject({\n environment: z.string(),\n description: z.optional(z.string()),\n // Deliberate escape hatch: overrides are deep-merged into the raw config\n // before validation, so their shape is the config's own.\n overrides: z.optional(z.record(z.string(), z.unknown())),\n});\n\n/**\n * A runtime, per-visitor content experiment — deliberately separate from\n * `abTesting.variants` above, which targets a whole build/environment via\n * `overrides`. This is the opposite granularity: one page, cookie-pinned per\n * visitor, with the two variants written directly in the page itself (no\n * config-schema representation of \"the content\"). `site.experiments` is a\n * record so running more than one experiment on different pages at once is\n * just another key — nothing here assumes only one is active.\n */\nconst ExperimentSchema = z.strictObject({\n enabled: z.boolean(),\n category: desc(\n z.optional(z.enum(['analytics', 'marketing'])),\n \"Consent category this experiment's assignment cookie waits on (default `analytics`) — independent of `site.tracking.category`, so an experiment never piggybacks on ad-attribution consent.\",\n ),\n cookieName: desc(z.optional(z.string()), 'Default `_ab_<experiment key>`.'),\n cookieMaxAge: desc(z.optional(z.number().check(z.int(), z.positive())), 'Seconds.'),\n splitRatio: desc(\n z.optional(z.number().check(z.gte(0), z.lte(1))),\n 'Fraction of new visitors auto-assigned to `variants[1]` (default 0.5). 0 means nobody is auto-assigned — a manually or query-param-set cookie still pins a visitor to `variants[1]`, which is what makes 0 a real blue/green-preview mode rather than a no-op.',\n ),\n variants: desc(\n z.tuple([z.string(), z.string()]),\n 'Exactly two variant names, e.g. [\"control\", \"new-form\"]. `variants[0]` is the default a visitor with no assignment yet effectively sees.',\n ),\n});\n\n// ── Fonts (Astro Fonts API projection) ──────────────────────────────────────────\n// Font *loading* — a serialisable projection of Astro's `fonts:[…]` config. A\n// loader maps `provider` (string) → `fontProviders.<name>()`. Distinct from the\n// design-system font *tokens* (`designSystem.themes.<theme>.fonts` / typography.families),\n// which reference the same `cssVariable`.\n\nconst FontProvider = z.enum([\n 'google',\n 'fontsource',\n 'adobe',\n 'bunny',\n 'fontshare',\n 'googleicons',\n 'npm',\n 'local',\n]);\nconst FontStyle = z.enum(['normal', 'italic']);\nconst FontDisplay = z.enum(['auto', 'block', 'swap', 'fallback', 'optional']);\nconst FontWeight = z.union([z.number(), z.string()]); // discrete, or a variable range like \"100 900\"\n\n/** A local-font face (`provider: 'local'`). */\nconst FontVariantSchema = z.strictObject({\n src: z.array(z.string()),\n weight: z.optional(FontWeight),\n style: z.optional(FontStyle),\n unicodeRange: z.optional(z.array(z.string())),\n display: z.optional(FontDisplay),\n});\n\nexport const SiteFontSchema = z.strictObject({\n name: z.string(),\n provider: FontProvider,\n cssVariable: z.string().check(z.regex(/^--/)),\n weights: z.optional(z.array(FontWeight)),\n styles: z.optional(z.array(FontStyle)),\n subsets: z.optional(z.array(z.string())),\n fallbacks: z.optional(z.array(z.string())),\n optimizedFallbacks: z.optional(z.boolean()),\n display: z.optional(FontDisplay),\n formats: z.optional(z.array(z.string())),\n unicodeRange: z.optional(z.array(z.string())),\n variants: z.optional(z.array(FontVariantSchema)), // local provider\n preload: desc(\n z.optional(\n z.union([\n z.boolean(),\n z.array(z.strictObject({ weight: FontWeight, style: z.optional(FontStyle) })),\n ]),\n ),\n 'Emit `<Font preload />` for this family (true, or a list of weight/style faces).',\n ),\n});\n\n// ── Templates (nav / form / nodes) ──────────────────────────────────────────────\n\nconst PresentSchema = z.optional(z.record(z.string(), z.unknown()));\n\nconst NavItemSchema: z.ZodMiniType = z.strictObject({\n label: z.optional(LocalizableSchema),\n image: z.optional(ImageRefSchema),\n href: z.optional(z.string()),\n icon: z.optional(z.string()),\n attrs: AttrsSchema,\n itemAttrs: AttrsSchema,\n submenu: z.optional(\n z.strictObject({\n present: PresentSchema,\n get items() {\n return z.optional(z.array(NavItemSchema));\n },\n }),\n ),\n});\n\nconst FormFieldType = z.enum([\n 'text',\n 'email',\n 'tel',\n 'url',\n 'number',\n 'password',\n 'textarea',\n 'select',\n 'checkbox',\n 'radio',\n 'date',\n 'file',\n 'hidden',\n]);\n\nconst FormFieldSchema = z.strictObject({\n name: z.string(),\n type: FormFieldType,\n label: z.optional(LocalizableSchema),\n required: z.optional(z.boolean()),\n validation: z.optional(z.string()), // regex source or named rule\n options: z.optional(\n z.union([z.string(), z.array(z.strictObject({ label: z.string(), value: z.string() }))]),\n ),\n attrs: AttrsSchema,\n});\n\nconst ContentNodeSchema: z.ZodMiniType = z.strictObject({\n tag: z.string(),\n attrs: AttrsSchema,\n text: z.optional(z.string()),\n get children() {\n return z.optional(z.array(ContentNodeSchema));\n },\n});\n\nconst TemplateSchema = z.union([\n z.strictObject({\n type: z.literal('nav'),\n tags: z.optional(z.array(z.string())),\n present: PresentSchema,\n items: z.optional(z.array(NavItemSchema)),\n }),\n z.strictObject({\n type: z.literal('form'),\n tags: z.optional(z.array(z.string())),\n present: PresentSchema,\n action: z.optional(z.string()),\n method: z.optional(z.enum(['get', 'post'])),\n fields: z.optional(z.array(FormFieldSchema)),\n submit: z.optional(z.record(z.string(), AttrValue)),\n honeypot: z.optional(z.boolean()),\n }),\n z.strictObject({\n type: z.literal('nodes'),\n tags: z.optional(z.array(z.string())),\n nodes: z.optional(z.array(ContentNodeSchema)),\n }),\n]);\n\n// ── Galleries / testimonials ────────────────────────────────────────────────────\n\nconst GalleryImageSchema = z.strictObject({\n src: z.string(),\n alt: LocalizableSchema,\n caption: z.optional(LocalizableSchema),\n});\n\nconst GallerySchema = z.strictObject({\n title: z.optional(LocalizableSchema),\n tags: z.optional(z.array(z.string())),\n images: z.array(GalleryImageSchema),\n});\n\nconst TestimonialItemSchema = z.strictObject({\n quote: LocalizableSchema,\n name: z.string(),\n role: z.optional(z.string()),\n rating: z.optional(z.number().check(z.gte(0), z.lte(5))),\n date: z.optional(IsoDate),\n});\n\nconst TestimonialGroupSchema = z.strictObject({\n title: z.optional(LocalizableSchema),\n items: z.array(TestimonialItemSchema),\n});\n\n// ── Services (schema.org Offer) ─────────────────────────────────────────────────\n\nconst OfferSchema = z.strictObject({\n name: z.optional(LocalizableSchema),\n price: z.optional(z.union([z.string(), z.number()])),\n priceCurrency: z.optional(Iso4217),\n availability: z.optional(z.string()),\n url: z.optional(z.url()),\n validFrom: z.optional(IsoDate),\n priceValidUntil: z.optional(IsoDate),\n});\n\nconst ServiceSchema = z.strictObject({\n name: LocalizableSchema,\n description: z.optional(LocalizableSchema),\n slug: z.optional(LocalizableSchema),\n offers: z.optional(z.array(OfferSchema)),\n});\n\n// ── SEO / social ─────────────────────────────────────────────────────────────\n\n// ── Indexing ────────────────────────────────────────────────────────────────────\n\n// ── Ad properties ───────────────────────────────────────────────────────────────\n\n// ── Reviews ─────────────────────────────────────────────────────────────────────\n\n// ── Plans & entitlements ───────────────────────────────────────────────────────\n\n/**\n * The commercial plan/add-on a site is entitled to — distinct from a `Config`\n * section's own `enabled` flag. `enabled` answers \"does this site do X at\n * all\" (a capability switch); `plan` answers \"is this client entitled to turn\n * X on\" (a commercial switch one layer above). Absence means unrestricted,\n * matching every other opt-in block in `Config`. `key` is an open string, not\n * a closed enum, so a client-specific plan needs no schema change; `addons`\n * is checked against `PLAN_CAPABILITIES` below. The commercial catalogue\n * itself (plan names, pricing, which add-ons a plan bundles) stays\n * Portal-side — this only records which one a site has.\n */\nconst PlanSchema = z.strictObject({\n key: desc(\n z.string(),\n 'Commercial plan identifier (e.g. \"essentials\", \"growth\") — open string, not a closed enum.',\n ),\n addons: desc(\n z.optional(z.array(z.string())),\n 'Add-on keys this site is entitled to (e.g. \"ab_testing\", \"server_side_tracking\") — checked against PLAN_CAPABILITIES.',\n ),\n});\n\n// ── CRM ─────────────────────────────────────────────────────────────────────────\n\n// ── Legal ───────────────────────────────────────────────────────────────────────\n\n/**\n * Which template set the generated legal documents are written against. This is\n * a closed enum rather than a free string because an unrecognised value would\n * otherwise silently fall back to the wrong body of law; `validateConfig` rejects\n * anything without a registered template. Add a member here and a matching entry\n * in `legal/templates/index.ts` — the two are checked against each other.\n */\nexport const JURISDICTIONS = ['ca'] as const;\nconst JurisdictionSchema = z.enum(JURISDICTIONS);\nexport type Jurisdiction = (typeof JURISDICTIONS)[number];\n\n/**\n * The country each template set frames cross-border transfers as *leaving*.\n *\n * A jurisdiction's own country is not a transfer, so this is what filters the\n * disclosure lists — without it, `country: \"Canada\"` renders the incoherent\n * \"outside of Canada, including Canada\".\n *\n * It belongs to the **jurisdiction**, not to `organization.address`: a `ca` policy\n * says \"outside of Canada\" even for a business incorporated elsewhere. (The\n * address drives a different sentence — the terms' governing-law clause, via\n * `governingCountry`.) `satisfies` makes a new jurisdiction unable to forget it,\n * the same guard style as `TEMPLATES`.\n */\nexport const JURISDICTION_COUNTRIES = {\n ca: 'Canada',\n} satisfies Record<Jurisdiction, string>;\n\n/**\n * A third party that receives personal information. The generator derives the\n * ones it can see (analytics IDs, Turnstile, the deploy platform); this is for\n * the rest, which no other part of the config implies.\n *\n * Deliberately facts, not prose: the config records *what is true*, the template\n * owns *how it is said*. That keeps a policy correct when the wording changes.\n */\nconst ProcessorStorageSchema = z.strictObject({\n country: desc(\n z.string(),\n 'A country or bloc where this provider stores or processes the information, as it should read in a sentence (e.g. \"Canada\", \"the United States\", \"the European Union\"). Naming the jurisdiction the policy is written for is meaningful: it says this information does not leave it.',\n ),\n scope: desc(\n z.optional(z.string()),\n 'Which information is held there, as a noun phrase that reads after \"in the case of\" (e.g. \"account and sign-in information\", \"mailbox contents\"). Omit when this location holds everything the provider receives — a scoped entry claims LESS than an unscoped one, so omitting it is the safe default.',\n ),\n});\n\nconst ProcessorSchema = z.strictObject({\n name: desc(z.string(), 'The provider, as a reader would recognise it (e.g. \"Stripe\").'),\n purpose: desc(\n z.string(),\n 'Why they receive it, as a noun phrase that reads after \"for\" (e.g. \"payment processing\").',\n ),\n country: desc(\n z.optional(z.string()),\n 'Shorthand for the common case where one country is both where they store it and whose laws reach it: asserts BOTH `storage: [{ country }]` AND `operatorCountry`. Reads inside a sentence (e.g. \"the United States\"). When the two differ — a Canadian region operated by a US company — state `storage` and `operatorCountry` instead; setting this alongside either is rejected.',\n ),\n storage: desc(\n z.optional(z.array(ProcessorStorageSchema)),\n 'Where the information actually rests. Feeds the \"stored or processed outside of <jurisdiction>\" disclosure and nothing else. Several entries are allowed, each optionally scoped to a category of information — which is what makes a Canadian-region tenant holding identity data in the US expressible.',\n ),\n operatorCountry: desc(\n z.optional(z.string()),\n 'The jurisdiction that can compel this provider to hand the information over — where it is established, or from which it is controlled. Reads after \"the laws of\" (e.g. \"the United States\"); a bloc is acceptable. A SEPARATE fact from `storage`, because privacy law cares about foreign *access*, not only foreign storage: a Canadian-region service run by a US company is `storage: [{ country: \"Canada\" }]` with `operatorCountry: \"the United States\"`.',\n ),\n privacyUrl: z.optional(z.url()),\n});\n\n// ── The `site` section ──────────────────────────────────────────────────────────\n// This published site: where it lives, what it says, how it is built. Everything\n// here is a fact about a *presentation* of the organization — swap the site and\n// these change while `organization` does not.\n\nconst SiteSectionSchema = z.strictObject({\n defaultLocale: desc(\n z.string(),\n 'The locale used when none is specified; must be a `locales` key.',\n ),\n locales: desc(\n z.record(z.string(), LocaleSchema),\n 'Locales the site is published in, keyed by BCP 47 tag (e.g. \"en\", \"fr\").',\n ),\n domains: desc(\n z.optional(\n z.strictObject({\n canonical: desc(z.url(), 'The canonical origin used for absolute URLs and SEO.'),\n aliases: desc(\n z.optional(z.array(DomainAliasSchema)),\n 'Alias domains and how they redirect to the canonical one.',\n ),\n }),\n ),\n 'Canonical domain + redirecting aliases.',\n ),\n dns: desc(\n z.optional(z.record(z.string(), DnsDomainSchema)),\n 'Desired DNS state per domain (provider, nameservers, records) — declarative reference, not applied automatically.',\n ),\n cloudflare: desc(\n z.optional(z.record(z.string(), z.unknown())),\n 'Deliberate escape hatch for provider-specific Cloudflare settings — out of scope to model here.',\n ),\n google: desc(\n z.optional(\n z.strictObject({\n project: desc(\n z.string(),\n 'Google Cloud project id that API usage is attributed to (quota and billing). One project per site keeps usage separate — Search Console today, Maps and anything else later. Sent as `x-goog-user-project`, which is required when the credential is a *user* one (an ADC login from `gcloud auth application-default login`, or `VITOPS_GOOGLE_*`): those use a shared OAuth client that carries no project of its own. A service-account credential belongs to a project already, so this is not needed for it. The identity must hold `serviceusage.services.use` on the project, and the APIs being called must be enabled there.',\n ),\n }),\n ),\n \"This site's Google Cloud project. Not a secret — the credentials stay in the environment.\",\n ),\n searchConsole: desc(\n z.optional(z.record(z.string(), SearchConsoleSetupSchema)),\n 'Domains to onboard as Google Search Console *domain properties* via `vitops search setup`, keyed by bare hostname (mirrors `dns`). Credentials come from the environment (CLOUDFLARE_API_TOKEN + the Google OAuth vars) — never in this file. Set `google.project` when using a user credential.',\n ),\n environments: desc(\n z.record(z.string(), EnvironmentSchema),\n 'Deploy environments (production, dev, …): URL, API origin, analytics toggle, robots policy, active A/B variant.',\n ),\n plan: desc(\n z.optional(PlanSchema),\n 'Commercial plan/add-on entitlement, gating which capability fields below may be turned on. Absence means unrestricted.',\n ),\n abTesting: desc(\n z.optional(\n z.strictObject({\n enabled: z.boolean(),\n cookieName: z.optional(z.string()),\n cookieMaxAge: desc(z.optional(z.number().check(z.int(), z.positive())), 'Seconds.'),\n splitRatio: desc(\n z.optional(z.number().check(z.gte(0), z.lte(1))),\n 'Fraction of traffic sent to the variant (0–1).',\n ),\n variants: desc(\n z.optional(z.record(z.string(), AbVariantSchema)),\n 'Named variants; each targets an environment and may deep-merge config `overrides`.',\n ),\n }),\n ),\n 'A/B testing: cookie-based split plus named variants whose `overrides` patch the config per environment.',\n ),\n experiments: desc(\n z.optional(z.record(z.string(), ExperimentSchema)),\n 'Runtime, per-visitor content experiments — one config-schema-free page branches on a cookie the vitopsAbTesting() middleware assigns. Distinct from `abTesting`, which merges a whole build/environment variant at resolve time; this instead lets one page (e.g. a real, nav-linked /contact) run a copy test without a second URL or a second deploy. Keyed by an open experiment name so more than one can run at once.',\n ),\n fonts: desc(\n z.optional(z.array(SiteFontSchema)),\n 'Font LOADING (a serialisable projection of the Astro Fonts API: provider, weights, subsets, preload). Font TOKENS live in `designSystem.themes.<theme>.fonts` and reference the same `cssVariable`.',\n ),\n\n tags: desc(\n z.optional(z.record(z.string(), z.unknown())),\n 'Free-form content-tag taxonomy (site-specific; not interpreted by the generator).',\n ),\n postTypes: desc(\n z.optional(z.record(z.string(), z.unknown())),\n 'Free-form content-type definitions (site-specific; not interpreted by the generator).',\n ),\n galleries: desc(\n z.optional(z.record(z.string(), GallerySchema)),\n 'Named image galleries (title, tags, images with localisable alt/caption).',\n ),\n testimonials: desc(\n z.optional(z.record(z.string(), TestimonialGroupSchema)),\n 'Named testimonial groups (quote, name, role, rating, date).',\n ),\n templates: desc(\n z.optional(z.record(z.string(), TemplateSchema)),\n 'Named content templates rendered at SSR time: `nav` (menu trees), `form` (field lists + submit), or `nodes` (raw element trees).',\n ),\n navigation: desc(\n z.optional(\n z.strictObject({\n activeTemplate: desc(\n z.optional(\n z.strictObject({\n default: desc(z.optional(z.string()), 'A `templates` key.'),\n breakpoints: desc(\n z.optional(z.record(z.string(), z.string())),\n 'Breakpoint name → `templates` key overrides.',\n ),\n }),\n ),\n 'Which nav template is active, optionally per breakpoint.',\n ),\n }),\n ),\n 'Site navigation settings (which nav template renders where).',\n ),\n seo: desc(\n z.optional(SeoSchema),\n 'SEO defaults: site name, title/description defaults, robots policy, verification tokens, Open Graph + Twitter cards, and post-deploy indexing notification. Read by `<Seo />`, `vitops robots` and `vitops search notify`.',\n ),\n analytics: desc(\n z.optional(\n z.strictObject({\n googleAnalyticsId: z.optional(z.string()),\n plausibleDomain: z.optional(z.string()),\n googleTagManagerId: z.optional(z.string()),\n clarityId: desc(z.optional(z.string()), 'Microsoft Clarity project ID.'),\n matomo: desc(\n z.optional(\n z.strictObject({\n url: desc(z.string(), 'Instance base URL (self-hosted, or `*.matomo.cloud`).'),\n siteId: desc(z.string(), 'Site ID within that instance.'),\n cookies: desc(\n z.optional(z.boolean()),\n 'Default false — Matomo runs cookieless (`disableCookies`), which is what lets the cookie notice state positively that it sets none.',\n ),\n abVariantDimensions: desc(\n z.optional(z.record(z.string(), z.number())),\n 'Pre-created Matomo custom-dimension index per `site.experiments` key — Matomo requires the dimension to exist in the instance before a value can be pushed for it.',\n ),\n }),\n ),\n 'Matomo instance.',\n ),\n }),\n ),\n 'Analytics provider IDs (gated per environment via `environments.<env>.analytics`). Which provider is set is also what the generated privacy policy and cookie notice disclose — see `legal`.',\n ),\n notifications: desc(\n NotificationsSchema,\n 'Where site notifications (form submissions, tracked calls) are sent. TODO: `sms` and `persist` channels — only `email` is implemented.',\n ),\n tracking: desc(TrackingSchema, 'Ad-click attribution for conversion tracking.'),\n ads: desc(\n z.optional(z.partialRecord(AdProviderSchema, AdPropertySchema)),\n 'Ad properties this site is linked to, keyed by platform. Read by `vitops ads setup` (ensure the DNS verification record), `vitops ads tags` (emit the consent-gated pixel), and the generated cookie notice (disclose what each pixel stores). Credentials never live here — the DNS write uses CLOUDFLARE_API_TOKEN from the environment.',\n ),\n reviews: desc(\n z.optional(ReviewsSchema),\n 'Google Business Profile reviews to cache and display, keyed by `organization.locations`. Read by `vitops reviews`. Credentials never live here — a Google OAuth credential comes from the environment, same as `site.searchConsole`.',\n ),\n crm: desc(\n z.optional(CrmSchema),\n \"Push form submissions into a client CRM (HubSpot, Zoho Bigin, or Jobber) alongside the notification email. Read by `createConversionRoute()`'s `crm` option and `vitops crm check`/`vitops crm setup`. Credentials never live here.\",\n ),\n security: desc(SecuritySchema, 'Security integrations (bot protection).'),\n legal: desc(\n z.optional(\n z.strictObject({\n jurisdiction: desc(\n z.optional(JurisdictionSchema),\n 'Which legal template set the generated documents use. Default `ca`.',\n ),\n privacyPolicy: z.optional(\n z.strictObject({\n enabled: z.boolean(),\n url: z.optional(z.url()),\n lastUpdated: z.optional(IsoDate),\n privacyOfficer: desc(\n z.optional(ContactConfigSchema),\n 'Who privacy requests go to. Falls back to `contact`, then `primaryLocation`.',\n ),\n retention: desc(\n z.optional(z.string()),\n 'How long personal information is kept, in prose (e.g. \"24 months after last contact\").',\n ),\n processors: desc(\n z.optional(z.array(ProcessorSchema)),\n 'Third parties that receive personal information and cannot be inferred from the rest of the config (payment processors, CRMs, mail senders). Known providers implied by `analytics`, `security` and `deployment` are added automatically — list only the rest.',\n ),\n }),\n ),\n termsOfService: z.optional(\n z.strictObject({\n enabled: z.boolean(),\n url: z.optional(z.url()),\n lastUpdated: z.optional(z.nullable(IsoDate)),\n governingLaw: desc(\n z.optional(z.string()),\n 'Governing-law clause, in prose (e.g. \"the Province of Ontario\"). Defaults from the contact address.',\n ),\n }),\n ),\n cookieConsent: z.optional(\n z.strictObject({\n enabled: z.boolean(),\n type: desc(z.optional(z.enum(['opt-in', 'opt-out'])), 'Consent model.'),\n position: z.optional(z.enum(['top', 'bottom', 'center'])),\n categories: z.optional(z.array(z.string())),\n }),\n ),\n }),\n ),\n 'Legal pages: which documents exist, where they live, and the facts the generated prose asserts.',\n ),\n icons: desc(\n z.optional(\n // LOOSE on purpose. The per-set keys below are the sets `iconMap` knows\n // semantically, but the value shape is \"any iconify collection name → a\n // list of icons\", which is open-ended by definition. A closed object\n // silently DROPPED unlisted collections (`icons: { ph: [...] }` vanished\n // in validateConfig with no error) while `generateIconInclude`'s parameter\n // type advertised `[prefix: string]` — so the config validated, the icons\n // never bundled, and the failure only showed as missing glyphs in prod.\n z.looseObject({\n ui: desc(z.optional(z.string()), 'Icon set used for UI chrome (e.g. \"lucide\", \"ph\").'),\n brand: desc(z.optional(z.string()), 'Icon set used for brand marks.'),\n weight: desc(\n z.optional(z.string()),\n 'Weight for suffix-weighted sets like Phosphor (\"regular\" | \"bold\" | \"duotone\" | \"fill\" | \"light\" | \"thin\"). Ignored by sets that split weights across collections, e.g. Font Awesome.',\n ),\n sprite: desc(\n z.optional(z.boolean()),\n 'Emit an SVG sprite (icons.svg) alongside the stylesheet, for consumers that cannot run an icon integration (Bricks/WordPress, EmDash renderers).',\n ),\n semantic: desc(z.optional(z.array(z.string())), 'Named semantic icons to include.'),\n 'fa7-solid': z.optional(z.array(z.string())),\n 'fa7-regular': z.optional(z.array(z.string())),\n 'fa7-light': z.optional(z.array(z.string())),\n 'fa7-thin': z.optional(z.array(z.string())),\n 'fa7-brands': z.optional(z.array(z.string())),\n 'simple-icons': z.optional(z.array(z.string())),\n 'material-symbols': z.optional(z.array(z.string())),\n lucide: z.optional(z.array(z.string())),\n ph: z.optional(z.array(z.string())),\n }),\n ),\n 'Icon sets and the specific icons to bundle from each (keys are iconify collection names).',\n ),\n favicon: desc(\n z.optional(\n z.strictObject({\n source: desc(z.string(), 'Source image (SVG/PNG) the favicon set is generated from.'),\n lowResSource: desc(\n z.optional(z.string()),\n 'Alternate source for small raster sizes (16/32px) when the main source scales down poorly.',\n ),\n name: desc(\n z.optional(z.string()),\n 'App name for the generated web manifest. Setting this AND `themeColor` is what makes the site installable: together they emit `site.webmanifest` (with `display: \"standalone\"`) and link it. Neither alone does anything. A marketing site that does not want a browser offering to install it should leave one of them unset.',\n ),\n themeColor: desc(\n z.optional(z.string()),\n 'Browser UI colour, emitted as `<meta name=\"theme-color\">` on every page — so it applies with or without a manifest. Note it is also half the manifest switch: see `name`.',\n ),\n backgroundColor: desc(\n z.optional(z.string()),\n 'Background composited under the OPAQUE generated icons — `apple-touch-icon.png` and the maskable `icon-mask.png` — which are produced whether or not there is a manifest. Defaults to white, so a dark logo on a transparent source needs this set. It is also the manifest `background_color` when one is emitted, but it is not manifest-only.',\n ),\n }),\n ),\n 'Favicon/PWA asset generation (consumed by `@getvitops/utils` favicon tooling).',\n ),\n deployment: desc(\n DeploymentSchema,\n 'How the site is built and deployed (platform, commands, output directory) — informational for tooling.',\n ),\n});\n\n// ── The `organization` section ──────────────────────────────────────────────────\n// The company itself. `OrganizationSchema` above is the schema.org core; the\n// section adds the things that describe the same entity rather than the site —\n// where it operates, how to reach it, what it sells, where it can be found.\n// Defined here rather than beside `OrganizationSchema` because it references\n// `ServiceSchema`, which is declared further down.\n\nconst OrganizationSectionSchema = z.extend(OrganizationSchema, {\n contact: desc(\n z.optional(ContactConfigSchema),\n 'Primary contact: either a `locations` key (string reference) or an inline name/email/phone/address object.',\n ),\n primaryLocation: desc(\n z.optional(z.string()),\n 'The main `locations` key (for JSON-LD and defaults).',\n ),\n locations: desc(\n z.optional(z.record(z.string(), LocationSchema)),\n 'Physical locations (schema.org LocalBusiness): address, geo, opening hours, service area.',\n ),\n services: desc(\n z.optional(z.record(z.string(), ServiceSchema)),\n 'Services offered (schema.org Service/Offer): name, description, slug, price offers.',\n ),\n links: desc(\n z.optional(\n z.strictObject({\n googleMaps: z.optional(z.url()),\n instagram: z.optional(z.url()),\n facebook: z.optional(z.url()),\n x: z.optional(z.url()),\n linkedin: z.optional(z.url()),\n youtube: z.optional(z.url()),\n github: z.optional(z.url()),\n }),\n ),\n 'Public profile URLs (also feed JSON-LD `sameAs` via `organization.sameAs`).',\n ),\n});\n\n// ── Top-level schema ────────────────────────────────────────────────────────────\n\n/**\n * The `Config` document's own SHAPE version — distinct from `@getvitops/generator`'s\n * package version, which is CSS-release-driven (bumps on every design-system/CSS\n * change) and says nothing about whether `Config`'s shape moved. Bump this constant,\n * and add a new literal to `configVersion`'s union below, only when a future shape\n * change is disruptive enough to warrant a migration note — the same bar the\n * pre-3.0 flat-config migration (`MOVED_KEYS`) already set, now with a real field\n * to check instead of pattern-matching which keys are present after the fact.\n * Most releases add optional fields and need no bump at all.\n */\nexport const CONFIG_VERSION = 1;\n\nexport const ConfigSchema = z.strictObject({\n $schema: desc(\n z.optional(z.string()),\n 'URL of the published config JSON Schema (stamped by `vitops init --site`) so editors provide autocomplete + validation.',\n ),\n configVersion: desc(\n z.optional(z.literal(CONFIG_VERSION)),\n 'The config shape version (see `CONFIG_VERSION`) — absent reads as version 1, which is every config validated by this schema so far.',\n ),\n designSystem: DesignSystemBlock,\n organization: desc(\n z.optional(OrganizationSectionSchema),\n 'The company: schema.org Organization details for JSON-LD (name, legalName, logo, tax IDs, sameAs), plus its contact, physical locations, services and public profiles. These stay true across sites — several sites can share one `organization` and differ only in `site`.',\n ),\n site: desc(\n SiteSectionSchema,\n 'This published site: locales, domains, environments, content templates, SEO, analytics, legal documents, icons, favicon and deployment. Facts about a *presentation* of the organization rather than the organization itself.',\n ),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n/** The `organization` section — the company, independent of any one site. */\nexport type OrganizationConfig = z.infer<typeof OrganizationSectionSchema>;\n/** The `site` section — one published presentation of the organization. */\nexport type SiteSection = z.infer<typeof SiteSectionSchema>;\n/** One `fonts[]` entry — a serialisable projection of an Astro Fonts API family. */\nexport type SiteFont = z.infer<typeof SiteFontSchema>;\n/** The `seo.indexing` block — what `vitops search notify` reads. */\nexport type SiteIndexing = z.infer<typeof IndexingSchema>;\n/** IndexNow submission settings. The `key` is public by design. */\nexport type SiteIndexNow = z.infer<typeof IndexNowSchema>;\n/** Google Search Console property settings. The credential is never in the config. */\nexport type SiteSearchConsole = z.infer<typeof SearchConsoleSchema>;\n/** One `site.searchConsole` entry — a domain to onboard via `vitops search setup`. */\nexport type SiteSearchConsoleSetup = z.infer<typeof SearchConsoleSetupSchema>;\n/** One `site.ads` entry — an ad property to link via `vitops ads setup`. */\nexport type SiteAdProperty = z.infer<typeof AdPropertySchema>;\n/** The `site.reviews` block — what `vitops reviews` reads. */\nexport type SiteReviews = z.infer<typeof ReviewsSchema>;\n/** One `site.reviews.locations` entry. */\nexport type SiteReviewLocation = z.infer<typeof ReviewLocationSchema>;\nexport type SitePlan = z.infer<typeof PlanSchema>;\nexport type SiteExperiment = z.infer<typeof ExperimentSchema>;\n\n// ── JSON Schema + validation ────────────────────────────────────────────────────\n\nexport const CONFIG_SCHEMA_URL = 'https://unpkg.com/@getvitops/generator/config.schema.json';\n\n/** The installed copy, not the unpinned unpkg URL — see `SCHEMA_LOCAL_PATH`'s twin. */\nexport const CONFIG_SCHEMA_LOCAL_PATH = './node_modules/@getvitops/generator/config.schema.json';\n\n/** The published JSON Schema (draft-2020-12), derived from the zod schema. */\nexport const configJsonSchema = {\n $id: CONFIG_SCHEMA_URL,\n ...z.toJSONSchema(ConfigSchema, { target: 'draft-2020-12' }),\n};\n\nexport type ConfigValidationResult =\n | { ok: true; data: Config; errors: [] }\n | { ok: false; data: undefined; errors: z.core.$ZodIssue[] };\n\ntype Issue = z.core.$ZodIssue;\nconst issue = (path: (string | number)[], message: string): Issue =>\n ({ code: 'custom', path, message }) as Issue;\n\n/**\n * One entry per add-on key `site.plan.addons` can name: `label` is the human\n * name used in the validation error, `gates` answers whether the config\n * actually has the gated feature turned on. Kept beside `Config`/`validateConfig`\n * (not in `shared.ts`, despite that file's own small-lookup-table pattern —\n * `shared.ts` exists specifically to let `generate.ts` and `docs.ts` share data\n * without one importing the other, and neither of those needs this table;\n * `CRM_PROVIDER_BLOCKS` below is the closer precedent for \"small map local to\n * `validateConfig`'s own concerns\").\n *\n * `bookkeeping`/`support`/`software_licenses` — the Portal's other `feature_key`\n * values — intentionally have no entry here: they're pure Portal/billing\n * features with no `Config` counterpart, not a gap to fill in later.\n */\nexport interface PlanCapability {\n label: string;\n gates: (cfg: Config) => boolean;\n}\nexport const PLAN_CAPABILITIES: Record<string, PlanCapability> = {\n ab_testing: {\n label: 'A/B testing',\n gates: (cfg) =>\n !!cfg.site.abTesting?.enabled ||\n Object.values(cfg.site.environments).some((e) => e.variant != null) ||\n // `site.experiments` (runtime, per-visitor — see ExperimentSchema) is a\n // separate mechanism from `abTesting` (build-time, whole-config\n // variants), added after this gate was first written, and was missed\n // here until found during downstream adoption planning: a site could\n // turn on a runtime experiment with no `ab_testing` add-on and this\n // check wouldn't catch it. Both mechanisms answer the same commercial\n // question — \"is this site entitled to run an A/B test\" — so both gate\n // the same add-on.\n Object.values(cfg.site.experiments ?? {}).some((e) => e.enabled),\n },\n server_side_tracking: {\n label: 'server-side conversion tracking',\n gates: (cfg) => !!cfg.site.tracking?.enabled,\n },\n};\n\n// ── Migration from the flat `SiteConfig` ────────────────────────────────────────\n\n/**\n * Where each key of the old flat config now lives.\n *\n * This exists so the restructure fails with a sentence a reader can act on. Zod\n * reports a flat config as a dozen separate `unrecognized_keys` issues plus a\n * missing required `site` — an accurate description of the document that teaches\n * nobody where anything went. Checked first, and it short-circuits: once we know\n * the document is the old shape, every other error is downstream noise.\n */\nconst MOVED_KEYS: Record<string, 'site' | 'organization'> = {\n defaultLocale: 'site',\n locales: 'site',\n domains: 'site',\n dns: 'site',\n cloudflare: 'site',\n environments: 'site',\n abTesting: 'site',\n fonts: 'site',\n tags: 'site',\n postTypes: 'site',\n galleries: 'site',\n testimonials: 'site',\n templates: 'site',\n navigation: 'site',\n seo: 'site',\n analytics: 'site',\n notifications: 'site',\n tracking: 'site',\n security: 'site',\n legal: 'site',\n icons: 'site',\n favicon: 'site',\n deployment: 'site',\n contact: 'organization',\n primaryLocation: 'organization',\n locations: 'organization',\n services: 'organization',\n links: 'organization',\n};\n\n/**\n * Detect the pre-3.0 flat shape and name the moves.\n *\n * Keyed on a moved key sitting at the ROOT, not on the absence of `site` — a\n * config that simply forgot `site` should get the ordinary \"required\" error, and\n * a partially-migrated one (some keys moved, some not) is exactly the case worth\n * catching loudly.\n */\nfunction migrationIssues(raw: unknown): Issue[] {\n if (typeof raw !== 'object' || raw == null || Array.isArray(raw)) return [];\n const found = Object.keys(raw).filter((k) => k in MOVED_KEYS);\n if (found.length === 0) return [];\n const moves = found.map((k) => ` ${k} → ${MOVED_KEYS[k]}.${k}`).join('\\n');\n return [\n issue(\n [],\n 'this is the pre-3.0 flat site config. The top level is now three sections — ' +\n '`designSystem`, `organization`, `site` — and these keys moved:\\n' +\n `${moves}\\n` +\n '`designSystem` and the fields already under `organization` stay where they are.',\n ),\n ];\n}\n\n/**\n * `unrecognized_keys` reports the offending keys structurally (`issue.keys`)\n * but zod's default message is a bare \"Invalid input\" — the same gap\n * `schema.ts`'s `explainRamp` works around for the design-system schema.\n * Config hits this on every keyed-record field (`site.ads`, `site.crm`'s\n * `fieldMap`, …), so it's a general post-processing step here rather than a\n * one-off. Not the same helper as `explainRamp`'s: that one also claims the\n * key was \"ignored at generate time\", which is true for a loose object's\n * silently-dropped extras but wrong here — a `partialRecord`'s key schema\n * (e.g. `AdProviderSchema`) genuinely rejects the config rather than\n * dropping the field, so this says \"rejected\", not \"ignored\".\n */\nconst explainUnrecognizedKeys = (issue: Issue): Issue => {\n if (issue.code !== 'unrecognized_keys') return issue;\n const keys = (issue as { keys?: string[] }).keys ?? [];\n if (!keys.length) return issue;\n return {\n ...issue,\n message: `unknown key${keys.length > 1 ? 's' : ''} ${keys.map((k) => `\"${k}\"`).join(', ')} — not part of the schema, rejected.`,\n };\n};\n\n/**\n * Validate a raw (already parsed) config: shape via zod, then the cross-field\n * integrity that JSON Schema can't express (referential keys, extends acyclicity).\n * These live only here — the published JSON Schema enforces shape, not integrity.\n */\nexport function validateConfig(input: unknown): ConfigValidationResult {\n const migration = migrationIssues(input);\n if (migration.length) return { ok: false, data: undefined, errors: migration };\n\n const parsed = z.safeParse(ConfigSchema, input);\n if (!parsed.success)\n return {\n ok: false,\n data: undefined,\n errors: parsed.error.issues.map(explainUnrecognizedKeys),\n };\n const cfg = parsed.data;\n const site = cfg.site;\n const org = cfg.organization;\n const errors: Issue[] = [];\n const has = (m: Record<string, unknown> | undefined, k: string) => !!m && k in m;\n\n if (!has(site.locales, site.defaultLocale))\n errors.push(\n issue(['site', 'defaultLocale'], `defaultLocale \"${site.defaultLocale}\" is not in locales`),\n );\n\n const themes = cfg.designSystem?.themes ?? {};\n const defaultTheme = cfg.designSystem?.defaultTheme;\n\n if (!has(themes, 'default') && defaultTheme == null)\n errors.push(issue(['designSystem', 'themes'], 'themes must include a \"default\" entry'));\n\n if (defaultTheme != null && !has(themes, defaultTheme))\n errors.push(\n issue(\n ['designSystem', 'defaultTheme'],\n `defaultTheme \"${defaultTheme}\" is not in designSystem.themes`,\n ),\n );\n\n for (const [key, entry] of Object.entries(themes)) {\n if (entry.extends != null && !has(themes, entry.extends))\n errors.push(\n issue(\n ['designSystem', 'themes', key, 'extends'],\n `extends \"${entry.extends}\" is not a themes key`,\n ),\n );\n }\n // extends acyclicity + each resolved theme is a complete DesignSystem\n for (const key of Object.keys(themes)) {\n try {\n resolveTheme(themes as Record<string, DesignSystemEntryT>, key);\n } catch (e) {\n errors.push(issue(['designSystem', 'themes', key], (e as Error).message));\n }\n }\n\n if (org?.primaryLocation != null && !has(org.locations, org.primaryLocation))\n errors.push(\n issue(\n ['organization', 'primaryLocation'],\n `primaryLocation \"${org.primaryLocation}\" is not in organization.locations`,\n ),\n );\n if (typeof org?.contact === 'string' && !has(org.locations, org.contact))\n errors.push(\n issue(\n ['organization', 'contact'],\n `contact \"${org.contact}\" is not an organization.locations key`,\n ),\n );\n\n for (const [name, v] of Object.entries(site.abTesting?.variants ?? {}))\n if (!has(site.environments, v.environment))\n errors.push(\n issue(\n ['site', 'abTesting', 'variants', name, 'environment'],\n `environment \"${v.environment}\" is not in site.environments`,\n ),\n );\n for (const [i, a] of (site.domains?.aliases ?? []).entries())\n if (a.environment != null && !has(site.environments, a.environment))\n errors.push(\n issue(\n ['site', 'domains', 'aliases', i, 'environment'],\n `environment \"${a.environment}\" is not in site.environments`,\n ),\n );\n\n const templates = site.templates;\n const at = site.navigation?.activeTemplate;\n if (at?.default != null && !has(templates, at.default))\n errors.push(\n issue(\n ['site', 'navigation', 'activeTemplate', 'default'],\n `template \"${at.default}\" is not in site.templates`,\n ),\n );\n for (const [bp, tpl] of Object.entries(at?.breakpoints ?? {}))\n if (!has(templates, tpl))\n errors.push(\n issue(\n ['site', 'navigation', 'activeTemplate', 'breakpoints', bp],\n `template \"${tpl}\" is not in site.templates`,\n ),\n );\n\n // Legal. An enabled document is a promise to publish a specific, correct\n // sentence — so the inputs those sentences interpolate are required here\n // rather than allowed to render as a blank. `jurisdiction` needs no check:\n // the enum rejects an unregistered value at parse time.\n const privacy = site.legal?.privacyPolicy;\n /**\n * `country` is shorthand for BOTH `storage` and `operatorCountry`, so combining it\n * with either is genuinely ambiguous — is the shorthand narrowing the explicit\n * fact, or adding to it? Both readings are plausible and they make *contradictory\n * legal claims*, so this is rejected rather than resolved by a silent rule.\n *\n * Checked unconditionally, not gated on `privacy.enabled`: the fact is wrong\n * either way, and a document turned on later shouldn't surface it for the first\n * time. Here rather than as a `z.refine` on the schema because parse-time\n * rejection would make `resolveConfig` throw on the `vitops legal` path, which\n * has no formatting for a zod issue — `validateConfig` is where every other\n * cross-field legal requirement already lives, and it prints `path: message`.\n */\n for (const [i, p] of (privacy?.processors ?? []).entries())\n if (p.country != null && (p.storage != null || p.operatorCountry != null))\n errors.push(\n issue(\n ['site', 'legal', 'privacyPolicy', 'processors', i, 'country'],\n `processor \"${p.name}\": \\`country\\` is shorthand for BOTH \\`storage\\` and \\`operatorCountry\\`, so combining it with either makes the narrower claim ambiguous — drop \\`country\\` and state the two facts, or drop the two and keep the shorthand`,\n ),\n );\n if (typeof privacy?.privacyOfficer === 'string' && !has(org?.locations, privacy.privacyOfficer))\n errors.push(\n issue(\n ['site', 'legal', 'privacyPolicy', 'privacyOfficer'],\n `privacyOfficer \"${privacy.privacyOfficer}\" is not an organization.locations key`,\n ),\n );\n if (privacy?.enabled) {\n if (resolvePrivacyContact(cfg) == null)\n errors.push(\n issue(\n ['site', 'legal', 'privacyPolicy'],\n 'privacyPolicy.enabled requires a contact for privacy requests — set site.legal.privacyPolicy.privacyOfficer, organization.contact, or organization.email/address',\n ),\n );\n if (site.domains?.canonical == null)\n errors.push(\n issue(\n ['site', 'legal', 'privacyPolicy'],\n 'privacyPolicy.enabled requires site.domains.canonical — the policy states where information is held',\n ),\n );\n }\n\n // Indexing. Both defaults (the sitemap URL and the IndexNow key location) are\n // built from `domains.canonical`, so without it the block is unresolvable —\n // and the failure would otherwise surface at deploy time, as a submission\n // against `undefined/sitemap-index.xml`, rather than here.\n const indexing = site.seo?.indexing;\n if (indexing != null && site.domains?.canonical == null) {\n if (indexing.sitemapUrl == null)\n errors.push(\n issue(\n ['site', 'seo', 'indexing', 'sitemapUrl'],\n 'site.seo.indexing needs site.domains.canonical to derive the sitemap URL — set one, or state sitemapUrl explicitly',\n ),\n );\n if (indexing.indexNow != null && indexing.indexNow.keyLocation == null)\n errors.push(\n issue(\n ['site', 'seo', 'indexing', 'indexNow', 'keyLocation'],\n 'site.seo.indexing.indexNow needs site.domains.canonical to derive the key location — set one, or state keyLocation explicitly',\n ),\n );\n }\n\n // Ad properties. The capability table decides what is even askable of a platform,\n // so a token set on a platform that has no domain verification is not a harmless\n // extra field — it is a belief about what will happen on the next `ads setup`,\n // and nothing will. Better said here than discovered by the record never being\n // checked by anyone.\n for (const [provider, entry] of Object.entries(site.ads ?? {})) {\n if (entry == null) continue;\n const platform = AD_PLATFORMS[provider as AdProvider];\n const at = ['site', 'ads', provider];\n if (entry.domainVerification != null && platform.verification.method === 'none')\n errors.push(\n issue(\n [...at, 'domainVerification'],\n `${platform.name} has no domain verification — ${platform.verification.reason ?? 'nothing verifies a domain there'}. Remove the token; linking is the tag and the account id.`,\n ),\n );\n if (entry.domainVerification != null && entry.domain == null && site.domains?.canonical == null)\n errors.push(\n issue(\n [...at, 'domain'],\n `site.ads.${provider}.domainVerification needs a domain to put the record on — set site.domains.canonical, or state site.ads.${provider}.domain explicitly`,\n ),\n );\n if (entry.accountId == null && entry.pixelId == null)\n errors.push(\n issue(\n at,\n `site.ads.${provider} identifies nothing — set accountId (the advertising account) and/or pixelId (the tag: ${platform.tag.needs} is what its snippet needs)`,\n ),\n );\n }\n\n // Review locations. Each key must name a real physical location, and one with\n // a Google listing on record — `vitops reviews` has nothing to fetch otherwise,\n // and a key that merely typos an `organization.locations` entry would silently\n // fetch zero reviews rather than error.\n for (const [key, entry] of Object.entries(site.reviews?.locations ?? {})) {\n const at = ['site', 'reviews', 'locations', key];\n if (!has(org?.locations, key))\n errors.push(issue(at, `\"${key}\" is not an organization.locations key`));\n else if (org?.locations?.[key]?.listings?.google == null)\n errors.push(\n issue(\n at,\n `organization.locations.${key} has no listings.google id — record the GBP location id there first`,\n ),\n );\n if (entry.accountId == null && site.reviews?.accountId == null)\n errors.push(\n issue(\n [...at, 'accountId'],\n `no accountId — set site.reviews.accountId or site.reviews.locations.${key}.accountId`,\n ),\n );\n }\n\n // CRM. `provider` decides which block is required — a config naming a\n // provider with no matching block is a config `planCrm` in\n // `@getvitops/utils/crm` would report as off with a reason, but stopping it\n // at validation is louder than discovering it at first submission. One\n // table rather than a hand-written `if` per provider, so a fourth provider\n // added to `CRM_PROVIDERS` with no matching entry here is a type error\n // (`Record<CrmProviderConfig, …>`) instead of a silently unchecked block.\n if (site.crm) {\n const at = ['site', 'crm'];\n const CRM_PROVIDER_BLOCKS: Record<CrmProviderConfig, 'hubspot' | 'bigin' | 'jobber'> = {\n hubspot: 'hubspot',\n bigin: 'bigin',\n jobber: 'jobber',\n };\n const block = CRM_PROVIDER_BLOCKS[site.crm.provider];\n if (site.crm[block] == null)\n errors.push(\n issue(\n [...at, block],\n `site.crm.provider is \"${site.crm.provider}\" but site.crm.${block} is missing`,\n ),\n );\n const knownTrackingKeys = new Set([...TRACKED_PARAMS, 'landingPage', 'referrer', 'ab_variant']);\n for (const key of Object.keys(site.crm.trackingFields ?? {})) {\n if (!knownTrackingKeys.has(key))\n errors.push(\n issue(\n [...at, 'trackingFields', key],\n `\"${key}\" is not a recognised _ac attribution key — a typo'd key silently maps nothing`,\n ),\n );\n }\n }\n\n // Plan entitlement. A gated feature turned on with no matching add-on is\n // rejected here rather than silently allowed — the toolchain enforcement\n // `site.plan` exists for in the first place (see PLAN_CAPABILITIES' docblock).\n for (const [key, cap] of Object.entries(PLAN_CAPABILITIES)) {\n if (cap.gates(cfg) && !(site.plan?.addons ?? []).includes(key))\n errors.push(\n issue(\n ['site', 'plan', 'addons'],\n `${cap.label} is enabled but site.plan doesn't list the \"${key}\" add-on`,\n ),\n );\n }\n\n if (errors.length) return { ok: false, data: undefined, errors };\n return { ok: true, data: cfg, errors: [] };\n}\n\n/**\n * Warning strings for an enabled `site.experiments` entry whose site also\n * configures Matomo but has no matching `abVariantDimensions` index — the\n * Matomo custom-dimension push for that experiment is silently skipped\n * without one, since Matomo requires the dimension to exist in the instance\n * first. A warning, not a `validateConfig` error, the same way\n * `localeConsistencyWarnings` (`@getvitops/astro/i18n.ts`) is: the pageview\n * still ships correctly, just without that one dimension, so this shouldn't\n * block a build — mirrors that function's shape (pure, `[]` when nothing to\n * warn about) rather than adding a `warnings` field to `ConfigValidationResult`.\n */\nexport function experimentDimensionWarnings(\n site:\n | {\n experiments?: Record<string, { enabled: boolean }>;\n analytics?: { matomo?: { abVariantDimensions?: Record<string, number> } };\n }\n | null\n | undefined,\n): string[] {\n if (!site?.experiments || !site.analytics?.matomo) return [];\n const dimensions = site.analytics.matomo.abVariantDimensions ?? {};\n const warnings: string[] = [];\n for (const [key, experiment] of Object.entries(site.experiments)) {\n if (experiment.enabled && dimensions[key] == null)\n warnings.push(\n `experiments.${key}: Matomo is configured but site.analytics.matomo.abVariantDimensions.${key} ` +\n `isn't set — this experiment's variant won't reach Matomo as a custom dimension until you ` +\n `create the dimension in your Matomo instance and record its index here.`,\n );\n }\n return warnings;\n}\n\n/**\n * Resolve who privacy requests go to: the explicit privacy officer, else the\n * organization's contact, else its primary location, else the organization itself.\n *\n * Exported because `validateConfig` and the legal-document derivation must agree\n * on it exactly — a config that validates must be one the policy can render, and\n * two copies of this precedence would drift into a policy with a blank address.\n *\n * Note every candidate but the first now lives in `organization`, and the first\n * (`site.legal.privacyPolicy.privacyOfficer`) still dereferences against\n * `organization.locations` — the officer is a person at the company, named by the\n * site because a company may publish more than one policy.\n */\nexport function resolvePrivacyContact(cfg: Config): ContactObject | undefined {\n const org = cfg.organization;\n // A location's `name` is Localizable and a contact's is a plain string; the\n // name is not used in the rendered address, so drop it rather than pick a locale.\n const deref = (c: string | ContactObject | undefined): ContactObject | undefined => {\n if (c == null) return undefined;\n if (typeof c !== 'string') return c;\n const loc = org?.locations?.[c];\n return loc && { email: loc.email, phone: loc.phone, address: loc.address };\n };\n const candidates = [\n deref(cfg.site.legal?.privacyPolicy?.privacyOfficer),\n deref(org?.contact),\n deref(org?.primaryLocation),\n org && { email: org.email, phone: org.phone, address: org.address },\n ];\n // A contact with no reachable channel is not a contact — skip to the next.\n return candidates.find((c) => c != null && (c.email != null || c.address != null));\n}\n\n// ── Theme resolution (extends) ──────────────────────────────────────────────────\n\ntype DesignSystemEntryT = Partial<DesignSystem> & { displayName?: unknown; extends?: string };\n\n/**\n * Resolve a design-system theme by following its `extends` chain and deep-merging\n * base → child (child wins; arrays replace wholesale, correct for token overrides).\n * Throws on unknown keys or an `extends` cycle. The result is a plain\n * `DesignSystem` (validate it against `DesignSystemSchema` for completeness).\n */\nexport function resolveTheme(\n designSystem: Record<string, DesignSystemEntryT>,\n key: string,\n): DesignSystem {\n const chain: DesignSystemEntryT[] = [];\n const seen = new Set<string>();\n let cur: string | undefined = key;\n while (cur != null) {\n if (seen.has(cur)) throw new Error(`extends cycle in designSystem at \"${cur}\"`);\n seen.add(cur);\n const entry: DesignSystemEntryT | undefined = designSystem[cur];\n if (entry == null) throw new Error(`designSystem theme \"${cur}\" not found`);\n chain.unshift(entry);\n cur = entry.extends;\n }\n const out: Record<string, unknown> = {};\n for (const entry of chain) {\n const { extends: _e, displayName: _d, ...ds } = entry;\n deepMerge(out, ds as Record<string, unknown>);\n }\n return out as DesignSystem;\n}\n\n/**\n * Normalise the two `designSystem` shorthands to the canonical\n * `{ themes: { … } }` shape.\n *\n * Both are keyed off what CANNOT be a theme name in the other reading:\n * - `colors` → a bare `DesignSystem` was written inline.\n * - `themes` → already canonical.\n * - neither → the legacy bare theme map, from before the block gained\n * system-wide fields. Every config authored against the old schema takes this\n * branch, which is what keeps the change forgiving at runtime even though the\n * published JSON Schema moved.\n */\nfunction normaliseDesignSystem(raw: Record<string, unknown>): void {\n const ds = raw.designSystem as Record<string, unknown> | undefined;\n if (ds == null || typeof ds !== 'object') return;\n if ('themes' in ds) return;\n raw.designSystem = 'colors' in ds ? { themes: { default: ds } } : { themes: ds };\n}\n\n/**\n * Resolve a raw (already-parsed) config into a validated `Config`:\n * 1. strip YAML nulls,\n * 2. normalise the `designSystem` shorthands to `{ themes: … }`,\n * 3. apply the active A/B variant's `overrides` (by `siteEnv`),\n * 4. validate (shape + cross-field).\n * Pure — no YAML/env access. A loader supplies `siteEnv`.\n *\n * Steps 2 and 3 are in this order deliberately. Normalising first means an\n * `abTesting` override always addresses the canonical shape\n * (`designSystem.themes.<name>`), whatever shorthand the base config used. With\n * the merge first, an override's key path depended on how the base happened to be\n * written — so the same patch hit a different place in two configs that were\n * otherwise equivalent.\n *\n * The A/B lookup reads `site.environments` / `site.abTesting`, and the overrides\n * still deep-merge at the **root** — a variant patches whichever section it names,\n * which is what lets one target `designSystem` and another `site.seo`.\n */\nexport function resolveConfig(input: unknown, siteEnv = 'production'): Config {\n const raw = stripNulls(input) as Record<string, unknown>;\n\n normaliseDesignSystem(raw);\n\n const site = raw.site as Record<string, unknown> | undefined;\n const envConfig = (site?.environments as Record<string, { variant?: string }> | undefined)?.[\n siteEnv\n ];\n if (envConfig?.variant) {\n const overrides = (\n site?.abTesting as { variants?: Record<string, { overrides?: Record<string, unknown> }> }\n )?.variants?.[envConfig.variant]?.overrides;\n if (overrides) {\n // An override may itself use a shorthand; normalise it to the same shape or\n // deepMerge would nest a bare map under the canonical one.\n normaliseDesignSystem(overrides);\n deepMerge(raw, overrides);\n }\n }\n\n const result = validateConfig(raw);\n if (!result.ok) {\n const msg = result.errors\n .map((e) => ` ${e.path.join('.') || '<root>'}: ${e.message}`)\n .join('\\n');\n throw new Error(`Invalid config:\\n${msg}`);\n }\n return result.data;\n}\n\n// ── Accepting either config kind ────────────────────────────────────────────────\n\n/**\n * Is this raw config a full `Config` rather than a bare `design-system.json`?\n *\n * The discriminator is **total**, not a heuristic, and both halves are load-\n * bearing: `ConfigSchema` cannot validate without a `designSystem` (it is a\n * required key), and `DesignSystemSchema` is strict, so a `designSystem` key in a\n * design system is an `unrecognized_keys` error. No document can be read as both,\n * and no document that is neither reaches here without failing validation anyway.\n *\n * The restructure did not weaken this: `designSystem` stayed at the root\n * precisely so the discriminator kept working unchanged.\n *\n * Deliberately shape-based rather than filename-based: consumers name this file\n * whatever suits them (`company.json`, `site.json`, `vitops.config.json`), and a\n * rule keyed to a name would silently stop working the moment someone renamed it.\n */\nexport function isConfig(raw: unknown): boolean {\n return typeof raw === 'object' && raw != null && !Array.isArray(raw) && 'designSystem' in raw;\n}\n\n/** What a config file turned out to hold. */\nexport interface ResolvedInput {\n /** The design system to build from — a resolved theme, if the input was a full `Config`. */\n designSystem: DesignSystem;\n /** The whole config, when that is what the input was. */\n config?: Config;\n /** Which `themes` key was selected. Absent for a bare `design-system.json`. */\n theme?: string;\n}\n\n/**\n * Resolve a raw config of either kind into the design system to build from.\n *\n * Every entry point that used to take a `design-system.json` goes through this,\n * so a consumer who keeps their tokens inside the larger config points the\n * same option at that file instead of maintaining a second one. The config\n * is handed back too, because the parts of generation that depend on site-level\n * facts (`designSystem.defaultColorScheme`, the legal documents, the icon\n * sprite) would otherwise need the same path declared a second time.\n *\n * The returned `designSystem` is **not** validated here — the caller does that,\n * so it can say which file and which theme the errors belong to. Validation of\n * the config itself has already happened (`resolveConfig` throws).\n */\nexport function resolveInput(\n raw: unknown,\n opts: { theme?: string; siteEnv?: string } = {},\n): ResolvedInput {\n if (!isConfig(raw)) {\n if (opts.theme != null)\n throw new Error(\n `theme \"${opts.theme}\" was requested, but this is a design-system.json — it holds one ` +\n 'design system and no `themes` map. Point at a full config to select a theme.',\n );\n return { designSystem: raw as DesignSystem };\n }\n const config = resolveConfig(raw, opts.siteEnv);\n const themes = (config.designSystem?.themes ?? {}) as Record<string, DesignSystemEntryT>;\n const theme = opts.theme ?? config.designSystem?.defaultTheme ?? 'default';\n if (!(theme in themes))\n throw new Error(\n `designSystem.themes has no \"${theme}\" entry (found: ${Object.keys(themes).join(', ') || 'none'})`,\n );\n return { designSystem: resolveTheme(themes, theme), config, theme };\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────────\n\n/** Strip nulls (YAML `~`/`null`) → undefined so optional fields validate. */\nexport function stripNulls(obj: unknown): unknown {\n if (obj === null) return undefined;\n if (Array.isArray(obj)) return obj.map(stripNulls);\n if (obj && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n const stripped = stripNulls(value);\n if (stripped !== undefined) result[key] = stripped;\n }\n return result;\n }\n return obj;\n}\n\n/** Deep-merge `source` into `target` (in place). Arrays replace wholesale. */\nexport function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>) {\n for (const key of Object.keys(source)) {\n const s = source[key];\n const t = target[key];\n if (\n s &&\n typeof s === 'object' &&\n !Array.isArray(s) &&\n t &&\n typeof t === 'object' &&\n !Array.isArray(t)\n ) {\n deepMerge(t as Record<string, unknown>, s as Record<string, unknown>);\n } else {\n target[key] = s;\n }\n }\n}\n\n// ── Design-system patch write-back ──────────────────────────────────────────\n// Shared by @getvitops/vite's dev-only `/__vitops/design-system` endpoint and\n// the EmDash design-system-editor plugin route (see AGENTS.md's \"live theme\n// editor\" and \"EmDash plugin as the design-system editing surface\" sections)\n// — one place \"patch a config file's design-system subtree\" lives, rather\n// than each consumer inventing its own copy.\n\n/**\n * Where the design system lives inside a config file on disk.\n *\n * `[]` for a `design-system.json` — the file *is* the design system. For a\n * site config it is under `designSystem`, and this reads the **raw** object\n * rather than the resolved one because a write-back has to land where the\n * author actually put it. `resolveConfig` normalises the two shorthands in\n * memory; a writer that assumed the canonical shape would grow a second\n * `themes` key beside the author's bare map and silently stop editing\n * anything.\n */\nexport function designSystemPath(raw: unknown, theme = 'default'): string[] {\n if (!isConfig(raw)) return [];\n const ds = (raw as Record<string, unknown>).designSystem as Record<string, unknown>;\n if (ds != null && typeof ds === 'object') {\n if ('themes' in ds) return ['designSystem', 'themes', theme];\n // A bare `DesignSystem` written inline — one theme, and it is `default`.\n if ('colors' in ds) return ['designSystem'];\n }\n return ['designSystem', theme]; // the legacy bare theme map\n}\n\nexport const getAt = (obj: unknown, path: string[]): unknown =>\n path.reduce<unknown>((cur, k) => (cur as Record<string, unknown>)?.[k], obj);\n\n/** Return a copy of `obj` with `path` replaced by `value`. Creates missing objects. */\nexport function setAt(obj: unknown, path: string[], value: unknown): unknown {\n if (!path.length) return value;\n const [head, ...rest] = path as [string, ...string[]];\n const base = (typeof obj === 'object' && obj !== null ? obj : {}) as Record<string, unknown>;\n return { ...base, [head]: setAt(base[head], rest, value) };\n}\n\n/**\n * Recursively merge a patch into a config, returning a new value rather than\n * mutating either argument. Plain objects merge key-wise; everything else\n * (scalars, and arrays — a token list is replaced, not appended) is\n * overwritten by the patch. Distinct from `deepMerge` above (which mutates\n * `target` in place and requires both sides to already be objects) — this one\n * has to handle `base` being `undefined` (a patch targeting a path that\n * doesn't exist yet) and a patch that is itself a scalar or array.\n */\nexport function mergePatch(base: unknown, patch: unknown): unknown {\n const isPlain = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v);\n if (!isPlain(base) || !isPlain(patch)) return patch;\n const out: Record<string, unknown> = { ...base };\n for (const [k, v] of Object.entries(patch)) out[k] = mergePatch(base[k], v);\n return out;\n}\n\n/** Printed width a rewritten config file is wrapped to — matches the repo formatter's default. */\nconst PRINT_WIDTH = 100;\n\n/**\n * Serialize a config the way a formatter would: 2-space indent, but arrays of\n * scalars kept on one line when they fit.\n *\n * `JSON.stringify(v, null, 2)` explodes every array onto its own lines, so\n * writing back a two-key patch would reflow a whole `design-system.json` — a\n * diff nobody can review, for a change of two values. Matching the\n * prevailing style keeps the write surgical, which is the whole point of\n * saving to source rather than copying a patch by hand.\n */\nexport function formatConfig(value: unknown, col = 0, indent = 0): string {\n const pad = ' '.repeat(indent);\n if (Array.isArray(value)) {\n if (!value.length) return '[]';\n if (value.every((v) => v === null || typeof v !== 'object')) {\n const inline = `[${value.map((v) => JSON.stringify(v)).join(', ')}]`;\n if (col + inline.length <= PRINT_WIDTH) return inline;\n }\n const items = value.map((v) => `${pad} ${formatConfig(v, indent + 2, indent + 2)}`);\n return `[\\n${items.join(',\\n')}\\n${pad}]`;\n }\n if (value !== null && typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>);\n if (!entries.length) return '{}';\n const items = entries.map(([k, v]) => {\n const head = `${pad} ${JSON.stringify(k)}: `;\n return head + formatConfig(v, head.length, indent + 2);\n });\n return `{\\n${items.join(',\\n')}\\n${pad}}`;\n }\n return JSON.stringify(value) ?? 'null';\n}\n"],"mappings":"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"}