@getvitops/generator 4.1.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["providersSection"],"sources":["../src/shared.ts","../src/schema.ts","../src/config.ts","../src/tokens.ts","../src/tiers.ts","../src/docs.ts","../src/design-md.ts","../src/legal/providers.ts","../src/legal/derive.ts","../src/legal/render.ts","../src/legal/templates/shared.ts","../src/legal/templates/cookies.ca.ts","../src/legal/templates/privacy.ca.ts","../src/legal/templates/terms.ca.ts","../src/legal/templates/index.ts","../src/legal/index.ts","../src/icons-sprite.ts","../src/generate.ts","../src/index.ts"],"sourcesContent":["/**\n * Data shared between the generator (`generate.ts`) and the docs bundle\n * (`docs.ts`). Lives in its own module because `generate.ts` imports `docs.ts` —\n * importing back the other way would be a cycle.\n */\n\n/**\n * Selector the dark functional-token flip hangs off.\n *\n * `data-brx-theme` is Bricks' own attribute — Bricks sets it, so it's what the\n * WordPress target needs. Nothing sets it anywhere else, which meant the dark\n * flip was unreachable outside Bricks: the shipped `<wc-color-scheme-toggle>` web\n * component writes `documentElement.dataset.theme` (i.e. `data-theme`), so\n * clicking \"Dark\" changed an attribute no rule matched. Matching both makes the\n * component work on every target without changing what Bricks already does.\n *\n * This covers the EXPLICIT choice. The OS preference is a second, opt-in block —\n * see `SYSTEM_DARK_SEL` — because turning it on flips a site dark for dark-OS\n * users, which is the site's decision rather than the design system's.\n *\n * Shared so the docs quote the selector the generator actually emits.\n */\nexport const DARK_SEL = ':root[data-brx-theme=\"dark\"], :root[data-theme=\"dark\"]';\n\n/**\n * Selector for the OS-preference dark block, emitted inside\n * `@media (prefers-color-scheme: dark)` when a site opts in.\n *\n * Derived from `DARK_SEL`'s attributes rather than written out a third time, and\n * inverted: this must apply when NO explicit choice has been made. That is\n * exactly what `<wc-color-scheme-toggle>`'s \"System\" position produces — it removes\n * `data-theme` entirely — so with this block present System resolves to the OS\n * instead of silently falling through to light, and needs no JS to do it.\n *\n * The `:not()`s are what keep an explicit *light* choice winning over a dark OS.\n */\nexport const SYSTEM_DARK_SEL = `:root${DARK_SEL.split(', ')\n .map((s) => s.replace(/^:root\\[([\\w-]+)=\"dark\"\\]$/, '[$1=\"light\"]'))\n .map((attr) => `:not(${attr})`)\n .join('')}`;\n\n/**\n * Roles the shipped CSS partials reference with NO fallback, so a config that\n * omits one leaves those rules resolving to nothing — an invalid declaration,\n * not a graceful degrade.\n *\n * `colors.roles` is an open record: any name works and generates a full token\n * set, utilities and dark flip. But the framework's own component CSS is\n * written against these six, so \"roles are arbitrary\" is only half true — they\n * are *extensible*, over a required core. `validate()` warns when one is\n * missing; `required-roles.test.ts` re-derives this list from the partials so\n * it cannot drift as components are added.\n *\n * Kept as a constant rather than scanned at call time because `validate()` is\n * a pure function — the CLI, the Vite plugin and `toJSONSchema` all import it,\n * and none of them should touch the filesystem to answer \"is this config ok?\".\n */\nexport const REQUIRED_ROLES: readonly string[] = [\n 'brand-primary',\n 'danger',\n 'neutral',\n 'surface',\n 'ui-primary',\n 'warning',\n];\n\n/**\n * Every token key a role can resolve to, across both role kinds. Shared so the\n * required-roles drift test greps for exactly what the generator emits.\n *\n * These are *keys*, not var names: the role sits in the middle of the property\n * (`--color-bg-danger-muted`), so compose them with `tokenVar()` from `tokens.ts`\n * rather than concatenating by hand.\n */\nexport const ROLE_TOKEN_KEYS: readonly string[] = [\n // backgrounds — surface roles get the bare token and the full range,\n // chromatic roles get tints plus the solid family.\n 'bg',\n 'bg-muted',\n 'bg-x-muted',\n 'bg-bold',\n 'bg-x-bold',\n 'bg-solid',\n 'bg-solid-bold',\n 'bg-solid-x-bold',\n // foregrounds\n 'text',\n 'text-bold',\n 'text-muted',\n 'text-x-muted',\n 'text-xx-muted',\n 'text-on',\n 'text-on-bold',\n // non-text tiers\n 'icon',\n 'icon-muted',\n 'border',\n 'border-muted',\n 'border-bold',\n];\n\n/** How a role is authored in `colors.roles`: a bare hue, or a hue plus its kind. */\n// `kind` admits an explicit `undefined` because the repo runs\n// `exactOptionalPropertyTypes` and the zod-inferred config type spells optionals\n// that way — without it every call site would need a cast.\nexport type RoleSpec = string | { hue: string; kind?: 'surface' | 'chromatic' | undefined };\n\n/** The palette hue a role points at, through either authoring form. */\nexport const roleHue = (spec: RoleSpec): string => (typeof spec === 'string' ? spec : spec.hue);\n\n/**\n * A role's kind. The bare-string shorthand means `chromatic`, because signal\n * colours are the common case and surfaces are the two or three you name once.\n */\nexport const roleKind = (spec: RoleSpec): 'surface' | 'chromatic' =>\n typeof spec === 'string' ? 'chromatic' : (spec.kind ?? 'chromatic');\n\n/**\n * Pattern base geometry props → per-pattern override-hook shorthand. Each hook\n * wraps the authored value (`padding: var(--p-btn, 0.4em 0.8em)`) so a\n * consumer restyles one pattern by setting one variable. The hook is named after\n * the pattern's key, not its class.\n */\nexport const BASE_HOOK: Record<string, string> = {\n padding: 'p',\n 'border-radius': 'br',\n border: 'b',\n 'box-shadow': 'ds',\n 'font-size': 'fs',\n // Both spellings map to `bg`, because patterns author either (`card` uses the\n // shorthand, `status` the longhand). A pattern setting both would map the\n // same var twice — a config error, not something to design around.\n background: 'bg',\n 'background-color': 'bg',\n};\n\n/**\n * Framework utility classes whose names collide with Tailwind's own defaults.\n * The `tailwind` format strips any rule targeting these — Tailwind provides\n * them, so consumers use Tailwind's utilities for these names instead.\n */\nexport const TW_CLASH: ReadonlySet<string> = new Set<string>([\n 'block',\n 'inline',\n 'inline-block',\n 'flow-root',\n 'flex',\n 'inline-flex',\n 'grid',\n 'inline-grid',\n 'table',\n 'inline-table',\n 'table-caption',\n 'table-cell',\n 'table-row',\n 'contents',\n 'hidden',\n 'list-item',\n 'static',\n 'fixed',\n 'absolute',\n 'relative',\n 'sticky',\n 'isolate',\n 'visible',\n 'invisible',\n 'collapse',\n 'sr-only',\n 'not-sr-only',\n 'flex-row',\n 'flex-row-reverse',\n 'flex-col',\n 'flex-col-reverse',\n 'flex-wrap',\n 'flex-nowrap',\n 'items-start',\n 'items-end',\n 'items-center',\n 'items-baseline',\n 'items-stretch',\n 'justify-start',\n 'justify-end',\n 'justify-center',\n 'justify-between',\n 'justify-around',\n 'justify-evenly',\n 'content-start',\n 'content-end',\n 'content-center',\n 'content-between',\n 'content-around',\n 'content-evenly',\n 'text-left',\n 'text-center',\n 'text-right',\n 'text-justify',\n 'text-start',\n 'text-end',\n 'text-wrap',\n 'text-nowrap',\n 'text-balance',\n 'text-pretty',\n]);\n","/**\n * Canonical `design-system.json` schema — the single source of truth.\n *\n * Authored with `zod/mini` (tree-shakeable Zod v4). 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 * as z from 'zod/mini';\nimport { REQUIRED_ROLES, type RoleSpec, roleHue } from './shared.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 const desc = <T extends { check(...checks: never[]): T }>(schema: T, text: string): T =>\n schema.check(z.describe(text) as never);\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/** 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 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 */\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 { desc, DesignSystemPatchSchema, type DesignSystem } from './schema.ts';\n\n// ── Primitives ────────────────────────────────────────────────────────────────\n\nconst LocalizableSchema = desc(\n z.union([z.string(), z.record(z.string(), z.string())]),\n 'A string, or a per-locale map of strings (`{ en: \"…\", fr: \"…\" }`).',\n);\n\nconst ImageRefSchema = z.union([\n z.string(),\n z.object({\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.object({\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.object({\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.object({\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.object({\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.object({\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.object({\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// 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\nconst LocationSchema = z.object({\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 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});\n\n// ── Organization (schema.org Organization) ──────────────────────────────────────\n\nconst OrganizationSchema = z.object({\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.object({\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.object({\n provider: z.optional(z.string()),\n nameservers: z.optional(z.array(z.string())),\n records: z.optional(z.array(DnsRecordSchema)),\n});\n\n/**\n * One domain to onboard into Google Search Console via `vitops search setup`.\n *\n * The verification token is fetched live from the Site Verification API at run\n * time and written to DNS — it is never stored here. What the config records is\n * the *intent*: which domains to onboard, and who should co-own them.\n */\nconst SearchConsoleSetupSchema = z.object({\n delegatedOwners: desc(\n z.optional(z.array(z.email())),\n 'Emails added as verification owners on the Site Verification web resource. Automated via the API — additive and idempotent, never removes an existing owner.',\n ),\n fullUserGroup: desc(\n z.optional(z.email()),\n 'A Google Group to grant Full-User access in Search Console. SURFACED AS A REMINDER only: Search Console exposes no user/permission API, so this step stays manual by design.',\n ),\n});\n\n// ── Environments ──────────────────────────────────────────────────────────────\n\nconst RobotsSchema = z.string(); // e.g. \"index,follow\" / \"noindex,nofollow\"\n\nconst EnvironmentSchema = z.object({\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.object({\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// ── 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.object({\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.object({\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.object({ 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.object({\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.object({\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.object({\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.object({ label: z.string(), value: z.string() }))]),\n ),\n attrs: AttrsSchema,\n});\n\nconst ContentNodeSchema: z.ZodMiniType = z.object({\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.object({\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.object({\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.object({\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.object({\n src: z.string(),\n alt: LocalizableSchema,\n caption: z.optional(LocalizableSchema),\n});\n\nconst GallerySchema = z.object({\n title: z.optional(LocalizableSchema),\n tags: z.optional(z.array(z.string())),\n images: z.array(GalleryImageSchema),\n});\n\nconst TestimonialItemSchema = z.object({\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.object({\n title: z.optional(LocalizableSchema),\n items: z.array(TestimonialItemSchema),\n});\n\n// ── Services (schema.org Offer) ─────────────────────────────────────────────────\n\nconst OfferSchema = z.object({\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.object({\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\nconst OpenGraphSchema = z.object({\n type: z.optional(z.string()),\n siteName: z.optional(z.string()),\n title: z.optional(LocalizableSchema),\n description: z.optional(LocalizableSchema),\n image: z.optional(ImageRefSchema),\n locale: z.optional(z.string()),\n});\n\nconst TwitterSchema = z.object({\n card: z.optional(z.enum(['summary', 'summary_large_image', 'app', 'player'])),\n site: z.optional(z.string()),\n creator: z.optional(z.string()),\n title: z.optional(LocalizableSchema),\n description: z.optional(LocalizableSchema),\n image: z.optional(ImageRefSchema),\n});\n\n// ── Indexing ────────────────────────────────────────────────────────────────────\n\n/**\n * What `vitops search notify` needs to tell search engines a deploy happened.\n *\n * Scoped by what search engines actually accept, which is narrower than it looks:\n * Google exposes **no** \"request indexing\" API (the Search Console button is not in\n * its API, and URL Inspection is read-only), and it removed the sitemap ping\n * endpoint in 2023. So the sanctioned set is: an accurate sitemap, a Search Console\n * sitemap resubmit, an IndexNow ping — which Google does *not* honour but Bing,\n * Yandex, Naver, Seznam and Yep do — and a read-only inspection pass to find out\n * what Google actually did.\n *\n * Facts only, the same rule the legal block follows: this records what the site has\n * (a key, a property, which pages matter), never what to say about it.\n */\nconst IndexNowSchema = z.object({\n key: desc(\n z.string().check(z.regex(/^[a-zA-Z0-9-]{8,128}$/)),\n 'IndexNow key (8–128 chars, hex is conventional). NOT a secret — it is served publicly at `keyLocation` so the engine can verify you own the host. Generate one with `vitops search notify --new-key`.',\n ),\n keyLocation: desc(\n z.optional(z.url()),\n 'Absolute URL of the key file. Defaults to `<canonical>/<key>.txt`; set it only when the file lives elsewhere.',\n ),\n endpoint: desc(\n z.optional(z.url()),\n 'IndexNow endpoint (default `https://api.indexnow.org/indexnow`). Any participating engine shares submissions with the rest, so one is normally enough.',\n ),\n});\n\nconst SearchConsoleSchema = z.object({\n siteUrl: desc(\n z.string(),\n 'The property exactly as Search Console identifies it — `sc-domain:acme.ca` for a domain property, or the URL-prefix form `https://acme.ca/`. A mismatch here is a 403, not a \"not found\".',\n ),\n resubmitSitemap: desc(\n z.optional(z.boolean()),\n 'Re-submit the sitemap through the Search Console API on each notify (default true when `searchConsole` is set). This is the automated equivalent of the manual resubmit in the UI.',\n ),\n});\n\nconst IndexingSchema = z.object({\n sitemapUrl: desc(\n z.optional(z.url()),\n 'The sitemap to submit and to diff for changed URLs. Defaults to `<canonical>/sitemap-index.xml`.',\n ),\n indexNow: desc(\n z.optional(IndexNowSchema),\n 'IndexNow submission (Bing, Yandex, Naver, Seznam, Yep — not Google). Omit to skip the channel.',\n ),\n searchConsole: desc(\n z.optional(SearchConsoleSchema),\n 'Google Search Console property. Needs a credential at run time — either a service account in `VITOPS_GSC_SERVICE_ACCOUNT` / `GOOGLE_APPLICATION_CREDENTIALS`, or the user OAuth credential `vitops search setup` uses (`VITOPS_GOOGLE_CLIENT_ID` / `_CLIENT_SECRET` / `_REFRESH_TOKEN`). The service account wins when both are set. Never put a key in this file.',\n ),\n priorityUrls: desc(\n z.optional(z.array(z.url())),\n 'The pages whose indexing actually matters. `vitops search notify --check` inspects these and exits non-zero if Google has not indexed one. Kept explicit because URL Inspection is quota-bound (2000/day), so checking every page is neither affordable nor informative.',\n ),\n});\n\n// ── Ad properties ───────────────────────────────────────────────────────────────\n\n/**\n * The ad platforms `vitops ads` can link a site to.\n *\n * A closed enum, mirroring `AD_PROVIDER_KEYS` in `@getvitops/utils/ads` — that\n * module owns what each platform *can do* (whether it verifies a domain, what its\n * tag is, which click ID it stamps), this owns what a config may *say*. Mirrored\n * rather than derived because a `z.enum` needs literals to reach the published JSON\n * Schema; `config.test.ts` asserts the two lists are the same set, so a provider\n * added to one and not the other fails the build rather than silently getting no\n * verification step and no tag.\n */\nexport const AD_PROVIDERS = [\n 'google',\n 'meta',\n 'linkedin',\n 'reddit',\n 'tiktok',\n 'microsoft',\n 'pinterest',\n 'snapchat',\n] as const;\nconst AdProviderSchema = z.enum(AD_PROVIDERS);\nexport type AdProvider = (typeof AD_PROVIDERS)[number];\n\n/**\n * One ad property this site is linked to.\n *\n * Facts, not prose — the same rule the legal block follows. This records *which*\n * account and *which* tag id, and the platform capability table decides what can be\n * done about them. It is also what finally lets the rest of the toolchain see an ad\n * pixel: the generated cookie notice discloses its cookies, `vitops ads lint`\n * checks its click ID is captured, and the consent gate is handed the cookie names\n * to clear on revoke. A pixel pasted into a template is invisible to all three.\n */\nconst AdPropertySchema = z.object({\n accountId: desc(\n z.optional(z.string()),\n 'The advertising account as the platform shows it — Google Ads customer ID, Meta ad account, LinkedIn partner ID, Reddit advertiser ID. For LinkedIn this is also the Insight Tag id; everywhere else the tag id is `pixelId`.',\n ),\n pixelId: desc(\n z.optional(z.string()),\n 'The tag/pixel ID the browser snippet initialises — Meta pixel, TikTok pixel, Reddit pixel, Microsoft UET tag ID, Pinterest tag ID, Snap pixel, or the Google Ads conversion ID (`AW-…`, which is NOT the customer ID).',\n ),\n conversionLabel: desc(\n z.optional(z.string()),\n 'Google Ads only: the conversion action label paired with the `AW-…` conversion ID.',\n ),\n domain: desc(\n z.optional(z.string()),\n 'Bare hostname to verify with this platform. Defaults to the host of `domains.canonical` — set it only when the ad account is verified against a different domain.',\n ),\n domainVerification: desc(\n z.optional(z.string()),\n 'The verification token from the platform UI, for the platforms that verify by DNS TXT (Meta, TikTok, Pinterest, Snapchat). `vitops ads setup` prompts for it and writes it here on first run. NOT a secret — it is published in DNS, and the platform fetching it back is the ownership proof, exactly like the IndexNow key. A value containing `=` is used as the whole record, which is the escape hatch if a platform changes its prefix.',\n ),\n category: desc(\n z.optional(z.enum(['marketing', 'analytics'])),\n 'Consent category the tag waits on (default `marketing`). An ad pixel is advertising by default; `analytics` is for a site using one purely for its own measurement.',\n ),\n enabled: desc(\n z.optional(z.boolean()),\n 'Set false to keep the property on record without emitting its tag.',\n ),\n});\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.object({\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.object({\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.object({\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.object({\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 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.',\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 abTesting: desc(\n z.optional(\n z.object({\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 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.object({\n activeTemplate: desc(\n z.optional(\n z.object({\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(\n z.object({\n titleTemplate: desc(z.optional(z.string()), 'Page-title pattern (e.g. \"%s · Acme\").'),\n descriptionTemplate: z.optional(z.string()),\n robots: desc(z.optional(RobotsSchema), 'e.g. \"index,follow\" / \"noindex,nofollow\".'),\n googleSiteVerification: z.optional(z.string()),\n bingSiteVerification: z.optional(z.string()),\n openGraph: z.optional(OpenGraphSchema),\n twitter: z.optional(TwitterSchema),\n indexing: desc(\n z.optional(IndexingSchema),\n 'How `vitops search notify` tells search engines about a deploy: which sitemap, IndexNow key, Search Console property, and which pages to verify afterwards.',\n ),\n }),\n ),\n 'SEO defaults: title/description templates, robots policy, verification tokens, Open Graph + Twitter cards, and post-deploy indexing notification.',\n ),\n analytics: desc(\n z.optional(\n z.object({\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.object({\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 }),\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 z.optional(\n z.object({\n email: desc(\n z.optional(\n z.union([\n z.email(),\n z.object({\n provider: desc(\n z.literal('cloudflare'),\n 'Delivery provider. Only Cloudflare Email Sending is implemented; the field is stated so adding another is additive.',\n ),\n to: desc(\n z.optional(z.email()),\n 'Recipient. Defaults to the primary location’s `email`, then the first location that has one.',\n ),\n from: desc(\n z.optional(z.email()),\n 'Sender. Defaults to `noreply@<domains.canonical>`. Its domain must be onboarded (`wrangler email sending enable <domain>`) or every send fails.',\n ),\n fromName: desc(\n z.optional(z.string()),\n 'Display name on the From header. Defaults to `organization.name`.',\n ),\n replyTo: desc(z.optional(z.email()), 'Reply-To header.'),\n binding: desc(\n z.optional(z.string()),\n 'Workers `send_email` binding name (default `EMAIL`). Set it when using a restricted binding.',\n ),\n }),\n ]),\n ),\n 'Where conversion notifications are e-mailed. A bare address is shorthand for `{ provider: \"cloudflare\", to }`.',\n ),\n }),\n ),\n 'Where site notifications (form submissions, tracked calls) are sent. TODO: `sms` and `persist` channels — only `email` is implemented.',\n ),\n tracking: desc(\n z.optional(\n z.object({\n enabled: desc(\n z.optional(z.boolean()),\n 'Capture ad click IDs and UTMs from the landing URL into the `_ac` cookie, for attributing conversions.',\n ),\n category: desc(\n z.optional(z.enum(['marketing', 'analytics'])),\n 'Consent category the `_ac` cookie waits on (default `marketing`). It is a 90-day identifier tying a visitor to the ad that brought them, so it is only written once this category is granted — and asking for it is what raises the banner.',\n ),\n platforms: desc(\n z.optional(z.array(z.string())),\n 'Informational list of ad platforms in use. Capture recognises every known click-ID parameter regardless.',\n ),\n }),\n ),\n 'Ad-click attribution for conversion tracking.',\n ),\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 security: desc(\n z.optional(\n z.object({\n turnstile: z.optional(\n z.object({\n siteKey: desc(z.optional(z.string()), 'Cloudflare Turnstile site key (public).'),\n }),\n ),\n }),\n ),\n 'Security integrations (bot protection).',\n ),\n legal: desc(\n z.optional(\n z.object({\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.object({\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.object({\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.object({\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.object({\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(z.optional(z.string()), 'App name for the generated web manifest / PWA.'),\n themeColor: desc(\n z.optional(z.string()),\n 'PWA theme color (also `<meta name=\"theme-color\">`).',\n ),\n backgroundColor: desc(z.optional(z.string()), 'PWA background color.'),\n }),\n ),\n 'Favicon/PWA asset generation (consumed by `@getvitops/utils` favicon tooling).',\n ),\n deployment: desc(\n z.optional(\n z.object({\n platform: z.optional(z.string()),\n buildCommand: z.optional(z.string()),\n deployCommand: z.optional(z.string()),\n outputDirectory: z.optional(z.string()),\n type: z.optional(z.string()),\n }),\n ),\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.object({\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\nexport const ConfigSchema = z.object({\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\n// ── JSON Schema + validation ────────────────────────────────────────────────────\n\nexport const CONFIG_SCHEMA_URL = 'https://unpkg.com/@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// ── 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 * 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) return { ok: false, data: undefined, errors: parsed.error.issues };\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 if (errors.length) return { ok: false, data: undefined, errors };\n return { ok: true, data: cfg, errors: [] };\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 * Palette expansion + semantic colour tokens.\n *\n * A palette hue is authored one of two ways:\n * • `{ seed, anchors? }` — an 11-step numeric scale (50…950) generated in\n * OKLCH via @getvitops/utils/color. Lightness comes from the shared\n * `LIGHTNESS_LADDER`; the seed (and any anchors) are reproduced verbatim at\n * their steps.\n * • `{ tones }` — a fixed brand kit: authored tones placed verbatim at their\n * nearest steps + tinted endpoints; nothing else is invented (strict kits).\n *\n * **The grammar.** Every role gets tokens named `--color-<target>-<role>[-<variant>]`,\n * where target ∈ bg | text | icon | border. Putting the target *inside* the name is\n * the point: `--color-bg-danger-muted` and `--color-text-danger-muted` are distinct\n * tokens, so the two axes that used to collide over one `<family>-<role>-<modifier>\n * ` namespace cannot any more. The utility class is the token name minus `--color-`.\n *\n * Variants are ordinal — xx-muted < x-muted < muted < (bare) < bold < x-bold —\n * and the tables are **sparse**: a target only emits the cells that are actually\n * viable. `bold` means \"more emphatic than the role's default in the current\n * appearance\", not \"darker\"; the appearance decides polarity.\n *\n * Roles come in two kinds (declared in `colors.roles`):\n * • `surface` — a page/panel colour. Has a bare `bg-<role>` plus the full\n * emphasis range and the complete text scale.\n * • `chromatic` (default) — a signal colour. Backgrounds split into *tints*\n * (`bg-<role>-x-muted` / `-muted`) and *solids* (`bg-<role>-solid[-bold|-x-bold]`);\n * there is deliberately **no bare `bg-<role>`**, because \"how loud?\" is a\n * question the author has to answer.\n *\n * Dark mode re-points which step each token reads; the solid family and the\n * `text-on-<role>` foreground computed against it stay mode-stable, so a filled\n * button keeps its identity across appearances.\n */\nimport {\n LIGHTNESS_LADDER,\n contrastLc,\n generateOklchPalette,\n hexToOklch,\n oklchStringToHex,\n pickOn,\n tintedEndpoints,\n} from '@getvitops/utils/color';\n\nexport const NUMERIC_STEPS = [\n '50',\n '100',\n '200',\n '300',\n '400',\n '500',\n '600',\n '700',\n '800',\n '900',\n '950',\n] as const;\ntype NumStep = (typeof NUMERIC_STEPS)[number];\n\n/**\n * Lightness of each numeric step. Re-exported from the engine's ladder rather\n * than restated — there used to be three copies of this curve (here, the engine,\n * and the linter) and they were free to drift.\n */\nconst STEP_L = Object.fromEntries(\n NUMERIC_STEPS.map((s) => [s, LIGHTNESS_LADDER[Number(s) as keyof typeof LIGHTNESS_LADDER]]),\n) as Record<NumStep, number>;\n\nexport interface ExpandedHue {\n /** Numeric steps (sparse for fixed-tone kits). */\n numeric: Partial<Record<NumStep, string>>;\n /** True when only authored tones + endpoints exist (no interpolation). */\n sparse?: boolean;\n /**\n * Steps the author pinned, and how far each sits from the ladder's lightness.\n * A pinned colour is reproduced exactly, so a large value here is legal — but\n * it means this hue reads heavier or lighter than its siblings at that step,\n * which the generator surfaces as a warning.\n */\n deviations?: Partial<Record<NumStep, number>>;\n}\n\ninterface SeedInput {\n seed: string;\n anchors?: Record<string, string>;\n}\ninterface TonesInput {\n tones: string[] | Record<string, string>;\n}\n\nconst isHex = (v: string) => v.startsWith('#');\nconst toOklchStr = (v: string) => {\n if (!isHex(v)) return v; // already oklch(...)\n const { l, c, h } = hexToOklch(v);\n return `oklch(${(l * 100).toFixed(2)}% ${c.toFixed(4)} ${h.toFixed(2)})`;\n};\nconst nearestStep = (l: number): NumStep =>\n NUMERIC_STEPS.reduce((best, s) =>\n Math.abs(l - STEP_L[s]) < Math.abs(l - STEP_L[best]) ? s : best,\n );\n\n/**\n * Claim `step` for `value`, refusing to overwrite a step another colour already\n * took.\n *\n * Silently dropping one of two colliding tones is the worst outcome: the palette\n * still builds, and the tone the author cared about is simply gone. The record\n * form (`tones: { \"600\": \"#…\", \"700\": \"#…\" }`) is the escape hatch, so the error\n * points at it.\n */\nfunction claim(\n into: Record<string, string>,\n step: string,\n value: string,\n hueLabel: string,\n what: string,\n): void {\n const taken = into[step];\n if (taken != null && taken !== value) {\n throw new Error(\n `palette hue \"${hueLabel}\": ${what} ${value} and ${taken} both map to step ${step}. ` +\n `Key them explicitly, e.g. { \"${step}\": \"${taken}\", \"${Number(step) + 100}\": \"${value}\" }.`,\n );\n }\n into[step] = value;\n}\n\nfunction expandSeeded(input: SeedInput, hueLabel: string): ExpandedHue {\n // The seed and any author anchors pin verbatim at their natural (or explicit)\n // steps; the engine fills every other step from the shared lightness ladder,\n // fading chroma toward the tinted ends. No implicit 50/950 anchors any more —\n // the ladder already defines the endpoints, and pinning them would override it.\n // Author anchors are placed FIRST and may collide only with each other. The\n // seed goes in afterwards, and only where an anchor hasn't already claimed the\n // step: an explicit anchor is the author overriding that step, which is exactly\n // what the live editor writes when you recolour a swatch. Treating that as a\n // collision would break the editor's save path.\n const anchors: Record<string, string> = {};\n for (const [key, value] of Object.entries(input.anchors ?? {})) {\n const step = (NUMERIC_STEPS as readonly string[]).includes(key)\n ? key\n : nearestStep(hexToOklch(value).l);\n claim(anchors, step, toOklchStr(value), hueLabel, 'anchors');\n }\n const seedStep = nearestStep(hexToOklch(input.seed).l);\n anchors[seedStep] ??= toOklchStr(input.seed);\n const scale = generateOklchPalette(anchors) as Record<string, string>;\n const numeric: Partial<Record<NumStep, string>> = {};\n for (const s of NUMERIC_STEPS) if (scale[s] != null) numeric[s] = oklchStringToHex(scale[s]);\n return { numeric, deviations: deviationsFor(anchors) };\n}\n\nfunction expandTones(input: TonesInput, hueLabel: string): ExpandedHue {\n // Strict kit: authored tones verbatim at their nearest step; add tinted\n // endpoints (the one allowed exception); interpolate nothing else.\n const entries: Array<[string | null, string]> = Array.isArray(input.tones)\n ? input.tones.map((hex) => [null, hex])\n : Object.entries(input.tones).map(([k, hex]) => [k, hex]);\n\n const placed: Record<string, string> = {};\n for (const [key, hex] of entries) {\n const step =\n key != null && (NUMERIC_STEPS as readonly string[]).includes(key)\n ? key\n : nearestStep(hexToOklch(hex).l);\n claim(placed, step, hex, hueLabel, 'tones');\n }\n\n const numeric: Partial<Record<NumStep, string>> = {};\n for (const [step, hex] of Object.entries(placed)) numeric[step as NumStep] = hex;\n\n const firstTone = entries[0]?.[1] ?? '#808080';\n const ends = tintedEndpoints(hexToOklch(firstTone).h);\n numeric['50'] ??= ends.light;\n numeric['950'] ??= ends.dark;\n\n return { numeric, sparse: true, deviations: deviationsFor(placed) };\n}\n\n/** How far each pinned colour sits from its step's ladder lightness. */\nfunction deviationsFor(pinned: Record<string, string>): Partial<Record<NumStep, number>> {\n const out: Partial<Record<NumStep, number>> = {};\n for (const [step, value] of Object.entries(pinned)) {\n const l = isHex(value) ? hexToOklch(value).l : hexToOklch(oklchStringToHex(value)).l;\n out[step as NumStep] = l - STEP_L[step as NumStep];\n }\n return out;\n}\n\n/** Snap to the nearest AVAILABLE numeric step (sparse kits). */\nfunction snap(numeric: Partial<Record<NumStep, string>>, want: NumStep): NumStep {\n if (numeric[want] != null) return want;\n const have = NUMERIC_STEPS.filter((s) => numeric[s] != null);\n return have.reduce((best, s) =>\n Math.abs(STEP_L[s] - STEP_L[want]) < Math.abs(STEP_L[best] - STEP_L[want]) ? s : best,\n );\n}\n\n/** Expand every palette hue into its numeric scale. */\nexport function expandPalette(raw: Record<string, unknown>): Record<string, ExpandedHue> {\n const out: Record<string, ExpandedHue> = {};\n for (const [name, entry] of Object.entries(raw)) {\n const e = entry as Partial<SeedInput & TonesInput>;\n if (typeof e?.seed === 'string') out[name] = expandSeeded(e as SeedInput, name);\n else if (e?.tones != null) out[name] = expandTones(e as TonesInput, name);\n else throw new Error(`palette hue \"${name}\" must have a \"seed\" or \"tones\"`);\n }\n return out;\n}\n\n/**\n * Warn about pinned colours that sit noticeably off the ladder. Not an error:\n * the author asked for that exact colour and gets it. But at ~0.03 L the hue\n * starts reading visibly heavier or lighter than its siblings at that step, and\n * that is the class of drift the fixed ladder exists to prevent.\n */\nexport const LADDER_TOLERANCE = 0.03;\n\nexport function ladderWarnings(palette: Record<string, ExpandedHue>): string[] {\n const warnings: string[] = [];\n for (const [hue, expanded] of Object.entries(palette)) {\n for (const [step, deviation] of Object.entries(expanded.deviations ?? {})) {\n if (Math.abs(deviation as number) <= LADDER_TOLERANCE) continue;\n const dir = (deviation as number) > 0 ? 'lighter' : 'darker';\n warnings.push(\n `colors.palette.${hue}: the colour pinned at step ${step} is ${Math.abs(\n deviation as number,\n ).toFixed(3)} ${dir} than the shared lightness ladder — this hue will read ` +\n `${dir} than others at ${step}. Legal, but move it to a neighbouring step if that wasn't intended.`,\n );\n }\n }\n return warnings;\n}\n\n/**\n * Gamut mapping nudges lightness by a hair, so an exact `<` comparison would\n * report rounding as an inversion. Well below any deviation a person could see.\n */\nconst MONOTONIC_EPSILON = 1e-3;\n\n/**\n * Ramps whose lightness does not fall monotonically from 50 to 950.\n *\n * A ramp built from the ladder alone cannot invert — only pinned colours (a seed,\n * an `anchor`, a `tones` entry) can, because they are the one thing allowed off\n * it. `ladderWarnings` will not catch it: it compares each pinned step against\n * *its own* ladder rung, never against its neighbours, so it reports the wrong\n * defect (\"reads darker than others at 600\") while the real problem is that 600\n * is darker than 700. And since `LADDER_TOLERANCE` is 0.03 — the same size as the\n * ladder's own 50→100 gap — two anchors can each sit within tolerance and still\n * invert, with no warning at all.\n *\n * This is an error rather than a warning because the rest of the system assumes\n * the order: `snap` picks the nearest step by ladder lightness, the mode-stable\n * solid family hard-codes 600/700/800 as increasingly dark, and both dark tables\n * re-point steps on the same assumption. An inverted ramp therefore runs hover\n * states backwards — the failure the fixed ladder was introduced to eliminate.\n */\nexport function monotonicityErrors(palette: Record<string, ExpandedHue>): string[] {\n const errors: string[] = [];\n for (const [hue, expanded] of Object.entries(palette)) {\n const numeric = expanded.numeric ?? {};\n // Present steps only — a sparse `tones` kit is legal, and comparing against\n // absent steps would invent inversions that aren't there.\n const steps = NUMERIC_STEPS.filter((s) => numeric[s] != null);\n for (let i = 1; i < steps.length; i++) {\n const [prev, step] = [steps[i - 1] as NumStep, steps[i] as NumStep];\n // The final hex, not the nominal ladder value: a pinned colour is emitted\n // verbatim, and it is precisely the pinned steps that can invert.\n const lPrev = hexToOklch(numeric[prev] as string).l;\n const lStep = hexToOklch(numeric[step] as string).l;\n if (lStep < lPrev + MONOTONIC_EPSILON) continue;\n // Point at the colour the author actually wrote. Only a pinned step can be\n // off the ladder, so naming its correct home is the actionable half — the\n // unpinned neighbour is already exactly where it belongs, and telling\n // someone to move that one sends them the wrong way.\n const pinned = expanded.deviations ?? {};\n const culprits = ([prev, step] as NumStep[]).filter((s) => pinned[s] != null);\n const fix = culprits.length\n ? culprits\n .map((s) => {\n const l = hexToOklch(numeric[s] as string).l;\n return `${numeric[s]} (pinned at ${s}) sits at L ${l.toFixed(3)}, nearest step ${nearestStep(l)}`;\n })\n .join('; ')\n : `no step here is pinned, so this is a bug in the generator rather than in your config`;\n errors.push(\n `colors.palette.${hue}: step ${step} (${numeric[step]}, L ${lStep.toFixed(3)}) is LIGHTER ` +\n `than step ${prev} (${numeric[prev]}, L ${lPrev.toFixed(3)}). A ramp must darken from 50 ` +\n `to 950 — inverted, a hover from \\`bg-<role>-solid\\` to \\`-solid-bold\\` gets lighter, and ` +\n `the dark-mode tables re-point steps assuming the order. ${fix}.`,\n );\n }\n }\n return errors;\n}\n\n// ── the token tables ─────────────────────────────────────────────────────────\n\n/** Which shape of token set a role gets. */\nexport type RoleKind = 'surface' | 'chromatic';\n\n/** Token key → numeric step. Keys are `<target>[-<variant>]`; see `tokenVar`. */\ntype Table = Record<string, NumStep>;\n\n/**\n * Surface roles: a bare `bg` (cards, panels, inputs), `bg-muted` for the page\n * behind them, `bg-x-muted` for wells, and `bg-bold`/`-x-bold` for the inverse\n * surface a tooltip sits on. Elevation is expressed by *which* token you reach\n * for — page `bg-muted`, card `bg` — rather than by a raised/sunken pair. That\n * is what lets a future `data-surfaces` axis flatten it without touching markup.\n */\nconst SURFACE_LIGHT: Table = {\n bg: '50',\n 'bg-muted': '100',\n 'bg-x-muted': '200',\n 'bg-bold': '800',\n 'bg-x-bold': '950',\n text: '900',\n 'text-bold': '950',\n 'text-muted': '700',\n 'text-x-muted': '500',\n 'text-xx-muted': '400',\n 'text-on-bold': '50',\n icon: '600',\n 'icon-muted': '500',\n 'border-muted': '200',\n border: '300',\n 'border-bold': '600',\n};\nconst SURFACE_DARK: Table = {\n bg: '900',\n 'bg-muted': '950',\n 'bg-x-muted': '950',\n 'bg-bold': '200',\n 'bg-x-bold': '50',\n text: '100',\n 'text-bold': '50',\n // 300 and 400, not v3.1's 400 and 500: those were tuned against WCAG and come\n // up short of APCA's secondary-text and non-text bars over a dark surface.\n 'text-muted': '300',\n 'text-x-muted': '500',\n 'text-xx-muted': '600',\n 'text-on-bold': '950',\n icon: '400',\n 'icon-muted': '500',\n 'border-muted': '800',\n border: '700',\n 'border-bold': '400',\n};\n\n/**\n * Chromatic roles: tints for alert/badge backgrounds, solids for fills. No bare\n * `bg` — see the module docblock. No `text-muted` either: a de-emphasised\n * coloured text could not hold its contrast target off a white surface, so the\n * way to soften coloured text is weight/size, not another colour.\n */\nconst CHROMATIC_LIGHT: Table = {\n 'bg-x-muted': '50',\n 'bg-muted': '100',\n text: '700',\n 'text-bold': '900',\n icon: '600',\n border: '200',\n 'border-bold': '300',\n};\nconst CHROMATIC_DARK: Table = {\n 'bg-x-muted': '950',\n 'bg-muted': '900',\n text: '300',\n 'text-bold': '200',\n icon: '400',\n border: '800',\n 'border-bold': '700',\n};\n\n/**\n * The solid family — mode-stable, so a filled button keeps its identity when the\n * appearance flips. Fixed steps rather than the old scan-and-clamp: with a shared\n * lightness ladder every hue's 600 already sits at the same lightness, so there\n * is nothing left to search for. `text-on-<role>` is computed against `bg-solid`.\n */\nconst SOLID: Table = { 'bg-solid': '600', 'bg-solid-bold': '700', 'bg-solid-x-bold': '800' };\n\n/**\n * Map a token key to its CSS custom property for a given role.\n *\n * `on` is the one irregular case: the foreground for a filled surface reads\n * `--color-text-on-<role>`, with the role *after* `on`, because it names what it\n * sits on rather than what it is.\n *\n * The utility class name is this minus the `--color-` prefix, which is why the\n * emitter and the linter can both derive their vocabulary from one function.\n */\nexport function tokenVar(role: string, key: string): string {\n const dash = key.indexOf('-');\n const target = dash === -1 ? key : key.slice(0, dash);\n const variant = dash === -1 ? '' : key.slice(dash + 1);\n if (variant === 'on') return `--color-${target}-on-${role}`;\n if (variant.startsWith('on-')) return `--color-${target}-on-${role}-${variant.slice(3)}`;\n return variant ? `--color-${target}-${role}-${variant}` : `--color-${target}-${role}`;\n}\n\n/** The class name a token key produces for a role (`bg-danger-solid`, …). */\nexport const tokenClass = (role: string, key: string): string =>\n tokenVar(role, key).slice('--color-'.length);\n\nexport interface FunctionalRole {\n role: string;\n hue: string;\n kind: RoleKind;\n /** token key → CSS value, per appearance. */\n light: Record<string, string>;\n dark: Record<string, string>;\n}\n\n/** Resolve the token set for one role over its hue. */\nexport function functionalRole(\n role: string,\n hueName: string,\n hue: ExpandedHue,\n kind: RoleKind = 'chromatic',\n): FunctionalRole {\n const numeric = hue.numeric;\n const v = (n: NumStep) => `var(--color-${hueName}-${snap(numeric, n)})`;\n const hex = (n: NumStep) => numeric[snap(numeric, n)] as string;\n\n const map = (table: Table): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const [token, step] of Object.entries(table)) out[token] = v(step);\n return out;\n };\n\n // Solids and the foreground computed against them are identical in both\n // appearances — that mode-stability is the whole point of the family.\n const solids = map(SOLID);\n const onSolid = pickOn(hex(SOLID['bg-solid'] as NumStep));\n\n const light = {\n ...map(kind === 'surface' ? SURFACE_LIGHT : CHROMATIC_LIGHT),\n ...solids,\n 'text-on': onSolid,\n };\n const dark = {\n ...map(kind === 'surface' ? SURFACE_DARK : CHROMATIC_DARK),\n ...solids,\n 'text-on': onSolid,\n };\n return { role, hue: hueName, kind, light, dark };\n}\n\n// ── the contrast contract ────────────────────────────────────────────────────\n\n/**\n * APCA targets. `TEXT` is the body-text bar; `SECONDARY` covers text on a\n * non-primary surface and de-emphasised text. `NON_TEXT` is the icon/boundary\n * tier — the APCA analogue of WCAG's 3:1, where a glyph may run more vivid than\n * text because shape carries meaning alongside contrast.\n */\nexport const CONTRAST = { TEXT: 75, SECONDARY: 60, NON_TEXT: 45 } as const;\n\n/**\n * Text tokens deliberately exempt from the contract. Placeholders and disabled\n * text are required to look unavailable; holding them to the body-text bar would\n * defeat the affordance. Nothing else may be exempt.\n */\nconst EXEMPT_TEXT = new Set(['text-x-muted', 'text-xx-muted']);\n\n/**\n * Verify a role's contrast targets. Returns human-readable failures.\n *\n * Chromatic roles are checked against the surface planes they actually sit on\n * (`surfaceBg`) as well as their own tints — coloured text almost never appears\n * over its own solid, it appears over the page. Checking only within the role\n * would have missed the pairing that matters most.\n */\nexport function checkContrast(\n fr: FunctionalRole,\n numericOf: (hueName: string) => Partial<Record<NumStep, string>>,\n surfaceBg?: { light: string[]; dark: string[] },\n): string[] {\n const failures: string[] = [];\n const resolve = (val: string): string => {\n const m = /^var\\(--color-([a-z0-9-]+)-(\\d+)\\)$/.exec(val);\n if (!m) return val;\n return numericOf(m[1] as string)[m[2] as NumStep] ?? val;\n };\n const fail = (appearance: string, msg: string) =>\n failures.push(`${fr.role}/${appearance}: ${msg}`);\n\n for (const [appearance, tokens] of [\n ['light', fr.light],\n ['dark', fr.dark],\n ] as const) {\n // Backgrounds this role's own foregrounds have to work on. For a surface\n // role that's its own planes; for a chromatic role it's the page surface\n // plus its own tints.\n const ownBg = Object.keys(tokens)\n .filter((k) => k === 'bg' || k.startsWith('bg-'))\n .filter((k) => !k.startsWith('bg-solid'))\n .filter((k) => !k.startsWith('bg-bold') && !k.startsWith('bg-x-bold'));\n const planes: Array<[string, string]> =\n fr.kind === 'surface'\n ? ownBg.map((k) => [k, resolve(tokens[k] as string)])\n : [\n ...(surfaceBg?.[appearance] ?? []).map(\n (h, i) => [`surface#${i}`, h] as [string, string],\n ),\n ...ownBg.map((k) => [k, resolve(tokens[k] as string)] as [string, string]),\n ];\n\n for (const [planeName, bg] of planes) {\n // `bg` is the role's primary surface and holds the full body-text bar;\n // every other plane holds the secondary bar.\n const textMin = planeName === 'bg' ? CONTRAST.TEXT : CONTRAST.SECONDARY;\n for (const key of ['text', 'text-bold', 'text-muted']) {\n if (tokens[key] == null || EXEMPT_TEXT.has(key)) continue;\n const min = key === 'text-muted' ? CONTRAST.SECONDARY : textMin;\n const lc = contrastLc(resolve(tokens[key] as string), bg);\n if (lc < min) fail(appearance, `${key} Lc ${lc.toFixed(1)} < ${min} on ${planeName} ${bg}`);\n }\n // Icons carry meaning, so they hold the non-text bar everywhere. Borders\n // do not: a chromatic `border-<role>` is *decorative* — the tinted edge of\n // an alert, where the colour reinforces a message the text already makes.\n // Only a surface role's `border-bold` is the \"this boundary is the only\n // thing separating two regions\" token, so only that one is guaranteed.\n const nonText = fr.kind === 'surface' ? ['icon', 'border-bold'] : ['icon'];\n for (const key of nonText) {\n if (tokens[key] == null) continue;\n const lc = contrastLc(resolve(tokens[key] as string), bg);\n if (lc < CONTRAST.NON_TEXT)\n fail(\n appearance,\n `${key} Lc ${lc.toFixed(1)} < ${CONTRAST.NON_TEXT} on ${planeName} ${bg}`,\n );\n }\n }\n\n // The filled-surface pairing: text-on against the solid it names.\n const solid = resolve(tokens['bg-solid'] as string);\n const onLc = contrastLc(tokens['text-on'] as string, solid);\n if (onLc < CONTRAST.SECONDARY)\n fail(appearance, `text-on Lc ${onLc.toFixed(1)} < ${CONTRAST.SECONDARY} on bg-solid`);\n\n // The inverse surface, where it exists.\n if (tokens['bg-bold'] != null && tokens['text-on-bold'] != null) {\n const lc = contrastLc(resolve(tokens['text-on-bold'] as string), resolve(tokens['bg-bold']));\n if (lc < CONTRAST.TEXT)\n fail(appearance, `text-on-bold Lc ${lc.toFixed(1)} < ${CONTRAST.TEXT} on bg-bold`);\n }\n }\n return failures;\n}\n","/**\n * Which tiers provide each pattern, and which call to make.\n *\n * The toolkit ships four tiers that COMPOSE — CSS framework classes, Lit web\n * components, Astro components, Bricks elements — and the composition is what a\n * consumer actually needs. For a tree: `.tree` styles it, `<Tree />` generates the\n * markup, `<wc-tree>` enhances it. This file is the single source for that, and\n * `tiers.test.ts` holds it to the files on disk.\n *\n * **Authored, not derived, and that is deliberate.** Name convention carries most\n * of it (`patterns/<name>.css` ↔ `WC<Name>.ts` → `wc-<name>` ↔\n * `bricks/elements/<name>.php`) but breaks where it matters:\n *\n * - `splitter.css` hosts TWO components (`wc-split-panel`, `wc-image-compare`);\n * - `anchor-link.css` provides `.link`, whose config pattern is `link`;\n * - `tag.css` carries parts for THREE config patterns (`badge`, `tag`, `status`);\n * - `layout.css` (a root partial, not under `patterns/`) provides `.split` and\n * `.centered`, both of which have Bricks elements;\n * - `forms.css`, `nav.css`, `navbar.css`, `navshell.css` each serve several tiers.\n *\n * A derivation would need an exceptions table longer than the rule, and a rename\n * would silently drop a link instead of failing. So it is authored, and the guards\n * make omission a build failure rather than a missing docs row.\n *\n * **The composition rule this encodes** (see `AGENTS.md`, tier 3): an Astro\n * component emits the `<wc-*>` tag with the accessible fallback INSIDE it. So\n * `<Tree />` is the whole call — wrapping it in your own `<wc-tree>` nests two\n * elements on one tree. `astro.wraps` records which case each component is, because\n * it varies: `Tree` and `CookieConsent` wrap a web component, while `Details`,\n * `Drawer`, `Popover`, `NavShell` and `Subgrid` emit tier-1 markup with no web\n * component at all. That cannot be inferred from the taxonomy.\n */\n\n/** A pattern's CSS. `generated` means `design-system.json`'s `patterns.items`. */\nexport interface TierCss {\n /**\n * Hand-written partial, relative to `packages/core/css/` — usually\n * `patterns/<name>.css`, occasionally a root partial such as `layout.css`.\n * Absent when the pattern is generated CSS only.\n */\n partial?: string;\n /** Representative classes. Not exhaustive — the class reference enumerates. */\n classes: string[];\n /**\n * True when the pattern is **config-authored** — its CSS comes from\n * `patterns.items.<name>`, so it gets the token cascade, `states`, role variants\n * and `BASE_HOOK` override vars. False means a purely structural partial with\n * none of those.\n *\n * Note `patterns.items` is CONSUMER-authored: `defaultConfig()` ships only\n * `btn`/`cta`/`card`, and a consumer declares whatever else they need. So this\n * flag records which patterns are *of that kind* — the reference set is this\n * repo's own `src/design-system.json`, which is what the docs render from — not a\n * promise about any particular consumer's config.\n */\n generated: boolean;\n}\n\nexport interface TierWc {\n tag: string;\n /** In `elements.js`. False = its own bundle, or not shipped at all. */\n registered: boolean;\n /** What JS adds over the fallback. The reason the tier exists for this pattern. */\n adds: string;\n /** Set when the element ships somewhere other than `elements.js`. */\n bundle?: string;\n}\n\nexport interface TierAstro {\n /** Import specifier, e.g. `@getvitops/astro/components/Tree.astro`. */\n component: string;\n /**\n * `wc` — emits the `<wc-*>` tag with the fallback inside, so this one call is the\n * whole composition. `css` — emits tier-1 markup; there is no web component.\n */\n wraps: 'wc' | 'css';\n}\n\nexport interface TierEntry {\n css: TierCss;\n wc?: TierWc;\n /**\n * Astro components for this pattern. An array because a pattern can ship more\n * than one — `navshell` has both `NavShell` and `NavShellToggle`, since the\n * toggle must be placeable outside the shell.\n */\n astro?: TierAstro[];\n /** Bricks element `$name`, e.g. `vitops-carousel`. */\n bricks?: string;\n /** The one line an agent needs: what to actually write. */\n use: string;\n}\n\nconst c = (classes: string[], partial?: string, generated = false): TierCss => ({\n ...(partial ? { partial } : {}),\n classes,\n generated,\n});\n\n/**\n * Shorthand for the usual `@getvitops/astro/components/<name>.astro` export.\n *\n * Not every component lives under `components/` — `CookieConsent.astro` is exported\n * from the package root — so those are written out in full. The specifier must be\n * one a consumer can actually import: `tiers.test.ts` checks each against\n * `packages/astro/package.json`'s `exports`, because a wrong one is a copy-pasteable\n * import that fails only in the consumer's project.\n */\nconst a = (name: string, wraps: 'wc' | 'css'): TierAstro[] => [\n { component: `@getvitops/astro/components/${name}.astro`, wraps },\n];\n\nexport const TIERS: Record<string, TierEntry> = {\n // ── Patterns that span tiers: the composition actually matters here ────────\n tree: {\n css: c(\n ['tree', 'tree__item', 'tree__content', 'tree__toggle', 'tree__label'],\n 'patterns/tree.css',\n true,\n ),\n wc: {\n tag: 'wc-tree',\n registered: true,\n adds: 'filter, expand/collapse all, hash deep-linking',\n },\n astro: a('Tree', 'wc'),\n use: '`<Tree items={…} />` — it emits `<wc-tree>` itself, so do NOT add your own wrapper.',\n },\n carousel: {\n css: c(['carousel'], 'patterns/carousel.css', true),\n wc: {\n tag: 'wc-carousel',\n registered: true,\n adds: 'cloned slides for a seamless loop, autoplay, snap nav',\n },\n bricks: 'vitops-carousel',\n use: '`<wc-carousel>` around your slides; each child is a slide. Works unenhanced as a scroll-snap strip.',\n },\n entries: {\n css: c(['entries__table', 'entries__scroll', 'entries__nav'], 'patterns/table.css'),\n wc: {\n tag: 'wc-entries',\n registered: true,\n adds: 'parses heading + `<dl>` pairs into a table above a breakpoint',\n },\n bricks: 'vitops-entries',\n use: '`<wc-entries>` around `<h3>` + `<dl>` pairs. The tier-2 exemplar: semantic pairs with no JS, a table with it.',\n },\n copy: {\n css: c(['copy', 'copy__button', 'copy__icon', 'copy__tooltip'], 'patterns/copy.css'),\n wc: { tag: 'wc-copy', registered: true, adds: 'clipboard write plus success feedback' },\n bricks: 'vitops-copy-button',\n use: '`<wc-copy>` around the content and a `[data-copy]` button.',\n },\n dismissable: {\n css: c(['banner__close', 'notification__close'], 'patterns/banner.css'),\n wc: {\n tag: 'wc-dismissable',\n registered: true,\n adds: 'fade-out + removal, optional auto-dismiss',\n },\n bricks: 'vitops-dismissable',\n use: '`<wc-dismissable>` around any banner/notification containing a `[data-dismiss]` control.',\n },\n 'split-panel': {\n css: c(['splitter', 'splitter__panel', 'splitter__handle'], 'patterns/splitter.css'),\n wc: { tag: 'wc-split-panel', registered: true, adds: 'draggable divider between two panels' },\n bricks: 'vitops-split-panel',\n use: '`<wc-split-panel>` with two children. Unenhanced they simply stack.',\n },\n 'image-compare': {\n // Same partial as split-panel — one of the reasons this file is authored.\n css: c(\n ['image-compare', 'image-compare__before', 'image-compare__handle'],\n 'patterns/splitter.css',\n ),\n wc: {\n tag: 'wc-image-compare',\n registered: true,\n adds: 'drag handle revealing the before/after image',\n },\n bricks: 'vitops-image-compare',\n use: '`<wc-image-compare>` with two images. Both are visible without JS.',\n },\n marquee: {\n css: c(['marquee', 'marquee__content', 'marquee__item'], 'patterns/marquee.css'),\n wc: {\n tag: 'wc-marquee',\n registered: true,\n adds: 'fills the track with enough copies to scroll seamlessly',\n },\n use: '`<wc-marquee>` around one `.marquee__content`. Scrolls via CSS alone; JS only removes the seam.',\n },\n 'multi-field': {\n // NOT generated: the config pattern here is `forms`. This component sits over\n // forms markup, so it has no `patterns.items` entry, no roles and no states.\n css: c(['form-group', 'input-group', 'fieldset'], 'patterns/forms.css'),\n wc: { tag: 'wc-multi-field', registered: true, adds: 'add/remove repeating field rows' },\n bricks: 'vitops-multi-field',\n use: '`<wc-multi-field>` around a field template. One row submits fine with no JS.',\n },\n 'color-scheme-toggle': {\n css: c([], 'patterns/icon.css'),\n wc: {\n tag: 'wc-color-scheme-toggle',\n registered: true,\n adds: 'segmented light/dark/system control; persists the choice (consent-gated)',\n },\n bricks: 'vitops-color-scheme-toggle',\n use: '`<wc-color-scheme-toggle></wc-color-scheme-toggle>`. Renamed from `<color-scheme-toggle>` in 4.0. Shadow DOM, so it is absent rather than broken without JS.',\n },\n consent: {\n css: c(\n ['consent', 'consent__body', 'consent__options', 'consent__actions'],\n 'patterns/consent.css',\n ),\n wc: {\n tag: 'wc-consent',\n registered: false,\n bundle: '@getvitops/core/consent',\n adds: 'the permission gate itself — activates `type=\"text/plain\"` tags on grant',\n },\n // Exported from the package root, not `components/`.\n astro: [{ component: '@getvitops/astro/CookieConsent.astro', wraps: 'wc' }],\n use: '`<CookieConsent />`. Its own Lit-free bundle so a site needing consent does not download a rendering framework.',\n },\n 'theme-editor': {\n css: c(['ed-panel', 'ed-launch', 'ed-input'], 'patterns/theme-editor.css'),\n wc: {\n tag: 'wc-theme-editor',\n registered: false,\n bundle: '@getvitops/core/editor',\n adds: 'live `:root` token overrides, export as CSS or a config patch',\n },\n use: '`<wc-theme-editor manifest=\"…\">`. TOOLING, not a page pattern — the one deliberate tier-2 exception, quarantined in its own opt-in bundle.',\n },\n\n // ── editor-v2 track: defined, but shipped in no bundle ────────────────────\n //\n // Registered by their own modules and imported by nothing, so nothing can be\n // consuming them. They are listed because the guards require every\n // `customElements.define` to be accounted for — and because \"exists but is not\n // shipped\" is exactly the kind of thing a reader needs told, rather than\n // discovering the tag does nothing.\n 'color-wheel': {\n css: c([]),\n wc: {\n tag: 'wc-color-wheel',\n registered: false,\n adds: 'hue/chroma wheel input',\n bundle: '(none — editor-v2 track, not yet bundled)',\n },\n use: 'Not shipped. Registered but absent from every bundle, so the tag is inert in a consumer project.',\n },\n 'oklch-color-picker': {\n css: c([]),\n wc: {\n tag: 'wc-oklch-color-picker',\n registered: false,\n adds: 'OKLCH L/C/H picker',\n bundle: '(none — editor-v2 track, not yet bundled)',\n },\n use: 'Not shipped. See `color-wheel`.',\n },\n 'icon-picker': {\n css: c([], 'patterns/icon.css'),\n wc: {\n tag: 'wc-icon-picker',\n registered: false,\n adds: 'browses the semantic icon map for the configured set',\n bundle: '(none — editor-v2 track, not yet bundled)',\n },\n use: 'Not shipped. See `color-wheel`.',\n },\n 'typography-config': {\n css: c([]),\n wc: {\n tag: 'wc-typography-config',\n registered: false,\n adds: 'type role editor',\n bundle: '(none — editor-v2 track, not yet bundled)',\n },\n use: 'Not shipped. See `color-wheel`.',\n },\n\n // ── Astro-only conveniences over tier-1 markup (no web component) ──────────\n details: {\n css: c(['details', 'details-trigger', 'details-icon'], 'patterns/details.css', true),\n astro: a('Details', 'css'),\n use: '`<Details>` — or hand-write `<details>`. No JS at either tier; `::details-content` animates in CSS.',\n },\n drawer: {\n css: c(['drawer', 'drawer--start', 'drawer--end'], 'patterns/drawer.css', true),\n astro: a('Drawer', 'css'),\n use: '`<Drawer>` — `<dialog class=\"drawer\">` plus an Invoker Commands trigger. No JS.',\n },\n popover: {\n css: c(['popover', 'popover-trigger', 'popover-anchor'], 'patterns/popover.css', true),\n astro: a('Popover', 'css'),\n use: '`<Popover>` — native Popover API + CSS Anchor Positioning. No JS.',\n },\n navshell: {\n css: c(\n ['navshell', 'navshell__bar', 'navshell__panel', 'navshell-toggle'],\n 'patterns/navshell.css',\n ),\n astro: [...a('NavShell', 'css'), ...a('NavShellToggle', 'css')],\n use: '`<NavShell>` with a `nav` slot, plus `<NavShellToggle>` if the toggle must live outside the shell.',\n },\n subgrid: {\n css: c(['subgrid', 'subgrid-card', 'pricing-grid'], 'patterns/subgrid.css'),\n astro: a('Subgrid', 'css'),\n use: '`<Subgrid>` — emits `<ul class=\"grid\">` with row-subgrid children so cards align across tracks.',\n },\n card: {\n css: c(['card'], undefined, true),\n astro: a('Cards', 'css'),\n use: '`<Cards>` for a list, or the `.card` class directly. Generated pattern: has roles and states.',\n },\n icon: {\n css: c(['icon', 'icon-button', 'icon-mask'], 'patterns/icon.css'),\n astro: a('Icon', 'css'),\n bricks: 'vitops-icon',\n use: '`<Icon name=\"menu\" />`. Names are semantic and resolve per configured set; a name containing `:` passes through.',\n },\n\n // ── Bricks + CSS, no web component ────────────────────────────────────────\n split: {\n css: c(['split', 'split-1-2', 'split-reverse'], 'layout.css'),\n bricks: 'vitops-split',\n use: '`.split` plus a ratio class. Pure CSS; `md-split-1-2` for the responsive form.',\n },\n centered: {\n css: c(['centered', 'spotlight', 'breakout', 'fullbleed'], 'layout.css'),\n bricks: 'vitops-centered',\n use: '`.centered` as a track grid. Children land in `measure` — give it a track child to lay out inside.',\n },\n sitenav: {\n css: c(['sitenav', 'sitenav__link', 'sitenav--drawer-start'], 'patterns/sitenav.css'),\n bricks: 'vitops-sitenav',\n use: '`.sitenav` with `--bp-*` and a drawer direction. `<details>` + Invoker Commands, no JS.',\n },\n 'split-link': {\n css: c(['split-link', 'split-link__toggle', 'split-link__panel'], 'patterns/split-link.css'),\n bricks: 'vitops-split-link',\n use: '`.split-link` — a link plus a disclosure toggle. No JS.',\n },\n\n // ── CSS-only patterns ─────────────────────────────────────────────────────\n btn: {\n css: c(['btn'], undefined, true),\n use: '`<button>` gets it with no class; `.btn` carries it to other tags. `fill: false`, so states drive `color`.',\n },\n cta: {\n css: c(['cta', 'cta-danger'], undefined, true),\n use: '`.cta` on any element — usually `<a>`, since a CTA navigates. Filled, with role variants.',\n },\n link: {\n css: c(['link', 'skip-link'], 'patterns/anchor-link.css', true),\n use: '`<a>` gets it at zero specificity; `.link` for other tags.',\n },\n badge: {\n css: c(['badge', 'badge-indicator'], 'patterns/tag.css', true),\n use: '`.badge` — a STATIC label. Use `tag` if it is dismissable or editable.',\n },\n tag: {\n css: c(['tag', 'tag__remove', 'tag__icon', 'tag-list'], 'patterns/tag.css', true),\n use: '`.tag` — an editable/dismissable label. Its group is `label`, not `tag`.',\n },\n status: {\n css: c(['status', 'status-dot--pulse'], 'patterns/tag.css', true),\n use: '`.status` with a role variant.',\n },\n tooltip: {\n css: c(['tooltip-trigger'], 'patterns/tooltip.css', true),\n use: '`.tooltip-trigger` — CSS only, anchor-positioned.',\n },\n dialog: {\n css: c(['dialog__header', 'dialog__body', 'dialog__footer'], 'patterns/dialog.css', true),\n use: 'Native `<dialog>` plus the `.dialog__*` parts. No JS beyond `showModal()`.',\n },\n dropdown: {\n css: c(['dropdown--show-on-hover', 'dropdown-menu'], 'patterns/dropdown.css', true),\n use: '`.dropdown` — Popover API based.',\n },\n notification: {\n css: c(\n ['notification', 'notification__title', 'notification__actions'],\n 'patterns/notification.css',\n true,\n ),\n use: '`.notification` with a role variant; wrap in `<wc-dismissable>` to make it dismissable.',\n },\n lightbox: {\n css: c(['lightbox', 'lightbox-dialog__content'], 'patterns/lightbox.css', true),\n use: '`.lightbox` thumbnails plus a `<dialog>`.',\n },\n comment: {\n css: c(['comment', 'comment__author', 'comment-thread'], 'patterns/comment.css', true),\n use: '`.comment` inside `.comment-thread`.',\n },\n tabs: {\n css: c(['tabs'], undefined, true),\n use: 'Generated pattern only; no structural partial and no component yet.',\n },\n nav: {\n css: c(['menu', 'navbar', 'nav-collapse', 'drawer-nav'], 'patterns/nav.css', true),\n use: '`.menu` / `.navbar`. See `navbar` and `navshell` for the newer shells.',\n },\n navbar: {\n css: c(['navbar', 'navbar--sticky', 'nav-items'], 'patterns/navbar.css'),\n use: '`.navbar` with `--start/--center/--end`.',\n },\n banner: {\n css: c(['banner', 'banner__content', 'banner__action'], 'patterns/banner.css', true),\n use: '`.banner`; wrap in `<wc-dismissable>` for a close button that works.',\n },\n table: {\n css: c(['table', 'table-wrapper'], 'patterns/table.css', true),\n use: '`.table` inside `.table-wrapper`. See `entries` for the responsive-to-table pattern.',\n },\n list: {\n css: c(['facet-list', 'filtered-list'], 'patterns/list.css', true),\n use: '`.facet-list` / `.filtered-list`.',\n },\n 'pull-quote': {\n css: c(['pull-quote', 'pull-quote__attribution'], 'patterns/pull-quote.css', true),\n use: '`.pull-quote`. Note the type role `quote` is separate.',\n },\n combobox: {\n css: c(['combobox', 'combobox__listbox', 'combobox__option'], 'patterns/combobox.css', true),\n use: 'CSS shell only — the Lit component is a TODO, so it is not interactive yet.',\n },\n forms: {\n css: c(['form-group', 'input-group', 'fieldset', 'custom-check'], 'patterns/forms.css', true),\n use: 'Wrap text controls in `.form-group` or `.input-group` — a bare `<input>` gets browser defaults.',\n },\n cluster: {\n css: c(['cluster', 'cluster-between', 'cluster-start'], 'patterns/cluster.css'),\n use: '`.cluster` plus an alignment variant.',\n },\n code: {\n css: c([], 'patterns/code.css'),\n use: 'Element selectors on `pre`/`code`; no class needed.',\n },\n grouped: {\n css: c(['group', 'group-inline', 'bordered'], 'patterns/grouped.css'),\n use: '`.group-inline` / `.group-block` to join adjacent controls.',\n },\n 'horizontal-scroll': {\n css: c(['horizontal-scroll'], 'patterns/horizontal-scroll.css'),\n use: '`.horizontal-scroll` for a snap strip.',\n },\n masonry: {\n css: c(['masonry', 'masonry__item'], 'patterns/masonry.css'),\n use: '`.masonry` — CSS columns based.',\n },\n media: {\n css: c(['media', 'media__figure', 'tile'], 'patterns/media.css'),\n use: '`.media` for a figure/body pair; `.tile` for the stacked form.',\n },\n overlay: { css: c(['overlay'], 'patterns/overlay.css'), use: '`.overlay` for a scrim.' },\n reveal: {\n css: c(['reveal', 'reveal-fade', 'reveal-h'], 'patterns/reveal.css'),\n use: '`.reveal` — scroll-driven, no JS. Hosts the `interpolate-size` that `<details>` animation needs.',\n },\n 'scroll-based': {\n css: c(['parallax', 'scroll-progress', 'scroll-spy'], 'patterns/scroll-based.css'),\n use: 'Scroll-timeline driven; no JS.',\n },\n 'scroll-target': {\n css: c(['scroll-target-group', 'toc-sidebar'], 'patterns/scroll-target.css'),\n use: '`.scroll-target-group` for `:target-current` highlighting.',\n },\n separator: {\n css: c(['separator', 'separator__text', 'separator__ornament'], 'patterns/separator.css'),\n use: '`.separator`, optionally with text or an ornament.',\n },\n stack: {\n css: c(['stack', 'stack__card'], 'patterns/stack.css'),\n use: '`.stack` for overlapping cards.',\n },\n sticky: {\n css: c(['sticky', 'sticky-header', 'sticky-nav'], 'patterns/sticky.css'),\n use: '`.sticky-header` etc. Pure CSS.',\n },\n svg: {\n css: c(['svg-container', 'svg-shape', 'svg-animated'], 'patterns/svg.css'),\n use: '`.svg-*` helpers for inline SVG.',\n },\n 'text-effects': {\n css: c(\n ['typing', 'text-highlight', 'text-gradient-animate', 'text-stagger'],\n 'patterns/text-effects.css',\n ),\n use: '`.typing`, `.text-highlight`, … CSS animation only.',\n },\n};\n\n/** Pattern names, sorted — a stable order for docs and tests. */\nexport const TIER_NAMES: readonly string[] = Object.keys(TIERS).sort();\n\n/** Every `wc-*` tag the manifest knows, whether shipped in `elements.js` or not. */\nexport function tierTags(): { tag: string; registered: boolean; pattern: string }[] {\n return Object.entries(TIERS)\n .filter(([, e]) => e.wc)\n .map(([pattern, e]) => ({ tag: e.wc!.tag, registered: e.wc!.registered, pattern }));\n}\n\n/** The four tiers, as a projection axis. */\nexport type Tier = 'css' | 'wc' | 'astro' | 'bricks';\n\n/** A pattern paired with its entry — what one tier's projection iterates. */\nexport interface TierProjection {\n name: string;\n entry: TierEntry;\n}\n\n/**\n * The patterns one tier provides, in `TIER_NAMES` order.\n *\n * Every renderer goes through this rather than filtering `TIERS` itself: the docs\n * bundle projects all four tiers into one table for agents, the docsite projects\n * each tier as its own page for humans, and they must agree about which patterns\n * are in a tier. Five copies of `.filter(e => e.wc)` would agree until one of them\n * didn't.\n *\n * `css` needs a predicate rather than a presence check, which is the non-obvious\n * part. `TierEntry.css` is required, so *every* entry has one — including the\n * editor-v2 track, whose entries carry `c([])`: no partial, no classes, not\n * generated. Treating the field's presence as membership would list four patterns\n * on the CSS page with nothing to show for them, and `color-wheel` genuinely has\n * no CSS. The other three tiers are optional fields, so presence is the test.\n */\nexport function tierPatterns(tier: Tier): TierProjection[] {\n const has = (e: TierEntry): boolean => {\n switch (tier) {\n case 'css':\n return !!e.css.partial || e.css.classes.length > 0 || e.css.generated;\n case 'wc':\n return !!e.wc;\n case 'astro':\n return !!e.astro?.length;\n case 'bricks':\n return !!e.bricks;\n }\n };\n return TIER_NAMES.filter((name) => has(TIERS[name]!)).map((name) => ({\n name,\n entry: TIERS[name]!,\n }));\n}\n","/**\n * OKF documentation bundle generator (ported from the repo's `generate-docs.ts`).\n *\n * Pure: `generateDocs(ds, assetsDir)` returns a `{ relPath: markdown }` map for the\n * Open Knowledge Format tree (top index, css/, bricks/), reading the Bricks element\n * PHP from `<assetsDir>/bricks/elements`. No filesystem writes — the caller decides\n * where the bundle lands (e.g. `<outDir>/docs`).\n */\nimport { readFileSync, readdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { jsonSchema, SCHEMA_URL, type DesignSystem } from './schema.ts';\nimport { configJsonSchema, CONFIG_SCHEMA_URL } from './config.ts';\nimport { BASE_HOOK, DARK_SEL, REQUIRED_ROLES, SYSTEM_DARK_SEL, TW_CLASH } from './shared.ts';\nimport { expandPalette } from './tokens.ts';\nimport { TIERS, TIER_NAMES, tierPatterns } from './tiers.ts';\n\nconst DS_PATH = 'design-system.json';\n/** The `resource` a config-reference doc points at. Consumers rename it freely. */\nconst CONFIG_PATH = 'site.json';\n\n// Curated element display order (by $name, sans the vitops- prefix). Unlisted\n// elements fall to the end alphabetically so new ones still appear.\nconst ORDER = [\n 'split',\n 'centered',\n 'carousel',\n 'wc-color-scheme-toggle',\n 'wc-copy',\n 'dismissable',\n 'entries',\n 'image-compare',\n 'sitenav',\n 'wc-multi-field',\n 'split-link',\n 'split-panel',\n];\n\n// ── PHP array-literal parser ─────────────────────────────────────────────────\ntype Json = string | number | boolean | null | Json[] | { [k: string]: Json };\n\ninterface Tok {\n t: 'str' | 'num' | 'id' | 'punc' | 'arrow';\n v: string;\n}\n\nfunction tokenize(src: string): Tok[] {\n const toks: Tok[] = [];\n let i = 0;\n const n = src.length;\n while (i < n) {\n const c = src[i] as string;\n if (c === ' ' || c === '\\t' || c === '\\n' || c === '\\r') {\n i++;\n continue;\n }\n if (c === '/' && src[i + 1] === '/') {\n while (i < n && src[i] !== '\\n') i++;\n continue;\n }\n if (c === '#') {\n while (i < n && src[i] !== '\\n') i++;\n continue;\n }\n if (c === '/' && src[i + 1] === '*') {\n i += 2;\n while (i < n && !(src[i] === '*' && src[i + 1] === '/')) i++;\n i += 2;\n continue;\n }\n if (c === \"'\" || c === '\"') {\n const quote = c;\n i++;\n let s = '';\n while (i < n && src[i] !== quote) {\n if (src[i] === '\\\\' && i + 1 < n) {\n const next = src[i + 1];\n s += next === 'n' ? '\\n' : next === 't' ? '\\t' : next;\n i += 2;\n } else {\n s += src[i++];\n }\n }\n i++;\n toks.push({ t: 'str', v: s });\n continue;\n }\n if (c === '=' && src[i + 1] === '>') {\n toks.push({ t: 'arrow', v: '=>' });\n i += 2;\n continue;\n }\n if ('[](){},'.includes(c)) {\n toks.push({ t: 'punc', v: c });\n i++;\n continue;\n }\n if (\n (c >= '0' && c <= '9') ||\n (c === '-' && (src[i + 1] as string) >= '0' && (src[i + 1] as string) <= '9')\n ) {\n let s = c;\n i++;\n while (i < n && (src[i] as string) >= '0' && (src[i] as string) <= '9') s += src[i++];\n toks.push({ t: 'num', v: s });\n continue;\n }\n if (/[A-Za-z_\\\\]/.test(c)) {\n let s = c;\n i++;\n while (i < n && /[A-Za-z0-9_\\\\]/.test(src[i] as string)) s += src[i++];\n toks.push({ t: 'id', v: s });\n continue;\n }\n i++;\n }\n return toks;\n}\n\nclass Parser {\n p = 0;\n toks: Tok[];\n constructor(toks: Tok[]) {\n this.toks = toks;\n }\n peek(): Tok | undefined {\n return this.toks[this.p];\n }\n next(): Tok | undefined {\n return this.toks[this.p++];\n }\n parseValue(): Json {\n const t = this.peek();\n if (!t) return null;\n if (t.t === 'str') {\n this.next();\n return t.v;\n }\n if (t.t === 'num') {\n this.next();\n return Number(t.v);\n }\n if (t.t === 'id') {\n this.next();\n if (t.v === 'true') return true;\n if (t.v === 'false') return false;\n if (t.v === 'null') return null;\n if (this.peek()?.t === 'punc' && this.peek()?.v === '(') {\n this.next();\n if (t.v === 'array') return this.parseBody(')');\n const args = this.parseCallArgs();\n return args.find((a) => typeof a === 'string') ?? args[0] ?? '';\n }\n return t.v;\n }\n if (t.t === 'punc' && t.v === '[') {\n this.next();\n return this.parseBody(']');\n }\n if (t.t === 'punc' && t.v === '(') {\n this.next();\n return this.parseBody(')');\n }\n this.next();\n return null;\n }\n private parseCallArgs(): Json[] {\n const args: Json[] = [];\n while (this.peek() && !(this.peek()!.t === 'punc' && this.peek()!.v === ')')) {\n args.push(this.parseValue());\n if (this.peek()?.t === 'punc' && this.peek()?.v === ',') this.next();\n }\n this.next();\n return args;\n }\n private parseBody(close: string): Json {\n const list: Json[] = [];\n const map: Record<string, Json> = {};\n let keyed = false;\n while (this.peek() && !(this.peek()!.t === 'punc' && this.peek()!.v === close)) {\n const first = this.parseValue();\n if (this.peek()?.t === 'arrow') {\n this.next();\n const val = this.parseValue();\n // PHP array keys are scalars; stringify objects defensively.\n map[typeof first === 'object' && first !== null ? JSON.stringify(first) : String(first)] =\n val;\n keyed = true;\n } else {\n list.push(first);\n }\n if (this.peek()?.t === 'punc' && this.peek()?.v === ',') this.next();\n }\n this.next();\n return keyed ? map : list;\n }\n}\n\nfunction parsePhpLiteral(text: string): Json {\n return new Parser(tokenize(text)).parseValue();\n}\n\n// ── Source-region helpers ────────────────────────────────────────────────────\nfunction matchBalanced(src: string, open: number): number {\n const pairs: Record<string, string> = { '(': ')', '[': ']', '{': '}' };\n const stack: string[] = [];\n let i = open;\n const n = src.length;\n while (i < n) {\n const c = src[i] as string;\n if (c === '/' && src[i + 1] === '/') {\n while (i < n && src[i] !== '\\n') i++;\n continue;\n }\n if (c === '/' && src[i + 1] === '*') {\n i += 2;\n while (i < n && !(src[i] === '*' && src[i + 1] === '/')) i++;\n i += 2;\n continue;\n }\n if (c === \"'\" || c === '\"') {\n i++;\n while (i < n && src[i] !== c) {\n if (src[i] === '\\\\') i++;\n i++;\n }\n i++;\n continue;\n }\n if (c in pairs) stack.push(pairs[c] as string);\n else if (c === ')' || c === ']' || c === '}') {\n if (stack.pop() !== c) {\n /* unbalanced — best effort */\n }\n if (stack.length === 0) return i + 1;\n }\n i++;\n }\n return n;\n}\n\nfunction methodBody(src: string, name: string): string | null {\n const m = new RegExp(`function\\\\s+${name}\\\\s*\\\\([^)]*\\\\)`).exec(src);\n if (!m) return null;\n const brace = src.indexOf('{', m.index + m[0].length);\n if (brace < 0) return null;\n const end = matchBalanced(src, brace);\n return src.slice(brace + 1, end - 1);\n}\n\nfunction literalAt(src: string, fromIdx: number): { text: string; end: number } | null {\n let i = fromIdx;\n while (i < src.length && /\\s/.test(src[i] as string)) i++;\n let open: number;\n if (src[i] === '[') open = i;\n else if (src.startsWith('array', i)) open = src.indexOf('(', i);\n else return null;\n const end = matchBalanced(src, open);\n return { text: src.slice(i, end), end };\n}\n\n// ── Per-element extraction ───────────────────────────────────────────────────\ninterface Control {\n key: string;\n def: Record<string, Json>;\n}\ninterface Element {\n name: string;\n label: string;\n nestable: boolean;\n docblock: string;\n controls: Control[];\n cssClass: string | null;\n children: string[];\n keywords: string[];\n}\n\nfunction firstString(re: RegExp, src: string): string | null {\n const m = re.exec(src);\n return m ? (m[1] ?? null) : null;\n}\n\nfunction extractDocblock(src: string): string {\n const m = /\\/\\*\\*([\\s\\S]*?)\\*\\//.exec(src);\n if (!m) return '';\n const lines = (m[1] as string)\n .split('\\n')\n .map((l) => l.replace(/^\\s*\\*?\\s?/, '').replace(/\\s+$/, ''));\n while (lines.length && lines[0] === '') lines.shift();\n if (lines.length && /Bricks Builder\\)\\./.test(lines[0] as string)) lines.shift();\n const owned = lines.findIndex((l) => l.startsWith('Owned by the framework repo'));\n const kept = (owned >= 0 ? lines.slice(0, owned) : lines).map((l) => l.replace(/^•\\s*/, '- '));\n while (kept.length && kept[kept.length - 1] === '') kept.pop();\n while (kept.length && kept[0] === '') kept.shift();\n return kept.join('\\n');\n}\n\nfunction extractControls(src: string): Control[] {\n const body = methodBody(src, 'set_controls');\n if (!body) return [];\n const controls: Control[] = [];\n const re = /\\$this->controls\\[\\s*'([^']+)'\\s*\\](\\[\\s*'([^']+)'\\s*\\])?\\s*=\\s*/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(body))) {\n const key = m[1] as string;\n if (m[2]) continue;\n const lit = literalAt(body, m.index + m[0].length);\n if (!lit) continue;\n const def = parsePhpLiteral(lit.text);\n if (def && typeof def === 'object' && !Array.isArray(def))\n controls.push({ key, def: def as Record<string, Json> });\n re.lastIndex = lit.end;\n }\n return controls;\n}\n\nfunction extractChildren(src: string): string[] {\n const body = methodBody(src, 'get_nestable_children');\n if (!body) return [];\n const labels: string[] = [];\n const re = /'label'\\s*=>\\s*esc_html__\\(\\s*'([^']*)'/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(body))) labels.push(m[1] as string);\n return labels;\n}\n\nfunction extractKeywords(src: string): string[] {\n const body = methodBody(src, 'get_keywords');\n if (!body) return [];\n const ret = /return\\s+/.exec(body);\n if (!ret) return [];\n const lit = literalAt(body, ret.index + ret[0].length);\n if (!lit) return [];\n const arr = parsePhpLiteral(lit.text);\n return Array.isArray(arr) ? arr.filter((x): x is string => typeof x === 'string') : [];\n}\n\nfunction parseElement(src: string): Element | null {\n const name = firstString(/public\\s+\\$name\\s*=\\s*'vitops-([^']+)'/, src);\n if (!name) return null;\n return {\n name,\n label:\n firstString(/function get_label\\(\\)[\\s\\S]*?return\\s+esc_html__\\(\\s*'([^']*)'/, src) ?? name,\n nestable: /public\\s+\\$nestable\\s*=\\s*true/.test(src),\n docblock: extractDocblock(src),\n controls: extractControls(src),\n cssClass: firstString(\n /\\$this->controls\\[\\s*'_cssClasses'\\s*\\]\\[\\s*'default'\\s*\\]\\s*=\\s*'([^']*)'/,\n src,\n ),\n children: extractChildren(src),\n keywords: extractKeywords(src),\n };\n}\n\n// ── Markdown rendering ───────────────────────────────────────────────────────\n/** Stringify a parsed-PHP Json value for prose (objects → JSON, not [object Object]). */\nconst asText = (v: Json | undefined): string =>\n v == null ? '' : typeof v === 'object' ? JSON.stringify(v) : String(v);\n\nfunction controlLine(c: Control): string {\n const def = c.def;\n if (def.type === 'info') return `- _Note:_ ${asText(def.content)}`;\n const label = (def.label as string) || c.key;\n const options =\n def.options && typeof def.options === 'object' && !Array.isArray(def.options)\n ? (def.options as Record<string, string>)\n : null;\n const meta: string[] = [];\n let type = (def.type as string) || 'text';\n if (def.units === true) type += '+units';\n meta.push(type);\n if (def.default !== undefined) {\n const raw = asText(def.default);\n const shown = options && options[raw] ? options[raw] : raw;\n meta.push(`default \\`${shown}\\``);\n }\n if (def.placeholder !== undefined && def.placeholder !== '')\n meta.push(`placeholder \\`${asText(def.placeholder)}\\``);\n if (def.min !== undefined || def.max !== undefined)\n meta.push(\n `range ${def.min != null ? asText(def.min) : '–'}–${def.max != null ? asText(def.max) : '∞'}`,\n );\n const tail: string[] = [];\n if (def.description) tail.push(asText(def.description));\n if (options)\n tail.push(\n `Options: ${Object.values(options)\n .map((o) => `\\`${o}\\``)\n .join(', ')}.`,\n );\n if (Array.isArray(def.css) && def.css.length) {\n const first = def.css[0];\n if (first && typeof first === 'object' && !Array.isArray(first) && 'property' in first)\n tail.push(`Bound to \\`${asText((first as Record<string, Json>).property)}\\`.`);\n }\n if (def.type === 'repeater' && def.fields && typeof def.fields === 'object') {\n const fields = Object.values(def.fields as Record<string, Json>)\n .map((f) =>\n f && typeof f === 'object' && !Array.isArray(f)\n ? asText((f as Record<string, Json>).label)\n : null,\n )\n .filter(Boolean);\n if (fields.length) tail.push(`Fields: ${fields.join(', ')}.`);\n }\n const head = `- **${label}** (${meta.join(', ')})`;\n return tail.length ? `${head} — ${tail.join(' ')}` : head;\n}\n\nfunction renderElement(el: Element): string {\n const out: string[] = [];\n const nest = el.nestable ? 'nestable' : 'not nestable';\n out.push(`## ${el.label} — \\`vitops-${el.name}\\` · ${nest}`);\n out.push('');\n if (el.docblock) {\n out.push(el.docblock);\n out.push('');\n }\n const real = el.controls.filter((c) => c.def.type !== 'info');\n if (real.length) {\n out.push('**Controls**');\n out.push('');\n for (const c of el.controls) out.push(controlLine(c));\n out.push('');\n } else {\n const notes = el.controls.filter((c) => c.def.type === 'info');\n if (notes.length) {\n for (const c of notes) out.push(controlLine(c));\n out.push('');\n }\n }\n if (el.cssClass) {\n out.push(\n `**Base CSS class:** \\`${el.cssClass}\\` (applied automatically; add ratio/modifier classes alongside it in the element's \"CSS classes\" field).`,\n );\n out.push('');\n }\n if (el.children.length) {\n out.push(`**Seeded children:** ${el.children.join(', ')}.`);\n out.push('');\n }\n if (el.keywords.length) {\n out.push(`**Keywords:** ${el.keywords.filter((k) => k !== 'vitops').join(', ')}.`);\n out.push('');\n }\n return out.join('\\n');\n}\n\n// ── OKF helpers ──────────────────────────────────────────────────────────────\ninterface Frontmatter {\n type: string;\n title: string;\n description: string;\n resource?: string;\n tags?: string[];\n}\nfunction frontmatter(fm: Frontmatter): string {\n const q = (s: string) => `\"${s.replace(/\"/g, '\\\\\"')}\"`;\n const lines = [\n `type: ${q(fm.type)}`,\n `title: ${q(fm.title)}`,\n `description: ${q(fm.description)}`,\n ];\n if (fm.resource) lines.push(`resource: ${q(fm.resource)}`);\n if (fm.tags) lines.push(`tags: [${fm.tags.join(', ')}]`);\n lines.push('generator: \"@getvitops/generator\"');\n return `---\\n${lines.join('\\n')}\\n---`;\n}\n\nconst INDEX_NOTE = `<!-- GENERATED by @getvitops/generator — do not edit; regenerate with \\`vitops generate\\`. -->`;\n\nconst ELEMENTS_FRONTMATTER = frontmatter({\n type: 'Bricks Elements Reference',\n title: 'Vitops — Bricks Builder elements reference',\n description:\n 'Every repo-owned Bricks element, its controls, defaults, seeded children and keywords, for driving the Bricks Builder UI.',\n resource: 'bricks/elements',\n tags: ['bricks', 'wordpress', 'elements', 'design-system'],\n});\n\nconst ELEMENTS_PREAMBLE = `${ELEMENTS_FRONTMATTER}\n\n# Vitops — Bricks Builder elements reference\n\nContext for driving the Bricks Builder UI (e.g. Claude for Chrome). Every section below\nis generated from the element's own source, so this reference always matches the elements\ncurrently deployed. See also the CSS class vocabulary in [/css/classes.md](../css/classes.md)\nand the integration guidance in [/bricks/index.md](index.md).\n\n## How they appear in the builder\n\n- The elements register from \\`dist/bricks/load.php\\` and group under a **\"Vitops\"** category\n pinned to the **top** of the element panel. Insert one by searching its **label** (e.g.\n \"Split\", \"Carousel\") or any of its **keywords** (listed per element).\n- Two rendering families:\n - **Web-component elements** render a Lit custom element (\\`<wc-*>\\`, \\`<wc-copy>\\`, …)\n from \\`dist/elements.js\\` and progressively enhance. A few (Image Compare, Split Panel)\n show their children stacked in the builder canvas until the client-side upgrade runs —\n that is expected, not broken.\n - **CSS-pattern elements** (Split, Centered, Menu, Split Link) render plain markup styled\n by the framework CSS — no JS dependency.\n- **Nestable** elements accept child elements dropped into them; some seed starter children\n (listed as \"Seeded children\"). **Non-nestable** elements are configured entirely through\n their controls.\n\n## Configuring layout\n\nSome layout is set through **controls**; some through **CSS classes typed into the element's\nbuilt-in \"CSS classes\" field** (called out per element as modifier classes). Responsive\nsuffixes on those classes engage from a container breakpoint: \\`-sm\\` = 30rem, \\`-md\\` = 48rem,\n\\`-lg\\` = 64rem, \\`-xl\\` = 80rem.\n\nEach control below lists its type, default/placeholder, any select options, and the CSS\ncustom property it writes (when it drives one). Info notes flagged _Note:_ carry the\nmodifier-class and structural guidance from the element itself.\n\n---\n`;\n\nfunction renderElementsDoc(elementsDir: string): string {\n const files = existsSync(elementsDir)\n ? readdirSync(elementsDir).filter((f) => f.endsWith('.php'))\n : [];\n const elements: Element[] = [];\n for (const f of files) {\n try {\n const el = parseElement(readFileSync(join(elementsDir, f), 'utf8'));\n if (el) elements.push(el);\n } catch {\n /* skip unparseable element */\n }\n }\n elements.sort((a, b) => {\n const ia = ORDER.indexOf(a.name);\n const ib = ORDER.indexOf(b.name);\n if (ia >= 0 && ib >= 0) return ia - ib;\n if (ia >= 0) return -1;\n if (ib >= 0) return 1;\n return a.name.localeCompare(b.name);\n });\n const body = elements.map(renderElement).join('\\n---\\n\\n');\n return `${ELEMENTS_PREAMBLE}\\n${body}`;\n}\n\n// ── CSS framework reference (rule-summarized, from the config) ────────────────\nconst code = (xs: string[]) => xs.map((x) => `\\`${x}\\``).join(', ');\n\nfunction renderCssClasses(ds: DesignSystem): string {\n const expanded = expandPalette(ds.colors.palette as Record<string, unknown>);\n const ramps = Object.keys(expanded);\n const roles = Object.keys(ds.colors.roles ?? {});\n const utils = ds.colors.utilities ?? ['bg', 'text', 'icon', 'border'];\n const typeRoles = Object.keys(ds.typography?.roles ?? {});\n const shadows = Object.keys(ds.shadows ?? {});\n const effects = Object.keys(ds.animations?.effects ?? {});\n // Split by keyframe family, because only composite/paint effects get the\n // hover-/focus-/active- state variants — `.transition` deliberately doesn't\n // transition `height`, so a `hover-size-grow` would be a class that resolves\n // to nothing. Listing every effect under \"with the state prefixes above\" is\n // what sent the docs site rendering exactly that.\n const stateful = Object.entries(ds.animations?.effects ?? {})\n .filter(([, e]) => e.kf === 'composite' || e.kf === 'paint')\n .map(([name]) => name);\n const keyframeOnly = effects.filter((name) => !stateful.includes(name));\n const items = (ds.patterns?.items ?? {}) as Record<\n string,\n { roles?: string[]; default_role?: string }\n >;\n const patterns = Object.keys(items);\n const patternRoles = Array.from(\n new Set(\n Object.values(items).flatMap(\n (p) => [p.default_role, ...(p.roles ?? [])].filter(Boolean) as string[],\n ),\n ),\n );\n const spaceNames = ds.spaceScale?.names ?? [];\n const typeNames = ds.typeScale?.names ?? [];\n const families = Object.keys(ds.typography?.families ?? {});\n const radii = Object.keys(ds.patterns?.radii ?? {});\n\n return `${frontmatter({\n type: 'CSS Framework Reference',\n title: 'Vitops CSS framework — class vocabulary',\n description:\n 'Every utility and component class in the Vitops CSS framework, stated as a naming rule over the design tokens it expands.',\n resource: DS_PATH,\n tags: ['css', 'utilities', 'patterns', 'design-system'],\n })}\n\n# Vitops CSS framework — class vocabulary (LLM reference)\n\nA variable-driven CSS framework. Classes encode the design system's **tokens** (colour,\ntype, space, shadow), **responsive grammar**, and **interaction states** — so styling with\nthese classes stays consistent and theme-/dark-mode-aware. Prefer them over hand-written\nCSS or ad-hoc property values.\n\nThis is a **rule reference**, not an exhaustive list: each family below is a naming rule\nplus the set of tokens it expands over. Applying a rule to any listed token yields a valid\nclass (e.g. rule \\`bg-<color>\\` + colour \\`pine-xl\\` → \\`bg-pine-xl\\`).\n\nThe tokens themselves are authored in \\`design-system.json\\` — see\n[/authoring.md](../authoring.md); the systems behind them are explained in\n[/concepts/](../concepts/index.md); per-format output differences (including which of\nthese utilities Tailwind provides natively) in [/formats.md](../formats.md).\n\n## Responsive & state variant grammar\n\nEvery utility accepts a **container-breakpoint prefix**; animation utilities also accept a\n**state prefix**. In CSS/Bricks the separator is \\`-\\`; in Tailwind it is \\`:\\` / \\`@\\`.\n\n| Intent | CSS / Bricks | Tailwind |\n| ----------------- | -------------------------- | ----------------------------------------- |\n| responsive split | \\`md-split-1-2\\` | \\`@md:split-1-2\\` |\n| responsive align | \\`md-items-center\\` | \\`@md:items-center\\` |\n| hover effect | \\`transition hover-fade-in\\` | \\`transition fade-in hover:flip-fade-in\\` |\n\n- Breakpoint prefixes (bare): \\`sm-\\` = 30rem, \\`md-\\` = 48rem, \\`lg-\\` = 64rem, \\`xl-\\` = 80rem.\n- State prefixes (animation effects only): \\`hover-\\`, \\`active-\\`, \\`focus-\\`, and \\`flip-<effect>\\`\n (plays the effect in reverse on toggle). Effects require \\`transition\\` on the element.\n\n## Layout & structure\n\n- **\\`centered\\`** — named-track grid centering content in the reading \\`measure\\` track.\n Widen a **direct child** by adding \\`breakout\\`, \\`spotlight\\`, or \\`fullbleed\\` (each\n breakpoint-prefixable) to that child. Track widths are set via \\`--width-measure\\` /\n \\`--width-breakout\\` / \\`--width-spotlight\\` and \\`--gutter\\`.\n- **\\`rhythm\\`** — relationship-based vertical spacing (margins between headings, paragraphs,\n lists, media) driven by the space scale. Usually paired with \\`centered\\`.\n- **\\`split\\`** — a two-column pair. Ratio rule: **\\`split-<a>-<b>\\`** where \\`<a>-<b>\\` ∈\n \\`1-2\\`, \\`2-1\\`, \\`1-3\\`, \\`3-1\\`, \\`1-4\\`, \\`4-1\\`, \\`2-3\\`, \\`3-2\\` (breakpoint-prefixable); equal\n columns without one. The ratio is a flex **basis**, so a column's padding counts\n inside its share, and \\`min-inline-size: 0\\` is built in so long unbreakable content\n can't stretch a column past it.\n - **Stacking is \\`flex-col\\`** — there is no split-specific class for it:\n \\`class=\"split flex-col md-split-1-2\"\\` is stacked below 48rem and 1:2 above,\n because the \\`<bp>-\\` ratio classes assert the row. While stacked the ratio goes\n inert on its own (a percentage basis against an auto-height column resolves as\n \\`content\\`), unless you give the split a definite \\`block-size\\`.\n - **\\`split-reverse\\`** — swaps the two panels (breakpoint-prefixable). Implemented\n as \\`order\\` on the first child, so it reverses on whichever axis the split is\n currently on: bare, it swaps the columns in a row AND the rows in a stack;\n scoped (\\`md-split-reverse\\`) it swaps only once there are two columns — media\n first in source so it leads on mobile, on the right at width. The ratio stays\n with the source-first child, not with the visual position.\n - **Accessibility:** reversing makes visual order disagree with DOM order, and\n focus order follows the DOM (WCAG 2.4.3 Focus Order). Put focusable content in\n **only one** of the two panels, or the tab order will not be linear. The\n pattern declares \\`reading-flow: flex-visual\\`, which fixes this properly where\n it is supported; support is not yet broad enough to rely on.\n- **Flex** — \\`flex\\`, \\`flex-row\\`, \\`flex-col\\`, \\`flex-row-reverse\\`, \\`flex-col-reverse\\`\n (all breakpoint-prefixable).\n- **Alignment** — \\`items-{start,center,end,stretch}\\`, \\`justify-{start,center,end,between}\\`,\n text align \\`text-{start,center,end}\\` (all breakpoint-prefixable).\n- **Display** — \\`block\\`, \\`inline\\`, \\`inline-block\\`, \\`flex\\`, \\`grid\\`, \\`hidden\\`\n (breakpoint-prefixable, e.g. \\`md-hidden\\`).\n- **Accessibility** — \\`sr-only\\` / \\`not-sr-only\\` (breakpoint-prefixable).\n- **State hooks** — \\`is-active\\`, \\`is-open\\` (styling flags toggled by JS / native state).\n\n## Spacing\n\nThe space scale is ${code(spaceNames)} exposed as \\`--space-<name>\\` tokens.\n\\`rhythm\\` margins consume these tokens; prefer \\`rhythm\\` for vertical flow rather than\nper-element margins.\n\nRule: **\\`gap-<name>\\`**, **\\`gap-x-<name>\\`** (column) and **\\`gap-y-<name>\\`** (row), name ∈\n${code(spaceNames)} — all breakpoint-prefixable (\\`md-gap-l\\`, \\`@md:gap-l\\`). These are the\nframework's own utilities in every format: the fluid steps are deliberately kept out of\nTailwind's \\`--spacing-*\\` namespace (named keys there shadow the size scales, so\n\\`max-w-7xl\\` would resolve to \\`var(--spacing-7xl)\\`), which means Tailwind's numeric\n\\`gap-4\\` still uses its own multiplier and coexists with these.\n\n## Typography\n\nRule: **\\`font-<role>\\`** — role ∈ ${code(typeRoles)}. Each role carries its own family,\nsize (from the type scale ${code(typeNames)}), tracking, transform, weight and \\`text-wrap\\`.\nFamilies: ${code(families)} (\\`--font-*\\`).\n\nBecause the role owns \\`text-wrap\\`, a heading is balanced and copy is \\`pretty\\` with **no\nclass at all** wherever \\`typography.headings\\` maps the bare element to a role. Override one\nelement with \\`text-{wrap,nowrap,balance,pretty}\\` — the per-element escape hatch, for markup\nthat carries no role class. (These four are Tailwind's own in the tailwind format.)\n\n## Colour\n\n**Functional tokens are the primary vocabulary** — classes name the *job*, not the tone, and\nevery one remaps automatically under \\`${DARK_SEL}\\` (background/text ends\nswap; \\`solid\\` fills stay mode-stable with a computed \\`on-\\` foreground). Prefer these over\nraw steps.\n\n**Role names are yours.** \\`colors.roles\\` is an open map: add a key, and the generator emits\nthat role's full token set, its dark flip and every utility below. Your config\ncurrently defines ${code(roles)}. Six of those are a **required core** — the framework's own\ncomponent CSS references \\`${REQUIRED_ROLES.join('`, `')}\\` with no fallback, so removing one\nleaves those components uncoloured (\\`vitops validate\\` warns). Everything beyond them is free.\n\nThe rule is one shape — **\\`<target>-<role>[-<variant>]\\`**, target ∈ \\`bg\\` \\`text\\` \\`icon\\`\n\\`border\\` — and the class name is exactly its token name minus \\`--color-\\`. Variants are\nordinal (\\`xx-muted\\` < \\`x-muted\\` < \\`muted\\` < bare < \\`bold\\` < \\`x-bold\\`) and sparse: only the\ncells that hold their contrast target exist.\n\n**Which cells exist depends on the role's \\`kind\\`:**\n\n*Surface roles* (page and panel colours):\n\n- **Backgrounds** — \\`bg-<role>\\` (the card/panel), \\`bg-<role>-muted\\` (the page behind it),\n \\`bg-<role>-x-muted\\` (well / inset), \\`bg-<role>-bold\\` and \\`-x-bold\\` (inverse surface).\n Elevation is *which* token you reach for, not a raised/sunken pair.\n- **Content** — \\`text-<role>\\` (body), \\`text-<role>-bold\\`, \\`text-<role>-muted\\` (secondary),\n \\`text-<role>-x-muted\\` (placeholder) and \\`-xx-muted\\` (disabled). The last two are\n contrast-exempt by design.\n- **Borders** — \\`border-<role>-muted\\` (hairline), \\`border-<role>\\`, \\`border-<role>-bold\\`\n (the one guaranteed to carry a boundary on its own).\n\n*Chromatic roles* (signal colours) — **there is no bare \\`bg-<role>\\`**; say tint or solid:\n\n- **Tints** — \\`bg-<role>-x-muted\\` (alert wash), \\`bg-<role>-muted\\` (badge).\n- **Solids** — \\`bg-<role>-solid\\`, \\`-solid-bold\\` (hover), \\`-solid-x-bold\\` (active), each\n pairing with \\`text-on-<role>\\` for a guaranteed-contrast foreground.\n- **Content** — \\`text-<role>\\`, \\`text-<role>-bold\\`. There is deliberately no\n \\`text-<role>-muted\\`: it could not hold its contrast target off a light surface, so soften\n coloured text with weight or size instead.\n- **Borders** — \\`border-<role>\\`, \\`border-<role>-bold\\` (decorative status edges).\n\nBoth kinds also get **\\`icon-<role>\\`** — a separate non-text tier, so a glyph may run more\nvivid than text — plus \\`glass\\` (translucent surface + backdrop blur), the \\`--overlay\\` scrim\nand \\`--color-border-focus\\` for focus rings.\n\nEveryday pairings, using the roles this config defines: page\n\\`bg-${roles[0] ?? 'neutral'}-muted\\`, cards \\`bg-${roles[0] ?? 'neutral'}\\` on top of it, body\n\\`text-${roles[0] ?? 'neutral'}\\`, captions \\`text-${roles[0] ?? 'neutral'}-muted\\`; buttons\n\\`bg-${roles[2] ?? roles[0] ?? 'ui-primary'}-solid text-on-${roles[2] ?? roles[0] ?? 'ui-primary'}\\`;\nalerts \\`bg-danger-x-muted text-danger\\`.\n\n**Raw scale** (secondary / fine control) — rule \\`<util>-<hue>-<step>\\` with util ∈\n${code(utils)}: every hue is an 11-step OKLCH scale generated from its seed (or fixed brand\ntones), numeric steps \\`50\\` … \\`950\\` (tinted near-white → tinted near-black) — e.g.\n\\`bg-${ramps[0] ?? 'brand'}-100\\`, \\`text-${ramps[0] ?? 'brand'}-800\\`. Hues: ${code(ramps)}.\n\n> **Raw scale classes are frozen — they do NOT remap in dark mode.**\n> \\`bg-${ramps[0] ?? 'brand'}-800\\` is that exact colour in every appearance. The automatic\n> dark flip described above applies **only** to the functional role tokens, because\n> \\`--color-<hue>-<step>\\` is emitted once and never re-pointed under \\`${DARK_SEL}\\`.\n> A raw step on a page that can switch appearance is a latent bug: it looks correct in\n> whichever mode you built it in and inverts in the other.\n>\n> If you are reaching for a raw step, you usually want a **role** instead — and roles are\n> extensible, so adding one is a two-line config change:\n>\n> | instead of | use | why |\n> | --- | --- | --- |\n> | \\`bg-<hue>-50\\` / \\`-950\\` | \\`bg-<role>\\` (surface kind) | the card plane, flips automatically |\n> | \\`bg-<hue>-100\\` / \\`-900\\` | \\`bg-<role>-muted\\` | the page, or a chromatic tint |\n> | \\`bg-<hue>-500\\`…\\`-700\\` | \\`bg-<role>-solid\\` | vivid fill, mode-stable, pairs with \\`text-on-<role>\\` |\n> | \\`text-<hue>-950\\` / \\`-50\\` | \\`text-<role>\\` | contrast-guaranteed body text |\n> | \\`text-<hue>-800\\` / \\`-200\\` | \\`text-<role>-muted\\` | secondary text |\n> | \\`border-<hue>-200\\` / \\`-800\\` | \\`border-<role>\\` | |\n>\n> Raw steps stay the right tool for genuinely fixed colours — a brand mark, a chart series,\n> an illustration — where the value must not move between appearances.\n\n## Shadows\n\nRule: **\\`drop-shadow-<size>\\`** — size ∈ ${code(shadows)} (applied as a \\`filter\\`, so it\nfollows non-rectangular shapes).\n\n## Animation\n\nAn effect carries no motion of its own — it sets \\`--<prop>-from\\`/\\`-to\\` and picks a keyframe.\nA **driver** supplies the motion, and you always compose one of each:\n\n- \\`animate-view\\` — plays as the element crosses the viewport\n- \\`animate-scroll\\` — scrubs against page scroll\n- \\`animate-trigger\\` — time-based; plays once when \\`.is-active\\` / \\`[data-active]\\` is set\n- \\`transition\\` — transitions the same from/to vars, so it reverses on a state flip\n\nRule: **\\`<effect>\\`** — effect ∈ ${code(effects)}. The state/flip prefixes above pair with\n\\`transition\\` and apply to every one of them.\n\nEach state matches the element **or its direct parent** (\\`.hover-<fx>:hover, :hover > .hover-<fx>\\`),\nwhich is what makes \\`reveal-*\\` usable: it rests at a zero-area \\`clip-path\\`, and \\`clip-path\\` clips\nhit-testing as well as painting, so the element itself can never be hovered.${\n keyframeOnly.length\n ? `\n\n${code(keyframeOnly)} animate \\`height\\`, the only stage that reflows and the only one behind a\nfeature gate: \\`0 → auto\\` is not interpolable without \\`interpolate-size: allow-keywords\\`, so\n\\`transition\\` declares \\`height\\` only inside an \\`@supports\\` for it. The \\`layout\\` **keyframe**\nhas the same dependency — this is not a limit of the transition driver.`\n : ''\n }\n\n**When it plays.** \\`animate-view\\` and \\`.is-active\\` are both timed off the element's **midpoint**:\nmotion starts once that midpoint is 10% of the viewport in, and a one-shot entrance completes at\n25%. Both stops are the element's position on screen rather than a fraction of its own height, so a\nsmall card and a full-bleed section behave alike. Shift the window with \\`--anim-start\\` /\n\\`--anim-end\\`, or replace it outright with \\`--anim-range\\`.\n\nComposed **journeys** chain multiple effects into one entrance: rule \\`<parts>-journey\\`\n(e.g. \\`fade-slide-journey\\`, \\`fade-scale-blur-journey\\`). They need a **keyframe** driver, not\n\\`transition\\`. A journey is entry → hold → exit, so it starts on that same 10% pivot but runs to the\nend of the exit phase — the hold occupies the middle of the crossing instead of the bottom edge of\nthe screen.\n\n**\\`stagger\\`** on a parent offsets each child by \\`--stagger-amount\\` (time-based drivers) and by\n\\`--stagger-range-step\\` (scroll-driven ones — \\`animation-delay\\` is ignored on a progress-based\ntimeline). Journeys set an explicit range and opt out.\n\n## Component patterns\n\nEach pattern is a base class \\`<pattern>\\` with interaction states (hover/active/focus-visible)\nbaked in; coloured patterns add role variants via rule **\\`<pattern>-<role>\\`**. (How the\npattern CSS is assembled — token cascade, \\`--p-<pattern>\\`-style override hooks, state\nshortcuts — is explained in [/concepts/patterns.md](../concepts/patterns.md).)\n\n- Patterns: ${code(patterns)}.\n- Roles (for coloured patterns — \\`badge\\`, \\`tag\\`, \\`status\\`, \\`cta\\`, \\`btn\\`, …):\n ${code(patternRoles)} — e.g. \\`badge-success\\`, \\`cta-danger\\`. A pattern that also styles an\n element accepts the bare role class too (\\`<button class=\"danger\">\\`). The default\n (unsuffixed) variant uses the pattern's \\`default_role\\`.\n- Shape primitives: \\`--br-<name>\\` radii — ${code(radii)}.\n`;\n}\n\n// ── design-system.json authoring reference (walked from the JSON Schema) ─────\n// Field docs are rendered from `jsonSchema`'s `description` metadata (authored\n// once in schema.ts via `desc()`), so this reference cannot drift from validation.\n\nexport interface JsonSchemaNode {\n type?: string;\n description?: string;\n properties?: Record<string, JsonSchemaNode>;\n required?: string[];\n additionalProperties?: JsonSchemaNode | boolean;\n anyOf?: JsonSchemaNode[];\n items?: JsonSchemaNode;\n enum?: unknown[];\n}\n\nconst isPrimitive = (n: JsonSchemaNode): boolean =>\n !n.properties && !n.anyOf && n.type != null && n.type !== 'object' && n.type !== 'array';\n\nfunction typeLabel(node: JsonSchemaNode): string {\n if (node.enum) return node.enum.map(String).join(' | ');\n if (node.anyOf)\n return node.anyOf.every(isPrimitive) ? node.anyOf.map((v) => v.type).join(' | ') : 'one of';\n if (node.type === 'array') {\n const it = node.items;\n if (it?.enum) return `array of ${it.enum.map(String).join(' | ')}`;\n return it?.type && it.type !== 'object' ? `array of ${it.type}` : 'array';\n }\n if (node.type === 'object') {\n const ap = node.additionalProperties;\n return ap && typeof ap === 'object' ? 'map' : 'object';\n }\n return node.type ?? 'value';\n}\n\n/** A node's documentable children: object properties, map values, or array items. */\nfunction childEntries(\n node: JsonSchemaNode,\n): Array<{ label: string; node: JsonSchemaNode; required: boolean }> {\n if (node.properties) {\n const req = node.required ?? [];\n return Object.entries(node.properties).map(([k, v]) => ({\n label: k,\n node: v,\n required: req.includes(k),\n }));\n }\n const ap = node.additionalProperties;\n if (ap && typeof ap === 'object' && (ap.description || ap.properties || ap.anyOf))\n return [{ label: '<name>', node: ap, required: false }];\n if (node.items && (node.items.description || node.items.properties || node.items.anyOf))\n return [{ label: '[items]', node: node.items, required: false }];\n return [];\n}\n\nfunction renderSchemaNode(\n label: string,\n node: JsonSchemaNode,\n required: boolean,\n depth: number,\n out: string[],\n maxDepth = 3,\n): void {\n const indent = ' '.repeat(depth);\n const meta = `(${typeLabel(node)}${required ? ', required' : ''})`;\n out.push(`${indent}- \\`${label}\\` ${meta}${node.description ? ` — ${node.description}` : ''}`);\n if (depth >= maxDepth) return;\n if (node.anyOf && !node.anyOf.every(isPrimitive)) {\n for (const variant of node.anyOf) {\n out.push(`${indent} - *one of*${variant.description ? ` — ${variant.description}` : ''}`);\n for (const c of childEntries(variant))\n renderSchemaNode(c.label, c.node, c.required, depth + 2, out, maxDepth);\n }\n return;\n }\n for (const c of childEntries(node))\n renderSchemaNode(c.label, c.node, c.required, depth + 1, out, maxDepth);\n}\n\n/**\n * One `## <key>` section per top-level property: its description, then its\n * fields as a bullet tree. Shared by both references so the two cannot drift in\n * presentation — only in which schema they are pointed at.\n */\nfunction schemaSections(schema: JsonSchemaNode, heading = '##', maxDepth = 3): string[] {\n const required = schema.required ?? [];\n const sections: string[] = [];\n for (const [key, node] of Object.entries(schema.properties ?? {})) {\n if (key === '$schema') continue;\n const parts: string[] = [\n `${heading} \\`${key}\\`${required.includes(key) ? '' : ' *(optional)*'}`,\n ];\n if (node.description) parts.push('', node.description);\n const bullets: string[] = [];\n for (const c of childEntries(node))\n renderSchemaNode(c.label, c.node, c.required, 0, bullets, maxDepth);\n if (bullets.length) parts.push('', ...bullets);\n sections.push(parts.join('\\n'));\n }\n return sections;\n}\n\n/* ── Schema → tree DATA (the second consumer of the same walk) ─────────────── */\n\nconst escapeHtml = (s: string): string =>\n s.replace(\n /[&<>\"]/g,\n (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' })[c] as string,\n );\n\n/** Sentinel for a lifted code span. Cannot occur in authored schema prose. */\nconst CODE_SLOT = '\u0000';\n\n/**\n * The inline markdown the schema's `desc()` text actually uses, as HTML. Closed\n * on purpose, exactly like the legal renderer's subset: these strings are\n * authored in `schema.ts`, so the set is knowable rather than guessed at.\n *\n * Escaping happens before any markup is emitted, so a description containing `<`\n * cannot inject tags — several do (`<canonical>/<key>.txt`). Exported because the\n * only safe place for this is one tested function; a caller doing its own escaping\n * is how one of them eventually doesn't.\n *\n * **Code spans are lifted out FIRST, and that is load-bearing rather than tidy.**\n * `colors.utilities` describes the target families as `` `bg-*` ``, `` `text-*` ``,\n * `` `border-*` `` — literal asterisk WILDCARDS. Run emphasis over the raw string\n * and the `*` closing `bg-*` pairs with the one closing `text-*`, wrapping the\n * text between two unrelated utilities in `<em>` and eating both asterisks. The\n * prose then silently describes families that don't exist. Lifting code spans\n * first makes emphasis structurally unable to see inside them.\n */\nexport const renderInlineMarkdown = (s: string): string => {\n const spans: string[] = [];\n const lifted = s.replace(/`([^`]+)`/g, (_, body: string) => {\n spans.push(body);\n return `${CODE_SLOT}${spans.length - 1}${CODE_SLOT}`;\n });\n return (\n escapeHtml(lifted)\n .replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>')\n // Single-asterisk emphasis, after strong so `**x**` is already consumed. The\n // schema uses it (`*presentation*`, `*domain properties*`), so omitting it\n // printed the asterisks literally on the page.\n .replace(/\\*([^*\\n]+)\\*/g, '<em>$1</em>')\n .replace(\n new RegExp(`${CODE_SLOT}(\\\\d+)${CODE_SLOT}`, 'g'),\n (_, i: string) => `<code>${escapeHtml(spans[Number(i)] ?? '')}</code>`,\n )\n );\n};\n\nexport interface SchemaTreeOptions {\n /** Dotted id prefix, so two trees on one page can't collide. */\n idPrefix?: string;\n /** Nesting cap. Unlike the markdown walk there is no reason to truncate. */\n maxDepth?: number;\n /**\n * Dotted paths to render but not descend into.\n *\n * Exists for one real case: the project config declares `designSystem.themes`\n * as a looser shape than `DesignSystemSchema`, because the full one is applied\n * separately by `resolveTheme`. Its embedded copy is therefore an\n * APPROXIMATION — measurably so, missing the descriptions for `colors`,\n * `colors.palette`, `colors.roles` and `colors.utilities`. Rendering it as the\n * token reference would quietly document the colour system less well than the\n * design-system schema does, so a caller prunes it here and renders\n * `jsonSchema` alongside instead.\n */\n prune?: readonly string[];\n}\n\nexport interface SchemaTreeNode {\n /** Field name, or `<name>` / `[items]` for a map value or array item. */\n label: string;\n /** Human type label — `object`, `map`, `string | number`, `one of`. */\n type: string;\n required: boolean;\n /** Raw schema description (the closed inline-markdown subset), if any. */\n description?: string;\n /**\n * Dotted config path (`site.analytics.clarityId`). Absent when the node is not\n * addressable: a pseudo-label, or a path already claimed by an earlier node.\n */\n id?: string;\n /** True for an `anyOf` branch, which has no name of its own. */\n variant?: boolean;\n children: SchemaTreeNode[];\n}\n\n/**\n * Walk a JSON Schema into tree DATA.\n *\n * The same walk that produces the `authoring.md` / `config.md` bullet lists,\n * returned as a node model instead of a string. Returning data rather than markup\n * is deliberate and follows `roleColorUtilities()`: the *shape* of the tree is one\n * decision, and each medium renders it — markdown for agents, an accessible\n * `<details>` tree for the docs site. An HTML-emitting version here would be a\n * second source of the markup contract for `<wc-tree>` to drift from.\n *\n * Ids are dotted paths so a field can be linked to directly. Map-value and\n * array-item pseudo-labels are skipped in the path: `site.dns.records` reads\n * better than `site.dns.<domain>.records`, and neither `<domain>` nor `[items]`\n * is a real key.\n */\nexport function schemaTreeNodes(\n schema: JsonSchemaNode,\n opts: SchemaTreeOptions = {},\n): SchemaTreeNode[] {\n const { idPrefix = '', maxDepth = 12, prune = [] } = opts;\n const pruned = new Set(prune);\n\n const isPseudo = (label: string) => label === '<name>' || label === '[items]';\n const join = (a: string, b: string) => (a ? `${a}.${b}` : b);\n\n /**\n * Paths already claimed. An `anyOf` branch has no key of its own, so sibling\n * branches sharing a field name resolve to the same dotted path\n * (`site.templates.type` exists in all three template variants). Rather than\n * invent a branch index that no real config document contains, the first\n * occurrence keeps the id — which is what `getElementById` would have picked\n * anyway, now true instead of accidental.\n */\n const seen = new Set<string>();\n\n const build = (\n label: string,\n n: JsonSchemaNode,\n required: boolean,\n path: string,\n depth: number,\n ): SchemaTreeNode => {\n const addressable = path !== '' && !isPseudo(label) && !seen.has(path);\n if (addressable) seen.add(path);\n\n // `anyOf` branches are children too: a union with object branches has to be\n // explorable, or `notifications.email` (address | object) renders as a leaf\n // with its six object fields simply absent from the page.\n const variants = n.anyOf && !n.anyOf.every(isPrimitive) ? n.anyOf : [];\n const children: SchemaTreeNode[] = [];\n\n if (depth < maxDepth && !pruned.has(path)) {\n for (const v of variants) {\n children.push({\n label: 'one of',\n type: typeLabel(v),\n required: false,\n variant: true,\n ...(v.description ? { description: v.description } : {}),\n children: childEntries(v).map((c) =>\n build(\n c.label,\n c.node,\n c.required,\n isPseudo(c.label) ? path : join(path, c.label),\n depth + 2,\n ),\n ),\n });\n }\n if (!variants.length)\n for (const c of childEntries(n))\n children.push(\n build(\n c.label,\n c.node,\n c.required,\n isPseudo(c.label) ? path : join(path, c.label),\n depth + 1,\n ),\n );\n }\n\n return {\n label,\n type: typeLabel(n),\n required,\n ...(n.description ? { description: n.description } : {}),\n ...(addressable ? { id: path } : {}),\n children,\n };\n };\n\n const required = schema.required ?? [];\n return Object.entries(schema.properties ?? {})\n .filter(([key]) => key !== '$schema')\n .map(([key, child]) => build(key, child, required.includes(key), join(idPrefix, key), 0));\n}\n\nfunction renderAuthoring(): string {\n const sections = schemaSections(jsonSchema as unknown as JsonSchemaNode);\n return `${frontmatter({\n type: 'Config Reference',\n title: 'Vitops — design-system.json authoring reference',\n description:\n 'Every field of the design-system.json config, generated from the published JSON Schema so it always matches validation.',\n resource: DS_PATH,\n tags: ['config', 'schema', 'authoring', 'design-system'],\n })}\n\n# \\`design-system.json\\` authoring reference\n\nThe single source of truth every output format is generated from. Each consumer authors\ntheir own config — there is no shared canonical token set. The field docs below are\nrendered from the published JSON Schema, so they always match what \\`vitops validate\\`\nenforces.\n\n- Set \\`\"$schema\": \"${SCHEMA_URL}\"\\` in the config for editor autocomplete + validation.\n- Scaffold a starter config with \\`vitops init\\`; check one with \\`vitops validate\\`.\n- **This can be a standalone file, or live inside a site config.** Anywhere the\n toolchain takes a config — \\`--input\\`, the Vite plugin, the Astro integration's\n \\`css.input\\` — that file may be a \\`design-system.json\\` or the larger site config\n that embeds one under \\`designSystem.themes.<name>\\`. They are told apart by shape,\n and the fields below are the same either way. A site config additionally supplies\n the site-level facts generation reads (its default colour scheme, legal documents,\n icon sprite), so the path is declared once rather than per option.\n- The *why* behind each section: [colour system](concepts/color.md),\n [type & space scales](concepts/scales.md), [component patterns](concepts/patterns.md).\n- What each output format does with these tokens: [formats.md](formats.md).\n\n${sections.join('\\n\\n')}\n`;\n}\n\n// ── Config authoring reference (walked from the site JSON Schema) ────────────\n// The same walker, pointed at the other published schema. Everything a consumer\n// can say about their *company* and their *site* — as opposed to their tokens —\n// is described here, and it is generated rather than written so it cannot claim\n// a field validation does not accept.\n\nfunction renderConfig(): string {\n const schema = configJsonSchema as unknown as JsonSchemaNode;\n const props = schema.properties ?? {};\n const required = schema.required ?? [];\n\n // The top level is three sections, so rendering it the way `authoring.md`\n // renders `design-system.json` would put ~23 unrelated fields under one\n // heading. Each section gets a `##`; each of ITS fields gets a `###`.\n const sections = Object.entries(props).map(([key, node]) => {\n const head = [\n `## \\`${key}\\`${required.includes(key) ? '' : ' *(optional)*'}`,\n ...(node.description ? ['', node.description] : []),\n ].join('\\n');\n // `designSystem` is documented in full by authoring.md; here it needs only\n // its own wrapper fields, not a second copy of the whole token schema. The\n // depth cap is what enforces that: `themes` is a map whose value node IS the\n // design-system schema, so the default walk descended into every token field\n // and re-emitted the ~57 field lines authoring.md already owns — directly\n // under a sentence promising it hadn't. Stop at the `<name>` bullet and let\n // the link carry the reader.\n const fields = schemaSections(node, '###', key === 'designSystem' ? 0 : 3).join('\\n\\n');\n if (key === 'designSystem')\n return [\n head,\n 'The token set. Its `themes.<name>` entries are full design systems — every field of\\none is in [authoring.md](authoring.md). Only the wrapper is listed here.',\n fields,\n ].join('\\n\\n');\n return [head, fields].join('\\n\\n');\n });\n\n return `${frontmatter({\n type: 'Config Reference',\n title: 'Vitops — config authoring reference',\n description:\n 'Every field of the three-section config (designSystem / organization / site), generated from the published JSON Schema so it always matches validation.',\n resource: CONFIG_PATH,\n tags: ['config', 'schema', 'authoring', 'site', 'organization'],\n })}\n\n# Config authoring reference\n\nThe document that describes a **whole project**: the token set, the company, and the\npublished site. It is the input every command that needs more than tokens is anchored\nto — \\`vitops legal\\`, \\`vitops icons\\`, \\`vitops search\\` — and it can also stand in for\na \\`design-system.json\\` anywhere the toolchain takes one, since it carries a full\n\\`designSystem\\`.\n\nConsumers name the file whatever suits them (\\`site.json\\`, \\`company.json\\`,\n\\`vitops.config.json\\`); it is recognised by **shape**, not by name — a document with a\ntop-level \\`designSystem\\` key is this, and one without it is a bare\n\\`design-system.json\\`.\n\n- Set \\`\"$schema\": \"${CONFIG_SCHEMA_URL}\"\\` in the config for editor autocomplete + validation.\n- Check one with \\`vitops validate\\`.\n\n## The three sections\n\n| Section | Holds | Changes when |\n| --- | --- | --- |\n| \\`designSystem\\` | the token set — named themes, which theme, which appearance | the brand's design changes |\n| \\`organization\\` | the company — name, contact, locations, services, profiles | the company changes |\n| \\`site\\` | this published site — locales, domains, environments, SEO, analytics, legal, icons, deployment | this site changes |\n\nThe split is what makes the multi-site case expressible: several sites can carry the\nsame \\`organization\\` and differ only in \\`site\\`. It is also what the generated legal\ndocuments rely on — a privacy policy asserts facts about the *company* (who to contact,\nwhere it is) and facts about the *site* (which forms exist, which analytics run), and\nthose two are separately true.\n\n**Fields are described where they are, not where they were.** If you are migrating a\npre-3.0 flat config, \\`vitops validate\\` names every move rather than reporting a dozen\nunknown keys.\n\n${sections.join('\\n\\n')}\n`;\n}\n\n// ── Output formats reference ──────────────────────────────────────────────────\nfunction renderFormats(ds: DesignSystem): string {\n const clashList = Array.from(TW_CLASH).sort();\n const spaceName = ds.spaceScale?.baseline ?? ds.spaceScale?.names?.[0] ?? 'm';\n return `${frontmatter({\n type: 'Formats Reference',\n title: 'Vitops — output formats (tailwind vs css vs bricks vs design)',\n description:\n 'What each vitops generate format emits, what the target platform provides instead, and the Tailwind-specific rules (which framework utilities are stripped in favour of Tailwind defaults).',\n resource: DS_PATH,\n tags: ['formats', 'tailwind', 'bricks', 'css', 'design', 'design-system'],\n })}\n\n# Output formats — \\`tailwind\\` vs \\`css\\` vs \\`bricks\\` vs \\`design\\`\n\nOne config, four targets: \\`vitops generate --format <tailwind|css|bricks|design>\\`. Three of\nthem are stylesheets, and across those the **class vocabulary is the same** (see\n[css/classes.md](css/classes.md)); what differs is which layers the generator emits versus\nwhich the platform provides, and the variant separator (\\`-\\` in CSS/Bricks, \\`:\\` / \\`@\\` in\nTailwind). The fourth, \\`design\\`, emits no CSS at all.\n\n\\`--format\\` takes a comma-separated list, so the brief composes with a stylesheet:\n\\`vitops generate --format css,design\\`.\n\n## \\`tailwind\\` — single-file Tailwind v4 layer\n\nEmits one self-contained \\`tailwind.css\\` (plus \\`tokens.json\\`): \\`@import \"tailwindcss\"\\`,\n\\`@theme\\` tokens, the framework's structural CSS + component patterns inlined, and\n\\`@utility\\` definitions for the bespoke families (type roles, animation effects,\nsplit ratios, track placement).\n\n**Use Tailwind's own utilities for these class names.** The framework's rules for them are\ndeliberately stripped from the bundle because Tailwind provides them natively — writing\nthem still works, but they are Tailwind's, not the framework's:\n\n${clashList.map((c) => `\\`${c}\\``).join(', ')}\n\nOther Tailwind-specific behaviour:\n\n- **Variants are Tailwind's job.** No pre-expanded breakpoint/state classes are emitted\n (the framework's \\`@container (min-width: …)\\` **variant** blocks are dropped; component\n container queries such as the sitenav's desktop switch are kept); use Tailwind syntax —\n \\`@md:split-1-2\\`, \\`hover:flip-fade-in\\`. Container breakpoints are registered as\n \\`--container-{sm,md,lg,xl}\\` = 30/48/64/80rem, backing the \\`@sm:\\`…\\`@xl:\\` variants.\n\n > **Three spellings, and only two of them work here.**\n >\n > | you write | in \\`tailwind\\` | note |\n > | --- | --- | --- |\n > | \\`@md:flex-row\\` | ✅ container query | the framework's breakpoints (48rem) |\n > | \\`md:flex-row\\` | ✅ media query | **Tailwind's** breakpoints, which differ — \\`sm:\\` is 40rem where \\`@sm:\\` is 30rem |\n > | \\`md-flex-row\\` | ❌ silently nothing | the css/bricks spelling; not emitted in this format |\n >\n > \\`md-*\\` is the trap: it is a real class in \\`css\\`/\\`bricks\\` and a no-op here, and\n > nothing errors — the element simply never changes at the breakpoint. Prefer \\`@md:\\`\n > so one vocabulary of breakpoints applies throughout.\n\n- **Overriding \\`--container-*\\` also moves Tailwind's width scale.** Registering the\n framework breakpoints in \\`@theme\\` re-points \\`max-w-sm\\`…\\`max-w-xl\\` at the same values,\n so \\`max-w-md\\` is 48rem here rather than Tailwind's stock 28rem. Use\n \\`max-w-(--container-md)\\` style arbitrary values if you need to be explicit.\n- **The space scale is NOT mapped into Tailwind's \\`--spacing-*\\` namespace** (that would\n corrupt Tailwind's numeric multipliers and \\`max-w-*\\` sizes). Numeric utilities like\n \\`p-4\\` keep Tailwind's 0.25rem meaning; use the design-system scale via arbitrary\n values — \\`p-(--space-${spaceName})\\`, \\`gap-(--space-${spaceName})\\`.\n- **Functional colour roles are plain \\`:root\\` variables, not \\`@theme\\` colours**, so\n Tailwind doesn't auto-derive utilities from them; the emitted \\`@utility\\` set\n (\\`bg-<role>\\`, \\`text-<role>-muted\\`, …) is the public API. The raw hue scales ARE\n \\`@theme\\` colours, so native \\`bg-<hue>-500\\`-style utilities work.\n\n This split is deliberate and load-bearing. When a token sits in \\`@theme\\` *and* an\n \\`@utility\\` of the derived name exists, Tailwind merges both into one rule with the\n \\`@theme\\` declaration last — regardless of source order. Only palette hues belong in\n \\`@theme\\`, where nothing competes for the name. Role tokens stay in a plain \\`:root\\`\n block, and \\`format-parity.test.ts\\` derives that guard from the emitted token names so\n it cannot go quiet if the grammar moves again.\n- **\\`colors.utilities\\` is a floor here, not a ceiling.** It controls which families get\n explicit role \\`@utility\\` rules, exactly as in \\`css\\`/\\`bricks\\`. But the raw hue scales\n are \\`@theme\\` colours, and Tailwind derives *every* colour family from those on demand\n (\\`ring-\\`, \\`divide-\\`, \\`accent-\\`, \\`caret-\\`, …), so hue-step utilities you did not enable\n still resolve in this format.\n\n## \\`css\\` — standalone bundle\n\nEmits a bundled, self-contained \\`styles.css\\` + \\`tokens.json\\` + \\`design-manifest.json\\`.\nThe colour and font/scale layers are fully included, and every utility family is\npre-expanded — including breakpoint/state variants with \\`-\\` separators\n(\\`md-split-1-2\\`, \\`hover-fade-in\\`). For non-Bricks, non-Tailwind consumers and the\ndocs build.\n\n**Cascade layers.** The bundle ships three, in precedence order:\n\n\\`\\`\\`\n@layer vitops.base, vitops.components, vitops.utilities;\n\\`\\`\\`\n\n- \\`vitops.base\\` — the reset (\\`box-sizing: border-box\\` on every element and pseudo-element,\n a 16px root, no body margin) and the pure \\`:root\\` token blocks. Lowest of the three, so\n your own reset overrides it — unlayered, or from a layer you declare before \\`vitops.base\\`.\n- \\`vitops.components\\` — the animation engine, the structural patterns (\\`.rhythm\\`,\n \\`.centered\\`, \\`.region\\`, \\`.split\\`, \\`.reveal\\`) and every UI pattern.\n- \\`vitops.utilities\\` — \\`bg-*\\`, \\`text-*\\`, \\`border-*\\`, \\`drop-shadow-*\\`, \\`font-*\\`,\n \\`gap-*\\`, animation effects, the layout utilities (\\`.m-*\\`, \\`.flex-*\\`, \\`.items-*\\`,\n \\`.split-<a>-<b>\\`, track placement) and the display/\\`sr-only\\` families.\n\nSo a utility overrides a pattern: \\`class=\"card bg-danger-muted\"\\` tints the card,\n\\`class=\"split flex-col\"\\` stacks the split, \\`class=\"table text-center\"\\` centres the table.\nYour own unlayered CSS beats all three — see [concepts/patterns.md](concepts/patterns.md) for\nthe override story and the one gotcha (a reset must be layered and ordered first).\n\nThe classification is by RULE, not by file: a partial that mixes patterns and utilities is\nsplit in two rather than shelved whole. \\`layout.css\\` (patterns) and \\`layout-utilities.css\\`\n(utilities) are the same family in two files for exactly this reason, and the \\`tailwind\\`\nformat reaches the same arrangement by its own route — patterns in \\`@layer components\\`,\nutilities as \\`@utility\\`.\n\nKnown gap: the \\`typography.headings\\` bare-element bindings (\\`h1\\`, \\`h2\\`, \\`body\\`) are\nemitted alongside \\`.font-<role>\\` and so sit in \\`vitops.utilities\\`, where a tag rule\noutranks every pattern — \\`<h2 class=\"pull-quote\">\\` keeps the heading's font-size in\n\\`css\\`/\\`bricks\\` and the pattern's in \\`tailwind\\`, which puts the bindings in \\`@layer base\\`.\nGive the element a \\`.font-<role>\\` class to pin it either way.\n\n## \\`bricks\\` — WordPress / Bricks Builder payload\n\nEmits the full deployable theme payload: \\`styles.min.css\\`, the Bricks import JSONs\n(\\`bricks-colors-{named,semantic}.json\\`, \\`bricks-variables.json\\`), \\`tokens.json\\`, the JS\nbundles (polyfills / elements / deferred), the Bricks element PHP under \\`bricks/\\`, and\nthis docs bundle under \\`docs/\\`.\n\n- **Bricks provides the token layer.** \\`color.css\\` and \\`type-tokens.css\\` are one-line\n stubs: the colour \\`:root\\` tokens, dark-mode overrides, colour utility classes, fonts,\n and type/space scales are generated live by Bricks' Color / Font / Variables Managers\n from the imported JSONs. Semantic palette entries carry \\`darkModeEnabled\\` + a \\`dark\\` ref so\n Bricks emits the dark-mode overrides on import.\n- Everything else (patterns, shadows, typography roles, animation effects, structural\n framework CSS) ships in \\`styles.min.css\\` as in the other formats.\n- Pattern states reference shadows by name, compiled to\n \\`filter: drop-shadow(var(--shadow-<name>))\\`.\n\n## \\`design\\` — the agent-facing brief\n\nEmits exactly one file, \\`DESIGN.md\\`, in the\n[google-labs-code/design.md](https://github.com/google-labs-code/design.md) format: YAML\nfront matter carrying the tokens (\\`colors\\`, \\`typography\\`, \\`rounded\\`, \\`spacing\\`,\n\\`components\\`, with \\`{group.token}\\` references) followed by a prose body carrying the\nrationale. It is meant to be run with \\`--out .\\` — DESIGN.md conventionally sits at a repo\nroot beside \\`AGENTS.md\\`, not in a build directory.\n\n**No CSS, no \\`tokens.json\\`, nothing else.** This format is a description of the system for\na tool that has to work without it — a coding agent in another repo, a Figma import, a\ndesigner. It is not a build target, and \\`vitops lint\\` does not accept it.\n\nThree things the format cannot represent, and what is emitted instead:\n\n| Ours | Why it doesn't fit | Emitted as |\n| --- | --- | --- |\n| fluid \\`clamp()\\` type / space steps | a spec \\`Dimension\\` is a number + px/em/rem | the **max** (desktop) value, with the prose saying so |\n| the automatic dark flip | the spec has no notion of a second appearance | **light** values only, with the flip explained in prose |\n| a \\`50%\\` radius | same \\`Dimension\\` restriction | dropped from \\`rounded\\`, named in the Shapes prose |\n\nRole tokens are emitted as \\`{colors.<hue>-<step>}\\` **references** into the raw ramps rather\nthan flattened hexes, so the role → ramp lineage survives the export. \\`on-solid\\` is the\nexception — it is a computed contrast literal with no step behind it.\n\n\\`meta.name\\` / \\`meta.description\\` in \\`design-system.json\\` supply the brand name and the\nOverview paragraph; everything else is derived from the config, so the brief cannot drift\nfrom what the other three formats build.\n`;\n}\n\n// ── Concept docs (colour / scales / patterns) ─────────────────────────────────\nfunction renderColorConcept(ds: DesignSystem): string {\n const hues = Object.keys(ds.colors.palette ?? {});\n const roles = Object.keys(ds.colors.roles ?? {});\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops colour system — seeded scales, target-prefixed tokens, automatic dark mode',\n description:\n 'How palette hues become 11-step OKLCH scales on a shared lightness ladder, how semantic roles derive target-prefixed tokens from them, and how dark mode flips automatically.',\n resource: DS_PATH,\n tags: ['color', 'oklch', 'dark-mode', 'design-system'],\n })}\n\n# Colour system\n\nAuthoring is two maps in \\`design-system.json\\` (see [authoring.md](../authoring.md)):\n\\`colors.palette\\` (hues) and \\`colors.roles\\` (semantic role → hue). Everything else —\nscales, role tokens, utilities, dark mode — is derived.\n\n## From seed to scale\n\nEach palette hue becomes an **11-step numeric OKLCH scale**, \\`--color-<hue>-50…950\\`,\nrunning tinted near-white → tinted near-black. Two authoring modes:\n\n- **Seeded** (\\`{ seed, anchors? }\\`): the scale is generated from one colour. The seed is\n preserved at its natural lightness step; \\`anchors\\` pin specific steps and the rest\n interpolate around them.\n- **Fixed** (\\`{ tones }\\`): a brand kit used verbatim — each authored tone lands at its\n nearest step, endpoints are tinted off-white/off-black, no interpolation.\n\nCurrent hues: ${code(hues)}.\n\n## The token grammar\n\nEvery colour token is named:\n\n\\`\\`\\`\n--color-<target>-<role>[-<variant>] target ∈ bg | text | icon | border\n\\`\\`\\`\n\nThe target sits **inside** the name on purpose. \\`--color-bg-danger-muted\\` and\n\\`--color-text-danger-muted\\` are different tokens, so there is nothing to arbitrate between\nthem — an earlier grammar put both on one \\`<family>-<role>-<modifier>\\` name and needed a\nprecedence rule, which made half the variants unreachable and the rest non-monotonic.\n\n**The token name is also the utility class name**, minus the \\`--color-\\` prefix. Write\n\\`class=\"bg-danger-muted\"\\` and you are using \\`--color-bg-danger-muted\\`. One vocabulary, not\ntwo (see [css/classes.md](../css/classes.md)).\n\nVariants are ordinal — \\`xx-muted\\` < \\`x-muted\\` < \\`muted\\` < (bare) < \\`bold\\` < \\`x-bold\\` — and\nthe tables are **sparse**: only cells that actually hold their contrast target exist.\n\\`bold\\` means *more emphatic in the current appearance*, not darker.\n\n## Role kinds\n\nA role in \\`colors.roles\\` (currently ${code(roles)}) is one of two kinds, and the kind decides\nwhich tokens exist:\n\n- **\\`surface\\`** — a page or panel colour. \\`bg-<role>\\` is the card, \\`bg-<role>-muted\\` the page\n behind it, \\`bg-<role>-x-muted\\` a well, \\`bg-<role>-bold\\` the inverse surface a tooltip sits\n on. Full text scale, and \\`border-<role>-bold\\` as the contrast-guaranteed boundary.\n- **\\`chromatic\\`** (the default, and what the bare-string form means) — a signal colour.\n Backgrounds split into *tints* (\\`bg-<role>-x-muted\\`, \\`bg-<role>-muted\\`) and *solids*\n (\\`bg-<role>-solid\\`, \\`-solid-bold\\`, \\`-solid-x-bold\\`). There is deliberately **no bare\n \\`bg-<role>\\`**: \"how loud?\" is a question the author answers. \\`text-on-<role>\\` is the\n guaranteed foreground for the solid family.\n\nPlus \\`--surface-glass\\` (translucent surface), \\`--overlay\\` (scrim) and\n\\`--color-border-focus\\` (the focus ring, taken from \\`ui-primary\\`'s solid tone).\n\n## Automatic dark mode\n\nDark mode re-points which step each token reads, under \\`${DARK_SEL}\\`:\nbackground and text ends of each scale swap, while the **solid family stays mode-stable**\nalong with the \\`text-on-<role>\\` foreground computed against it — so a filled button keeps\nits identity when the appearance flips. There is no per-appearance scheme grammar to author\nand no named steps: a role token means the same *job* in both appearances.\n\nRaw hue steps (\\`--color-<hue>-<step>\\`) are the exception — they are fixed values and are\n**not** re-pointed. Reach for a role token unless you specifically want a colour that\nignores the appearance.\n\nTwo attributes, one flip: \\`data-brx-theme\\` is Bricks' own (Bricks sets it on the\nWordPress target), \\`data-theme\\` is what the shipped \\`<wc-color-scheme-toggle>\\` writes on\n\\`<html>\\`, so the toggle works on every other target. Set either.\n\nThe OS preference is a **second, opt-in block**. Set\n\\`designSystem.defaultColorScheme: \"system\"\\` in your site config and the same delta is emitted again inside\n\\`@media (prefers-color-scheme: dark)\\`, under\n\\`${SYSTEM_DARK_SEL}\\` — i.e. whenever no explicit choice has been made. That is what makes\n\\`<wc-color-scheme-toggle>\\`'s \"System\" position resolve to the OS (it *removes* the attribute,\nso without this block it fell through to light), and it gives a no-JS page the OS\nappearance, which the toggle alone never could. An explicit light choice still wins.\n\nIt is opt-in rather than default because turning it on flips a site dark for dark-OS\nvisitors, which is the site's decision and not the design system's.\n\n## Contrast guarantees\n\nEnforced **at build time** — a violation fails \\`generate\\`, so an unreadable pairing cannot\nship. In both appearances:\n\n| tier | target | applies to |\n| --- | --- | --- |\n| text | APCA Lc ≥ 75 | \\`text-<role>\\` on the role's primary background |\n| secondary | Lc ≥ 60 | text on any other background plane; \\`text-<role>-muted\\`; \\`text-on-<role>\\` on its solid |\n| non-text | Lc ≥ 45 | \\`icon-<role>\\`, and a surface role's \\`border-<role>-bold\\` |\n\nTwo deliberate exemptions: \\`text-<role>-x-muted\\` (placeholders) and \\`-xx-muted\\` (disabled\ntext) are *required* to look unavailable, and holding them to the body-text bar would defeat\nthe affordance. Nothing else is exempt.\n\nChromatic text is checked against the **surface planes it actually sits on**, not only its\nown tints — coloured text appears over the page far more often than over its own wash.\n\nA \\`tones\\` kit thin enough that snapping can't cover a tier is reported rather than shipped;\nthe fix is another tone, and the failure says so.\n`;\n}\n\nfunction renderScalesConcept(ds: DesignSystem): string {\n const t = ds.typeScale;\n const s = ds.spaceScale;\n const scaleLine = (label: string, sc: typeof t): string =>\n sc\n ? `- **${label}**: base \\`${sc.base}\\` at step \\`${sc.names?.[(sc.baseStep ?? 1) - 1] ?? sc.baseStep}\\`, ratio ${sc.ratio}${sc.fluid ? ` (${sc.fluid.minRatio} below ${sc.fluid.minVw})` : ''}; steps ${code(sc.names ?? [])}.`\n : `- **${label}**: not configured.`;\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops type & space scales — fluid modular scales',\n description:\n 'How typeScale and spaceScale compile to clamp()-based fluid modular scales, and which utilities consume the resulting tokens.',\n resource: DS_PATH,\n tags: ['typography', 'spacing', 'fluid', 'modular-scale', 'design-system'],\n })}\n\n# Type & space scales\n\nBoth scales share one model (authored in \\`design-system.json\\` as \\`typeScale\\` /\n\\`spaceScale\\` — see [authoring.md](../authoring.md)): a **fluid modular scale**.\n\n## The model\n\n- \\`base\\` anchors the value at \\`baseStep\\`; every other step is a power of the \\`ratio\\`\n away (step n = base × ratio^(n − baseStep)).\n- With \\`fluid\\`, each step compiles to a **\\`clamp()\\`**: the scale uses \\`fluid.minRatio\\`\n at/below \\`fluid.minVw\\` and grows to \\`ratio\\` at \\`fluid.maxVw\\`, interpolating between —\n so large steps spread apart on wide viewports and compress on phones, with no\n breakpoint jumps. \\`baseline\\` names the pivot step that stays closest to \\`base\\`.\n- \\`names\\` become the token suffixes.\n\n${scaleLine('Type', t)}\n${scaleLine('Space', s)}\n\n## What consumes them\n\n- **Type**: \\`--text-<name>\\` tokens → typography role sizes (\\`font-<role>\\` classes,\n heading defaults) and text-size utilities.\n- **Space**: \\`--space-<name>\\` tokens → gap (\\`g\\`), spacing utilities, and \\`rhythm\\`\n (relationship-based vertical margins between headings, paragraphs, lists, media).\n Prefer \\`rhythm\\` for vertical flow over per-element margins.\n- In the \\`tailwind\\` format these stay in their own namespaces (\\`--text-*\\` via \\`@theme\\`,\n \\`--space-*\\` as plain vars) — see [formats.md](../formats.md) for why \\`--spacing-*\\` is\n deliberately not used.\n`;\n}\n\nfunction renderPatternsConcept(ds: DesignSystem): string {\n const items = (ds.patterns?.items ?? {}) as Record<string, { group?: string }>;\n const groups = Object.keys(ds.patterns?.groups ?? {});\n const patternNames = Object.keys(items);\n const hookTable = Object.entries(BASE_HOOK)\n .map(([prop, sfx]) => `| \\`${prop}\\` | \\`--${sfx}-<pattern>\\` |`)\n .join('\\n');\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops component patterns — token cascade, override hooks, states',\n description:\n 'How pattern CSS is assembled: the token cascade (defaults → groups → per-pattern overrides), per-pattern override-hook variables, state shortcuts, and role variants.',\n resource: DS_PATH,\n tags: ['patterns', 'components', 'cascade', 'css', 'design-system'],\n })}\n\n# Component patterns — the CSS chain\n\nPatterns (currently ${code(patternNames)}) are authored declaratively under \\`patterns\\` in\n\\`design-system.json\\` (see [authoring.md](../authoring.md)) and compiled to CSS in a\n**components cascade layer** — so utility classes, which live in a later layer, always win over\npattern styling without specificity fights. \\`class=\"card bg-danger-muted\"\\` tints the card.\n\nThe layer names differ by format, because each defers to its host:\n\n| format | layer stack (last wins) |\n| --- | --- |\n| \\`css\\`, \\`bricks\\` | \\`vitops.base\\` → \\`vitops.components\\` → \\`vitops.utilities\\` |\n| \\`tailwind\\` | Tailwind's own \\`theme\\` → \\`base\\` → \\`components\\` → \\`utilities\\` |\n\n**Your own CSS beats all of it.** Unlayered styles outrank every cascade layer regardless of\nspecificity, so a plain stylesheet, an Astro scoped \\`<style>\\`, or a Bricks-authored class\noverrides the framework with no \\`!important\\` and no specificity escalation. That is the\nintended override story.\n\nThe one thing to watch: a **reset** must be layered too, and ordered *below* the framework —\nleft unlayered it beats the very component rules it is meant to sit under (a bare\n\\`p { margin: 0 }\\` would defeat \\`.rhythm\\`). Declare the order before you load the stylesheet,\nsince layer precedence is fixed by first declaration:\n\n\\`\\`\\`html\n<style>@layer my.reset, vitops.base, vitops.components, vitops.utilities;</style>\n<link rel=\"stylesheet\" href=\"/styles.css\">\n\\`\\`\\`\n\nPut it *after* the link and \\`my.reset\\` becomes a new name introduced later — which sorts\n**last**, i.e. highest priority, and the reset wins. That is the one non-obvious step.\n\n## 1 — Token cascade\n\nShared geometry resolves through a variable chain, most-specific first:\n\n- \\`patterns.defaults\\` → \\`--<prop>-default\\` (cascade-wide fallbacks).\n- \\`patterns.groups.<group>\\` → \\`--<prop>-<group>\\` (e.g. groups ${code(groups)}); a pattern\n opts in via its \\`group\\` key.\n- Per-pattern: each grouped pattern gets aliases \\`--<prop>-<name>-group\\` →\n \\`var(--<prop>-<group>)\\`, and \\`overrides\\` replace individual aliases with literal values.\n- \\`patterns.radii\\` → \\`--br-<name>\\` shape primitives; \\`patterns.z\\` → \\`--z-tier-<name>\\`.\n\n## 2 — Base declarations & override hooks\n\nEach pattern's \\`base\\` block is emitted on its selector:\n\n- \\`class\\` only → \\`.<class ?? name>\\`, at normal class specificity.\n- \\`element\\` only → a **zero-specificity** \\`:where(<element>)\\` rule, so author CSS can always\n override it.\n- **both** → one \\`:where(<element>, .<class>)\\` rule (e.g. \\`:where(button, .btn)\\`). The element\n gets the styling with no class needed, the class carries it to any other tag, and — because the\n whole thing sits at zero specificity — any explicit class wins, including a louder pattern\n (\\`.cta\\`) or a component's own rule (\\`.dialog__close\\`).\n\nGeometry properties are wrapped in a **per-pattern override hook**:\n\n| base property | hook variable |\n| --- | --- |\n${hookTable}\n\ne.g. \\`padding: var(--p-btn, 0.4em 0.8em)\\` — a consumer restyles every button by setting\n\\`--p-btn\\` on \\`:root\\`, without touching the pattern. The hook is named after the pattern's\n**key**, not its class.\n\n\\`background\\` and \\`background-color\\` share the \\`bg\\` hook, since a pattern may author either.\nThat is what makes a pattern's fill **undoable** — a flat, border-only card:\n\n\\`\\`\\`html\n<!-- via the hook: applies wherever you set it, including :root for all cards -->\n<div class=\"card\" style=\"--bg-card: transparent; --ds-card: none\">…</div>\n\n<!-- or compose a utility, which reads better inline and is what most authors want -->\n<div class=\"card bg-transparent\" style=\"--ds-card: none\">…</div>\n\\`\\`\\`\n\n\\`bg-transparent\\` and \\`bg-inherit\\` are emitted for \\`css\\`/\\`bricks\\`; in \\`tailwind\\` they\ncome from Tailwind itself. There is no utility for the shadow, so \\`--ds-card: none\\` is the\nway to drop it in every format.\n\nRole variants are emitted as their own rules and are **not** wrapped, so setting \\`--bg-card\\`\ntunes the default fill without silently defeating \\`.card-danger\\`.\n\n## 3 — States\n\n\\`states\\` (hover / active / focus-visible) compile from shortcuts:\n\n- \\`step: n\\` — intensify the pattern's colour one rung: fills swap\n \\`--color-bg-<role>-solid\\` → \\`-solid-bold\\`; text patterns swap\n \\`--color-text-<role>\\` → \\`--color-text-<role>-bold\\`.\n- \\`scale: 0.97\\` — transform scale; \\`lift: \"<length>\"\\` — \\`translate: 0 calc(-1 * <length>)\\`.\n- \\`shadow: \"<name>\"\\` — \\`filter: drop-shadow(var(--shadow-<name>))\\`; \\`shadow: true\\` — the\n generic lift box-shadow.\n- \\`ring: true\\` — focus ring (\\`box-shadow\\` in the role's solid tone, or\n \\`--color-border-focus\\` when the pattern has no role; outline removed).\n- \\`css: { … }\\` — raw declarations escape hatch.\n\nAny pattern with states also gets a composed transition block (translate / scale / filter /\nbox-shadow / colours, \\`--interact-duration\\` / \\`--interact-easing\\` overridable). Hover\nrules are wrapped in \\`@media (hover: hover)\\` so touch devices never stick.\n\n## 4 — Role variants\n\n\\`roles\\` lists semantic colour variants: class patterns emit \\`.<pattern>-<role>\\`\n(\\`.badge-success\\`). A pattern with an \\`element\\` emits both the bare role class on the\nelement and the \\`-<role>\\` form (\\`:where(button, .btn).danger, .btn-danger\\`), so the same\nvariant works on a non-element host — both at class specificity, so neither outranks a\nplain class. Fill\npatterns set \\`background-color: var(--color-bg-<role>-solid)\\` +\n\\`color: var(--color-text-on-<role>)\\`; text patterns use \\`var(--color-text-<role>)\\`, the\ntoken guaranteed legible over a surface in both appearances. \\`default_role\\` colours the\nbare, unsuffixed pattern. States re-apply per variant with the variant's role.\n`;\n}\n\n/**\n * All four tiers in ONE doc — the agent-facing projection of `TIERS`.\n *\n * The docsite projects each tier as its own page, because a human arrives already\n * knowing which stack they are in (\"show me the Astro components\"). An agent\n * arrives the other way round: it knows the *pattern* it needs and has to be told\n * which tiers offer it and which call to make. Four docs would mean an agent\n * fetching `components/astro` learns `<Tree />` exists and never learns it must not\n * wrap it in `<wc-tree>` — the composition only exists between the tiers, so the\n * projection that serves agents is the one that keeps them together.\n *\n * `ds` is read for one thing: whether each config-authored pattern is actually\n * declared in THIS consumer's `patterns.items`. `TIERS.css.generated` records that a\n * pattern is *of that kind* against this repo's reference config; it cannot know\n * that a given consumer dropped `card`. Reporting a class that this config emits no\n * CSS for is the failure worth preventing here.\n */\nfunction renderComponentsConcept(ds: DesignSystem): string {\n const declared = new Set(Object.keys(ds.patterns?.items ?? {}));\n // Table cells: a literal pipe would split the column, and `use` strings are prose.\n const cell = (s: string) => s.replace(/\\|/g, '\\\\|');\n const code = (s: string) => `\\`${s}\\``;\n const list = (xs: string[]) => xs.map(code).join(', ');\n\n const tiersOf = (name: string): string[] =>\n (['css', 'wc', 'astro', 'bricks'] as const).filter((t) =>\n tierPatterns(t).some((p) => p.name === name),\n );\n\n const overview = TIER_NAMES.map((name) => {\n const e = TIERS[name]!;\n return `| ${code(name)} | ${tiersOf(name).join(' · ')} | ${cell(e.use)} |`;\n }).join('\\n');\n\n const wc = tierPatterns('wc')\n .map(({ name, entry }) => {\n const w = entry.wc!;\n const ships = w.registered ? code('elements.js') : w.bundle ? code(w.bundle) : 'nothing';\n return `| ${code(`<${w.tag}>`)} | ${code(name)} | ${ships} | ${cell(w.adds)} |`;\n })\n .join('\\n');\n\n const astro = tierPatterns('astro')\n .flatMap(({ name, entry }) =>\n entry.astro!.map(\n (a) =>\n `| ${code(a.component)} | ${code(name)} | ${\n a.wraps === 'wc'\n ? `the ${code(`<${entry.wc!.tag}>`)} tag, fallback inside`\n : 'tier-1 markup — no web component'\n } |`,\n ),\n )\n .join('\\n');\n\n const bricks = tierPatterns('bricks')\n .map(({ name, entry }) => `| ${code(entry.bricks!)} | ${code(name)} |`)\n .join('\\n');\n\n const css = tierPatterns('css')\n .map(({ name, entry }) => {\n const c = entry.css;\n const config = !c.generated\n ? '—'\n : declared.has(name)\n ? 'declared'\n : '**absent from this config — no CSS emitted**';\n return `| ${code(name)} | ${c.partial ? code(c.partial) : '—'} | ${\n c.classes.length ? list(c.classes) : '—'\n } | ${config} |`;\n })\n .join('\\n');\n\n // `BASE_HOOK` maps a CSS property to a var suffix, so it has no single spelling to\n // quote — derive the distinct hooks rather than interpolating the object.\n const hooks = [...new Set(Object.values(BASE_HOOK))]\n .map((sfx) => code(`--${sfx}-<pattern>`))\n .join(', ');\n\n const unshipped = tierPatterns('wc')\n .filter(({ entry }) => !entry.wc!.registered && entry.wc!.bundle?.startsWith('(none'))\n .map(({ entry }) => code(`<${entry.wc!.tag}>`))\n .join(', ');\n\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops components — which tier provides a pattern, and what to write',\n description:\n 'Every UI pattern across the four tiers (CSS classes, wc-* web components, Astro components, Bricks elements): which tiers provide it, which call to make, and how the tiers compose.',\n resource: DS_PATH,\n tags: ['components', 'web-components', 'astro', 'bricks', 'tiers', 'design-system'],\n })}\n\n# Components\n\nA pattern is provided by up to four tiers, and they **compose** rather than compete:\n\n1. **CSS framework classes** — every pattern expressible in pure HTML/CSS. Reach here first.\n2. **Web components** (${code('<wc-*>')}, Lit) — only where a pattern genuinely benefits from\n progressive enhancement. The slotted markup is the fallback and must be usable with no JS;\n the element parses and augments it in place.\n3. **Astro components** — authoring conveniences that emit the correct markup. They must not\n require runtime JS. Where a pattern has a web component, the Astro component emits that tag\n **with the accessible fallback inside it**.\n4. **Bricks elements** — the same patterns as WordPress/Bricks Builder elements.\n\n## Choosing\n\n**Use the highest-numbered tier available for your stack, and write only its call.** In Astro\nthat is the Astro component; in Bricks the element; anywhere else the classes, plus the\n${code('<wc-*>')} tag when one exists.\n\nThe trap is composing two tiers by hand. When ${code('wraps')} below says the Astro component\nemits the tag, that one call is the whole composition —\n${code('<wc-tree><Tree /></wc-tree>')} nests two elements on one tree. A tier-3 component that\nwould need runtime JS is in the wrong tier: build a web component instead and have the wrapper\nemit its tag.\n\n## Every pattern\n\n| Pattern | Tiers | What to write |\n| --- | --- | --- |\n${overview}\n\n## Web components\n\nShipped as feature-detected, deferred ES-module bundles. ${code('elements.js')} carries the\nregistered set; ${code('<wc-consent>')} and ${code('<wc-theme-editor>')} ship separately, the\nfirst so a site needing consent does not download a rendering framework, the second because it\nis tooling and opt-in per consumer.\n\n| Tag | Pattern | Ships in | What JS adds over the fallback |\n| --- | --- | --- | --- |\n${wc}\n\n${\n unshipped\n ? `${unshipped} are **registered but in no bundle** (the editor-v2 track). The tags are inert in a consumer project — they are listed so that \"the tag does nothing\" is documented rather than discovered.`\n : ''\n}\n\n## Astro components\n\n| Component | Pattern | Emits |\n| --- | --- | --- |\n${astro}\n\n## Bricks elements\n\nControls, defaults and seeded children for each are in [the elements reference](../bricks/elements.md).\n\n| Element | Pattern |\n| --- | --- |\n${bricks}\n\n## CSS\n\n${code('patterns.items')} patterns get the full token cascade — ${code('base')} declarations,\n${code('states')}, role variants and override hooks (${hooks}); see\n[component patterns](patterns.md). A structural partial has none of those. The class lists below\nare representative, not exhaustive — [the class vocabulary](../css/classes.md) states the naming\nrules that generate them all.\n\n| Pattern | Partial | Classes | ${code('patterns.items')} |\n| --- | --- | --- | --- |\n${css}\n`;\n}\n\n// ── Reserved index.md listings (no frontmatter) ──────────────────────────────\nfunction renderTopIndex(): string {\n return `${INDEX_NOTE}\n\n# Vitops design system\n\nLLM-oriented documentation bundle (Open Knowledge Format) for the Vitops design system — a\nvariable-driven CSS framework plus progressively-enhanced web components, generated from\n\\`design-system.json\\` and published alongside the deployed theme.\n\n# Contents\n\n* [Authoring reference](authoring.md) - every design-system.json field, generated from the JSON Schema\n* [Config reference](config.md) - every field of the three-section config (designSystem / organization / site), generated from the JSON Schema\n* [Output formats](formats.md) - tailwind vs css vs bricks vs design: what's emitted, what the platform provides, which utilities Tailwind owns\n* [Concepts](concepts/) - the colour system, type/space scales, pattern CSS architecture, the four component tiers, icons, and the consent / tracking / search / legal subsystems\n* [CSS framework](css/) - the class vocabulary (colour, type, space, layout, animation, component patterns), stated as naming rules\n* [Bricks Builder](bricks/) - custom elements and how to style them\n`;\n}\n\nfunction renderIconsConcept(): string {\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops icons — one semantic vocabulary across icon sets',\n description:\n 'Semantic icon names that resolve per configured set, how the bundle is derived on a server build, and the three delivery paths (astro-icon, astro-iconset, SVG sprite).',\n resource: DS_PATH,\n tags: ['icons', 'svg', 'sprite', 'astro-icon', 'design-system'],\n })}\n\n# Icons\n\nIcons are named by **meaning**, not by set. \\`menu\\` resolves to \\`fa7-solid:bars\\`,\n\\`lucide:menu\\` or \\`ph:list\\` depending on which set the site configures, so changing\nsets is a config edit rather than a find-and-replace across templates.\n\nThe escape hatch is deliberate and always available: **a name containing \\`:\\` passes\nthrough untouched**. \\`<Icon name=\"simple-icons:zoho\" />\\` renders that exact glyph\nwhether or not the semantic map knows it.\n\n## Declaring them\n\nThe \\`icons\\` block lives in the **site config**, not \\`design-system.json\\` — it\ndescribes what a site uses, not what the design system defines.\n\n\\`\\`\\`json\n{\n \"icons\": {\n \"ui\": \"ph\",\n \"brand\": \"simple-icons\",\n \"weight\": \"bold\",\n \"semantic\": [\"menu\", \"close\", \"arrow-right\"],\n \"simple-icons\": [\"zoho\", \"cloudflare\"],\n \"sprite\": true\n }\n}\n\\`\\`\\`\n\n\\`ui\\` and \\`brand\\` pick which set a semantic name resolves against. Any other key is\nan iconify collection name with an explicit list, passed through verbatim.\n\n**\\`weight\\` is only meaningful for sets that encode weight in the icon NAME.**\nPhosphor does (\\`list\\`, \\`list-bold\\`, \\`list-fill\\`), so \\`ph\\` accepts it; Font Awesome\nsplits weights across collections instead (\\`fa7-solid\\` vs \\`fa7-regular\\`), so there\nthe weight is part of the prefix and this key is ignored.\n\n## Why the bundle list exists\n\nastro-icon is **zero-config on a static build**. Under \\`output: 'server'\\` it bundles\n*every icon in a set* unless given an \\`include\\` map — which is why projects end up\nhand-maintaining one.\n\nThe \\`icons\\` option on \\`vitops()\\` derives it by scanning your source, merged with\nwhatever you declare. On a static build **no include is passed at all**: there is\nnothing to trim there, and a list could only drop a glyph the scan couldn't see.\n\nTwo failure modes, treated differently on purpose:\n\n- A name you **declared** that doesn't resolve is a config error and **throws**.\n- A name only the **scan** found and can't resolve just **warns** — a bare unmapped\n name is more often a local \\`src/icons/*.svg\\` than a mistake, and a dev server\n that dies on a template typo is worse than one that tells you.\n\nNames computed at runtime (\\`<Icon name={expr} />\\`) can't be read statically. They are\nreported with file and line, never guessed at — declare them in \\`semantic\\` or a\nper-set list. Run \\`vitops icons\\` to see the whole report.\n\n## Delivery\n\n| Path | Used by | Needs |\n| --- | --- | --- |\n| \\`astro-icon\\` / \\`astro-iconset\\` | Astro sites | the integration, an optional peer |\n| **SVG sprite** (\\`icons.svg\\`) | Bricks/WordPress, EmDash renderers, plain HTML | \\`icons.sprite: true\\` |\n\nThe sprite is the no-JavaScript path: \\`<svg><use href=\"/vitops/icons.svg#ph--list\"></svg>\\`.\nIds are the qualified name with \\`:\\` replaced by \\`--\\` (\\`:\\` is not valid in a fragment\nidentifier), **plus a set-independent \\`icon-<name>\\` alias for every semantic name** —\nso sprite markup survives an icon-set change the same way \\`resolveIcon\\` protects Astro\ncall sites.\n\nIn WordPress, \\`vitops_icon('menu')\\` and \\`[vitops_icon name=\"menu\"]\\` emit that markup,\nand a **Vitops → Icon** Bricks element wraps the same helper.\n\n⚠️ An external-file \\`<use>\\` is **same-origin only** and dead under \\`file://\\`. Serving\n\\`dist/\\` from a different origin makes every icon vanish with no console error.\n\n## Markup\n\nAlways the framework's \\`.icon\\` box:\n\n\\`\\`\\`html\n<span class=\"icon\" aria-hidden=\"true\"><svg>…</svg></span>\n\\`\\`\\`\n\n\\`.icon\\` sizes in \\`em\\` via \\`--icon-size\\` (default \\`1.25em\\`) and sets \\`fill: currentColor\\`,\nso an icon inherits the colour of whatever it sits in. Because \\`.cta\\` and\n\\`:where(button, .btn)\\` are already \\`inline-flex\\` with a \\`gap\\`, **a start or end icon is\nchild order — not a modifier class**.\n\nIcons are \\`aria-hidden\\` by default. Pass a label only when the icon carries meaning on\nits own; beside a text label it would be announced twice.\n\nNote \\`.icon-mask\\` is a different thing: the CSS-only adornment path used by\n\\`.link--icon::before\\`, where the glyph is a \\`mask-image\\` on a pseudo-element and there\nis no markup to hang an \\`<svg>\\` on.\n`;\n}\n\nfunction renderConsentConcept(): string {\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops consent — a demand-driven permission gate',\n description:\n 'How the consent gate works: inert `type=\"text/plain\"` tags, demand-driven prompting, three-valued choices, and the invariants that make the gate real rather than a promise.',\n resource: CONFIG_PATH,\n tags: ['consent', 'cookies', 'privacy', 'gdpr', 'analytics'],\n })}\n\n# The consent gate\n\n\\`@getvitops/core/consent\\` is a **general permission gate, not an analytics feature**. Anything\nmarked \\`data-consent=\"<category>\"\\` waits on one visitor choice — a third-party tag, an A/B\nassignment, a personalisation cookie, an embedded map. It carries no Lit and is a separate\nbundle from \\`elements.js\\`, because consent is a legal requirement: a site that needs it must\nnot be made to download a rendering framework first.\n\nCategories are \\`necessary\\`, \\`analytics\\`, \\`marketing\\`, \\`preferences\\`.\n\n## Gating something\n\nA gated script renders **inert**, with its URL parked on \\`data-src\\`:\n\n\\`\\`\\`html\n<script\n type=\"text/plain\"\n data-vitops-tag\n data-consent=\"analytics\"\n data-consent-cookies=\"_ga,_ga_*\"\n data-src=\"https://example.com/analytics.js\"\n></script>\n\\`\\`\\`\n\n⚠️ **\\`type=\"text/plain\"\\` is what makes the gate real. Never give a gated tag a live \\`src\\`.**\nThe browser neither parses the body nor fetches the library, so an undecided visitor's page\nissues **no third-party request at all**. A gate that instead loads a script and politely asks\nit not to track is a promise, not a gate.\n\n\\`data-consent-cookies\\` is written by whoever emitted the tag, because that is who knows what\nthe provider sets. It is what a revoke clears.\n\n## Demand-driven: two different ideas\n\n**Offered** categories are a build-time fact — which rows \\`<CookieConsent />\\` renders. The\ndefault is deliberately generous; a hidden row costs nothing.\n\n**Demanded** categories are a runtime fact — what something has actually asked for and the\nvisitor hasn't answered. The banner appears only when a demand is outstanding, so **a site\nwhose only provider is cookieless never interrupts anyone.**\n\nDemand is registered by:\n\n- a gated element **reaching its loading strategy** — so an \\`idle\\` tag asks after \\`load\\`, off\n the LCP path, and an \\`interaction\\` tag asks only once the visitor acts; or\n- an explicit \\`require()\\` / \\`request()\\`.\n\n## The runtime API\n\n\\`window.vitopsConsent\\`, plus a \\`vitops:consent\\` \\`CustomEvent\\` on \\`document\\`.\n\n| Call | Does |\n| --- | --- |\n| \\`granted(cat)\\` | Is it granted? **Passive — does not prompt.** |\n| \\`require(cat)\\` | Declare a need *now* and report whether it's granted. **This is what raises the banner.** Synchronous. |\n| \\`request(cat)\\` | \\`require()\\`, but resolves once the visitor answers *this* category. |\n| \\`needed()\\` | Is a prompt warranted? True only if something demanded an unanswered category. |\n| \\`demanded()\\` | What has asked, this page view. |\n| \\`set(patch)\\` | Record a decision for exactly these categories. |\n| \\`open()\\` | Re-show the banner without discarding the current choice. |\n| \\`reset()\\` | Forget the choice and re-prompt. |\n\n⚠️ If you want a side effect to be *possible*, you must \\`require()\\` it. Calling \\`granted()\\`\nand doing nothing else is a **permanent no-op** on any site where nothing else demands that\ncategory: it is never offered, never granted, and your write never happens — silently.\n\n## An absent gate means \"store freely\"\n\n\\`consent.js\\` and \\`elements.js\\` are both deferred with no ordering between them, so a component\ncan upgrade and be clicked before the gate exists. \\`<Head />\\` therefore emits a synchronous\ninline **stub** that answers \\`false\\` and queues; the runtime replays the queue on load.\n\nThat makes the absence of \\`window.vitopsConsent\\` meaningful: it reliably means **this site has\nno gate**. Read it as *store freely* — never as *denied*.\n\nBecause the stub is not the full API, listen for the \\`vitops:consent\\` event rather than calling\n\\`subscribe()\\`, which the stub does not have.\n\n## Three-valued, and why it matters\n\nThe cookie (\\`vitops_consent\\`, v2) records each category as \\`true\\` / \\`false\\` / **\\`null\\`**.\n\"Not asked\" is a third value, not a synonym for \"declined\" — and only \\`null\\` can be\nre-prompted. That is what lets a \\`preferences\\` demand arrive *after* an \\`analytics\\` prompt was\nalready answered.\n\nThree consequences:\n\n- **Nothing is stored until the visitor chooses.** Absence of the cookie is *undecided*, and\n undecided denies everything but \\`necessary\\`. If merely showing the banner wrote state, the\n banner would be the thing it asks permission for.\n- **A corrupt or wrong-version cookie re-prompts.** It does not read as \"decided, all denied\" —\n that safe-looking read strands a visitor who wants to opt in with no way to say so.\n- **A patch must cover exactly the categories a showing put on screen.** \\`<wc-consent>\\` builds\n its own patch rather than calling \\`acceptAll()\\`, because \"Accept\" on a preferences-only\n prompt that also granted analytics would be consent nobody gave. \\`acceptAll()\\` /\n \\`rejectAll()\\` mean *literally every* optional category — widening a patch to \"all\" is the\n easy version of this bug.\n\n## Revoking reloads\n\nAn already-executing tracker cannot be unloaded. Clearing its cookies only stops it identifying\nthe visitor *next* time, while the running instance keeps reporting until the document goes\naway — so a revoke clears the named cookies and **reloads**. (\\`reloadOnRevoke = false\\` defers\nthat to the next navigation.)\n\n## The notice must match what loads\n\nThe same config facts drive the **generated cookie notice** — see\n[legal.md](legal.md). \\`site.analytics.clarityId\\` is what makes the notice name Clarity; the\nsame provider in \\`vitops({ analytics })\\` is what makes the tag load. The Astro integration\n**warns when the two disagree**, because a site running a tag its own notice omits is a\ncompliance defect, not a documentation gap.\n\n## Reference consumer\n\n\\`<wc-color-scheme-toggle>\\` applies the chosen scheme **immediately** and gates only the\n\\`localStorage\\` write. Nothing about honouring a visitor's click needs permission; remembering\nit does.\n`;\n}\n\nfunction renderTrackingConcept(): string {\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops conversion tracking — ad attribution and notifications',\n description:\n 'How an ad click becomes a notified conversion: the `_ac` cookie, consent-demanding capture, the pure notification planner, and the Cloudflare email channel.',\n resource: CONFIG_PATH,\n tags: ['tracking', 'attribution', 'conversions', 'notifications', 'consent'],\n })}\n\n# Conversion tracking\n\nA visitor arrives on an ad carrying a click ID; \\`<Tracking />\\` captures it into the\nfirst-party **\\`_ac\\`** cookie; when they later submit a form or tap a \\`tel:\\` link,\n\\`createConversionRoute()\\` reads the cookie back and notifies whoever the config names.\n\n\\`\\`\\`json\n{\n \"site\": {\n \"tracking\": { \"enabled\": true, \"category\": \"marketing\" },\n \"notifications\": { \"email\": \"leads@example.com\" }\n }\n}\n\\`\\`\\`\n\nA bare address is shorthand for \\`{ provider: \"cloudflare\", to }\\`. The recipient otherwise\nfalls back to the primary location's email, and the sender to \\`noreply@<domains.canonical>\\`.\n\n## Where each piece lives\n\n| Layer | Module | Why there |\n| --- | --- | --- |\n| Attribution vocabulary + cookie | \\`@getvitops/utils/tracking\\` | Needed on **both** sides of the wire |\n| Plan / render / send | \\`@getvitops/utils/notify\\` | Pure planner, I/O sender |\n| Capture script, \\`<Tracking />\\`, route factory | \\`@getvitops/astro\\` | Beside the analytics components |\n\nBoth utils entries are **separate subpaths** because they are the only modules that run in a\n**Worker** rather than at build time. Keeping them off the package index is what stops a\nconversion endpoint pulling \\`sharp\\` into its bundle. Neither may use a Node builtin.\n\n## The capture demands consent\n\n\\`_ac\\` is a 90-day identifier tying a visitor to an ad, so it waits on \\`marketing\\` (override\nwith \\`site.tracking.category\\`).\n\n⚠️ The script calls **\\`require()\\`**, not \\`granted()\\` — \\`require()\\` is what *raises the\nbanner*. A passive \\`granted()\\` here is a permanent no-op: nothing else on a page demands\n\\`marketing\\`, so it is never offered, never granted, and \\`_ac\\` is never written — silently, on\nevery gated site. The integration adds \\`marketing\\` to the offered categories when tracking is\non, so there is a row for the category the script will ask about.\n\n**Only an arrival that carried something asks.** The demand is guarded on the URL actually\nholding a click ID or UTM, so an organic visitor — who has nothing to attribute — is never\ninterrupted. That is demand-driven consent applied to attribution.\n\n**The capture is synchronous; only the write waits.** Reading the query string is not storage\nand needs no permission; *keeping* it does. The click ID is in the URL only on the landing\npage, so deferring the read would lose it outright.\n\nThe marker element carries \\`data-consent\\` but deliberately **not** \\`data-vitops-tag\\`: the\nscan never tries to \"activate\" it (it is ungated by design), while the revoke path — which\nqueries \\`[data-consent=\"…\"]\\` — still finds it and clears \\`_ac\\`.\n\n## The event is the abstraction\n\n\\`ConversionEvent\\` is the *fact*; how it reads belongs to the channel. That is what lets an SMS\nchannel render 160 characters from the same event an email renders in full.\n\n**The plan is pure and says why anything is skipped.** \\`planNotifications\\` touches no network\nand no binding, so a misconfigured site can be told exactly why no notification will arrive — a\nsilently unsent conversion notification is indistinguishable from no conversion.\n\n## The email channel\n\nCloudflare Email Sending's **current** binding — structured\n\\`env.EMAIL.send({ to, from, subject, html, text })\\`, not the legacy \\`EmailMessage\\` plus\nhand-built MIME. The binding is **passed in, never imported**, so utils takes no Cloudflare\ndependency.\n\nOnly transient codes are retried. \\`E_SENDER_NOT_VERIFIED\\` and friends are surfaced\n**verbatim**, because nothing here can check whether the sending domain was onboarded — run:\n\n\\`\\`\\`sh\nwrangler email sending enable <domain>\n\\`\\`\\`\n\nA generic \"send failed\" would hide the one thing worth knowing.\n\nOnly \\`email\\` is implemented. \\`sms\\` and \\`persist\\` are a planned seam\n(\\`NotificationsConfig\\` plus a sender with \\`sendEmail\\`'s signature); one channel is not enough\nto know what the abstraction should be.\n\n## Disclosure\n\n\\`_ac\\` is disclosed by the generated cookie notice as a first-party cookie. It has to be stated\nexplicitly: no provider table would ever name a first-party cookie, so a site running\nattribution alongside a **cookieless** analytics provider would otherwise be described as\nsetting no cookies at all. See [legal.md](legal.md).\n`;\n}\n\nfunction renderSearchConcept(): string {\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops search — Search Console onboarding and deploy notification',\n description:\n 'What search engines actually accept, why the Indexing API is deliberately not wired, and how `vitops search setup` and `vitops search notify` work.',\n resource: CONFIG_PATH,\n tags: ['seo', 'search-console', 'indexnow', 'sitemap', 'indexing'],\n })}\n\n# Search\n\nTwo commands, both anchored to a full config:\n\n- **\\`vitops search notify\\`** — tell search engines a deploy happened (from \\`site.seo.indexing\\`).\n- **\\`vitops search setup\\`** — onboard domains into Search Console (from \\`site.searchConsole\\`).\n\n## Start from what engines actually accept\n\nThe obvious assumption is wrong, and every design decision here follows from that:\n\n- **Google exposes no \"request indexing\" API.** The button in the Search Console UI is not in\n the Search Console API or anywhere else, and the **URL Inspection API is read-only**.\n- **The sitemap ping endpoint was removed in June 2023.** \\`google.com/ping?sitemap=\\` is a no-op.\n- **The Indexing API is scoped to \\`JobPosting\\` / \\`BroadcastEvent\\`.** It accepts other URLs and\n discards them; general use violates its terms, with *your own* GCP project on the line.\n ⚠️ **Deliberately not wired. Do not add it.**\n- **Google does not participate in IndexNow.** Bing, Yandex, Naver, Seznam and Yep do.\n\nSo \\`search notify\\` does every sanctioned thing and then **verifies**: resubmit the sitemap,\nping IndexNow, and \\`--check\\` inspects \\`priorityUrls\\` and exits non-zero on one Google hasn't\nindexed. That last part is what actually replaces the manual Search Console visit.\n\n⚠️ Never describe this as making Google re-index faster. It cannot.\n\n## \\`search notify\\`\n\n- **The pure/I-O split is the point.** The planner decides everything — which URLs, which\n channels, why each was skipped — and touches no network, no filesystem, no clock. That is what\n makes \\`--dry\\` a *complete* account of a run rather than an approximation.\n- **\\`lastmod\\` is not a nice-to-have, it is the mechanism.** The changed-URL diff compares each\n sitemap entry's \\`<lastmod>\\` against a stored snapshot. With no lastmod the diff can see pages\n appear and disappear but **never see one change** — so an edited page is never resubmitted, and\n the command looks healthy while doing less than it appears to. It counts lastmod-less entries\n and says so every run.\n\n \\`gitLastmod()\\` in \\`@getvitops/astro\\` derives real dates from \\`git log\\`. It is an exported\n helper rather than a \\`sitemap\\` option because it shells out to git and returns **nothing**\n from a shallow CI clone (\\`fetch-depth: 1\\`). It leaves an unmatched URL alone rather than\n stamping the build time: Google weighs lastmod only while it stays consistent with what\n actually changed, so a site that stamps every page every deploy teaches it to distrust the\n field site-wide.\n- **The \\`noindex\\` gate reads the environment, so the URLs must too.** The run is refused\n entirely when the resolved environment's \\`robots\\` contains \\`noindex\\` — submitting a staging\n host to IndexNow publishes it to several engines and invites them to crawl it, which a later\n directive does not undo. Origins therefore derive from \\`site.environments[env].url\\` **before**\n \\`domains.canonical\\`: the canonical is the *production* origin, so deriving from it while\n notifying staging would submit production URLs the gate would not catch.\n- **Verify the IndexNow key file before submitting.** A submission whose key file is unreachable\n returns \\`403\\`, but one whose key file is *reachable and stale* is accepted with \\`202\\` and then\n silently discarded. Only a prior GET distinguishes \"submitted\" from \"submitted and ignored\".\n The key is **not a secret** — the engine fetching it back is the ownership proof — so it lives\n in the config, and the Astro integration writes \\`public/<key>.txt\\` from it.\n- **Write the snapshot last, and only on success.** Writing it eagerly records URLs as notified\n that never were; because the next run diffs against it, one transient \\`503\\` would drop those\n pages from every future run — silently and permanently. A corrupt or absent snapshot reads as\n \"submit everything, and say so\", never as \"nothing changed\".\n\n## \\`search setup\\`\n\nAutomates the otherwise-manual DNS-paste / wait / verify / add-property dance.\n\\`site.searchConsole\\` is keyed by bare hostname (mirroring \\`site.dns\\`):\n\n\\`\\`\\`json\n{\n \"site\": {\n \"searchConsole\": {\n \"example.com\": {\n \"delegatedOwners\": [\"dev@example.com\"],\n \"fullUserGroup\": \"seo@example.com\"\n }\n }\n }\n}\n\\`\\`\\`\n\nPer domain it ensures the apex verification TXT in Cloudflare, verifies ownership via the Site\nVerification API (\\`DNS_TXT\\`), adds the \\`sc-domain:\\` property, then adds any\n\\`delegatedOwners\\`. The verification token is fetched live and written to DNS — never stored in\nthe config.\n\n- **Idempotency lives in the planner.** A step whose desired state already holds resolves to\n \\`skip\\`, so re-running an onboarded domain is a no-op **by construction**, not because the\n executors check twice. \\`--check\\` reports drift, exits non-zero and mutates nothing;\n \\`--dry\\` prints the plan and stops.\n- **DNS is only ever created, never edited or deleted.** The command never removes a record, so\n the Cloudflare executor simply has no update or delete verb.\n- **Verification retries with backoff, then reports PENDING — not failed.** \\`DNS_TXT\\`\n verification fails until the record propagates, which is slow, not broken. A domain still\n unverified after the last attempt is \\`PENDING\\`, and its property and owner steps are skipped\n for that run. Re-run later.\n- **Search Console has no user/permission API.** Adding a Google Group as a **Full User** is\n genuinely un-automatable, so \\`fullUserGroup\\` is surfaced as a **reminder** in the summary,\n never attempted. That is distinct from \\`delegatedOwners\\`, which *are* automated — those are\n Site Verification web-resource owners (an additive union, so an existing owner is never\n dropped), a different concept from Search Console property users. Don't conflate them.\n\n## Credentials\n\nAlways from the environment; never in the config. There is **one** token exchange and **two\ngrants**, tracking where each command runs:\n\n| Grant | Env vars | Used by |\n| --- | --- | --- |\n| **Service account** (JWT bearer) | \\`VITOPS_GSC_SERVICE_ACCOUNT\\` (inline JSON) or \\`GOOGLE_APPLICATION_CREDENTIALS\\` (path) | \\`search notify\\` — never expires, right for CI |\n| **User OAuth** (refresh token) | \\`VITOPS_GOOGLE_CLIENT_ID\\` / \\`_CLIENT_SECRET\\` / \\`_REFRESH_TOKEN\\` | \\`search setup\\` — **required** |\n\nCloudflare uses \\`CLOUDFLARE_API_TOKEN\\` (a \\`Zone:DNS:Edit\\` token; the standard \"Edit zone DNS\"\ntemplate also carries the \\`Zone:Read\\` the zone-by-name lookup needs).\n\n\\`search setup\\` requires user OAuth because **verifying a site makes the caller an owner** of\nthe property, and that should be a person, not a project robot. Note a refresh token can be\nrevoked, and for an OAuth client still in *Testing* publishing status Google expires it after\n**7 days** — fine for a one-time human setup, bad for a deploy step.\n\n**\\`search notify\\` accepts either**, preferring the service account when both are set. Search\nConsole does not care which identity calls it, and someone who has run \\`search setup\\` already\nholds a Google credential.\n\n⚠️ Do not add \\`googleapis\\` — an enormous dependency for a handful of REST endpoints in a CLI\nthat installs into every consumer project. The JWT is minted with ~30 lines of \\`node:crypto\\`.\n`;\n}\n\nfunction renderLegalConcept(): string {\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops legal documents — generated policy, terms and cookie notice',\n description:\n 'How the privacy policy, terms of service and cookie notice are derived from config facts, why the provider table exists, and the four delivery paths.',\n resource: CONFIG_PATH,\n tags: ['legal', 'privacy', 'cookies', 'pipeda', 'compliance'],\n })}\n\n# Legal documents\n\nA privacy policy, terms of service and cookie notice, rendered from a full config: the company\nfrom \\`organization\\`, what the site actually *does* from \\`site\\`.\n\nIt is a **sibling of the docs generator, not a \\`generate()\\` format** — structurally, not\nstylistically. \\`generate()\\` is keyed to a design system, so a \"legal format\" would be a format\nthat ignores its own input.\n\n## The governing rule\n\n**The config records facts; the template owns prose.**\n\nNothing in the derivation writes a sentence a lawyer would review, and no template invents a\nfact. That is what lets wording be corrected without touching your config, and your provider\nchange land without touching prose.\n\n⚠️ It also means **the fix for a wrong policy is a corrected config.** Hand-editing the output\nis overwritten by the next build.\n\n## What derives from what\n\n- **The provider table is what makes derivation possible.** A policy naming Plausible while the\n site runs GA is a compliance defect, not a typo — so the provider comes from *which analytics\n ID is set*, whether \\`site.security.turnstile.siteKey\\` exists, and what\n \\`site.deployment.platform\\` says. Never from a hand-maintained string.\n\n It covers only what the schema can imply. Everything else — payment, CRM, mail — is declared\n in \\`site.legal.privacyPolicy.processors\\` and flows through the same pipeline.\n\n- **\\`cookies: []\\` is meaningfully different from \\`undefined\\`.** It *asserts* a provider is\n cookieless (Plausible), which the cookie notice states **positively** rather than omitting.\n\n- **\"Stored in\" is not the same fact as \"reachable by\".** A processor's \\`storage\\` is where the\n information rests; \\`operatorCountry\\` is the jurisdiction that can compel the provider to hand\n it over. Privacy law turns on foreign **access**, not merely foreign storage, so the two get\n separate sentences — an Azure tenant in a Canadian region never moves the data and is still\n subject to US law. \\`country\\` is shorthand asserting both, and combining it with either is\n **rejected** rather than resolved by a silent rule: whether it narrows or adds is a\n contradiction between two legal claims, not a formatting choice.\n\n A \\`storage\\` entry may be \\`scope\\`d to a category, which is what makes a Canadian tenant\n holding identity data abroad expressible. A country in the policy's own jurisdiction is not a\n transfer and is filtered out — that is what stopped \\`country: \"Canada\"\\` rendering \"outside of\n Canada, including Canada\". Only what the config states is asserted: hosts like Cloudflare\n declare an \\`operatorCountry\\` and **no** storage, because anycast means the config cannot know\n which region served a request, and \"we don't know\" is a fact.\n\n- **Form templates are the PII inventory.** \\`site.templates\\` entries of type \\`form\\` are the\n only place the config says what personal information the site actually collects, so the\n disclosed list derives from their fields. \\`hidden\\` fields and honeypots are **excluded** —\n neither is visitor-supplied, and describing them as collected would be untrue.\n\n- **First-party cookies are declared, not detected.** The attribution cookie \\`_ac\\` is disclosed\n this way; see [tracking.md](tracking.md).\n\n## The markdown subset is closed\n\nWe author every template, so the renderer is exactly as capable as they are: \\`#\\`/\\`##\\`/\\`###\\`,\n\\`- \\` bullets, \\`> \\` quote, \\`**strong**\\`, \\`\\\\\\`code\\\\\\`\\`. **An unsupported construct is an error,\nnot a silent degrade** — that is what stops a literal \\`| --- |\\` reaching a published page.\n\nPortable Text maps the \\`> \\` quote to a banner block and **drops the \\`# \\` heading**, which is\nEmDash's own title field.\n\n## Jurisdictions\n\nAdding one is: author three templates, add one enum member, add one registry key. The two are\nchecked against each other at compile time, so skipping either **fails to compile** rather than\nrendering against the wrong body of law.\n\n⚠️ Only **\\`ca\\` (PIPEDA)** ships. Its prose names the Office of the Privacy Commissioner of\nCanada and frames transfers as \"outside of Canada\" — **do not reuse it for another\njurisdiction.**\n\n## Delivery: one renderer, four consumers\n\n| Consumer | How |\n| --- | --- |\n| **any stack** | \\`vitops legal [--doc <name>] [--format md\\\\|html\\\\|portable-text] [--out <dir>]\\` — stdout without \\`--out\\`. Hugo, Eleventy or a hand-built WordPress theme need no integration code. |\n| **WordPress** | \\`generate({ site })\\` also emits \\`dist/legal/*.html\\`; \\`[vitops_legal doc=\"privacy\"]\\` renders one. \\`doc\\` is matched against a fixed allowlist, because it lands in a filesystem read. |\n| **Astro** | \\`vitops({ legal: { input, out } })\\` — a sibling of \\`css\\`, not a widening of it. Regenerates on config change; writes markdown to a content collection. No route injection. |\n| **EmDash** | \\`--format portable-text\\`, pasted into the admin. |\n\nThe CLI is the load-bearing one: it is the surface every consumer has regardless of stack.\n\n## The review banner\n\nEvery document opens with a **non-optional** review banner. These are rendered from a template\nby a build tool; the one failure mode with real consequences is a consumer publishing one as-is.\n`;\n}\n\nfunction renderConceptsIndex(): string {\n return `${INDEX_NOTE}\n\n# Design-system concepts\n\n# Contents\n\n* [Colour system](color.md) - seeded OKLCH scales on a shared lightness ladder, target-prefixed tokens, automatic dark mode\n* [Type & space scales](scales.md) - fluid modular scales and the tokens they emit\n* [Component patterns](patterns.md) - token cascade, override hooks, states, role variants\n* [Components](components.md) - which of the four tiers provides each pattern, and the call to make\n* [Icons](icons.md) - semantic names across icon sets, bundle derivation, sprite delivery\n* [Consent gate](consent.md) - inert gated tags, demand-driven prompting, three-valued choices\n* [Conversion tracking](tracking.md) - ad-click attribution, the \\`_ac\\` cookie, conversion notifications\n* [Search](search.md) - what engines accept, Search Console onboarding, deploy notification\n* [Legal documents](legal.md) - policy/terms/cookie notice derived from config facts\n`;\n}\n\nfunction renderCssIndex(): string {\n return `${INDEX_NOTE}\n\n# CSS framework\n\n# Contents\n\n* [Class vocabulary](classes.md) - every utility and component class, summarized by naming rule\n`;\n}\n\nfunction renderBricksIndex(): string {\n return `${INDEX_NOTE}\n\n# Bricks Builder integration\n\n# Styling\n\nPrefer adding the framework **CSS classes** — see [/css/classes.md](../css/classes.md) — in a\nBricks element's \"CSS classes\" field over hand-setting spacing, colour, or typography through\nthe Bricks Builder property panels. The classes encode the design system's tokens, responsive\ngrammar, and interaction states, so they stay consistent, respond to theme / dark mode, and\nupdate with the system. Values typed directly into Bricks' property controls are one-off,\ndrift from the system, and don't react to theme changes — reserve them for genuinely bespoke,\none-element cases.\n\n# Contents\n\n* [Elements reference](elements.md) - every custom Vitops element, its controls, defaults, seeded children and keywords\n* [Class vocabulary](../css/classes.md) - the framework CSS classes to apply to elements\n`;\n}\n\n/**\n * Build the OKF docs bundle for a config. Returns a `{ relPath: content }` map;\n * the caller writes it wherever the bundle should live (e.g. `<outDir>/docs`).\n */\nexport function generateDocs(ds: DesignSystem, assetsDir: string): Record<string, string> {\n const elementsDir = join(assetsDir, 'bricks', 'elements');\n return {\n 'index.md': renderTopIndex(),\n 'authoring.md': renderAuthoring(),\n 'config.md': renderConfig(),\n 'formats.md': renderFormats(ds),\n 'concepts/index.md': renderConceptsIndex(),\n 'concepts/color.md': renderColorConcept(ds),\n 'concepts/scales.md': renderScalesConcept(ds),\n 'concepts/patterns.md': renderPatternsConcept(ds),\n 'concepts/components.md': renderComponentsConcept(ds),\n 'concepts/icons.md': renderIconsConcept(),\n 'concepts/consent.md': renderConsentConcept(),\n 'concepts/tracking.md': renderTrackingConcept(),\n 'concepts/search.md': renderSearchConcept(),\n 'concepts/legal.md': renderLegalConcept(),\n 'css/index.md': renderCssIndex(),\n 'css/classes.md': renderCssClasses(ds),\n 'bricks/index.md': renderBricksIndex(),\n 'bricks/elements.md': renderElementsDoc(elementsDir),\n };\n}\n","/**\n * `DESIGN.md` emitter — the `design` format.\n *\n * DESIGN.md (google-labs-code/design.md, alpha) is a single plain-text file that\n * gives AI coding agents a persistent, structured understanding of a visual\n * identity: YAML front matter carrying the tokens, then a prose body carrying the\n * *why*. It is the agent-facing sibling of `tokens.json` — where that file is a\n * verbatim dump for programmatic consumers, this one is curated for a reader.\n *\n * Three impedance mismatches between our schema and the spec, resolved the same\n * way every time (and stated in the prose so the file is self-describing):\n *\n * • **Fluid sizes are `clamp()`**; a spec `Dimension` is a bare number + px/em/rem.\n * → Emit the scale's **max** rem as the canonical size and say in the prose that\n * the real token is fluid. A `clamp()` string would fail every consumer's parse.\n * • **Dark mode has no first-class representation.** → `colors` carries the LIGHT\n * values; the Colors prose explains that the framework flips functionally at\n * runtime, so an agent that uses the role tokens gets dark mode for free and\n * should never hand-pick a dark value.\n * • **A role is not a ramp alias.** Functional tokens resolve to a ramp step, so\n * they are emitted as `{colors.<hue>-<step>}` **references** rather than\n * flattened hexes — that keeps the role → ramp lineage visible in the file,\n * which is the one thing a flattened export destroys. `on-solid` is the\n * exception: it is a computed contrast literal with no step behind it.\n */\nimport type { DesignSystem } from './schema.ts';\nimport { DARK_SEL, type RoleSpec, roleHue } from './shared.ts';\nimport { tokenClass, type ExpandedHue, type FunctionalRole } from './tokens.ts';\n\n/** Structural view of `generate.ts`'s ScaleStep (kept local to avoid a cycle). */\ninterface Step {\n name: string;\n value: string;\n max: string;\n}\n\nexport interface DesignMdCtx {\n ds: DesignSystem;\n expandedPalette: Record<string, ExpandedHue>;\n scaleRoles: FunctionalRole[];\n typeSteps: Step[];\n spaceSteps: Step[];\n shadows: Record<string, string> | undefined;\n}\n\ninterface PatternItem {\n group?: string;\n overrides?: Record<string, string>;\n element?: string;\n class?: string;\n fill?: boolean;\n default_role?: string;\n base?: Record<string, string>;\n states?: Record<string, Record<string, unknown>>;\n roles?: string[];\n}\n\n// ── minimal YAML writer ───────────────────────────────────────────────────────\n// Hand-rolled rather than pulled in as a dependency: the generator emits a fixed,\n// known shape (scalars two levels deep), and every string is double-quoted so\n// nothing here has to reason about YAML's plain-scalar edge cases — `#RRGGBB`\n// starting a comment, `{colors.x}` reading as a flow mapping, `2xl` as a key.\nconst q = (s: string) => `\"${s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\n/** Keys are quoted only when they would not survive as a plain scalar. */\nconst key = (k: string) => (/^[A-Za-z_][A-Za-z0-9_-]*$/.test(k) ? k : q(k));\nconst scalar = (v: string | number) => (typeof v === 'number' ? String(v) : q(v));\n\nconst yamlMap = (name: string, entries: [string, string | number][], indent = ''): string =>\n entries.length === 0\n ? ''\n : `${indent}${name}:\\n` +\n entries.map(([k, v]) => `${indent} ${key(k)}: ${scalar(v)}`).join('\\n') +\n '\\n';\n\n// ── value resolution ──────────────────────────────────────────────────────────\n/** `var(--x)` → `x`, else undefined. Tolerates a fallback: `var(--x, y)` → `x`. */\nconst varName = (v: string): string | undefined => {\n const m = /^var\\(\\s*--([a-z0-9-]+)\\s*(?:,[^)]*)?\\)$/i.exec(v.trim());\n return m ? (m[1] as string) : undefined;\n};\n\n/** A spec `Dimension` is a number plus px / em / rem — nothing else parses. */\nconst isDimension = (v: string) => /^-?(?:\\d+\\.?\\d*|\\.\\d+)(?:px|em|rem)$/.test(v.trim());\n\n/**\n * Only these reach a `Color` slot. `inherit` / `currentColor` / `initial` are\n * valid CSS in a pattern's `base` and meaningless as a token value, so a\n * component that says `color: inherit` emits no `textColor` at all rather than\n * an unresolvable one.\n */\nconst isColorLiteral = (v: string) =>\n /^#[0-9a-f]{3,8}$/i.test(v.trim()) ||\n /^(?:rgba?|hsla?|hwb|oklch|oklab|lch|lab|color-mix)\\(/i.test(v.trim()) ||\n /^(?:transparent|white|black)$/i.test(v.trim());\n\nexport function emitDesignMd(ctx: DesignMdCtx): string {\n const { ds, expandedPalette, scaleRoles, typeSteps, spaceSteps, shadows } = ctx;\n const meta = ds.meta ?? {};\n const name = meta.name ?? 'Design System';\n const roleMap = ds.colors.roles as Record<string, RoleSpec>;\n const patterns = ds.patterns ?? {};\n const pDefaults = (patterns.defaults ?? {}) as Record<string, string>;\n const pRadii = (patterns.radii ?? {}) as Record<string, string>;\n const pGroups = (patterns.groups ?? {}) as Record<string, Record<string, string>>;\n const pItems = (patterns.items ?? {}) as Record<string, PatternItem>;\n\n // ── colors ─────────────────────────────────────────────────────────────────\n // Raw ramps first (they are what everything else references), then the\n // functional role tokens as refs into them, then the spec's recommended names\n // as refs into those. Three layers, each one hop from the last.\n const ramps: [string, string][] = [];\n for (const [hue, expanded] of Object.entries(expandedPalette))\n for (const [step, hex] of Object.entries(expanded.numeric)) ramps.push([`${hue}-${step}`, hex]);\n\n const rampNames = new Set(ramps.map(([k]) => k));\n /** `var(--color-<hue>-<step>)` → `{colors.<hue>-<step>}`; literals pass through. */\n const rampRef = (value: string): string => {\n const v = varName(value);\n const bare = v?.startsWith('color-') ? v.slice('color-'.length) : undefined;\n return bare && rampNames.has(bare) ? `{colors.${bare}}` : value;\n };\n\n const roleTokens: [string, string][] = [];\n for (const fr of scaleRoles)\n for (const [token, value] of Object.entries(fr.light))\n // Flattened as the utility class name (`bg-surface`, `text-on-danger`) —\n // the same string an agent would write in markup, so the brief and the\n // markup vocabulary are one thing rather than two.\n roleTokens.push([tokenClass(fr.role, token), rampRef(value)]);\n\n const colorNames = new Set([...rampNames, ...roleTokens.map(([k]) => k)]);\n /** Recommended-name alias, emitted only when the role behind it exists. */\n const aliasAs = (as: string, token: string): [string, string][] =>\n colorNames.has(token) ? [[as, `{colors.${token}}`]] : [];\n // The spec's non-normative recommended names (`primary`, `on-primary`,\n // `error`, …). Ours are role-scoped, so nothing here is a new value — each is\n // a one-hop reference, which is exactly what makes a generic DESIGN.md\n // consumer (and the linter's `primary`-must-exist rule) work against a\n // vocabulary that never uses those words.\n const interop: [string, string][] = [\n ...aliasAs('primary', 'bg-ui-primary-solid'),\n ...aliasAs('on-primary', 'text-on-ui-primary'),\n ...aliasAs('secondary', 'bg-ui-secondary-solid'),\n ...aliasAs('on-secondary', 'text-on-ui-secondary'),\n ...aliasAs('tertiary', 'bg-ui-accent-solid'),\n ...aliasAs('on-tertiary', 'text-on-ui-accent'),\n ...aliasAs('neutral', 'bg-neutral'),\n ...aliasAs('surface', 'bg-surface'),\n ...aliasAs('on-surface', 'text-surface'),\n ...aliasAs('error', 'bg-danger-solid'),\n ...aliasAs('on-error', 'text-on-danger'),\n ];\n\n // ── typography ─────────────────────────────────────────────────────────────\n const fonts = (ds.fonts ?? {}) as Record<string, string>;\n const families = (ds.typography?.families ?? {}) as Record<string, string>;\n /** `display` → `var(--font-display)` → the actual stack. */\n const fontStack = (family: string | undefined): string | undefined => {\n if (!family) return undefined;\n const declared = families[family];\n if (declared == null) return fonts[family];\n const v = varName(declared);\n const bare = v?.startsWith('font-') ? v.slice('font-'.length) : undefined;\n return (bare && fonts[bare]) ?? declared;\n };\n const textMax = new Map(typeSteps.map((s) => [s.name, s.max]));\n /** `var(--text-3xl)` → that step's MAX rem (a clamp() is not a Dimension). */\n const typeSize = (size: string | number | undefined): string | undefined => {\n if (size == null) return undefined;\n const raw = String(size);\n const v = varName(raw);\n const bare = v?.startsWith('text-') ? v.slice('text-'.length) : undefined;\n const resolved = bare != null ? textMax.get(bare) : raw;\n return resolved != null && isDimension(resolved) ? resolved : undefined;\n };\n\n const typoRoles = (ds.typography?.roles ?? {}) as Record<\n string,\n Record<string, string | number | undefined>\n >;\n const typography: [string, [string, string | number][]][] = [];\n for (const [role, spec] of Object.entries(typoRoles)) {\n const props: [string, string | number][] = [];\n const stack = fontStack(spec.family as string | undefined);\n if (stack) props.push(['fontFamily', stack]);\n const size = typeSize(spec.size);\n if (size) props.push(['fontSize', size]);\n if (spec.weight != null) props.push(['fontWeight', Number(spec.weight)]);\n const lh = spec['line-height'];\n if (lh != null) {\n const n = Number(lh);\n props.push(['lineHeight', Number.isFinite(n) ? n : String(lh)]);\n }\n const tracking = spec.tracking;\n if (tracking != null && isDimension(String(tracking)))\n props.push(['letterSpacing', String(tracking)]);\n if (props.length) typography.push([role, props]);\n }\n\n // ── rounded ────────────────────────────────────────────────────────────────\n // DEFAULT + the named radii + one entry per pattern GROUP, because a component\n // references its group's radius (`{rounded.control}`), not a bare literal —\n // the group alias layer is the whole point of the cascade.\n //\n // A spec `Dimension` is a number plus px/em/rem, so a bare `0` is rejected\n // even though it is perfectly good CSS: normalise it to `0px`, which is the\n // same value in every context a radius is used. A radius that is genuinely not\n // a Dimension (`50%`, for a circle) cannot be normalised and is dropped from\n // the map rather than emitted as an error — `unroundable` carries it into the\n // Shapes prose so it is stated, not lost.\n const unroundable: [string, string][] = [];\n const asDimension = (v: string): string | undefined => {\n const t = v.trim();\n if (isDimension(t)) return t;\n return /^-?0+(?:\\.0+)?$/.test(t) ? '0px' : undefined;\n };\n const rounded: [string, string][] = [];\n const pushRadius = (name: string, value: string) => {\n const dim = asDimension(value);\n if (dim) rounded.push([name, dim]);\n else unroundable.push([name, value]);\n };\n if (pDefaults.br) pushRadius('DEFAULT', pDefaults.br);\n for (const [n, v] of Object.entries(pRadii)) pushRadius(n, v);\n const roundedNames = new Set(rounded.map(([k]) => k));\n /** `var(--br-default)` → `{rounded.DEFAULT}`, `var(--br-pill, 999px)` → `{rounded.pill}`. */\n const roundedRef = (value: string): string => {\n const v = varName(value);\n const bare = v?.startsWith('br-') ? v.slice('br-'.length) : undefined;\n if (bare === 'default') return '{rounded.DEFAULT}';\n return bare && roundedNames.has(bare) ? `{rounded.${bare}}` : value;\n };\n for (const [group, props] of Object.entries(pGroups)) {\n if (props.br == null) continue;\n const ref = roundedRef(props.br);\n if (ref !== props.br) rounded.push([group, ref]);\n else pushRadius(group, props.br);\n }\n const roundedAll = new Set(rounded.map(([k]) => k));\n\n // ── spacing ────────────────────────────────────────────────────────────────\n // Max rem again: the emitted `--space-*` tokens are fluid clamps.\n const spacing: [string, string][] = [];\n if (ds.spaceScale?.base) spacing.push(['base', ds.spaceScale.base]);\n for (const s of spaceSteps)\n if (!spacing.some(([k]) => k === s.name)) spacing.push([s.name, s.max]);\n\n // ── components ─────────────────────────────────────────────────────────────\n /** Walk a pattern's geometry cascade: overrides → group → defaults. */\n const cascade = (p: PatternItem, prop: string): string | undefined =>\n p.overrides?.[prop] ?? (p.group ? pGroups[p.group]?.[prop] : undefined) ?? pDefaults[prop];\n\n /** A colour-ish CSS value → a `{colors.x}` ref, a literal, or nothing. */\n const colorValue = (value: string | undefined): string | undefined => {\n if (value == null) return undefined;\n const v = varName(value);\n if (v != null) {\n if (colorNames.has(v)) return `{colors.${v}}`;\n const bare = v.startsWith('color-') ? v.slice('color-'.length) : undefined;\n if (bare && colorNames.has(bare)) return `{colors.${bare}}`;\n return undefined;\n }\n return isColorLiteral(value) ? value.trim() : undefined;\n };\n\n /**\n * Resolve a `base` declaration that goes through the group alias layer\n * (`var(--br-card-group)` → the card's `br` cascade), and turn the result into\n * a `{rounded.*}` ref where one exists.\n */\n const geometry = (\n p: PatternItem,\n pname: string,\n baseProp: string,\n token: string,\n ): string | undefined => {\n const declared = p.base?.[baseProp];\n if (declared == null) return undefined;\n const v = varName(declared);\n if (v !== `${token}-${pname}-group`) return declared;\n const resolved = cascade(p, token);\n if (resolved == null) return undefined;\n if (token !== 'br') return resolved;\n const ref = roundedRef(resolved);\n if (ref !== resolved) return ref;\n // A bare literal here came from the group's own `br` — and the group IS a\n // `rounded` entry — UNLESS the pattern overrode it, in which case the value\n // is this pattern's alone and pointing at the group would be a lie.\n return p.overrides?.br == null && p.group && roundedAll.has(p.group)\n ? `{rounded.${p.group}}`\n : resolved;\n };\n\n const components: [string, [string, string][]][] = [];\n const roleVariants: string[] = [];\n for (const [pname, p] of Object.entries(pItems)) {\n if (!p.base) continue;\n const base = p.base;\n // Mirrors generate.ts's fill inference exactly — a component whose fill is\n // guessed differently here would describe colours the CSS never sets.\n const fills =\n p.fill ??\n (pname === 'button' ||\n pname === 'badge' ||\n base['background-color'] != null ||\n base['background'] != null);\n const props: [string, string][] = [];\n if (fills) {\n const bg =\n colorValue(base['background-color']) ??\n colorValue(base['background']) ??\n (p.default_role ? colorValue(`var(--color-bg-${p.default_role}-solid)`) : undefined);\n if (bg) props.push(['backgroundColor', bg]);\n }\n const fg =\n colorValue(base['color']) ??\n (fills && p.default_role ? colorValue(`var(--color-text-on-${p.default_role})`) : undefined);\n if (fg) props.push(['textColor', fg]);\n // A radius that didn't survive into `rounded` (a `50%` circle) would emit\n // either a broken reference or a non-Dimension literal here, so the property\n // is dropped instead; the Shapes prose names those patterns.\n const br = geometry(p, pname, 'border-radius', 'br');\n const brRef = /^\\{rounded\\.([^}]+)\\}$/.exec(br ?? '');\n if (brRef && roundedAll.has(brRef[1] as string)) props.push(['rounded', br as string]);\n else if (br && asDimension(br)) props.push(['rounded', asDimension(br) as string]);\n else if (br) {\n // The Shapes prose wants the value, not the plumbing: `var(--br-circle,\n // 50%)` is how the cascade spells it, `50%` is what the reader needs.\n const named = varName(br);\n const bare = named?.startsWith('br-') ? named.slice('br-'.length) : undefined;\n unroundable.push([pname, (bare ? pRadii[bare] : undefined) ?? br]);\n }\n const pad = geometry(p, pname, 'padding', 'p');\n if (pad) props.push(['padding', pad]);\n if (props.length) components.push([pname, props]);\n\n // A hover that carries `step` intensifies the pattern's own colour; that is\n // a real variant an agent must reproduce, so it gets its own entry (the\n // spec's `-hover` sibling-key convention).\n const hover = p.states?.hover;\n const dr = p.default_role;\n if (hover && typeof hover.step === 'number' && dr) {\n const strong = hover.step >= 1;\n const hv = fills\n ? colorValue(`var(--color-bg-${dr}-${strong ? 'solid-bold' : 'solid'})`)\n : colorValue(`var(--color-text-${dr}${strong ? '-bold' : ''})`);\n if (hv) components.push([`${pname}-hover`, [[fills ? 'backgroundColor' : 'textColor', hv]]]);\n }\n if (p.roles?.length)\n roleVariants.push(\n `\\`${pname}\\` → ${p.roles.map((r) => `\\`.${p.class ?? pname}-${r}\\``).join(', ')}`,\n );\n }\n\n // ── front matter ───────────────────────────────────────────────────────────\n const fm: string[] = ['---', 'version: alpha', `name: ${q(name)}`];\n if (meta.description) fm.push(`description: ${q(meta.description)}`);\n fm.push('colors:');\n fm.push(' # Raw hue ramps — 11 OKLCH steps each, tinted near-white → tinted near-black.');\n for (const [k, v] of ramps) fm.push(` ${key(k)}: ${scalar(v)}`);\n fm.push(' # Functional role tokens (LIGHT values). These are the public API: use these,');\n fm.push(' # not the raw steps, and dark mode resolves itself. See \"## Colors\" below.');\n for (const [k, v] of roleTokens) fm.push(` ${key(k)}: ${scalar(v)}`);\n if (interop.length) {\n fm.push(\" # Aliases for the spec's recommended names — references, not new values.\");\n for (const [k, v] of interop) fm.push(` ${key(k)}: ${scalar(v)}`);\n }\n if (typography.length) {\n fm.push('typography:');\n for (const [role, props] of typography) {\n fm.push(` ${key(role)}:`);\n for (const [k, v] of props) fm.push(` ${k}: ${scalar(v)}`);\n }\n }\n fm.push(yamlMap('rounded', rounded).trimEnd());\n fm.push(yamlMap('spacing', spacing).trimEnd());\n if (components.length) {\n fm.push('components:');\n for (const [cname, props] of components) {\n fm.push(` ${key(cname)}:`);\n for (const [k, v] of props) fm.push(` ${k}: ${scalar(v)}`);\n }\n }\n fm.push('---');\n\n return `${fm.filter(Boolean).join('\\n')}\\n\\n# ${name}\\n\\n${prose({\n ctx,\n name,\n meta,\n roleMap,\n ramps,\n rounded,\n unroundable,\n roleVariants,\n typography: typography.map(([r]) => r),\n })}`;\n}\n\n// ── prose body ────────────────────────────────────────────────────────────────\n/**\n * Section order is normative (Overview → Colors → Typography → Layout →\n * Elevation → Shapes → Components → Do's and Don'ts); a consumer that parses\n * sections positionally breaks if they are reordered.\n *\n * Every section interpolates live config, so this cannot drift into describing a\n * system the generator no longer emits — the same discipline `docs.ts` follows.\n */\nfunction prose(a: {\n ctx: DesignMdCtx;\n name: string;\n meta: { name?: string | undefined; description?: string | undefined };\n roleMap: Record<string, RoleSpec>;\n ramps: [string, string][];\n rounded: [string, string][];\n unroundable: [string, string][];\n roleVariants: string[];\n typography: string[];\n}): string {\n const { ctx, name, meta, roleMap, rounded, unroundable, roleVariants } = a;\n const { ds, expandedPalette, scaleRoles, typeSteps, spaceSteps, shadows } = ctx;\n const hues = Object.keys(expandedPalette);\n const roles = Object.keys(roleMap);\n const shadowNames = Object.keys(shadows ?? {});\n const typeNames = typeSteps.map((s) => s.name);\n const spaceNames = spaceSteps.map((s) => s.name);\n const bodyRole = ds.typography?.headings?.body ?? 'body';\n const s = (list: string[]) => list.map((x) => `\\`${x}\\``).join(', ');\n\n const overview =\n meta.description ??\n `${name} is a variable-driven design system: an OKLCH colour engine, fluid ` +\n `modular type and space scales, and a small set of component patterns, all ` +\n `expressed as CSS custom properties with utility classes over them.`;\n\n return `## Overview\n\n${overview}\n\nEvery value in this document is generated from a single \\`design-system.json\\` and\nemitted as CSS custom properties plus utility classes. **Prefer the class vocabulary\nover hand-written CSS** — \\`vitops docs classes\\` prints the full list, and \\`vitops lint\\`\nreports classes that resolve to nothing.\n\nThe token names below are the contract. Reach for a raw ramp step only when no\nfunctional role expresses what you mean.\n\n> Most tokens here are consumed by **utility classes**, not by the \\`components\\` block —\n> \\`bg-<role>\\`, \\`text-<role>-muted\\` and friends are the API. \\`design.md lint\\` reports\n> those as \\`orphaned-tokens\\`; that rule assumes a component-only system and does not\n> apply. Everything else it reports is worth reading.\n\n## Colors\n\n${hues.length} hue${hues.length === 1 ? '' : 's'} (${s(hues)}), each generated as an 11-step\nOKLCH scale from a seed — step \\`50\\` is a tinted near-white, \\`950\\` a tinted near-black,\nwith chroma damped toward both ends so the extremes read as neutral rather than washed.\n\n${roles.length} semantic **roles** map onto those hues:\n\n${roles.map((r) => `- \\`${r}\\` → \\`${roleHue(roleMap[r] as RoleSpec)}\\``).join('\\n')}\n\nA role is **not** an alias for a ramp. It resolves to tokens named\n\\`<target>-<role>[-<variant>]\\`, where target is one of \\`bg\\` \\`text\\` \\`icon\\` \\`border\\`. The\ntarget is part of the name on purpose: \\`bg-danger-muted\\` and \\`text-danger-muted\\` are\ndifferent tokens, so there is no ambiguity about which one a name refers to. **The token\nname is also the utility class name** — write \\`class=\"bg-danger-muted\"\\` and you are using\n\\`--color-bg-danger-muted\\`.\n\nVariants are ordinal: \\`xx-muted\\` < \\`x-muted\\` < \\`muted\\` < (bare) < \\`bold\\` < \\`x-bold\\`.\n\\`bold\\` means *more emphatic in the current appearance*, not darker.\n\nRoles come in two kinds, and the kind decides which tokens exist:\n\n- **surface** (page and panel colours) — \\`bg-<role>\\` is the card/panel, \\`bg-<role>-muted\\`\n the page behind it, \\`bg-<role>-x-muted\\` a well. Full text scale, \\`border-<role>-bold\\`\n as the contrast-guaranteed boundary.\n- **chromatic** (signal colours) — backgrounds are either *tints*\n (\\`bg-<role>-x-muted\\` / \\`-muted\\`) or *solids*\n (\\`bg-<role>-solid\\` / \\`-solid-bold\\` / \\`-solid-x-bold\\`). **There is no bare \\`bg-<role>\\`**:\n say how loud you mean. \\`text-on-<role>\\` is the guaranteed-contrast foreground for the\n solid family.\n\n**Dark mode is automatic, and this file only lists the light values.** The spec has no\nway to express a second appearance, so do not try to reconstruct one: the framework\nre-points each token at a different ramp step under \\`${DARK_SEL}\\`, so \\`bg-<role>\\`\nbecomes dark and \\`text-<role>\\` becomes light on their own. The solid family and\n\\`text-on-<role>\\` stay mode-stable by design, so a filled button keeps its identity.\n**An agent that styles with the role tokens gets dark mode for free; one that flattens\nthem to hexes breaks it.**\n\nContrast is enforced at build time, not by convention — a violation fails the build.\nText is held to APCA Lc 75 on a role's primary background and Lc 60 on its secondary\nplanes; icons and the surface boundary to Lc 45; and chromatic text is checked against\nthe *surface* planes it actually sits on, not just its own tints. Pairing\n\\`text-<role>\\` with \\`bg-<role>\\`, or \\`text-on-<role>\\` with \\`bg-<role>-solid\\`, is always\nsafe. Pairing a raw ramp step with another raw ramp step is not.\n\n## Typography\n\nFont stacks are named, and roles consume the name rather than the stack — so swapping a\ntypeface is one edit:\n\n${Object.entries((ds.fonts ?? {}) as Record<string, string>)\n .map(([n, stack]) => `- **${n}** — \\`${stack}\\``)\n .join('\\n')}\n\nType is a fluid modular scale: ${typeNames.length} steps (${s(typeNames)}) built from a\n${ds.typeScale?.base ?? '1rem'} base at a ${ds.typeScale?.ratio ?? 1.2} ratio${\n ds.typeScale?.fluid\n ? `, interpolating between a ${ds.typeScale.fluid.minRatio} ratio at ${ds.typeScale.fluid.minVw} viewport width and the full ratio at ${ds.typeScale.fluid.maxVw}`\n : ''\n }. **The \\`fontSize\\` values in the front matter are the maximum (desktop) sizes** — the\nreal tokens are \\`clamp()\\` expressions, which the spec's \\`Dimension\\` type cannot hold.\nNever hard-code the emitted number; use the scale (\\`--text-<step>\\`) or the role class.\n\nEach typography role is a class (\\`.font-<role>\\`): ${s(a.typography.map((t) => `font-${t}`))}.\nRoles also carry properties this format has no slot for — \\`text-transform\\`,\n\\`text-wrap\\`, and a \\`color\\` — so **apply the role class rather than copying its\nfront-matter properties**, or uppercase eyebrows and balanced headings silently\ndisappear. Base page text is bound to the \\`${bodyRole}\\` role, so prose inherits it.\n\n## Layout & Spacing\n\nSpacing is its own fluid modular scale: ${spaceNames.length} steps (${s(spaceNames)}) from a\n${ds.spaceScale?.base ?? '1rem'} base at a ${ds.spaceScale?.ratio ?? 1.25} ratio. As with type,\nthe front-matter values are the maxima and the live tokens are fluid.\n\nLayout is composed from utilities rather than bespoke CSS:\n\n- \\`.centered\\` — track-based centering: content sits in a centred measure while\n full-bleed children can still break out. Use it instead of \\`margin-inline: auto\\`.\n- \\`.rhythm\\` — vertical rhythm between flow children, so sibling spacing is one\n decision rather than per-element margins.\n- \\`.flex\\` / \\`.split-<a>-<b>\\` / \\`.grid\\` — the structural families, with container-query\n variants prefixed \\`sm-\\` / \\`md-\\` / \\`lg-\\` / \\`xl-\\` (30 / 48 / 64 / 80rem).\n \\`.split\\` is a two-column pair. Stack it with \\`.flex-col\\` and let a\n breakpoint-prefixed ratio un-stack it (\\`split flex-col md-split-1-2\\`);\n \\`.split-reverse\\` swaps the two panels. Reversing puts visual order out of step\n with DOM order, so keep focusable content in only one panel.\n\nBreakpoints are **container** queries, not viewport media queries: a component\nresponds to the space it is given, so the same markup works in a sidebar and a full-width\nsection.\n\n## Elevation & Depth\n\n${\n shadowNames.length\n ? `Depth comes from ${shadowNames.length} named shadow${shadowNames.length === 1 ? '' : 's'} (${s(shadowNames)}), applied as \\`--shadow-<name>\\` tokens or \\`.drop-shadow-<name>\\` utilities:\n\n${shadowNames.map((n) => `- \\`${n}\\` — \\`${(shadows ?? {})[n]}\\``).join('\\n')}\n\nEach value is deliberately a **single layer with no spread and no \\`inset\\`**: the same\ntoken feeds both \\`box-shadow\\` (pattern geometry) and \\`filter: drop-shadow()\\` (the\nutilities), and \\`drop-shadow()\\` rejects all three, which would drop the whole filter.`\n : `This system is flat: no shadow tokens are defined. Convey hierarchy with the\nsurface planes (\\`surface-bg\\` / \\`surface-bg-muted\\` / \\`surface-bg-bold\\`) and borders.`\n}\n\nSurfaces stack tonally as well: \\`surface-bg-bold\\` is the *raised* plane in both\nappearances, so a card on a page reads as lifted without any shadow at all.\n\n## Shapes\n\nCorner radii resolve through a cascade rather than being set per component:\n\\`--br-<pattern>\\` (your override hook) → \\`--br-<pattern>-group\\` → the group's radius →\n\\`--br-default\\`. Overriding one variable restyles every pattern in that tier.\n\n${rounded.map(([k, v]) => `- \\`${k}\\` — \\`${v}\\``).join('\\n')}\n\nChange a group's radius to restyle a whole tier; change \\`DEFAULT\\` to restyle everything\nthat has not opted out.\n${\n unroundable.length\n ? `\n**Not in the front matter above**, because the spec's \\`Dimension\\` type only holds\npx / em / rem — these are real radii in the system and have to be applied as CSS:\n\n${unroundable.map(([k, v]) => `- \\`${k}\\` — \\`${v}\\``).join('\\n')}`\n : ''\n}\n\n## Components\n\nPatterns are classes, not components — apply them to whatever element is semantically\ncorrect. Two tiers of button exist and the distinction is intent, not looks:\n\n- **\\`.cta\\`** is *persuasion* — filled, bolder, more padding, lifts on hover. Usually on an\n \\`<a>\\`, because a call to action usually navigates.\n- **\\`.btn\\`** is *affordance* — it only says \"this is interactive\". It is emitted at zero\n specificity for both \\`<button>\\` and \\`.btn\\`, so a bare \\`<button>\\` gets it with no class\n and **any** explicit class overrides it.\n\n${\n roleVariants.length\n ? `Role variants are systematic rather than enumerated above. A filled pattern's variant sets\n\\`background-color: var(--<role>-solid)\\` with \\`color: var(--<role>-on-solid)\\`; a text\npattern's sets \\`color: var(--color-<role>-bold)\\`:\n\n${roleVariants.map((r) => `- ${r}`).join('\\n')}`\n : ''\n}\n\nInteraction states are generated from a small grammar — \\`step\\` (intensify the colour),\n\\`scale\\`, \\`lift\\`, \\`shadow\\`, \\`ring\\` — so hover, active and focus-visible stay consistent\nacross every pattern. Focus rings are never removed, only restyled.\n\n## Do's and Don'ts\n\n- **Do** use functional role tokens (\\`ui-primary-solid\\`, \\`surface-bg\\`) over raw ramp steps.\n- **Do** pair \\`<role>-text\\` with \\`<role>-bg\\`, and \\`<role>-on-solid\\` with \\`<role>-solid\\` —\n those pairings are contrast-tested; arbitrary ones are not.\n- **Do** apply the \\`.font-<role>\\` classes rather than copying their font properties.\n- **Do** reach for a utility class before writing CSS; run \\`vitops lint\\` to catch classes\n that resolve to nothing.\n- **Don't** hard-code the \\`fontSize\\` / \\`spacing\\` numbers from the front matter — they are\n the maxima of fluid \\`clamp()\\` scales.\n- **Don't** flatten role tokens to hex values: that is exactly what breaks dark mode.\n- **Don't** invent a colour outside the ${hues.length} ramps${\n scaleRoles.length ? ` or the ${scaleRoles.length} roles` : ''\n }; add a hue to the config instead.\n- **Don't** edit this file by hand — it is generated from \\`design-system.json\\`. Change the\n config and re-run \\`vitops generate --format design\\`.\n`;\n}\n","/**\n * What the config already tells us about third parties that receive personal\n * information.\n *\n * A privacy policy's riskiest sentence is the one naming service providers: if\n * it says \"Plausible\" while the site runs Google Analytics, the document is a\n * compliance defect, not a typo. The site config already records which analytics\n * ID is set, whether Turnstile is deployed and where the site is hosted — so the\n * sentence derives from those signals rather than from a hand-maintained string\n * that drifts the moment someone swaps providers.\n *\n * Presence of the key is the signal, matching how `analytics` already works\n * (provider identity is implied by which ID is set, not by an enum).\n *\n * This table is deliberately small and covers only what the schema can imply.\n * Everything else — payment processors, CRMs, mail senders — is declared by the\n * consumer in `legal.privacyPolicy.processors`, which flows through the same\n * pipeline. This is not a directory of the web; it's the set of providers the\n * toolchain itself can vouch for.\n */\nimport { AD_PLATFORMS, AD_PROVIDER_KEYS } from '@getvitops/utils/ads';\nimport type { Config } from '../config.ts';\n\n/** One place a provider holds information, and which information if not all of it. */\nexport interface ProcessorStorage {\n /** Reads inside a sentence: \"…including the United States\". */\n country: string;\n /**\n * Reads after \"in the case of\". Present means this location holds only SOME of\n * what the provider receives, which is a narrower claim than an unscoped entry —\n * so the template gives it its own sentence rather than folding it into the list,\n * where a reader would take it to cover everything.\n */\n scope?: string | undefined;\n}\n\nexport interface Processor {\n /** The provider as a reader would recognise it. */\n name: string;\n /** Reads after \"for\": \"…to Stripe for payment processing\". */\n purpose: string;\n /**\n * Shorthand asserting BOTH `storage` and `operatorCountry` are this one country.\n *\n * Kept for the common case (and because it is public API), but note it is the\n * field whose *meaning* was never defined — its old doc comment described how it\n * READ, not what it asserted, which is how one string came to stand for two\n * different facts. Prefer the explicit pair when they differ.\n */\n country?: string | undefined;\n /**\n * Where the information actually rests. Feeds the \"stored or processed outside\n * of <jurisdiction>\" disclosure and nothing else.\n */\n storage?: ProcessorStorage[] | undefined;\n /**\n * The jurisdiction that can compel this provider to produce the information —\n * where it is established, or from which it is controlled. Reads after \"the laws\n * of\".\n *\n * A separate fact from `storage`, and the one privacy law actually turns on: the\n * OPC's concern is foreign *access*, not foreign storage. Azure in a Canadian\n * region is `storage: [{ country: 'Canada' }]`, `operatorCountry: 'the United\n * States'` — the bytes never move and US law still reaches them.\n */\n operatorCountry?: string | undefined;\n privacyUrl?: string | undefined;\n /**\n * Cookies this provider sets. An empty array is meaningful and not the same as\n * `undefined`: it asserts the provider is cookieless (Plausible), which the\n * cookie notice states positively rather than omitting.\n */\n cookies?: string[] | undefined;\n /** A user-facing opt-out, when the provider offers one. */\n optOut?: string | undefined;\n}\n\n/**\n * The providers the config can imply. Keyed for testability — a test can assert\n * a given config resolves to a given key without matching on prose.\n */\nexport const KNOWN_PROCESSORS = {\n googleAnalytics: {\n name: 'Google Analytics',\n purpose: 'website analytics',\n country: 'the United States',\n privacyUrl: 'https://policies.google.com/privacy',\n cookies: ['_ga', '_gid'],\n optOut: 'https://tools.google.com/dlpage/gaoptout',\n },\n googleTagManager: {\n name: 'Google Tag Manager',\n purpose: 'tag management',\n country: 'the United States',\n privacyUrl: 'https://policies.google.com/privacy',\n cookies: [],\n },\n plausible: {\n name: 'Plausible Analytics',\n purpose: 'website analytics',\n country: 'the European Union',\n privacyUrl: 'https://plausible.io/privacy',\n // Plausible sets no cookies and stores no cross-site identifiers. Stated as\n // an empty list rather than omitted, so the cookie notice can say so.\n cookies: [],\n },\n clarity: {\n name: 'Microsoft Clarity',\n purpose: 'session replay and heatmaps',\n country: 'the United States',\n privacyUrl: 'https://privacy.microsoft.com/privacystatement',\n // Clarity records what a visitor does on the page, not just that they were\n // here, so the purpose says \"session replay\" rather than \"analytics\" — a\n // reader deciding whether to consent needs to know they may be recorded.\n cookies: ['_clck', '_clsk', 'MUID'],\n optOut: 'https://privacy.microsoft.com/privacystatement',\n },\n // Matomo appears twice on purpose: whether it sets cookies is a *configuration*\n // choice (`analytics.matomo.cookies`), and the notice says something materially\n // different in each case. One entry with a conditional cookie list would put\n // that branch in the prose layer, where the rule is that templates own wording\n // and never facts.\n matomo: {\n name: 'Matomo',\n purpose: 'website analytics',\n privacyUrl: 'https://matomo.org/privacy-policy/',\n cookies: ['_pk_id', '_pk_ses'],\n },\n matomoCookieless: {\n name: 'Matomo',\n purpose: 'website analytics',\n privacyUrl: 'https://matomo.org/privacy-policy/',\n // `disableCookies` is on: Matomo stores no identifier on the device. The\n // empty list is the assertion — see the Processor.cookies note above.\n cookies: [],\n },\n // ── Edge / hosting: operator jurisdiction, NOT storage ──────────────────────\n //\n // These four asserted `country: 'the United States'` into a sentence that says\n // \"stored or processed in\" — a claim about the wrong fact. Cloudflare is anycast:\n // a request from Toronto is answered from a Toronto PoP, and Workers/R2 have\n // residency controls the config cannot see. Vercel and Netlify are region-\n // configurable in the same way.\n //\n // What is true regardless of which PoP or region served the request is that a US\n // company can be compelled under US law. So that is what they now assert, and\n // they assert nothing about where the bytes rest. This generalises the rule the\n // Matomo note below already stated: \"we don't know\" is a fact. A consumer who\n // pins a region should declare `storage` on a processor of their own.\n turnstile: {\n name: 'Cloudflare Turnstile',\n purpose: 'bot protection on forms',\n operatorCountry: 'the United States',\n privacyUrl: 'https://www.cloudflare.com/privacypolicy/',\n cookies: ['cf_clearance'],\n },\n cloudflare: {\n name: 'Cloudflare',\n purpose: 'website hosting and content delivery',\n operatorCountry: 'the United States',\n privacyUrl: 'https://www.cloudflare.com/privacypolicy/',\n cookies: [],\n },\n vercel: {\n name: 'Vercel',\n purpose: 'website hosting',\n operatorCountry: 'the United States',\n privacyUrl: 'https://vercel.com/legal/privacy-policy',\n cookies: [],\n },\n netlify: {\n name: 'Netlify',\n purpose: 'website hosting',\n operatorCountry: 'the United States',\n privacyUrl: 'https://www.netlify.com/privacy/',\n cookies: [],\n },\n} satisfies Record<string, Processor>;\n\nexport type KnownProcessorKey = keyof typeof KNOWN_PROCESSORS;\n\n/** Substring → hosting provider. `deployment.platform` is a free-form string. */\nconst HOSTING_PATTERNS: [RegExp, KnownProcessorKey][] = [\n [/cloudflare|workers|pages\\.dev/i, 'cloudflare'],\n [/vercel/i, 'vercel'],\n [/netlify/i, 'netlify'],\n];\n\n/**\n * Which known providers this config implies, in a stable order (analytics →\n * security → hosting) so the rendered sentence doesn't churn between builds.\n *\n * Returns keys rather than processors so a caller can test the detection\n * independently of the prose attached to it.\n */\nexport function detectProcessorKeys(cfg: Config): KnownProcessorKey[] {\n const site = cfg.site;\n const keys: KnownProcessorKey[] = [];\n const analytics = site.analytics;\n if (analytics?.googleAnalyticsId) keys.push('googleAnalytics');\n if (analytics?.googleTagManagerId) keys.push('googleTagManager');\n if (analytics?.plausibleDomain) keys.push('plausible');\n if (analytics?.clarityId) keys.push('clarity');\n // Cookieless is the default, matching the tag the Astro integration emits\n // (`_paq.push(['disableCookies'])` unless `cookies: true`). The two must agree:\n // a notice claiming no cookies while the tag sets them is the defect this whole\n // table exists to prevent.\n if (analytics?.matomo) keys.push(analytics.matomo.cookies ? 'matomo' : 'matomoCookieless');\n if (site.security?.turnstile?.siteKey) keys.push('turnstile');\n\n const platform = site.deployment?.platform;\n const hosting = platform && HOSTING_PATTERNS.find(([re]) => re.test(platform))?.[1];\n // Turnstile already names Cloudflare; listing it twice reads as sloppy and\n // implies two relationships where there is one.\n if (hosting && !keys.includes(hosting)) keys.push(hosting);\n return keys;\n}\n\n/**\n * Every processor this policy must disclose: the ones implied by the config,\n * then the ones the consumer declared.\n *\n * Consumer entries come last and are never deduplicated against the built-ins —\n * an explicit declaration is a statement of fact we have no grounds to drop.\n */\nexport function resolveProcessors(cfg: Config): Processor[] {\n const detected = detectProcessorKeys(cfg).map((k) =>\n matomoLocation(KNOWN_PROCESSORS[k] as Processor, cfg.site),\n );\n const declared = cfg.site.legal?.privacyPolicy?.processors ?? [];\n return [...detected, ...adProcessors(cfg), ...declared].map(desugarCountry);\n}\n\n/**\n * The ad platforms `site.ads` links this site to, as processors.\n *\n * Derived from `AD_PLATFORMS` rather than written out here, because the cookie\n * names, the privacy URL and the opt-out are the *same facts* `vitops ads tags`\n * writes into `data-consent-cookies` — and the one failure that matters is those\n * two disagreeing. A pixel that sets `_fbp` while the notice omits it is a\n * compliance defect, and a revoke that clears a cookie the notice never mentioned\n * is the same defect seen from the other end.\n *\n * `enabled: false` keeps a property on record without emitting its tag, so nothing\n * is set and nothing is disclosed. Everything else with an id is live.\n */\nfunction adProcessors(cfg: Config): Processor[] {\n const ads = cfg.site.ads ?? {};\n return AD_PROVIDER_KEYS.filter((provider) => {\n const entry = ads[provider];\n return entry != null && entry.enabled !== false && (entry.pixelId ?? entry.accountId) != null;\n }).map((provider) => {\n const platform = AD_PLATFORMS[provider];\n return {\n name: platform.name,\n purpose: 'advertising measurement and retargeting',\n operatorCountry: platform.operatorCountry,\n privacyUrl: platform.tag.privacyUrl,\n cookies: platform.tag.cookies,\n ...(platform.tag.optOut ? { optOut: platform.tag.optOut } : {}),\n } satisfies Processor;\n });\n}\n\n/**\n * `country` → both facts it has always asserted.\n *\n * The sentence it fed claimed storage *and* legal reach in one breath (\"may be\n * stored or processed in … including X. As a result … access requests from\n * governments … in those jurisdictions\"). So expanding it to storage alone would\n * silently retract half of a claim consumers have already published. Expanding to\n * both is also what keeps the rendered output byte-identical for every config that\n * used the shorthand.\n *\n * `country` is left in place — it is public API and `PolicyVars.countries` still\n * reports it. When the explicit fields are present they win; `validateConfig`\n * rejects that combination, so it is unreachable through a validated config, but\n * `resolveProcessors` is exported and needs a defined answer regardless.\n */\nfunction desugarCountry(p: Processor): Processor {\n if (!p.country) return p;\n return {\n ...p,\n storage: p.storage ?? [{ country: p.country }],\n operatorCountry: p.operatorCountry ?? p.country,\n };\n}\n\n/**\n * Processors the config discloses but places nowhere.\n *\n * Such a processor cannot appear in the transfer disclosure — there is nothing true\n * to say about it — and today it vanishes from that section in silence, which is the\n * tidy-looking failure. Names only, and deliberately NOT on `PolicyVars`: that type\n * is the facts a template renders from, and a document must not editorialise about\n * its own gaps. The CLI reports these on stderr instead.\n *\n * Not a `validateConfig` error either: a bare `{ name, purpose }` validates today,\n * so rejecting it would make this a breaking change.\n */\nexport function processorsMissingLocation(cfg: Config): string[] {\n return resolveProcessors(cfg)\n .filter((p) => !p.operatorCountry && !p.storage?.length)\n .map((p) => p.name);\n}\n\n/**\n * Matomo is the one provider whose location the config actually knows.\n *\n * Matomo Cloud is hosted in the EU; a self-hosted instance is wherever the\n * consumer put it, which is very often their own infrastructure in their own\n * country. So the cross-border transfer sentence is asserted only for the case we\n * can see. Naming a transfer that isn't happening is the same class of error as\n * omitting one that is — the config records facts, and \"we don't know\" is a fact.\n *\n * This sets `storage`, not `operatorCountry`: Matomo Cloud genuinely holds the data\n * in the EU. InnoCraft is New Zealand-based, but nothing in the config sees that, so\n * no operator jurisdiction is asserted — the same rule, applied to the other fact.\n */\nfunction matomoLocation(processor: Processor, site: Config['site']): Processor {\n if (processor.name !== 'Matomo') return processor;\n const url = site.analytics?.matomo?.url ?? '';\n return /\\.matomo\\.cloud/i.test(url)\n ? { ...processor, storage: [{ country: 'the European Union' }] }\n : processor;\n}\n","/**\n * Site config → the facts a legal document asserts.\n *\n * The division of labour here is the whole point: **the config records facts,\n * the template owns prose.** Nothing in this module writes a sentence a lawyer\n * would need to review, and nothing in a template invents a fact. That is what\n * lets the wording be corrected without touching a consumer's config, and a\n * consumer's provider to change without touching the prose.\n *\n * Everything it returns is derived from config the site already has to hold to\n * function — which analytics ID is set, which forms exist, where it deploys —\n * plus the facts a consumer declares in `legal.privacyPolicy`. There is no\n * source of truth here beyond `Config`.\n *\n * Pure: no I/O, no clock. `lastUpdated` comes from the config rather than\n * `Date.now()` so a rebuild produces a byte-identical document.\n */\nimport { t } from '@getvitops/utils';\nimport {\n JURISDICTION_COUNTRIES,\n resolvePrivacyContact,\n type ContactObject,\n type Config,\n} from '../config.ts';\nimport { resolveProcessors, type Processor } from './providers.ts';\n\n/**\n * The facts every legal template renders from.\n *\n * List-shaped fields are `string[]`, not pre-joined strings, because they land\n * in bullet positions: a template that splices an empty string into a list emits\n * a stray `-` bullet, and that is exactly the kind of silent breakage a\n * published policy must not have.\n */\nexport interface PolicyVars {\n businessName: string;\n url: string;\n /** Reads after \"at\": \"…contact our Privacy Officer at <this>.\" */\n mailingAddress: string;\n lastUpdated: string | undefined;\n /** Extra retention sentence, when the consumer stated one. */\n retention: string | undefined;\n /** A consumer-supplied governing-law phrase, which wins over the two below. */\n governingLaw: string | undefined;\n /** Province/territory, spelled out — \"Ontario\", never \"ON\". */\n governingProvince: string | undefined;\n governingCountry: string;\n\n /** Circumstances in which personal information is collected. */\n collectionReasons: string[];\n /** Categories of personal information collected. */\n piiCollected: string[];\n /** What the browser sends automatically. */\n techInfo: string[];\n /** Why that technical information is used. */\n techInfoPurposes: string[];\n /** What cookies track. */\n cookieTracked: string[];\n /** Why cookies are used. */\n cookiePurposes: string[];\n /** A sentence about the consent tool, or `undefined` when there is none. */\n cookieTool: string | undefined;\n /** How collected information is used. */\n usePurposes: string[];\n /** Choices a visitor has. */\n optOutOptions: string[];\n /** The subset of `optOutOptions` about cookies — an e-mail unsubscribe link is\n * not a cookie choice, and listing it in a cookie notice reads as padding. */\n cookieOptOutOptions: string[];\n\n processors: Processor[];\n /**\n * Cookies the site sets itself.\n *\n * Separate from `processors`, which are third parties — no provider table would\n * ever name a first-party cookie, so without this the notice can say \"we do not\n * set cookies\" while `_ac` sits in the visitor's browser.\n */\n firstPartyCookies: { name: string; purpose: string; retention: string }[];\n /**\n * The country this document frames transfers as *leaving*, from the jurisdiction\n * rather than the org's address — a `ca` policy says \"outside of Canada\" even for\n * a business incorporated elsewhere. (`governingCountry` is the address, and\n * drives a different sentence: the terms' governing-law clause.)\n */\n jurisdictionCountry: string;\n /**\n * Reads after \"including\": foreign countries where information rests, with no\n * category attached — the broad claim.\n */\n storageCountries: string | undefined;\n /**\n * Foreign storage locations holding only SOME categories. Structured rather than\n * pre-joined, because the connective (\"in the case of\") is the template's word,\n * not a fact. Disjoint from `storageCountries`: a country already claimed\n * unscoped is never repeated here, since the unscoped claim is the broader one.\n */\n scopedStorage: { country: string; scope: string }[];\n /**\n * Reads after \"the laws of\": foreign jurisdictions that can compel a provider to\n * produce information, EXCLUDING any already named in `storageCountries` —\n * saying US law reaches information already disclosed as stored in the US adds a\n * sentence and no fact.\n */\n operatorCountries: string | undefined;\n /**\n * Reads after \"including\": \"…the United States and the European Union\".\n *\n * @deprecated Split into `storageCountries` and `operatorCountries`, which keep\n * residency and legal reach apart. Retained, and still every country the field\n * ever named, so a consumer's own template renders what it always rendered.\n */\n countries: string | undefined;\n consentModel: 'opt-in' | 'opt-out' | 'none';\n cookieCategories: string[];\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────────\n\n/** \"A\", \"A and B\", \"A, B and C\". */\nexport function list(items: string[]): string {\n if (items.length <= 1) return items[0] ?? '';\n return `${items.slice(0, -1).join(', ')} and ${items[items.length - 1]}`;\n}\n\n/** Order-preserving dedupe — the bullet lists are assembled from several sources. */\nconst uniq = (items: (string | undefined)[]): string[] => [\n ...new Set(items.filter((s): s is string => !!s)),\n];\n\n/**\n * Render a contact into the phrase that follows \"at\". Prefers e-mail (the\n * channel a reader can actually use from the page) and adds the postal address\n * when there is one, because access and correction requests are commonly posted.\n */\nfunction formatContact(contact: ContactObject | undefined): string {\n if (!contact) return '';\n const a = contact.address;\n const postal =\n a &&\n [\n a.streetAddress,\n a.addressLocality,\n [a.addressRegion, a.postalCode].filter(Boolean).join(' '),\n a.addressCountry,\n ]\n .filter(Boolean)\n .join(', ');\n if (contact.email && postal) return `${contact.email}, or by mail at ${postal}`;\n return contact.email ?? postal ?? '';\n}\n\n/**\n * What a form field actually collects, as a noun phrase.\n *\n * Typed fields carry their meaning (`email` is an e-mail address in any form);\n * `text` does not, so it falls back to the field's name. A policy that under-\n * describes what a form collects is the failure mode worth avoiding, so an\n * unrecognised text field lands in a catch-all bullet rather than being dropped.\n */\nfunction fieldPhrase(name: string, type: string): string | undefined {\n switch (type) {\n // `hidden` is not visitor-supplied and a honeypot exists to be left empty —\n // describing either as collected information would be inaccurate.\n case 'hidden':\n return undefined;\n case 'email':\n return 'your e-mail address';\n case 'tel':\n return 'your telephone number';\n case 'url':\n return 'any website address you provide';\n case 'date':\n return 'any dates you provide';\n case 'file':\n return 'any files or documents you upload';\n case 'textarea':\n return 'the content of the messages you send us';\n case 'number':\n return 'any numeric details you provide';\n case 'password':\n return 'account credentials';\n case 'select':\n case 'radio':\n case 'checkbox':\n return 'your answers to the questions we ask';\n default:\n break;\n }\n if (/name/i.test(name)) return 'your name';\n if (/compan|organi|business/i.test(name)) return 'your company or organization name';\n if (/address|street|city|province|state|postal|zip|country/i.test(name))\n return 'your mailing address';\n return 'the other details you enter in our forms';\n}\n\nconst PROVINCES: Record<string, string> = {\n AB: 'Alberta',\n BC: 'British Columbia',\n MB: 'Manitoba',\n NB: 'New Brunswick',\n NL: 'Newfoundland and Labrador',\n NS: 'Nova Scotia',\n NT: 'Northwest Territories',\n NU: 'Nunavut',\n ON: 'Ontario',\n PE: 'Prince Edward Island',\n QC: 'Quebec',\n SK: 'Saskatchewan',\n YT: 'Yukon',\n};\n\n/**\n * `addressRegion` is conventionally a two-letter code, which is right for a\n * postal address and wrong inside a governing-law clause — \"the laws of ON\" is\n * not a sentence a lawyer would sign off. Anything already spelled out (or from\n * another country) passes through untouched.\n */\nfunction expandProvince(region: string | undefined): string | undefined {\n if (!region) return undefined;\n return PROVINCES[region.toUpperCase()] ?? region;\n}\n\n/** Every field across every `form` template, honeypots excluded. */\nfunction formFields(site: Config['site']): { name: string; type: string }[] {\n const out: { name: string; type: string }[] = [];\n for (const tpl of Object.values(site.templates ?? {})) {\n if (tpl.type !== 'form') continue;\n for (const f of tpl.fields ?? []) out.push({ name: f.name, type: f.type });\n }\n return out;\n}\n\n// ── Derivation ──────────────────────────────────────────────────────────────────\n\nexport function derivePolicyVars(cfg: Config): PolicyVars {\n // The two sections this reads from. Everything the policy asserts about the\n // *company* comes from `organization`; everything it asserts about what the\n // *site* does (forms, analytics, cookies, A/B) comes from `site`.\n const site = cfg.site;\n const org = cfg.organization;\n const locale = site.defaultLocale;\n const legal = site.legal;\n const privacy = legal?.privacyPolicy;\n const processors = resolveProcessors(cfg);\n const fields = formFields(site);\n const hasForms = fields.length > 0;\n // Any configured provider counts, whether its config is an ID string\n // (`googleAnalyticsId`) or an object (`matomo`). Checking only for strings\n // would silently under-report a Matomo-only site as having no analytics at all.\n const hasAnalytics = Object.values(site.analytics ?? {}).some((v) =>\n typeof v === 'string' ? v.length > 0 : !!v,\n );\n const cookieProcessors = processors.filter((p) => p.cookies?.length);\n const consent = legal?.cookieConsent;\n const contact = resolvePrivacyContact(cfg);\n\n const businessName =\n org?.legalName ?? (org?.name != null ? t(org.name, locale, locale) : undefined) ?? 'we';\n\n const collectionReasons = uniq([\n 'contact us through e-mail, telephone, mail or other correspondence',\n hasForms ? 'submit one of the forms on our Site' : undefined,\n org?.services && Object.keys(org.services).length > 0\n ? 'register for a service we provide'\n : undefined,\n fields.some((f) => /newsletter|subscribe|mailing/i.test(f.name))\n ? 'register to receive our newsletter'\n : undefined,\n ]);\n\n // Only claim to collect what a configured form actually asks for. With no\n // forms, the generic categories stand in — the site still receives whatever a\n // visitor sends by e-mail.\n const piiCollected = uniq([\n ...(hasForms\n ? fields.map((f) => fieldPhrase(f.name, f.type))\n : [\n 'your full name',\n 'contact information, such as your address, telephone number, or e-mail address',\n ]),\n 'any other personal information that you choose to submit to us',\n ]);\n\n // Session replay is a materially different disclosure from page-view analytics\n // and cannot be folded into `hasAnalytics`: a policy that lists \"the pages you\n // view\" while the site records mouse movement, scrolling and clicks is\n // under-disclosing, not summarising.\n const hasSessionReplay = !!site.analytics?.clarityId;\n\n const techInfo = uniq([\n 'your domain name',\n 'your numerical IP address',\n hasAnalytics ? 'the pages you view and the files you request' : undefined,\n hasAnalytics ? 'the type of browser and operating system you use' : undefined,\n hasAnalytics ? 'the address of the site that referred you' : undefined,\n hasSessionReplay\n ? 'a recording of how you interacted with a page, including mouse movement, scrolling and clicks'\n : undefined,\n ]);\n\n const techInfoPurposes = uniq([\n hasAnalytics ? 'measure the performance of our Site' : undefined,\n hasSessionReplay ? 'see where visitors encounter difficulty using our Site' : undefined,\n site.security?.turnstile?.siteKey\n ? 'protect our Site and its forms from automated abuse'\n : undefined,\n 'better understand how visitors use our Site',\n 'improve our Site to better meet your needs',\n ]);\n\n const ab = site.abTesting;\n\n /**\n * A site offering the `preferences` category stores at least one setting the\n * visitor chose — `<wc-color-scheme-toggle>` writes `vitops-color-scheme` to local\n * storage, gated on exactly this category. The banner asking about it while the\n * notice never mentions it is the disclosure gap `providers.ts` exists to\n * prevent, just on the browser-storage side rather than the third-party one.\n */\n const hasPreferences = consent?.enabled === true && !!consent.categories?.includes('preferences');\n\n /**\n * `site.tracking.enabled` writes the `_ac` cookie: the click ID from the ad a\n * visitor followed, kept for 90 days so a later enquiry can be attributed to\n * the campaign that produced it. It is first-party and never leaves the site,\n * which is exactly why nothing in the provider table would ever mention it —\n * and why it has to be stated here instead. A notice that lists every\n * third-party cookie while omitting the one the site sets itself is the same\n * disclosure defect, pointed inward.\n */\n const hasAdTracking = site.tracking?.enabled === true;\n\n const cookieTracked = uniq([\n 'your IP address',\n 'the type of web browser and operating system used',\n 'the pages of the Site visited',\n hasPreferences\n ? 'display settings you have chosen, such as light or dark appearance'\n : undefined,\n hasAdTracking ? 'which advertisement or campaign brought you to our Site' : undefined,\n ab?.enabled ? 'which version of a page you were shown' : undefined,\n hasSessionReplay ? 'how you moved through and interacted with a page' : undefined,\n ]);\n\n const cookiePurposes = uniq([\n 'keep the Site functioning as you move between pages',\n hasAnalytics ? 'understand how our Site is used, in aggregate' : undefined,\n hasPreferences ? 'remember display settings you choose, between visits' : undefined,\n hasAdTracking\n ? 'attribute an enquiry to the advertisement that brought you here, for up to 90 days'\n : undefined,\n hasSessionReplay ? 'recognise a returning visit as part of the same session' : undefined,\n ab?.enabled ? 'keep you on a consistent version of the Site between visits' : undefined,\n site.security?.turnstile?.siteKey ? 'distinguish visitors from automated traffic' : undefined,\n ]);\n\n // Not \"shown when you first visit\": the banner is raised by whatever needs the\n // permission, at the point it needs it — on arrival for an analytics tag, on the\n // click for a display setting. A site that gates nothing never shows one at all,\n // so promising a first-visit banner would describe a thing that never happens.\n const cookieTool = consent?.enabled\n ? consent.type === 'opt-in'\n ? 'You may also choose which categories of cookies to allow using the consent banner, which appears when something on the Site first needs your permission, and you may change that choice at any time.'\n : 'You may also withdraw your consent to non-essential cookies at any time using the consent controls on our Site.'\n : undefined;\n\n const usePurposes = uniq([\n 'respond to your inquiries',\n 'supply you with requested products or services',\n site.notifications?.email\n ? 'route your message to the appropriate person in our organization'\n : undefined,\n site.tracking?.enabled ? 'measure the effectiveness of our marketing' : undefined,\n 'send you informational or promotional communication',\n 'carry out other purposes that are disclosed to you and to which you consent',\n 'carry out any other purpose permitted or required by law',\n ]);\n\n const cookieOptOutOptions = uniq([\n 'You may configure your browser to refuse cookies, though parts of our Site may not function as intended.',\n consent?.enabled ? cookieTool : undefined,\n ...processors\n .filter((p) => p.optOut)\n .map((p) => `You may opt out of ${p.name} directly at ${p.optOut}.`),\n ]);\n\n const optOutOptions = uniq([\n 'You may unsubscribe from any commercial e-mail we send using the \"unsubscribe\" link in that e-mail.',\n ...cookieOptOutOptions,\n ]);\n\n /**\n * The cross-border disclosure, as two facts rather than one flattened list.\n *\n * Order matters here — each step narrows what the next may claim:\n *\n * 1. Anything in this jurisdiction is not a transfer at all, so it is filtered\n * out. Without this, `country: \"Canada\"` rendered \"outside of Canada,\n * including Canada\".\n * 2. An unscoped storage country is the BROAD claim; a scoped one covering the\n * same country would only narrow it, so it is dropped as redundant.\n * 3. An operator country already named as storage adds no fact — \"US law reaches\n * information stored in the US\" is a sentence, not information.\n *\n * Steps 2 and 3 are what make the rendered output byte-identical for every config\n * that used `country` (which desugars to both facts).\n *\n * No geography is inferred — \"France\" is not resolved into \"the European Union\".\n * Only what the config states is asserted, which is the `matomoLocation` rule.\n */\n const jurisdictionCountry = JURISDICTION_COUNTRIES[legal?.jurisdiction ?? 'ca'];\n // Compare loosely: \"the United States\" and \"United States\" are one fact, and a\n // template must never have to know that \"canada\" is \"Canada\".\n const norm = (c: string) =>\n c\n .trim()\n .toLowerCase()\n .replace(/^the\\s+/, '');\n const foreign = (c: string) => norm(c) !== norm(jurisdictionCountry);\n\n const allStorage = processors.flatMap((p) => p.storage ?? []);\n const unscoped = uniq(\n allStorage.filter((s) => !s.scope && foreign(s.country)).map((s) => s.country),\n );\n const storageCountries = list(unscoped);\n const named = new Set(unscoped.map(norm));\n const scopedStorage = [\n ...new Map(\n allStorage\n .filter((s) => s.scope && foreign(s.country) && !named.has(norm(s.country)))\n .map((s) => [`${norm(s.country)}|${s.scope!}`, { country: s.country, scope: s.scope! }]),\n ).values(),\n ];\n const operatorCountries = list(\n uniq(processors.map((p) => p.operatorCountry)).filter((c) => foreign(c) && !named.has(norm(c))),\n );\n\n // Back-compat: every country the old field ever named, unfiltered, in processor\n // order — storage before operator, matching how `country` desugars.\n const countries = list(\n uniq(\n processors.flatMap((p) => [...(p.storage ?? []).map((s) => s.country), p.operatorCountry]),\n ),\n );\n\n const address = contact?.address ?? org?.address;\n\n return {\n businessName,\n url: site.domains?.canonical ?? '',\n mailingAddress: formatContact(contact),\n lastUpdated: privacy?.lastUpdated,\n retention: privacy?.retention,\n governingLaw: legal?.termsOfService?.governingLaw,\n governingProvince: expandProvince(address?.addressRegion),\n governingCountry: address?.addressCountry ?? 'Canada',\n collectionReasons,\n piiCollected,\n techInfo,\n techInfoPurposes,\n cookieTracked,\n cookiePurposes,\n cookieTool,\n usePurposes,\n optOutOptions,\n cookieOptOutOptions,\n processors,\n firstPartyCookies: hasAdTracking\n ? [\n {\n name: '_ac',\n purpose:\n 'records the advertisement or campaign you arrived from, so an enquiry can be attributed to it',\n retention: '90 days',\n },\n ]\n : [],\n jurisdictionCountry,\n storageCountries: storageCountries || undefined,\n scopedStorage,\n operatorCountries: operatorCountries || undefined,\n countries: countries || undefined,\n consentModel: consent?.enabled ? (consent.type ?? 'opt-in') : 'none',\n cookieCategories: consent?.categories ?? [],\n };\n}\n","/**\n * The legal documents are authored in markdown; consumers need markdown, HTML\n * and EmDash Portable Text. This parses the markdown **once** into a small block\n * model, and the three outputs render from that.\n *\n * The subset is **closed by construction** — we author every template, so the\n * parser does not need to be a markdown implementation, it needs to be exactly\n * as capable as the templates are. That is why it *throws* on anything outside\n * the subset rather than passing it through: an unrecognised construct that\n * silently degrades to a paragraph is how a published policy ends up with a\n * literal `| --- |` in it. A template that grows a table fails the test suite\n * instead.\n *\n * Supported, and nothing else:\n * block `#`/`##`/`###` headings, `- ` bullets, `> ` quote, paragraphs\n * inline `**strong**`, `` `code` ``\n *\n * HTML rendering delegates to `nodesToHtml` from `@getvitops/utils`, which\n * already solves escaping and void elements — this module maps to `ContentNode`\n * and stops there.\n */\nimport { nodesToHtml, type ContentNode } from '@getvitops/utils';\n\nexport interface Span {\n text: string;\n strong?: boolean;\n code?: boolean;\n}\n\nexport type Block =\n | { kind: 'heading'; level: 1 | 2 | 3; spans: Span[] }\n | { kind: 'paragraph'; spans: Span[] }\n | { kind: 'list'; items: Span[][] }\n | { kind: 'quote'; spans: Span[] };\n\n/** Constructs that look like markdown but are outside the subset. */\nconst UNSUPPORTED: [RegExp, string][] = [\n [/^#{4,}\\s/, 'headings deeper than ###'],\n [/^\\s*\\d+[.)]\\s/, 'ordered lists'],\n [/^\\s*```/, 'code fences'],\n [/^\\s*\\|/, 'tables'],\n [/^\\s*[*+]\\s/, 'bullets other than `- `'],\n [/^\\s+-\\s/, 'nested lists'],\n];\n\n// Bold and code spans, in one pass so a `**` inside backticks stays literal.\nconst INLINE = /(\\*\\*[^*]+\\*\\*|`[^`]+`)/g;\n\nfunction parseInline(text: string, where: string): Span[] {\n const spans: Span[] = [];\n let last = 0;\n for (const m of text.matchAll(INLINE)) {\n const token = m[0];\n if (m.index > last) spans.push({ text: text.slice(last, m.index) });\n if (token.startsWith('`')) spans.push({ text: token.slice(1, -1), code: true });\n else spans.push({ text: token.slice(2, -2), strong: true });\n last = m.index + token.length;\n }\n if (last < text.length) spans.push({ text: text.slice(last) });\n\n // Check what's left as literal text, so `**bold**` doesn't trip the `*` guard\n // and a cookie name like `_ga` (already inside a code span) doesn't either.\n for (const span of spans) {\n if (span.strong || span.code) continue;\n if (/!?\\[[^\\]]*\\]\\(/.test(span.text))\n throw new Error(\n `legal template uses links or images, which are outside the subset: ${where}`,\n );\n if (span.text.includes('**'))\n throw new Error(`legal template has an unmatched \\`**\\`: ${where}`);\n if (span.text.includes('`'))\n throw new Error(`legal template has an unmatched backtick: ${where}`);\n }\n return spans;\n}\n\n/** Markdown (our subset) → blocks. Throws on anything it does not model. */\nexport function parseMarkdown(md: string): Block[] {\n const blocks: Block[] = [];\n const lines = md.split('\\n');\n let paragraph: string[] = [];\n\n const flush = () => {\n if (paragraph.length === 0) return;\n const text = paragraph.join(' ');\n blocks.push({ kind: 'paragraph', spans: parseInline(text, text.slice(0, 60)) });\n paragraph = [];\n };\n\n for (const line of lines) {\n for (const [re, what] of UNSUPPORTED)\n if (re.test(line))\n throw new Error(`legal template uses ${what}, outside the subset: ${line}`);\n\n if (line.trim() === '') {\n flush();\n continue;\n }\n\n const heading = /^(#{1,3})\\s+(.*)$/.exec(line);\n if (heading) {\n flush();\n blocks.push({\n kind: 'heading',\n level: heading[1]!.length as 1 | 2 | 3,\n spans: parseInline(heading[2]!.trim(), line),\n });\n continue;\n }\n\n const quote = /^>\\s+(.*)$/.exec(line);\n if (quote) {\n flush();\n blocks.push({ kind: 'quote', spans: parseInline(quote[1]!.trim(), line) });\n continue;\n }\n\n const bullet = /^-\\s+(.*)$/.exec(line);\n if (bullet) {\n flush();\n const item = parseInline(bullet[1]!.trim(), line);\n // Consecutive `- ` lines are one list; a blank line between them starts a\n // new one, which is what markdown means and what the templates rely on.\n const prev = blocks[blocks.length - 1];\n if (prev?.kind === 'list') prev.items.push(item);\n else blocks.push({ kind: 'list', items: [item] });\n continue;\n }\n\n paragraph.push(line.trim());\n }\n flush();\n return blocks;\n}\n\n// ── ContentNode / HTML ──────────────────────────────────────────────────────────\n\nfunction spanNodes(spans: Span[]): ContentNode[] {\n return spans.map((s) =>\n s.strong ? { tag: 'strong', text: s.text } : s.code ? { tag: 'code', text: s.text } : s.text,\n );\n}\n\n/**\n * Blocks → `ContentNode[]`, the framework-agnostic tree the site config already\n * uses for `templates` of type `nodes` and `NodeRenderer.astro` already renders.\n */\nexport function toContentNodes(blocks: Block[]): ContentNode[] {\n return blocks.map((b): ContentNode => {\n switch (b.kind) {\n case 'heading':\n return { tag: `h${b.level}`, children: spanNodes(b.spans) };\n case 'paragraph':\n return { tag: 'p', children: spanNodes(b.spans) };\n case 'quote':\n return { tag: 'blockquote', children: [{ tag: 'p', children: spanNodes(b.spans) }] };\n case 'list':\n return {\n tag: 'ul',\n children: b.items.map((item) => ({ tag: 'li', children: spanNodes(item) })),\n };\n }\n });\n}\n\nexport function toHtmlFragment(blocks: Block[]): string {\n return nodesToHtml(toContentNodes(blocks));\n}\n\n// ── Portable Text (EmDash) ──────────────────────────────────────────────────────\n\n/**\n * Blocks → EmDash Portable Text, matching the shape already seeded in\n * `packages/create/templates/emdash/seed/seed.json`.\n *\n * Two deliberate mappings:\n * - the `# ` heading is **dropped** — in EmDash the page title is a field\n * (`data.title`), and repeating it as the first content block renders twice;\n * - the review blockquote becomes a `vitops.banner` with `tone: \"warning\"`,\n * which is exactly the block the hand-written placeholder pages used.\n *\n * `_key`s are derived from position rather than randomness, so regenerating an\n * unchanged config produces an identical seed and a clean diff.\n */\nexport function toPortableText(blocks: Block[], prefix: string): unknown[] {\n const out: unknown[] = [];\n blocks.forEach((b, i) => {\n const key = `${prefix}-${i}`;\n if (b.kind === 'heading' && b.level === 1) return;\n\n if (b.kind === 'quote') {\n out.push({\n _type: 'vitops.banner',\n _key: key,\n message: b.spans.map((s) => s.text).join(''),\n tone: 'warning',\n dismissible: false,\n });\n return;\n }\n\n const block = (spans: Span[], k: string, extra: Record<string, unknown>) => ({\n _type: 'block',\n _key: k,\n markDefs: [],\n children: spans.map((s, j) => ({\n _type: 'span',\n _key: `${k}-${j}`,\n text: s.text,\n marks: [s.strong && 'strong', s.code && 'code'].filter(Boolean),\n })),\n ...extra,\n });\n\n if (b.kind === 'list') {\n b.items.forEach((item, j) =>\n out.push(block(item, `${key}-${j}`, { style: 'normal', listItem: 'bullet', level: 1 })),\n );\n return;\n }\n\n out.push(block(b.spans, key, { style: b.kind === 'heading' ? `h${b.level}` : 'normal' }));\n });\n return out;\n}\n","/**\n * Pieces every legal template shares.\n *\n * Kept deliberately tiny: anything that grows here is prose leaking out of the\n * jurisdiction-specific templates into a shared file, which is how a document\n * ends up asserting something that isn't true of the body of law it claims to\n * follow. Formatting helpers belong here; sentences almost never do.\n */\nimport type { PolicyVars } from '../derive.ts';\n\n/**\n * The banner every generated document opens with.\n *\n * Not optional and not configurable. These documents are rendered from a\n * template by a build tool, not drafted for a specific business by someone who\n * can be asked follow-up questions — and the one failure mode with real\n * consequences is a consumer publishing one as-is. It is a blockquote so it\n * renders as a callout in HTML and as a warning banner in EmDash.\n */\nexport const REVIEW_NOTICE =\n \"> Generated from this site's configuration. It is a starting point, not legal advice — have it reviewed before you publish it, and make sure it matches what your site actually does.\";\n\n/** A markdown bullet list. Empty in, empty out — never a stray `-`. */\nexport function bullets(items: string[]): string {\n return items.map((item) => `- ${item}`).join('\\n');\n}\n\n/**\n * Taken from config rather than the clock, so a rebuild of an unchanged config\n * produces a byte-identical document.\n */\nexport function updatedLine(v: Pick<PolicyVars, 'lastUpdated'>): string {\n return v.lastUpdated ? `\\nLast updated: ${v.lastUpdated}\\n` : '';\n}\n","/**\n * Cookie notice — Canada.\n *\n * The one document here that is almost entirely derived: which cookies a site\n * sets follows from which providers it uses, and the config already knows that.\n * The prose is a frame around `v.processors` and `v.cookieCategories`.\n *\n * Rendered as headings and bullets rather than a table, deliberately — the\n * markdown subset the renderer supports is closed, and a table would widen it\n * for one document. Bullets also survive a narrow viewport, which a four-column\n * cookie table does not.\n */\nimport { list, type PolicyVars } from '../derive.ts';\nimport { bullets, REVIEW_NOTICE, updatedLine } from './shared.ts';\n\nexport function cookiesCa(v: PolicyVars): string {\n return `# Cookie Notice\n${updatedLine(v)}\n${REVIEW_NOTICE}\n\nThis notice explains how ${v.businessName} uses cookies and similar technologies on ${v.url} (the \"Site\"). It supplements our Privacy Policy.\n\n## What Cookies Are\n\nA cookie is a small text file that a website asks your browser to store. Cookies let a site remember things between pages and between visits — for example, that you have already dismissed a message. Similar technologies, such as local storage, do much the same thing.\n\n## What We Use Them For\n\n${bullets(v.cookiePurposes)}\n\nCookies used on this Site may track:\n\n${bullets(v.cookieTracked)}\n\n${providersSection(v)}${categoriesSection(v)}\n## Your Choices\n\n${bullets(v.cookieOptOutOptions)}\n\nMost browsers let you see which cookies are stored, delete them individually or in bulk, and block them entirely. Blocking all cookies will stop parts of the Site from working as intended.\n\n## Contact\n\nIf you have questions about our use of cookies, please contact us at ${v.mailingAddress}.\n`;\n}\n\n/**\n * \"This site sets no cookies\" is a real and increasingly common answer — a\n * cookieless analytics provider is a selling point, not an omission. Saying it\n * plainly beats an empty section that reads as an oversight.\n *\n * But it is only true if the site sets none of its **own**, which is why\n * `firstPartyCookies` is checked alongside the processors: a site running\n * attribution with a cookieless analytics provider sets `_ac` and no third-party\n * cookie at all, and the old wording would have declared it cookie-free.\n */\nfunction providersSection(v: PolicyVars): string {\n const setting = v.processors.filter((p) => p.cookies?.length);\n const cookieless = v.processors.filter((p) => p.cookies?.length === 0);\n const own = v.firstPartyCookies;\n\n const ownSection = own.length\n ? `\\n### Cookies We Set Ourselves\\n\\n${bullets(\n own.map((c) => `\\`${c.name}\\` — ${c.purpose}. Kept for ${c.retention}.`),\n )}\\n`\n : '';\n\n if (setting.length === 0) {\n const named = cookieless.length\n ? ` The third party ${cookieless.length === 1 ? 'service' : 'services'} we use on this Site — ${list(\n cookieless.map((p) => p.name),\n )} — ${cookieless.length === 1 ? 'does' : 'do'} not set cookies of ${\n cookieless.length === 1 ? 'its' : 'their'\n } own.`\n : '';\n const none = own.length\n ? `Beyond the cookies strictly necessary to serve and secure the Site, no third party sets cookies through this Site.${named}`\n : `Beyond the cookies strictly necessary to serve and secure the Site, we do not set cookies.${named}`;\n return `## Cookies Set on This Site\n\n${none}\n${ownSection}`;\n }\n\n return `## Cookies Set on This Site\n\n${bullets(\n setting.map(\n (p) =>\n // Cookie names go in code spans, not bare: `_ga, _gid` in running markdown\n // is a matched pair of underscores, which a downstream renderer turns into\n // emphasis and eats the names.\n `**${p.name}** (${p.purpose}) — ${(p.cookies ?? []).map((c) => `\\`${c}\\``).join(', ')}${\n p.privacyUrl ? `. Privacy policy: ${p.privacyUrl}` : ''\n }`,\n ),\n)}\n${\n cookieless.length\n ? `\\nWe also use ${list(cookieless.map((p) => p.name))}, which ${\n cookieless.length === 1 ? 'does' : 'do'\n } not set cookies of ${cookieless.length === 1 ? 'its' : 'their'} own.\\n`\n : ''\n}${ownSection}`;\n}\n\n/** Only meaningful when a consent tool actually offers the categories. */\nfunction categoriesSection(v: PolicyVars): string {\n if (v.consentModel === 'none' || v.cookieCategories.length === 0) return '';\n return `\n## Cookie Categories\n\nOur consent controls group cookies into the following categories, which you can accept or decline${\n v.consentModel === 'opt-in'\n ? ' before any non-essential cookie is set'\n : ' at any time after your first visit'\n }:\n\n${bullets(v.cookieCategories)}\n`;\n}\n","/**\n * Privacy policy — Canada (PIPEDA).\n *\n * Ported from the pandoc prototype at `packages/core/legal-templates/`. Two\n * things changed in the port and both are load-bearing:\n *\n * 1. `${var}` is now real TypeScript interpolation rather than a pandoc Lua\n * filter, so an unresolved variable is a compile error. The filter left\n * unknown keys as the literal text `${key}` — which would ship a live\n * privacy policy containing `${countries}`.\n * 2. Lists are built from arrays, not by splicing a string into a fixed bullet.\n * An empty derived value used to produce a stray `- ; and` bullet.\n *\n * The prose is jurisdiction-specific: it names the Office of the Privacy\n * Commissioner of Canada and frames transfers as \"outside of Canada\". Do not\n * reuse it for another jurisdiction — add a sibling template instead.\n */\n// `list` is a formatting helper, the same class as `bullets` — the connectives\n// (\"including\", \"in the case of\") stay in the prose below, where they belong.\nimport { list, type PolicyVars } from '../derive.ts';\nimport { bullets, REVIEW_NOTICE, updatedLine } from './shared.ts';\n\nexport function privacyCa(v: PolicyVars): string {\n return `# Privacy Policy\n${updatedLine(v)}\n${REVIEW_NOTICE}\n\nThis is the privacy policy of ${v.businessName} (\"Business\"). It summarizes what personal information we collect and how we use and disclose this information.\n\nBy using our website (the \"Site\"), you signify your consent to the terms of our Privacy Policy. If you do not agree with any terms of this Privacy Policy, please do not use this Site or submit any personal information to us, or use the preference tools we provide to adjust your settings. This Privacy Policy also describes certain choices you have on how we use your personal information.\n\nWe reserve the right to modify this Privacy Policy at any time. We will reflect any such modifications to this Privacy Policy on our Site. We suggest that you periodically consult this Privacy Policy. Your continued use of the Site after any such changes constitutes your acceptance of this Privacy Policy, as revised.\n\n**Privacy Policy Summary.**\n\n${bullets([\n 'What Personal Information We Collect',\n 'How We Use Personal Information',\n 'How We Share Personal Information',\n 'Your Choices',\n])}\n\n## Full Privacy Policy\n\n### What Personal Information We Collect and How We Collect It\n\nPersonal information is information about an identifiable individual. We collect personal information only for purposes that a reasonable person would consider appropriate in the circumstances and only with your knowledge and consent, except where otherwise required or permitted by law. Business collects personal information when you voluntarily provide it through our Site or when you provide it to us through other means. For example, we may collect personal information when you:\n\n${bullets(v.collectionReasons)}\n\nThe personal information we may collect will depend on the service you request and may include:\n\n${bullets(v.piiCollected)}\n\n### How Business Collects Information Through Technological Means\n\nWhen you visit our Site, we may collect information that is automatically sent to us by your web browser. This information may include:\n\n${bullets(v.techInfo)}\n\nWe use this information to:\n\n${bullets(v.techInfoPurposes)}\n\nThe amount of information that is sent by your web browser depends on the browser and settings you use. Please refer to the instructions provided by your browser if you want to learn more about what information it sends to websites you visit or how you may change or restrict this.\n\nBusiness may use cookies and other similar devices on this Site to enhance functionality. These devices may track information which includes:\n\n${bullets(v.cookieTracked)}\n\nWe use this information to:\n\n${bullets(v.cookiePurposes)}\n\nIf you wish to disable cookies, refer to your browser help menu to learn how.${v.cookieTool ? ` ${v.cookieTool}` : ''}\n\n### How Business Uses and Discloses Personal Information\n\nThe personal information we collect may be used by Business for the purposes for which it was collected, as provided in this Privacy Policy, or for other purposes that are disclosed to you and to which you consent.\n\nFor example, we may use your personal information to:\n\n${bullets(v.usePurposes)}\n\n${providersSection(v)}\n\nBusiness reserves the right to transfer personal information in the event that we merge with or are acquired by a third party. We also may disclose your personal information for any other purpose required or permitted by law or to which you consent.\n\n### Your Choices\n\n${bullets(v.optOutOptions)}\n\n### How We Protect Personal Information\n\nThe security of your personal information is important to us. We protect your personal information in our control through appropriate security safeguards against loss, theft, unauthorized access, disclosure, copying, use or modification. These safeguards include physical measures (such as locked filing cabinets), organizational measures (such as employee training and restricted access), and technological measures (such as encryption and passwords). Personal information may be accessed by persons within our organization who require such access to carry out the purposes described in this Privacy Policy, or such other purposes as permitted or required by law. Personal information we collect is maintained with the source of the information at ${v.url}.\n\nWe retain personal information that we collect only as long as necessary for the purposes for which it was collected or to meet legal requirements. We destroy personal information when it is no longer needed for such purposes.${v.retention ? ` In general, we keep personal information for ${v.retention}.` : ''}\n\nIt is important to understand that no security measures are absolute. We cannot guarantee the safety of any information you provide to us.\n${transferSection(v)}\n### Accessing and Correcting Your Personal Information\n\nYou have a right to access your personal information and to request a correction to it if you believe it is inaccurate. If you have submitted personal information and would like to have access to it, or if you would like to have it corrected, please contact us using the contact information provided below. We may require you verify your identity before allowing you to access your personal information.\n\n### How to Contact Us\n\nIf you have any questions regarding this Privacy Policy, to submit a complaint, or to access or correct your information, please contact our Privacy Officer at ${v.mailingAddress}. If you are not satisfied with our response to your privacy concerns, you may contact the Office of the Privacy Commissioner of Canada at www.priv.gc.ca or 1-800-282-1376.\n`;\n}\n\n/**\n * Named separately because a site with no third parties at all should not claim\n * to have service providers, and one with them owes the reader their identity —\n * \"we may share with service providers\" without naming them is the vaguest and\n * least useful sentence a policy can contain.\n */\nfunction providersSection(v: PolicyVars): string {\n if (v.processors.length === 0)\n return 'We do not transfer personal information to third party service providers.';\n return `We may transfer personal information to third party service providers that assist us with carrying out these purposes. When we transfer personal information to service providers, we require them to protect the information in a manner consistent with our privacy practices and applicable privacy laws. These service providers are:\n\n${bullets(\n v.processors.map(\n (p) => `${p.name}, for ${p.purpose}${p.privacyUrl ? ` (privacy policy: ${p.privacyUrl})` : ''}`,\n ),\n)}\n\nWe remain responsible for personal information in the possession of our service providers.`;\n}\n\n/**\n * Omitted entirely when nothing leaves the country — a false claim otherwise.\n *\n * Two clauses, because storage and legal reach are two facts and the OPC's concern\n * is foreign **access**, not merely foreign storage. A provider can hold data in\n * Canada and still be compellable abroad (Azure in a Canadian region), and a\n * provider can hold only one category of data abroad (a Canadian tenant whose\n * identity data sits in the US). One sentence could state neither.\n *\n * The closer is shared: it is true of whichever clauses appear.\n */\nfunction transferSection(v: PolicyVars): string {\n const clauses = [storageClause(v), operatorClause(v)].filter(Boolean);\n if (clauses.length === 0) return '';\n return `\n### We May Transfer Personal Information to Other Countries\n\n${clauses.join('\\n\\n')}\n\nAs a result, this information may be subject to access requests from governments, courts or law enforcement in those jurisdictions according to laws in those jurisdictions.\n`;\n}\n\n/**\n * Where the information rests.\n *\n * A scoped location gets its own sentence rather than joining the \"including …\"\n * list: folded in, a reader would take it to cover everything the provider holds,\n * which is a broader claim than the config made.\n */\nfunction storageClause(v: PolicyVars): string {\n const scoped = list(v.scopedStorage.map((s) => `${s.country}, in the case of ${s.scope}`));\n if (v.storageCountries)\n return `Some or all of the personal information we collect may be stored or processed in jurisdictions outside of Canada, including ${v.storageCountries}.${\n scoped\n ? ` Certain categories of personal information are held outside of Canada even where the rest is not: ${scoped}.`\n : ''\n }`;\n if (scoped)\n return `Certain categories of the personal information we collect are stored or processed outside of Canada: ${scoped}.`;\n return '';\n}\n\n/** The Azure-in-Canada case: the information never moves, and foreign law still reaches it. */\nfunction operatorClause(v: PolicyVars): string {\n if (!v.operatorCountries) return '';\n return `Some of the service providers we use are established in, or controlled from, jurisdictions outside of Canada, including ${v.operatorCountries}. Personal information those providers handle on our behalf may be subject to the laws of those jurisdictions even when it is stored in Canada.`;\n}\n","/**\n * Terms of service — Canada.\n *\n * Unlike the privacy policy, this has no prototype in the repo to port: the\n * prose is new. It is written as **generic website terms** — the clauses almost\n * every informational site needs (acceptable use, intellectual property,\n * disclaimer, limitation of liability, governing law) and nothing more.\n *\n * It deliberately does NOT cover the things that actually vary between\n * businesses and carry the most risk: sales and refunds, subscriptions and\n * renewals, user-generated content and its moderation, accounts and\n * termination, professional advice, or anything sector-regulated. A site doing\n * any of those needs clauses drafted for it — the review banner says so, and\n * this file should not grow them, because a template that half-covers payments\n * is more dangerous than one that visibly omits them.\n */\nimport type { PolicyVars } from '../derive.ts';\nimport { bullets, REVIEW_NOTICE, updatedLine } from './shared.ts';\n\nexport function termsCa(v: PolicyVars): string {\n return `# Terms of Service\n${updatedLine(v)}\n${REVIEW_NOTICE}\n\nThese terms govern your use of ${v.url} (the \"Site\"), operated by ${v.businessName} (\"we\", \"us\"). By accessing or using the Site, you agree to these terms. If you do not agree to them, please do not use the Site.\n\nWe may change these terms from time to time. The version published on the Site is the one that applies, and your continued use of the Site after a change means you accept the revised terms.\n\n## Use of the Site\n\nYou may use the Site for lawful purposes only. You agree not to:\n\n${bullets([\n 'use the Site in any way that breaches any applicable law or regulation',\n 'attempt to gain unauthorized access to the Site, its servers, or any connected system',\n 'interfere with or disrupt the operation of the Site, including by introducing malicious code',\n 'collect or harvest information about other users of the Site',\n 'reproduce, duplicate, or resell any part of the Site except as these terms permit',\n])}\n\nWe may suspend or withdraw access to the Site, in whole or in part, at any time and without notice.\n\n## Intellectual Property\n\nUnless stated otherwise, the content of the Site — including text, graphics, logos, and layout — is owned by or licensed to us and is protected by copyright and other intellectual property laws. You may view, download, and print content from the Site for your own personal, non-commercial use. Any other use requires our prior written permission.\n\n## Accuracy of Information\n\nWe take reasonable care to keep the Site accurate and current, but we make no representation or warranty that the content is complete, accurate, or up to date. Content on the Site is provided for general information only and should not be relied on as advice for your particular circumstances.\n\n## Third Party Links and Services\n\nThe Site may link to, or rely on, websites and services operated by others. We do not control those sites and services and are not responsible for their content, availability, or practices. A link is not an endorsement.\n\n## Disclaimer\n\n**The Site is provided \"as is\" and \"as available\", without warranty of any kind, whether express or implied.** To the fullest extent permitted by law, we disclaim all warranties, including implied warranties of merchantability, fitness for a particular purpose, and non-infringement. We do not warrant that the Site will be uninterrupted, secure, or error free.\n\n## Limitation of Liability\n\n**To the fullest extent permitted by law, we will not be liable for any indirect, incidental, special, consequential, or punitive damages, or for any loss of profits, revenue, data, or goodwill, arising out of or in connection with your use of the Site** — whether the claim is based in contract, tort, or any other legal theory, and whether or not we were advised of the possibility of such damages.\n\nNothing in these terms excludes or limits liability that cannot be excluded or limited under applicable law.\n\n## Privacy\n\nOur handling of personal information is described in our Privacy Policy, which forms part of these terms.\n\n## Governing Law\n\nThese terms are governed by the laws of ${governingLaw(v)}. You agree to the exclusive jurisdiction of the courts of that jurisdiction for any dispute arising out of or in connection with these terms or the Site.\n\n## Contact\n\nIf you have questions about these terms, please contact us at ${v.mailingAddress}.\n`;\n}\n\n/**\n * Canadian law is split between the provinces and the federal Parliament, so the\n * conventional clause names both. Without a province we can only name the\n * country — better a broader clause than one asserting a province we guessed.\n */\nfunction governingLaw(v: PolicyVars): string {\n if (v.governingLaw) return v.governingLaw;\n return v.governingProvince\n ? `${v.governingProvince} and the federal laws of ${v.governingCountry} applicable therein`\n : v.governingCountry;\n}\n","/**\n * The jurisdiction registry.\n *\n * Adding a jurisdiction is: author the three templates, add one key here, add\n * one member to `JURISDICTIONS` in `config.ts`. The `satisfies` below makes the\n * second and third steps a compile error if you skip either — a config could\n * otherwise name a jurisdiction with no templates behind it and silently render\n * against the wrong body of law.\n *\n * Every jurisdiction owes all three documents. A partial set would mean\n * `legal.termsOfService.enabled` silently emitting nothing.\n */\nimport type { Jurisdiction } from '../../config.ts';\nimport type { PolicyVars } from '../derive.ts';\nimport { cookiesCa } from './cookies.ca.ts';\nimport { privacyCa } from './privacy.ca.ts';\nimport { termsCa } from './terms.ca.ts';\n\nexport type LegalDoc = 'privacy' | 'terms' | 'cookies';\n\nexport type DocSet = Record<LegalDoc, (v: PolicyVars) => string>;\n\nexport const TEMPLATES = {\n ca: { privacy: privacyCa, terms: termsCa, cookies: cookiesCa },\n} satisfies Record<Jurisdiction, DocSet>;\n\n/** Stable output order, independent of which docs a given config enables. */\nexport const DOC_ORDER: LegalDoc[] = ['privacy', 'terms', 'cookies'];\n\n/** Output filename stem per document — also the Bricks shortcode's allowlist. */\nexport const DOC_SLUGS: Record<LegalDoc, string> = {\n privacy: 'privacy-policy',\n terms: 'terms-of-service',\n cookies: 'cookie-notice',\n};\n","/**\n * Generate a site's legal documents from its config.\n *\n * Shaped after `generateDocs` rather than after a `generate()` format, and the\n * reason is structural: `generate()` is keyed to a **`DesignSystem`**, while a\n * privacy policy renders from a **`Config`**. Bolting it on as a `Format`\n * would mean a format that ignores its own input. So this is a sibling public\n * function that returns a `{ relPath: content }` map and lets each caller write\n * it where it belongs — the CLI to stdout or a directory, the bricks build into\n * `dist/legal/`, the Astro integration into a content collection.\n *\n * Pure: no filesystem, no clock, no shared state.\n */\nimport { derivePolicyVars, type PolicyVars } from './derive.ts';\nimport { parseMarkdown, toContentNodes, toHtmlFragment, toPortableText } from './render.ts';\nimport { DOC_ORDER, DOC_SLUGS, TEMPLATES, type LegalDoc } from './templates/index.ts';\nimport type { Config } from '../config.ts';\nimport type { ContentNode } from '@getvitops/utils';\n\nexport type LegalOutput = 'md' | 'html' | 'portable-text';\n\nexport interface GenerateLegalOptions {\n /** Which documents to render. Defaults to those enabled in the config. */\n docs?: LegalDoc[];\n /** Output format. Default `md`. */\n output?: LegalOutput;\n}\n\nconst EXT: Record<LegalOutput, string> = {\n md: 'md',\n html: 'html',\n 'portable-text': 'json',\n};\n\n/** Which documents the config asks for, in a stable order. */\nexport function enabledDocs(cfg: Config): LegalDoc[] {\n const legal = cfg.site.legal;\n const on: Record<LegalDoc, boolean> = {\n privacy: !!legal?.privacyPolicy?.enabled,\n terms: !!legal?.termsOfService?.enabled,\n cookies: !!legal?.cookieConsent?.enabled,\n };\n return DOC_ORDER.filter((d) => on[d]);\n}\n\n/** Render one document to markdown. The other outputs derive from this. */\nexport function renderMarkdown(cfg: Config, doc: LegalDoc, vars?: PolicyVars): string {\n const jurisdiction = cfg.site.legal?.jurisdiction ?? 'ca';\n // `validateConfig` rejects an unregistered jurisdiction, so this is a guard for\n // callers that skipped validation rather than an expected path.\n const set = TEMPLATES[jurisdiction];\n if (!set) throw new Error(`no legal templates for jurisdiction \"${jurisdiction}\"`);\n return set[doc](vars ?? derivePolicyVars(cfg));\n}\n\n/**\n * Render one document as a `ContentNode` tree — the framework-agnostic shape the\n * site config already uses for `templates` of type `nodes`, so an Astro consumer\n * can hand it to `NodeRenderer` instead of injecting a string of HTML.\n */\nexport function renderNodes(cfg: Config, doc: LegalDoc): ContentNode[] {\n return toContentNodes(parseMarkdown(renderMarkdown(cfg, doc)));\n}\n\n/**\n * Every enabled legal document, keyed by output path.\n *\n * Documents are keyed by filename (`privacy-policy.md`) rather than by document\n * id so a caller can write the map verbatim.\n */\nexport function generateLegal(\n cfg: Config,\n opts: GenerateLegalOptions = {},\n): Record<string, string> {\n const output = opts.output ?? 'md';\n const docs = opts.docs ?? enabledDocs(cfg);\n // Derived once: every document asserts the same facts, and re-deriving per\n // document would let them disagree if the derivation ever stopped being pure.\n const vars = derivePolicyVars(cfg);\n\n const out: Record<string, string> = {};\n for (const doc of docs) {\n const md = renderMarkdown(cfg, doc, vars);\n const slug = DOC_SLUGS[doc];\n const content =\n output === 'md'\n ? md\n : output === 'html'\n ? toHtmlFragment(parseMarkdown(md))\n : JSON.stringify(toPortableText(parseMarkdown(md), slug), null, 2) + '\\n';\n out[`${slug}.${EXT[output]}`] = content;\n }\n return out;\n}\n\nexport { derivePolicyVars, type PolicyVars } from './derive.ts';\nexport {\n detectProcessorKeys,\n KNOWN_PROCESSORS,\n processorsMissingLocation,\n resolveProcessors,\n} from './providers.ts';\nexport type { KnownProcessorKey, Processor, ProcessorStorage } from './providers.ts';\nexport { parseMarkdown, toContentNodes, toHtmlFragment, toPortableText } from './render.ts';\nexport type { Block, Span } from './render.ts';\nexport { DOC_ORDER, DOC_SLUGS, TEMPLATES } from './templates/index.ts';\nexport type { DocSet, LegalDoc } from './templates/index.ts';\n","/**\n * Build an SVG sprite from an icon `include` map.\n *\n * This is the delivery path for consumers that cannot run an icon integration:\n * Bricks/WordPress, EmDash's renderers, anything rendering HTML outside an Astro\n * build. Markup is `<svg><use href=\"…/icons.svg#ph--caret-down\"/></svg>` — no\n * runtime JS and no network call, which is what keeps it inside the tier rules\n * (a runtime-fetching element would be behaviour JS with no fallback to enhance).\n *\n * The icon DATA comes from the `@iconify-json/*` collections, which stay optional\n * peers loaded dynamically: `@iconify-json/ph` alone is ~4.5 MB and the semantic\n * map spans five sets, so depending on them directly would be indefensible for\n * every consumer who never asks for a sprite.\n */\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { IconifyJSON } from '@iconify/types';\nimport { getIconData, iconToSVG, replaceIDs } from '@iconify/utils';\n\nexport interface IconSpriteOptions {\n /** Exactly `generateIconInclude()`'s shape: collection → icon names. */\n include: Record<string, string[]>;\n /**\n * Extra ids pointing at an already-included icon, e.g. `{ 'icon-menu': 'ph:list' }`,\n * so a consumer can reference a semantic name without knowing the set.\n */\n aliases?: Record<string, string>;\n /**\n * Directory to resolve `@iconify-json/*` from. Defaults to `process.cwd()`.\n *\n * Load-bearing: the collections are the CONSUMER's dependency, not this\n * package's, so a bare `import('@iconify-json/ph/…')` from inside the\n * generator resolves against the generator's own node_modules and misses them\n * entirely — which reads as \"not installed\" on a project that has them.\n */\n resolveFrom?: string;\n /** Injected in tests so the emitter can run without any @iconify-json/* installed. */\n loadSet?: (prefix: string) => Promise<IconifyJSON | null>;\n}\n\nexport interface IconSpriteResult {\n svg: string;\n /** Every `<symbol>` id emitted, in order. */\n ids: string[];\n /** `prefix:name` entries that were asked for but not found. */\n missing: string[];\n}\n\n/**\n * `ph:caret-down` → `ph--caret-down`.\n *\n * The one place this grammar lives. `Icon.astro` mirrors it and `icon.test.ts`\n * guards the pair, because a drift here resolves `<use>` to nothing and renders\n * as an empty box rather than an error.\n */\nexport function spriteId(qualified: string): string {\n return qualified.replace(':', '--');\n}\n\n/**\n * Default loader: the collection JSON shipped by `@iconify-json/<prefix>`.\n *\n * Resolved through a `createRequire` rooted at the consumer's directory, then\n * imported by absolute path — a bare specifier would resolve against this\n * package instead, where the collections deliberately aren't installed.\n */\nasync function loadCollection(prefix: string, from: string): Promise<IconifyJSON | null> {\n try {\n const req = createRequire(pathToFileURL(join(from, 'noop.js')));\n const path = req.resolve(`@iconify-json/${prefix}/icons.json`);\n const mod = await import(pathToFileURL(path).href, { with: { type: 'json' } });\n return (mod.default ?? mod) as IconifyJSON;\n } catch {\n return null;\n }\n}\n\nexport async function buildIconSprite(o: IconSpriteOptions): Promise<IconSpriteResult> {\n const from = o.resolveFrom ?? process.cwd();\n const load = o.loadSet ?? ((prefix: string) => loadCollection(prefix, from));\n const symbols: string[] = [];\n const ids: string[] = [];\n const missing: string[] = [];\n /** qualified name → its rendered body+viewBox, so an alias can reuse it. */\n const rendered = new Map<string, { viewBox: string; body: string }>();\n\n for (const [prefix, names] of Object.entries(o.include)) {\n if (!names?.length) continue;\n const set = await load(prefix);\n if (!set) {\n throw new Error(\n `[vitops icons] Cannot build the sprite: the \"${prefix}\" icon set is not installed. ` +\n `Run \\`pnpm add -D @iconify-json/${prefix}\\`, or drop it from your icons config.`,\n );\n }\n for (const name of names) {\n // getIconData resolves aliases and parent chains, so `include` can name\n // either a real icon or one of the set's own aliases.\n const data = getIconData(set, name);\n if (!data) {\n missing.push(`${prefix}:${name}`);\n continue;\n }\n const built = iconToSVG(data, { height: 'none' });\n // MANDATORY. Two icons carrying the same internal gradient/clip id would\n // otherwise collide once concatenated into one document, and the second\n // silently renders with the first's paint.\n const body = replaceIDs(built.body);\n const id = spriteId(`${prefix}:${name}`);\n rendered.set(`${prefix}:${name}`, { viewBox: built.attributes.viewBox, body });\n ids.push(id);\n symbols.push(`<symbol id=\"${id}\" viewBox=\"${built.attributes.viewBox}\">${body}</symbol>`);\n }\n }\n\n for (const [alias, target] of Object.entries(o.aliases ?? {})) {\n const hit = rendered.get(target);\n if (!hit) {\n missing.push(`${target} (aliased as ${alias})`);\n continue;\n }\n // The body is DUPLICATED rather than nested as <use href=\"#target\"> inside\n // the symbol. Nested-use is legal but unreliable precisely under an\n // external-file <use>, which is exactly how this sprite is consumed; a\n // handful of duplicated paths in a ~40 KB file is the cheaper trade.\n ids.push(alias);\n symbols.push(`<symbol id=\"${alias}\" viewBox=\"${hit.viewBox}\">${hit.body}</symbol>`);\n }\n\n const svg =\n `<svg xmlns=\"http://www.w3.org/2000/svg\" style=\"display:none\" aria-hidden=\"true\">` +\n symbols.join('') +\n `</svg>\\n`;\n\n return { svg, ids, missing };\n}\n\n/**\n * One icon's renderable parts, for inlining into markup.\n *\n * Exists because `<Icon />` cannot go through astro-icon: its `./components`\n * entry is a TypeScript file that Vite must transform, so it can only be\n * reached by a statically-analysable import — and a static import is exactly\n * what made the optional peer mandatory for anyone rendering Popover, Details\n * or Drawer. Reading the collection directly sidesteps the peer entirely and\n * shares this file's loader with the sprite, so both paths draw the same glyph.\n */\nexport async function loadIconSvg(\n qualified: string,\n opts?: { resolveFrom?: string; loadSet?: (prefix: string) => Promise<IconifyJSON | null> },\n): Promise<{ viewBox: string; body: string } | null> {\n const i = qualified.indexOf(':');\n if (i <= 0) return null;\n const prefix = qualified.slice(0, i);\n const name = qualified.slice(i + 1);\n const from = opts?.resolveFrom ?? process.cwd();\n const load = opts?.loadSet ?? ((p: string) => loadCollection(p, from));\n const set = await load(prefix);\n if (!set) return null;\n const data = getIconData(set, name);\n if (!data) return null;\n const built = iconToSVG(data, { height: 'none' });\n // Same id-collision guard as the sprite: several inlined icons share one\n // document, so an un-rewritten gradient id would cross-render.\n return { viewBox: built.attributes.viewBox, body: replaceIDs(built.body) };\n}\n","/**\n * Pure, parameterized port of the Vitops design-system generator.\n *\n * `generate({ input, format, outDir })` reads a consumer's `design-system.json`,\n * validates it, and emits consumer-ready output for the chosen format into\n * `outDir`. Unlike the original CWD-bound script it mutates no shared state: every\n * generated token layer is built in memory and either bundled (css/bricks) or\n * inlined (tailwind) before writing.\n *\n * Framework-static assets (the hand-written CSS partials, the Bricks PHP + loader,\n * and the pre-built JS bundles) live under `assets/` in this package and are read /\n * copied from there — they are the same for every consumer.\n */\nimport { readFileSync, writeFileSync, mkdirSync, cpSync, existsSync, readdirSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createHash } from 'node:crypto';\nimport { transform } from 'lightningcss';\nimport { validate, type DesignSystem } from './schema.ts';\nimport { generateDocs } from './docs.ts';\nimport { emitDesignMd } from './design-md.ts';\nimport { generateLegal } from './legal/index.ts';\nimport { buildIconSprite } from './icons-sprite.ts';\nimport { resolveInput, resolveConfig, type Config } from './config.ts';\nimport { generateIconInclude, resolveIcon } from '@getvitops/utils';\nimport {\n BASE_HOOK,\n DARK_SEL,\n SYSTEM_DARK_SEL,\n TW_CLASH,\n type RoleSpec,\n roleHue,\n roleKind,\n} from './shared.ts';\nimport {\n checkContrast,\n expandPalette,\n functionalRole,\n ladderWarnings,\n monotonicityErrors,\n NUMERIC_STEPS,\n tokenClass,\n tokenVar,\n type ExpandedHue,\n type FunctionalRole,\n} from './tokens.ts';\n\nexport type Format = 'bricks' | 'css' | 'tailwind' | 'design';\n\n/**\n * Formats that emit a stylesheet. `design` is the odd one out — it emits a\n * single `DESIGN.md` brief and no CSS at all — so anything that expects to\n * import the generator's output (the Vite plugin's injected stylesheet, the\n * Astro integration) types against this narrower set.\n */\nexport type StylesheetFormat = Exclude<Format, 'design'>;\n\nexport interface GenerateOptions {\n /**\n * The config to build from — a path, or an already-parsed object.\n *\n * **Either kind is accepted.** A bare `design-system.json`, or the larger\n * `Config` that embeds one (commonly `company.json` / `site.json`), in\n * which case the design system is `designSystem.themes[theme]` with its\n * `extends` chain resolved. The two are told apart by shape, not by filename —\n * see `isConfig`.\n *\n * Passing a site config here also supplies `site`, so the site-level facts\n * generation depends on (`designSystem.defaultColorScheme`, the legal\n * documents, the icon sprite) don't need the same path declared twice. Each of\n * those is still gated on a field in that config, so nothing new appears\n * unless the config asks for it.\n */\n input: string | DesignSystem | Config;\n /** Output target. Default: 'bricks'. */\n format?: Format;\n /** Directory to write outputs into. Default: 'dist'. */\n outDir?: string;\n /** Override the framework asset root (advanced/testing). */\n assetsDir?: string;\n /**\n * Which `designSystem.themes` entry to build. Default: the config's\n * `defaultTheme`, else `default`. An error on a bare `design-system.json`,\n * which holds one design system and no themes map.\n */\n theme?: string;\n /**\n * Environment whose A/B variant applies to the site config, wherever it came\n * from (`input` or `site`). Default: `'production'`.\n */\n siteEnv?: string;\n /**\n * The site config, when it is a *different* file from `input` — enabling\n * legal-document output into `<outDir>/legal/*.html` and supplying\n * `designSystem.defaultColorScheme`.\n *\n * Redundant when `input` is already a site config; set both and this one wins.\n */\n site?: string | Config;\n /**\n * Emit the `prefers-color-scheme: dark` block (see `BuildOptions`).\n *\n * Normally this comes from the site config's `designSystem.defaultColorScheme: \"system\"`, which\n * is where the fact belongs. This is the escape hatch for consumers with a\n * `design-system.json` and no site config at all: requiring a whole\n * `Config` — which must carry a full `designSystem` — to set one boolean\n * would be out of proportion. Set explicitly, it wins over the site config.\n */\n systemColorScheme?: boolean;\n}\n\nexport interface GenerateResult {\n format: Format;\n outDir: string;\n written: string[];\n}\n\nconst HERE = dirname(fileURLToPath(import.meta.url));\nconst DEFAULT_ASSETS = join(HERE, '..', 'assets');\n\n// ── colour machinery ─────────────────────────────────────────────────────────\n// Every hue is an 11-step numeric OKLCH scale on a shared lightness ladder (see\n// tokens.ts); every role resolves to `--color-<target>-<role>[-<variant>]`.\n// Dark mode re-points which step each token reads; the solid family is stable.\nconst UTILITY_PROPS: Record<string, string> = {\n bg: 'background-color',\n text: 'color',\n icon: 'color',\n border: 'border-color',\n outline: 'outline-color',\n fill: 'fill',\n stroke: 'stroke',\n};\n\n/**\n * Which token target a utility family draws from. Four families have tokens of\n * their own; the other three are aliases, because an SVG fill wants the icon\n * tier (3:1, may run vivid) and an outline wants the border tier — minting\n * separate tokens for them would be three more things to keep in contrast.\n */\nconst UTILITY_SOURCE: Record<string, string> = {\n bg: 'bg',\n text: 'text',\n icon: 'icon',\n border: 'border',\n outline: 'border',\n fill: 'icon',\n stroke: 'icon',\n};\n\n/** The target segment of a token key (`bg-solid-bold` → `bg`). */\nconst targetOf = (key: string): string => {\n const i = key.indexOf('-');\n return i === -1 ? key : key.slice(0, i);\n};\n\nexport interface ColorUtility {\n /** Class name, without the leading dot. */\n cls: string;\n /** CSS property the class sets. */\n prop: string;\n /** `var(--…)` reference the class resolves to. */\n value: string;\n}\n\n/**\n * The framework's container breakpoints. `sm-`/`md-`/`lg-`/`xl-` prefixes in the\n * css/bricks formats; `@sm:`/`@md:`/… in tailwind, where they are registered as\n * `--container-*` in `@theme` and Tailwind expands the variants itself.\n */\nexport const BREAKPOINTS: readonly (readonly [string, string])[] = [\n ['sm', '30rem'],\n ['md', '48rem'],\n ['lg', '64rem'],\n ['xl', '80rem'],\n] as const;\n\n/**\n * Gap utilities over the space scale, emitted from one list into all three\n * formats — same arrangement as `roleColorUtilities`, for the same reason.\n *\n * These did not exist. `vitops docs css` advertised a `g` class that was never\n * emitted, so the honest answer for a css/bricks consumer was an inline\n * `style=\"gap: …\"`, which is what this repo's own `index.html` does throughout.\n * Tailwind does not fill the hole either: the fluid space steps are deliberately\n * kept OUT of Tailwind's `--spacing-*` namespace (named keys there shadow the\n * size scales — `max-w-7xl` would resolve to `var(--spacing-7xl)`), so `gap-md`\n * is not something Tailwind can derive on its own. Measured against\n * tailwindcss@4.3.3: an explicit `@utility gap-md` is honoured, coexists with\n * the built-in numeric `gap-4`, and picks up variants (`@md:gap-md`).\n *\n * The whole matrix is emitted rather than a useful-looking subset: an undefined\n * step produces no rule and no error in either format, so a missing\n * `md-gap-x-2xl` would be indistinguishable from a working one.\n */\nexport function gapUtilities(steps: { name: string }[]): ColorUtility[] {\n const FAMILIES: [string, string][] = [\n ['gap', 'gap'],\n ['gap-x', 'column-gap'],\n ['gap-y', 'row-gap'],\n ];\n return steps.flatMap(({ name }) =>\n FAMILIES.map(([prefix, prop]) => ({\n cls: `${prefix}-${name}`,\n prop,\n value: `var(--space-${name})`,\n })),\n );\n}\n\n/**\n * Every role colour utility, each class name emitted EXACTLY once.\n *\n * There is now a single axis. The target lives *inside* the token name, so\n * `bg-danger-muted` and `text-danger-muted` are different tokens and the\n * collision the old plane/stop precedence rule existed to arbitrate cannot\n * arise. Both the css/bricks and tailwind paths render from this one list, which\n * is what keeps the three formats in step; `format-parity.test.ts` holds them\n * there.\n *\n * The class name IS the token name minus `--color-`, so there is no separate\n * naming rule to drift — see `tokenClass` in tokens.ts.\n */\nexport function roleColorUtilities(\n roles: readonly FunctionalRole[],\n utilities: readonly string[],\n): ColorUtility[] {\n const out: ColorUtility[] = [];\n for (const fr of roles) {\n for (const fam of utilities) {\n const source = UTILITY_SOURCE[fam];\n if (source == null) continue;\n for (const key of Object.keys(fr.light)) {\n if (targetOf(key) !== source) continue;\n const canonical = tokenClass(fr.role, key);\n // Alias families keep the token but rename the leading segment:\n // `border-danger-bold` → `outline-danger-bold`.\n const cls = fam === source ? canonical : fam + canonical.slice(source.length);\n out.push({\n cls,\n prop: UTILITY_PROPS[fam] as string,\n value: `var(${tokenVar(fr.role, key)})`,\n });\n }\n }\n }\n return out;\n}\n\n/** Render the shared set as plain rules (css/bricks formats). */\nconst colorUtilityRules = (u: ColorUtility[]): string =>\n u.map(({ cls, prop, value }) => `.${cls} { ${prop}: ${value}; }`).join('\\n');\n\nconst decls = (obj: Record<string, string>, indent = ' ') =>\n Object.entries(obj)\n .map(([k, v]) => `${indent}${k}: ${v};`)\n .join('\\n');\n\n// ── fluid modular scale ───────────────────────────────────────────────────────\ninterface ScaleConfig {\n base: string;\n ratio: number;\n steps?: number;\n names?: string[];\n baseStep?: number;\n baseline?: string;\n fluid?: { minVw: string; maxVw: string; minRatio: number };\n}\ninterface ScaleStep {\n name: string;\n value: string;\n max: string;\n offset: number;\n}\nconst round = (n: number) => Number(n.toFixed(4)).toString();\nconst rem = (v: string) => parseFloat(v);\nconst buildScale = (s: ScaleConfig): ScaleStep[] => {\n const names = s.names ?? Array.from({ length: s.steps ?? 0 }, (_, i) => String(i + 1));\n const base = rem(s.base);\n const baseStep = s.baseStep ?? Math.ceil(names.length / 2);\n const baselineIdx = s.baseline ? names.indexOf(s.baseline) : baseStep - 1;\n return names.map((name, i) => {\n const k = i - (baseStep - 1);\n const vMax = base * Math.pow(s.ratio, k);\n const max = `${round(vMax)}rem`;\n let value = max;\n if (s.fluid) {\n const { minVw, maxVw, minRatio } = s.fluid;\n const vMin = base * Math.pow(minRatio, k);\n const lo = Math.min(vMin, vMax);\n const hi = Math.max(vMin, vMax);\n if (lo !== hi) {\n const slope = (vMax - vMin) / (rem(maxVw) - rem(minVw));\n const intercept = vMin - slope * rem(minVw);\n const sign = slope < 0 ? '-' : '+';\n const pref = `calc(${round(intercept)}rem ${sign} ${round(Math.abs(slope * 100))}vw)`;\n value = `clamp(${round(lo)}rem, ${pref}, ${round(hi)}rem)`;\n }\n }\n return { name, value, max, offset: i - baselineIdx };\n });\n};\n\n// ── typography ─────────────────────────────────────────────────────────────────\ninterface TypographyRole {\n family?: string;\n [key: string]: string | number | undefined;\n}\nconst TYPO_KEYMAP: Record<string, [string, string]> = {\n family: ['font-family', 'ff'],\n size: ['font-size', 'fs'],\n weight: ['font-weight', 'fw'],\n style: ['font-style', 'fst'],\n 'line-height': ['line-height', 'lh'],\n tracking: ['letter-spacing', 'ls'],\n 'text-decoration': ['text-decoration', 'td'],\n 'text-transform': ['text-transform', 'tt'],\n 'text-wrap': ['text-wrap', 'tw'],\n color: ['color', 'color'],\n};\n/**\n * Wrong spellings worth naming explicitly, because each is a plausible reading of\n * the key it isn't. `transform`/`decoration` were documented in the schema for a\n * while and shipped title-case navigation to production; `letter-spacing` and\n * `font-*` are the natural guesses for keys we chose to shorten.\n */\nconst ALSO_MEANT: Record<string, string> = {\n transform: 'text-transform',\n decoration: 'text-decoration',\n 'letter-spacing': 'tracking',\n wrap: 'text-wrap',\n 'font-family': 'family',\n 'font-size': 'size',\n 'font-weight': 'weight',\n 'font-style': 'style',\n lineHeight: 'line-height',\n};\nconst TYPO_IDENTITY: Record<string, string> = {\n 'font-style': 'normal',\n 'letter-spacing': 'normal',\n 'text-decoration': 'none',\n 'text-transform': 'none',\n 'text-wrap': 'wrap',\n};\n\n// ── animation state defaults ─────────────────────────────────────────────────\nconst STATE_DEFAULT: Record<string, string> = {\n opacity: '1',\n 'translate-x': '0',\n 'translate-y': '0',\n 'scale-x': '1',\n 'scale-y': '1',\n rotate: '0deg',\n blur: '0px',\n shadow: '0 0 0 transparent',\n brightness: '1',\n grayscale: '0',\n contrast: '1',\n saturate: '1',\n sepia: '0',\n 'hue-rotate': '0deg',\n clip: 'none',\n // The layout stage. `.transition` only declares `height` inside\n // `@supports (interpolate-size: allow-keywords)`, since `0 → auto` is not\n // interpolable without it — but the default belongs here either way, so the\n // flip resolves to the element's natural height rather than to nothing.\n height: 'auto',\n};\n\ninterface Pattern {\n group?: string;\n overrides?: Record<string, string>;\n element?: string;\n class?: string;\n fill?: boolean;\n default_role?: string;\n base?: Record<string, string>;\n states?: Record<string, Record<string, unknown>>;\n roles?: string[];\n}\n\nconst id = (key: string) => createHash('sha256').update(key).digest('hex').slice(0, 6);\n\n/**\n * The in-memory output of building a design system. String fields are CSS/JSON\n * ready to write; the generated CSS partials feed the css/bricks bundler.\n */\ninterface Built {\n generated: Record<string, string>; // filename (under generated/) -> css\n bricksColorsNamed: string;\n bricksColorsSemantic: string;\n bricksVariables: string;\n tokensJson: string;\n designManifest: string;\n tailwind: string;\n designMd: string;\n // captured for the tailwind bundler\n twTypeTokensCss: string;\n twPatternTokensCss: string;\n patternsCss: string;\n}\n\n// Exported for tests only — deliberately NOT re-exported from index.ts, so the\n// package's public API stays `generate` / `generateDocs` / `validate`.\nexport interface BuildOptions {\n /**\n * Also flip to dark when the OS asks and no explicit choice has been made —\n * `@media (prefers-color-scheme: dark)`.\n *\n * A build flag rather than a `DesignSystem` field: it describes what a *site*\n * wants, not what the system defines, so it comes from the site config's\n * `designSystem.defaultColorScheme` and `generate()` stays keyed to a `DesignSystem`.\n * Off by default, because turning it on flips a site dark for dark-OS users.\n */\n systemColorScheme?: boolean;\n}\n\nexport function build(\n ds: DesignSystem,\n format: Format,\n assetsDir: string,\n buildOpts: BuildOptions = {},\n): Built {\n const BRICKS = format === 'bricks';\n // Every hue expands to its 11-step numeric OKLCH scale; every role resolves\n // to functional tokens over its hue. Dark mode is the automatic flip.\n const expandedPalette = expandPalette(ds.colors.palette as Record<string, unknown>);\n const roleMap = ds.colors.roles as Record<string, RoleSpec>;\n const scaleRoles: FunctionalRole[] = [];\n for (const [role, spec] of Object.entries(roleMap)) {\n const hueName = roleHue(spec);\n const hue = expandedPalette[hueName];\n if (hue == null) throw new Error(`role \"${role}\" references unknown palette hue \"${hueName}\"`);\n scaleRoles.push(functionalRole(role, hueName, hue, roleKind(spec)));\n }\n const surfaceRole = scaleRoles.find((r) => r.role === 'surface');\n // The focus ring is role-less by default, so it needs one nominated source.\n // `ui-primary` is the interaction hue — a ring in the brand colour would drift\n // away from the buttons and links it appears on.\n const focusRole = scaleRoles.find((r) => r.role === 'ui-primary') ?? scaleRoles[0];\n\n // A pinned brand colour that sits off the shared lightness ladder is legal —\n // the author asked for that exact colour — but past ~0.03 L the hue reads\n // visibly heavier or lighter than its siblings at that step, so say so.\n for (const w of ladderWarnings(expandedPalette)) console.warn(`[vitops] ${w}`);\n\n // A pinned colour far enough off the ladder can leave the ramp non-monotonic —\n // some step lighter than the one above it. That is an error, not a warning:\n // `snap`, the mode-stable solid family and the dark tables all assume the\n // order, so an inverted ramp runs hover states backwards. Same reasoning as the\n // contrast contract below — this is exactly the drift the fixed ladder exists\n // to eliminate, and it is always author-caused, so it is always actionable.\n {\n const errors = monotonicityErrors(expandedPalette);\n if (errors.length) throw new Error(errors.join('\\n'));\n }\n\n // The contrast contract runs at BUILD time, not only in tests: a consumer\n // editing their own palette has no test suite, and an illegible pairing that\n // ships is far more expensive than a build that stops. Chromatic roles are\n // checked against the surface planes they actually sit on, since coloured text\n // appears over the page far more often than over its own tint.\n {\n const numericOf = (hueName: string) => expandedPalette[hueName]?.numeric ?? {};\n const resolve = (val: string): string => {\n const m = /^var\\(--color-([a-z0-9-]+)-(\\d+)\\)$/.exec(val);\n return m ? (numericOf(m[1] as string)[m[2] as never] ?? val) : val;\n };\n const planeKeys = ['bg', 'bg-muted', 'bg-x-muted'] as const;\n const surfaceBg = surfaceRole\n ? {\n light: planeKeys.flatMap((k) =>\n surfaceRole.light[k] ? [resolve(surfaceRole.light[k] as string)] : [],\n ),\n dark: planeKeys.flatMap((k) =>\n surfaceRole.dark[k] ? [resolve(surfaceRole.dark[k] as string)] : [],\n ),\n }\n : undefined;\n const failures = scaleRoles.flatMap((fr) => checkContrast(fr, numericOf, surfaceBg));\n if (failures.length)\n throw new Error(\n `colour contrast contract failed (${failures.length} pairing${\n failures.length === 1 ? '' : 's'\n }):\\n ${failures.join('\\n ')}`,\n );\n }\n const patterns = ds.patterns;\n const shadows = ds.shadows;\n const typography = ds.typography;\n const UTILITIES = (ds.colors.utilities ?? ['bg', 'text', 'icon', 'border']).filter(\n (u) => u in UTILITY_PROPS,\n );\n\n const generated: Record<string, string> = {};\n\n /**\n * The two background utilities that aren't derived from the palette, so\n * neither the generated scale nor Bricks' own palette import produces them.\n *\n * They exist to undo a pattern's fill — `class=\"card bg-transparent\"` for a\n * flat, border-only card. Tailwind ships both as built-ins, so the tailwind\n * format deliberately emits neither and defers, exactly as it does for the\n * `TW_CLASH` names.\n */\n const NON_PALETTE_BG =\n `/* Undo a pattern's fill (Tailwind provides these natively in that format). */\\n` +\n `.bg-transparent { background-color: transparent; }\\n` +\n `.bg-inherit { background-color: inherit; }\\n`;\n\n // ── color.css ──────────────────────────────────────────────────────────────\n if (BRICKS) {\n generated['color.css'] =\n '/* Colours provided by Bricks (palette import generates tokens + utilities). */\\n' +\n NON_PALETTE_BG;\n } else {\n let css = `/* GENERATED from design-system.json — do not edit by hand. */\\n:root {\\n`;\n css += ` color-scheme: light;\\n`;\n css += ` /* Hue scales (numeric steps, 50 = tinted near-white … 950 = tinted near-black) */\\n`;\n for (const [name, hue] of Object.entries(expandedPalette))\n for (const [n, hex] of Object.entries(hue.numeric))\n css += ` --color-${name}-${n}: ${hex};\\n`;\n css += `\\n /* Role tokens (the public API) */\\n`;\n for (const fr of scaleRoles)\n for (const [t, val] of Object.entries(fr.light))\n css += ` ${tokenVar(fr.role, t)}: ${val};\\n`;\n if (focusRole) {\n css += `\\n /* Focus ring — a boundary, so it takes the solid tone, not a border tint. */\\n`;\n css += ` --color-border-focus: ${focusRole.light['bg-solid']};\\n`;\n }\n if (surfaceRole) {\n css += `\\n /* Translucent surface + scrim */\\n`;\n css += ` --surface-glass: color-mix(in oklch, var(--color-bg-surface) 72%, transparent);\\n`;\n css += ` --overlay: color-mix(in oklch, var(--color-${surfaceRole.hue}-950) 45%, transparent);\\n`;\n }\n css += `}\\n\\n`;\n // Dark appearance: the automatic functional flip (solid stays mode-stable).\n {\n let fb = '';\n for (const fr of scaleRoles)\n for (const [t, val] of Object.entries(fr.dark))\n if (fr.light[t] !== val) fb += ` ${tokenVar(fr.role, t)}: ${val};\\n`;\n if (surfaceRole)\n fb += ` --overlay: color-mix(in oklch, var(--color-${surfaceRole.hue}-950) 60%, transparent);\\n`;\n if (fb) {\n css += `/* Functional role tokens (dark) */\\n`;\n css += `${DARK_SEL} {\\n color-scheme: dark;\\n${fb}}\\n\\n`;\n // The same delta again, for \"no explicit choice + a dark OS\". Opt-in,\n // because switching it on flips a site dark for dark-OS users.\n //\n // This is what makes <wc-color-scheme-toggle>'s \"System\" position mean\n // anything: System *removes* data-theme, so with only the block above it\n // fell through to light on every machine. It also gives a no-JS page the\n // OS appearance, which the toggle alone never could.\n //\n // Yes, `fb` is emitted twice. It is a delta — only the tokens whose dark\n // value differs, and the raw hue ramps never re-point — and two identical\n // runs of text compress to almost nothing, so the cost is far below what\n // a second full colour layer would suggest.\n if (buildOpts.systemColorScheme)\n css +=\n `/* Functional role tokens (dark) — OS preference, no explicit choice */\\n` +\n `@media (prefers-color-scheme: dark) {\\n` +\n ` ${SYSTEM_DARK_SEL} {\\n color-scheme: dark;\\n${fb.replace(/^ {2}/gm, ' ')} }\\n}\\n\\n`;\n }\n }\n // Raw hue steps, then the role set. One axis means every class here is\n // emitted exactly once by construction — no precedence rule, and no reliance\n // on the minifier dropping a shadowed rule.\n css += `/* Colour utilities — ${UTILITIES.join(', ')} */\\n`;\n for (const [name, hue] of Object.entries(expandedPalette))\n for (const n of Object.keys(hue.numeric))\n css +=\n UTILITIES.map(\n (cls) => `.${cls}-${name}-${n} { ${UTILITY_PROPS[cls]}: var(--color-${name}-${n}); }`,\n ).join('\\n') + '\\n';\n css += `\\n/* Role utilities (the public API) */\\n`;\n css += `${colorUtilityRules(roleColorUtilities(scaleRoles, UTILITIES))}\\n`;\n if (surfaceRole)\n css += `.glass { background-color: var(--surface-glass); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }\\n`;\n css += NON_PALETTE_BG;\n generated['color.css'] = css;\n }\n\n // ── shadows.css ──────────────────────────────────────────────────────────────\n {\n const entries = Object.entries(shadows ?? {});\n let sh = `/* GENERATED drop-shadow tokens + utilities — do not edit by hand. */\\n`;\n if (entries.length) {\n sh += `:root {\\n`;\n for (const [name, value] of entries) sh += ` --shadow-${name}: ${value};\\n`;\n sh += `}\\n\\n`;\n for (const [name] of entries)\n sh += `.drop-shadow-${name} { filter: drop-shadow(var(--shadow-${name})); }\\n`;\n }\n generated['shadows.css'] = sh;\n }\n\n // ── scales ───────────────────────────────────────────────────────────────────\n const typeSteps = ds.typeScale ? buildScale(ds.typeScale as ScaleConfig) : [];\n const spaceSteps = ds.spaceScale ? buildScale(ds.spaceScale as ScaleConfig) : [];\n const textMax: Record<string, string> = Object.fromEntries(\n typeSteps.map((s) => [`text-${s.name}`, s.max]),\n );\n\n const typographyFamilies = typography?.families ?? {};\n\n // The recognised key set is closed (TYPO_KEYMAP), and an unrecognised key is\n // dropped rather than emitted — so a typo, or one of the plausible-but-wrong\n // short forms (`transform` for `text-transform`, `decoration` for\n // `text-decoration`), produces a role that looks configured and renders\n // unstyled. That is invisible in the output and survives review, so say it here\n // rather than leaving it to be noticed on a live page.\n {\n const known = new Set(Object.keys(TYPO_KEYMAP));\n for (const [role, spec] of Object.entries(typography?.roles ?? {}))\n for (const key of Object.keys(spec as TypographyRole)) {\n if (known.has(key)) continue;\n const near = ALSO_MEANT[key];\n console.warn(\n `[vitops] typography.roles.${role}: unknown key \"${key}\" — ignored` +\n (near ? `. Did you mean \"${near}\"?` : `. Recognised: ${[...known].join(', ')}.`),\n );\n }\n }\n const withScaleFallback = (v: string) =>\n v.replace(/var\\(\\s*(--text-[\\w-]+)\\s*\\)/g, (m, name) =>\n textMax[name.slice(2)] ? `var(${name}, ${textMax[name.slice(2)]})` : m,\n );\n const roleDecls = (role: string, spec: TypographyRole): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const [key, [prop, sfx]] of Object.entries(TYPO_KEYMAP)) {\n const identity = TYPO_IDENTITY[prop];\n if (spec[key] == null && identity == null) continue;\n const raw =\n spec[key] == null\n ? (identity as string)\n : key === 'family'\n ? (typographyFamilies[spec.family as string] ?? String(spec.family))\n : key === 'size'\n ? withScaleFallback(String(spec[key]))\n : String(spec[key]);\n out[prop] = `var(--${role}-${sfx}, ${raw})`;\n }\n return out;\n };\n\n // ── type-tokens.css ──────────────────────────────────────────────────────────\n let twTypeTokensCss = '';\n if (BRICKS) {\n generated['type-tokens.css'] =\n '/* Fonts + type/space scales provided by Bricks (Font + Variables managers). */\\n';\n } else {\n const root: Record<string, string> = {};\n for (const [name, stack] of Object.entries(ds.fonts ?? {})) root[`--font-${name}`] = stack;\n for (const s of typeSteps) root[`--text-${s.name}`] = s.value;\n for (const s of spaceSteps) root[`--space-${s.name}`] = s.value;\n const css =\n `/* GENERATED font families + fluid type/space scales — do not edit by hand.\\n` +\n ` --font-* are STACKS ONLY; no @font-face is emitted here. Load webfonts with\\n` +\n ` Astro's fonts: config and point the token at the family's cssVariable. */\\n` +\n `:root {\\n${decls(root)}\\n}\\n`;\n twTypeTokensCss = css;\n generated['type-tokens.css'] = css;\n }\n\n // ── spacing.css (gap utilities) ──────────────────────────────────────────────\n // Emitted for css AND bricks: the `--space-*` tokens come from this file in the\n // css format and from Bricks' Variables import in the bricks format, but the\n // class names are ours either way — Bricks generates utility classes only for\n // the colour palette.\n {\n const gaps = gapUtilities(spaceSteps);\n let sp = `/* GENERATED gap utilities — do not edit by hand. */\\n`;\n if (gaps.length) {\n for (const { cls, prop, value } of gaps) sp += `.${cls} { ${prop}: ${value}; }\\n`;\n for (const [bp, width] of BREAKPOINTS) {\n sp += `\\n@container (min-width: ${width}) {\\n`;\n for (const { cls, prop, value } of gaps) sp += ` .${bp}-${cls} { ${prop}: ${value}; }\\n`;\n sp += `}\\n`;\n }\n }\n generated['spacing.css'] = sp;\n }\n\n // ── tokens.css (pattern token cascade) ───────────────────────────────────────\n let twPatternTokensCss = '';\n {\n const tDefaults = patterns?.defaults ?? {};\n const tRadii = patterns?.radii ?? {};\n const tGroups = patterns?.groups ?? {};\n const tZ = patterns?.z ?? {};\n const tItems = (patterns?.items ?? {}) as Record<string, Pattern>;\n const root: Record<string, string> = {};\n for (const [prop, val] of Object.entries(tDefaults)) root[`--${prop}-default`] = val;\n if (!BRICKS) for (const [name, val] of Object.entries(tRadii)) root[`--br-${name}`] = val;\n for (const [group, props] of Object.entries(tGroups))\n for (const [prop, val] of Object.entries(props)) root[`--${prop}-${group}`] = val;\n for (const [name, n] of Object.entries(tZ)) root[`--z-tier-${name}`] = String(n);\n const aliases: Record<string, string> = {};\n for (const [name, p] of Object.entries(tItems)) {\n if (!p.group) continue;\n for (const prop of Object.keys(tGroups[p.group] ?? {}))\n aliases[`--${prop}-${name}-group`] = `var(--${prop}-${p.group})`;\n for (const [prop, val] of Object.entries(p.overrides ?? {}))\n aliases[`--${prop}-${name}-group`] = val;\n }\n let tok = `/* GENERATED pattern token cascade — do not edit by hand. */\\n:root {\\n`;\n tok += decls(root) + '\\n';\n if (Object.keys(aliases).length) tok += '\\n' + decls(aliases) + '\\n';\n tok += `}\\n`;\n twPatternTokensCss = tok;\n generated['tokens.css'] = tok;\n }\n\n // ── typography.css (.font-* roles) ───────────────────────────────────────────\n {\n const roles = (typography?.roles ?? {}) as Record<string, TypographyRole>;\n const headings = typography?.headings ?? {};\n let typo = `/* GENERATED typography roles — do not edit by hand. */\\n`;\n for (const [role, spec] of Object.entries(roles))\n typo += `.font-${role} {\\n${decls(roleDecls(role, spec))}\\n}\\n`;\n for (const [tag, role] of Object.entries(headings))\n if (roles[role]) typo += `${tag} {\\n${decls(roleDecls(role, roles[role]))}\\n}\\n`;\n generated['typography.css'] = typo;\n }\n\n // ── patterns.css (component interaction patterns) ────────────────────────────\n // `sel` is a *builder* taking the state's pseudo, not a finished selector, and\n // that indirection is load-bearing rather than stylistic: an element pattern\n // has to place the pseudo INSIDE its `:where()`, because `:where()` zeroes the\n // element but a pseudo appended outside it still counts. `:where(a, .link):hover`\n // is 0-1-0 — the same weight as `.cta-brand-primary` — so the link pattern's\n // hover colour tied with every `<a class=\"cta\">` and won on source order,\n // turning a filled CTA's text dark mid-hover. `:where(a:hover, .link:hover)` is\n // a true 0-0-0 and loses to any explicit class, which is what the base rule\n // already promised. It returns a list because an element pattern emits both\n // `:where(el, .cls).role` and `.cls-role`.\n const stateRules = (\n sel: (pseudo: string) => string[],\n role: string | null,\n states: Record<string, Record<string, unknown>>,\n colorProp: 'background-color' | 'color' = 'background-color',\n ) => {\n let out = '';\n for (const [state, spec] of Object.entries(states)) {\n const body: string[] = [];\n // `step` intensifies the pattern's colour: fills swap solid → solid-bold;\n // text swaps the bold emphasis stop → x-bold.\n if (typeof spec.step === 'number' && role) {\n const stateVar =\n colorProp === 'background-color'\n ? `var(--color-bg-${role}-${spec.step >= 1 ? 'solid-bold' : 'solid'})`\n : spec.step >= 1\n ? `var(--color-text-${role}-bold)`\n : `var(--color-text-${role})`;\n body.push(`${colorProp}: ${stateVar};`);\n }\n if (typeof spec.scale === 'number') body.push(`scale: ${spec.scale};`);\n if (typeof spec.lift === 'string') body.push(`translate: 0 calc(-1 * ${spec.lift});`);\n if (typeof spec.shadow === 'string' && shadows?.[spec.shadow])\n body.push(`filter: drop-shadow(var(--shadow-${spec.shadow}));`);\n else if (spec.shadow === true)\n body.push(`box-shadow: var(--lift-shadow, 0 8px 20px -6px rgb(0 0 0 / 0.25));`);\n if (spec.ring === true) {\n // A focus ring has to be *seen*, so it uses the solid tone rather than a\n // decorative border tint. `--color-border-focus` is the role-less\n // default, emitted once from ui-primary and contrast-checked as a\n // non-text boundary.\n const ringColor = role ? `var(--color-bg-${role}-solid)` : `var(--color-border-focus)`;\n body.push(`outline: none;`, `box-shadow: 0 0 0 3px ${ringColor};`);\n }\n if (spec.css && typeof spec.css === 'object')\n for (const [k, v] of Object.entries(spec.css as Record<string, string>))\n body.push(`${k}: ${v};`);\n if (!body.length) continue;\n const pseudo =\n state === 'hover'\n ? ':hover'\n : state === 'active'\n ? ':active'\n : state === 'focus-visible'\n ? ':focus-visible'\n : `:${state}`;\n const rule = `${sel(pseudo).join(',\\n')} {\\n ${body.join('\\n ')}\\n}\\n`;\n out += state === 'hover' ? `@media (hover: hover) {\\n${rule}}\\n` : rule;\n }\n return out;\n };\n\n let pat = `/* GENERATED component patterns — do not edit by hand. */\\n`;\n pat += `/* Interaction transitions for patterned elements (independent props compose). */\\n`;\n for (const [pname, p] of Object.entries((patterns?.items ?? {}) as Record<string, Pattern>)) {\n if (!p.base) continue;\n const states = p.states ?? {};\n // `class` defaults to the pattern key only for class-only patterns, so an\n // `element`-only entry never sprouts a surprise class.\n const cls = p.class ?? (p.element ? undefined : pname);\n // Element patterns style at zero specificity (`:where(…)`) so any explicit\n // class — a louder pattern, or a component's own BEM rule — wins without\n // !important. Class-only patterns stay unwrapped at 0-1-0, or they'd lose to\n // every utility. With both, the element and the class share one rule, which\n // is what lets `.btn` / `.link` be applied to any tag.\n //\n // `pseudo` goes inside the `:where()` so a state rule keeps that promise —\n // see the note on `stateRules`. `extra` (a role class) stays outside it,\n // since the variant is meant to carry a class's weight.\n const elementSel = (extra = '', pseudo = '') =>\n `:where(${[p.element, cls && `.${cls}`]\n .filter(Boolean)\n .map((s) => `${s}${pseudo}`)\n .join(', ')})${extra}`;\n const defaultSel = p.element ? elementSel() : `.${cls}`;\n const defaultSelFor = (pseudo: string) =>\n p.element ? [elementSel('', pseudo)] : [`.${cls}${pseudo}`];\n const defaultRole = p.default_role ?? null;\n const base = { ...p.base };\n // Explicit `fill` wins; otherwise infer, keeping the historical name-based\n // special cases so existing consumer configs don't shift behaviour.\n const fills =\n p.fill ??\n (pname === 'button' ||\n pname === 'badge' ||\n base['background-color'] != null ||\n base['background'] != null);\n const colorProp: 'background-color' | 'color' = fills ? 'background-color' : 'color';\n pat += `${defaultSel} {\\n`;\n const hasStates = Object.keys(states).length > 0;\n if (hasStates) {\n pat += ` transition-property: translate, scale, rotate, filter, box-shadow, background-color, color;\\n`;\n pat += ` transition-duration: var(--interact-duration, 200ms);\\n`;\n pat += ` transition-timing-function: var(--interact-easing, ease);\\n`;\n pat += ` translate: 0 0; scale: 1; rotate: 0deg;\\n`;\n }\n if (defaultRole && fills && base['background-color'] == null && base['background'] == null)\n base['background-color'] = `var(--color-bg-${defaultRole}-solid)`;\n const wrappedBase: Record<string, string> = {};\n for (const [prop, val] of Object.entries(base)) {\n const sfx = BASE_HOOK[prop];\n wrappedBase[prop] = sfx ? `var(--${sfx}-${pname}, ${val})` : String(val);\n }\n pat += decls(wrappedBase) + '\\n}\\n';\n pat += stateRules(defaultSelFor, defaultRole, states, colorProp);\n for (const role of p.roles ?? []) {\n // Element patterns take the role as a bare class (`<button class=\"danger\">`)\n // AND as the `<pattern>-<role>` form that class patterns use, so the same\n // variant reaches a non-element host (`<a class=\"btn btn-danger\">`). Both\n // land at 0-1-0 — the element half stays inside :where() so a role variant\n // can't outrank a plain class the way `button.danger` (0-1-1) used to.\n const variantSelsFor = (pseudo: string) =>\n p.element\n ? [elementSel(`.${role}`, pseudo), ...(cls ? [`.${cls}-${role}${pseudo}`] : [])]\n : [`.${cls}-${role}${pseudo}`];\n const variantSels = variantSelsFor('');\n // Fills sit on the role's solid and pair with the foreground computed\n // against it; text variants use the role's text token, which is the one\n // guaranteed legible over a surface in both appearances.\n const variantColorDecl = fills\n ? `background-color: var(--color-bg-${role}-solid); color: var(--color-text-on-${role})`\n : `color: var(--color-text-${role})`;\n pat += `${variantSels.join(',\\n')} { ${variantColorDecl}; }\\n`;\n pat += stateRules(variantSelsFor, role, states, colorProp);\n }\n pat += '\\n';\n }\n generated['patterns.css'] = pat;\n\n // ── animation-effects.css ────────────────────────────────────────────────────\n {\n const anim = ds.animations ?? {};\n const asStr = (v: string | number) => String(v);\n const block = (sel: string, d: Record<string, string>) => `.${sel} {\\n${decls(d)}\\n}\\n`;\n let out = `/* GENERATED animation effects + journeys — do not edit by hand. */\\n`;\n for (const [name, e] of Object.entries(anim.effects ?? {})) {\n const d: Record<string, string> = { '--_anim': e.kf };\n for (const [k, v] of Object.entries(e.css ?? {})) d[k] = asStr(v);\n for (const [k, v] of Object.entries(e.vars ?? {})) d[`--${k}`] = asStr(v);\n out += block(name, d);\n }\n const base = anim.journeys?.base ?? {};\n for (const parts of anim.journeys?.compose ?? []) {\n const d: Record<string, string> = {\n '--_anim': parts.map((p) => `${p}-journey`).join(', '),\n // A journey is entry → hold → exit (keyframes at 0%/100% hidden,\n // 25%–75% held), so it needs the long range that a one-shot entrance\n // doesn't. It starts on the same pivot as `.animate-view` — the\n // element's midpoint 15% into the viewport, which is `entry 50%` plus\n // 10vh (see the note on .animate-view in core's animation.css) — and\n // runs to the end of the exit phase, so the hold occupies the middle of\n // the crossing rather than the bottom edge of the screen.\n //\n // The END is spelled `exit 100%` rather than the equivalent bare `exit`,\n // because lightningcss misparses the shorthand: an omitted offset on the\n // END defaults to 0% there instead of the spec's 100%, so `entry exit`\n // bundled as `entry exit 0%` and every journey snapped back to its hidden\n // `from` state as the element reached the top of the viewport. Guarded by\n // animation-effects.test.ts, which asserts on the BUNDLED css.\n 'animation-range': 'entry calc(50% + 10vh) exit 100%',\n };\n for (const p of parts)\n for (const [k, v] of Object.entries(base[p] ?? {})) d[`--${k}`] = asStr(v);\n out += block(`${parts.join('-')}-journey`, d);\n }\n // Each state matches the element itself OR its direct parent, mirroring the\n // precedent animation.css already sets for the trigger driver\n // (`:is(.is-active, [data-active]) > .animate-trigger`). The parent form is\n // load-bearing, not a convenience: a `hover-reveal-*` element rests at\n // `clip-path: inset(0 100% 0 0)`, and clip-path clips HIT-TESTING as well as\n // painting — so with `:hover` alone the element has zero hittable area and\n // can never receive the hover that would reveal it. Same specificity (0,2,0)\n // as the self form, so nothing reorders.\n const STATES: [string, (s: string) => string][] = [\n ['hover', (s) => `.${s}:hover, :hover > .${s}`],\n ['focus', (s) => `.${s}:focus-visible, :focus-within > .${s}`],\n ['active', (s) => `.${s}.is-active, .${s}[data-active]`],\n // The top layer's own state. A popover/dialog rests CLOSED at the effect's\n // `from` values and flips to `to` when it opens — the same shape as hover,\n // so it costs one row here rather than a bespoke driver, and every effect\n // gains `open-<fx>` in all three formats for free. `:popover-open` covers\n // the Popover API; `[open]` covers `<dialog open>` (and `<details open>`,\n // which is a legitimate use of the same flip).\n //\n // The MECHANISM a top-layer element additionally needs — `display`/`overlay`\n // in transition-property with `allow-discrete`, plus the `@starting-style`\n // that makes the entry run at all — is not per-effect, so it lives once in\n // animation.css rather than being multiplied across every effect here.\n ['open', (s) => `.${s}:popover-open, .${s}[open]`],\n ];\n out += `\\n/* State-flip variants — compose with .transition (hover-/focus-/active-<fx>). */\\n`;\n // Every keyframe family gets state variants, `layout` included: `.transition`\n // covers `height` inside `@supports (interpolate-size: allow-keywords)`, and\n // the `layout` keyframe depends on exactly the same feature — so excluding\n // layout here bought no portability, it only made `hover-size-grow` a class\n // that resolved to nothing while the docs advertised it.\n for (const [name, e] of Object.entries(anim.effects ?? {})) {\n const props: Record<string, { from?: string; to?: string }> = {};\n for (const [k, v] of Object.entries(e.vars ?? {})) {\n const m = /^(.*)-(from|to)$/.exec(k);\n if (m) (props[m[1] as string] ??= {})[m[2] as 'from' | 'to'] = asStr(v);\n }\n // The effect's own `css` block travels with the variant too — `size-grow`\n // declares `overflow: clip`, without which a collapsed (0-height) box\n // spills its content instead of hiding it.\n const rest: Record<string, string> = {};\n for (const [k, v] of Object.entries(e.css ?? {})) rest[k] = asStr(v);\n for (const [p, ft] of Object.entries(props)) {\n if (ft.from != null && ft.from !== STATE_DEFAULT[p]) rest[`--${p}-from`] = ft.from;\n if (ft.to != null && ft.to !== STATE_DEFAULT[p]) rest[`--${p}-to`] = ft.to;\n }\n const flip: Record<string, string> = Object.fromEntries(\n Object.keys(props).map((p) => [`--t-${p}`, `var(--${p}-to, ${STATE_DEFAULT[p]})`]),\n );\n if (Object.keys(rest).length)\n out += `${STATES.map(([s]) => `.${s}-${name}`).join(', ')} {\\n${decls(rest)}\\n}\\n`;\n for (const [s, sel] of STATES) out += `${sel(`${s}-${name}`)} {\\n${decls(flip)}\\n}\\n`;\n }\n generated['animation-effects.css'] = out;\n }\n\n // ── Bricks palettes ──────────────────────────────────────────────────────────\n // Named = the hue scales (numeric steps); Semantic = the functional role\n // tokens with their automatic light/dark pairing.\n const namedColors: unknown[] = [];\n for (const [name, hue] of Object.entries(expandedPalette))\n for (const [n, hex] of Object.entries(hue.numeric)) {\n const token = `${name}-${n}`;\n namedColors.push({\n raw: `var(--color-${token})`,\n light: hex,\n id: id(`named:${token}`),\n utilityClasses: UTILITIES,\n });\n }\n const semanticColors: unknown[] = [];\n for (const fr of scaleRoles)\n for (const [t, light] of Object.entries(fr.light)) {\n const dark = fr.dark[t] as string;\n semanticColors.push({\n raw: `var(${tokenVar(fr.role, t)})`,\n light,\n darkModeEnabled: light !== dark,\n dark,\n id: id(`semantic:${fr.role}-${t}`),\n utilityClasses: UTILITIES,\n });\n }\n const bricksColorsNamed = JSON.stringify(\n { id: id('palette:named'), name: 'Named', colors: namedColors },\n null,\n 2,\n );\n const bricksColorsSemantic = JSON.stringify(\n { id: id('palette:semantic'), name: 'Semantic', colors: semanticColors },\n null,\n 2,\n );\n\n // ── Bricks Global Variables (fonts + scales) ─────────────────────────────────\n const bricksVariables = (() => {\n type BrxScale = { scale: number; scaleName: string };\n type BrxVar = { id: string; name: string; value: string; category?: string; scale?: BrxScale };\n type BrxCat = { id: string; name: string; scale: Record<string, unknown>; utilityClasses: [] };\n const scaleMeta = (scope: string, prefix: string, s: ScaleConfig, names: string[]) => {\n const px = Math.round(rem(s.base) * 16);\n const lo = s.fluid?.minRatio ?? s.ratio;\n return {\n scaleScope: scope,\n scaleType: 'tshirt',\n scaleNames: names,\n prefix,\n minFontSize: px,\n minScaleRatio: lo,\n minScaleRatioSelect: lo,\n maxFontSize: px,\n maxScaleRatio: s.ratio,\n maxScaleRatioSelect: s.ratio,\n baseline: s.baseline ?? names[Math.floor((names.length - 1) / 2)],\n };\n };\n const categories: BrxCat[] = [];\n const variables: BrxVar[] = [];\n const addScale = (\n label: string,\n scope: string,\n prefix: string,\n cfg: ScaleConfig | undefined,\n steps: ScaleStep[],\n ) => {\n if (!cfg || !steps.length) return;\n const names = steps.map((s) => s.name);\n const catId = id(`varcat:${scope}`);\n categories.push({\n id: catId,\n name: label,\n scale: scaleMeta(scope, prefix, cfg, names),\n utilityClasses: [],\n });\n for (const st of steps)\n variables.push({\n id: id(`var:${prefix}${st.name}`),\n name: `${prefix}${st.name}`,\n value: st.value,\n category: catId,\n scale: { scale: st.offset, scaleName: st.name },\n });\n };\n addScale('Typography', 'typography', 'text-', ds.typeScale as ScaleConfig, typeSteps);\n addScale('Spacing', 'spacing', 'space-', ds.spaceScale as ScaleConfig, spaceSteps);\n for (const [name, stack] of Object.entries(ds.fonts ?? {}))\n variables.push({ id: id(`var:font-${name}`), name: `font-${name}`, value: stack });\n for (const [name, val] of Object.entries(ds.patterns?.radii ?? {}))\n variables.push({ id: id(`var:br-${name}`), name: `br-${name}`, value: val });\n return JSON.stringify({ variables, categories }, null, 2);\n })();\n\n // ── tokens.json (trimmed token export for programmatic consumers) ────────────\n const numericPalette = Object.fromEntries(\n Object.entries(expandedPalette).map(([k, v]) => [k, v.numeric]),\n );\n const tokensJson = JSON.stringify(\n {\n colors: {\n palette: numericPalette,\n roles: roleMap,\n functional: Object.fromEntries(\n scaleRoles.map((fr) => [fr.role, { light: fr.light, dark: fr.dark }]),\n ),\n },\n fonts: ds.fonts ?? {},\n text: Object.fromEntries(typeSteps.map((s) => [s.name, s.value])),\n spacing: Object.fromEntries(spaceSteps.map((s) => [s.name, s.value])),\n shadows: shadows ?? {},\n radii: ds.patterns?.radii ?? {},\n },\n null,\n 2,\n );\n\n // ── design-manifest.json (live-editor manifest; css format) ──────────────────\n const designManifest = (() => {\n const reverseIndex: Record<string, string> = {};\n // A numeric step maps back to that step's `anchors` entry, NOT to the hue's\n // `seed`: the seed regenerates the whole ramp (and every step would collapse\n // to one path, so editing two steps of a hue would silently keep only one),\n // whereas `anchors.<step>` is precisely the per-step override (see schema.ts).\n for (const [name, hue] of Object.entries(expandedPalette))\n for (const n of Object.keys(hue.numeric))\n reverseIndex[`--color-${name}-${n}`] = `colors.palette.${name}.anchors.${n}`;\n // `kind` travels with the role so the editor picks the right `roleTokens`\n // variant on a remap — it used to infer that from `role === 'surface'`, which\n // silently did the wrong thing for any other surface-kind role.\n const colorRoles = Object.entries(roleMap).map(([name, spec]) => ({\n name,\n ramp: roleHue(spec),\n kind: roleKind(spec),\n }));\n // Per-hue token sets, so a client (the live editor) can re-point a role at\n // another hue. It can't derive these itself: `text-on` is a computed contrast\n // literal, not a var() ref. One variant per role KIND, because the two kinds\n // emit different token sets — a chromatic role has no bare `bg`, a surface\n // role has no solid tints.\n //\n // Keys are token keys (`bg`, `text-on`, `border-bold`, …) — the same ones\n // `tokenVar()` turns into `--color-<target>-<role>[-<variant>]`.\n const roleTokens = Object.fromEntries(\n Object.entries(expandedPalette).map(([hueName, hue]) => {\n const chromatic = functionalRole('_', hueName, hue, 'chromatic');\n const surface = functionalRole('_', hueName, hue, 'surface');\n return [\n hueName,\n {\n chromatic: { light: chromatic.light, dark: chromatic.dark },\n surface: { light: surface.light, dark: surface.dark },\n },\n ];\n }),\n );\n const typoRoles = (typography?.roles ?? {}) as Record<string, TypographyRole>;\n const hooks: Record<string, { prop: string; key: string }> = {};\n for (const [key, [prop, sfx]] of Object.entries(TYPO_KEYMAP)) hooks[sfx] = { prop, key };\n // Index EVERY hook for every role, not just the ones the role already\n // declares. The editor builds its control set from `typography.hooks` (all\n // of TYPO_KEYMAP), so a role that omits `tracking` still gets a `--<role>-ls`\n // control; without an entry here that edit previews live and is then dropped\n // as \"skipped\" on save. The path is a valid place to write whether or not it\n // exists yet — `roles` is an open record and the patch deep-merges.\n for (const role of Object.keys(typoRoles))\n for (const [key, [, sfx]] of Object.entries(TYPO_KEYMAP))\n reverseIndex[`--${role}-${sfx}`] = `typography.roles.${role}.${key}`;\n const pDefaults = patterns?.defaults ?? {};\n const pRadii = patterns?.radii ?? {};\n const pGroups = patterns?.groups ?? {};\n const pItems = (patterns?.items ?? {}) as Record<string, Pattern>;\n for (const prop of Object.keys(pDefaults))\n reverseIndex[`--${prop}-default`] = `patterns.defaults.${prop}`;\n for (const [group, props] of Object.entries(pGroups))\n for (const prop of Object.keys(props))\n reverseIndex[`--${prop}-${group}`] = `patterns.groups.${group}.${prop}`;\n const items = Object.entries(pItems).map(([name, p]) => {\n const base = p.base ?? {};\n const wrappable = Object.keys(base)\n .filter((prop) => prop in BASE_HOOK)\n .map((prop) => ({ sfx: BASE_HOOK[prop] as string, prop }));\n for (const { sfx, prop } of wrappable)\n reverseIndex[`--${sfx}-${name}`] = `patterns.items.${name}.base.${prop}`;\n return { name, group: p.group ?? null, base, wrappable, roles: p.roles ?? [] };\n });\n // Radii last, and only where a pattern hasn't already claimed the var: a\n // `patterns.radii` key that equals a pattern name collides on `--br-<name>`\n // (e.g. radii `card` vs the `card` pattern — a live collision in the example\n // config). The pattern's BASE_HOOK is the documented override, so it wins,\n // and `validate()` surfaces the collision as a warning so it isn't silent.\n for (const name of Object.keys(pRadii))\n if (!(`--br-${name}` in reverseIndex))\n reverseIndex[`--br-${name}`] = `patterns.radii.${name}`;\n return JSON.stringify(\n {\n colors: {\n ramps: Object.keys(expandedPalette),\n steps: NUMERIC_STEPS,\n palette: numericPalette,\n roles: colorRoles,\n roleTokens,\n },\n typography: {\n roles: Object.keys(typoRoles),\n hooks,\n families: typographyFamilies,\n specs: typoRoles,\n },\n scales: {\n text: typeSteps.map((s) => ({ name: s.name, value: s.value, max: s.max })),\n space: spaceSteps.map((s) => ({ name: s.name, value: s.value, max: s.max })),\n },\n fonts: ds.fonts ?? {},\n patterns: { defaults: pDefaults, radii: pRadii, groups: pGroups, items },\n shadows: shadows ?? {},\n reverseIndex,\n },\n null,\n 2,\n );\n })();\n\n // ── Tailwind bundle ──────────────────────────────────────────────────────────\n // Only the tailwind format consumes this (see `generate`), and assembling it\n // reads every framework partial off disk — so skip the work for css/bricks.\n const tailwind =\n format !== 'tailwind'\n ? ''\n : emitTailwind({\n ds,\n expandedPalette,\n scaleRoles,\n shadows,\n typeSteps,\n spaceSteps,\n typography,\n roleDecls,\n twTypeTokensCss,\n twPatternTokensCss,\n patternsCss: pat,\n assetsDir,\n utilities: UTILITIES,\n systemColorScheme: buildOpts.systemColorScheme === true,\n });\n\n // ── DESIGN.md ────────────────────────────────────────────────────────────────\n // Same deal as the tailwind bundle: only its own format consumes it, so the\n // other three don't pay for building it.\n const designMd =\n format !== 'design'\n ? ''\n : emitDesignMd({ ds, expandedPalette, scaleRoles, typeSteps, spaceSteps, shadows });\n\n return {\n generated,\n bricksColorsNamed,\n bricksColorsSemantic,\n bricksVariables,\n tokensJson,\n designManifest,\n tailwind,\n designMd,\n twTypeTokensCss,\n twPatternTokensCss,\n patternsCss: pat,\n };\n}\n\n// ── Tailwind emitter ──────────────────────────────────────────────────────────\ninterface TwCtx {\n ds: DesignSystem;\n expandedPalette: Record<string, ExpandedHue>;\n scaleRoles: FunctionalRole[];\n shadows: Record<string, string> | undefined;\n typeSteps: ScaleStep[];\n spaceSteps: ScaleStep[];\n typography: DesignSystem['typography'];\n roleDecls: (role: string, spec: TypographyRole) => Record<string, string>;\n twTypeTokensCss: string;\n twPatternTokensCss: string;\n patternsCss: string;\n assetsDir: string;\n /**\n * The configured `colors.utilities`. Was previously hardcoded to\n * bg/text/border at the emit site, so a consumer who enabled `outline`/\n * `fill`/`stroke` got them in css/bricks but not tailwind.\n */\n utilities: string[];\n /** `BuildOptions.systemColorScheme` — see the OS-preference block below. */\n systemColorScheme: boolean;\n}\n\nfunction emitTailwind(ctx: TwCtx): string {\n const {\n ds,\n expandedPalette,\n scaleRoles,\n shadows,\n typeSteps,\n spaceSteps,\n typography,\n roleDecls,\n twTypeTokensCss,\n twPatternTokensCss,\n patternsCss,\n assetsDir,\n utilities,\n } = ctx;\n const cssDir = join(assetsDir, 'css');\n const nl = (arr: string[]) => arr.filter(Boolean).join('\\n');\n const parts: string[] = [\n `/* GENERATED for Tailwind v4 (Astro) — do not edit by hand.\\n` +\n ` Class reference: npx vitops docs classes · All topics: npx vitops docs\\n` +\n ` Fonts below are STACKS ONLY — this file loads no webfonts. Load them with\\n` +\n ` Astro's fonts: config and point the token at the family's cssVariable. */`,\n ];\n parts.push(`@import \"tailwindcss\";\\n`);\n\n const theme: string[] = [];\n theme.push(` /* Hue scales → bg-<hue>-<step> text-* border-* (numeric, 50…950) */`);\n for (const [name, hue] of Object.entries(expandedPalette))\n for (const [n, hex] of Object.entries(hue.numeric))\n theme.push(` --color-${name}-${n}: ${hex};`);\n theme.push(`\\n /* Fonts → font-* (stacks only; no @font-face is emitted — see header) */`);\n for (const [name, stack] of Object.entries(ds.fonts ?? {}))\n theme.push(` --font-${name}: ${stack};`);\n theme.push(`\\n /* Fluid type scale → text-* */`);\n for (const s of typeSteps) theme.push(` --text-${s.name}: ${s.value};`);\n // Fluid space steps are NOT put in Tailwind's --spacing-* namespace: named\n // spacing keys shadow the size scales (e.g. `max-w-7xl` would resolve to\n // var(--spacing-7xl) ≈ 6rem and collapse layouts). They ship as --space-*\n // (matching the css format) in a plain :root below; use var(--space-<name>)\n // or the TW4 arbitrary form p-(--space-md). Numeric spacing (p-4 …) keeps\n // Tailwind's default --spacing multiplier.\n theme.push(`\\n /* Drop-shadows → shadow-* */`);\n for (const [name, value] of Object.entries(shadows ?? {}))\n theme.push(` --shadow-${name}: ${value};`);\n theme.push(`\\n /* Container breakpoints → @sm:/@md:/@lg:/@xl: */`);\n for (const [name, val] of BREAKPOINTS) theme.push(` --container-${name}: ${val};`);\n parts.push(`@theme {\\n${theme.join('\\n')}\\n}\\n`);\n\n if (spaceSteps.length)\n parts.push(\n `/* Fluid space scale — var(--space-<name>) or p-(--space-<name>) */\\n:root {\\n` +\n spaceSteps.map((s) => ` --space-${s.name}: ${s.value};`).join('\\n') +\n `\\n}\\n`,\n );\n\n // Role tokens go in a plain :root block, NOT @theme — including the emphasis\n // stops, despite those living in the --color-* namespace. The @utility set\n // below is the public API.\n //\n // This is load-bearing, not stylistic. Measured against tailwindcss@4.3.3:\n // when a token is in @theme AND an @utility of the derived name exists,\n // Tailwind merges both into one rule with the @theme declaration LAST, and it\n // does so regardless of source order. Putting `--color-<role>-<stop>` in\n // @theme would therefore silently substitute the stop for the plane on the\n // five colliding classes — including `text-<role>-muted` (step 800 → 300) and\n // `text-<role>-x-muted` (600 → 100), i.e. exactly the tokens tokens.ts's APCA\n // test guarantees are readable. Raw hue scales are safe in @theme because no\n // @utility competes for those names.\n if (scaleRoles.length) {\n let fn = '';\n for (const fr of scaleRoles)\n for (const [t, val] of Object.entries(fr.light)) fn += ` ${tokenVar(fr.role, t)}: ${val};\\n`;\n const focus = scaleRoles.find((r) => r.role === 'ui-primary') ?? scaleRoles[0];\n if (focus) fn += ` --color-border-focus: ${focus.light['bg-solid']};\\n`;\n const surface = scaleRoles.find((r) => r.role === 'surface');\n if (surface) {\n fn += ` --surface-glass: color-mix(in oklch, var(--color-bg-surface) 72%, transparent);\\n`;\n fn += ` --overlay: color-mix(in oklch, var(--color-${surface.hue}-950) 45%, transparent);\\n`;\n }\n parts.push(`/* Role tokens (the public API) */\\n:root {\\n${fn}}\\n`);\n }\n\n parts.push(\n `/* ── Framework tokens (consumed by the inlined components) ── */\\n` +\n `${twTypeTokensCss}\\n${twPatternTokensCss}`,\n );\n\n // Dark appearance: the automatic functional flip (solid stays mode-stable).\n let darkBlock = '';\n for (const fr of scaleRoles)\n for (const [t, val] of Object.entries(fr.dark))\n if (fr.light[t] !== val) darkBlock += ` ${tokenVar(fr.role, t)}: ${val};\\n`;\n {\n const surface = scaleRoles.find((r) => r.role === 'surface');\n if (surface)\n darkBlock += ` --overlay: color-mix(in oklch, var(--color-${surface.hue}-950) 60%, transparent);\\n`;\n }\n if (darkBlock) {\n parts.push(\n `/* Functional role tokens (dark) */\\n${DARK_SEL} {\\n color-scheme: dark;\\n${darkBlock}}\\n`,\n );\n // Same opt-in OS-preference block as the css/bricks path — see the comment\n // there. Emitted unlayered here for the same reason the rest of this format\n // is: Tailwind owns the layering, and role tokens must stay out of `@theme`.\n if (ctx.systemColorScheme)\n parts.push(\n `/* Functional role tokens (dark) — OS preference, no explicit choice */\\n` +\n `@media (prefers-color-scheme: dark) {\\n ${SYSTEM_DARK_SEL} {\\n` +\n ` color-scheme: dark;\\n${darkBlock.replace(/^ {2}/gm, ' ')} }\\n}\\n`,\n );\n }\n\n parts.push(\n `/* State variant for the active flip (hover/focus-visible are built in). */\\n` +\n `@custom-variant is-active (&.is-active, &[data-active]);\\n`,\n );\n\n // `typography.headings` — the bare-element → role bindings, the same rules the\n // css/bricks path emits into typography.css. This format used to emit only the\n // `@utility font-<role>` half, so a Tailwind consumer's <h1> and <body> got no\n // role styling at all: no family, no size, no text-wrap.\n //\n // Tailwind's `base` layer, deliberately. It puts these behind BOTH `@utility\n // font-<role>` (utilities layer) and the patterns (components layer), matching\n // css/bricks — where typography.css sits in vitops.utilities and the bare tag\n // selector loses to `.font-<role>` on specificity rather than on layer. Emitted\n // unlayered, an `h1` rule here would beat every Tailwind utility.\n {\n const roles = (typography?.roles ?? {}) as Record<string, TypographyRole>;\n const bindings = Object.entries(typography?.headings ?? {}).filter(([, r]) => roles[r]);\n if (bindings.length)\n parts.push(\n `/* Bare-element type roles (typography.headings) */\\n@layer base {\\n` +\n bindings\n .map(\n ([tag, role]) =>\n ` ${tag} {\\n${decls(roleDecls(role, roles[role] as TypographyRole), ' ')}\\n }`,\n )\n .join('\\n') +\n `\\n}\\n`,\n );\n }\n\n const util: string[] = [];\n if (scaleRoles.length) {\n util.push(`/* Role colour utilities (the public API) */`);\n // Same source as the css/bricks formats — the two used to diverge because\n // this path re-parsed the other's generated strings and only ever ran the\n // functional half. See roleColorUtilities().\n for (const { cls, prop, value } of roleColorUtilities(scaleRoles, utilities))\n util.push(`@utility ${cls} {\\n ${prop}: ${value};\\n}`);\n if (scaleRoles.some((r) => r.role === 'surface'))\n util.push(\n `@utility glass {\\n background-color: var(--surface-glass);\\n backdrop-filter: blur(12px);\\n -webkit-backdrop-filter: blur(12px);\\n}`,\n );\n }\n util.push(`/* Typography roles */`);\n for (const [role, spec] of Object.entries(\n (typography?.roles ?? {}) as Record<string, TypographyRole>,\n ))\n util.push(`@utility font-${role} {\\n${decls(roleDecls(role, spec))}\\n}`);\n util.push(`\\n/* Animation effects (pair with .transition or a driver) */`);\n const asStr = (v: string | number) => String(v);\n for (const [name, e] of Object.entries(ds.animations?.effects ?? {})) {\n const d: Record<string, string> = { '--_anim': e.kf };\n for (const [k, v] of Object.entries(e.css ?? {})) d[k] = asStr(v);\n for (const [k, v] of Object.entries(e.vars ?? {})) d[`--${k}`] = asStr(v);\n util.push(`@utility ${name} {\\n${decls(d)}\\n}`);\n // No `kf` filter — see the css path. `flip-size-grow` is as real as\n // `flip-fade-in`; both rest on `.transition`, which covers height behind\n // `@supports (interpolate-size: allow-keywords)`.\n const props = new Set<string>();\n for (const k of Object.keys(e.vars ?? {})) {\n const m = /^(.*)-(from|to)$/.exec(k);\n if (m) props.add(m[1] as string);\n }\n const flip = Object.fromEntries(\n [...props].map((p) => [`--t-${p}`, `var(--${p}-to, ${STATE_DEFAULT[p]})`]),\n );\n util.push(`@utility flip-${name} {\\n${decls(flip)}\\n}`);\n }\n util.push(`\\n/* Split — internal fractions (pair split with a ratio) */`);\n // The `.split` PATTERN itself is not here — it is emitted into `@layer\n // components` with the rest of the structure, so `flex-col` beats it by layer\n // exactly as it does in css/bricks. Only its modifiers are utilities.\n //\n // That placement costs `@md:split`, and nothing recovers it. Measured against\n // tailwindcss@4.3.3: `@utility` throws \"`@utility` cannot be nested\" inside\n // `@layer`, AND inside a file pulled in with `@import … layer(…)` — the layer\n // clause is itself a nesting context. A `@custom-variant` doesn't help either:\n // a variant applied to a components-layer class emits nothing, because variants\n // attach to utility candidates only. `md-flex-row` says \"become a row at md\" in\n // every format, so the loss is a bare `<bp>-split` that had no unique job.\n //\n // `order`, not `row-reverse`, so the swap applies on whichever axis the split\n // is currently on — which is the point: it decides which panel comes FIRST,\n // and that is mostly a question about the stacked state. `reading-flow` keeps\n // focus order with the visual order where supported; until that is broad,\n // only one of the two panels should hold focusable content (WCAG 2.4.3).\n util.push(\n `@utility split-reverse {\\n reading-flow: flex-visual;\\n & > :first-child { order: 1; }\\n}`,\n );\n const RATIOS: [number, number][] = [\n [1, 2],\n [2, 1],\n [1, 3],\n [3, 1],\n [1, 4],\n [4, 1],\n [2, 3],\n [3, 2],\n ];\n for (const [a, b] of RATIOS)\n util.push(\n `@utility split-${a}-${b} {\\n flex-direction: row;\\n --_split-a: ${a};\\n --_split-b: ${b};\\n}`,\n );\n // Not derivable from `@theme`: the fluid space steps are deliberately kept out\n // of Tailwind's `--spacing-*` namespace (see the note above the `:root` block),\n // so `gap-md` has to be an explicit utility here. Verified against\n // tailwindcss@4.3.3 to win over the built-in functional `gap-*` and to accept\n // variants (`@md:gap-md`), which is why no per-breakpoint classes are emitted.\n const gaps = gapUtilities(spaceSteps);\n if (gaps.length) {\n util.push(`\\n/* Gap — the fluid space scale (var(--space-<name>)) */`);\n for (const { cls, prop, value } of gaps)\n util.push(`@utility ${cls} {\\n ${prop}: ${value};\\n}`);\n }\n util.push(`\\n/* Track placement (inside .centered) */`);\n for (const track of ['measure', 'breakout', 'spotlight', 'fullbleed'])\n util.push(`@utility ${track} {\\n grid-column: ${track};\\n}`);\n\n // `layout.css` is skipped wholesale in this format and a subset re-emitted\n // above, which left these two families missing from tailwind ENTIRELY — not\n // dropped via TW_CLASH, just never re-emitted. Unlike the `<bp>-` classes they\n // have no Tailwind equivalent to fall back on, and unlike a misspelt class\n // `vitops lint` cannot flag them, because they are not anchored to the\n // consumer's config. A consumer who used them got silence and no styling.\n util.push(`\\n/* Auto-fit grid — column count is content-driven, unlike .split */`);\n util.push(\n `@utility grid-auto {\\n display: grid;\\n gap: var(--grid-gap, 1rem);\\n` +\n ` grid-template-columns: repeat(auto-fit, minmax(var(--grid-min, 13rem), 1fr));\\n` +\n // Was missing here while layout.css carried it, so in THIS format a\n // `<ul class=\"grid-auto\">` inside `.rhythm` kept the `li + li` margin: the\n // grid stretched the row to the tallest and the first cell alone looked\n // vertically offset — the exact symptom layout.css warns about.\n ` &:is(ul, ol) > li + li { margin-block-start: 0; }\\n}`,\n );\n // Applied to the SECOND element of a pair, to override the rhythm it inherited.\n util.push(`\\n/* Vertical-rhythm overrides (mirrors layout.css) */`);\n for (const pair of [\n 'h-p',\n 'p-p',\n 'p-h',\n 'h-h',\n 'p-list',\n 'list-p',\n 'li-li',\n 'text-media',\n 'media-text',\n ])\n util.push(\n `@utility m-${pair} {\\n margin-top: calc(var(--rhythm-base) * var(--rhythm-${pair}));\\n}`,\n );\n for (const [name, mult] of [\n ['0', null],\n ['xs', '0.25'],\n ['s', '0.5'],\n ['m', '1'],\n ['l', '1.5'],\n ['xl', '2'],\n ] as const)\n util.push(\n `@utility m-${name} {\\n margin-top: ${mult == null ? '0' : `calc(var(--rhythm-base) * ${mult})`};\\n}`,\n );\n parts.push(util.join('\\n') + '\\n');\n\n // Structure mirrors layout.css (kept literal for parity with the original emitter).\n parts.push(`/* ── Structure (mirrors src/css/layout.css) ── */\n:root {\n --rhythm-scale: 1;\n --rhythm-base: calc(1rlh * var(--rhythm-scale));\n --rhythm-h-p: 0.4;\n --rhythm-p-p: 0.9;\n --rhythm-p-h: 1.6;\n --rhythm-h-h: 0.6;\n --rhythm-p-list: 0.5;\n --rhythm-list-p: 0.9;\n --rhythm-li-li: 0.3;\n --rhythm-text-media: 1.2;\n --rhythm-media-text: 1.2;\n --width-measure: 65ch;\n --width-breakout: 90ch;\n --width-spotlight: 120ch;\n --gutter: clamp(1rem, 4cqi, 3rem);\n}\n\nbody {\n container-type: inline-size;\n /* Named so \\`patterns/scroll-target.css\\`'s \\`@container body (…)\\` queries\n resolve — .toc-layout/.toc-sidebar/.toc-inline. Those partials are inlined\n into this bundle verbatim, so dropping the name (as this literal did) left\n the TOC permanently in its narrow layout in the tailwind format only. */\n container-name: body;\n}\n\n/* Class-level structure rules live in \\`components\\` so track/spacing utilities\n (@layer utilities — later in the layer order) can override them; unlayered\n CSS would beat ALL layered utilities regardless of specificity (e.g.\n \\`.centered > *\\` pinning children to \\`measure\\` over \\`.spotlight\\`). */\n@layer components {\n.rhythm {\n display: flow-root;\n}\n.rhythm > * + * {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-p-p));\n}\n.rhythm > :where(h1, h2, h3, h4, h5, h6) + p {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-h-p));\n}\n.rhythm > p + :where(h1, h2, h3, h4, h5, h6) {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-p-h));\n}\n.rhythm > :where(h1, h2, h3, h4, h5, h6) + :where(h1, h2, h3, h4, h5, h6) {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-h-h));\n}\n.rhythm > p + :where(ul, ol) {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-p-list));\n}\n.rhythm > :where(ul, ol) + p {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-list-p));\n}\n.rhythm :where(ul, ol) > li + li {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-li-li));\n}\n.rhythm > :where(p, h1, h2, h3, h4, h5, h6, ul, ol) + :where(figure, img, picture, video) {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-text-media));\n}\n.rhythm > :where(figure, img, picture, video) + :where(p, h1, h2, h3, h4, h5, h6, ul, ol) {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-media-text));\n}\n\n.centered {\n --_measure: min(var(--width-measure), 100% - var(--gutter) * 2);\n --_breakout: minmax(0, calc((var(--width-breakout) - var(--width-measure)) / 2));\n --_spotlight: minmax(0, calc((var(--width-spotlight) - var(--width-breakout)) / 2));\n position: relative;\n display: grid;\n grid-template-columns:\n [fullbleed-start] minmax(var(--gutter), 1fr)\n [spotlight-start] var(--_spotlight)\n [breakout-start] var(--_breakout)\n [measure-start] var(--_measure) [measure-end]\n var(--_breakout) [breakout-end]\n var(--_spotlight) [spotlight-end]\n minmax(var(--gutter), 1fr) [fullbleed-end];\n}\n.centered > * {\n grid-column: measure;\n}\n\n.region {\n padding-block: clamp(\n var(--region-space-min, 3rem),\n var(--region-space, 8vh),\n var(--region-space-max, 8rem)\n );\n}\n\n/* \\`.split\\` is a PATTERN, so it belongs here rather than in an \\`@utility\\` — that\n is what makes \\`flex-col\\` beat it by layer instead of by a source-order race\n whose winner depends on Tailwind's property-based sort of custom utilities.\n Its ratio/reversal modifiers stay utilities. Mirrors layout.css, where each\n rule's rationale is written out; in short: \\`min-inline-size: 0\\` because a flex\n item's automatic minimum is its min-content size; the ratio as a flex BASIS\n rather than a grow factor, because grow shares out only the free space and a\n child's padding is not part of it; scoped to a two-child split because a ratio\n is a pair contract and a middle child with no basis would collapse to zero;\n \\`box-sizing: border-box\\` because a basis only sizes the border box on a\n border-box item (Tailwind's preflight sets it, the other formats' reset does). */\n.split {\n display: flex;\n flex-direction: row;\n}\n.split > * {\n flex: 1;\n box-sizing: border-box;\n min-inline-size: 0;\n}\n.split > :first-child {\n flex-grow: var(--_split-a, 1);\n}\n.split > :last-child {\n flex-grow: var(--_split-b, 1);\n}\n.split > :first-child:nth-last-child(2) {\n flex-basis: ${splitBasis('--_split-a')};\n}\n.split > :nth-child(2):last-child {\n flex-basis: ${splitBasis('--_split-b')};\n}\n}\n`);\n\n // Same layering rationale as the structure block above. Guarded on existence\n // like componentPartialOrder below: `assets/**` is a gitignored build artifact\n // that `vp test` does not produce, so an unguarded read makes the tailwind\n // format untestable in a clean checkout — which is how an 87-class vocabulary\n // gap between css and tailwind went unnoticed. The token layer still emits.\n const animPath = join(cssDir, 'animation.css');\n const animEngine = existsSync(animPath) ? readFileSync(animPath, 'utf8') : '';\n if (animEngine)\n parts.push(\n `/* ── Animation engine (animation.css) ── */\\n@layer components {\\n${animEngine}\\n}`,\n );\n // Patterns live in Tailwind's `components` layer so single-purpose utilities\n // (@layer utilities — declared later in the layer order) override them, e.g.\n // `.text-on-ui-primary` beating the link pattern's element-level `a { color }`.\n // Unlayered CSS would win over ALL layered utilities regardless of specificity.\n parts.push(`/* ── Component patterns ── */\\n@layer components {\\n${patternsCss}\\n}`);\n\n // Component + structural partials: the full framework library, minus the\n // Tailwind-owned utility layer. Sourced live from the CSS partials (in index.css\n // cascade order) so this never goes stale, then run through stripForTailwind\n // (dropping the TW_CLASH names Tailwind provides itself).\n const droppedClashes = new Set<string>();\n let droppedVariantBlocks = 0;\n /**\n * Is this `@container (min-width: …)` block a PRE-EXPANDED VARIANT block —\n * i.e. only `.sm-*`/`.md-*`/`.lg-*`/`.xl-*` utility classes, which Tailwind\n * regenerates on demand as `@md:`?\n *\n * Anything else in a container query is component *behaviour*, not a variant,\n * and dropping it breaks the component. `sitenav.css` is the case that caught\n * this: its `@container (min-width: 48rem) { .sitenav--bp-md { … } }` is what\n * switches the nav to its desktop layout, and blanket-dropping every\n * container block meant the tailwind format shipped a nav stuck in mobile.\n */\n const isVariantBlock = (raw: string): boolean => {\n const open = raw.indexOf('{');\n const body = raw.slice(open + 1, raw.lastIndexOf('}'));\n const selectors: string[] = [];\n let depth = 0;\n let start = 0;\n for (let i = 0; i < body.length; i++) {\n const ch = body[i];\n if (ch === '{') {\n if (depth === 0) selectors.push(body.slice(start, i));\n depth++;\n } else if (ch === '}') {\n depth--;\n if (depth === 0) start = i + 1;\n }\n }\n const names = selectors\n .flatMap((s) => s.split(','))\n .map((s) => s.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '').trim())\n .filter(Boolean);\n return names.length > 0 && names.every((n) => /^\\.(sm|md|lg|xl)-/.test(n));\n };\n const stripForTailwind = (css: string): string => {\n const kept: string[] = [];\n let depth = 0;\n let start = 0;\n let preludeEnd = -1;\n for (let i = 0; i < css.length; i++) {\n const ch = css[i];\n if (ch === '/' && css[i + 1] === '*') {\n const end = css.indexOf('*/', i + 2);\n i = end === -1 ? css.length : end + 1;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n i += 1;\n while (i < css.length && css[i] !== ch) i += css[i] === '\\\\' ? 2 : 1;\n continue;\n }\n if (ch === '{') {\n if (depth === 0) preludeEnd = i;\n depth++;\n } else if (ch === '}') {\n depth--;\n if (depth === 0) {\n const raw = css.slice(start, i + 1).trim();\n const prelude = css\n .slice(start, preludeEnd)\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .trim();\n const clash = /^\\.([A-Za-z0-9_-]+)/.exec(prelude);\n const name = clash?.[1] as string | undefined;\n if (/^@container\\s*\\(\\s*min-width:/.test(prelude) && isVariantBlock(raw))\n droppedVariantBlocks++;\n else if (name && TW_CLASH.has(name) && !CLASH_KEEP.has(name)) droppedClashes.add(name);\n else if (raw) kept.push(raw);\n start = i + 1;\n }\n }\n }\n return kept.join('\\n\\n');\n };\n\n const partials = componentPartialOrder(cssDir);\n const componentCss = partials\n .map((rel) => {\n const css = readFileSync(join(cssDir, rel), 'utf8');\n return `/* ── ${rel} ── */\\n${stripForTailwind(css)}`;\n })\n .join('\\n\\n');\n // Same layering rationale as the patterns block above. `componentPartialOrder`\n // already returns [] when assets are absent, so this is empty in that case.\n if (componentCss)\n parts.push(\n `/* ── Component + structural partials (Tailwind-clashing utilities dropped) ── */\\n` +\n `/* Dropped ${droppedVariantBlocks} pre-expanded breakpoint block(s) — write @sm:/@md:/@lg:/@xl: instead.\\n` +\n ` Dropped ${droppedClashes.size} clashing utilit(ies) Tailwind provides itself:\\n` +\n ` ${[...droppedClashes].sort().join(' ') || '(none)'} */\\n` +\n `@layer components {\\n${componentCss}\\n}`,\n );\n\n return nl(parts) + '\\n';\n}\n\n/**\n * Partials the tailwind format does NOT inline, because it re-creates them by\n * hand: the engine (`global.css` — Tailwind's preflight covers the reset;\n * `animation.css` — read directly and wrapped in `@layer components`), and the\n * two layout partials, whose utilities are re-emitted as `@utility` and whose\n * structure is re-emitted in the `@layer components` literal.\n *\n * **Every partial mapped to `vitops.utilities` must be listed here.** Inlining a\n * utility family lands it in tailwind's `@layer components`, the exact inversion\n * the layer split exists to remove — and it fails SILENTLY, because each of those\n * classes already exists as an `@utility` that wins on layer anyway. You would get\n * ~30 dead rules and no test failure. `format-parity.test.ts` asserts the\n * implication structurally rather than spot-checking the output.\n *\n * The implication is one-way: `layout.css` is skipped while sitting in\n * `vitops.components`, because its structure is re-emitted by hand.\n */\n/**\n * Framework COMPONENTS whose class name collides with a Tailwind utility, and\n * which must therefore survive the `TW_CLASH` strip.\n *\n * The clash test matches a rule's leading `.<name>`, which is right for a\n * single-purpose utility (Tailwind ships its own) and wrong for a pattern that\n * merely shares the name. `patterns/sticky.css` opens `.sticky { … }` and was\n * being deleted from the tailwind bundle WHOLESALE — the `--_sticky-offset`\n * wiring, the z-index, and every `&.sticky--bottom`/`--inline-start` variant —\n * so a consumer writing `class=\"sticky sticky--bottom\"` got bare\n * `position: sticky` and nothing else.\n *\n * `table` is here for the same reason but was never actually hit: `table.css`'s\n * prelude is `table,\\n.table`, which doesn't start with `.`, so the regex missed\n * it by luck. Listing it makes that explicit rather than accidental.\n */\nconst CLASH_KEEP: ReadonlySet<string> = new Set(['sticky', 'table']);\n\nexport const TAILWIND_SKIP: ReadonlySet<string> = new Set([\n 'global.css',\n 'animation.css',\n 'layout.css',\n 'layout-utilities.css',\n // Everything left here after the reveal family moved to patterns/reveal.css is\n // either a TW_CLASH name (display, sr-only, text-wrap) or a pre-expanded\n // variant block, so the strip already emptied it — reading it was pure waste,\n // and leaving it out made the invariant above look violated when it wasn't.\n 'utilities.css',\n]);\n\n/**\n * The component/structural CSS partials to inline into the Tailwind bundle, in\n * index.css cascade order. Everything the aggregator imports EXCEPT `TAILWIND_SKIP`\n * and the generated token layer (Tailwind builds its own via @theme).\n */\nfunction componentPartialOrder(cssDir: string): string[] {\n const indexPath = join(cssDir, 'index.css');\n const order: string[] = [];\n const seen = new Set<string>();\n const text = existsSync(indexPath) ? readFileSync(indexPath, 'utf8') : '';\n for (const m of text.matchAll(/@import\\s+['\"]\\.\\/([^'\"]+)['\"]/g)) {\n const rel = m[1] as string;\n if (rel.startsWith('generated/')) continue;\n if (TAILWIND_SKIP.has(rel)) continue;\n if (!seen.has(rel) && existsSync(join(cssDir, rel))) {\n seen.add(rel);\n order.push(rel);\n }\n }\n // Fallback: if no index.css, inline utilities + every pattern partial.\n if (!order.length) {\n if (existsSync(join(cssDir, 'utilities.css'))) order.push('utilities.css');\n const pdir = join(cssDir, 'patterns');\n if (existsSync(pdir))\n for (const f of readdirSync(pdir).sort()) if (f.endsWith('.css')) order.push(`patterns/${f}`);\n }\n return order;\n}\n\n// ── CSS bundling (css + bricks formats) ───────────────────────────────────────\n\n/** The bundle's cascade layers, in precedence order (last wins). */\nexport const CSS_LAYERS = ['vitops.base', 'vitops.components', 'vitops.utilities'] as const;\n\n/**\n * Which layer each `index.css` chunk belongs to. Anything unmapped defaults to\n * `vitops.components` — the safe default, since an unrecognised partial is far\n * more likely to be a component than a utility family.\n *\n * The split is by what the file *emits*, not what it's named:\n * • base — the UA reset and the pure `:root` token blocks.\n * • components — the animation engine, structural layout, and every pattern.\n * • utilities — the single-purpose classes that must be able to override a\n * pattern (`bg-*`, `drop-shadow-*`, `font-*`, effects, …).\n *\n * `color.css` and `shadows.css` each mix a `:root` block with utility classes\n * and go to `utilities` whole. That is safe because custom-property resolution\n * is NOT source-order dependent — a `:root` block declared after a rule that\n * reads it still resolves.\n *\n * `layout.css` is genuinely mixed (structural `.rhythm`/`.centered` AND\n * `.m-*`/`.flex`/`.split-*` utilities) and stays in `components` whole, so its\n * utility half still can't override a pattern. Splitting it is a separate\n * change; see the 0.9.0 changelog.\n */\nexport const CHUNK_LAYER: Record<string, (typeof CSS_LAYERS)[number]> = {\n 'global.css': 'vitops.base',\n 'generated/type-tokens.css': 'vitops.base',\n 'generated/tokens.css': 'vitops.base',\n 'generated/color.css': 'vitops.utilities',\n 'generated/shadows.css': 'vitops.utilities',\n 'generated/typography.css': 'vitops.utilities',\n 'generated/animation-effects.css': 'vitops.utilities',\n 'generated/spacing.css': 'vitops.utilities',\n 'layout-utilities.css': 'vitops.utilities',\n 'utilities.css': 'vitops.utilities',\n};\n\n/**\n * A `.split` child's flex basis. The ratio is a BASIS rather than a grow factor\n * because grow shares out only the FREE space, which a child's padding is not\n * part of — so a padded column came out wider than its sibling by exactly its\n * horizontal padding. Must stay character-identical to layout.css; the parity\n * suite matches this expression against both.\n */\nexport const splitBasis = (v: '--_split-a' | '--_split-b'): string =>\n `calc(var(${v}, 1) / (var(--_split-a, 1) + var(--_split-b, 1)) * 100%)`;\n\n/** The layer a partial's rules are wrapped in; unmapped partials are components. */\nexport const layerForPartial = (rel: string): (typeof CSS_LAYERS)[number] =>\n CHUNK_LAYER[rel] ?? 'vitops.components';\n\n/**\n * Assemble the full stylesheet by resolving index.css's @import order against the\n * static partials (from assets) and the freshly generated token partials (in\n * memory), then minify with lightningcss. No @import survives, so no disk\n * resolution / shared `generated/` dir is needed.\n *\n * Each chunk is wrapped in a cascade layer. This is what lets a single-purpose\n * utility override a component pattern — `class=\"card bg-danger-muted\"` — which\n * previously depended on source order and so silently did nothing here while\n * working in the tailwind format, where Tailwind's own layers already ordered\n * them correctly.\n *\n * Consequence worth knowing: unlayered CSS beats ALL layered CSS regardless of\n * specificity, so a consumer's own stylesheet now wins over the framework by\n * default. That is deliberate — it is the override story every layered\n * framework ships — but it means an unlayered *reset* will beat framework\n * component rules it used to lose to. Such a reset belongs in a layer declared\n * before `vitops.base` (see the `<style>` block in this repo's index.html).\n */\nfunction bundleCss(\n generated: Record<string, string>,\n assetsDir: string,\n minify: boolean,\n): { code: string; map: string | undefined } {\n const cssDir = join(assetsDir, 'css');\n const indexPath = join(cssDir, 'index.css');\n const index = readFileSync(indexPath, 'utf8');\n const chunks: string[] = [];\n for (const line of index.split('\\n')) {\n const m = /@import\\s+['\"]\\.\\/([^'\"]+)['\"]/.exec(line);\n if (!m) continue;\n const rel = m[1] as string;\n const body = rel.startsWith('generated/')\n ? (generated[rel.slice('generated/'.length)] ?? '')\n : readFileSync(join(cssDir, rel), 'utf8');\n if (!body.trim()) continue;\n chunks.push(`@layer ${layerForPartial(rel)} {\\n${body}\\n}`);\n }\n // `/*!` rather than `/*`: lightningcss strips ordinary comments when\n // minifying, and both the css and bricks bundles are minified — so a plain\n // banner would never reach the file anyone actually opens. Whoever opens this\n // is looking for a class name; point them at the live reference.\n const banner =\n `/*! GENERATED by @getvitops/generator — do not edit by hand.\\n` +\n ` Class reference: npx vitops docs classes · All topics: npx vitops docs */\\n`;\n // Declare the order up front so it is explicit rather than an artifact of\n // which chunk happened to appear first.\n const merged = banner + `@layer ${CSS_LAYERS.join(', ')};\\n` + chunks.join('\\n');\n const res = transform({\n filename: 'styles.css',\n code: Buffer.from(merged),\n minify,\n sourceMap: minify,\n });\n return {\n code: res.code.toString(),\n map: res.map ? res.map.toString() : undefined,\n };\n}\n\n// ── public generate() ─────────────────────────────────────────────────────────\n/**\n * Read `input` as whichever config kind it is, and return the design system to\n * build from plus the site config if that is what it was.\n *\n * The design system is validated here rather than in `resolveInput` so the error\n * can name where it came from: a theme inside a site config reports its `themes`\n * path, which is the difference between \"your config is wrong\" and \"your config\n * is wrong *here*\" when the file is a few hundred lines of company facts.\n */\nfunction loadInput(\n input: string | DesignSystem | Config,\n opts: { theme?: string; siteEnv?: string },\n): { ds: DesignSystem; config?: Config } {\n const raw = typeof input === 'string' ? JSON.parse(readFileSync(input, 'utf8')) : input;\n const resolved = resolveInput(raw, opts);\n const result = validate(resolved.designSystem);\n if (!result.ok) {\n const where =\n resolved.theme != null\n ? `design system at designSystem.themes.${resolved.theme}`\n : 'design-system.json';\n const lines = result.errors\n .slice(0, 12)\n .map((e) => ` • ${e.path.join('.') || '(root)'}: ${e.message}`)\n .join('\\n');\n throw new Error(`Invalid ${where}:\\n${lines}`);\n }\n for (const w of result.warnings) console.warn(`[vitops] ${w}`);\n return { ds: result.data, ...(resolved.config ? { config: resolved.config } : {}) };\n}\n\nexport async function generate(options: GenerateOptions): Promise<GenerateResult> {\n const format: Format = options.format ?? 'bricks';\n const outDir = options.outDir ?? 'dist';\n const assetsDir = options.assetsDir ?? DEFAULT_ASSETS;\n const { ds, config: embedded } = loadInput(options.input, {\n ...(options.theme != null ? { theme: options.theme } : {}),\n ...(options.siteEnv != null ? { siteEnv: options.siteEnv } : {}),\n });\n // Loaded before `build` because `designSystem.defaultColorScheme` decides what\n // the colour layer emits. (It is read again below for legal documents;\n // resolving twice would validate twice and double any warning.)\n //\n // An explicit `site` wins over one embedded in `input` — it is the more\n // specific statement, and the two are the same file in every case but the one\n // where a consumer deliberately split them.\n const config = options.site != null ? loadConfigFile(options.site, options.siteEnv) : embedded;\n const built = build(ds, format, assetsDir, {\n systemColorScheme:\n options.systemColorScheme ?? config?.designSystem?.defaultColorScheme === 'system',\n });\n mkdirSync(outDir, { recursive: true });\n const written: string[] = [];\n const put = (rel: string, content: string) => {\n const p = join(outDir, rel);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, content);\n written.push(p);\n };\n\n if (format === 'design') {\n // Deliberately the only output: DESIGN.md conventionally lives at the repo\n // root next to AGENTS.md, not in a build directory, so this format is meant\n // to be run with `--out .` — writing a stylesheet alongside it would be\n // surprising. Compose it when you want both: `--format css,design`.\n put('DESIGN.md', built.designMd);\n } else if (format === 'tailwind') {\n put('tailwind.css', built.tailwind);\n put('tokens.json', built.tokensJson);\n } else if (format === 'css') {\n const { code } = bundleCss(built.generated, assetsDir, true);\n put('styles.css', code);\n put('tokens.json', built.tokensJson);\n put('design-manifest.json', built.designManifest);\n } else {\n // bricks: bundled minified CSS + Bricks import JSON + copied JS/PHP/docs.\n const { code, map } = bundleCss(built.generated, assetsDir, true);\n put('styles.min.css', map ? code + `\\n/*# sourceMappingURL=styles.min.css.map */` : code);\n if (map) put('styles.min.css.map', map);\n put('bricks-colors-named.json', built.bricksColorsNamed);\n put('bricks-colors-semantic.json', built.bricksColorsSemantic);\n put('bricks-variables.json', built.bricksVariables);\n put('tokens.json', built.tokensJson);\n // Framework-static JS bundles → outDir root (theme enqueues them).\n const jsDir = join(assetsDir, 'js');\n if (existsSync(jsDir)) {\n cpSync(jsDir, outDir, { recursive: true });\n for (const f of readdirSync(jsDir)) written.push(join(outDir, f));\n }\n // Bricks PHP elements + loader → outDir/bricks.\n const bricksSrc = join(assetsDir, 'bricks');\n if (existsSync(bricksSrc)) {\n cpSync(bricksSrc, join(outDir, 'bricks'), { recursive: true });\n written.push(join(outDir, 'bricks'));\n }\n // OKF docs bundle (generated per-config) → outDir/docs.\n const docs = generateDocs(ds, assetsDir);\n for (const [rel, content] of Object.entries(docs)) put(join('docs', rel), content);\n }\n\n // Legal documents → outDir/legal, as HTML fragments.\n //\n // Opt-in via `site`, and emitted for every format that emits files at all —\n // passing a site config and silently getting nothing back would be the\n // surprising behaviour. `design` is excluded because it emits DESIGN.md and\n // deliberately nothing else.\n //\n // HTML rather than markdown because this is the fragment a WordPress theme,\n // a Bricks shortcode or a plain page can include with no build step of its own.\n if (config != null && format !== 'design') {\n const legal = generateLegal(config, { output: 'html' });\n for (const [name, content] of Object.entries(legal)) put(join('legal', name), content);\n\n // Icon sprite → outDir/icons.svg.\n //\n // Opt-in via `icons.sprite`, because building it needs the @iconify-json/*\n // collections and most consumers render icons through their framework's own\n // integration instead. This is the path for the ones that can't: Bricks,\n // EmDash renderers, any plain HTML — `<use href=\"…/icons.svg#id\">`, no JS.\n const icons = config.site.icons as\n | { sprite?: boolean; ui?: string; brand?: string; weight?: string; semantic?: string[] }\n | undefined;\n if (icons?.sprite) {\n const { ui, brand, weight, semantic, sprite: _sprite, ...sets } = icons;\n const include = generateIconInclude({\n ...(ui ? { ui } : {}),\n ...(brand ? { brand } : {}),\n ...(weight ? { weight } : {}),\n ...(semantic ? { semantic } : {}),\n ...sets,\n });\n // Semantic names get a set-independent alias (`icon-menu`) alongside the\n // qualified id, so markup written against a sprite survives a set swap —\n // the same guarantee `resolveIcon` gives Astro consumers.\n const aliases: Record<string, string> = {};\n for (const name of semantic ?? []) {\n try {\n aliases[`icon-${name}`] = resolveIcon(name, ui ?? 'fa7-solid', weight ? { weight } : {});\n } catch {\n // Already reported by generateIconInclude, which throws on the same input.\n }\n }\n const built = await buildIconSprite({ include, aliases });\n put('icons.svg', built.svg);\n if (built.missing.length)\n console.warn(\n `[vitops] icons.sprite: ${built.missing.length} icon(s) were not found and are ` +\n `absent from the sprite: ${built.missing.join(', ')}.`,\n );\n }\n }\n\n return { format, outDir, written };\n}\n\nfunction loadConfigFile(input: string | Config, siteEnv?: string): Config {\n const raw = typeof input === 'string' ? JSON.parse(readFileSync(input, 'utf8')) : input;\n // resolveConfig validates and throws with one issue per line.\n return resolveConfig(raw, siteEnv);\n}\n","/**\n * @getvitops/generator — public API.\n *\n * Turn a `design-system.json` into platform outputs (Bricks, standalone CSS,\n * Tailwind v4). The `zod/mini` schema is the single source of truth: types,\n * validation, and the published JSON Schema all derive from it.\n */\nexport { generate, roleColorUtilities } from './generate.ts';\nexport type {\n GenerateOptions,\n GenerateResult,\n Format,\n StylesheetFormat,\n ColorUtility,\n} from './generate.ts';\n\n// Exposed so `vitops lint` can ask what the generator emits instead of\n// re-deriving the vocabulary and drifting from it.\nexport { expandPalette, functionalRole } from './tokens.ts';\nexport type { ExpandedHue, FunctionalRole } from './tokens.ts';\n\nexport {\n generateDocs,\n renderInlineMarkdown,\n schemaTreeNodes,\n type JsonSchemaNode,\n type SchemaTreeNode,\n type SchemaTreeOptions,\n} from './docs.ts';\n\n// Which tiers provide each pattern, and the call to make. Authored + drift-guarded;\n// see tiers.ts for why it can't be derived from naming convention.\nexport {\n TIERS,\n TIER_NAMES,\n tierPatterns,\n tierTags,\n type Tier,\n type TierAstro,\n type TierCss,\n type TierEntry,\n type TierProjection,\n type TierWc,\n} from './tiers.ts';\n/**\n * SVG sprite emitter. `spriteId` is the id grammar `<use href=\"…#id\">` targets;\n * @getvitops/astro's Icon.astro mirrors it, so treat it as a shared contract.\n */\nexport { buildIconSprite, loadIconSvg, spriteId } from './icons-sprite.ts';\nexport type { IconSpriteOptions, IconSpriteResult } from './icons-sprite.ts';\nexport { NUMERIC_STEPS } from './tokens.ts';\nexport {\n TW_CLASH,\n BASE_HOOK,\n DARK_SEL,\n REQUIRED_ROLES,\n ROLE_TOKEN_KEYS,\n roleHue,\n roleKind,\n} from './shared.ts';\nexport type { RoleSpec } from './shared.ts';\nexport { tokenVar, tokenClass, CONTRAST } from './tokens.ts';\nexport type { RoleKind } from './tokens.ts';\n\nexport { DesignSystemSchema, jsonSchema, SCHEMA_URL, validate } from './schema.ts';\nexport type { DesignSystem, ValidationResult } from './schema.ts';\nexport {\n ConfigSchema,\n SiteFontSchema,\n configJsonSchema,\n CONFIG_SCHEMA_URL,\n validateConfig,\n resolveConfig,\n resolvePrivacyContact,\n resolveTheme,\n // Every entry point that takes a config goes through these, so a consumer who\n // keeps their tokens inside the larger three-section config points the same\n // option at that file rather than maintaining a second one.\n isConfig,\n resolveInput,\n stripNulls,\n deepMerge,\n JURISDICTIONS,\n JURISDICTION_COUNTRIES,\n AD_PROVIDERS,\n} from './config.ts';\nexport type {\n AdProvider,\n SiteAdProperty,\n ContactObject,\n Jurisdiction,\n PostalAddress,\n ResolvedInput,\n Config,\n OrganizationConfig,\n SiteSection,\n SiteFont,\n SiteIndexNow,\n SiteIndexing,\n SiteSearchConsole,\n ConfigValidationResult,\n} from './config.ts';\n\n// Legal documents. A sibling of `generateDocs`, not a `generate()` format:\n// `generate()` is keyed to a DesignSystem, and these render from a Config.\nexport {\n generateLegal,\n enabledDocs,\n renderMarkdown,\n renderNodes,\n derivePolicyVars,\n detectProcessorKeys,\n processorsMissingLocation,\n resolveProcessors,\n KNOWN_PROCESSORS,\n parseMarkdown,\n toContentNodes,\n toHtmlFragment,\n toPortableText,\n DOC_ORDER,\n DOC_SLUGS,\n TEMPLATES,\n} from './legal/index.ts';\nexport type {\n GenerateLegalOptions,\n LegalDoc,\n LegalOutput,\n PolicyVars,\n Processor,\n ProcessorStorage,\n KnownProcessorKey,\n Block,\n Span,\n DocSet,\n} from './legal/index.ts';\n\nimport { SCHEMA_URL, type DesignSystem } from './schema.ts';\n\n/**\n * A minimal but complete starter design system, used by `vitops init`. It\n * validates against the schema and generates real output in every format, so a\n * new project can `vitops generate` immediately and then tune from here.\n */\nexport function defaultConfig(): DesignSystem {\n return {\n $schema: SCHEMA_URL,\n colors: {\n // Each hue is generated as an 11-step OKLCH scale from its seed.\n palette: {\n brand: { seed: '#2e9b73' },\n ink: { seed: '#3f4a5c' },\n sky: { seed: '#2f7bc0' },\n sun: { seed: '#d08a1f' },\n rose: { seed: '#c74a42' },\n },\n // role → hue. Tokens (--color-<target>-<role>-<variant>) derive from the\n // hue's scale; dark mode flips automatically. `kind: \"surface\"` marks the\n // page/panel colours, which get a bare `bg-<role>`; the bare-string form\n // means chromatic, so a signal colour says tint-or-solid rather than\n // leaving \"how loud?\" to a guess.\n roles: {\n neutral: { hue: 'ink', kind: 'surface' },\n surface: { hue: 'ink', kind: 'surface' },\n 'ui-primary': 'brand',\n 'brand-primary': 'brand',\n info: 'sky',\n success: 'brand',\n warning: 'sun',\n danger: 'rose',\n },\n utilities: ['bg', 'text', 'icon', 'border'],\n },\n shadows: {\n sm: '0 1px 2px rgb(0 0 0 / 0.08)',\n md: '0 4px 6px rgb(0 0 0 / 0.12)',\n lg: '0 10px 15px rgb(0 0 0 / 0.18)',\n },\n fonts: {\n display: 'system-ui, -apple-system, \"Segoe UI\", sans-serif',\n sans: 'system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif',\n mono: 'ui-monospace, \"SF Mono\", Menlo, monospace',\n },\n typeScale: {\n base: '1rem',\n names: ['2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl'],\n baseStep: 4,\n baseline: 'm',\n ratio: 1.2,\n fluid: { minVw: '22.5rem', maxVw: '80rem', minRatio: 1.12 },\n },\n spaceScale: {\n base: '1rem',\n names: ['2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl'],\n baseStep: 4,\n baseline: 'm',\n ratio: 1.25,\n fluid: { minVw: '22.5rem', maxVw: '80rem', minRatio: 1.2 },\n },\n patterns: {\n defaults: {\n ds: 'none',\n b: '1px solid var(--color-border-surface-muted)',\n br: '0.375rem',\n p: '1rem',\n fs: '1rem',\n },\n // No `card` key here: a radii key named after a pattern collides on `--br-<name>`,\n // shadowing that pattern's override hook and leaving its `-group` alias unreachable\n // (validate() warns about exactly this). `card` is in the `panel` group, which already\n // carries the same 0.5rem, so dropping it is value-preserving.\n radii: { pill: '999px', circle: '50%' },\n groups: {\n control: {\n ds: 'var(--ds-default)',\n b: 'var(--b-default)',\n br: 'var(--br-default)',\n p: '0.5em 1em',\n fs: 'var(--fs-default)',\n },\n panel: {\n ds: 'var(--shadow-md)',\n b: 'var(--b-default)',\n br: '0.5rem',\n p: '1rem',\n fs: 'var(--fs-default)',\n },\n },\n z: { raised: 1, sticky: 100, overlay: 200, top: 1000 },\n items: {\n // Affordance tier: bare <button> and .btn share one zero-specificity rule,\n // so any explicit class (including .cta) overrides it.\n btn: {\n group: 'control',\n element: 'button',\n class: 'btn',\n fill: false,\n // Geometry resolves through the group alias layer (`--<prop>-btn-group`),\n // so the mapping to the `control` group lives in CSS and stays editable;\n // `overrides` restate only what this tier does differently.\n overrides: { b: '1px solid transparent', fs: 'inherit' },\n base: {\n display: 'inline-flex',\n 'align-items': 'center',\n 'justify-content': 'center',\n gap: '0.4em',\n padding: 'var(--p-btn-group)',\n 'border-radius': 'var(--br-btn-group)',\n border: 'var(--b-btn-group)',\n 'box-shadow': 'var(--ds-btn-group)',\n background: 'transparent',\n color: 'inherit',\n 'font-family': 'inherit',\n 'font-size': 'var(--fs-btn-group)',\n 'font-weight': 'inherit',\n 'text-decoration': 'none',\n cursor: 'pointer',\n },\n states: {\n hover: { step: 1, css: { 'background-color': 'var(--color-bg-surface-muted)' } },\n 'focus-visible': { ring: true },\n },\n roles: [],\n },\n // Persuasion tier: opt-in, works on any element (<a>, <button>, <summary>).\n cta: {\n group: 'control',\n class: 'cta',\n fill: true,\n // `ui-primary`, not `brand-primary`: a CTA is a prominent *interface*\n // affordance, and its prominence already comes from fill/weight/padding.\n // Keeping it on the ui role means the whole interaction family (btn,\n // link, cta) shares one hue lineage — otherwise focus rings change\n // colour depending on which tier you tabbed onto. Brand stays reachable\n // as an explicit `.cta-brand-primary` variant.\n default_role: 'ui-primary',\n overrides: { p: '0.75em 1.5em', b: 'none', ds: 'var(--shadow-sm)', fs: 'inherit' },\n base: {\n display: 'inline-flex',\n 'align-items': 'center',\n 'justify-content': 'center',\n gap: '0.5em',\n padding: 'var(--p-cta-group)',\n 'border-radius': 'var(--br-cta-group)',\n border: 'var(--b-cta-group)',\n 'font-family': 'inherit',\n 'font-size': 'var(--fs-cta-group)',\n 'font-weight': '600',\n 'text-decoration': 'none',\n cursor: 'pointer',\n color: 'var(--color-text-on-ui-primary)',\n 'box-shadow': 'var(--ds-cta-group)',\n },\n states: {\n hover: { step: 1, lift: '1px' },\n active: { scale: 0.97 },\n 'focus-visible': { ring: true },\n },\n roles: [],\n },\n card: {\n group: 'panel',\n class: 'card',\n base: {\n 'border-radius': 'var(--br-card-group)',\n padding: '1.5rem',\n background: 'var(--color-bg-surface)',\n border: 'var(--b-card-group)',\n 'box-shadow': 'var(--ds-card-group)',\n },\n states: {},\n roles: [],\n },\n },\n },\n typography: {\n families: {\n display: 'var(--font-display)',\n sans: 'var(--font-sans)',\n code: 'var(--font-mono, ui-monospace, monospace)',\n },\n // `text-wrap` is stated on every role because omitting it is NOT \"inherit\":\n // it is emitted at its identity (`wrap`) so role classes fully reset one\n // another, which would cancel the `pretty` a role inherits from body.\n roles: {\n display: {\n family: 'display',\n size: 'var(--text-3xl)',\n weight: 700,\n 'line-height': '1.05',\n tracking: '-0.03em',\n 'text-wrap': 'balance',\n },\n heading: {\n family: 'display',\n size: 'var(--text-xl)',\n weight: 600,\n 'line-height': '1.3',\n 'text-wrap': 'balance',\n },\n body: {\n family: 'sans',\n size: 'var(--text-m)',\n weight: 400,\n 'line-height': '1.55',\n 'text-wrap': 'pretty',\n },\n },\n // `body` binds base page typography to the body role, so prose inherits it\n // and the role's tokens stay the single place it's edited.\n headings: { body: 'body', h1: 'display', h2: 'heading', h3: 'heading' },\n },\n animations: {\n effects: {\n 'fade-in': { kf: 'composite', vars: { 'opacity-from': 0 } },\n 'slide-up': {\n kf: 'composite',\n vars: { 'translate-y-from': 'var(--slide-distance, 2rem)' },\n },\n },\n journeys: {\n // Each part must declare the `from` endpoint its keyframe reads — an\n // empty `slide` leaves slide-journey animating translate 0 → 0, i.e. a\n // journey that silently doesn't slide. Same var as the `slide-up`\n // effect above, so `--slide-distance` tunes both.\n base: {\n fade: { 'opacity-from': 0 },\n slide: { 'translate-y-from': 'var(--slide-distance, 2rem)' },\n },\n compose: [['fade'], ['slide'], ['fade', 'slide']],\n },\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["providersSection"],"sources":["../src/shared.ts","../src/tokens.ts","../src/token-refs.ts","../src/schema.ts","../src/config.ts","../src/tiers.ts","../src/docs.ts","../src/design-md.ts","../src/legal/providers.ts","../src/legal/derive.ts","../src/legal/render.ts","../src/legal/templates/shared.ts","../src/legal/templates/cookies.ca.ts","../src/legal/templates/privacy.ca.ts","../src/legal/templates/terms.ca.ts","../src/legal/templates/index.ts","../src/legal/index.ts","../src/icons-sprite.ts","../src/generate.ts","../src/index.ts"],"sourcesContent":["/**\n * Data shared between the generator (`generate.ts`) and the docs bundle\n * (`docs.ts`). Lives in its own module because `generate.ts` imports `docs.ts` —\n * importing back the other way would be a cycle.\n */\n\n/**\n * Selector the dark functional-token flip hangs off.\n *\n * `data-brx-theme` is Bricks' own attribute — Bricks sets it, so it's what the\n * WordPress target needs. Nothing sets it anywhere else, which meant the dark\n * flip was unreachable outside Bricks: the shipped `<wc-color-scheme-toggle>` web\n * component writes `documentElement.dataset.theme` (i.e. `data-theme`), so\n * clicking \"Dark\" changed an attribute no rule matched. Matching both makes the\n * component work on every target without changing what Bricks already does.\n *\n * This covers the EXPLICIT choice. The OS preference is a second, opt-in block —\n * see `SYSTEM_DARK_SEL` — because turning it on flips a site dark for dark-OS\n * users, which is the site's decision rather than the design system's.\n *\n * Shared so the docs quote the selector the generator actually emits.\n */\nexport const DARK_SEL = ':root[data-brx-theme=\"dark\"], :root[data-theme=\"dark\"]';\n\n/**\n * Selector for the OS-preference dark block, emitted inside\n * `@media (prefers-color-scheme: dark)` when a site opts in.\n *\n * Derived from `DARK_SEL`'s attributes rather than written out a third time, and\n * inverted: this must apply when NO explicit choice has been made. That is\n * exactly what `<wc-color-scheme-toggle>`'s \"System\" position produces — it removes\n * `data-theme` entirely — so with this block present System resolves to the OS\n * instead of silently falling through to light, and needs no JS to do it.\n *\n * The `:not()`s are what keep an explicit *light* choice winning over a dark OS.\n */\nexport const SYSTEM_DARK_SEL = `:root${DARK_SEL.split(', ')\n .map((s) => s.replace(/^:root\\[([\\w-]+)=\"dark\"\\]$/, '[$1=\"light\"]'))\n .map((attr) => `:not(${attr})`)\n .join('')}`;\n\n/**\n * Roles the shipped CSS partials reference with NO fallback, so a config that\n * omits one leaves those rules resolving to nothing — an invalid declaration,\n * not a graceful degrade.\n *\n * `colors.roles` is an open record: any name works and generates a full token\n * set, utilities and dark flip. But the framework's own component CSS is\n * written against these six, so \"roles are arbitrary\" is only half true — they\n * are *extensible*, over a required core. `validate()` warns when one is\n * missing; `required-roles.test.ts` re-derives this list from the partials so\n * it cannot drift as components are added.\n *\n * Kept as a constant rather than scanned at call time because `validate()` is\n * a pure function — the CLI, the Vite plugin and `toJSONSchema` all import it,\n * and none of them should touch the filesystem to answer \"is this config ok?\".\n */\nexport const REQUIRED_ROLES: readonly string[] = [\n 'brand-primary',\n 'danger',\n 'neutral',\n 'surface',\n 'ui-primary',\n 'warning',\n];\n\n/**\n * Every token key a role can resolve to, across both role kinds. Shared so the\n * required-roles drift test greps for exactly what the generator emits.\n *\n * These are *keys*, not var names: the role sits in the middle of the property\n * (`--color-bg-danger-muted`), so compose them with `tokenVar()` from `tokens.ts`\n * rather than concatenating by hand.\n */\nexport const ROLE_TOKEN_KEYS: readonly string[] = [\n // backgrounds — surface roles get the bare token and the full range,\n // chromatic roles get tints plus the solid family.\n 'bg',\n 'bg-muted',\n 'bg-x-muted',\n 'bg-bold',\n 'bg-x-bold',\n 'bg-solid',\n 'bg-solid-bold',\n 'bg-solid-x-bold',\n // foregrounds\n 'text',\n 'text-bold',\n 'text-muted',\n 'text-x-muted',\n 'text-xx-muted',\n 'text-on',\n 'text-on-bold',\n // non-text tiers\n 'icon',\n 'icon-muted',\n 'border',\n 'border-muted',\n 'border-bold',\n];\n\n/** How a role is authored in `colors.roles`: a bare hue, or a hue plus its kind. */\n// `kind` admits an explicit `undefined` because the repo runs\n// `exactOptionalPropertyTypes` and the zod-inferred config type spells optionals\n// that way — without it every call site would need a cast.\nexport type RoleSpec = string | { hue: string; kind?: 'surface' | 'chromatic' | undefined };\n\n/** The palette hue a role points at, through either authoring form. */\nexport const roleHue = (spec: RoleSpec): string => (typeof spec === 'string' ? spec : spec.hue);\n\n/**\n * A role's kind. The bare-string shorthand means `chromatic`, because signal\n * colours are the common case and surfaces are the two or three you name once.\n */\nexport const roleKind = (spec: RoleSpec): 'surface' | 'chromatic' =>\n typeof spec === 'string' ? 'chromatic' : (spec.kind ?? 'chromatic');\n\n/**\n * Pattern base geometry props → per-pattern override-hook shorthand. Each hook\n * wraps the authored value (`padding: var(--p-btn, 0.4em 0.8em)`) so a\n * consumer restyles one pattern by setting one variable. The hook is named after\n * the pattern's key, not its class.\n */\nexport const BASE_HOOK: Record<string, string> = {\n padding: 'p',\n 'border-radius': 'br',\n border: 'b',\n 'box-shadow': 'ds',\n 'font-size': 'fs',\n // Both spellings map to `bg`, because patterns author either (`card` uses the\n // shorthand, `status` the longhand). A pattern setting both would map the\n // same var twice — a config error, not something to design around.\n background: 'bg',\n 'background-color': 'bg',\n};\n\n/**\n * Framework utility classes whose names collide with Tailwind's own defaults.\n * The `tailwind` format strips any rule targeting these — Tailwind provides\n * them, so consumers use Tailwind's utilities for these names instead.\n */\nexport const TW_CLASH: ReadonlySet<string> = new Set<string>([\n 'block',\n 'inline',\n 'inline-block',\n 'flow-root',\n 'flex',\n 'inline-flex',\n 'grid',\n 'inline-grid',\n 'table',\n 'inline-table',\n 'table-caption',\n 'table-cell',\n 'table-row',\n 'contents',\n 'hidden',\n 'list-item',\n 'static',\n 'fixed',\n 'absolute',\n 'relative',\n 'sticky',\n 'isolate',\n 'visible',\n 'invisible',\n 'collapse',\n 'sr-only',\n 'not-sr-only',\n 'flex-row',\n 'flex-row-reverse',\n 'flex-col',\n 'flex-col-reverse',\n 'flex-wrap',\n 'flex-nowrap',\n 'items-start',\n 'items-end',\n 'items-center',\n 'items-baseline',\n 'items-stretch',\n 'justify-start',\n 'justify-end',\n 'justify-center',\n 'justify-between',\n 'justify-around',\n 'justify-evenly',\n 'content-start',\n 'content-end',\n 'content-center',\n 'content-between',\n 'content-around',\n 'content-evenly',\n 'text-left',\n 'text-center',\n 'text-right',\n 'text-justify',\n 'text-start',\n 'text-end',\n 'text-wrap',\n 'text-nowrap',\n 'text-balance',\n 'text-pretty',\n]);\n","/**\n * Palette expansion + semantic colour tokens.\n *\n * A palette hue is authored one of two ways:\n * • `{ seed, anchors? }` — an 11-step numeric scale (50…950) generated in\n * OKLCH via @getvitops/utils/color. Lightness comes from the shared\n * `LIGHTNESS_LADDER`; the seed (and any anchors) are reproduced verbatim at\n * their steps.\n * • `{ tones }` — a fixed brand kit: authored tones placed verbatim at their\n * nearest steps + tinted endpoints; nothing else is invented (strict kits).\n *\n * **The grammar.** Every role gets tokens named `--color-<target>-<role>[-<variant>]`,\n * where target ∈ bg | text | icon | border. Putting the target *inside* the name is\n * the point: `--color-bg-danger-muted` and `--color-text-danger-muted` are distinct\n * tokens, so the two axes that used to collide over one `<family>-<role>-<modifier>\n * ` namespace cannot any more. The utility class is the token name minus `--color-`.\n *\n * Variants are ordinal — xx-muted < x-muted < muted < (bare) < bold < x-bold —\n * and the tables are **sparse**: a target only emits the cells that are actually\n * viable. `bold` means \"more emphatic than the role's default in the current\n * appearance\", not \"darker\"; the appearance decides polarity.\n *\n * Roles come in two kinds (declared in `colors.roles`):\n * • `surface` — a page/panel colour. Has a bare `bg-<role>` plus the full\n * emphasis range and the complete text scale.\n * • `chromatic` (default) — a signal colour. Backgrounds split into *tints*\n * (`bg-<role>-x-muted` / `-muted`) and *solids* (`bg-<role>-solid[-bold|-x-bold]`);\n * there is deliberately **no bare `bg-<role>`**, because \"how loud?\" is a\n * question the author has to answer.\n *\n * Dark mode re-points which step each token reads; the solid family and the\n * `text-on-<role>` foreground computed against it stay mode-stable, so a filled\n * button keeps its identity across appearances.\n */\nimport {\n LIGHTNESS_LADDER,\n contrastLc,\n generateOklchPalette,\n hexToOklch,\n oklchStringToHex,\n pickOn,\n tintedEndpoints,\n} from '@getvitops/utils/color';\n\nexport const NUMERIC_STEPS = [\n '50',\n '100',\n '200',\n '300',\n '400',\n '500',\n '600',\n '700',\n '800',\n '900',\n '950',\n] as const;\ntype NumStep = (typeof NUMERIC_STEPS)[number];\n\n/**\n * Lightness of each numeric step. Re-exported from the engine's ladder rather\n * than restated — there used to be three copies of this curve (here, the engine,\n * and the linter) and they were free to drift.\n */\nconst STEP_L = Object.fromEntries(\n NUMERIC_STEPS.map((s) => [s, LIGHTNESS_LADDER[Number(s) as keyof typeof LIGHTNESS_LADDER]]),\n) as Record<NumStep, number>;\n\nexport interface ExpandedHue {\n /** Numeric steps (sparse for fixed-tone kits). */\n numeric: Partial<Record<NumStep, string>>;\n /** True when only authored tones + endpoints exist (no interpolation). */\n sparse?: boolean;\n /**\n * Steps the author pinned, and how far each sits from the ladder's lightness.\n * A pinned colour is reproduced exactly, so a large value here is legal — but\n * it means this hue reads heavier or lighter than its siblings at that step,\n * which the generator surfaces as a warning.\n */\n deviations?: Partial<Record<NumStep, number>>;\n}\n\ninterface SeedInput {\n seed: string;\n anchors?: Record<string, string>;\n}\ninterface TonesInput {\n tones: string[] | Record<string, string>;\n}\n\nconst isHex = (v: string) => v.startsWith('#');\nconst toOklchStr = (v: string) => {\n if (!isHex(v)) return v; // already oklch(...)\n const { l, c, h } = hexToOklch(v);\n return `oklch(${(l * 100).toFixed(2)}% ${c.toFixed(4)} ${h.toFixed(2)})`;\n};\nconst nearestStep = (l: number): NumStep =>\n NUMERIC_STEPS.reduce((best, s) =>\n Math.abs(l - STEP_L[s]) < Math.abs(l - STEP_L[best]) ? s : best,\n );\n\n/**\n * Claim `step` for `value`, refusing to overwrite a step another colour already\n * took.\n *\n * Silently dropping one of two colliding tones is the worst outcome: the palette\n * still builds, and the tone the author cared about is simply gone. The record\n * form (`tones: { \"600\": \"#…\", \"700\": \"#…\" }`) is the escape hatch, so the error\n * points at it.\n */\nfunction claim(\n into: Record<string, string>,\n step: string,\n value: string,\n hueLabel: string,\n what: string,\n): void {\n const taken = into[step];\n if (taken != null && taken !== value) {\n throw new Error(\n `palette hue \"${hueLabel}\": ${what} ${value} and ${taken} both map to step ${step}. ` +\n `Key them explicitly, e.g. { \"${step}\": \"${taken}\", \"${Number(step) + 100}\": \"${value}\" }.`,\n );\n }\n into[step] = value;\n}\n\nfunction expandSeeded(input: SeedInput, hueLabel: string): ExpandedHue {\n // The seed and any author anchors pin verbatim at their natural (or explicit)\n // steps; the engine fills every other step from the shared lightness ladder,\n // fading chroma toward the tinted ends. No implicit 50/950 anchors any more —\n // the ladder already defines the endpoints, and pinning them would override it.\n // Author anchors are placed FIRST and may collide only with each other. The\n // seed goes in afterwards, and only where an anchor hasn't already claimed the\n // step: an explicit anchor is the author overriding that step, which is exactly\n // what the live editor writes when you recolour a swatch. Treating that as a\n // collision would break the editor's save path.\n const anchors: Record<string, string> = {};\n for (const [key, value] of Object.entries(input.anchors ?? {})) {\n const step = (NUMERIC_STEPS as readonly string[]).includes(key)\n ? key\n : nearestStep(hexToOklch(value).l);\n claim(anchors, step, toOklchStr(value), hueLabel, 'anchors');\n }\n const seedStep = nearestStep(hexToOklch(input.seed).l);\n anchors[seedStep] ??= toOklchStr(input.seed);\n const scale = generateOklchPalette(anchors) as Record<string, string>;\n const numeric: Partial<Record<NumStep, string>> = {};\n for (const s of NUMERIC_STEPS) if (scale[s] != null) numeric[s] = oklchStringToHex(scale[s]);\n return { numeric, deviations: deviationsFor(anchors) };\n}\n\nfunction expandTones(input: TonesInput, hueLabel: string): ExpandedHue {\n // Strict kit: authored tones verbatim at their nearest step; add tinted\n // endpoints (the one allowed exception); interpolate nothing else.\n const entries: Array<[string | null, string]> = Array.isArray(input.tones)\n ? input.tones.map((hex) => [null, hex])\n : Object.entries(input.tones).map(([k, hex]) => [k, hex]);\n\n const placed: Record<string, string> = {};\n for (const [key, hex] of entries) {\n const step =\n key != null && (NUMERIC_STEPS as readonly string[]).includes(key)\n ? key\n : nearestStep(hexToOklch(hex).l);\n claim(placed, step, hex, hueLabel, 'tones');\n }\n\n const numeric: Partial<Record<NumStep, string>> = {};\n for (const [step, hex] of Object.entries(placed)) numeric[step as NumStep] = hex;\n\n const firstTone = entries[0]?.[1] ?? '#808080';\n const ends = tintedEndpoints(hexToOklch(firstTone).h);\n numeric['50'] ??= ends.light;\n numeric['950'] ??= ends.dark;\n\n return { numeric, sparse: true, deviations: deviationsFor(placed) };\n}\n\n/** How far each pinned colour sits from its step's ladder lightness. */\nfunction deviationsFor(pinned: Record<string, string>): Partial<Record<NumStep, number>> {\n const out: Partial<Record<NumStep, number>> = {};\n for (const [step, value] of Object.entries(pinned)) {\n const l = isHex(value) ? hexToOklch(value).l : hexToOklch(oklchStringToHex(value)).l;\n out[step as NumStep] = l - STEP_L[step as NumStep];\n }\n return out;\n}\n\n/** Snap to the nearest AVAILABLE numeric step (sparse kits). */\nfunction snap(numeric: Partial<Record<NumStep, string>>, want: NumStep): NumStep {\n if (numeric[want] != null) return want;\n const have = NUMERIC_STEPS.filter((s) => numeric[s] != null);\n return have.reduce((best, s) =>\n Math.abs(STEP_L[s] - STEP_L[want]) < Math.abs(STEP_L[best] - STEP_L[want]) ? s : best,\n );\n}\n\n/** Expand every palette hue into its numeric scale. */\nexport function expandPalette(raw: Record<string, unknown>): Record<string, ExpandedHue> {\n const out: Record<string, ExpandedHue> = {};\n for (const [name, entry] of Object.entries(raw)) {\n const e = entry as Partial<SeedInput & TonesInput>;\n if (typeof e?.seed === 'string') out[name] = expandSeeded(e as SeedInput, name);\n else if (e?.tones != null) out[name] = expandTones(e as TonesInput, name);\n else throw new Error(`palette hue \"${name}\" must have a \"seed\" or \"tones\"`);\n }\n return out;\n}\n\n/**\n * Warn about pinned colours that sit noticeably off the ladder. Not an error:\n * the author asked for that exact colour and gets it. But at ~0.03 L the hue\n * starts reading visibly heavier or lighter than its siblings at that step, and\n * that is the class of drift the fixed ladder exists to prevent.\n */\nexport const LADDER_TOLERANCE = 0.03;\n\nexport function ladderWarnings(palette: Record<string, ExpandedHue>): string[] {\n const warnings: string[] = [];\n for (const [hue, expanded] of Object.entries(palette)) {\n for (const [step, deviation] of Object.entries(expanded.deviations ?? {})) {\n if (Math.abs(deviation as number) <= LADDER_TOLERANCE) continue;\n const dir = (deviation as number) > 0 ? 'lighter' : 'darker';\n warnings.push(\n `colors.palette.${hue}: the colour pinned at step ${step} is ${Math.abs(\n deviation as number,\n ).toFixed(3)} ${dir} than the shared lightness ladder — this hue will read ` +\n `${dir} than others at ${step}. Legal, but move it to a neighbouring step if that wasn't intended.`,\n );\n }\n }\n return warnings;\n}\n\n/**\n * Gamut mapping nudges lightness by a hair, so an exact `<` comparison would\n * report rounding as an inversion. Well below any deviation a person could see.\n */\nconst MONOTONIC_EPSILON = 1e-3;\n\n/**\n * Ramps whose lightness does not fall monotonically from 50 to 950.\n *\n * A ramp built from the ladder alone cannot invert — only pinned colours (a seed,\n * an `anchor`, a `tones` entry) can, because they are the one thing allowed off\n * it. `ladderWarnings` will not catch it: it compares each pinned step against\n * *its own* ladder rung, never against its neighbours, so it reports the wrong\n * defect (\"reads darker than others at 600\") while the real problem is that 600\n * is darker than 700. And since `LADDER_TOLERANCE` is 0.03 — the same size as the\n * ladder's own 50→100 gap — two anchors can each sit within tolerance and still\n * invert, with no warning at all.\n *\n * This is an error rather than a warning because the rest of the system assumes\n * the order: `snap` picks the nearest step by ladder lightness, the mode-stable\n * solid family hard-codes 600/700/800 as increasingly dark, and both dark tables\n * re-point steps on the same assumption. An inverted ramp therefore runs hover\n * states backwards — the failure the fixed ladder was introduced to eliminate.\n */\nexport function monotonicityErrors(palette: Record<string, ExpandedHue>): string[] {\n const errors: string[] = [];\n for (const [hue, expanded] of Object.entries(palette)) {\n const numeric = expanded.numeric ?? {};\n // Present steps only — a sparse `tones` kit is legal, and comparing against\n // absent steps would invent inversions that aren't there.\n const steps = NUMERIC_STEPS.filter((s) => numeric[s] != null);\n for (let i = 1; i < steps.length; i++) {\n const [prev, step] = [steps[i - 1] as NumStep, steps[i] as NumStep];\n // The final hex, not the nominal ladder value: a pinned colour is emitted\n // verbatim, and it is precisely the pinned steps that can invert.\n const lPrev = hexToOklch(numeric[prev] as string).l;\n const lStep = hexToOklch(numeric[step] as string).l;\n if (lStep < lPrev + MONOTONIC_EPSILON) continue;\n // Point at the colour the author actually wrote. Only a pinned step can be\n // off the ladder, so naming its correct home is the actionable half — the\n // unpinned neighbour is already exactly where it belongs, and telling\n // someone to move that one sends them the wrong way.\n const pinned = expanded.deviations ?? {};\n const culprits = ([prev, step] as NumStep[]).filter((s) => pinned[s] != null);\n const fix = culprits.length\n ? culprits\n .map((s) => {\n const l = hexToOklch(numeric[s] as string).l;\n return `${numeric[s]} (pinned at ${s}) sits at L ${l.toFixed(3)}, nearest step ${nearestStep(l)}`;\n })\n .join('; ')\n : `no step here is pinned, so this is a bug in the generator rather than in your config`;\n errors.push(\n `colors.palette.${hue}: step ${step} (${numeric[step]}, L ${lStep.toFixed(3)}) is LIGHTER ` +\n `than step ${prev} (${numeric[prev]}, L ${lPrev.toFixed(3)}). A ramp must darken from 50 ` +\n `to 950 — inverted, a hover from \\`bg-<role>-solid\\` to \\`-solid-bold\\` gets lighter, and ` +\n `the dark-mode tables re-point steps assuming the order. ${fix}.`,\n );\n }\n }\n return errors;\n}\n\n// ── the token tables ─────────────────────────────────────────────────────────\n\n/** Which shape of token set a role gets. */\nexport type RoleKind = 'surface' | 'chromatic';\n\n/** Token key → numeric step. Keys are `<target>[-<variant>]`; see `tokenVar`. */\ntype Table = Record<string, NumStep>;\n\n/**\n * Surface roles: a bare `bg` (cards, panels, inputs), `bg-muted` for the page\n * behind them, `bg-x-muted` for wells, and `bg-bold`/`-x-bold` for the inverse\n * surface a tooltip sits on. Elevation is expressed by *which* token you reach\n * for — page `bg-muted`, card `bg` — rather than by a raised/sunken pair. That\n * is what lets a future `data-surfaces` axis flatten it without touching markup.\n */\nconst SURFACE_LIGHT: Table = {\n bg: '50',\n 'bg-muted': '100',\n 'bg-x-muted': '200',\n 'bg-bold': '800',\n 'bg-x-bold': '950',\n text: '900',\n 'text-bold': '950',\n 'text-muted': '700',\n 'text-x-muted': '500',\n 'text-xx-muted': '400',\n 'text-on-bold': '50',\n icon: '600',\n 'icon-muted': '500',\n 'border-muted': '200',\n border: '300',\n 'border-bold': '600',\n};\nconst SURFACE_DARK: Table = {\n bg: '900',\n 'bg-muted': '950',\n 'bg-x-muted': '950',\n 'bg-bold': '200',\n 'bg-x-bold': '50',\n text: '100',\n 'text-bold': '50',\n // 300 and 400, not v3.1's 400 and 500: those were tuned against WCAG and come\n // up short of APCA's secondary-text and non-text bars over a dark surface.\n 'text-muted': '300',\n 'text-x-muted': '500',\n 'text-xx-muted': '600',\n 'text-on-bold': '950',\n icon: '400',\n 'icon-muted': '500',\n 'border-muted': '800',\n border: '700',\n 'border-bold': '400',\n};\n\n/**\n * Chromatic roles: tints for alert/badge backgrounds, solids for fills. No bare\n * `bg` — see the module docblock. No `text-muted` either: a de-emphasised\n * coloured text could not hold its contrast target off a white surface, so the\n * way to soften coloured text is weight/size, not another colour.\n */\nconst CHROMATIC_LIGHT: Table = {\n 'bg-x-muted': '50',\n 'bg-muted': '100',\n text: '700',\n 'text-bold': '900',\n icon: '600',\n border: '200',\n 'border-bold': '300',\n};\nconst CHROMATIC_DARK: Table = {\n 'bg-x-muted': '950',\n 'bg-muted': '900',\n text: '300',\n 'text-bold': '200',\n icon: '400',\n border: '800',\n 'border-bold': '700',\n};\n\n/**\n * The solid family — mode-stable, so a filled button keeps its identity when the\n * appearance flips. Fixed steps rather than the old scan-and-clamp: with a shared\n * lightness ladder every hue's 600 already sits at the same lightness, so there\n * is nothing left to search for. `text-on-<role>` is computed against `bg-solid`.\n */\nconst SOLID: Table = { 'bg-solid': '600', 'bg-solid-bold': '700', 'bg-solid-x-bold': '800' };\n\n/**\n * Map a token key to its CSS custom property for a given role.\n *\n * `on` is the one irregular case: the foreground for a filled surface reads\n * `--color-text-on-<role>`, with the role *after* `on`, because it names what it\n * sits on rather than what it is.\n *\n * The utility class name is this minus the `--color-` prefix, which is why the\n * emitter and the linter can both derive their vocabulary from one function.\n */\nexport function tokenVar(role: string, key: string): string {\n const dash = key.indexOf('-');\n const target = dash === -1 ? key : key.slice(0, dash);\n const variant = dash === -1 ? '' : key.slice(dash + 1);\n if (variant === 'on') return `--color-${target}-on-${role}`;\n if (variant.startsWith('on-')) return `--color-${target}-on-${role}-${variant.slice(3)}`;\n return variant ? `--color-${target}-${role}-${variant}` : `--color-${target}-${role}`;\n}\n\n/** The class name a token key produces for a role (`bg-danger-solid`, …). */\nexport const tokenClass = (role: string, key: string): string =>\n tokenVar(role, key).slice('--color-'.length);\n\nexport interface FunctionalRole {\n role: string;\n hue: string;\n kind: RoleKind;\n /** token key → CSS value, per appearance. */\n light: Record<string, string>;\n dark: Record<string, string>;\n}\n\n/** Resolve the token set for one role over its hue. */\nexport function functionalRole(\n role: string,\n hueName: string,\n hue: ExpandedHue,\n kind: RoleKind = 'chromatic',\n): FunctionalRole {\n const numeric = hue.numeric;\n const v = (n: NumStep) => `var(--color-${hueName}-${snap(numeric, n)})`;\n const hex = (n: NumStep) => numeric[snap(numeric, n)] as string;\n\n const map = (table: Table): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const [token, step] of Object.entries(table)) out[token] = v(step);\n return out;\n };\n\n // Solids and the foreground computed against them are identical in both\n // appearances — that mode-stability is the whole point of the family.\n const solids = map(SOLID);\n const onSolid = pickOn(hex(SOLID['bg-solid'] as NumStep));\n\n const light = {\n ...map(kind === 'surface' ? SURFACE_LIGHT : CHROMATIC_LIGHT),\n ...solids,\n 'text-on': onSolid,\n };\n const dark = {\n ...map(kind === 'surface' ? SURFACE_DARK : CHROMATIC_DARK),\n ...solids,\n 'text-on': onSolid,\n };\n return { role, hue: hueName, kind, light, dark };\n}\n\n// ── the contrast contract ────────────────────────────────────────────────────\n\n/**\n * APCA targets. `TEXT` is the body-text bar; `SECONDARY` covers text on a\n * non-primary surface and de-emphasised text. `NON_TEXT` is the icon/boundary\n * tier — the APCA analogue of WCAG's 3:1, where a glyph may run more vivid than\n * text because shape carries meaning alongside contrast.\n */\nexport const CONTRAST = { TEXT: 75, SECONDARY: 60, NON_TEXT: 45 } as const;\n\n/**\n * Text tokens deliberately exempt from the contract. Placeholders and disabled\n * text are required to look unavailable; holding them to the body-text bar would\n * defeat the affordance. Nothing else may be exempt.\n */\nconst EXEMPT_TEXT = new Set(['text-x-muted', 'text-xx-muted']);\n\n/**\n * Verify a role's contrast targets. Returns human-readable failures.\n *\n * Chromatic roles are checked against the surface planes they actually sit on\n * (`surfaceBg`) as well as their own tints — coloured text almost never appears\n * over its own solid, it appears over the page. Checking only within the role\n * would have missed the pairing that matters most.\n */\nexport function checkContrast(\n fr: FunctionalRole,\n numericOf: (hueName: string) => Partial<Record<NumStep, string>>,\n surfaceBg?: { light: string[]; dark: string[] },\n): string[] {\n const failures: string[] = [];\n const resolve = (val: string): string => {\n const m = /^var\\(--color-([a-z0-9-]+)-(\\d+)\\)$/.exec(val);\n if (!m) return val;\n return numericOf(m[1] as string)[m[2] as NumStep] ?? val;\n };\n const fail = (appearance: string, msg: string) =>\n failures.push(`${fr.role}/${appearance}: ${msg}`);\n\n for (const [appearance, tokens] of [\n ['light', fr.light],\n ['dark', fr.dark],\n ] as const) {\n // Backgrounds this role's own foregrounds have to work on. For a surface\n // role that's its own planes; for a chromatic role it's the page surface\n // plus its own tints.\n const ownBg = Object.keys(tokens)\n .filter((k) => k === 'bg' || k.startsWith('bg-'))\n .filter((k) => !k.startsWith('bg-solid'))\n .filter((k) => !k.startsWith('bg-bold') && !k.startsWith('bg-x-bold'));\n const planes: Array<[string, string]> =\n fr.kind === 'surface'\n ? ownBg.map((k) => [k, resolve(tokens[k] as string)])\n : [\n ...(surfaceBg?.[appearance] ?? []).map(\n (h, i) => [`surface#${i}`, h] as [string, string],\n ),\n ...ownBg.map((k) => [k, resolve(tokens[k] as string)] as [string, string]),\n ];\n\n for (const [planeName, bg] of planes) {\n // `bg` is the role's primary surface and holds the full body-text bar;\n // every other plane holds the secondary bar.\n const textMin = planeName === 'bg' ? CONTRAST.TEXT : CONTRAST.SECONDARY;\n for (const key of ['text', 'text-bold', 'text-muted']) {\n if (tokens[key] == null || EXEMPT_TEXT.has(key)) continue;\n const min = key === 'text-muted' ? CONTRAST.SECONDARY : textMin;\n const lc = contrastLc(resolve(tokens[key] as string), bg);\n if (lc < min) fail(appearance, `${key} Lc ${lc.toFixed(1)} < ${min} on ${planeName} ${bg}`);\n }\n // Icons carry meaning, so they hold the non-text bar everywhere. Borders\n // do not: a chromatic `border-<role>` is *decorative* — the tinted edge of\n // an alert, where the colour reinforces a message the text already makes.\n // Only a surface role's `border-bold` is the \"this boundary is the only\n // thing separating two regions\" token, so only that one is guaranteed.\n const nonText = fr.kind === 'surface' ? ['icon', 'border-bold'] : ['icon'];\n for (const key of nonText) {\n if (tokens[key] == null) continue;\n const lc = contrastLc(resolve(tokens[key] as string), bg);\n if (lc < CONTRAST.NON_TEXT)\n fail(\n appearance,\n `${key} Lc ${lc.toFixed(1)} < ${CONTRAST.NON_TEXT} on ${planeName} ${bg}`,\n );\n }\n }\n\n // The filled-surface pairing: text-on against the solid it names.\n const solid = resolve(tokens['bg-solid'] as string);\n const onLc = contrastLc(tokens['text-on'] as string, solid);\n if (onLc < CONTRAST.SECONDARY)\n fail(appearance, `text-on Lc ${onLc.toFixed(1)} < ${CONTRAST.SECONDARY} on bg-solid`);\n\n // The inverse surface, where it exists.\n if (tokens['bg-bold'] != null && tokens['text-on-bold'] != null) {\n const lc = contrastLc(resolve(tokens['text-on-bold'] as string), resolve(tokens['bg-bold']));\n if (lc < CONTRAST.TEXT)\n fail(appearance, `text-on-bold Lc ${lc.toFixed(1)} < ${CONTRAST.TEXT} on bg-bold`);\n }\n }\n return failures;\n}\n","/**\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 */\nexport function 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). 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 * 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 const desc = <T extends { check(...checks: never[]): T }>(schema: T, text: string): T =>\n schema.check(z.describe(text) as never);\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 */\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 { desc, DesignSystemPatchSchema, type DesignSystem } from './schema.ts';\n\n// ── Primitives ────────────────────────────────────────────────────────────────\n\nconst LocalizableSchema = desc(\n z.union([z.string(), z.record(z.string(), z.string())]),\n 'A string, or a per-locale map of strings (`{ en: \"…\", fr: \"…\" }`).',\n);\n\nconst ImageRefSchema = z.union([\n z.string(),\n z.object({\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.object({\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.object({\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.object({\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.object({\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.object({\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.object({\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// 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\nconst LocationSchema = z.object({\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 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});\n\n// ── Organization (schema.org Organization) ──────────────────────────────────────\n\nconst OrganizationSchema = z.object({\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.object({\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.object({\n provider: z.optional(z.string()),\n nameservers: z.optional(z.array(z.string())),\n records: z.optional(z.array(DnsRecordSchema)),\n});\n\n/**\n * One domain to onboard into Google Search Console via `vitops search setup`.\n *\n * The verification token is fetched live from the Site Verification API at run\n * time and written to DNS — it is never stored here. What the config records is\n * the *intent*: which domains to onboard, and who should co-own them.\n */\nconst SearchConsoleSetupSchema = z.object({\n delegatedOwners: desc(\n z.optional(z.array(z.email())),\n 'Emails added as verification owners on the Site Verification web resource. Automated via the API — additive and idempotent, never removes an existing owner.',\n ),\n fullUserGroup: desc(\n z.optional(z.email()),\n 'A Google Group to grant Full-User access in Search Console. SURFACED AS A REMINDER only: Search Console exposes no user/permission API, so this step stays manual by design.',\n ),\n});\n\n// ── Environments ──────────────────────────────────────────────────────────────\n\nconst RobotsSchema = z.string(); // e.g. \"index,follow\" / \"noindex,nofollow\"\n\nconst EnvironmentSchema = z.object({\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.object({\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// ── 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.object({\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.object({\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.object({ 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.object({\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.object({\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.object({\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.object({ label: z.string(), value: z.string() }))]),\n ),\n attrs: AttrsSchema,\n});\n\nconst ContentNodeSchema: z.ZodMiniType = z.object({\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.object({\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.object({\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.object({\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.object({\n src: z.string(),\n alt: LocalizableSchema,\n caption: z.optional(LocalizableSchema),\n});\n\nconst GallerySchema = z.object({\n title: z.optional(LocalizableSchema),\n tags: z.optional(z.array(z.string())),\n images: z.array(GalleryImageSchema),\n});\n\nconst TestimonialItemSchema = z.object({\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.object({\n title: z.optional(LocalizableSchema),\n items: z.array(TestimonialItemSchema),\n});\n\n// ── Services (schema.org Offer) ─────────────────────────────────────────────────\n\nconst OfferSchema = z.object({\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.object({\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\nconst OpenGraphSchema = z.object({\n type: z.optional(z.string()),\n siteName: z.optional(z.string()),\n title: z.optional(LocalizableSchema),\n description: z.optional(LocalizableSchema),\n image: z.optional(ImageRefSchema),\n locale: z.optional(z.string()),\n});\n\nconst TwitterSchema = z.object({\n card: z.optional(z.enum(['summary', 'summary_large_image', 'app', 'player'])),\n site: z.optional(z.string()),\n creator: z.optional(z.string()),\n title: z.optional(LocalizableSchema),\n description: z.optional(LocalizableSchema),\n image: z.optional(ImageRefSchema),\n});\n\n// ── Indexing ────────────────────────────────────────────────────────────────────\n\n/**\n * What `vitops search notify` needs to tell search engines a deploy happened.\n *\n * Scoped by what search engines actually accept, which is narrower than it looks:\n * Google exposes **no** \"request indexing\" API (the Search Console button is not in\n * its API, and URL Inspection is read-only), and it removed the sitemap ping\n * endpoint in 2023. So the sanctioned set is: an accurate sitemap, a Search Console\n * sitemap resubmit, an IndexNow ping — which Google does *not* honour but Bing,\n * Yandex, Naver, Seznam and Yep do — and a read-only inspection pass to find out\n * what Google actually did.\n *\n * Facts only, the same rule the legal block follows: this records what the site has\n * (a key, a property, which pages matter), never what to say about it.\n */\nconst IndexNowSchema = z.object({\n key: desc(\n z.string().check(z.regex(/^[a-zA-Z0-9-]{8,128}$/)),\n 'IndexNow key (8–128 chars, hex is conventional). NOT a secret — it is served publicly at `keyLocation` so the engine can verify you own the host. Generate one with `vitops search notify --new-key`.',\n ),\n keyLocation: desc(\n z.optional(z.url()),\n 'Absolute URL of the key file. Defaults to `<canonical>/<key>.txt`; set it only when the file lives elsewhere.',\n ),\n endpoint: desc(\n z.optional(z.url()),\n 'IndexNow endpoint (default `https://api.indexnow.org/indexnow`). Any participating engine shares submissions with the rest, so one is normally enough.',\n ),\n});\n\nconst SearchConsoleSchema = z.object({\n siteUrl: desc(\n z.string(),\n 'The property exactly as Search Console identifies it — `sc-domain:acme.ca` for a domain property, or the URL-prefix form `https://acme.ca/`. A mismatch here is a 403, not a \"not found\".',\n ),\n resubmitSitemap: desc(\n z.optional(z.boolean()),\n 'Re-submit the sitemap through the Search Console API on each notify (default true when `searchConsole` is set). This is the automated equivalent of the manual resubmit in the UI.',\n ),\n});\n\nconst IndexingSchema = z.object({\n sitemapUrl: desc(\n z.optional(z.url()),\n 'The sitemap to submit and to diff for changed URLs. Defaults to `<canonical>/sitemap-index.xml`.',\n ),\n indexNow: desc(\n z.optional(IndexNowSchema),\n 'IndexNow submission (Bing, Yandex, Naver, Seznam, Yep — not Google). Omit to skip the channel.',\n ),\n searchConsole: desc(\n z.optional(SearchConsoleSchema),\n 'Google Search Console property. Needs a credential at run time — either a service account in `VITOPS_GSC_SERVICE_ACCOUNT` / `GOOGLE_APPLICATION_CREDENTIALS`, or the user OAuth credential `vitops search setup` uses (`VITOPS_GOOGLE_CLIENT_ID` / `_CLIENT_SECRET` / `_REFRESH_TOKEN`). The service account wins when both are set. Never put a key in this file.',\n ),\n priorityUrls: desc(\n z.optional(z.array(z.url())),\n 'The pages whose indexing actually matters. `vitops search notify --check` inspects these and exits non-zero if Google has not indexed one. Kept explicit because URL Inspection is quota-bound (2000/day), so checking every page is neither affordable nor informative.',\n ),\n});\n\n// ── Ad properties ───────────────────────────────────────────────────────────────\n\n/**\n * The ad platforms `vitops ads` can link a site to.\n *\n * A closed enum, mirroring `AD_PROVIDER_KEYS` in `@getvitops/utils/ads` — that\n * module owns what each platform *can do* (whether it verifies a domain, what its\n * tag is, which click ID it stamps), this owns what a config may *say*. Mirrored\n * rather than derived because a `z.enum` needs literals to reach the published JSON\n * Schema; `config.test.ts` asserts the two lists are the same set, so a provider\n * added to one and not the other fails the build rather than silently getting no\n * verification step and no tag.\n */\nexport const AD_PROVIDERS = [\n 'google',\n 'meta',\n 'linkedin',\n 'reddit',\n 'tiktok',\n 'microsoft',\n 'pinterest',\n 'snapchat',\n] as const;\nconst AdProviderSchema = z.enum(AD_PROVIDERS);\nexport type AdProvider = (typeof AD_PROVIDERS)[number];\n\n/**\n * One ad property this site is linked to.\n *\n * Facts, not prose — the same rule the legal block follows. This records *which*\n * account and *which* tag id, and the platform capability table decides what can be\n * done about them. It is also what finally lets the rest of the toolchain see an ad\n * pixel: the generated cookie notice discloses its cookies, `vitops ads lint`\n * checks its click ID is captured, and the consent gate is handed the cookie names\n * to clear on revoke. A pixel pasted into a template is invisible to all three.\n */\nconst AdPropertySchema = z.object({\n accountId: desc(\n z.optional(z.string()),\n 'The advertising account as the platform shows it — Google Ads customer ID, Meta ad account, LinkedIn partner ID, Reddit advertiser ID. For LinkedIn this is also the Insight Tag id; everywhere else the tag id is `pixelId`.',\n ),\n pixelId: desc(\n z.optional(z.string()),\n 'The tag/pixel ID the browser snippet initialises — Meta pixel, TikTok pixel, Reddit pixel, Microsoft UET tag ID, Pinterest tag ID, Snap pixel, or the Google Ads conversion ID (`AW-…`, which is NOT the customer ID).',\n ),\n conversionLabel: desc(\n z.optional(z.string()),\n 'Google Ads only: the conversion action label paired with the `AW-…` conversion ID.',\n ),\n domain: desc(\n z.optional(z.string()),\n 'Bare hostname to verify with this platform. Defaults to the host of `domains.canonical` — set it only when the ad account is verified against a different domain.',\n ),\n domainVerification: desc(\n z.optional(z.string()),\n 'The verification token from the platform UI, for the platforms that verify by DNS TXT (Meta, TikTok, Pinterest, Snapchat). `vitops ads setup` prompts for it and writes it here on first run. NOT a secret — it is published in DNS, and the platform fetching it back is the ownership proof, exactly like the IndexNow key. A value containing `=` is used as the whole record, which is the escape hatch if a platform changes its prefix.',\n ),\n category: desc(\n z.optional(z.enum(['marketing', 'analytics'])),\n 'Consent category the tag waits on (default `marketing`). An ad pixel is advertising by default; `analytics` is for a site using one purely for its own measurement.',\n ),\n enabled: desc(\n z.optional(z.boolean()),\n 'Set false to keep the property on record without emitting its tag.',\n ),\n});\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.object({\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.object({\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.object({\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.object({\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 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.',\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 abTesting: desc(\n z.optional(\n z.object({\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 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.object({\n activeTemplate: desc(\n z.optional(\n z.object({\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(\n z.object({\n titleTemplate: desc(z.optional(z.string()), 'Page-title pattern (e.g. \"%s · Acme\").'),\n descriptionTemplate: z.optional(z.string()),\n robots: desc(z.optional(RobotsSchema), 'e.g. \"index,follow\" / \"noindex,nofollow\".'),\n googleSiteVerification: z.optional(z.string()),\n bingSiteVerification: z.optional(z.string()),\n openGraph: z.optional(OpenGraphSchema),\n twitter: z.optional(TwitterSchema),\n indexing: desc(\n z.optional(IndexingSchema),\n 'How `vitops search notify` tells search engines about a deploy: which sitemap, IndexNow key, Search Console property, and which pages to verify afterwards.',\n ),\n }),\n ),\n 'SEO defaults: title/description templates, robots policy, verification tokens, Open Graph + Twitter cards, and post-deploy indexing notification.',\n ),\n analytics: desc(\n z.optional(\n z.object({\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.object({\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 }),\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 z.optional(\n z.object({\n email: desc(\n z.optional(\n z.union([\n z.email(),\n z.object({\n provider: desc(\n z.literal('cloudflare'),\n 'Delivery provider. Only Cloudflare Email Sending is implemented; the field is stated so adding another is additive.',\n ),\n to: desc(\n z.optional(z.email()),\n 'Recipient. Defaults to the primary location’s `email`, then the first location that has one.',\n ),\n from: desc(\n z.optional(z.email()),\n 'Sender. Defaults to `noreply@<domains.canonical>`. Its domain must be onboarded (`wrangler email sending enable <domain>`) or every send fails.',\n ),\n fromName: desc(\n z.optional(z.string()),\n 'Display name on the From header. Defaults to `organization.name`.',\n ),\n replyTo: desc(z.optional(z.email()), 'Reply-To header.'),\n binding: desc(\n z.optional(z.string()),\n 'Workers `send_email` binding name (default `EMAIL`). Set it when using a restricted binding.',\n ),\n }),\n ]),\n ),\n 'Where conversion notifications are e-mailed. A bare address is shorthand for `{ provider: \"cloudflare\", to }`.',\n ),\n }),\n ),\n 'Where site notifications (form submissions, tracked calls) are sent. TODO: `sms` and `persist` channels — only `email` is implemented.',\n ),\n tracking: desc(\n z.optional(\n z.object({\n enabled: desc(\n z.optional(z.boolean()),\n 'Capture ad click IDs and UTMs from the landing URL into the `_ac` cookie, for attributing conversions.',\n ),\n category: desc(\n z.optional(z.enum(['marketing', 'analytics'])),\n 'Consent category the `_ac` cookie waits on (default `marketing`). It is a 90-day identifier tying a visitor to the ad that brought them, so it is only written once this category is granted — and asking for it is what raises the banner.',\n ),\n platforms: desc(\n z.optional(z.array(z.string())),\n 'Informational list of ad platforms in use. Capture recognises every known click-ID parameter regardless.',\n ),\n }),\n ),\n 'Ad-click attribution for conversion tracking.',\n ),\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 security: desc(\n z.optional(\n z.object({\n turnstile: z.optional(\n z.object({\n siteKey: desc(z.optional(z.string()), 'Cloudflare Turnstile site key (public).'),\n }),\n ),\n }),\n ),\n 'Security integrations (bot protection).',\n ),\n legal: desc(\n z.optional(\n z.object({\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.object({\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.object({\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.object({\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.object({\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 z.optional(\n z.object({\n platform: z.optional(z.string()),\n buildCommand: z.optional(z.string()),\n deployCommand: z.optional(z.string()),\n outputDirectory: z.optional(z.string()),\n type: z.optional(z.string()),\n }),\n ),\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.object({\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\nexport const ConfigSchema = z.object({\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\n// ── JSON Schema + validation ────────────────────────────────────────────────────\n\nexport const CONFIG_SCHEMA_URL = 'https://unpkg.com/@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// ── 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 * 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) return { ok: false, data: undefined, errors: parsed.error.issues };\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 if (errors.length) return { ok: false, data: undefined, errors };\n return { ok: true, data: cfg, errors: [] };\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 * Which tiers provide each pattern, and which call to make.\n *\n * The toolkit ships three tiers that COMPOSE — CSS framework classes, Lit web\n * components, and the platform wrappers (Astro components, Bricks elements) — and\n * the composition is what a consumer actually needs. For a tree: `.tree` styles it, `<Tree />` generates the\n * markup, `<wc-tree>` enhances it. This file is the single source for that, and\n * `tiers.test.ts` holds it to the files on disk.\n *\n * **Authored, not derived, and that is deliberate.** Name convention carries most\n * of it (`patterns/<name>.css` ↔ `WC<Name>.ts` → `wc-<name>` ↔\n * `bricks/elements/<name>.php`) but breaks where it matters:\n *\n * - `splitter.css` hosts TWO components (`wc-split-panel`, `wc-image-compare`);\n * - `anchor-link.css` provides `.link`, whose config pattern is `link`;\n * - `tag.css` carries parts for THREE config patterns (`badge`, `tag`, `status`);\n * - `layout.css` (a root partial, not under `patterns/`) provides `.split` and\n * `.centered`, both of which have Bricks elements;\n * - `forms.css`, `nav.css`, `navbar.css`, `navshell.css` each serve several tiers.\n *\n * A derivation would need an exceptions table longer than the rule, and a rename\n * would silently drop a link instead of failing. So it is authored, and the guards\n * make omission a build failure rather than a missing docs row.\n *\n * **The composition rule this encodes** (see `AGENTS.md`, tier 3): an Astro\n * component emits the `<wc-*>` tag with the accessible fallback INSIDE it. So\n * `<Tree />` is the whole call — wrapping it in your own `<wc-tree>` nests two\n * elements on one tree. `astro.wraps` records which case each component is, because\n * it varies: `Tree` and `CookieConsent` wrap a web component, while `Details`,\n * `Drawer`, `Popover`, `NavShell` and `Subgrid` emit tier-1 markup with no web\n * component at all. That cannot be inferred from the taxonomy.\n */\n\n/** A pattern's CSS. `generated` means `design-system.json`'s `patterns.items`. */\nexport interface TierCss {\n /**\n * Hand-written partial, relative to `packages/core/css/` — usually\n * `patterns/<name>.css`, occasionally a root partial such as `layout.css`.\n * Absent when the pattern is generated CSS only.\n */\n partial?: string;\n /** Representative classes. Not exhaustive — the class reference enumerates. */\n classes: string[];\n /**\n * True when the pattern is **config-authored** — its CSS comes from\n * `patterns.items.<name>`, so it gets the token cascade, `states`, role variants\n * and `BASE_HOOK` override vars. False means a purely structural partial with\n * none of those.\n *\n * Note `patterns.items` is CONSUMER-authored: `defaultConfig()` ships only\n * `btn`/`cta`/`card`, and a consumer declares whatever else they need. So this\n * flag records which patterns are *of that kind* — the reference set is this\n * repo's own `src/design-system.json`, which is what the docs render from — not a\n * promise about any particular consumer's config.\n */\n generated: boolean;\n}\n\nexport interface TierWc {\n tag: string;\n /** In `elements.js`. False = its own bundle, or not shipped at all. */\n registered: boolean;\n /** What JS adds over the fallback. The reason the tier exists for this pattern. */\n adds: string;\n /** Set when the element ships somewhere other than `elements.js`. */\n bundle?: string;\n}\n\nexport interface TierAstro {\n /** Import specifier, e.g. `@getvitops/astro/components/Tree.astro`. */\n component: string;\n /**\n * `wc` — emits the `<wc-*>` tag with the fallback inside, so this one call is the\n * whole composition. `css` — emits tier-1 markup; there is no web component.\n */\n wraps: 'wc' | 'css';\n}\n\nexport interface TierEntry {\n css: TierCss;\n wc?: TierWc;\n /**\n * Astro components for this pattern. An array because a pattern can ship more\n * than one — `navshell` has both `NavShell` and `NavShellToggle`, since the\n * toggle must be placeable outside the shell.\n */\n astro?: TierAstro[];\n /** Bricks element `$name`, e.g. `vitops-carousel`. */\n bricks?: string;\n /** The one line an agent needs: what to actually write. */\n use: string;\n}\n\nconst c = (classes: string[], partial?: string, generated = false): TierCss => ({\n ...(partial ? { partial } : {}),\n classes,\n generated,\n});\n\n/**\n * Shorthand for the usual `@getvitops/astro/components/<name>.astro` export.\n *\n * Not every component lives under `components/` — `CookieConsent.astro` is exported\n * from the package root — so those are written out in full. The specifier must be\n * one a consumer can actually import: `tiers.test.ts` checks each against\n * `packages/astro/package.json`'s `exports`, because a wrong one is a copy-pasteable\n * import that fails only in the consumer's project.\n */\nconst a = (name: string, wraps: 'wc' | 'css'): TierAstro[] => [\n { component: `@getvitops/astro/components/${name}.astro`, wraps },\n];\n\nexport const TIERS: Record<string, TierEntry> = {\n // ── Patterns that span tiers: the composition actually matters here ────────\n tree: {\n css: c(\n ['tree', 'tree__item', 'tree__content', 'tree__toggle', 'tree__label'],\n 'patterns/tree.css',\n true,\n ),\n wc: {\n tag: 'wc-tree',\n registered: true,\n adds: 'filter, expand/collapse all, hash deep-linking',\n },\n astro: a('Tree', 'wc'),\n use: '`<Tree items={…} />` — it emits `<wc-tree>` itself, so do NOT add your own wrapper.',\n },\n carousel: {\n css: c(['carousel'], 'patterns/carousel.css', true),\n wc: {\n tag: 'wc-carousel',\n registered: true,\n adds: 'cloned slides for a seamless loop, autoplay, snap nav',\n },\n bricks: 'vitops-carousel',\n use: '`<wc-carousel>` around your slides; each child is a slide. Works unenhanced as a scroll-snap strip.',\n },\n entries: {\n css: c(['entries__table', 'entries__scroll', 'entries__nav'], 'patterns/table.css'),\n wc: {\n tag: 'wc-entries',\n registered: true,\n adds: 'parses heading + `<dl>` pairs into a table above a breakpoint',\n },\n bricks: 'vitops-entries',\n use: '`<wc-entries>` around `<h3>` + `<dl>` pairs. The tier-2 exemplar: semantic pairs with no JS, a table with it.',\n },\n copy: {\n css: c(['copy', 'copy__button', 'copy__icon', 'copy__tooltip'], 'patterns/copy.css'),\n wc: { tag: 'wc-copy', registered: true, adds: 'clipboard write plus success feedback' },\n bricks: 'vitops-copy-button',\n use: '`<wc-copy>` around the content and a `[data-copy]` button.',\n },\n dismissable: {\n css: c(['banner__close', 'notification__close'], 'patterns/banner.css'),\n wc: {\n tag: 'wc-dismissable',\n registered: true,\n adds: 'fade-out + removal, optional auto-dismiss',\n },\n bricks: 'vitops-dismissable',\n use: '`<wc-dismissable>` around any banner/notification containing a `[data-dismiss]` control.',\n },\n 'split-panel': {\n css: c(['splitter', 'splitter__panel', 'splitter__handle'], 'patterns/splitter.css'),\n wc: { tag: 'wc-split-panel', registered: true, adds: 'draggable divider between two panels' },\n bricks: 'vitops-split-panel',\n use: '`<wc-split-panel>` with two children. Unenhanced they simply stack.',\n },\n 'image-compare': {\n // Same partial as split-panel — one of the reasons this file is authored.\n css: c(\n ['image-compare', 'image-compare__before', 'image-compare__handle'],\n 'patterns/splitter.css',\n ),\n wc: {\n tag: 'wc-image-compare',\n registered: true,\n adds: 'drag handle revealing the before/after image',\n },\n bricks: 'vitops-image-compare',\n use: '`<wc-image-compare>` with two images. Both are visible without JS.',\n },\n marquee: {\n css: c(['marquee', 'marquee__content', 'marquee__item'], 'patterns/marquee.css'),\n wc: {\n tag: 'wc-marquee',\n registered: true,\n adds: 'fills the track with enough copies to scroll seamlessly',\n },\n use: '`<wc-marquee>` around one `.marquee__content`. Scrolls via CSS alone; JS only removes the seam.',\n },\n 'multi-field': {\n // NOT generated: the config pattern here is `forms`. This component sits over\n // forms markup, so it has no `patterns.items` entry, no roles and no states.\n css: c(['form-group', 'input-group', 'fieldset'], 'patterns/forms.css'),\n wc: { tag: 'wc-multi-field', registered: true, adds: 'add/remove repeating field rows' },\n bricks: 'vitops-multi-field',\n use: '`<wc-multi-field>` around a field template. One row submits fine with no JS.',\n },\n 'color-scheme-toggle': {\n css: c([], 'patterns/icon.css'),\n wc: {\n tag: 'wc-color-scheme-toggle',\n registered: true,\n adds: 'segmented light/dark/system control; persists the choice (consent-gated)',\n },\n bricks: 'vitops-color-scheme-toggle',\n use: '`<wc-color-scheme-toggle></wc-color-scheme-toggle>`. Renamed from `<color-scheme-toggle>` in 4.0. Shadow DOM, so it is absent rather than broken without JS.',\n },\n consent: {\n css: c(\n ['consent', 'consent__body', 'consent__options', 'consent__actions'],\n 'patterns/consent.css',\n ),\n wc: {\n tag: 'wc-consent',\n registered: false,\n bundle: '@getvitops/core/consent',\n adds: 'the permission gate itself — activates `type=\"text/plain\"` tags on grant',\n },\n // Exported from the package root, not `components/`.\n astro: [{ component: '@getvitops/astro/CookieConsent.astro', wraps: 'wc' }],\n use: '`<CookieConsent />`. Its own Lit-free bundle so a site needing consent does not download a rendering framework.',\n },\n 'theme-editor': {\n css: c(['ed-panel', 'ed-launch', 'ed-input'], 'patterns/theme-editor.css'),\n wc: {\n tag: 'wc-theme-editor',\n registered: false,\n bundle: '@getvitops/core/editor',\n adds: 'live `:root` token overrides, export as CSS or a config patch',\n },\n use: '`<wc-theme-editor manifest=\"…\">`. TOOLING, not a page pattern — the one deliberate tier-2 exception, quarantined in its own opt-in bundle.',\n },\n\n // ── editor-v2 track: defined, but shipped in no bundle ────────────────────\n //\n // Registered by their own modules and imported by nothing, so nothing can be\n // consuming them. They are listed because the guards require every\n // `customElements.define` to be accounted for — and because \"exists but is not\n // shipped\" is exactly the kind of thing a reader needs told, rather than\n // discovering the tag does nothing.\n 'color-wheel': {\n css: c([]),\n wc: {\n tag: 'wc-color-wheel',\n registered: false,\n adds: 'hue/chroma wheel input',\n bundle: '(none — editor-v2 track, not yet bundled)',\n },\n use: 'Not shipped. Registered but absent from every bundle, so the tag is inert in a consumer project.',\n },\n 'oklch-color-picker': {\n css: c([]),\n wc: {\n tag: 'wc-oklch-color-picker',\n registered: false,\n adds: 'OKLCH L/C/H picker',\n bundle: '(none — editor-v2 track, not yet bundled)',\n },\n use: 'Not shipped. See `color-wheel`.',\n },\n 'icon-picker': {\n css: c([], 'patterns/icon.css'),\n wc: {\n tag: 'wc-icon-picker',\n registered: false,\n adds: 'browses the semantic icon map for the configured set',\n bundle: '(none — editor-v2 track, not yet bundled)',\n },\n use: 'Not shipped. See `color-wheel`.',\n },\n 'typography-config': {\n css: c([]),\n wc: {\n tag: 'wc-typography-config',\n registered: false,\n adds: 'type role editor',\n bundle: '(none — editor-v2 track, not yet bundled)',\n },\n use: 'Not shipped. See `color-wheel`.',\n },\n\n // ── Astro-only conveniences over tier-1 markup (no web component) ──────────\n details: {\n css: c(['details', 'details-trigger', 'details-icon'], 'patterns/details.css', true),\n astro: a('Details', 'css'),\n use: '`<Details>` — or hand-write `<details>`. No JS at either tier; `::details-content` animates in CSS.',\n },\n drawer: {\n css: c(['drawer', 'drawer--start', 'drawer--end'], 'patterns/drawer.css', true),\n astro: a('Drawer', 'css'),\n use: '`<Drawer>` — `<dialog class=\"drawer\">` plus an Invoker Commands trigger. No JS.',\n },\n popover: {\n css: c(['popover', 'popover-trigger', 'popover-anchor'], 'patterns/popover.css', true),\n astro: a('Popover', 'css'),\n use: '`<Popover>` — native Popover API + CSS Anchor Positioning. No JS.',\n },\n navshell: {\n css: c(\n ['navshell', 'navshell__bar', 'navshell__panel', 'navshell-toggle'],\n 'patterns/navshell.css',\n ),\n astro: [...a('NavShell', 'css'), ...a('NavShellToggle', 'css')],\n use: '`<NavShell>` with a `nav` slot, plus `<NavShellToggle>` if the toggle must live outside the shell.',\n },\n subgrid: {\n css: c(['subgrid', 'subgrid-card', 'pricing-grid'], 'patterns/subgrid.css'),\n astro: a('Subgrid', 'css'),\n use: '`<Subgrid>` — emits `<ul class=\"subgrid\" role=\"list\">`; author `<li class=\"card subgrid-card\">` items yourself, so tranches align across the set.',\n },\n card: {\n css: c(['card'], 'patterns/card.css', true),\n wc: {\n tag: 'wc-cards',\n registered: true,\n adds: 'whole-card click that keeps the card text selectable',\n },\n astro: a('Cards', 'wc'),\n use: '`<Cards>` — it emits `<wc-cards>` itself, so do NOT add your own wrapper. `<Subgrid>` is the same grid without the click enhancement.',\n },\n icon: {\n css: c(['icon', 'icon-button', 'icon-mask'], 'patterns/icon.css'),\n astro: a('Icon', 'css'),\n bricks: 'vitops-icon',\n use: '`<Icon name=\"menu\" />`. Names are semantic and resolve per configured set; a name containing `:` passes through.',\n },\n\n // ── Bricks + CSS, no web component ────────────────────────────────────────\n split: {\n css: c(['split', 'split-1-2', 'split-reverse'], 'layout.css'),\n bricks: 'vitops-split',\n use: '`.split` plus a ratio class. Pure CSS; `md-split-1-2` for the responsive form.',\n },\n centered: {\n css: c(['centered', 'spotlight', 'breakout', 'fullbleed'], 'layout.css'),\n bricks: 'vitops-centered',\n use: '`.centered` as a track grid. Children land in `measure` — give it a track child to lay out inside.',\n },\n sitenav: {\n css: c(['sitenav', 'sitenav__link', 'sitenav--drawer-start'], 'patterns/sitenav.css'),\n bricks: 'vitops-sitenav',\n use: '`.sitenav` with `--bp-*` and a drawer direction. `<details>` + Invoker Commands, no JS.',\n },\n 'split-link': {\n css: c(['split-link', 'split-link__toggle', 'split-link__panel'], 'patterns/split-link.css'),\n bricks: 'vitops-split-link',\n use: '`.split-link` — a link plus a disclosure toggle. No JS.',\n },\n\n // ── CSS-only patterns ─────────────────────────────────────────────────────\n btn: {\n css: c(['btn'], undefined, true),\n use: '`<button>` gets it with no class; `.btn` carries it to other tags. `fill: false`, so states drive `color`.',\n },\n cta: {\n css: c(['cta', 'cta-danger'], undefined, true),\n use: '`.cta` on any element — usually `<a>`, since a CTA navigates. Filled, with role variants.',\n },\n link: {\n css: c(['link', 'skip-link', 'stretched-link', 'raised'], 'patterns/anchor-link.css', true),\n use: '`<a>` gets it at zero specificity; `.link` for other tags. `.stretched-link` makes one link cover its positioned ancestor (whole-card click, no JS — but the card text stops being selectable); `.raised` lifts content back above that overlay.',\n },\n badge: {\n css: c(['badge', 'badge-indicator'], 'patterns/tag.css', true),\n use: '`.badge` — a STATIC label. Use `tag` if it is dismissable or editable.',\n },\n tag: {\n css: c(['tag', 'tag__remove', 'tag__icon', 'tag-list'], 'patterns/tag.css', true),\n use: '`.tag` — an editable/dismissable label. Its group is `label`, not `tag`.',\n },\n status: {\n css: c(['status', 'status-dot--pulse'], 'patterns/tag.css', true),\n use: '`.status` with a role variant.',\n },\n tooltip: {\n css: c(['tooltip-trigger'], 'patterns/tooltip.css', true),\n use: '`.tooltip-trigger` — CSS only, anchor-positioned.',\n },\n dialog: {\n css: c(['dialog__header', 'dialog__body', 'dialog__footer'], 'patterns/dialog.css', true),\n use: 'Native `<dialog>` plus the `.dialog__*` parts. No JS beyond `showModal()`.',\n },\n dropdown: {\n css: c(['dropdown--show-on-hover', 'dropdown-menu'], 'patterns/dropdown.css', true),\n use: '`.dropdown` — Popover API based.',\n },\n notification: {\n css: c(\n ['notification', 'notification__title', 'notification__actions'],\n 'patterns/notification.css',\n true,\n ),\n use: '`.notification` with a role variant; wrap in `<wc-dismissable>` to make it dismissable.',\n },\n lightbox: {\n css: c(['lightbox', 'lightbox-dialog__content'], 'patterns/lightbox.css', true),\n use: '`.lightbox` thumbnails plus a `<dialog>`.',\n },\n comment: {\n css: c(['comment', 'comment__author', 'comment-thread'], 'patterns/comment.css', true),\n use: '`.comment` inside `.comment-thread`.',\n },\n tabs: {\n css: c(['tabs'], undefined, true),\n use: 'Generated pattern only; no structural partial and no component yet.',\n },\n nav: {\n css: c(['menu', 'navbar', 'nav-collapse', 'drawer-nav'], 'patterns/nav.css', true),\n use: '`.menu` / `.navbar`. See `navbar` and `navshell` for the newer shells.',\n },\n navbar: {\n css: c(['navbar', 'navbar--sticky', 'nav-items'], 'patterns/navbar.css'),\n use: '`.navbar` with `--start/--center/--end`.',\n },\n banner: {\n css: c(['banner', 'banner__content', 'banner__action'], 'patterns/banner.css', true),\n use: '`.banner`; wrap in `<wc-dismissable>` for a close button that works.',\n },\n table: {\n css: c(['table', 'table-wrapper'], 'patterns/table.css', true),\n use: '`.table` inside `.table-wrapper`. See `entries` for the responsive-to-table pattern.',\n },\n list: {\n css: c(['facet-list', 'filtered-list'], 'patterns/list.css', true),\n use: '`.facet-list` / `.filtered-list`.',\n },\n 'pull-quote': {\n css: c(['pull-quote', 'pull-quote__attribution'], 'patterns/pull-quote.css', true),\n use: '`.pull-quote`. Note the type role `quote` is separate.',\n },\n combobox: {\n css: c(['combobox', 'combobox__listbox', 'combobox__option'], 'patterns/combobox.css', true),\n use: 'CSS shell only — the Lit component is a TODO, so it is not interactive yet.',\n },\n forms: {\n css: c(['form-group', 'input-group', 'fieldset', 'custom-check'], 'patterns/forms.css', true),\n use: 'Wrap text controls in `.form-group` or `.input-group` — a bare `<input>` gets browser defaults.',\n },\n cluster: {\n css: c(['cluster', 'cluster-between', 'cluster-start'], 'patterns/cluster.css'),\n use: '`.cluster` plus an alignment variant.',\n },\n code: {\n css: c([], 'patterns/code.css'),\n use: 'Element selectors on `pre`/`code`; no class needed.',\n },\n grouped: {\n css: c(['group', 'group-inline', 'bordered'], 'patterns/grouped.css'),\n use: '`.group-inline` / `.group-block` to join adjacent controls.',\n },\n 'horizontal-scroll': {\n css: c(['horizontal-scroll'], 'patterns/horizontal-scroll.css'),\n use: '`.horizontal-scroll` for a snap strip.',\n },\n masonry: {\n css: c(['masonry', 'masonry__item'], 'patterns/masonry.css'),\n use: '`.masonry` — CSS columns based.',\n },\n media: {\n css: c(['media', 'media__figure', 'tile'], 'patterns/media.css'),\n use: '`.media` for a figure/body pair; `.tile` for the stacked form.',\n },\n overlay: { css: c(['overlay'], 'patterns/overlay.css'), use: '`.overlay` for a scrim.' },\n reveal: {\n css: c(['reveal', 'reveal-fade', 'reveal-h'], 'patterns/reveal.css'),\n use: '`.reveal` — scroll-driven, no JS. Hosts the `interpolate-size` that `<details>` animation needs.',\n },\n 'scroll-based': {\n css: c(['parallax', 'scroll-progress', 'scroll-spy'], 'patterns/scroll-based.css'),\n use: 'Scroll-timeline driven; no JS.',\n },\n 'scroll-target': {\n css: c(['scroll-target-group', 'toc-sidebar'], 'patterns/scroll-target.css'),\n use: '`.scroll-target-group` for `:target-current` highlighting.',\n },\n separator: {\n css: c(['separator', 'separator__text', 'separator__ornament'], 'patterns/separator.css'),\n use: '`.separator`, optionally with text or an ornament.',\n },\n stack: {\n css: c(['stack', 'stack__card'], 'patterns/stack.css'),\n use: '`.stack` for overlapping cards.',\n },\n sticky: {\n css: c(['sticky', 'sticky-header', 'sticky-nav'], 'patterns/sticky.css'),\n use: '`.sticky-header` etc. Pure CSS.',\n },\n svg: {\n css: c(['svg-container', 'svg-shape', 'svg-animated'], 'patterns/svg.css'),\n use: '`.svg-*` helpers for inline SVG.',\n },\n 'text-effects': {\n css: c(\n ['typing', 'text-highlight', 'text-gradient-animate', 'text-stagger'],\n 'patterns/text-effects.css',\n ),\n use: '`.typing`, `.text-highlight`, … CSS animation only.',\n },\n};\n\n/** Pattern names, sorted — a stable order for docs and tests. */\nexport const TIER_NAMES: readonly string[] = Object.keys(TIERS).sort();\n\n/** Every `wc-*` tag the manifest knows, whether shipped in `elements.js` or not. */\nexport function tierTags(): { tag: string; registered: boolean; pattern: string }[] {\n return Object.entries(TIERS)\n .filter(([, e]) => e.wc)\n .map(([pattern, e]) => ({ tag: e.wc!.tag, registered: e.wc!.registered, pattern }));\n}\n\n/**\n * The projection axis: four keys, THREE tiers.\n *\n * `astro` and `bricks` are both the platform-wrapper tier — siblings chosen by\n * platform, not levels 3 and 4. They are separate keys because they are separate\n * packages with separate tables, and no project uses both. Anything rendering a\n * tier NUMBER must map them to the same one; deriving it from this union's order\n * is what put Bricks at \"tier 4\" on the docsite.\n */\nexport type Tier = 'css' | 'wc' | 'astro' | 'bricks';\n\n/** A pattern paired with its entry — what one tier's projection iterates. */\nexport interface TierProjection {\n name: string;\n entry: TierEntry;\n}\n\n/**\n * The patterns one tier provides, in `TIER_NAMES` order.\n *\n * Every renderer goes through this rather than filtering `TIERS` itself: the docs\n * bundle projects every tier into one table for agents, the docsite projects\n * each tier as its own page for humans, and they must agree about which patterns\n * are in a tier. Five copies of `.filter(e => e.wc)` would agree until one of them\n * didn't.\n *\n * `css` needs a predicate rather than a presence check, which is the non-obvious\n * part. `TierEntry.css` is required, so *every* entry has one — including the\n * editor-v2 track, whose entries carry `c([])`: no partial, no classes, not\n * generated. Treating the field's presence as membership would list four patterns\n * on the CSS page with nothing to show for them, and `color-wheel` genuinely has\n * no CSS. The other three tiers are optional fields, so presence is the test.\n */\nexport function tierPatterns(tier: Tier): TierProjection[] {\n const has = (e: TierEntry): boolean => {\n switch (tier) {\n case 'css':\n return !!e.css.partial || e.css.classes.length > 0 || e.css.generated;\n case 'wc':\n return !!e.wc;\n case 'astro':\n return !!e.astro?.length;\n case 'bricks':\n return !!e.bricks;\n }\n };\n return TIER_NAMES.filter((name) => has(TIERS[name]!)).map((name) => ({\n name,\n entry: TIERS[name]!,\n }));\n}\n","/**\n * OKF documentation bundle generator (ported from the repo's `generate-docs.ts`).\n *\n * Pure: `generateDocs(ds, assetsDir)` returns a `{ relPath: markdown }` map for the\n * Open Knowledge Format tree (top index, css/, bricks/), reading the Bricks element\n * PHP from `<assetsDir>/bricks/elements`. No filesystem writes — the caller decides\n * where the bundle lands (e.g. `<outDir>/docs`).\n */\nimport { readFileSync, readdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { jsonSchema, SCHEMA_URL, type DesignSystem } from './schema.ts';\nimport { configJsonSchema, CONFIG_SCHEMA_URL } from './config.ts';\nimport { BASE_HOOK, DARK_SEL, REQUIRED_ROLES, SYSTEM_DARK_SEL, TW_CLASH } from './shared.ts';\nimport { expandPalette } from './tokens.ts';\nimport { TIERS, TIER_NAMES, tierPatterns } from './tiers.ts';\n\nconst DS_PATH = 'design-system.json';\n/** The `resource` a config-reference doc points at. Consumers rename it freely. */\nconst CONFIG_PATH = 'site.json';\n\n// Curated element display order (by $name, sans the vitops- prefix). Unlisted\n// elements fall to the end alphabetically so new ones still appear.\nconst ORDER = [\n 'split',\n 'centered',\n 'carousel',\n 'wc-color-scheme-toggle',\n 'wc-copy',\n 'dismissable',\n 'entries',\n 'image-compare',\n 'sitenav',\n 'wc-multi-field',\n 'split-link',\n 'split-panel',\n];\n\n// ── PHP array-literal parser ─────────────────────────────────────────────────\ntype Json = string | number | boolean | null | Json[] | { [k: string]: Json };\n\ninterface Tok {\n t: 'str' | 'num' | 'id' | 'punc' | 'arrow';\n v: string;\n}\n\nfunction tokenize(src: string): Tok[] {\n const toks: Tok[] = [];\n let i = 0;\n const n = src.length;\n while (i < n) {\n const c = src[i] as string;\n if (c === ' ' || c === '\\t' || c === '\\n' || c === '\\r') {\n i++;\n continue;\n }\n if (c === '/' && src[i + 1] === '/') {\n while (i < n && src[i] !== '\\n') i++;\n continue;\n }\n if (c === '#') {\n while (i < n && src[i] !== '\\n') i++;\n continue;\n }\n if (c === '/' && src[i + 1] === '*') {\n i += 2;\n while (i < n && !(src[i] === '*' && src[i + 1] === '/')) i++;\n i += 2;\n continue;\n }\n if (c === \"'\" || c === '\"') {\n const quote = c;\n i++;\n let s = '';\n while (i < n && src[i] !== quote) {\n if (src[i] === '\\\\' && i + 1 < n) {\n const next = src[i + 1];\n s += next === 'n' ? '\\n' : next === 't' ? '\\t' : next;\n i += 2;\n } else {\n s += src[i++];\n }\n }\n i++;\n toks.push({ t: 'str', v: s });\n continue;\n }\n if (c === '=' && src[i + 1] === '>') {\n toks.push({ t: 'arrow', v: '=>' });\n i += 2;\n continue;\n }\n if ('[](){},'.includes(c)) {\n toks.push({ t: 'punc', v: c });\n i++;\n continue;\n }\n if (\n (c >= '0' && c <= '9') ||\n (c === '-' && (src[i + 1] as string) >= '0' && (src[i + 1] as string) <= '9')\n ) {\n let s = c;\n i++;\n while (i < n && (src[i] as string) >= '0' && (src[i] as string) <= '9') s += src[i++];\n toks.push({ t: 'num', v: s });\n continue;\n }\n if (/[A-Za-z_\\\\]/.test(c)) {\n let s = c;\n i++;\n while (i < n && /[A-Za-z0-9_\\\\]/.test(src[i] as string)) s += src[i++];\n toks.push({ t: 'id', v: s });\n continue;\n }\n i++;\n }\n return toks;\n}\n\nclass Parser {\n p = 0;\n toks: Tok[];\n constructor(toks: Tok[]) {\n this.toks = toks;\n }\n peek(): Tok | undefined {\n return this.toks[this.p];\n }\n next(): Tok | undefined {\n return this.toks[this.p++];\n }\n parseValue(): Json {\n const t = this.peek();\n if (!t) return null;\n if (t.t === 'str') {\n this.next();\n return t.v;\n }\n if (t.t === 'num') {\n this.next();\n return Number(t.v);\n }\n if (t.t === 'id') {\n this.next();\n if (t.v === 'true') return true;\n if (t.v === 'false') return false;\n if (t.v === 'null') return null;\n if (this.peek()?.t === 'punc' && this.peek()?.v === '(') {\n this.next();\n if (t.v === 'array') return this.parseBody(')');\n const args = this.parseCallArgs();\n return args.find((a) => typeof a === 'string') ?? args[0] ?? '';\n }\n return t.v;\n }\n if (t.t === 'punc' && t.v === '[') {\n this.next();\n return this.parseBody(']');\n }\n if (t.t === 'punc' && t.v === '(') {\n this.next();\n return this.parseBody(')');\n }\n this.next();\n return null;\n }\n private parseCallArgs(): Json[] {\n const args: Json[] = [];\n while (this.peek() && !(this.peek()!.t === 'punc' && this.peek()!.v === ')')) {\n args.push(this.parseValue());\n if (this.peek()?.t === 'punc' && this.peek()?.v === ',') this.next();\n }\n this.next();\n return args;\n }\n private parseBody(close: string): Json {\n const list: Json[] = [];\n const map: Record<string, Json> = {};\n let keyed = false;\n while (this.peek() && !(this.peek()!.t === 'punc' && this.peek()!.v === close)) {\n const first = this.parseValue();\n if (this.peek()?.t === 'arrow') {\n this.next();\n const val = this.parseValue();\n // PHP array keys are scalars; stringify objects defensively.\n map[typeof first === 'object' && first !== null ? JSON.stringify(first) : String(first)] =\n val;\n keyed = true;\n } else {\n list.push(first);\n }\n if (this.peek()?.t === 'punc' && this.peek()?.v === ',') this.next();\n }\n this.next();\n return keyed ? map : list;\n }\n}\n\nfunction parsePhpLiteral(text: string): Json {\n return new Parser(tokenize(text)).parseValue();\n}\n\n// ── Source-region helpers ────────────────────────────────────────────────────\nfunction matchBalanced(src: string, open: number): number {\n const pairs: Record<string, string> = { '(': ')', '[': ']', '{': '}' };\n const stack: string[] = [];\n let i = open;\n const n = src.length;\n while (i < n) {\n const c = src[i] as string;\n if (c === '/' && src[i + 1] === '/') {\n while (i < n && src[i] !== '\\n') i++;\n continue;\n }\n if (c === '/' && src[i + 1] === '*') {\n i += 2;\n while (i < n && !(src[i] === '*' && src[i + 1] === '/')) i++;\n i += 2;\n continue;\n }\n if (c === \"'\" || c === '\"') {\n i++;\n while (i < n && src[i] !== c) {\n if (src[i] === '\\\\') i++;\n i++;\n }\n i++;\n continue;\n }\n if (c in pairs) stack.push(pairs[c] as string);\n else if (c === ')' || c === ']' || c === '}') {\n if (stack.pop() !== c) {\n /* unbalanced — best effort */\n }\n if (stack.length === 0) return i + 1;\n }\n i++;\n }\n return n;\n}\n\nfunction methodBody(src: string, name: string): string | null {\n const m = new RegExp(`function\\\\s+${name}\\\\s*\\\\([^)]*\\\\)`).exec(src);\n if (!m) return null;\n const brace = src.indexOf('{', m.index + m[0].length);\n if (brace < 0) return null;\n const end = matchBalanced(src, brace);\n return src.slice(brace + 1, end - 1);\n}\n\nfunction literalAt(src: string, fromIdx: number): { text: string; end: number } | null {\n let i = fromIdx;\n while (i < src.length && /\\s/.test(src[i] as string)) i++;\n let open: number;\n if (src[i] === '[') open = i;\n else if (src.startsWith('array', i)) open = src.indexOf('(', i);\n else return null;\n const end = matchBalanced(src, open);\n return { text: src.slice(i, end), end };\n}\n\n// ── Per-element extraction ───────────────────────────────────────────────────\ninterface Control {\n key: string;\n def: Record<string, Json>;\n}\ninterface Element {\n name: string;\n label: string;\n nestable: boolean;\n docblock: string;\n controls: Control[];\n cssClass: string | null;\n children: string[];\n keywords: string[];\n}\n\nfunction firstString(re: RegExp, src: string): string | null {\n const m = re.exec(src);\n return m ? (m[1] ?? null) : null;\n}\n\nfunction extractDocblock(src: string): string {\n const m = /\\/\\*\\*([\\s\\S]*?)\\*\\//.exec(src);\n if (!m) return '';\n const lines = (m[1] as string)\n .split('\\n')\n .map((l) => l.replace(/^\\s*\\*?\\s?/, '').replace(/\\s+$/, ''));\n while (lines.length && lines[0] === '') lines.shift();\n if (lines.length && /Bricks Builder\\)\\./.test(lines[0] as string)) lines.shift();\n const owned = lines.findIndex((l) => l.startsWith('Owned by the framework repo'));\n const kept = (owned >= 0 ? lines.slice(0, owned) : lines).map((l) => l.replace(/^•\\s*/, '- '));\n while (kept.length && kept[kept.length - 1] === '') kept.pop();\n while (kept.length && kept[0] === '') kept.shift();\n return kept.join('\\n');\n}\n\nfunction extractControls(src: string): Control[] {\n const body = methodBody(src, 'set_controls');\n if (!body) return [];\n const controls: Control[] = [];\n const re = /\\$this->controls\\[\\s*'([^']+)'\\s*\\](\\[\\s*'([^']+)'\\s*\\])?\\s*=\\s*/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(body))) {\n const key = m[1] as string;\n if (m[2]) continue;\n const lit = literalAt(body, m.index + m[0].length);\n if (!lit) continue;\n const def = parsePhpLiteral(lit.text);\n if (def && typeof def === 'object' && !Array.isArray(def))\n controls.push({ key, def: def as Record<string, Json> });\n re.lastIndex = lit.end;\n }\n return controls;\n}\n\nfunction extractChildren(src: string): string[] {\n const body = methodBody(src, 'get_nestable_children');\n if (!body) return [];\n const labels: string[] = [];\n const re = /'label'\\s*=>\\s*esc_html__\\(\\s*'([^']*)'/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(body))) labels.push(m[1] as string);\n return labels;\n}\n\nfunction extractKeywords(src: string): string[] {\n const body = methodBody(src, 'get_keywords');\n if (!body) return [];\n const ret = /return\\s+/.exec(body);\n if (!ret) return [];\n const lit = literalAt(body, ret.index + ret[0].length);\n if (!lit) return [];\n const arr = parsePhpLiteral(lit.text);\n return Array.isArray(arr) ? arr.filter((x): x is string => typeof x === 'string') : [];\n}\n\nfunction parseElement(src: string): Element | null {\n const name = firstString(/public\\s+\\$name\\s*=\\s*'vitops-([^']+)'/, src);\n if (!name) return null;\n return {\n name,\n label:\n firstString(/function get_label\\(\\)[\\s\\S]*?return\\s+esc_html__\\(\\s*'([^']*)'/, src) ?? name,\n nestable: /public\\s+\\$nestable\\s*=\\s*true/.test(src),\n docblock: extractDocblock(src),\n controls: extractControls(src),\n cssClass: firstString(\n /\\$this->controls\\[\\s*'_cssClasses'\\s*\\]\\[\\s*'default'\\s*\\]\\s*=\\s*'([^']*)'/,\n src,\n ),\n children: extractChildren(src),\n keywords: extractKeywords(src),\n };\n}\n\n// ── Markdown rendering ───────────────────────────────────────────────────────\n/** Stringify a parsed-PHP Json value for prose (objects → JSON, not [object Object]). */\nconst asText = (v: Json | undefined): string =>\n v == null ? '' : typeof v === 'object' ? JSON.stringify(v) : String(v);\n\nfunction controlLine(c: Control): string {\n const def = c.def;\n if (def.type === 'info') return `- _Note:_ ${asText(def.content)}`;\n const label = (def.label as string) || c.key;\n const options =\n def.options && typeof def.options === 'object' && !Array.isArray(def.options)\n ? (def.options as Record<string, string>)\n : null;\n const meta: string[] = [];\n let type = (def.type as string) || 'text';\n if (def.units === true) type += '+units';\n meta.push(type);\n if (def.default !== undefined) {\n const raw = asText(def.default);\n const shown = options && options[raw] ? options[raw] : raw;\n meta.push(`default \\`${shown}\\``);\n }\n if (def.placeholder !== undefined && def.placeholder !== '')\n meta.push(`placeholder \\`${asText(def.placeholder)}\\``);\n if (def.min !== undefined || def.max !== undefined)\n meta.push(\n `range ${def.min != null ? asText(def.min) : '–'}–${def.max != null ? asText(def.max) : '∞'}`,\n );\n const tail: string[] = [];\n if (def.description) tail.push(asText(def.description));\n if (options)\n tail.push(\n `Options: ${Object.values(options)\n .map((o) => `\\`${o}\\``)\n .join(', ')}.`,\n );\n if (Array.isArray(def.css) && def.css.length) {\n const first = def.css[0];\n if (first && typeof first === 'object' && !Array.isArray(first) && 'property' in first)\n tail.push(`Bound to \\`${asText((first as Record<string, Json>).property)}\\`.`);\n }\n if (def.type === 'repeater' && def.fields && typeof def.fields === 'object') {\n const fields = Object.values(def.fields as Record<string, Json>)\n .map((f) =>\n f && typeof f === 'object' && !Array.isArray(f)\n ? asText((f as Record<string, Json>).label)\n : null,\n )\n .filter(Boolean);\n if (fields.length) tail.push(`Fields: ${fields.join(', ')}.`);\n }\n const head = `- **${label}** (${meta.join(', ')})`;\n return tail.length ? `${head} — ${tail.join(' ')}` : head;\n}\n\nfunction renderElement(el: Element): string {\n const out: string[] = [];\n const nest = el.nestable ? 'nestable' : 'not nestable';\n out.push(`## ${el.label} — \\`vitops-${el.name}\\` · ${nest}`);\n out.push('');\n if (el.docblock) {\n out.push(el.docblock);\n out.push('');\n }\n const real = el.controls.filter((c) => c.def.type !== 'info');\n if (real.length) {\n out.push('**Controls**');\n out.push('');\n for (const c of el.controls) out.push(controlLine(c));\n out.push('');\n } else {\n const notes = el.controls.filter((c) => c.def.type === 'info');\n if (notes.length) {\n for (const c of notes) out.push(controlLine(c));\n out.push('');\n }\n }\n if (el.cssClass) {\n out.push(\n `**Base CSS class:** \\`${el.cssClass}\\` (applied automatically; add ratio/modifier classes alongside it in the element's \"CSS classes\" field).`,\n );\n out.push('');\n }\n if (el.children.length) {\n out.push(`**Seeded children:** ${el.children.join(', ')}.`);\n out.push('');\n }\n if (el.keywords.length) {\n out.push(`**Keywords:** ${el.keywords.filter((k) => k !== 'vitops').join(', ')}.`);\n out.push('');\n }\n return out.join('\\n');\n}\n\n// ── OKF helpers ──────────────────────────────────────────────────────────────\ninterface Frontmatter {\n type: string;\n title: string;\n description: string;\n resource?: string;\n tags?: string[];\n}\nfunction frontmatter(fm: Frontmatter): string {\n const q = (s: string) => `\"${s.replace(/\"/g, '\\\\\"')}\"`;\n const lines = [\n `type: ${q(fm.type)}`,\n `title: ${q(fm.title)}`,\n `description: ${q(fm.description)}`,\n ];\n if (fm.resource) lines.push(`resource: ${q(fm.resource)}`);\n if (fm.tags) lines.push(`tags: [${fm.tags.join(', ')}]`);\n lines.push('generator: \"@getvitops/generator\"');\n return `---\\n${lines.join('\\n')}\\n---`;\n}\n\nconst INDEX_NOTE = `<!-- GENERATED by @getvitops/generator — do not edit; regenerate with \\`vitops generate\\`. -->`;\n\nconst ELEMENTS_FRONTMATTER = frontmatter({\n type: 'Bricks Elements Reference',\n title: 'Vitops — Bricks Builder elements reference',\n description:\n 'Every repo-owned Bricks element, its controls, defaults, seeded children and keywords, for driving the Bricks Builder UI.',\n resource: 'bricks/elements',\n tags: ['bricks', 'wordpress', 'elements', 'design-system'],\n});\n\nconst ELEMENTS_PREAMBLE = `${ELEMENTS_FRONTMATTER}\n\n# Vitops — Bricks Builder elements reference\n\nContext for driving the Bricks Builder UI (e.g. Claude for Chrome). Every section below\nis generated from the element's own source, so this reference always matches the elements\ncurrently deployed. See also the CSS class vocabulary in [/css/classes.md](../css/classes.md)\nand the integration guidance in [/bricks/index.md](index.md).\n\n## How they appear in the builder\n\n- The elements register from \\`dist/bricks/load.php\\` and group under a **\"Vitops\"** category\n pinned to the **top** of the element panel. Insert one by searching its **label** (e.g.\n \"Split\", \"Carousel\") or any of its **keywords** (listed per element).\n- Two rendering families:\n - **Web-component elements** render a Lit custom element (\\`<wc-*>\\`, \\`<wc-copy>\\`, …)\n from \\`dist/elements.js\\` and progressively enhance. A few (Image Compare, Split Panel)\n show their children stacked in the builder canvas until the client-side upgrade runs —\n that is expected, not broken.\n - **CSS-pattern elements** (Split, Centered, Menu, Split Link) render plain markup styled\n by the framework CSS — no JS dependency.\n- **Nestable** elements accept child elements dropped into them; some seed starter children\n (listed as \"Seeded children\"). **Non-nestable** elements are configured entirely through\n their controls.\n\n## Configuring layout\n\nSome layout is set through **controls**; some through **CSS classes typed into the element's\nbuilt-in \"CSS classes\" field** (called out per element as modifier classes). Responsive\nsuffixes on those classes engage from a container breakpoint: \\`-sm\\` = 30rem, \\`-md\\` = 48rem,\n\\`-lg\\` = 64rem, \\`-xl\\` = 80rem.\n\nEach control below lists its type, default/placeholder, any select options, and the CSS\ncustom property it writes (when it drives one). Info notes flagged _Note:_ carry the\nmodifier-class and structural guidance from the element itself.\n\n---\n`;\n\nfunction renderElementsDoc(elementsDir: string): string {\n const files = existsSync(elementsDir)\n ? readdirSync(elementsDir).filter((f) => f.endsWith('.php'))\n : [];\n const elements: Element[] = [];\n for (const f of files) {\n try {\n const el = parseElement(readFileSync(join(elementsDir, f), 'utf8'));\n if (el) elements.push(el);\n } catch {\n /* skip unparseable element */\n }\n }\n elements.sort((a, b) => {\n const ia = ORDER.indexOf(a.name);\n const ib = ORDER.indexOf(b.name);\n if (ia >= 0 && ib >= 0) return ia - ib;\n if (ia >= 0) return -1;\n if (ib >= 0) return 1;\n return a.name.localeCompare(b.name);\n });\n const body = elements.map(renderElement).join('\\n---\\n\\n');\n return `${ELEMENTS_PREAMBLE}\\n${body}`;\n}\n\n// ── CSS framework reference (rule-summarized, from the config) ────────────────\nconst code = (xs: string[]) => xs.map((x) => `\\`${x}\\``).join(', ');\n\nfunction renderCssClasses(ds: DesignSystem): string {\n const expanded = expandPalette(ds.colors.palette as Record<string, unknown>);\n const ramps = Object.keys(expanded);\n const roles = Object.keys(ds.colors.roles ?? {});\n const utils = ds.colors.utilities ?? ['bg', 'text', 'icon', 'border'];\n const typeRoles = Object.keys(ds.typography?.roles ?? {});\n const shadows = Object.keys(ds.shadows ?? {});\n const effects = Object.keys(ds.animations?.effects ?? {});\n // Split by keyframe family, because only composite/paint effects get the\n // hover-/focus-/active- state variants — `.transition` deliberately doesn't\n // transition `height`, so a `hover-size-grow` would be a class that resolves\n // to nothing. Listing every effect under \"with the state prefixes above\" is\n // what sent the docs site rendering exactly that.\n const stateful = Object.entries(ds.animations?.effects ?? {})\n .filter(([, e]) => e.kf === 'composite' || e.kf === 'paint')\n .map(([name]) => name);\n const keyframeOnly = effects.filter((name) => !stateful.includes(name));\n const items = (ds.patterns?.items ?? {}) as Record<\n string,\n { roles?: string[]; default_role?: string }\n >;\n const patterns = Object.keys(items);\n const patternRoles = Array.from(\n new Set(\n Object.values(items).flatMap(\n (p) => [p.default_role, ...(p.roles ?? [])].filter(Boolean) as string[],\n ),\n ),\n );\n const spaceNames = ds.spaceScale?.names ?? [];\n const typeNames = ds.typeScale?.names ?? [];\n const families = Object.keys(ds.typography?.families ?? {});\n const radii = Object.keys(ds.patterns?.radii ?? {});\n\n return `${frontmatter({\n type: 'CSS Framework Reference',\n title: 'Vitops CSS framework — class vocabulary',\n description:\n 'Every utility and component class in the Vitops CSS framework, stated as a naming rule over the design tokens it expands.',\n resource: DS_PATH,\n tags: ['css', 'utilities', 'patterns', 'design-system'],\n })}\n\n# Vitops CSS framework — class vocabulary (LLM reference)\n\nA variable-driven CSS framework. Classes encode the design system's **tokens** (colour,\ntype, space, shadow), **responsive grammar**, and **interaction states** — so styling with\nthese classes stays consistent and theme-/dark-mode-aware. Prefer them over hand-written\nCSS or ad-hoc property values.\n\nThis is a **rule reference**, not an exhaustive list: each family below is a naming rule\nplus the set of tokens it expands over. Applying a rule to any listed token yields a valid\nclass (e.g. rule \\`bg-<color>\\` + colour \\`pine-xl\\` → \\`bg-pine-xl\\`).\n\nThe tokens themselves are authored in \\`design-system.json\\` — see\n[/authoring.md](../authoring.md); the systems behind them are explained in\n[/concepts/](../concepts/index.md); per-format output differences (including which of\nthese utilities Tailwind provides natively) in [/formats.md](../formats.md).\n\n## Responsive & state variant grammar\n\nEvery utility accepts a **container-breakpoint prefix**; animation utilities also accept a\n**state prefix**. In CSS/Bricks the separator is \\`-\\`; in Tailwind it is \\`:\\` / \\`@\\`.\n\n| Intent | CSS / Bricks | Tailwind |\n| ----------------- | -------------------------- | ----------------------------------------- |\n| responsive split | \\`md-split-1-2\\` | \\`@md:split-1-2\\` |\n| responsive align | \\`md-items-center\\` | \\`@md:items-center\\` |\n| hover effect | \\`transition hover-fade-in\\` | \\`transition fade-in hover:flip-fade-in\\` |\n\n- Breakpoint prefixes (bare): \\`sm-\\` = 30rem, \\`md-\\` = 48rem, \\`lg-\\` = 64rem, \\`xl-\\` = 80rem.\n- State prefixes (animation effects only): \\`hover-\\`, \\`active-\\`, \\`focus-\\`, and \\`flip-<effect>\\`\n (plays the effect in reverse on toggle). Effects require \\`transition\\` on the element.\n\n## Foundations — read this before writing any page markup\n\nSix classes carry the structure of almost every page. They are not a starting suggestion\nyou refine into hand-written CSS; **they are the answer**, and reaching past them is the\nsingle most common way a page drifts off the design system. Each line below is the\ntemptation followed by what to write instead.\n\n| If you are about to write… | Write this instead |\n| -------------------------------------------------------------- | ------------------------------------------------------ |\n| a \\`wrap\\` / \\`wrapper\\` / \\`container\\` / \\`inner\\` class | **\\`centered\\`** — never invent a container class |\n| \\`max-width\\` + \\`margin-inline: auto\\` | **\\`centered\\`** |\n| \\`padding-block\\` on a section, to space it from the next | **\\`region\\`** |\n| margins between headings, paragraphs and lists | **\\`rhythm\\`** on the container |\n| \\`display: grid\\` + \\`grid-template-columns: repeat(n, 1fr)\\` | **\\`subgrid\\`** — see below, this is the missed one |\n| \\`grid-template-columns: repeat(auto-fit, minmax(…))\\` | **\\`grid-auto\\`** (or \\`subgrid\\`, see below) |\n| \\`display: flex\\` + \\`gap\\` for a row of buttons/badges/meta | **\\`cluster\\`** (or \\`flex\\` + \\`items-*\\` utilities) |\n\n**The container is \\`centered\\`, and it is not a max-width box.** It is a grid of *named\ntracks*, so a child opts into a wider track (\\`breakout\\`, \\`spotlight\\`, \\`fullbleed\\`) without\nthe parent knowing. A hand-rolled \\`.wrap\\` renders the same on the happy path and then has\nno answer for the full-bleed image, which is why the escape from it is always more\nhand-written CSS. There is **no case** where a bespoke container class is the right call.\n\n**Multiple cards means \\`subgrid\\`, essentially always.** This is the most under-used class in\nthe framework, and the reason is that a plain \\`grid\\` *looks* correct: it aligns the outer\nboxes. What it cannot do is align the tranches **inside** them — so across three cards the\nheadings sit at three different heights, the bodies start at three different points, and the\nfooters float wherever the copy ended. \\`subgrid\\` re-declares the parent's row tracks on every\nitem, so head / body / footer land on shared row lines no matter how much content each card\nholds. If the answer to \"is this a repeated set of things with internal structure\" is yes,\nthis is the class.\n\n**The one honest alternative is \\`grid-auto\\`** — an auto-fit track (\\`--grid-min\\`, \\`--grid-gap\\`)\nwhere the column count is content-driven. Use it when the items have **no internal tranches to\nalign**: a bare image gallery, a logo wall, a row of icons. The moment an item has an eyebrow\nand a heading and a footer, \\`subgrid\\` is the one that makes them line up. Never hand-write\n\\`repeat(auto-fit, minmax(…))\\` — that is \\`grid-auto\\`.\n\n## Layout & structure\n\n- **\\`centered\\`** — named-track grid centering content in the reading \\`measure\\` track.\n Widen a **direct child** by adding \\`breakout\\`, \\`spotlight\\`, or \\`fullbleed\\` (each\n breakpoint-prefixable) to that child. Track widths are set via \\`--width-measure\\` /\n \\`--width-breakout\\` / \\`--width-spotlight\\` and \\`--gutter\\`.\n- **\\`rhythm\\`** — relationship-based vertical spacing (margins between headings, paragraphs,\n lists, media) driven by the space scale. Usually paired with \\`centered\\`.\n- **\\`region\\`** — vertical rhythm *between sections* (fluid \\`padding-block\\`, tunable with\n \\`--region-space\\` / \\`--region-space-min\\` / \\`--region-space-max\\`). Goes on the section;\n \\`centered\\` goes on the container inside it. \\`rhythm\\` handles flow **within** a region.\n- **\\`subgrid\\`** — the class for any repeated set of items with internal structure: cards,\n pricing tiers, feature panels. Items share the parent's row tracks, so each item's\n tranches (head / body / footer) align across the whole set — which a plain \\`grid\\`\n cannot do. **Reach for this whenever there is more than one card.**\n - Columns: \\`--subgrid-cols\\` (default 3) or \\`subgrid-cols-{1,2,3,4}\\`; tranches per item:\n \\`--subgrid-row-span\\` (default 2) or \\`subgrid-rows-{2,3,4}\\` — this must match how many\n row bands each item actually contains.\n - \\`subgrid-responsive\\` collapses to 2 columns under 60rem and 1 under 40rem.\n - Gaps: \\`--subgrid-gap\\` (between columns *and* between tranches) and \\`--subgrid-row-gap\\`\n (extra space between wrapped rows of items only).\n - \\`subgrid-card\\` is the matching item: \\`--subgrid-card-rows\\` tranches, with\n \\`subgrid-card__media\\` (bleeds to the card edge) and \\`subgrid-card__footer\\`\n (pinned to the last row band, so CTAs line up across the set).\n - It is markerless when it is a \\`ul\\`/\\`ol\\` — and a set of cards **is** a list, so prefer\n \\`<ul class=\"subgrid\" role=\"list\">\\` with \\`<li>\\` items over a stack of \\`<div>\\`s.\n **\\`role=\"list\"\\` is not optional here.** Safari + VoiceOver stop announcing a marker-less\n \\`<ul>\\` as a list, so the marker reset silently costs the semantics the \\`<ul>\\` was chosen\n for. \\`<Subgrid>\\` adds it for you; hand-written markup must say it.\n - **When the whole card is a link, the card is still the item**, and there are two ways to\n do it. Both keep the accessible name on real text rather than on a whole card of it.\n | Want | Use |\n | -------------------------------------------- | -------------------------------------------- |\n | no JS at all | \\`stretched-link\\` — **text not selectable** |\n | selectable text and a clickable card | \\`<Cards>\\` / \\`<wc-cards>\\` — needs JS |\n - \\`stretched-link\\` goes on a link **inside** the card (usually the heading); its\n \\`::after\\` covers the card. \\`subgrid-card\\` already carries the \\`position: relative\\` it\n resolves against; on a bare \\`card\\`, add \\`relative\\`. Anything else interactive in the\n card needs **\\`raised\\`** to sit above the overlay — \\`relative\\` alone is not enough,\n because a positioned element at \\`z-index: auto\\` does not rise above an explicit one.\n The cost is inherent: the overlay takes the pointer-drag, so the card's text can no\n longer be selected.\n - \\`<Cards>\\` wraps the list in \\`<wc-cards>\\`, which adds no overlay and instead tells a\n click apart from the end of a drag. Text stays selectable; with no JS the card's own\n link still works, and the pointer cursor only appears once the element has upgraded.\n - **Never layer the two** — the overlay wins, so you lose selection and the JS never\n runs. \\`vitops lint\\` reports the combination.\n **\\`<li><a class=\"card\">\\` is the wrong shape and it renders fine**, which is why it keeps\n getting written: the \\`<li>\\` is the grid item, so the anchor is an ordinary block inside it\n and the tranches within the anchor never reach the parent's shared row lines — the\n alignment subgrid exists for silently does not happen, and the anchor does not fill the\n cell either. Putting the anchor in the grid's place instead (\\`<ul><a></ul>\\`) is invalid\n HTML. \\`vitops lint\\` reports this one.\n - Related subgrid layouts: \\`pricing-grid\\` + \\`pricing-card\\` (with \\`pricing-card--featured\\`)\n and \\`comparison-table\\`.\n- **\\`grid-auto\\`** — an auto-fit grid: items wrap into as many equal columns as fit, each at\n least \\`--grid-min\\` wide (default 13rem), gap \\`--grid-gap\\`. The content-driven counterpart\n to \\`split\\`'s explicit fractions. Prefer \\`subgrid\\` when the items have internal tranches to\n align; this is the right class for a gallery, a logo wall, a row of icons.\n- **\\`stretched-link\\`** — makes one link cover its nearest positioned ancestor, so a whole\n card is clickable while the accessible name stays on real text. Pair with \\`relative\\` on the\n container (\\`subgrid-card\\` already has it). **The card's text stops being selectable** — the\n overlay takes the pointer-drag — so where that matters use \\`<Cards>\\` instead.\n- **\\`raised\\`** — lifts content back above a \\`stretched-link\\` overlay, for a second link or a\n button in the same card. Sets \\`position: relative\\` **and** a z-index, both of which are\n required: \\`relative\\` on its own leaves the element underneath and unclickable.\n- **\\`relative\\`** — \\`position: relative\\`, the containing block \\`stretched-link\\` needs.\n- **\\`cluster\\`** — a wrapping row of related inline things (buttons, badges, tags, meta) with\n a shared \\`--cluster-gap\\`. Alignment variants \\`cluster-{start,center,end}\\`,\n \\`cluster-{between,around,evenly}\\`, and the two-axis form\n \\`cluster-<align>-<justify>\\` over \\`start\\`/\\`center\\`/\\`end\\`. Prefer this over a hand-written\n \\`display: flex\\` + \\`gap\\` for a group of controls.\n- **\\`split\\`** — a two-column pair. Ratio rule: **\\`split-<a>-<b>\\`** where \\`<a>-<b>\\` ∈\n \\`1-2\\`, \\`2-1\\`, \\`1-3\\`, \\`3-1\\`, \\`1-4\\`, \\`4-1\\`, \\`2-3\\`, \\`3-2\\` (breakpoint-prefixable); equal\n columns without one. The ratio is a flex **basis**, so a column's padding counts\n inside its share, and \\`min-inline-size: 0\\` is built in so long unbreakable content\n can't stretch a column past it.\n - **Stacking is \\`flex-col\\`** — there is no split-specific class for it:\n \\`class=\"split flex-col md-split-1-2\"\\` is stacked below 48rem and 1:2 above,\n because the \\`<bp>-\\` ratio classes assert the row. While stacked the ratio goes\n inert on its own (a percentage basis against an auto-height column resolves as\n \\`content\\`), unless you give the split a definite \\`block-size\\`.\n - **\\`split-reverse\\`** — swaps the two panels (breakpoint-prefixable). Implemented\n as \\`order\\` on the first child, so it reverses on whichever axis the split is\n currently on: bare, it swaps the columns in a row AND the rows in a stack;\n scoped (\\`md-split-reverse\\`) it swaps only once there are two columns — media\n first in source so it leads on mobile, on the right at width. The ratio stays\n with the source-first child, not with the visual position.\n - **Accessibility:** reversing makes visual order disagree with DOM order, and\n focus order follows the DOM (WCAG 2.4.3 Focus Order). Put focusable content in\n **only one** of the two panels, or the tab order will not be linear. The\n pattern declares \\`reading-flow: flex-visual\\`, which fixes this properly where\n it is supported; support is not yet broad enough to rely on.\n- **Flex** — \\`flex\\`, \\`flex-row\\`, \\`flex-col\\`, \\`flex-row-reverse\\`, \\`flex-col-reverse\\`\n (all breakpoint-prefixable).\n- **Alignment** — \\`items-{start,center,end,stretch}\\`, \\`justify-{start,center,end,between}\\`,\n text align \\`text-{start,center,end}\\` (all breakpoint-prefixable).\n- **Display** — \\`block\\`, \\`inline\\`, \\`inline-block\\`, \\`flex\\`, \\`grid\\`, \\`hidden\\`\n (breakpoint-prefixable, e.g. \\`md-hidden\\`).\n- **Accessibility** — \\`sr-only\\` / \\`not-sr-only\\` (breakpoint-prefixable).\n- **State hooks** — \\`is-active\\`, \\`is-open\\` (styling flags toggled by JS / native state).\n\n## Spacing\n\nThe space scale is ${code(spaceNames)} exposed as \\`--space-<name>\\` tokens.\n\\`rhythm\\` margins consume these tokens; prefer \\`rhythm\\` for vertical flow rather than\nper-element margins.\n\nRule: **\\`gap-<name>\\`**, **\\`gap-x-<name>\\`** (column) and **\\`gap-y-<name>\\`** (row), name ∈\n${code(spaceNames)} — all breakpoint-prefixable (\\`md-gap-l\\`, \\`@md:gap-l\\`). These are the\nframework's own utilities in every format: the fluid steps are deliberately kept out of\nTailwind's \\`--spacing-*\\` namespace (named keys there shadow the size scales, so\n\\`max-w-7xl\\` would resolve to \\`var(--spacing-7xl)\\`), which means Tailwind's numeric\n\\`gap-4\\` still uses its own multiplier and coexists with these.\n\n## Typography\n\nRule: **\\`font-<role>\\`** — role ∈ ${code(typeRoles)}. Each role carries its own family,\nsize (from the type scale ${code(typeNames)}), tracking, transform, weight and \\`text-wrap\\`.\nFamilies: ${code(families)} (\\`--font-*\\`).\n\nBecause the role owns \\`text-wrap\\`, a heading is balanced and copy is \\`pretty\\` with **no\nclass at all** wherever \\`typography.headings\\` maps the bare element to a role. Override one\nelement with \\`text-{wrap,nowrap,balance,pretty}\\` — the per-element escape hatch, for markup\nthat carries no role class. (These four are Tailwind's own in the tailwind format.)\n\n## Colour\n\n**Functional tokens are the primary vocabulary** — classes name the *job*, not the tone, and\nevery one remaps automatically under \\`${DARK_SEL}\\` (background/text ends\nswap; \\`solid\\` fills stay mode-stable with a computed \\`on-\\` foreground). Prefer these over\nraw steps.\n\n**Role names are yours.** \\`colors.roles\\` is an open map: add a key, and the generator emits\nthat role's full token set, its dark flip and every utility below. Your config\ncurrently defines ${code(roles)}. Six of those are a **required core** — the framework's own\ncomponent CSS references \\`${REQUIRED_ROLES.join('`, `')}\\` with no fallback, so removing one\nleaves those components uncoloured (\\`vitops validate\\` warns). Everything beyond them is free.\n\nThe rule is one shape — **\\`<target>-<role>[-<variant>]\\`**, target ∈ \\`bg\\` \\`text\\` \\`icon\\`\n\\`border\\` — and the class name is exactly its token name minus \\`--color-\\`. Variants are\nordinal (\\`xx-muted\\` < \\`x-muted\\` < \\`muted\\` < bare < \\`bold\\` < \\`x-bold\\`) and sparse: only the\ncells that hold their contrast target exist.\n\n**Which cells exist depends on the role's \\`kind\\`:**\n\n*Surface roles* (page and panel colours):\n\n- **Backgrounds** — \\`bg-<role>\\` (the card/panel), \\`bg-<role>-muted\\` (the page behind it),\n \\`bg-<role>-x-muted\\` (well / inset), \\`bg-<role>-bold\\` and \\`-x-bold\\` (inverse surface).\n Elevation is *which* token you reach for, not a raised/sunken pair.\n- **Content** — \\`text-<role>\\` (body), \\`text-<role>-bold\\`, \\`text-<role>-muted\\` (secondary),\n \\`text-<role>-x-muted\\` (placeholder) and \\`-xx-muted\\` (disabled). The last two are\n contrast-exempt by design.\n- **Borders** — \\`border-<role>-muted\\` (hairline), \\`border-<role>\\`, \\`border-<role>-bold\\`\n (the one guaranteed to carry a boundary on its own).\n\n*Chromatic roles* (signal colours) — **there is no bare \\`bg-<role>\\`**; say tint or solid:\n\n- **Tints** — \\`bg-<role>-x-muted\\` (alert wash), \\`bg-<role>-muted\\` (badge).\n- **Solids** — \\`bg-<role>-solid\\`, \\`-solid-bold\\` (hover), \\`-solid-x-bold\\` (active), each\n pairing with \\`text-on-<role>\\` for a guaranteed-contrast foreground.\n- **Content** — \\`text-<role>\\`, \\`text-<role>-bold\\`. There is deliberately no\n \\`text-<role>-muted\\`: it could not hold its contrast target off a light surface, so soften\n coloured text with weight or size instead.\n- **Borders** — \\`border-<role>\\`, \\`border-<role>-bold\\` (decorative status edges).\n\nBoth kinds also get **\\`icon-<role>\\`** — a separate non-text tier, so a glyph may run more\nvivid than text — plus \\`glass\\` (translucent surface + backdrop blur), the \\`--overlay\\` scrim\nand \\`--color-border-focus\\` for focus rings.\n\nEveryday pairings, using the roles this config defines: page\n\\`bg-${roles[0] ?? 'neutral'}-muted\\`, cards \\`bg-${roles[0] ?? 'neutral'}\\` on top of it, body\n\\`text-${roles[0] ?? 'neutral'}\\`, captions \\`text-${roles[0] ?? 'neutral'}-muted\\`; buttons\n\\`bg-${roles[2] ?? roles[0] ?? 'ui-primary'}-solid text-on-${roles[2] ?? roles[0] ?? 'ui-primary'}\\`;\nalerts \\`bg-danger-x-muted text-danger\\`.\n\n**Raw scale** (secondary / fine control) — rule \\`<util>-<hue>-<step>\\` with util ∈\n${code(utils)}: every hue is an 11-step OKLCH scale generated from its seed (or fixed brand\ntones), numeric steps \\`50\\` … \\`950\\` (tinted near-white → tinted near-black) — e.g.\n\\`bg-${ramps[0] ?? 'brand'}-100\\`, \\`text-${ramps[0] ?? 'brand'}-800\\`. Hues: ${code(ramps)}.\n\n> **Raw scale classes are frozen — they do NOT remap in dark mode.**\n> \\`bg-${ramps[0] ?? 'brand'}-800\\` is that exact colour in every appearance. The automatic\n> dark flip described above applies **only** to the functional role tokens, because\n> \\`--color-<hue>-<step>\\` is emitted once and never re-pointed under \\`${DARK_SEL}\\`.\n> A raw step on a page that can switch appearance is a latent bug: it looks correct in\n> whichever mode you built it in and inverts in the other.\n>\n> If you are reaching for a raw step, you usually want a **role** instead — and roles are\n> extensible, so adding one is a two-line config change:\n>\n> | instead of | use | why |\n> | --- | --- | --- |\n> | \\`bg-<hue>-50\\` / \\`-950\\` | \\`bg-<role>\\` (surface kind) | the card plane, flips automatically |\n> | \\`bg-<hue>-100\\` / \\`-900\\` | \\`bg-<role>-muted\\` | the page, or a chromatic tint |\n> | \\`bg-<hue>-500\\`…\\`-700\\` | \\`bg-<role>-solid\\` | vivid fill, mode-stable, pairs with \\`text-on-<role>\\` |\n> | \\`text-<hue>-950\\` / \\`-50\\` | \\`text-<role>\\` | contrast-guaranteed body text |\n> | \\`text-<hue>-800\\` / \\`-200\\` | \\`text-<role>-muted\\` | secondary text |\n> | \\`border-<hue>-200\\` / \\`-800\\` | \\`border-<role>\\` | |\n>\n> Raw steps stay the right tool for genuinely fixed colours — a brand mark, a chart series,\n> an illustration — where the value must not move between appearances.\n\n## Shadows\n\nRule: **\\`drop-shadow-<size>\\`** — size ∈ ${code(shadows)} (applied as a \\`filter\\`, so it\nfollows non-rectangular shapes).\n\n## Animation\n\nAn effect carries no motion of its own — it sets \\`--<prop>-from\\`/\\`-to\\` and picks a keyframe.\nA **driver** supplies the motion, and you always compose one of each:\n\n- \\`animate-view\\` — plays as the element crosses the viewport\n- \\`animate-scroll\\` — scrubs against page scroll\n- \\`animate-trigger\\` — time-based; plays once when \\`.is-active\\` / \\`[data-active]\\` is set\n- \\`transition\\` — transitions the same from/to vars, so it reverses on a state flip\n\nRule: **\\`<effect>\\`** — effect ∈ ${code(effects)}. The state/flip prefixes above pair with\n\\`transition\\` and apply to every one of them.\n\nEach state matches the element **or its direct parent** (\\`.hover-<fx>:hover, :hover > .hover-<fx>\\`),\nwhich is what makes \\`reveal-*\\` usable: it rests at a zero-area \\`clip-path\\`, and \\`clip-path\\` clips\nhit-testing as well as painting, so the element itself can never be hovered.${\n keyframeOnly.length\n ? `\n\n${code(keyframeOnly)} animate \\`height\\`, the only stage that reflows and the only one behind a\nfeature gate: \\`0 → auto\\` is not interpolable without \\`interpolate-size: allow-keywords\\`, so\n\\`transition\\` declares \\`height\\` only inside an \\`@supports\\` for it. The \\`layout\\` **keyframe**\nhas the same dependency — this is not a limit of the transition driver.`\n : ''\n }\n\n**When it plays.** \\`animate-view\\` and \\`.is-active\\` are both timed off the element's **midpoint**:\nmotion starts once that midpoint is 10% of the viewport in, and a one-shot entrance completes at\n25%. Both stops are the element's position on screen rather than a fraction of its own height, so a\nsmall card and a full-bleed section behave alike. Shift the window with \\`--anim-start\\` /\n\\`--anim-end\\`, or replace it outright with \\`--anim-range\\`.\n\nComposed **journeys** chain multiple effects into one entrance: rule \\`<parts>-journey\\`\n(e.g. \\`fade-slide-journey\\`, \\`fade-scale-blur-journey\\`). They need a **keyframe** driver, not\n\\`transition\\`. A journey is entry → hold → exit, so it starts on that same 10% pivot but runs to the\nend of the exit phase — the hold occupies the middle of the crossing instead of the bottom edge of\nthe screen.\n\n**\\`stagger\\`** on a parent offsets each child by \\`--stagger-amount\\` (time-based drivers) and by\n\\`--stagger-range-step\\` (scroll-driven ones — \\`animation-delay\\` is ignored on a progress-based\ntimeline). Journeys set an explicit range and opt out.\n\n## Component patterns\n\nEach pattern is a base class \\`<pattern>\\` with interaction states (hover/active/focus-visible)\nbaked in; coloured patterns add role variants via rule **\\`<pattern>-<role>\\`**. (How the\npattern CSS is assembled — token cascade, \\`--p-<pattern>\\`-style override hooks, state\nshortcuts — is explained in [/concepts/patterns.md](../concepts/patterns.md).)\n\n- Patterns: ${code(patterns)}.\n- Roles (for coloured patterns — \\`badge\\`, \\`tag\\`, \\`status\\`, \\`cta\\`, \\`btn\\`, …):\n ${code(patternRoles)} — e.g. \\`badge-success\\`, \\`cta-danger\\`. A pattern that also styles an\n element accepts the bare role class too (\\`<button class=\"danger\">\\`). The default\n (unsuffixed) variant uses the pattern's \\`default_role\\`.\n- Shape primitives: \\`--br-<name>\\` radii — ${code(radii)}.\n`;\n}\n\n// ── design-system.json authoring reference (walked from the JSON Schema) ─────\n// Field docs are rendered from `jsonSchema`'s `description` metadata (authored\n// once in schema.ts via `desc()`), so this reference cannot drift from validation.\n\nexport interface JsonSchemaNode {\n type?: string;\n description?: string;\n properties?: Record<string, JsonSchemaNode>;\n required?: string[];\n additionalProperties?: JsonSchemaNode | boolean;\n anyOf?: JsonSchemaNode[];\n items?: JsonSchemaNode;\n enum?: unknown[];\n}\n\nconst isPrimitive = (n: JsonSchemaNode): boolean =>\n !n.properties && !n.anyOf && n.type != null && n.type !== 'object' && n.type !== 'array';\n\nfunction typeLabel(node: JsonSchemaNode): string {\n if (node.enum) return node.enum.map(String).join(' | ');\n if (node.anyOf)\n return node.anyOf.every(isPrimitive) ? node.anyOf.map((v) => v.type).join(' | ') : 'one of';\n if (node.type === 'array') {\n const it = node.items;\n if (it?.enum) return `array of ${it.enum.map(String).join(' | ')}`;\n return it?.type && it.type !== 'object' ? `array of ${it.type}` : 'array';\n }\n if (node.type === 'object') {\n const ap = node.additionalProperties;\n return ap && typeof ap === 'object' ? 'map' : 'object';\n }\n return node.type ?? 'value';\n}\n\n/** A node's documentable children: object properties, map values, or array items. */\nfunction childEntries(\n node: JsonSchemaNode,\n): Array<{ label: string; node: JsonSchemaNode; required: boolean }> {\n if (node.properties) {\n const req = node.required ?? [];\n return Object.entries(node.properties).map(([k, v]) => ({\n label: k,\n node: v,\n required: req.includes(k),\n }));\n }\n const ap = node.additionalProperties;\n if (ap && typeof ap === 'object' && (ap.description || ap.properties || ap.anyOf))\n return [{ label: '<name>', node: ap, required: false }];\n if (node.items && (node.items.description || node.items.properties || node.items.anyOf))\n return [{ label: '[items]', node: node.items, required: false }];\n return [];\n}\n\nfunction renderSchemaNode(\n label: string,\n node: JsonSchemaNode,\n required: boolean,\n depth: number,\n out: string[],\n maxDepth = 3,\n): void {\n const indent = ' '.repeat(depth);\n const meta = `(${typeLabel(node)}${required ? ', required' : ''})`;\n out.push(`${indent}- \\`${label}\\` ${meta}${node.description ? ` — ${node.description}` : ''}`);\n if (depth >= maxDepth) return;\n if (node.anyOf && !node.anyOf.every(isPrimitive)) {\n for (const variant of node.anyOf) {\n out.push(`${indent} - *one of*${variant.description ? ` — ${variant.description}` : ''}`);\n for (const c of childEntries(variant))\n renderSchemaNode(c.label, c.node, c.required, depth + 2, out, maxDepth);\n }\n return;\n }\n for (const c of childEntries(node))\n renderSchemaNode(c.label, c.node, c.required, depth + 1, out, maxDepth);\n}\n\n/**\n * One `## <key>` section per top-level property: its description, then its\n * fields as a bullet tree. Shared by both references so the two cannot drift in\n * presentation — only in which schema they are pointed at.\n */\nfunction schemaSections(schema: JsonSchemaNode, heading = '##', maxDepth = 3): string[] {\n const required = schema.required ?? [];\n const sections: string[] = [];\n for (const [key, node] of Object.entries(schema.properties ?? {})) {\n if (key === '$schema') continue;\n const parts: string[] = [\n `${heading} \\`${key}\\`${required.includes(key) ? '' : ' *(optional)*'}`,\n ];\n if (node.description) parts.push('', node.description);\n const bullets: string[] = [];\n for (const c of childEntries(node))\n renderSchemaNode(c.label, c.node, c.required, 0, bullets, maxDepth);\n if (bullets.length) parts.push('', ...bullets);\n sections.push(parts.join('\\n'));\n }\n return sections;\n}\n\n/* ── Schema → tree DATA (the second consumer of the same walk) ─────────────── */\n\nconst escapeHtml = (s: string): string =>\n s.replace(\n /[&<>\"]/g,\n (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' })[c] as string,\n );\n\n/**\n * Sentinel for a lifted code span. Cannot occur in authored schema prose.\n *\n * Written as an ESCAPE, never as the literal byte. A raw NUL here made this whole\n * file `data` rather than `text` to libmagic, so grep and ripgrep classified it\n * as binary and **silently skipped it** — every search for a string in the\n * largest doc emitter in the repo returned nothing, with no error and nothing to\n * notice. That is the failure mode this codebase is written against, aimed at the\n * tool an agent uses to find anything.\n */\nconst CODE_SLOT = '\\u0000';\n\n/**\n * The inline markdown the schema's `desc()` text actually uses, as HTML. Closed\n * on purpose, exactly like the legal renderer's subset: these strings are\n * authored in `schema.ts`, so the set is knowable rather than guessed at.\n *\n * Escaping happens before any markup is emitted, so a description containing `<`\n * cannot inject tags — several do (`<canonical>/<key>.txt`). Exported because the\n * only safe place for this is one tested function; a caller doing its own escaping\n * is how one of them eventually doesn't.\n *\n * **Code spans are lifted out FIRST, and that is load-bearing rather than tidy.**\n * `colors.utilities` describes the target families as `` `bg-*` ``, `` `text-*` ``,\n * `` `border-*` `` — literal asterisk WILDCARDS. Run emphasis over the raw string\n * and the `*` closing `bg-*` pairs with the one closing `text-*`, wrapping the\n * text between two unrelated utilities in `<em>` and eating both asterisks. The\n * prose then silently describes families that don't exist. Lifting code spans\n * first makes emphasis structurally unable to see inside them.\n */\nexport const renderInlineMarkdown = (s: string): string => {\n const spans: string[] = [];\n const lifted = s.replace(/`([^`]+)`/g, (_, body: string) => {\n spans.push(body);\n return `${CODE_SLOT}${spans.length - 1}${CODE_SLOT}`;\n });\n return (\n escapeHtml(lifted)\n .replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>')\n // Single-asterisk emphasis, after strong so `**x**` is already consumed. The\n // schema uses it (`*presentation*`, `*domain properties*`), so omitting it\n // printed the asterisks literally on the page.\n .replace(/\\*([^*\\n]+)\\*/g, '<em>$1</em>')\n .replace(\n new RegExp(`${CODE_SLOT}(\\\\d+)${CODE_SLOT}`, 'g'),\n (_, i: string) => `<code>${escapeHtml(spans[Number(i)] ?? '')}</code>`,\n )\n );\n};\n\nexport interface SchemaTreeOptions {\n /** Dotted id prefix, so two trees on one page can't collide. */\n idPrefix?: string;\n /** Nesting cap. Unlike the markdown walk there is no reason to truncate. */\n maxDepth?: number;\n /**\n * Dotted paths to render but not descend into.\n *\n * Exists for one real case: the project config declares `designSystem.themes`\n * as a looser shape than `DesignSystemSchema`, because the full one is applied\n * separately by `resolveTheme`. Its embedded copy is therefore an\n * APPROXIMATION — measurably so, missing the descriptions for `colors`,\n * `colors.palette`, `colors.roles` and `colors.utilities`. Rendering it as the\n * token reference would quietly document the colour system less well than the\n * design-system schema does, so a caller prunes it here and renders\n * `jsonSchema` alongside instead.\n */\n prune?: readonly string[];\n}\n\nexport interface SchemaTreeNode {\n /** Field name, or `<name>` / `[items]` for a map value or array item. */\n label: string;\n /** Human type label — `object`, `map`, `string | number`, `one of`. */\n type: string;\n required: boolean;\n /** Raw schema description (the closed inline-markdown subset), if any. */\n description?: string;\n /**\n * Dotted config path (`site.analytics.clarityId`). Absent when the node is not\n * addressable: a pseudo-label, or a path already claimed by an earlier node.\n */\n id?: string;\n /** True for an `anyOf` branch, which has no name of its own. */\n variant?: boolean;\n children: SchemaTreeNode[];\n}\n\n/**\n * Walk a JSON Schema into tree DATA.\n *\n * The same walk that produces the `authoring.md` / `config.md` bullet lists,\n * returned as a node model instead of a string. Returning data rather than markup\n * is deliberate and follows `roleColorUtilities()`: the *shape* of the tree is one\n * decision, and each medium renders it — markdown for agents, an accessible\n * `<details>` tree for the docs site. An HTML-emitting version here would be a\n * second source of the markup contract for `<wc-tree>` to drift from.\n *\n * Ids are dotted paths so a field can be linked to directly. Map-value and\n * array-item pseudo-labels are skipped in the path: `site.dns.records` reads\n * better than `site.dns.<domain>.records`, and neither `<domain>` nor `[items]`\n * is a real key.\n */\nexport function schemaTreeNodes(\n schema: JsonSchemaNode,\n opts: SchemaTreeOptions = {},\n): SchemaTreeNode[] {\n const { idPrefix = '', maxDepth = 12, prune = [] } = opts;\n const pruned = new Set(prune);\n\n const isPseudo = (label: string) => label === '<name>' || label === '[items]';\n const join = (a: string, b: string) => (a ? `${a}.${b}` : b);\n\n /**\n * Paths already claimed. An `anyOf` branch has no key of its own, so sibling\n * branches sharing a field name resolve to the same dotted path\n * (`site.templates.type` exists in all three template variants). Rather than\n * invent a branch index that no real config document contains, the first\n * occurrence keeps the id — which is what `getElementById` would have picked\n * anyway, now true instead of accidental.\n */\n const seen = new Set<string>();\n\n const build = (\n label: string,\n n: JsonSchemaNode,\n required: boolean,\n path: string,\n depth: number,\n ): SchemaTreeNode => {\n const addressable = path !== '' && !isPseudo(label) && !seen.has(path);\n if (addressable) seen.add(path);\n\n // `anyOf` branches are children too: a union with object branches has to be\n // explorable, or `notifications.email` (address | object) renders as a leaf\n // with its six object fields simply absent from the page.\n const variants = n.anyOf && !n.anyOf.every(isPrimitive) ? n.anyOf : [];\n const children: SchemaTreeNode[] = [];\n\n if (depth < maxDepth && !pruned.has(path)) {\n for (const v of variants) {\n children.push({\n label: 'one of',\n type: typeLabel(v),\n required: false,\n variant: true,\n ...(v.description ? { description: v.description } : {}),\n children: childEntries(v).map((c) =>\n build(\n c.label,\n c.node,\n c.required,\n isPseudo(c.label) ? path : join(path, c.label),\n depth + 2,\n ),\n ),\n });\n }\n if (!variants.length)\n for (const c of childEntries(n))\n children.push(\n build(\n c.label,\n c.node,\n c.required,\n isPseudo(c.label) ? path : join(path, c.label),\n depth + 1,\n ),\n );\n }\n\n return {\n label,\n type: typeLabel(n),\n required,\n ...(n.description ? { description: n.description } : {}),\n ...(addressable ? { id: path } : {}),\n children,\n };\n };\n\n const required = schema.required ?? [];\n return Object.entries(schema.properties ?? {})\n .filter(([key]) => key !== '$schema')\n .map(([key, child]) => build(key, child, required.includes(key), join(idPrefix, key), 0));\n}\n\nfunction renderAuthoring(): string {\n const sections = schemaSections(jsonSchema as unknown as JsonSchemaNode);\n return `${frontmatter({\n type: 'Config Reference',\n title: 'Vitops — design-system.json authoring reference',\n description:\n 'Every field of the design-system.json config, generated from the published JSON Schema so it always matches validation.',\n resource: DS_PATH,\n tags: ['config', 'schema', 'authoring', 'design-system'],\n })}\n\n# \\`design-system.json\\` authoring reference\n\nThe single source of truth every output format is generated from. Each consumer authors\ntheir own config — there is no shared canonical token set. The field docs below are\nrendered from the published JSON Schema, so they always match what \\`vitops validate\\`\nenforces.\n\n- Set \\`\"$schema\": \"${SCHEMA_URL}\"\\` in the config for editor autocomplete + validation.\n- Scaffold a starter config with \\`vitops init\\`; check one with \\`vitops validate\\`.\n- **This can be a standalone file, or live inside a site config.** Anywhere the\n toolchain takes a config — \\`--input\\`, the Vite plugin, the Astro integration's\n \\`css.input\\` — that file may be a \\`design-system.json\\` or the larger site config\n that embeds one under \\`designSystem.themes.<name>\\`. They are told apart by shape,\n and the fields below are the same either way. A site config additionally supplies\n the site-level facts generation reads (its default colour scheme, legal documents,\n icon sprite), so the path is declared once rather than per option.\n- The *why* behind each section: [colour system](concepts/color.md),\n [type & space scales](concepts/scales.md), [component patterns](concepts/patterns.md).\n- What each output format does with these tokens: [formats.md](formats.md).\n\n${sections.join('\\n\\n')}\n`;\n}\n\n// ── Config authoring reference (walked from the site JSON Schema) ────────────\n// The same walker, pointed at the other published schema. Everything a consumer\n// can say about their *company* and their *site* — as opposed to their tokens —\n// is described here, and it is generated rather than written so it cannot claim\n// a field validation does not accept.\n\nfunction renderConfig(): string {\n const schema = configJsonSchema as unknown as JsonSchemaNode;\n const props = schema.properties ?? {};\n const required = schema.required ?? [];\n\n // The top level is three sections, so rendering it the way `authoring.md`\n // renders `design-system.json` would put ~23 unrelated fields under one\n // heading. Each section gets a `##`; each of ITS fields gets a `###`.\n const sections = Object.entries(props).map(([key, node]) => {\n const head = [\n `## \\`${key}\\`${required.includes(key) ? '' : ' *(optional)*'}`,\n ...(node.description ? ['', node.description] : []),\n ].join('\\n');\n // `designSystem` is documented in full by authoring.md; here it needs only\n // its own wrapper fields, not a second copy of the whole token schema. The\n // depth cap is what enforces that: `themes` is a map whose value node IS the\n // design-system schema, so the default walk descended into every token field\n // and re-emitted the ~57 field lines authoring.md already owns — directly\n // under a sentence promising it hadn't. Stop at the `<name>` bullet and let\n // the link carry the reader.\n const fields = schemaSections(node, '###', key === 'designSystem' ? 0 : 3).join('\\n\\n');\n if (key === 'designSystem')\n return [\n head,\n 'The token set. Its `themes.<name>` entries are full design systems — every field of\\none is in [authoring.md](authoring.md). Only the wrapper is listed here.',\n fields,\n ].join('\\n\\n');\n return [head, fields].join('\\n\\n');\n });\n\n return `${frontmatter({\n type: 'Config Reference',\n title: 'Vitops — config authoring reference',\n description:\n 'Every field of the three-section config (designSystem / organization / site), generated from the published JSON Schema so it always matches validation.',\n resource: CONFIG_PATH,\n tags: ['config', 'schema', 'authoring', 'site', 'organization'],\n })}\n\n# Config authoring reference\n\nThe document that describes a **whole project**: the token set, the company, and the\npublished site. It is the input every command that needs more than tokens is anchored\nto — \\`vitops legal\\`, \\`vitops icons\\`, \\`vitops search\\` — and it can also stand in for\na \\`design-system.json\\` anywhere the toolchain takes one, since it carries a full\n\\`designSystem\\`.\n\nConsumers name the file whatever suits them (\\`site.json\\`, \\`company.json\\`,\n\\`vitops.config.json\\`); it is recognised by **shape**, not by name — a document with a\ntop-level \\`designSystem\\` key is this, and one without it is a bare\n\\`design-system.json\\`.\n\n- Set \\`\"$schema\": \"${CONFIG_SCHEMA_URL}\"\\` in the config for editor autocomplete + validation.\n- Check one with \\`vitops validate\\`.\n\n## The three sections\n\n| Section | Holds | Changes when |\n| --- | --- | --- |\n| \\`designSystem\\` | the token set — named themes, which theme, which appearance | the brand's design changes |\n| \\`organization\\` | the company — name, contact, locations, services, profiles | the company changes |\n| \\`site\\` | this published site — locales, domains, environments, SEO, analytics, legal, icons, deployment | this site changes |\n\nThe split is what makes the multi-site case expressible: several sites can carry the\nsame \\`organization\\` and differ only in \\`site\\`. It is also what the generated legal\ndocuments rely on — a privacy policy asserts facts about the *company* (who to contact,\nwhere it is) and facts about the *site* (which forms exist, which analytics run), and\nthose two are separately true.\n\n**Fields are described where they are, not where they were.** If you are migrating a\npre-3.0 flat config, \\`vitops validate\\` names every move rather than reporting a dozen\nunknown keys.\n\n${sections.join('\\n\\n')}\n`;\n}\n\n// ── Output formats reference ──────────────────────────────────────────────────\nfunction renderFormats(ds: DesignSystem): string {\n const clashList = Array.from(TW_CLASH).sort();\n const spaceName = ds.spaceScale?.baseline ?? ds.spaceScale?.names?.[0] ?? 'm';\n return `${frontmatter({\n type: 'Formats Reference',\n title: 'Vitops — output formats (tailwind vs css vs bricks vs design)',\n description:\n 'What each vitops generate format emits, what the target platform provides instead, and the Tailwind-specific rules (which framework utilities are stripped in favour of Tailwind defaults).',\n resource: DS_PATH,\n tags: ['formats', 'tailwind', 'bricks', 'css', 'design', 'design-system'],\n })}\n\n# Output formats — \\`tailwind\\` vs \\`css\\` vs \\`bricks\\` vs \\`design\\`\n\nOne config, four targets: \\`vitops generate --format <tailwind|css|bricks|design>\\`. Three of\nthem are stylesheets, and across those the **class vocabulary is the same** (see\n[css/classes.md](css/classes.md)); what differs is which layers the generator emits versus\nwhich the platform provides, and the variant separator (\\`-\\` in CSS/Bricks, \\`:\\` / \\`@\\` in\nTailwind). The fourth, \\`design\\`, emits no CSS at all.\n\n\\`--format\\` takes a comma-separated list, so the brief composes with a stylesheet:\n\\`vitops generate --format css,design\\`.\n\n## \\`tailwind\\` — single-file Tailwind v4 layer\n\nEmits one self-contained \\`tailwind.css\\` (plus \\`tokens.json\\`): \\`@import \"tailwindcss\"\\`,\n\\`@theme\\` tokens, the framework's structural CSS + component patterns inlined, and\n\\`@utility\\` definitions for the bespoke families (type roles, animation effects,\nsplit ratios, track placement).\n\n**Use Tailwind's own utilities for these class names.** The framework's rules for them are\ndeliberately stripped from the bundle because Tailwind provides them natively — writing\nthem still works, but they are Tailwind's, not the framework's:\n\n${clashList.map((c) => `\\`${c}\\``).join(', ')}\n\nOther Tailwind-specific behaviour:\n\n- **Variants are Tailwind's job.** No pre-expanded breakpoint/state classes are emitted\n (the framework's \\`@container (min-width: …)\\` **variant** blocks are dropped; component\n container queries such as the sitenav's desktop switch are kept); use Tailwind syntax —\n \\`@md:split-1-2\\`, \\`hover:flip-fade-in\\`. Container breakpoints are registered as\n \\`--container-{sm,md,lg,xl}\\` = 30/48/64/80rem, backing the \\`@sm:\\`…\\`@xl:\\` variants.\n\n > **Three spellings, and only two of them work here.**\n >\n > | you write | in \\`tailwind\\` | note |\n > | --- | --- | --- |\n > | \\`@md:flex-row\\` | ✅ container query | the framework's breakpoints (48rem) |\n > | \\`md:flex-row\\` | ✅ media query | **Tailwind's** breakpoints, which differ — \\`sm:\\` is 40rem where \\`@sm:\\` is 30rem |\n > | \\`md-flex-row\\` | ❌ silently nothing | the css/bricks spelling; not emitted in this format |\n >\n > \\`md-*\\` is the trap: it is a real class in \\`css\\`/\\`bricks\\` and a no-op here, and\n > nothing errors — the element simply never changes at the breakpoint. Prefer \\`@md:\\`\n > so one vocabulary of breakpoints applies throughout.\n\n- **Overriding \\`--container-*\\` also moves Tailwind's width scale.** Registering the\n framework breakpoints in \\`@theme\\` re-points \\`max-w-sm\\`…\\`max-w-xl\\` at the same values,\n so \\`max-w-md\\` is 48rem here rather than Tailwind's stock 28rem. Use\n \\`max-w-(--container-md)\\` style arbitrary values if you need to be explicit.\n- **The space scale is NOT mapped into Tailwind's \\`--spacing-*\\` namespace** (that would\n corrupt Tailwind's numeric multipliers and \\`max-w-*\\` sizes). Numeric utilities like\n \\`p-4\\` keep Tailwind's 0.25rem meaning; use the design-system scale via arbitrary\n values — \\`p-(--space-${spaceName})\\`, \\`gap-(--space-${spaceName})\\`.\n- **Functional colour roles are plain \\`:root\\` variables, not \\`@theme\\` colours**, so\n Tailwind doesn't auto-derive utilities from them; the emitted \\`@utility\\` set\n (\\`bg-<role>\\`, \\`text-<role>-muted\\`, …) is the public API. The raw hue scales ARE\n \\`@theme\\` colours, so native \\`bg-<hue>-500\\`-style utilities work.\n\n This split is deliberate and load-bearing. When a token sits in \\`@theme\\` *and* an\n \\`@utility\\` of the derived name exists, Tailwind merges both into one rule with the\n \\`@theme\\` declaration last — regardless of source order. Only palette hues belong in\n \\`@theme\\`, where nothing competes for the name. Role tokens stay in a plain \\`:root\\`\n block, and \\`format-parity.test.ts\\` derives that guard from the emitted token names so\n it cannot go quiet if the grammar moves again.\n- **\\`colors.utilities\\` is a floor here, not a ceiling.** It controls which families get\n explicit role \\`@utility\\` rules, exactly as in \\`css\\`/\\`bricks\\`. But the raw hue scales\n are \\`@theme\\` colours, and Tailwind derives *every* colour family from those on demand\n (\\`ring-\\`, \\`divide-\\`, \\`accent-\\`, \\`caret-\\`, …), so hue-step utilities you did not enable\n still resolve in this format.\n\n## \\`css\\` — standalone bundle\n\nEmits a bundled, self-contained \\`styles.css\\` + \\`tokens.json\\` + \\`design-manifest.json\\`.\nThe colour and font/scale layers are fully included, and every utility family is\npre-expanded — including breakpoint/state variants with \\`-\\` separators\n(\\`md-split-1-2\\`, \\`hover-fade-in\\`). For non-Bricks, non-Tailwind consumers and the\ndocs build.\n\n**Cascade layers.** The bundle ships three, in precedence order:\n\n\\`\\`\\`\n@layer vitops.base, vitops.components, vitops.utilities;\n\\`\\`\\`\n\n- \\`vitops.base\\` — the reset (\\`box-sizing: border-box\\` on every element and pseudo-element,\n a 16px root, no body margin) and the pure \\`:root\\` token blocks. Lowest of the three, so\n your own reset overrides it — unlayered, or from a layer you declare before \\`vitops.base\\`.\n- \\`vitops.components\\` — the animation engine, the structural patterns (\\`.rhythm\\`,\n \\`.centered\\`, \\`.region\\`, \\`.split\\`, \\`.reveal\\`) and every UI pattern.\n- \\`vitops.utilities\\` — \\`bg-*\\`, \\`text-*\\`, \\`border-*\\`, \\`drop-shadow-*\\`, \\`font-*\\`,\n \\`gap-*\\`, animation effects, the layout utilities (\\`.m-*\\`, \\`.flex-*\\`, \\`.items-*\\`,\n \\`.split-<a>-<b>\\`, track placement) and the display/\\`sr-only\\` families.\n\nSo a utility overrides a pattern: \\`class=\"card bg-danger-muted\"\\` tints the card,\n\\`class=\"split flex-col\"\\` stacks the split, \\`class=\"table text-center\"\\` centres the table.\nYour own unlayered CSS beats all three — see [concepts/patterns.md](concepts/patterns.md) for\nthe override story and the one gotcha (a reset must be layered and ordered first).\n\nThe classification is by RULE, not by file: a partial that mixes patterns and utilities is\nsplit in two rather than shelved whole. \\`layout.css\\` (patterns) and \\`layout-utilities.css\\`\n(utilities) are the same family in two files for exactly this reason, and the \\`tailwind\\`\nformat reaches the same arrangement by its own route — patterns in \\`@layer components\\`,\nutilities as \\`@utility\\`.\n\nKnown gap: the \\`typography.headings\\` bare-element bindings (\\`h1\\`, \\`h2\\`, \\`body\\`) are\nemitted alongside \\`.font-<role>\\` and so sit in \\`vitops.utilities\\`, where a tag rule\noutranks every pattern — \\`<h2 class=\"pull-quote\">\\` keeps the heading's font-size in\n\\`css\\`/\\`bricks\\` and the pattern's in \\`tailwind\\`, which puts the bindings in \\`@layer base\\`.\nGive the element a \\`.font-<role>\\` class to pin it either way.\n\n## \\`bricks\\` — WordPress / Bricks Builder payload\n\nEmits the full deployable theme payload: \\`styles.min.css\\`, the Bricks import JSONs\n(\\`bricks-colors-{named,semantic}.json\\`, \\`bricks-variables.json\\`), \\`tokens.json\\`, the JS\nbundles (polyfills / elements / deferred), the Bricks element PHP under \\`bricks/\\`, and\nthis docs bundle under \\`docs/\\`.\n\n- **Bricks provides the token layer.** \\`color.css\\` and \\`type-tokens.css\\` are one-line\n stubs: the colour \\`:root\\` tokens, dark-mode overrides, colour utility classes, fonts,\n and type/space scales are generated live by Bricks' Color / Font / Variables Managers\n from the imported JSONs. Semantic palette entries carry \\`darkModeEnabled\\` + a \\`dark\\` ref so\n Bricks emits the dark-mode overrides on import.\n- Everything else (patterns, shadows, typography roles, animation effects, structural\n framework CSS) ships in \\`styles.min.css\\` as in the other formats.\n- Pattern states reference shadows by name, compiled to\n \\`filter: drop-shadow(var(--shadow-<name>))\\`.\n\n## \\`design\\` — the agent-facing brief\n\nEmits exactly one file, \\`DESIGN.md\\`, in the\n[google-labs-code/design.md](https://github.com/google-labs-code/design.md) format: YAML\nfront matter carrying the tokens (\\`colors\\`, \\`typography\\`, \\`rounded\\`, \\`spacing\\`,\n\\`components\\`, with \\`{group.token}\\` references) followed by a prose body carrying the\nrationale. It is meant to be run with \\`--out .\\` — DESIGN.md conventionally sits at a repo\nroot beside \\`AGENTS.md\\`, not in a build directory.\n\n**No CSS, no \\`tokens.json\\`, nothing else.** This format is a description of the system for\na tool that has to work without it — a coding agent in another repo, a Figma import, a\ndesigner. It is not a build target, and \\`vitops lint\\` does not accept it.\n\nThree things the format cannot represent, and what is emitted instead:\n\n| Ours | Why it doesn't fit | Emitted as |\n| --- | --- | --- |\n| fluid \\`clamp()\\` type / space steps | a spec \\`Dimension\\` is a number + px/em/rem | the **max** (desktop) value, with the prose saying so |\n| the automatic dark flip | the spec has no notion of a second appearance | **light** values only, with the flip explained in prose |\n| a \\`50%\\` radius | same \\`Dimension\\` restriction | dropped from \\`rounded\\`, named in the Shapes prose |\n\nRole tokens are emitted as \\`{colors.<hue>-<step>}\\` **references** into the raw ramps rather\nthan flattened hexes, so the role → ramp lineage survives the export. \\`on-solid\\` is the\nexception — it is a computed contrast literal with no step behind it.\n\n\\`meta.name\\` / \\`meta.description\\` in \\`design-system.json\\` supply the brand name and the\nOverview paragraph; everything else is derived from the config, so the brief cannot drift\nfrom what the other three formats build.\n`;\n}\n\n// ── Concept docs (colour / scales / patterns) ─────────────────────────────────\nfunction renderColorConcept(ds: DesignSystem): string {\n const hues = Object.keys(ds.colors.palette ?? {});\n const roles = Object.keys(ds.colors.roles ?? {});\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops colour system — seeded scales, target-prefixed tokens, automatic dark mode',\n description:\n 'How palette hues become 11-step OKLCH scales on a shared lightness ladder, how semantic roles derive target-prefixed tokens from them, and how dark mode flips automatically.',\n resource: DS_PATH,\n tags: ['color', 'oklch', 'dark-mode', 'design-system'],\n })}\n\n# Colour system\n\nAuthoring is two maps in \\`design-system.json\\` (see [authoring.md](../authoring.md)):\n\\`colors.palette\\` (hues) and \\`colors.roles\\` (semantic role → hue). Everything else —\nscales, role tokens, utilities, dark mode — is derived.\n\n## From seed to scale\n\nEach palette hue becomes an **11-step numeric OKLCH scale**, \\`--color-<hue>-50…950\\`,\nrunning tinted near-white → tinted near-black. Two authoring modes:\n\n- **Seeded** (\\`{ seed, anchors? }\\`): the scale is generated from one colour. The seed is\n preserved at its natural lightness step; \\`anchors\\` pin specific steps and the rest\n interpolate around them.\n- **Fixed** (\\`{ tones }\\`): a brand kit used verbatim — each authored tone lands at its\n nearest step, endpoints are tinted off-white/off-black, no interpolation.\n\nCurrent hues: ${code(hues)}.\n\n## The token grammar\n\nEvery colour token is named:\n\n\\`\\`\\`\n--color-<target>-<role>[-<variant>] target ∈ bg | text | icon | border\n\\`\\`\\`\n\nThe target sits **inside** the name on purpose. \\`--color-bg-danger-muted\\` and\n\\`--color-text-danger-muted\\` are different tokens, so there is nothing to arbitrate between\nthem — an earlier grammar put both on one \\`<family>-<role>-<modifier>\\` name and needed a\nprecedence rule, which made half the variants unreachable and the rest non-monotonic.\n\n**The token name is also the utility class name**, minus the \\`--color-\\` prefix. Write\n\\`class=\"bg-danger-muted\"\\` and you are using \\`--color-bg-danger-muted\\`. One vocabulary, not\ntwo (see [css/classes.md](../css/classes.md)).\n\nVariants are ordinal — \\`xx-muted\\` < \\`x-muted\\` < \\`muted\\` < (bare) < \\`bold\\` < \\`x-bold\\` — and\nthe tables are **sparse**: only cells that actually hold their contrast target exist.\n\\`bold\\` means *more emphatic in the current appearance*, not darker.\n\n## Role kinds\n\nA role in \\`colors.roles\\` (currently ${code(roles)}) is one of two kinds, and the kind decides\nwhich tokens exist:\n\n- **\\`surface\\`** — a page or panel colour. \\`bg-<role>\\` is the card, \\`bg-<role>-muted\\` the page\n behind it, \\`bg-<role>-x-muted\\` a well, \\`bg-<role>-bold\\` the inverse surface a tooltip sits\n on. Full text scale, and \\`border-<role>-bold\\` as the contrast-guaranteed boundary.\n- **\\`chromatic\\`** (the default, and what the bare-string form means) — a signal colour.\n Backgrounds split into *tints* (\\`bg-<role>-x-muted\\`, \\`bg-<role>-muted\\`) and *solids*\n (\\`bg-<role>-solid\\`, \\`-solid-bold\\`, \\`-solid-x-bold\\`). There is deliberately **no bare\n \\`bg-<role>\\`**: \"how loud?\" is a question the author answers. \\`text-on-<role>\\` is the\n guaranteed foreground for the solid family.\n\nPlus \\`--surface-glass\\` (translucent surface), \\`--overlay\\` (scrim) and\n\\`--color-border-focus\\` (the focus ring, taken from \\`ui-primary\\`'s solid tone).\n\n## Automatic dark mode\n\nDark mode re-points which step each token reads, under \\`${DARK_SEL}\\`:\nbackground and text ends of each scale swap, while the **solid family stays mode-stable**\nalong with the \\`text-on-<role>\\` foreground computed against it — so a filled button keeps\nits identity when the appearance flips. There is no per-appearance scheme grammar to author\nand no named steps: a role token means the same *job* in both appearances.\n\nRaw hue steps (\\`--color-<hue>-<step>\\`) are the exception — they are fixed values and are\n**not** re-pointed. Reach for a role token unless you specifically want a colour that\nignores the appearance.\n\nTwo attributes, one flip: \\`data-brx-theme\\` is Bricks' own (Bricks sets it on the\nWordPress target), \\`data-theme\\` is what the shipped \\`<wc-color-scheme-toggle>\\` writes on\n\\`<html>\\`, so the toggle works on every other target. Set either.\n\nThe OS preference is a **second, opt-in block**. Set\n\\`designSystem.defaultColorScheme: \"system\"\\` in your site config and the same delta is emitted again inside\n\\`@media (prefers-color-scheme: dark)\\`, under\n\\`${SYSTEM_DARK_SEL}\\` — i.e. whenever no explicit choice has been made. That is what makes\n\\`<wc-color-scheme-toggle>\\`'s \"System\" position resolve to the OS (it *removes* the attribute,\nso without this block it fell through to light), and it gives a no-JS page the OS\nappearance, which the toggle alone never could. An explicit light choice still wins.\n\nIt is opt-in rather than default because turning it on flips a site dark for dark-OS\nvisitors, which is the site's decision and not the design system's.\n\n## Contrast guarantees\n\nEnforced **at build time** — a violation fails \\`generate\\`, so an unreadable pairing cannot\nship. In both appearances:\n\n| tier | target | applies to |\n| --- | --- | --- |\n| text | APCA Lc ≥ 75 | \\`text-<role>\\` on the role's primary background |\n| secondary | Lc ≥ 60 | text on any other background plane; \\`text-<role>-muted\\`; \\`text-on-<role>\\` on its solid |\n| non-text | Lc ≥ 45 | \\`icon-<role>\\`, and a surface role's \\`border-<role>-bold\\` |\n\nTwo deliberate exemptions: \\`text-<role>-x-muted\\` (placeholders) and \\`-xx-muted\\` (disabled\ntext) are *required* to look unavailable, and holding them to the body-text bar would defeat\nthe affordance. Nothing else is exempt.\n\nChromatic text is checked against the **surface planes it actually sits on**, not only its\nown tints — coloured text appears over the page far more often than over its own wash.\n\nA \\`tones\\` kit thin enough that snapping can't cover a tier is reported rather than shipped;\nthe fix is another tone, and the failure says so.\n`;\n}\n\nfunction renderScalesConcept(ds: DesignSystem): string {\n const t = ds.typeScale;\n const s = ds.spaceScale;\n const scaleLine = (label: string, sc: typeof t): string =>\n sc\n ? `- **${label}**: base \\`${sc.base}\\` at step \\`${sc.names?.[(sc.baseStep ?? 1) - 1] ?? sc.baseStep}\\`, ratio ${sc.ratio}${sc.fluid ? ` (${sc.fluid.minRatio} below ${sc.fluid.minVw})` : ''}; steps ${code(sc.names ?? [])}.`\n : `- **${label}**: not configured.`;\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops type & space scales — fluid modular scales',\n description:\n 'How typeScale and spaceScale compile to clamp()-based fluid modular scales, and which utilities consume the resulting tokens.',\n resource: DS_PATH,\n tags: ['typography', 'spacing', 'fluid', 'modular-scale', 'design-system'],\n })}\n\n# Type & space scales\n\nBoth scales share one model (authored in \\`design-system.json\\` as \\`typeScale\\` /\n\\`spaceScale\\` — see [authoring.md](../authoring.md)): a **fluid modular scale**.\n\n## The model\n\n- \\`base\\` anchors the value at \\`baseStep\\`; every other step is a power of the \\`ratio\\`\n away (step n = base × ratio^(n − baseStep)).\n- With \\`fluid\\`, each step compiles to a **\\`clamp()\\`**: the scale uses \\`fluid.minRatio\\`\n at/below \\`fluid.minVw\\` and grows to \\`ratio\\` at \\`fluid.maxVw\\`, interpolating between —\n so large steps spread apart on wide viewports and compress on phones, with no\n breakpoint jumps. \\`baseline\\` names the pivot step that stays closest to \\`base\\`.\n- \\`names\\` become the token suffixes.\n\n${scaleLine('Type', t)}\n${scaleLine('Space', s)}\n\n## What consumes them\n\n- **Type**: \\`--text-<name>\\` tokens → typography role sizes (\\`font-<role>\\` classes,\n heading defaults) and text-size utilities.\n- **Space**: \\`--space-<name>\\` tokens → gap (\\`g\\`), spacing utilities, and \\`rhythm\\`\n (relationship-based vertical margins between headings, paragraphs, lists, media).\n Prefer \\`rhythm\\` for vertical flow over per-element margins.\n- In the \\`tailwind\\` format these stay in their own namespaces (\\`--text-*\\` via \\`@theme\\`,\n \\`--space-*\\` as plain vars) — see [formats.md](../formats.md) for why \\`--spacing-*\\` is\n deliberately not used.\n`;\n}\n\nfunction renderPatternsConcept(ds: DesignSystem): string {\n const items = (ds.patterns?.items ?? {}) as Record<string, { group?: string }>;\n const groups = Object.keys(ds.patterns?.groups ?? {});\n const patternNames = Object.keys(items);\n const hookTable = Object.entries(BASE_HOOK)\n .map(([prop, sfx]) => `| \\`${prop}\\` | \\`--${sfx}-<pattern>\\` |`)\n .join('\\n');\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops component patterns — token cascade, override hooks, states',\n description:\n 'How pattern CSS is assembled: the token cascade (defaults → groups → per-pattern overrides), per-pattern override-hook variables, state shortcuts, and role variants.',\n resource: DS_PATH,\n tags: ['patterns', 'components', 'cascade', 'css', 'design-system'],\n })}\n\n# Component patterns — the CSS chain\n\nPatterns (currently ${code(patternNames)}) are authored declaratively under \\`patterns\\` in\n\\`design-system.json\\` (see [authoring.md](../authoring.md)) and compiled to CSS in a\n**components cascade layer** — so utility classes, which live in a later layer, always win over\npattern styling without specificity fights. \\`class=\"card bg-danger-muted\"\\` tints the card.\n\nThe layer names differ by format, because each defers to its host:\n\n| format | layer stack (last wins) |\n| --- | --- |\n| \\`css\\`, \\`bricks\\` | \\`vitops.base\\` → \\`vitops.components\\` → \\`vitops.utilities\\` |\n| \\`tailwind\\` | Tailwind's own \\`theme\\` → \\`base\\` → \\`components\\` → \\`utilities\\` |\n\n**Your own CSS beats all of it.** Unlayered styles outrank every cascade layer regardless of\nspecificity, so a plain stylesheet, an Astro scoped \\`<style>\\`, or a Bricks-authored class\noverrides the framework with no \\`!important\\` and no specificity escalation. That is the\nintended override story.\n\nThe one thing to watch: a **reset** must be layered too, and ordered *below* the framework —\nleft unlayered it beats the very component rules it is meant to sit under (a bare\n\\`p { margin: 0 }\\` would defeat \\`.rhythm\\`). Declare the order before you load the stylesheet,\nsince layer precedence is fixed by first declaration:\n\n\\`\\`\\`html\n<style>@layer my.reset, vitops.base, vitops.components, vitops.utilities;</style>\n<link rel=\"stylesheet\" href=\"/styles.css\">\n\\`\\`\\`\n\nPut it *after* the link and \\`my.reset\\` becomes a new name introduced later — which sorts\n**last**, i.e. highest priority, and the reset wins. That is the one non-obvious step.\n\n## 1 — Token cascade\n\nShared geometry resolves through a variable chain, most-specific first:\n\n- \\`patterns.defaults\\` → \\`--<prop>-default\\` (cascade-wide fallbacks).\n- \\`patterns.groups.<group>\\` → \\`--<prop>-<group>\\` (e.g. groups ${code(groups)}); a pattern\n opts in via its \\`group\\` key.\n- Per-pattern: each grouped pattern gets aliases \\`--<prop>-<name>-group\\` →\n \\`var(--<prop>-<group>)\\`, and \\`overrides\\` replace individual aliases with literal values.\n- \\`patterns.radii\\` → \\`--br-<name>\\` shape primitives; \\`patterns.z\\` → \\`--z-tier-<name>\\`.\n\n## 2 — Base declarations & override hooks\n\nEach pattern's \\`base\\` block is emitted on its selector:\n\n- \\`class\\` only → \\`.<class ?? name>\\`, at normal class specificity.\n- \\`element\\` only → a **zero-specificity** \\`:where(<element>)\\` rule, so author CSS can always\n override it.\n- **both** → one \\`:where(<element>, .<class>)\\` rule (e.g. \\`:where(button, .btn)\\`). The element\n gets the styling with no class needed, the class carries it to any other tag, and — because the\n whole thing sits at zero specificity — any explicit class wins, including a louder pattern\n (\\`.cta\\`) or a component's own rule (\\`.dialog__close\\`).\n\nGeometry properties are wrapped in a **per-pattern override hook**:\n\n| base property | hook variable |\n| --- | --- |\n${hookTable}\n\ne.g. \\`padding: var(--p-btn, 0.4em 0.8em)\\` — a consumer restyles every button by setting\n\\`--p-btn\\` on \\`:root\\`, without touching the pattern. The hook is named after the pattern's\n**key**, not its class.\n\n\\`background\\` and \\`background-color\\` share the \\`bg\\` hook, since a pattern may author either.\nThat is what makes a pattern's fill **undoable** — a flat, border-only card:\n\n\\`\\`\\`html\n<!-- via the hook: applies wherever you set it, including :root for all cards -->\n<div class=\"card\" style=\"--bg-card: transparent; --ds-card: none\">…</div>\n\n<!-- or compose a utility, which reads better inline and is what most authors want -->\n<div class=\"card bg-transparent\" style=\"--ds-card: none\">…</div>\n\\`\\`\\`\n\n\\`bg-transparent\\` and \\`bg-inherit\\` are emitted for \\`css\\`/\\`bricks\\`; in \\`tailwind\\` they\ncome from Tailwind itself. There is no utility for the shadow, so \\`--ds-card: none\\` is the\nway to drop it in every format.\n\nRole variants are emitted as their own rules and are **not** wrapped, so setting \\`--bg-card\\`\ntunes the default fill without silently defeating \\`.card-danger\\`.\n\n## 3 — States\n\n\\`states\\` (hover / active / focus-visible) compile from shortcuts:\n\n- \\`step: n\\` — intensify the pattern's colour one rung: fills swap\n \\`--color-bg-<role>-solid\\` → \\`-solid-bold\\`; text patterns swap\n \\`--color-text-<role>\\` → \\`--color-text-<role>-bold\\`.\n- \\`scale: 0.97\\` — transform scale; \\`lift: \"<length>\"\\` — \\`translate: 0 calc(-1 * <length>)\\`.\n- \\`shadow: \"<name>\"\\` — \\`filter: drop-shadow(var(--shadow-<name>))\\`; \\`shadow: true\\` — the\n generic lift box-shadow.\n- \\`ring: true\\` — focus ring (\\`box-shadow\\` in the role's solid tone, or\n \\`--color-border-focus\\` when the pattern has no role; outline removed).\n- \\`css: { … }\\` — raw declarations escape hatch.\n\nAny pattern with states also gets a composed transition block (translate / scale / filter /\nbox-shadow / colours, \\`--interact-duration\\` / \\`--interact-easing\\` overridable). Hover\nrules are wrapped in \\`@media (hover: hover)\\` so touch devices never stick.\n\n## 4 — Role variants\n\n\\`roles\\` lists semantic colour variants: class patterns emit \\`.<pattern>-<role>\\`\n(\\`.badge-success\\`). A pattern with an \\`element\\` emits both the bare role class on the\nelement and the \\`-<role>\\` form (\\`:where(button, .btn).danger, .btn-danger\\`), so the same\nvariant works on a non-element host — both at class specificity, so neither outranks a\nplain class. Fill\npatterns set \\`background-color: var(--color-bg-<role>-solid)\\` +\n\\`color: var(--color-text-on-<role>)\\`; text patterns use \\`var(--color-text-<role>)\\`, the\ntoken guaranteed legible over a surface in both appearances. \\`default_role\\` colours the\nbare, unsuffixed pattern. States re-apply per variant with the variant's role.\n`;\n}\n\n/**\n * All three tiers in ONE doc — the agent-facing projection of `TIERS`.\n *\n * Four columns, three tiers: Astro and Bricks are both the platform-wrapper tier,\n * split by package rather than ranked.\n *\n * The docsite projects each tier as its own page, because a human arrives already\n * knowing which stack they are in (\"show me the Astro components\"). An agent\n * arrives the other way round: it knows the *pattern* it needs and has to be told\n * which tiers offer it and which call to make. Four docs would mean an agent\n * fetching `components/astro` learns `<Tree />` exists and never learns it must not\n * wrap it in `<wc-tree>` — the composition only exists between the tiers, so the\n * projection that serves agents is the one that keeps them together.\n *\n * `ds` is read for one thing: whether each config-authored pattern is actually\n * declared in THIS consumer's `patterns.items`. `TIERS.css.generated` records that a\n * pattern is *of that kind* against this repo's reference config; it cannot know\n * that a given consumer dropped `card`. Reporting a class that this config emits no\n * CSS for is the failure worth preventing here.\n */\nfunction renderComponentsConcept(ds: DesignSystem): string {\n const declared = new Set(Object.keys(ds.patterns?.items ?? {}));\n // Table cells: a literal pipe would split the column, and `use` strings are prose.\n const cell = (s: string) => s.replace(/\\|/g, '\\\\|');\n const code = (s: string) => `\\`${s}\\``;\n const list = (xs: string[]) => xs.map(code).join(', ');\n\n const tiersOf = (name: string): string[] =>\n (['css', 'wc', 'astro', 'bricks'] as const).filter((t) =>\n tierPatterns(t).some((p) => p.name === name),\n );\n\n const overview = TIER_NAMES.map((name) => {\n const e = TIERS[name]!;\n return `| ${code(name)} | ${tiersOf(name).join(' · ')} | ${cell(e.use)} |`;\n }).join('\\n');\n\n const wc = tierPatterns('wc')\n .map(({ name, entry }) => {\n const w = entry.wc!;\n const ships = w.registered ? code('elements.js') : w.bundle ? code(w.bundle) : 'nothing';\n return `| ${code(`<${w.tag}>`)} | ${code(name)} | ${ships} | ${cell(w.adds)} |`;\n })\n .join('\\n');\n\n const astro = tierPatterns('astro')\n .flatMap(({ name, entry }) =>\n entry.astro!.map(\n (a) =>\n `| ${code(a.component)} | ${code(name)} | ${\n a.wraps === 'wc'\n ? `the ${code(`<${entry.wc!.tag}>`)} tag, fallback inside`\n : 'tier-1 markup — no web component'\n } |`,\n ),\n )\n .join('\\n');\n\n const bricks = tierPatterns('bricks')\n .map(({ name, entry }) => `| ${code(entry.bricks!)} | ${code(name)} |`)\n .join('\\n');\n\n const css = tierPatterns('css')\n .map(({ name, entry }) => {\n const c = entry.css;\n const config = !c.generated\n ? '—'\n : declared.has(name)\n ? 'declared'\n : '**absent from this config — no CSS emitted**';\n return `| ${code(name)} | ${c.partial ? code(c.partial) : '—'} | ${\n c.classes.length ? list(c.classes) : '—'\n } | ${config} |`;\n })\n .join('\\n');\n\n // `BASE_HOOK` maps a CSS property to a var suffix, so it has no single spelling to\n // quote — derive the distinct hooks rather than interpolating the object.\n const hooks = [...new Set(Object.values(BASE_HOOK))]\n .map((sfx) => code(`--${sfx}-<pattern>`))\n .join(', ');\n\n const unshipped = tierPatterns('wc')\n .filter(({ entry }) => !entry.wc!.registered && entry.wc!.bundle?.startsWith('(none'))\n .map(({ entry }) => code(`<${entry.wc!.tag}>`))\n .join(', ');\n\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops components — which tier provides a pattern, and what to write',\n description:\n 'Every UI pattern across the three tiers (CSS classes, wc-* web components, and the platform wrappers: Astro components and Bricks elements): which tiers provide it, which call to make, and how the tiers compose.',\n resource: DS_PATH,\n tags: ['components', 'web-components', 'astro', 'bricks', 'tiers', 'design-system'],\n })}\n\n# Components\n\nA pattern is provided by up to **three tiers**, and they **compose** rather than compete:\n\n1. **CSS framework classes** — every pattern expressible in pure HTML/CSS. Reach here first.\n2. **Web components** (${code('<wc-*>')}, Lit) — only where a pattern genuinely benefits from\n progressive enhancement. The slotted markup is the fallback and must be usable with no JS;\n the element parses and augments it in place.\n3. **Platform wrappers** — authoring conveniences that generate the correct markup at build\n time, using the classes and elements of tiers 1 and 2. They must not require runtime JS.\n Where a pattern has a web component, the wrapper emits that tag **with the accessible\n fallback inside it**. Two platforms:\n - **Astro components** (${code('@getvitops/astro')})\n - **Bricks elements** (WordPress / Bricks Builder)\n\n**Astro and Bricks are the same tier**, not tiers 3 and 4. They are siblings chosen by which\nplatform you are on — no project uses both, and neither outranks the other. The tables below\ngive them separate columns because they are separate packages, not separate levels.\n\n## Choosing\n\n**Use the highest tier available for your stack, and write only its call.** In Astro\nthat is the Astro component; in Bricks the element; anywhere else the classes, plus the\n${code('<wc-*>')} tag when one exists.\n\nThe trap is composing two tiers by hand. When ${code('wraps')} below says the Astro component\nemits the tag, that one call is the whole composition —\n${code('<wc-tree><Tree /></wc-tree>')} nests two elements on one tree. A tier-3 component that\nwould need runtime JS is in the wrong tier: build a web component instead and have the wrapper\nemit its tag.\n\n## Every pattern\n\n| Pattern | Tiers | What to write |\n| --- | --- | --- |\n${overview}\n\n## Web components\n\nShipped as feature-detected, deferred ES-module bundles. ${code('elements.js')} carries the\nregistered set; ${code('<wc-consent>')} and ${code('<wc-theme-editor>')} ship separately, the\nfirst so a site needing consent does not download a rendering framework, the second because it\nis tooling and opt-in per consumer.\n\n| Tag | Pattern | Ships in | What JS adds over the fallback |\n| --- | --- | --- | --- |\n${wc}\n\n${\n unshipped\n ? `${unshipped} are **registered but in no bundle** (the editor-v2 track). The tags are inert in a consumer project — they are listed so that \"the tag does nothing\" is documented rather than discovered.`\n : ''\n}\n\n## Astro components\n\n| Component | Pattern | Emits |\n| --- | --- | --- |\n${astro}\n\n## Bricks elements\n\nControls, defaults and seeded children for each are in [the elements reference](../bricks/elements.md).\n\n| Element | Pattern |\n| --- | --- |\n${bricks}\n\n## CSS\n\n${code('patterns.items')} patterns get the full token cascade — ${code('base')} declarations,\n${code('states')}, role variants and override hooks (${hooks}); see\n[component patterns](patterns.md). A structural partial has none of those. The class lists below\nare representative, not exhaustive — [the class vocabulary](../css/classes.md) states the naming\nrules that generate them all.\n\n| Pattern | Partial | Classes | ${code('patterns.items')} |\n| --- | --- | --- | --- |\n${css}\n`;\n}\n\n// ── Reserved index.md listings (no frontmatter) ──────────────────────────────\nfunction renderTopIndex(): string {\n return `${INDEX_NOTE}\n\n# Vitops design system\n\nLLM-oriented documentation bundle (Open Knowledge Format) for the Vitops design system — a\nvariable-driven CSS framework plus progressively-enhanced web components, generated from\n\\`design-system.json\\` and published alongside the deployed theme.\n\n# Contents\n\n* [Authoring reference](authoring.md) - every design-system.json field, generated from the JSON Schema\n* [Config reference](config.md) - every field of the three-section config (designSystem / organization / site), generated from the JSON Schema\n* [Output formats](formats.md) - tailwind vs css vs bricks vs design: what's emitted, what the platform provides, which utilities Tailwind owns\n* [Concepts](concepts/) - the colour system, type/space scales, pattern CSS architecture, the four component tiers, icons, and the consent / tracking / search / legal subsystems\n* [CSS framework](css/) - the class vocabulary (colour, type, space, layout, animation, component patterns), stated as naming rules\n* [Bricks Builder](bricks/) - custom elements and how to style them\n`;\n}\n\nfunction renderIconsConcept(): string {\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops icons — one semantic vocabulary across icon sets',\n description:\n 'Semantic icon names that resolve per configured set, how the bundle is derived on a server build, and the three delivery paths (astro-icon, astro-iconset, SVG sprite).',\n resource: DS_PATH,\n tags: ['icons', 'svg', 'sprite', 'astro-icon', 'design-system'],\n })}\n\n# Icons\n\nIcons are named by **meaning**, not by set. \\`menu\\` resolves to \\`fa7-solid:bars\\`,\n\\`lucide:menu\\` or \\`ph:list\\` depending on which set the site configures, so changing\nsets is a config edit rather than a find-and-replace across templates.\n\nThe escape hatch is deliberate and always available: **a name containing \\`:\\` passes\nthrough untouched**. \\`<Icon name=\"simple-icons:zoho\" />\\` renders that exact glyph\nwhether or not the semantic map knows it.\n\n## Declaring them\n\nThe \\`icons\\` block lives in the **site config**, not \\`design-system.json\\` — it\ndescribes what a site uses, not what the design system defines.\n\n\\`\\`\\`json\n{\n \"icons\": {\n \"ui\": \"ph\",\n \"brand\": \"simple-icons\",\n \"weight\": \"bold\",\n \"semantic\": [\"menu\", \"close\", \"arrow-right\"],\n \"simple-icons\": [\"zoho\", \"cloudflare\"],\n \"sprite\": true\n }\n}\n\\`\\`\\`\n\n\\`ui\\` and \\`brand\\` pick which set a semantic name resolves against. Any other key is\nan iconify collection name with an explicit list, passed through verbatim.\n\n**\\`weight\\` is only meaningful for sets that encode weight in the icon NAME.**\nPhosphor does (\\`list\\`, \\`list-bold\\`, \\`list-fill\\`), so \\`ph\\` accepts it; Font Awesome\nsplits weights across collections instead (\\`fa7-solid\\` vs \\`fa7-regular\\`), so there\nthe weight is part of the prefix and this key is ignored.\n\n## Why the bundle list exists\n\nastro-icon is **zero-config on a static build**. Under \\`output: 'server'\\` it bundles\n*every icon in a set* unless given an \\`include\\` map — which is why projects end up\nhand-maintaining one.\n\nThe \\`icons\\` option on \\`vitops()\\` derives it by scanning your source, merged with\nwhatever you declare. On a static build **no include is passed at all**: there is\nnothing to trim there, and a list could only drop a glyph the scan couldn't see.\n\nTwo failure modes, treated differently on purpose:\n\n- A name you **declared** that doesn't resolve is a config error and **throws**.\n- A name only the **scan** found and can't resolve just **warns** — a bare unmapped\n name is more often a local \\`src/icons/*.svg\\` than a mistake, and a dev server\n that dies on a template typo is worse than one that tells you.\n\nNames computed at runtime (\\`<Icon name={expr} />\\`) can't be read statically. They are\nreported with file and line, never guessed at — declare them in \\`semantic\\` or a\nper-set list. Run \\`vitops icons\\` to see the whole report.\n\n## Delivery\n\n| Path | Used by | Needs |\n| --- | --- | --- |\n| \\`astro-icon\\` / \\`astro-iconset\\` | Astro sites | the integration, an optional peer |\n| **SVG sprite** (\\`icons.svg\\`) | Bricks/WordPress, EmDash renderers, plain HTML | \\`icons.sprite: true\\` |\n\nThe sprite is the no-JavaScript path: \\`<svg><use href=\"/vitops/icons.svg#ph--list\"></svg>\\`.\nIds are the qualified name with \\`:\\` replaced by \\`--\\` (\\`:\\` is not valid in a fragment\nidentifier), **plus a set-independent \\`icon-<name>\\` alias for every semantic name** —\nso sprite markup survives an icon-set change the same way \\`resolveIcon\\` protects Astro\ncall sites.\n\nIn WordPress, \\`vitops_icon('menu')\\` and \\`[vitops_icon name=\"menu\"]\\` emit that markup,\nand a **Vitops → Icon** Bricks element wraps the same helper.\n\n⚠️ An external-file \\`<use>\\` is **same-origin only** and dead under \\`file://\\`. Serving\n\\`dist/\\` from a different origin makes every icon vanish with no console error.\n\n## Markup\n\nAlways the framework's \\`.icon\\` box:\n\n\\`\\`\\`html\n<span class=\"icon\" aria-hidden=\"true\"><svg>…</svg></span>\n\\`\\`\\`\n\n\\`.icon\\` sizes in \\`em\\` via \\`--icon-size\\` (default \\`1.25em\\`) and sets \\`fill: currentColor\\`,\nso an icon inherits the colour of whatever it sits in. Because \\`.cta\\` and\n\\`:where(button, .btn)\\` are already \\`inline-flex\\` with a \\`gap\\`, **a start or end icon is\nchild order — not a modifier class**.\n\nIcons are \\`aria-hidden\\` by default. Pass a label only when the icon carries meaning on\nits own; beside a text label it would be announced twice.\n\nNote \\`.icon-mask\\` is a different thing: the CSS-only adornment path used by\n\\`.link--icon::before\\`, where the glyph is a \\`mask-image\\` on a pseudo-element and there\nis no markup to hang an \\`<svg>\\` on.\n`;\n}\n\nfunction renderConsentConcept(): string {\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops consent — a demand-driven permission gate',\n description:\n 'How the consent gate works: inert `type=\"text/plain\"` tags, demand-driven prompting, three-valued choices, and the invariants that make the gate real rather than a promise.',\n resource: CONFIG_PATH,\n tags: ['consent', 'cookies', 'privacy', 'gdpr', 'analytics'],\n })}\n\n# The consent gate\n\n\\`@getvitops/core/consent\\` is a **general permission gate, not an analytics feature**. Anything\nmarked \\`data-consent=\"<category>\"\\` waits on one visitor choice — a third-party tag, an A/B\nassignment, a personalisation cookie, an embedded map. It carries no Lit and is a separate\nbundle from \\`elements.js\\`, because consent is a legal requirement: a site that needs it must\nnot be made to download a rendering framework first.\n\nCategories are \\`necessary\\`, \\`analytics\\`, \\`marketing\\`, \\`preferences\\`.\n\n## Gating something\n\nA gated script renders **inert**, with its URL parked on \\`data-src\\`:\n\n\\`\\`\\`html\n<script\n type=\"text/plain\"\n data-vitops-tag\n data-consent=\"analytics\"\n data-consent-cookies=\"_ga,_ga_*\"\n data-src=\"https://example.com/analytics.js\"\n></script>\n\\`\\`\\`\n\n⚠️ **\\`type=\"text/plain\"\\` is what makes the gate real. Never give a gated tag a live \\`src\\`.**\nThe browser neither parses the body nor fetches the library, so an undecided visitor's page\nissues **no third-party request at all**. A gate that instead loads a script and politely asks\nit not to track is a promise, not a gate.\n\n\\`data-consent-cookies\\` is written by whoever emitted the tag, because that is who knows what\nthe provider sets. It is what a revoke clears.\n\n## Demand-driven: two different ideas\n\n**Offered** categories are a build-time fact — which rows \\`<CookieConsent />\\` renders. The\ndefault is deliberately generous; a hidden row costs nothing.\n\n**Demanded** categories are a runtime fact — what something has actually asked for and the\nvisitor hasn't answered. The banner appears only when a demand is outstanding, so **a site\nwhose only provider is cookieless never interrupts anyone.**\n\nDemand is registered by:\n\n- a gated element **reaching its loading strategy** — so an \\`idle\\` tag asks after \\`load\\`, off\n the LCP path, and an \\`interaction\\` tag asks only once the visitor acts; or\n- an explicit \\`require()\\` / \\`request()\\`.\n\n## The runtime API\n\n\\`window.vitopsConsent\\`, plus a \\`vitops:consent\\` \\`CustomEvent\\` on \\`document\\`.\n\n| Call | Does |\n| --- | --- |\n| \\`granted(cat)\\` | Is it granted? **Passive — does not prompt.** |\n| \\`require(cat)\\` | Declare a need *now* and report whether it's granted. **This is what raises the banner.** Synchronous. |\n| \\`request(cat)\\` | \\`require()\\`, but resolves once the visitor answers *this* category. |\n| \\`needed()\\` | Is a prompt warranted? True only if something demanded an unanswered category. |\n| \\`demanded()\\` | What has asked, this page view. |\n| \\`set(patch)\\` | Record a decision for exactly these categories. |\n| \\`open()\\` | Re-show the banner without discarding the current choice. |\n| \\`reset()\\` | Forget the choice and re-prompt. |\n\n⚠️ If you want a side effect to be *possible*, you must \\`require()\\` it. Calling \\`granted()\\`\nand doing nothing else is a **permanent no-op** on any site where nothing else demands that\ncategory: it is never offered, never granted, and your write never happens — silently.\n\n## An absent gate means \"store freely\"\n\n\\`consent.js\\` and \\`elements.js\\` are both deferred with no ordering between them, so a component\ncan upgrade and be clicked before the gate exists. \\`<Head />\\` therefore emits a synchronous\ninline **stub** that answers \\`false\\` and queues; the runtime replays the queue on load.\n\nThat makes the absence of \\`window.vitopsConsent\\` meaningful: it reliably means **this site has\nno gate**. Read it as *store freely* — never as *denied*.\n\nBecause the stub is not the full API, listen for the \\`vitops:consent\\` event rather than calling\n\\`subscribe()\\`, which the stub does not have.\n\n## Three-valued, and why it matters\n\nThe cookie (\\`vitops_consent\\`, v2) records each category as \\`true\\` / \\`false\\` / **\\`null\\`**.\n\"Not asked\" is a third value, not a synonym for \"declined\" — and only \\`null\\` can be\nre-prompted. That is what lets a \\`preferences\\` demand arrive *after* an \\`analytics\\` prompt was\nalready answered.\n\nThree consequences:\n\n- **Nothing is stored until the visitor chooses.** Absence of the cookie is *undecided*, and\n undecided denies everything but \\`necessary\\`. If merely showing the banner wrote state, the\n banner would be the thing it asks permission for.\n- **A corrupt or wrong-version cookie re-prompts.** It does not read as \"decided, all denied\" —\n that safe-looking read strands a visitor who wants to opt in with no way to say so.\n- **A patch must cover exactly the categories a showing put on screen.** \\`<wc-consent>\\` builds\n its own patch rather than calling \\`acceptAll()\\`, because \"Accept\" on a preferences-only\n prompt that also granted analytics would be consent nobody gave. \\`acceptAll()\\` /\n \\`rejectAll()\\` mean *literally every* optional category — widening a patch to \"all\" is the\n easy version of this bug.\n\n## Revoking reloads\n\nAn already-executing tracker cannot be unloaded. Clearing its cookies only stops it identifying\nthe visitor *next* time, while the running instance keeps reporting until the document goes\naway — so a revoke clears the named cookies and **reloads**. (\\`reloadOnRevoke = false\\` defers\nthat to the next navigation.)\n\n## The notice must match what loads\n\nThe same config facts drive the **generated cookie notice** — see\n[legal.md](legal.md). \\`site.analytics.clarityId\\` is what makes the notice name Clarity; the\nsame provider in \\`vitops({ analytics })\\` is what makes the tag load. The Astro integration\n**warns when the two disagree**, because a site running a tag its own notice omits is a\ncompliance defect, not a documentation gap.\n\n## Reference consumer\n\n\\`<wc-color-scheme-toggle>\\` applies the chosen scheme **immediately** and gates only the\n\\`localStorage\\` write. Nothing about honouring a visitor's click needs permission; remembering\nit does.\n`;\n}\n\nfunction renderTrackingConcept(): string {\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops conversion tracking — ad attribution and notifications',\n description:\n 'How an ad click becomes a notified conversion: the `_ac` cookie, consent-demanding capture, the pure notification planner, and the Cloudflare email channel.',\n resource: CONFIG_PATH,\n tags: ['tracking', 'attribution', 'conversions', 'notifications', 'consent'],\n })}\n\n# Conversion tracking\n\nA visitor arrives on an ad carrying a click ID; \\`<Tracking />\\` captures it into the\nfirst-party **\\`_ac\\`** cookie; when they later submit a form or tap a \\`tel:\\` link,\n\\`createConversionRoute()\\` reads the cookie back and notifies whoever the config names.\n\n\\`\\`\\`json\n{\n \"site\": {\n \"tracking\": { \"enabled\": true, \"category\": \"marketing\" },\n \"notifications\": { \"email\": \"leads@example.com\" }\n }\n}\n\\`\\`\\`\n\nA bare address is shorthand for \\`{ provider: \"cloudflare\", to }\\`. The recipient otherwise\nfalls back to the primary location's email, and the sender to \\`noreply@<domains.canonical>\\`.\n\n## Where each piece lives\n\n| Layer | Module | Why there |\n| --- | --- | --- |\n| Attribution vocabulary + cookie | \\`@getvitops/utils/tracking\\` | Needed on **both** sides of the wire |\n| Plan / render / send | \\`@getvitops/utils/notify\\` | Pure planner, I/O sender |\n| Capture script, \\`<Tracking />\\`, route factory | \\`@getvitops/astro\\` | Beside the analytics components |\n\nBoth utils entries are **separate subpaths** because they are the only modules that run in a\n**Worker** rather than at build time. Keeping them off the package index is what stops a\nconversion endpoint pulling \\`sharp\\` into its bundle. Neither may use a Node builtin.\n\n**Import them from \\`@getvitops/astro\\` if that is your only direct dependency.**\n\\`@getvitops/astro/tracking\\` re-exports everything in \\`@getvitops/utils/tracking\\` (plus\n\\`TRACKING_ENDPOINT\\`), so the flow works with one install — under strict pnpm, app code cannot\nresolve a transitive dependency, and \\`@getvitops/utils\\` would otherwise have to be added by\nhand. Do **not** reach for the same symbols on \\`@getvitops/astro\\`'s index instead: that entry\npulls the integration and its Node builtins, which is the import that drags \\`sharp\\` toward a\nWorker bundle. \\`@getvitops/astro/tracking\\` and \\`@getvitops/astro/routes\\` are both clean.\n\n⚠️ The route you mount must answer **\\`/api/track\\`** (\\`TRACKING_ENDPOINT\\`) — the capture\nscript beacons \\`tel:\\` conversions there, and a route at any other path means every call\nconversion 404s silently. The integration warns at build when tracking is on and no such route\nexists.\n\n## The capture demands consent\n\n\\`_ac\\` is a 90-day identifier tying a visitor to an ad, so it waits on \\`marketing\\` (override\nwith \\`site.tracking.category\\`).\n\n⚠️ The script calls **\\`require()\\`**, not \\`granted()\\` — \\`require()\\` is what *raises the\nbanner*. A passive \\`granted()\\` here is a permanent no-op: nothing else on a page demands\n\\`marketing\\`, so it is never offered, never granted, and \\`_ac\\` is never written — silently, on\nevery gated site. The integration adds \\`marketing\\` to the offered categories when tracking is\non, so there is a row for the category the script will ask about.\n\n**Only an arrival that carried something asks.** The demand is guarded on the URL actually\nholding a click ID or UTM, so an organic visitor — who has nothing to attribute — is never\ninterrupted. That is demand-driven consent applied to attribution.\n\n**The capture is synchronous; only the write waits.** Reading the query string is not storage\nand needs no permission; *keeping* it does. The click ID is in the URL only on the landing\npage, so deferring the read would lose it outright.\n\nThe marker element carries \\`data-consent\\` but deliberately **not** \\`data-vitops-tag\\`: the\nscan never tries to \"activate\" it (it is ungated by design), while the revoke path — which\nqueries \\`[data-consent=\"…\"]\\` — still finds it and clears \\`_ac\\`.\n\n## The event is the abstraction\n\n\\`ConversionEvent\\` is the *fact*; how it reads belongs to the channel. That is what lets an SMS\nchannel render 160 characters from the same event an email renders in full.\n\n**The plan is pure and says why anything is skipped.** \\`planNotifications\\` touches no network\nand no binding, so a misconfigured site can be told exactly why no notification will arrive — a\nsilently unsent conversion notification is indistinguishable from no conversion.\n\n## The email channel\n\nCloudflare Email Sending's **current** binding — structured\n\\`env.EMAIL.send({ to, from, subject, html, text })\\`, not the legacy \\`EmailMessage\\` plus\nhand-built MIME. The binding is **passed in, never imported**, so utils takes no Cloudflare\ndependency.\n\nOnly transient codes are retried. \\`E_SENDER_NOT_VERIFIED\\` and friends are surfaced\n**verbatim**, because nothing here can check whether the sending domain was onboarded — run:\n\n\\`\\`\\`sh\nwrangler email sending enable <domain>\n\\`\\`\\`\n\nA generic \"send failed\" would hide the one thing worth knowing.\n\nOnly \\`email\\` is implemented. \\`sms\\` and \\`persist\\` are a planned seam\n(\\`NotificationsConfig\\` plus a sender with \\`sendEmail\\`'s signature); one channel is not enough\nto know what the abstraction should be.\n\n## Disclosure\n\n\\`_ac\\` is disclosed by the generated cookie notice as a first-party cookie. It has to be stated\nexplicitly: no provider table would ever name a first-party cookie, so a site running\nattribution alongside a **cookieless** analytics provider would otherwise be described as\nsetting no cookies at all. See [legal.md](legal.md).\n`;\n}\n\nfunction renderSearchConcept(): string {\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops search — Search Console onboarding and deploy notification',\n description:\n 'What search engines actually accept, why the Indexing API is deliberately not wired, and how `vitops search setup` and `vitops search notify` work.',\n resource: CONFIG_PATH,\n tags: ['seo', 'search-console', 'indexnow', 'sitemap', 'indexing'],\n })}\n\n# Search\n\nTwo commands, both anchored to a full config:\n\n- **\\`vitops search notify\\`** — tell search engines a deploy happened (from \\`site.seo.indexing\\`).\n- **\\`vitops search setup\\`** — onboard domains into Search Console (from \\`site.searchConsole\\`).\n\n## Start from what engines actually accept\n\nThe obvious assumption is wrong, and every design decision here follows from that:\n\n- **Google exposes no \"request indexing\" API.** The button in the Search Console UI is not in\n the Search Console API or anywhere else, and the **URL Inspection API is read-only**.\n- **The sitemap ping endpoint was removed in June 2023.** \\`google.com/ping?sitemap=\\` is a no-op.\n- **The Indexing API is scoped to \\`JobPosting\\` / \\`BroadcastEvent\\`.** It accepts other URLs and\n discards them; general use violates its terms, with *your own* GCP project on the line.\n ⚠️ **Deliberately not wired. Do not add it.**\n- **Google does not participate in IndexNow.** Bing, Yandex, Naver, Seznam and Yep do.\n\nSo \\`search notify\\` does every sanctioned thing and then **verifies**: resubmit the sitemap,\nping IndexNow, and \\`--check\\` inspects \\`priorityUrls\\` and exits non-zero on one Google hasn't\nindexed. That last part is what actually replaces the manual Search Console visit.\n\n⚠️ Never describe this as making Google re-index faster. It cannot.\n\n## \\`search notify\\`\n\n- **The pure/I-O split is the point.** The planner decides everything — which URLs, which\n channels, why each was skipped — and touches no network, no filesystem, no clock. That is what\n makes \\`--dry\\` a *complete* account of a run rather than an approximation.\n- **\\`lastmod\\` is not a nice-to-have, it is the mechanism.** The changed-URL diff compares each\n sitemap entry's \\`<lastmod>\\` against a stored snapshot. With no lastmod the diff can see pages\n appear and disappear but **never see one change** — so an edited page is never resubmitted, and\n the command looks healthy while doing less than it appears to. It counts lastmod-less entries\n and says so every run.\n\n \\`gitLastmod()\\` in \\`@getvitops/astro\\` derives real dates from \\`git log\\`. It is an exported\n helper rather than a \\`sitemap\\` option because it shells out to git and returns **nothing**\n from a shallow CI clone (\\`fetch-depth: 1\\`). It leaves an unmatched URL alone rather than\n stamping the build time: Google weighs lastmod only while it stays consistent with what\n actually changed, so a site that stamps every page every deploy teaches it to distrust the\n field site-wide.\n- **The \\`noindex\\` gate reads the environment, so the URLs must too.** The run is refused\n entirely when the resolved environment's \\`robots\\` contains \\`noindex\\` — submitting a staging\n host to IndexNow publishes it to several engines and invites them to crawl it, which a later\n directive does not undo. Origins therefore derive from \\`site.environments[env].url\\` **before**\n \\`domains.canonical\\`: the canonical is the *production* origin, so deriving from it while\n notifying staging would submit production URLs the gate would not catch.\n- **Verify the IndexNow key file before submitting.** A submission whose key file is unreachable\n returns \\`403\\`, but one whose key file is *reachable and stale* is accepted with \\`202\\` and then\n silently discarded. Only a prior GET distinguishes \"submitted\" from \"submitted and ignored\".\n The key is **not a secret** — the engine fetching it back is the ownership proof — so it lives\n in the config, and the Astro integration writes \\`public/<key>.txt\\` from it.\n- **Write the snapshot last, and only on success.** Writing it eagerly records URLs as notified\n that never were; because the next run diffs against it, one transient \\`503\\` would drop those\n pages from every future run — silently and permanently. A corrupt or absent snapshot reads as\n \"submit everything, and say so\", never as \"nothing changed\".\n\n## \\`search setup\\`\n\nAutomates the otherwise-manual DNS-paste / wait / verify / add-property dance.\n\\`site.searchConsole\\` is keyed by bare hostname (mirroring \\`site.dns\\`):\n\n\\`\\`\\`json\n{\n \"site\": {\n \"searchConsole\": {\n \"example.com\": {\n \"delegatedOwners\": [\"dev@example.com\"],\n \"fullUserGroup\": \"seo@example.com\"\n }\n }\n }\n}\n\\`\\`\\`\n\nPer domain it ensures the apex verification TXT in Cloudflare, verifies ownership via the Site\nVerification API (\\`DNS_TXT\\`), adds the \\`sc-domain:\\` property, then adds any\n\\`delegatedOwners\\`. The verification token is fetched live and written to DNS — never stored in\nthe config.\n\n- **Idempotency lives in the planner.** A step whose desired state already holds resolves to\n \\`skip\\`, so re-running an onboarded domain is a no-op **by construction**, not because the\n executors check twice. \\`--check\\` reports drift, exits non-zero and mutates nothing;\n \\`--dry\\` prints the plan and stops.\n- **DNS is only ever created, never edited or deleted.** The command never removes a record, so\n the Cloudflare executor simply has no update or delete verb.\n- **Verification retries with backoff, then reports PENDING — not failed.** \\`DNS_TXT\\`\n verification fails until the record propagates, which is slow, not broken. A domain still\n unverified after the last attempt is \\`PENDING\\`, and its property and owner steps are skipped\n for that run. Re-run later.\n- **Search Console has no user/permission API.** Adding a Google Group as a **Full User** is\n genuinely un-automatable, so \\`fullUserGroup\\` is surfaced as a **reminder** in the summary,\n never attempted. That is distinct from \\`delegatedOwners\\`, which *are* automated — those are\n Site Verification web-resource owners (an additive union, so an existing owner is never\n dropped), a different concept from Search Console property users. Don't conflate them.\n\n## Credentials\n\nAlways from the environment; never in the config. There is **one** token exchange and **two\ngrants**, tracking where each command runs:\n\n| Grant | Env vars | Used by |\n| --- | --- | --- |\n| **Service account** (JWT bearer) | \\`VITOPS_GSC_SERVICE_ACCOUNT\\` (inline JSON) or \\`GOOGLE_APPLICATION_CREDENTIALS\\` (path) | \\`search notify\\` — never expires, right for CI |\n| **User OAuth** (refresh token) | \\`VITOPS_GOOGLE_CLIENT_ID\\` / \\`_CLIENT_SECRET\\` / \\`_REFRESH_TOKEN\\` | \\`search setup\\` — **required** |\n\nCloudflare uses \\`CLOUDFLARE_API_TOKEN\\` (a \\`Zone:DNS:Edit\\` token; the standard \"Edit zone DNS\"\ntemplate also carries the \\`Zone:Read\\` the zone-by-name lookup needs).\n\n\\`search setup\\` requires user OAuth because **verifying a site makes the caller an owner** of\nthe property, and that should be a person, not a project robot. Note a refresh token can be\nrevoked, and for an OAuth client still in *Testing* publishing status Google expires it after\n**7 days** — fine for a one-time human setup, bad for a deploy step.\n\n**\\`search notify\\` accepts either**, preferring the service account when both are set. Search\nConsole does not care which identity calls it, and someone who has run \\`search setup\\` already\nholds a Google credential.\n\n⚠️ Do not add \\`googleapis\\` — an enormous dependency for a handful of REST endpoints in a CLI\nthat installs into every consumer project. The JWT is minted with ~30 lines of \\`node:crypto\\`.\n`;\n}\n\nfunction renderLegalConcept(): string {\n return `${frontmatter({\n type: 'Design Concept',\n title: 'Vitops legal documents — generated policy, terms and cookie notice',\n description:\n 'How the privacy policy, terms of service and cookie notice are derived from config facts, why the provider table exists, and the four delivery paths.',\n resource: CONFIG_PATH,\n tags: ['legal', 'privacy', 'cookies', 'pipeda', 'compliance'],\n })}\n\n# Legal documents\n\nA privacy policy, terms of service and cookie notice, rendered from a full config: the company\nfrom \\`organization\\`, what the site actually *does* from \\`site\\`.\n\nIt is a **sibling of the docs generator, not a \\`generate()\\` format** — structurally, not\nstylistically. \\`generate()\\` is keyed to a design system, so a \"legal format\" would be a format\nthat ignores its own input.\n\n## The governing rule\n\n**The config records facts; the template owns prose.**\n\nNothing in the derivation writes a sentence a lawyer would review, and no template invents a\nfact. That is what lets wording be corrected without touching your config, and your provider\nchange land without touching prose.\n\n⚠️ It also means **the fix for a wrong policy is a corrected config.** Hand-editing the output\nis overwritten by the next build.\n\n## What derives from what\n\n- **The provider table is what makes derivation possible.** A policy naming Plausible while the\n site runs GA is a compliance defect, not a typo — so the provider comes from *which analytics\n ID is set*, whether \\`site.security.turnstile.siteKey\\` exists, and what\n \\`site.deployment.platform\\` says. Never from a hand-maintained string.\n\n It covers only what the schema can imply. Everything else — payment, CRM, mail — is declared\n in \\`site.legal.privacyPolicy.processors\\` and flows through the same pipeline.\n\n- **\\`cookies: []\\` is meaningfully different from \\`undefined\\`.** It *asserts* a provider is\n cookieless (Plausible), which the cookie notice states **positively** rather than omitting.\n\n- **\"Stored in\" is not the same fact as \"reachable by\".** A processor's \\`storage\\` is where the\n information rests; \\`operatorCountry\\` is the jurisdiction that can compel the provider to hand\n it over. Privacy law turns on foreign **access**, not merely foreign storage, so the two get\n separate sentences — an Azure tenant in a Canadian region never moves the data and is still\n subject to US law. \\`country\\` is shorthand asserting both, and combining it with either is\n **rejected** rather than resolved by a silent rule: whether it narrows or adds is a\n contradiction between two legal claims, not a formatting choice.\n\n A \\`storage\\` entry may be \\`scope\\`d to a category, which is what makes a Canadian tenant\n holding identity data abroad expressible. A country in the policy's own jurisdiction is not a\n transfer and is filtered out — that is what stopped \\`country: \"Canada\"\\` rendering \"outside of\n Canada, including Canada\". Only what the config states is asserted: hosts like Cloudflare\n declare an \\`operatorCountry\\` and **no** storage, because anycast means the config cannot know\n which region served a request, and \"we don't know\" is a fact.\n\n- **Form templates are the PII inventory.** \\`site.templates\\` entries of type \\`form\\` are the\n only place the config says what personal information the site actually collects, so the\n disclosed list derives from their fields. \\`hidden\\` fields and honeypots are **excluded** —\n neither is visitor-supplied, and describing them as collected would be untrue.\n\n- **First-party cookies are declared, not detected.** The attribution cookie \\`_ac\\` is disclosed\n this way; see [tracking.md](tracking.md).\n\n## The markdown subset is closed\n\nWe author every template, so the renderer is exactly as capable as they are: \\`#\\`/\\`##\\`/\\`###\\`,\n\\`- \\` bullets, \\`> \\` quote, \\`**strong**\\`, \\`\\\\\\`code\\\\\\`\\`. **An unsupported construct is an error,\nnot a silent degrade** — that is what stops a literal \\`| --- |\\` reaching a published page.\n\nPortable Text maps the \\`> \\` quote to a banner block and **drops the \\`# \\` heading**, which is\nEmDash's own title field.\n\n## Jurisdictions\n\nAdding one is: author three templates, add one enum member, add one registry key. The two are\nchecked against each other at compile time, so skipping either **fails to compile** rather than\nrendering against the wrong body of law.\n\n⚠️ Only **\\`ca\\` (PIPEDA)** ships. Its prose names the Office of the Privacy Commissioner of\nCanada and frames transfers as \"outside of Canada\" — **do not reuse it for another\njurisdiction.**\n\n## Delivery: one renderer, four consumers\n\n| Consumer | How |\n| --- | --- |\n| **any stack** | \\`vitops legal [--doc <name>] [--format md\\\\|html\\\\|portable-text] [--out <dir>]\\` — stdout without \\`--out\\`. Hugo, Eleventy or a hand-built WordPress theme need no integration code. |\n| **WordPress** | \\`generate({ site })\\` also emits \\`dist/legal/*.html\\`; \\`[vitops_legal doc=\"privacy\"]\\` renders one. \\`doc\\` is matched against a fixed allowlist, because it lands in a filesystem read. |\n| **Astro** | \\`vitops({ legal: { input, out } })\\` — a sibling of \\`css\\`, not a widening of it. Regenerates on config change; writes markdown to a content collection. No route injection. |\n| **EmDash** | \\`--format portable-text\\`, pasted into the admin. |\n\nThe CLI is the load-bearing one: it is the surface every consumer has regardless of stack.\n\n## The review banner\n\nEvery document opens with a **non-optional** review banner. These are rendered from a template\nby a build tool; the one failure mode with real consequences is a consumer publishing one as-is.\n`;\n}\n\nfunction renderConceptsIndex(): string {\n return `${INDEX_NOTE}\n\n# Design-system concepts\n\n# Contents\n\n* [Colour system](color.md) - seeded OKLCH scales on a shared lightness ladder, target-prefixed tokens, automatic dark mode\n* [Type & space scales](scales.md) - fluid modular scales and the tokens they emit\n* [Component patterns](patterns.md) - token cascade, override hooks, states, role variants\n* [Components](components.md) - which of the three tiers provides each pattern, and the call to make\n* [Icons](icons.md) - semantic names across icon sets, bundle derivation, sprite delivery\n* [Consent gate](consent.md) - inert gated tags, demand-driven prompting, three-valued choices\n* [Conversion tracking](tracking.md) - ad-click attribution, the \\`_ac\\` cookie, conversion notifications\n* [Search](search.md) - what engines accept, Search Console onboarding, deploy notification\n* [Legal documents](legal.md) - policy/terms/cookie notice derived from config facts\n`;\n}\n\nfunction renderCssIndex(): string {\n return `${INDEX_NOTE}\n\n# CSS framework\n\n# Contents\n\n* [Class vocabulary](classes.md) - every utility and component class, summarized by naming rule\n`;\n}\n\nfunction renderBricksIndex(): string {\n return `${INDEX_NOTE}\n\n# Bricks Builder integration\n\n# Styling\n\nPrefer adding the framework **CSS classes** — see [/css/classes.md](../css/classes.md) — in a\nBricks element's \"CSS classes\" field over hand-setting spacing, colour, or typography through\nthe Bricks Builder property panels. The classes encode the design system's tokens, responsive\ngrammar, and interaction states, so they stay consistent, respond to theme / dark mode, and\nupdate with the system. Values typed directly into Bricks' property controls are one-off,\ndrift from the system, and don't react to theme changes — reserve them for genuinely bespoke,\none-element cases.\n\n# Contents\n\n* [Elements reference](elements.md) - every custom Vitops element, its controls, defaults, seeded children and keywords\n* [Class vocabulary](../css/classes.md) - the framework CSS classes to apply to elements\n`;\n}\n\n/**\n * Build the OKF docs bundle for a config. Returns a `{ relPath: content }` map;\n * the caller writes it wherever the bundle should live (e.g. `<outDir>/docs`).\n */\nexport function generateDocs(ds: DesignSystem, assetsDir: string): Record<string, string> {\n const elementsDir = join(assetsDir, 'bricks', 'elements');\n return {\n 'index.md': renderTopIndex(),\n 'authoring.md': renderAuthoring(),\n 'config.md': renderConfig(),\n 'formats.md': renderFormats(ds),\n 'concepts/index.md': renderConceptsIndex(),\n 'concepts/color.md': renderColorConcept(ds),\n 'concepts/scales.md': renderScalesConcept(ds),\n 'concepts/patterns.md': renderPatternsConcept(ds),\n 'concepts/components.md': renderComponentsConcept(ds),\n 'concepts/icons.md': renderIconsConcept(),\n 'concepts/consent.md': renderConsentConcept(),\n 'concepts/tracking.md': renderTrackingConcept(),\n 'concepts/search.md': renderSearchConcept(),\n 'concepts/legal.md': renderLegalConcept(),\n 'css/index.md': renderCssIndex(),\n 'css/classes.md': renderCssClasses(ds),\n 'bricks/index.md': renderBricksIndex(),\n 'bricks/elements.md': renderElementsDoc(elementsDir),\n };\n}\n","/**\n * `DESIGN.md` emitter — the `design` format.\n *\n * DESIGN.md (google-labs-code/design.md, alpha) is a single plain-text file that\n * gives AI coding agents a persistent, structured understanding of a visual\n * identity: YAML front matter carrying the tokens, then a prose body carrying the\n * *why*. It is the agent-facing sibling of `tokens.json` — where that file is a\n * verbatim dump for programmatic consumers, this one is curated for a reader.\n *\n * Three impedance mismatches between our schema and the spec, resolved the same\n * way every time (and stated in the prose so the file is self-describing):\n *\n * • **Fluid sizes are `clamp()`**; a spec `Dimension` is a bare number + px/em/rem.\n * → Emit the scale's **max** rem as the canonical size and say in the prose that\n * the real token is fluid. A `clamp()` string would fail every consumer's parse.\n * • **Dark mode has no first-class representation.** → `colors` carries the LIGHT\n * values; the Colors prose explains that the framework flips functionally at\n * runtime, so an agent that uses the role tokens gets dark mode for free and\n * should never hand-pick a dark value.\n * • **A role is not a ramp alias.** Functional tokens resolve to a ramp step, so\n * they are emitted as `{colors.<hue>-<step>}` **references** rather than\n * flattened hexes — that keeps the role → ramp lineage visible in the file,\n * which is the one thing a flattened export destroys. `on-solid` is the\n * exception: it is a computed contrast literal with no step behind it.\n */\nimport type { DesignSystem } from './schema.ts';\nimport { DARK_SEL, type RoleSpec, roleHue } from './shared.ts';\nimport { tokenClass, type ExpandedHue, type FunctionalRole } from './tokens.ts';\n\n/** Structural view of `generate.ts`'s ScaleStep (kept local to avoid a cycle). */\ninterface Step {\n name: string;\n value: string;\n max: string;\n}\n\nexport interface DesignMdCtx {\n ds: DesignSystem;\n expandedPalette: Record<string, ExpandedHue>;\n scaleRoles: FunctionalRole[];\n typeSteps: Step[];\n spaceSteps: Step[];\n shadows: Record<string, string> | undefined;\n}\n\ninterface PatternItem {\n group?: string;\n overrides?: Record<string, string>;\n element?: string;\n class?: string;\n fill?: boolean;\n default_role?: string;\n base?: Record<string, string>;\n states?: Record<string, Record<string, unknown>>;\n roles?: string[];\n}\n\n// ── minimal YAML writer ───────────────────────────────────────────────────────\n// Hand-rolled rather than pulled in as a dependency: the generator emits a fixed,\n// known shape (scalars two levels deep), and every string is double-quoted so\n// nothing here has to reason about YAML's plain-scalar edge cases — `#RRGGBB`\n// starting a comment, `{colors.x}` reading as a flow mapping, `2xl` as a key.\nconst q = (s: string) => `\"${s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\n/** Keys are quoted only when they would not survive as a plain scalar. */\nconst key = (k: string) => (/^[A-Za-z_][A-Za-z0-9_-]*$/.test(k) ? k : q(k));\nconst scalar = (v: string | number) => (typeof v === 'number' ? String(v) : q(v));\n\nconst yamlMap = (name: string, entries: [string, string | number][], indent = ''): string =>\n entries.length === 0\n ? ''\n : `${indent}${name}:\\n` +\n entries.map(([k, v]) => `${indent} ${key(k)}: ${scalar(v)}`).join('\\n') +\n '\\n';\n\n// ── value resolution ──────────────────────────────────────────────────────────\n/** `var(--x)` → `x`, else undefined. Tolerates a fallback: `var(--x, y)` → `x`. */\nconst varName = (v: string): string | undefined => {\n const m = /^var\\(\\s*--([a-z0-9-]+)\\s*(?:,[^)]*)?\\)$/i.exec(v.trim());\n return m ? (m[1] as string) : undefined;\n};\n\n/** A spec `Dimension` is a number plus px / em / rem — nothing else parses. */\nconst isDimension = (v: string) => /^-?(?:\\d+\\.?\\d*|\\.\\d+)(?:px|em|rem)$/.test(v.trim());\n\n/**\n * Only these reach a `Color` slot. `inherit` / `currentColor` / `initial` are\n * valid CSS in a pattern's `base` and meaningless as a token value, so a\n * component that says `color: inherit` emits no `textColor` at all rather than\n * an unresolvable one.\n */\nconst isColorLiteral = (v: string) =>\n /^#[0-9a-f]{3,8}$/i.test(v.trim()) ||\n /^(?:rgba?|hsla?|hwb|oklch|oklab|lch|lab|color-mix)\\(/i.test(v.trim()) ||\n /^(?:transparent|white|black)$/i.test(v.trim());\n\nexport function emitDesignMd(ctx: DesignMdCtx): string {\n const { ds, expandedPalette, scaleRoles, typeSteps, spaceSteps, shadows } = ctx;\n const meta = ds.meta ?? {};\n const name = meta.name ?? 'Design System';\n const roleMap = ds.colors.roles as Record<string, RoleSpec>;\n const patterns = ds.patterns ?? {};\n const pDefaults = (patterns.defaults ?? {}) as Record<string, string>;\n const pRadii = (patterns.radii ?? {}) as Record<string, string>;\n const pGroups = (patterns.groups ?? {}) as Record<string, Record<string, string>>;\n const pItems = (patterns.items ?? {}) as Record<string, PatternItem>;\n\n // ── colors ─────────────────────────────────────────────────────────────────\n // Raw ramps first (they are what everything else references), then the\n // functional role tokens as refs into them, then the spec's recommended names\n // as refs into those. Three layers, each one hop from the last.\n const ramps: [string, string][] = [];\n for (const [hue, expanded] of Object.entries(expandedPalette))\n for (const [step, hex] of Object.entries(expanded.numeric)) ramps.push([`${hue}-${step}`, hex]);\n\n const rampNames = new Set(ramps.map(([k]) => k));\n /** `var(--color-<hue>-<step>)` → `{colors.<hue>-<step>}`; literals pass through. */\n const rampRef = (value: string): string => {\n const v = varName(value);\n const bare = v?.startsWith('color-') ? v.slice('color-'.length) : undefined;\n return bare && rampNames.has(bare) ? `{colors.${bare}}` : value;\n };\n\n const roleTokens: [string, string][] = [];\n for (const fr of scaleRoles)\n for (const [token, value] of Object.entries(fr.light))\n // Flattened as the utility class name (`bg-surface`, `text-on-danger`) —\n // the same string an agent would write in markup, so the brief and the\n // markup vocabulary are one thing rather than two.\n roleTokens.push([tokenClass(fr.role, token), rampRef(value)]);\n\n const colorNames = new Set([...rampNames, ...roleTokens.map(([k]) => k)]);\n /** Recommended-name alias, emitted only when the role behind it exists. */\n const aliasAs = (as: string, token: string): [string, string][] =>\n colorNames.has(token) ? [[as, `{colors.${token}}`]] : [];\n // The spec's non-normative recommended names (`primary`, `on-primary`,\n // `error`, …). Ours are role-scoped, so nothing here is a new value — each is\n // a one-hop reference, which is exactly what makes a generic DESIGN.md\n // consumer (and the linter's `primary`-must-exist rule) work against a\n // vocabulary that never uses those words.\n const interop: [string, string][] = [\n ...aliasAs('primary', 'bg-ui-primary-solid'),\n ...aliasAs('on-primary', 'text-on-ui-primary'),\n ...aliasAs('secondary', 'bg-ui-secondary-solid'),\n ...aliasAs('on-secondary', 'text-on-ui-secondary'),\n ...aliasAs('tertiary', 'bg-ui-accent-solid'),\n ...aliasAs('on-tertiary', 'text-on-ui-accent'),\n ...aliasAs('neutral', 'bg-neutral'),\n ...aliasAs('surface', 'bg-surface'),\n ...aliasAs('on-surface', 'text-surface'),\n ...aliasAs('error', 'bg-danger-solid'),\n ...aliasAs('on-error', 'text-on-danger'),\n ];\n\n // ── typography ─────────────────────────────────────────────────────────────\n const fonts = (ds.fonts ?? {}) as Record<string, string>;\n const families = (ds.typography?.families ?? {}) as Record<string, string>;\n /** `display` → `var(--font-display)` → the actual stack. */\n const fontStack = (family: string | undefined): string | undefined => {\n if (!family) return undefined;\n const declared = families[family];\n if (declared == null) return fonts[family];\n const v = varName(declared);\n const bare = v?.startsWith('font-') ? v.slice('font-'.length) : undefined;\n return (bare && fonts[bare]) ?? declared;\n };\n const textMax = new Map(typeSteps.map((s) => [s.name, s.max]));\n /** `var(--text-3xl)` → that step's MAX rem (a clamp() is not a Dimension). */\n const typeSize = (size: string | number | undefined): string | undefined => {\n if (size == null) return undefined;\n const raw = String(size);\n const v = varName(raw);\n const bare = v?.startsWith('text-') ? v.slice('text-'.length) : undefined;\n const resolved = bare != null ? textMax.get(bare) : raw;\n return resolved != null && isDimension(resolved) ? resolved : undefined;\n };\n\n const typoRoles = (ds.typography?.roles ?? {}) as Record<\n string,\n Record<string, string | number | undefined>\n >;\n const typography: [string, [string, string | number][]][] = [];\n for (const [role, spec] of Object.entries(typoRoles)) {\n const props: [string, string | number][] = [];\n const stack = fontStack(spec.family as string | undefined);\n if (stack) props.push(['fontFamily', stack]);\n const size = typeSize(spec.size);\n if (size) props.push(['fontSize', size]);\n if (spec.weight != null) props.push(['fontWeight', Number(spec.weight)]);\n const lh = spec['line-height'];\n if (lh != null) {\n const n = Number(lh);\n props.push(['lineHeight', Number.isFinite(n) ? n : String(lh)]);\n }\n const tracking = spec.tracking;\n if (tracking != null && isDimension(String(tracking)))\n props.push(['letterSpacing', String(tracking)]);\n if (props.length) typography.push([role, props]);\n }\n\n // ── rounded ────────────────────────────────────────────────────────────────\n // DEFAULT + the named radii + one entry per pattern GROUP, because a component\n // references its group's radius (`{rounded.control}`), not a bare literal —\n // the group alias layer is the whole point of the cascade.\n //\n // A spec `Dimension` is a number plus px/em/rem, so a bare `0` is rejected\n // even though it is perfectly good CSS: normalise it to `0px`, which is the\n // same value in every context a radius is used. A radius that is genuinely not\n // a Dimension (`50%`, for a circle) cannot be normalised and is dropped from\n // the map rather than emitted as an error — `unroundable` carries it into the\n // Shapes prose so it is stated, not lost.\n const unroundable: [string, string][] = [];\n const asDimension = (v: string): string | undefined => {\n const t = v.trim();\n if (isDimension(t)) return t;\n return /^-?0+(?:\\.0+)?$/.test(t) ? '0px' : undefined;\n };\n const rounded: [string, string][] = [];\n const pushRadius = (name: string, value: string) => {\n const dim = asDimension(value);\n if (dim) rounded.push([name, dim]);\n else unroundable.push([name, value]);\n };\n if (pDefaults.br) pushRadius('DEFAULT', pDefaults.br);\n for (const [n, v] of Object.entries(pRadii)) pushRadius(n, v);\n const roundedNames = new Set(rounded.map(([k]) => k));\n /** `var(--br-default)` → `{rounded.DEFAULT}`, `var(--br-pill, 999px)` → `{rounded.pill}`. */\n const roundedRef = (value: string): string => {\n const v = varName(value);\n const bare = v?.startsWith('br-') ? v.slice('br-'.length) : undefined;\n if (bare === 'default') return '{rounded.DEFAULT}';\n return bare && roundedNames.has(bare) ? `{rounded.${bare}}` : value;\n };\n for (const [group, props] of Object.entries(pGroups)) {\n if (props.br == null) continue;\n const ref = roundedRef(props.br);\n if (ref !== props.br) rounded.push([group, ref]);\n else pushRadius(group, props.br);\n }\n const roundedAll = new Set(rounded.map(([k]) => k));\n\n // ── spacing ────────────────────────────────────────────────────────────────\n // Max rem again: the emitted `--space-*` tokens are fluid clamps.\n const spacing: [string, string][] = [];\n if (ds.spaceScale?.base) spacing.push(['base', ds.spaceScale.base]);\n for (const s of spaceSteps)\n if (!spacing.some(([k]) => k === s.name)) spacing.push([s.name, s.max]);\n\n // ── components ─────────────────────────────────────────────────────────────\n /** Walk a pattern's geometry cascade: overrides → group → defaults. */\n const cascade = (p: PatternItem, prop: string): string | undefined =>\n p.overrides?.[prop] ?? (p.group ? pGroups[p.group]?.[prop] : undefined) ?? pDefaults[prop];\n\n /** A colour-ish CSS value → a `{colors.x}` ref, a literal, or nothing. */\n const colorValue = (value: string | undefined): string | undefined => {\n if (value == null) return undefined;\n const v = varName(value);\n if (v != null) {\n if (colorNames.has(v)) return `{colors.${v}}`;\n const bare = v.startsWith('color-') ? v.slice('color-'.length) : undefined;\n if (bare && colorNames.has(bare)) return `{colors.${bare}}`;\n return undefined;\n }\n return isColorLiteral(value) ? value.trim() : undefined;\n };\n\n /**\n * Resolve a `base` declaration that goes through the group alias layer\n * (`var(--br-card-group)` → the card's `br` cascade), and turn the result into\n * a `{rounded.*}` ref where one exists.\n */\n const geometry = (\n p: PatternItem,\n pname: string,\n baseProp: string,\n token: string,\n ): string | undefined => {\n const declared = p.base?.[baseProp];\n if (declared == null) return undefined;\n const v = varName(declared);\n if (v !== `${token}-${pname}-group`) return declared;\n const resolved = cascade(p, token);\n if (resolved == null) return undefined;\n if (token !== 'br') return resolved;\n const ref = roundedRef(resolved);\n if (ref !== resolved) return ref;\n // A bare literal here came from the group's own `br` — and the group IS a\n // `rounded` entry — UNLESS the pattern overrode it, in which case the value\n // is this pattern's alone and pointing at the group would be a lie.\n return p.overrides?.br == null && p.group && roundedAll.has(p.group)\n ? `{rounded.${p.group}}`\n : resolved;\n };\n\n const components: [string, [string, string][]][] = [];\n const roleVariants: string[] = [];\n for (const [pname, p] of Object.entries(pItems)) {\n if (!p.base) continue;\n const base = p.base;\n // Mirrors generate.ts's fill inference exactly — a component whose fill is\n // guessed differently here would describe colours the CSS never sets.\n const fills =\n p.fill ??\n (pname === 'button' ||\n pname === 'badge' ||\n base['background-color'] != null ||\n base['background'] != null);\n const props: [string, string][] = [];\n if (fills) {\n const bg =\n colorValue(base['background-color']) ??\n colorValue(base['background']) ??\n (p.default_role ? colorValue(`var(--color-bg-${p.default_role}-solid)`) : undefined);\n if (bg) props.push(['backgroundColor', bg]);\n }\n const fg =\n colorValue(base['color']) ??\n (fills && p.default_role ? colorValue(`var(--color-text-on-${p.default_role})`) : undefined);\n if (fg) props.push(['textColor', fg]);\n // A radius that didn't survive into `rounded` (a `50%` circle) would emit\n // either a broken reference or a non-Dimension literal here, so the property\n // is dropped instead; the Shapes prose names those patterns.\n const br = geometry(p, pname, 'border-radius', 'br');\n const brRef = /^\\{rounded\\.([^}]+)\\}$/.exec(br ?? '');\n if (brRef && roundedAll.has(brRef[1] as string)) props.push(['rounded', br as string]);\n else if (br && asDimension(br)) props.push(['rounded', asDimension(br) as string]);\n else if (br) {\n // The Shapes prose wants the value, not the plumbing: `var(--br-circle,\n // 50%)` is how the cascade spells it, `50%` is what the reader needs.\n const named = varName(br);\n const bare = named?.startsWith('br-') ? named.slice('br-'.length) : undefined;\n unroundable.push([pname, (bare ? pRadii[bare] : undefined) ?? br]);\n }\n const pad = geometry(p, pname, 'padding', 'p');\n if (pad) props.push(['padding', pad]);\n if (props.length) components.push([pname, props]);\n\n // A hover that carries `step` intensifies the pattern's own colour; that is\n // a real variant an agent must reproduce, so it gets its own entry (the\n // spec's `-hover` sibling-key convention).\n const hover = p.states?.hover;\n const dr = p.default_role;\n if (hover && typeof hover.step === 'number' && dr) {\n const strong = hover.step >= 1;\n const hv = fills\n ? colorValue(`var(--color-bg-${dr}-${strong ? 'solid-bold' : 'solid'})`)\n : colorValue(`var(--color-text-${dr}${strong ? '-bold' : ''})`);\n if (hv) components.push([`${pname}-hover`, [[fills ? 'backgroundColor' : 'textColor', hv]]]);\n }\n if (p.roles?.length)\n roleVariants.push(\n `\\`${pname}\\` → ${p.roles.map((r) => `\\`.${p.class ?? pname}-${r}\\``).join(', ')}`,\n );\n }\n\n // ── front matter ───────────────────────────────────────────────────────────\n const fm: string[] = ['---', 'version: alpha', `name: ${q(name)}`];\n if (meta.description) fm.push(`description: ${q(meta.description)}`);\n fm.push('colors:');\n fm.push(' # Raw hue ramps — 11 OKLCH steps each, tinted near-white → tinted near-black.');\n for (const [k, v] of ramps) fm.push(` ${key(k)}: ${scalar(v)}`);\n fm.push(' # Functional role tokens (LIGHT values). These are the public API: use these,');\n fm.push(' # not the raw steps, and dark mode resolves itself. See \"## Colors\" below.');\n for (const [k, v] of roleTokens) fm.push(` ${key(k)}: ${scalar(v)}`);\n if (interop.length) {\n fm.push(\" # Aliases for the spec's recommended names — references, not new values.\");\n for (const [k, v] of interop) fm.push(` ${key(k)}: ${scalar(v)}`);\n }\n if (typography.length) {\n fm.push('typography:');\n for (const [role, props] of typography) {\n fm.push(` ${key(role)}:`);\n for (const [k, v] of props) fm.push(` ${k}: ${scalar(v)}`);\n }\n }\n fm.push(yamlMap('rounded', rounded).trimEnd());\n fm.push(yamlMap('spacing', spacing).trimEnd());\n if (components.length) {\n fm.push('components:');\n for (const [cname, props] of components) {\n fm.push(` ${key(cname)}:`);\n for (const [k, v] of props) fm.push(` ${k}: ${scalar(v)}`);\n }\n }\n fm.push('---');\n\n return `${fm.filter(Boolean).join('\\n')}\\n\\n# ${name}\\n\\n${prose({\n ctx,\n name,\n meta,\n roleMap,\n ramps,\n rounded,\n unroundable,\n roleVariants,\n typography: typography.map(([r]) => r),\n })}`;\n}\n\n// ── prose body ────────────────────────────────────────────────────────────────\n/**\n * Section order is normative (Overview → Colors → Typography → Layout →\n * Elevation → Shapes → Components → Do's and Don'ts); a consumer that parses\n * sections positionally breaks if they are reordered.\n *\n * Every section interpolates live config, so this cannot drift into describing a\n * system the generator no longer emits — the same discipline `docs.ts` follows.\n */\nfunction prose(a: {\n ctx: DesignMdCtx;\n name: string;\n meta: { name?: string | undefined; description?: string | undefined };\n roleMap: Record<string, RoleSpec>;\n ramps: [string, string][];\n rounded: [string, string][];\n unroundable: [string, string][];\n roleVariants: string[];\n typography: string[];\n}): string {\n const { ctx, name, meta, roleMap, rounded, unroundable, roleVariants } = a;\n const { ds, expandedPalette, scaleRoles, typeSteps, spaceSteps, shadows } = ctx;\n const hues = Object.keys(expandedPalette);\n const roles = Object.keys(roleMap);\n const shadowNames = Object.keys(shadows ?? {});\n const typeNames = typeSteps.map((s) => s.name);\n const spaceNames = spaceSteps.map((s) => s.name);\n const bodyRole = ds.typography?.headings?.body ?? 'body';\n const s = (list: string[]) => list.map((x) => `\\`${x}\\``).join(', ');\n\n const overview =\n meta.description ??\n `${name} is a variable-driven design system: an OKLCH colour engine, fluid ` +\n `modular type and space scales, and a small set of component patterns, all ` +\n `expressed as CSS custom properties with utility classes over them.`;\n\n return `## Overview\n\n${overview}\n\nEvery value in this document is generated from a single \\`design-system.json\\` and\nemitted as CSS custom properties plus utility classes. **Prefer the class vocabulary\nover hand-written CSS** — \\`vitops docs classes\\` prints the full list, and \\`vitops lint\\`\nreports classes that resolve to nothing.\n\nThe token names below are the contract. Reach for a raw ramp step only when no\nfunctional role expresses what you mean.\n\n> Most tokens here are consumed by **utility classes**, not by the \\`components\\` block —\n> \\`bg-<role>\\`, \\`text-<role>-muted\\` and friends are the API. \\`design.md lint\\` reports\n> those as \\`orphaned-tokens\\`; that rule assumes a component-only system and does not\n> apply. Everything else it reports is worth reading.\n\n## Colors\n\n${hues.length} hue${hues.length === 1 ? '' : 's'} (${s(hues)}), each generated as an 11-step\nOKLCH scale from a seed — step \\`50\\` is a tinted near-white, \\`950\\` a tinted near-black,\nwith chroma damped toward both ends so the extremes read as neutral rather than washed.\n\n${roles.length} semantic **roles** map onto those hues:\n\n${roles.map((r) => `- \\`${r}\\` → \\`${roleHue(roleMap[r] as RoleSpec)}\\``).join('\\n')}\n\nA role is **not** an alias for a ramp. It resolves to tokens named\n\\`<target>-<role>[-<variant>]\\`, where target is one of \\`bg\\` \\`text\\` \\`icon\\` \\`border\\`. The\ntarget is part of the name on purpose: \\`bg-danger-muted\\` and \\`text-danger-muted\\` are\ndifferent tokens, so there is no ambiguity about which one a name refers to. **The token\nname is also the utility class name** — write \\`class=\"bg-danger-muted\"\\` and you are using\n\\`--color-bg-danger-muted\\`.\n\nVariants are ordinal: \\`xx-muted\\` < \\`x-muted\\` < \\`muted\\` < (bare) < \\`bold\\` < \\`x-bold\\`.\n\\`bold\\` means *more emphatic in the current appearance*, not darker.\n\nRoles come in two kinds, and the kind decides which tokens exist:\n\n- **surface** (page and panel colours) — \\`bg-<role>\\` is the card/panel, \\`bg-<role>-muted\\`\n the page behind it, \\`bg-<role>-x-muted\\` a well. Full text scale, \\`border-<role>-bold\\`\n as the contrast-guaranteed boundary.\n- **chromatic** (signal colours) — backgrounds are either *tints*\n (\\`bg-<role>-x-muted\\` / \\`-muted\\`) or *solids*\n (\\`bg-<role>-solid\\` / \\`-solid-bold\\` / \\`-solid-x-bold\\`). **There is no bare \\`bg-<role>\\`**:\n say how loud you mean. \\`text-on-<role>\\` is the guaranteed-contrast foreground for the\n solid family.\n\n**Dark mode is automatic, and this file only lists the light values.** The spec has no\nway to express a second appearance, so do not try to reconstruct one: the framework\nre-points each token at a different ramp step under \\`${DARK_SEL}\\`, so \\`bg-<role>\\`\nbecomes dark and \\`text-<role>\\` becomes light on their own. The solid family and\n\\`text-on-<role>\\` stay mode-stable by design, so a filled button keeps its identity.\n**An agent that styles with the role tokens gets dark mode for free; one that flattens\nthem to hexes breaks it.**\n\nContrast is enforced at build time, not by convention — a violation fails the build.\nText is held to APCA Lc 75 on a role's primary background and Lc 60 on its secondary\nplanes; icons and the surface boundary to Lc 45; and chromatic text is checked against\nthe *surface* planes it actually sits on, not just its own tints. Pairing\n\\`text-<role>\\` with \\`bg-<role>\\`, or \\`text-on-<role>\\` with \\`bg-<role>-solid\\`, is always\nsafe. Pairing a raw ramp step with another raw ramp step is not.\n\n## Typography\n\nFont stacks are named, and roles consume the name rather than the stack — so swapping a\ntypeface is one edit:\n\n${Object.entries((ds.fonts ?? {}) as Record<string, string>)\n .map(([n, stack]) => `- **${n}** — \\`${stack}\\``)\n .join('\\n')}\n\nType is a fluid modular scale: ${typeNames.length} steps (${s(typeNames)}) built from a\n${ds.typeScale?.base ?? '1rem'} base at a ${ds.typeScale?.ratio ?? 1.2} ratio${\n ds.typeScale?.fluid\n ? `, interpolating between a ${ds.typeScale.fluid.minRatio} ratio at ${ds.typeScale.fluid.minVw} viewport width and the full ratio at ${ds.typeScale.fluid.maxVw}`\n : ''\n }. **The \\`fontSize\\` values in the front matter are the maximum (desktop) sizes** — the\nreal tokens are \\`clamp()\\` expressions, which the spec's \\`Dimension\\` type cannot hold.\nNever hard-code the emitted number; use the scale (\\`--text-<step>\\`) or the role class.\n\nEach typography role is a class (\\`.font-<role>\\`): ${s(a.typography.map((t) => `font-${t}`))}.\nRoles also carry properties this format has no slot for — \\`text-transform\\`,\n\\`text-wrap\\`, and a \\`color\\` — so **apply the role class rather than copying its\nfront-matter properties**, or uppercase eyebrows and balanced headings silently\ndisappear. Base page text is bound to the \\`${bodyRole}\\` role, so prose inherits it.\n\n## Layout & Spacing\n\nSpacing is its own fluid modular scale: ${spaceNames.length} steps (${s(spaceNames)}) from a\n${ds.spaceScale?.base ?? '1rem'} base at a ${ds.spaceScale?.ratio ?? 1.25} ratio. As with type,\nthe front-matter values are the maxima and the live tokens are fluid.\n\nLayout is composed from utilities rather than bespoke CSS:\n\n- \\`.centered\\` — track-based centering: content sits in a centred measure while\n full-bleed children can still break out. Use it instead of \\`margin-inline: auto\\`.\n- \\`.rhythm\\` — vertical rhythm between flow children, so sibling spacing is one\n decision rather than per-element margins.\n- \\`.flex\\` / \\`.split-<a>-<b>\\` / \\`.grid\\` — the structural families, with container-query\n variants prefixed \\`sm-\\` / \\`md-\\` / \\`lg-\\` / \\`xl-\\` (30 / 48 / 64 / 80rem).\n \\`.split\\` is a two-column pair. Stack it with \\`.flex-col\\` and let a\n breakpoint-prefixed ratio un-stack it (\\`split flex-col md-split-1-2\\`);\n \\`.split-reverse\\` swaps the two panels. Reversing puts visual order out of step\n with DOM order, so keep focusable content in only one panel.\n\nBreakpoints are **container** queries, not viewport media queries: a component\nresponds to the space it is given, so the same markup works in a sidebar and a full-width\nsection.\n\n## Elevation & Depth\n\n${\n shadowNames.length\n ? `Depth comes from ${shadowNames.length} named shadow${shadowNames.length === 1 ? '' : 's'} (${s(shadowNames)}), applied as \\`--shadow-<name>\\` tokens or \\`.drop-shadow-<name>\\` utilities:\n\n${shadowNames.map((n) => `- \\`${n}\\` — \\`${(shadows ?? {})[n]}\\``).join('\\n')}\n\nEach value is deliberately a **single layer with no spread and no \\`inset\\`**: the same\ntoken feeds both \\`box-shadow\\` (pattern geometry) and \\`filter: drop-shadow()\\` (the\nutilities), and \\`drop-shadow()\\` rejects all three, which would drop the whole filter.`\n : `This system is flat: no shadow tokens are defined. Convey hierarchy with the\nsurface planes (\\`surface-bg\\` / \\`surface-bg-muted\\` / \\`surface-bg-bold\\`) and borders.`\n}\n\nSurfaces stack tonally as well: \\`surface-bg-bold\\` is the *raised* plane in both\nappearances, so a card on a page reads as lifted without any shadow at all.\n\n## Shapes\n\nCorner radii resolve through a cascade rather than being set per component:\n\\`--br-<pattern>\\` (your override hook) → \\`--br-<pattern>-group\\` → the group's radius →\n\\`--br-default\\`. Overriding one variable restyles every pattern in that tier.\n\n${rounded.map(([k, v]) => `- \\`${k}\\` — \\`${v}\\``).join('\\n')}\n\nChange a group's radius to restyle a whole tier; change \\`DEFAULT\\` to restyle everything\nthat has not opted out.\n${\n unroundable.length\n ? `\n**Not in the front matter above**, because the spec's \\`Dimension\\` type only holds\npx / em / rem — these are real radii in the system and have to be applied as CSS:\n\n${unroundable.map(([k, v]) => `- \\`${k}\\` — \\`${v}\\``).join('\\n')}`\n : ''\n}\n\n## Components\n\nPatterns are classes, not components — apply them to whatever element is semantically\ncorrect. Two tiers of button exist and the distinction is intent, not looks:\n\n- **\\`.cta\\`** is *persuasion* — filled, bolder, more padding, lifts on hover. Usually on an\n \\`<a>\\`, because a call to action usually navigates.\n- **\\`.btn\\`** is *affordance* — it only says \"this is interactive\". It is emitted at zero\n specificity for both \\`<button>\\` and \\`.btn\\`, so a bare \\`<button>\\` gets it with no class\n and **any** explicit class overrides it.\n\n${\n roleVariants.length\n ? `Role variants are systematic rather than enumerated above. A filled pattern's variant sets\n\\`background-color: var(--<role>-solid)\\` with \\`color: var(--<role>-on-solid)\\`; a text\npattern's sets \\`color: var(--color-<role>-bold)\\`:\n\n${roleVariants.map((r) => `- ${r}`).join('\\n')}`\n : ''\n}\n\nInteraction states are generated from a small grammar — \\`step\\` (intensify the colour),\n\\`scale\\`, \\`lift\\`, \\`shadow\\`, \\`ring\\` — so hover, active and focus-visible stay consistent\nacross every pattern. Focus rings are never removed, only restyled.\n\n## Do's and Don'ts\n\n- **Do** use functional role tokens (\\`ui-primary-solid\\`, \\`surface-bg\\`) over raw ramp steps.\n- **Do** pair \\`<role>-text\\` with \\`<role>-bg\\`, and \\`<role>-on-solid\\` with \\`<role>-solid\\` —\n those pairings are contrast-tested; arbitrary ones are not.\n- **Do** apply the \\`.font-<role>\\` classes rather than copying their font properties.\n- **Do** reach for a utility class before writing CSS; run \\`vitops lint\\` to catch classes\n that resolve to nothing.\n- **Don't** hard-code the \\`fontSize\\` / \\`spacing\\` numbers from the front matter — they are\n the maxima of fluid \\`clamp()\\` scales.\n- **Don't** flatten role tokens to hex values: that is exactly what breaks dark mode.\n- **Don't** invent a colour outside the ${hues.length} ramps${\n scaleRoles.length ? ` or the ${scaleRoles.length} roles` : ''\n }; add a hue to the config instead.\n- **Don't** edit this file by hand — it is generated from \\`design-system.json\\`. Change the\n config and re-run \\`vitops generate --format design\\`.\n`;\n}\n","/**\n * What the config already tells us about third parties that receive personal\n * information.\n *\n * A privacy policy's riskiest sentence is the one naming service providers: if\n * it says \"Plausible\" while the site runs Google Analytics, the document is a\n * compliance defect, not a typo. The site config already records which analytics\n * ID is set, whether Turnstile is deployed and where the site is hosted — so the\n * sentence derives from those signals rather than from a hand-maintained string\n * that drifts the moment someone swaps providers.\n *\n * Presence of the key is the signal, matching how `analytics` already works\n * (provider identity is implied by which ID is set, not by an enum).\n *\n * This table is deliberately small and covers only what the schema can imply.\n * Everything else — payment processors, CRMs, mail senders — is declared by the\n * consumer in `legal.privacyPolicy.processors`, which flows through the same\n * pipeline. This is not a directory of the web; it's the set of providers the\n * toolchain itself can vouch for.\n */\nimport { AD_PLATFORMS, AD_PROVIDER_KEYS } from '@getvitops/utils/ads';\nimport type { Config } from '../config.ts';\n\n/** One place a provider holds information, and which information if not all of it. */\nexport interface ProcessorStorage {\n /** Reads inside a sentence: \"…including the United States\". */\n country: string;\n /**\n * Reads after \"in the case of\". Present means this location holds only SOME of\n * what the provider receives, which is a narrower claim than an unscoped entry —\n * so the template gives it its own sentence rather than folding it into the list,\n * where a reader would take it to cover everything.\n */\n scope?: string | undefined;\n}\n\nexport interface Processor {\n /** The provider as a reader would recognise it. */\n name: string;\n /** Reads after \"for\": \"…to Stripe for payment processing\". */\n purpose: string;\n /**\n * Shorthand asserting BOTH `storage` and `operatorCountry` are this one country.\n *\n * Kept for the common case (and because it is public API), but note it is the\n * field whose *meaning* was never defined — its old doc comment described how it\n * READ, not what it asserted, which is how one string came to stand for two\n * different facts. Prefer the explicit pair when they differ.\n */\n country?: string | undefined;\n /**\n * Where the information actually rests. Feeds the \"stored or processed outside\n * of <jurisdiction>\" disclosure and nothing else.\n */\n storage?: ProcessorStorage[] | undefined;\n /**\n * The jurisdiction that can compel this provider to produce the information —\n * where it is established, or from which it is controlled. Reads after \"the laws\n * of\".\n *\n * A separate fact from `storage`, and the one privacy law actually turns on: the\n * OPC's concern is foreign *access*, not foreign storage. Azure in a Canadian\n * region is `storage: [{ country: 'Canada' }]`, `operatorCountry: 'the United\n * States'` — the bytes never move and US law still reaches them.\n */\n operatorCountry?: string | undefined;\n privacyUrl?: string | undefined;\n /**\n * Cookies this provider sets. An empty array is meaningful and not the same as\n * `undefined`: it asserts the provider is cookieless (Plausible), which the\n * cookie notice states positively rather than omitting.\n */\n cookies?: string[] | undefined;\n /** A user-facing opt-out, when the provider offers one. */\n optOut?: string | undefined;\n}\n\n/**\n * The providers the config can imply. Keyed for testability — a test can assert\n * a given config resolves to a given key without matching on prose.\n */\nexport const KNOWN_PROCESSORS = {\n googleAnalytics: {\n name: 'Google Analytics',\n purpose: 'website analytics',\n country: 'the United States',\n privacyUrl: 'https://policies.google.com/privacy',\n cookies: ['_ga', '_gid'],\n optOut: 'https://tools.google.com/dlpage/gaoptout',\n },\n googleTagManager: {\n name: 'Google Tag Manager',\n purpose: 'tag management',\n country: 'the United States',\n privacyUrl: 'https://policies.google.com/privacy',\n cookies: [],\n },\n plausible: {\n name: 'Plausible Analytics',\n purpose: 'website analytics',\n country: 'the European Union',\n privacyUrl: 'https://plausible.io/privacy',\n // Plausible sets no cookies and stores no cross-site identifiers. Stated as\n // an empty list rather than omitted, so the cookie notice can say so.\n cookies: [],\n },\n clarity: {\n name: 'Microsoft Clarity',\n purpose: 'session replay and heatmaps',\n country: 'the United States',\n privacyUrl: 'https://privacy.microsoft.com/privacystatement',\n // Clarity records what a visitor does on the page, not just that they were\n // here, so the purpose says \"session replay\" rather than \"analytics\" — a\n // reader deciding whether to consent needs to know they may be recorded.\n cookies: ['_clck', '_clsk', 'MUID'],\n optOut: 'https://privacy.microsoft.com/privacystatement',\n },\n // Matomo appears twice on purpose: whether it sets cookies is a *configuration*\n // choice (`analytics.matomo.cookies`), and the notice says something materially\n // different in each case. One entry with a conditional cookie list would put\n // that branch in the prose layer, where the rule is that templates own wording\n // and never facts.\n matomo: {\n name: 'Matomo',\n purpose: 'website analytics',\n privacyUrl: 'https://matomo.org/privacy-policy/',\n cookies: ['_pk_id', '_pk_ses'],\n },\n matomoCookieless: {\n name: 'Matomo',\n purpose: 'website analytics',\n privacyUrl: 'https://matomo.org/privacy-policy/',\n // `disableCookies` is on: Matomo stores no identifier on the device. The\n // empty list is the assertion — see the Processor.cookies note above.\n cookies: [],\n },\n // ── Edge / hosting: operator jurisdiction, NOT storage ──────────────────────\n //\n // These four asserted `country: 'the United States'` into a sentence that says\n // \"stored or processed in\" — a claim about the wrong fact. Cloudflare is anycast:\n // a request from Toronto is answered from a Toronto PoP, and Workers/R2 have\n // residency controls the config cannot see. Vercel and Netlify are region-\n // configurable in the same way.\n //\n // What is true regardless of which PoP or region served the request is that a US\n // company can be compelled under US law. So that is what they now assert, and\n // they assert nothing about where the bytes rest. This generalises the rule the\n // Matomo note below already stated: \"we don't know\" is a fact. A consumer who\n // pins a region should declare `storage` on a processor of their own.\n turnstile: {\n name: 'Cloudflare Turnstile',\n purpose: 'bot protection on forms',\n operatorCountry: 'the United States',\n privacyUrl: 'https://www.cloudflare.com/privacypolicy/',\n cookies: ['cf_clearance'],\n },\n cloudflare: {\n name: 'Cloudflare',\n purpose: 'website hosting and content delivery',\n operatorCountry: 'the United States',\n privacyUrl: 'https://www.cloudflare.com/privacypolicy/',\n cookies: [],\n },\n vercel: {\n name: 'Vercel',\n purpose: 'website hosting',\n operatorCountry: 'the United States',\n privacyUrl: 'https://vercel.com/legal/privacy-policy',\n cookies: [],\n },\n netlify: {\n name: 'Netlify',\n purpose: 'website hosting',\n operatorCountry: 'the United States',\n privacyUrl: 'https://www.netlify.com/privacy/',\n cookies: [],\n },\n} satisfies Record<string, Processor>;\n\nexport type KnownProcessorKey = keyof typeof KNOWN_PROCESSORS;\n\n/** Substring → hosting provider. `deployment.platform` is a free-form string. */\nconst HOSTING_PATTERNS: [RegExp, KnownProcessorKey][] = [\n [/cloudflare|workers|pages\\.dev/i, 'cloudflare'],\n [/vercel/i, 'vercel'],\n [/netlify/i, 'netlify'],\n];\n\n/**\n * Which known providers this config implies, in a stable order (analytics →\n * security → hosting) so the rendered sentence doesn't churn between builds.\n *\n * Returns keys rather than processors so a caller can test the detection\n * independently of the prose attached to it.\n */\nexport function detectProcessorKeys(cfg: Config): KnownProcessorKey[] {\n const site = cfg.site;\n const keys: KnownProcessorKey[] = [];\n const analytics = site.analytics;\n if (analytics?.googleAnalyticsId) keys.push('googleAnalytics');\n if (analytics?.googleTagManagerId) keys.push('googleTagManager');\n if (analytics?.plausibleDomain) keys.push('plausible');\n if (analytics?.clarityId) keys.push('clarity');\n // Cookieless is the default, matching the tag the Astro integration emits\n // (`_paq.push(['disableCookies'])` unless `cookies: true`). The two must agree:\n // a notice claiming no cookies while the tag sets them is the defect this whole\n // table exists to prevent.\n if (analytics?.matomo) keys.push(analytics.matomo.cookies ? 'matomo' : 'matomoCookieless');\n if (site.security?.turnstile?.siteKey) keys.push('turnstile');\n\n const platform = site.deployment?.platform;\n const hosting = platform && HOSTING_PATTERNS.find(([re]) => re.test(platform))?.[1];\n // Turnstile already names Cloudflare; listing it twice reads as sloppy and\n // implies two relationships where there is one.\n if (hosting && !keys.includes(hosting)) keys.push(hosting);\n return keys;\n}\n\n/**\n * Every processor this policy must disclose: the ones implied by the config,\n * then the ones the consumer declared.\n *\n * Consumer entries come last and are never deduplicated against the built-ins —\n * an explicit declaration is a statement of fact we have no grounds to drop.\n */\nexport function resolveProcessors(cfg: Config): Processor[] {\n const detected = detectProcessorKeys(cfg).map((k) =>\n matomoLocation(KNOWN_PROCESSORS[k] as Processor, cfg.site),\n );\n const declared = cfg.site.legal?.privacyPolicy?.processors ?? [];\n return [...detected, ...adProcessors(cfg), ...declared].map(desugarCountry);\n}\n\n/**\n * The ad platforms `site.ads` links this site to, as processors.\n *\n * Derived from `AD_PLATFORMS` rather than written out here, because the cookie\n * names, the privacy URL and the opt-out are the *same facts* `vitops ads tags`\n * writes into `data-consent-cookies` — and the one failure that matters is those\n * two disagreeing. A pixel that sets `_fbp` while the notice omits it is a\n * compliance defect, and a revoke that clears a cookie the notice never mentioned\n * is the same defect seen from the other end.\n *\n * `enabled: false` keeps a property on record without emitting its tag, so nothing\n * is set and nothing is disclosed. Everything else with an id is live.\n */\nfunction adProcessors(cfg: Config): Processor[] {\n const ads = cfg.site.ads ?? {};\n return AD_PROVIDER_KEYS.filter((provider) => {\n const entry = ads[provider];\n return entry != null && entry.enabled !== false && (entry.pixelId ?? entry.accountId) != null;\n }).map((provider) => {\n const platform = AD_PLATFORMS[provider];\n return {\n name: platform.name,\n purpose: 'advertising measurement and retargeting',\n operatorCountry: platform.operatorCountry,\n privacyUrl: platform.tag.privacyUrl,\n cookies: platform.tag.cookies,\n ...(platform.tag.optOut ? { optOut: platform.tag.optOut } : {}),\n } satisfies Processor;\n });\n}\n\n/**\n * `country` → both facts it has always asserted.\n *\n * The sentence it fed claimed storage *and* legal reach in one breath (\"may be\n * stored or processed in … including X. As a result … access requests from\n * governments … in those jurisdictions\"). So expanding it to storage alone would\n * silently retract half of a claim consumers have already published. Expanding to\n * both is also what keeps the rendered output byte-identical for every config that\n * used the shorthand.\n *\n * `country` is left in place — it is public API and `PolicyVars.countries` still\n * reports it. When the explicit fields are present they win; `validateConfig`\n * rejects that combination, so it is unreachable through a validated config, but\n * `resolveProcessors` is exported and needs a defined answer regardless.\n */\nfunction desugarCountry(p: Processor): Processor {\n if (!p.country) return p;\n return {\n ...p,\n storage: p.storage ?? [{ country: p.country }],\n operatorCountry: p.operatorCountry ?? p.country,\n };\n}\n\n/**\n * Processors the config discloses but places nowhere.\n *\n * Such a processor cannot appear in the transfer disclosure — there is nothing true\n * to say about it — and today it vanishes from that section in silence, which is the\n * tidy-looking failure. Names only, and deliberately NOT on `PolicyVars`: that type\n * is the facts a template renders from, and a document must not editorialise about\n * its own gaps. The CLI reports these on stderr instead.\n *\n * Not a `validateConfig` error either: a bare `{ name, purpose }` validates today,\n * so rejecting it would make this a breaking change.\n */\nexport function processorsMissingLocation(cfg: Config): string[] {\n return resolveProcessors(cfg)\n .filter((p) => !p.operatorCountry && !p.storage?.length)\n .map((p) => p.name);\n}\n\n/**\n * Matomo is the one provider whose location the config actually knows.\n *\n * Matomo Cloud is hosted in the EU; a self-hosted instance is wherever the\n * consumer put it, which is very often their own infrastructure in their own\n * country. So the cross-border transfer sentence is asserted only for the case we\n * can see. Naming a transfer that isn't happening is the same class of error as\n * omitting one that is — the config records facts, and \"we don't know\" is a fact.\n *\n * This sets `storage`, not `operatorCountry`: Matomo Cloud genuinely holds the data\n * in the EU. InnoCraft is New Zealand-based, but nothing in the config sees that, so\n * no operator jurisdiction is asserted — the same rule, applied to the other fact.\n */\nfunction matomoLocation(processor: Processor, site: Config['site']): Processor {\n if (processor.name !== 'Matomo') return processor;\n const url = site.analytics?.matomo?.url ?? '';\n return /\\.matomo\\.cloud/i.test(url)\n ? { ...processor, storage: [{ country: 'the European Union' }] }\n : processor;\n}\n","/**\n * Site config → the facts a legal document asserts.\n *\n * The division of labour here is the whole point: **the config records facts,\n * the template owns prose.** Nothing in this module writes a sentence a lawyer\n * would need to review, and nothing in a template invents a fact. That is what\n * lets the wording be corrected without touching a consumer's config, and a\n * consumer's provider to change without touching the prose.\n *\n * Everything it returns is derived from config the site already has to hold to\n * function — which analytics ID is set, which forms exist, where it deploys —\n * plus the facts a consumer declares in `legal.privacyPolicy`. There is no\n * source of truth here beyond `Config`.\n *\n * Pure: no I/O, no clock. `lastUpdated` comes from the config rather than\n * `Date.now()` so a rebuild produces a byte-identical document.\n */\nimport { t } from '@getvitops/utils';\nimport {\n JURISDICTION_COUNTRIES,\n resolvePrivacyContact,\n type ContactObject,\n type Config,\n} from '../config.ts';\nimport { resolveProcessors, type Processor } from './providers.ts';\n\n/**\n * The facts every legal template renders from.\n *\n * List-shaped fields are `string[]`, not pre-joined strings, because they land\n * in bullet positions: a template that splices an empty string into a list emits\n * a stray `-` bullet, and that is exactly the kind of silent breakage a\n * published policy must not have.\n */\nexport interface PolicyVars {\n businessName: string;\n url: string;\n /** Reads after \"at\": \"…contact our Privacy Officer at <this>.\" */\n mailingAddress: string;\n lastUpdated: string | undefined;\n /** Extra retention sentence, when the consumer stated one. */\n retention: string | undefined;\n /** A consumer-supplied governing-law phrase, which wins over the two below. */\n governingLaw: string | undefined;\n /** Province/territory, spelled out — \"Ontario\", never \"ON\". */\n governingProvince: string | undefined;\n governingCountry: string;\n\n /** Circumstances in which personal information is collected. */\n collectionReasons: string[];\n /** Categories of personal information collected. */\n piiCollected: string[];\n /** What the browser sends automatically. */\n techInfo: string[];\n /** Why that technical information is used. */\n techInfoPurposes: string[];\n /** What cookies track. */\n cookieTracked: string[];\n /** Why cookies are used. */\n cookiePurposes: string[];\n /** A sentence about the consent tool, or `undefined` when there is none. */\n cookieTool: string | undefined;\n /** How collected information is used. */\n usePurposes: string[];\n /** Choices a visitor has. */\n optOutOptions: string[];\n /** The subset of `optOutOptions` about cookies — an e-mail unsubscribe link is\n * not a cookie choice, and listing it in a cookie notice reads as padding. */\n cookieOptOutOptions: string[];\n\n processors: Processor[];\n /**\n * Cookies the site sets itself.\n *\n * Separate from `processors`, which are third parties — no provider table would\n * ever name a first-party cookie, so without this the notice can say \"we do not\n * set cookies\" while `_ac` sits in the visitor's browser.\n */\n firstPartyCookies: { name: string; purpose: string; retention: string }[];\n /**\n * The country this document frames transfers as *leaving*, from the jurisdiction\n * rather than the org's address — a `ca` policy says \"outside of Canada\" even for\n * a business incorporated elsewhere. (`governingCountry` is the address, and\n * drives a different sentence: the terms' governing-law clause.)\n */\n jurisdictionCountry: string;\n /**\n * Reads after \"including\": foreign countries where information rests, with no\n * category attached — the broad claim.\n */\n storageCountries: string | undefined;\n /**\n * Foreign storage locations holding only SOME categories. Structured rather than\n * pre-joined, because the connective (\"in the case of\") is the template's word,\n * not a fact. Disjoint from `storageCountries`: a country already claimed\n * unscoped is never repeated here, since the unscoped claim is the broader one.\n */\n scopedStorage: { country: string; scope: string }[];\n /**\n * Reads after \"the laws of\": foreign jurisdictions that can compel a provider to\n * produce information, EXCLUDING any already named in `storageCountries` —\n * saying US law reaches information already disclosed as stored in the US adds a\n * sentence and no fact.\n */\n operatorCountries: string | undefined;\n /**\n * Reads after \"including\": \"…the United States and the European Union\".\n *\n * @deprecated Split into `storageCountries` and `operatorCountries`, which keep\n * residency and legal reach apart. Retained, and still every country the field\n * ever named, so a consumer's own template renders what it always rendered.\n */\n countries: string | undefined;\n consentModel: 'opt-in' | 'opt-out' | 'none';\n cookieCategories: string[];\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────────\n\n/** \"A\", \"A and B\", \"A, B and C\". */\nexport function list(items: string[]): string {\n if (items.length <= 1) return items[0] ?? '';\n return `${items.slice(0, -1).join(', ')} and ${items[items.length - 1]}`;\n}\n\n/** Order-preserving dedupe — the bullet lists are assembled from several sources. */\nconst uniq = (items: (string | undefined)[]): string[] => [\n ...new Set(items.filter((s): s is string => !!s)),\n];\n\n/**\n * Render a contact into the phrase that follows \"at\". Prefers e-mail (the\n * channel a reader can actually use from the page) and adds the postal address\n * when there is one, because access and correction requests are commonly posted.\n */\nfunction formatContact(contact: ContactObject | undefined): string {\n if (!contact) return '';\n const a = contact.address;\n const postal =\n a &&\n [\n a.streetAddress,\n a.addressLocality,\n [a.addressRegion, a.postalCode].filter(Boolean).join(' '),\n a.addressCountry,\n ]\n .filter(Boolean)\n .join(', ');\n if (contact.email && postal) return `${contact.email}, or by mail at ${postal}`;\n return contact.email ?? postal ?? '';\n}\n\n/**\n * What a form field actually collects, as a noun phrase.\n *\n * Typed fields carry their meaning (`email` is an e-mail address in any form);\n * `text` does not, so it falls back to the field's name. A policy that under-\n * describes what a form collects is the failure mode worth avoiding, so an\n * unrecognised text field lands in a catch-all bullet rather than being dropped.\n */\nfunction fieldPhrase(name: string, type: string): string | undefined {\n switch (type) {\n // `hidden` is not visitor-supplied and a honeypot exists to be left empty —\n // describing either as collected information would be inaccurate.\n case 'hidden':\n return undefined;\n case 'email':\n return 'your e-mail address';\n case 'tel':\n return 'your telephone number';\n case 'url':\n return 'any website address you provide';\n case 'date':\n return 'any dates you provide';\n case 'file':\n return 'any files or documents you upload';\n case 'textarea':\n return 'the content of the messages you send us';\n case 'number':\n return 'any numeric details you provide';\n case 'password':\n return 'account credentials';\n case 'select':\n case 'radio':\n case 'checkbox':\n return 'your answers to the questions we ask';\n default:\n break;\n }\n if (/name/i.test(name)) return 'your name';\n if (/compan|organi|business/i.test(name)) return 'your company or organization name';\n if (/address|street|city|province|state|postal|zip|country/i.test(name))\n return 'your mailing address';\n return 'the other details you enter in our forms';\n}\n\nconst PROVINCES: Record<string, string> = {\n AB: 'Alberta',\n BC: 'British Columbia',\n MB: 'Manitoba',\n NB: 'New Brunswick',\n NL: 'Newfoundland and Labrador',\n NS: 'Nova Scotia',\n NT: 'Northwest Territories',\n NU: 'Nunavut',\n ON: 'Ontario',\n PE: 'Prince Edward Island',\n QC: 'Quebec',\n SK: 'Saskatchewan',\n YT: 'Yukon',\n};\n\n/**\n * `addressRegion` is conventionally a two-letter code, which is right for a\n * postal address and wrong inside a governing-law clause — \"the laws of ON\" is\n * not a sentence a lawyer would sign off. Anything already spelled out (or from\n * another country) passes through untouched.\n */\nfunction expandProvince(region: string | undefined): string | undefined {\n if (!region) return undefined;\n return PROVINCES[region.toUpperCase()] ?? region;\n}\n\n/** Every field across every `form` template, honeypots excluded. */\nfunction formFields(site: Config['site']): { name: string; type: string }[] {\n const out: { name: string; type: string }[] = [];\n for (const tpl of Object.values(site.templates ?? {})) {\n if (tpl.type !== 'form') continue;\n for (const f of tpl.fields ?? []) out.push({ name: f.name, type: f.type });\n }\n return out;\n}\n\n// ── Derivation ──────────────────────────────────────────────────────────────────\n\nexport function derivePolicyVars(cfg: Config): PolicyVars {\n // The two sections this reads from. Everything the policy asserts about the\n // *company* comes from `organization`; everything it asserts about what the\n // *site* does (forms, analytics, cookies, A/B) comes from `site`.\n const site = cfg.site;\n const org = cfg.organization;\n const locale = site.defaultLocale;\n const legal = site.legal;\n const privacy = legal?.privacyPolicy;\n const processors = resolveProcessors(cfg);\n const fields = formFields(site);\n const hasForms = fields.length > 0;\n // Any configured provider counts, whether its config is an ID string\n // (`googleAnalyticsId`) or an object (`matomo`). Checking only for strings\n // would silently under-report a Matomo-only site as having no analytics at all.\n const hasAnalytics = Object.values(site.analytics ?? {}).some((v) =>\n typeof v === 'string' ? v.length > 0 : !!v,\n );\n const cookieProcessors = processors.filter((p) => p.cookies?.length);\n const consent = legal?.cookieConsent;\n const contact = resolvePrivacyContact(cfg);\n\n const businessName =\n org?.legalName ?? (org?.name != null ? t(org.name, locale, locale) : undefined) ?? 'we';\n\n const collectionReasons = uniq([\n 'contact us through e-mail, telephone, mail or other correspondence',\n hasForms ? 'submit one of the forms on our Site' : undefined,\n org?.services && Object.keys(org.services).length > 0\n ? 'register for a service we provide'\n : undefined,\n fields.some((f) => /newsletter|subscribe|mailing/i.test(f.name))\n ? 'register to receive our newsletter'\n : undefined,\n ]);\n\n // Only claim to collect what a configured form actually asks for. With no\n // forms, the generic categories stand in — the site still receives whatever a\n // visitor sends by e-mail.\n const piiCollected = uniq([\n ...(hasForms\n ? fields.map((f) => fieldPhrase(f.name, f.type))\n : [\n 'your full name',\n 'contact information, such as your address, telephone number, or e-mail address',\n ]),\n 'any other personal information that you choose to submit to us',\n ]);\n\n // Session replay is a materially different disclosure from page-view analytics\n // and cannot be folded into `hasAnalytics`: a policy that lists \"the pages you\n // view\" while the site records mouse movement, scrolling and clicks is\n // under-disclosing, not summarising.\n const hasSessionReplay = !!site.analytics?.clarityId;\n\n const techInfo = uniq([\n 'your domain name',\n 'your numerical IP address',\n hasAnalytics ? 'the pages you view and the files you request' : undefined,\n hasAnalytics ? 'the type of browser and operating system you use' : undefined,\n hasAnalytics ? 'the address of the site that referred you' : undefined,\n hasSessionReplay\n ? 'a recording of how you interacted with a page, including mouse movement, scrolling and clicks'\n : undefined,\n ]);\n\n const techInfoPurposes = uniq([\n hasAnalytics ? 'measure the performance of our Site' : undefined,\n hasSessionReplay ? 'see where visitors encounter difficulty using our Site' : undefined,\n site.security?.turnstile?.siteKey\n ? 'protect our Site and its forms from automated abuse'\n : undefined,\n 'better understand how visitors use our Site',\n 'improve our Site to better meet your needs',\n ]);\n\n const ab = site.abTesting;\n\n /**\n * A site offering the `preferences` category stores at least one setting the\n * visitor chose — `<wc-color-scheme-toggle>` writes `vitops-color-scheme` to local\n * storage, gated on exactly this category. The banner asking about it while the\n * notice never mentions it is the disclosure gap `providers.ts` exists to\n * prevent, just on the browser-storage side rather than the third-party one.\n */\n const hasPreferences = consent?.enabled === true && !!consent.categories?.includes('preferences');\n\n /**\n * `site.tracking.enabled` writes the `_ac` cookie: the click ID from the ad a\n * visitor followed, kept for 90 days so a later enquiry can be attributed to\n * the campaign that produced it. It is first-party and never leaves the site,\n * which is exactly why nothing in the provider table would ever mention it —\n * and why it has to be stated here instead. A notice that lists every\n * third-party cookie while omitting the one the site sets itself is the same\n * disclosure defect, pointed inward.\n */\n const hasAdTracking = site.tracking?.enabled === true;\n\n const cookieTracked = uniq([\n 'your IP address',\n 'the type of web browser and operating system used',\n 'the pages of the Site visited',\n hasPreferences\n ? 'display settings you have chosen, such as light or dark appearance'\n : undefined,\n hasAdTracking ? 'which advertisement or campaign brought you to our Site' : undefined,\n ab?.enabled ? 'which version of a page you were shown' : undefined,\n hasSessionReplay ? 'how you moved through and interacted with a page' : undefined,\n ]);\n\n const cookiePurposes = uniq([\n 'keep the Site functioning as you move between pages',\n hasAnalytics ? 'understand how our Site is used, in aggregate' : undefined,\n hasPreferences ? 'remember display settings you choose, between visits' : undefined,\n hasAdTracking\n ? 'attribute an enquiry to the advertisement that brought you here, for up to 90 days'\n : undefined,\n hasSessionReplay ? 'recognise a returning visit as part of the same session' : undefined,\n ab?.enabled ? 'keep you on a consistent version of the Site between visits' : undefined,\n site.security?.turnstile?.siteKey ? 'distinguish visitors from automated traffic' : undefined,\n ]);\n\n // Not \"shown when you first visit\": the banner is raised by whatever needs the\n // permission, at the point it needs it — on arrival for an analytics tag, on the\n // click for a display setting. A site that gates nothing never shows one at all,\n // so promising a first-visit banner would describe a thing that never happens.\n const cookieTool = consent?.enabled\n ? consent.type === 'opt-in'\n ? 'You may also choose which categories of cookies to allow using the consent banner, which appears when something on the Site first needs your permission, and you may change that choice at any time.'\n : 'You may also withdraw your consent to non-essential cookies at any time using the consent controls on our Site.'\n : undefined;\n\n const usePurposes = uniq([\n 'respond to your inquiries',\n 'supply you with requested products or services',\n site.notifications?.email\n ? 'route your message to the appropriate person in our organization'\n : undefined,\n site.tracking?.enabled ? 'measure the effectiveness of our marketing' : undefined,\n 'send you informational or promotional communication',\n 'carry out other purposes that are disclosed to you and to which you consent',\n 'carry out any other purpose permitted or required by law',\n ]);\n\n const cookieOptOutOptions = uniq([\n 'You may configure your browser to refuse cookies, though parts of our Site may not function as intended.',\n consent?.enabled ? cookieTool : undefined,\n ...processors\n .filter((p) => p.optOut)\n .map((p) => `You may opt out of ${p.name} directly at ${p.optOut}.`),\n ]);\n\n const optOutOptions = uniq([\n 'You may unsubscribe from any commercial e-mail we send using the \"unsubscribe\" link in that e-mail.',\n ...cookieOptOutOptions,\n ]);\n\n /**\n * The cross-border disclosure, as two facts rather than one flattened list.\n *\n * Order matters here — each step narrows what the next may claim:\n *\n * 1. Anything in this jurisdiction is not a transfer at all, so it is filtered\n * out. Without this, `country: \"Canada\"` rendered \"outside of Canada,\n * including Canada\".\n * 2. An unscoped storage country is the BROAD claim; a scoped one covering the\n * same country would only narrow it, so it is dropped as redundant.\n * 3. An operator country already named as storage adds no fact — \"US law reaches\n * information stored in the US\" is a sentence, not information.\n *\n * Steps 2 and 3 are what make the rendered output byte-identical for every config\n * that used `country` (which desugars to both facts).\n *\n * No geography is inferred — \"France\" is not resolved into \"the European Union\".\n * Only what the config states is asserted, which is the `matomoLocation` rule.\n */\n const jurisdictionCountry = JURISDICTION_COUNTRIES[legal?.jurisdiction ?? 'ca'];\n // Compare loosely: \"the United States\" and \"United States\" are one fact, and a\n // template must never have to know that \"canada\" is \"Canada\".\n const norm = (c: string) =>\n c\n .trim()\n .toLowerCase()\n .replace(/^the\\s+/, '');\n const foreign = (c: string) => norm(c) !== norm(jurisdictionCountry);\n\n const allStorage = processors.flatMap((p) => p.storage ?? []);\n const unscoped = uniq(\n allStorage.filter((s) => !s.scope && foreign(s.country)).map((s) => s.country),\n );\n const storageCountries = list(unscoped);\n const named = new Set(unscoped.map(norm));\n const scopedStorage = [\n ...new Map(\n allStorage\n .filter((s) => s.scope && foreign(s.country) && !named.has(norm(s.country)))\n .map((s) => [`${norm(s.country)}|${s.scope!}`, { country: s.country, scope: s.scope! }]),\n ).values(),\n ];\n const operatorCountries = list(\n uniq(processors.map((p) => p.operatorCountry)).filter((c) => foreign(c) && !named.has(norm(c))),\n );\n\n // Back-compat: every country the old field ever named, unfiltered, in processor\n // order — storage before operator, matching how `country` desugars.\n const countries = list(\n uniq(\n processors.flatMap((p) => [...(p.storage ?? []).map((s) => s.country), p.operatorCountry]),\n ),\n );\n\n const address = contact?.address ?? org?.address;\n\n return {\n businessName,\n url: site.domains?.canonical ?? '',\n mailingAddress: formatContact(contact),\n lastUpdated: privacy?.lastUpdated,\n retention: privacy?.retention,\n governingLaw: legal?.termsOfService?.governingLaw,\n governingProvince: expandProvince(address?.addressRegion),\n governingCountry: address?.addressCountry ?? 'Canada',\n collectionReasons,\n piiCollected,\n techInfo,\n techInfoPurposes,\n cookieTracked,\n cookiePurposes,\n cookieTool,\n usePurposes,\n optOutOptions,\n cookieOptOutOptions,\n processors,\n firstPartyCookies: hasAdTracking\n ? [\n {\n name: '_ac',\n purpose:\n 'records the advertisement or campaign you arrived from, so an enquiry can be attributed to it',\n retention: '90 days',\n },\n ]\n : [],\n jurisdictionCountry,\n storageCountries: storageCountries || undefined,\n scopedStorage,\n operatorCountries: operatorCountries || undefined,\n countries: countries || undefined,\n consentModel: consent?.enabled ? (consent.type ?? 'opt-in') : 'none',\n cookieCategories: consent?.categories ?? [],\n };\n}\n","/**\n * The legal documents are authored in markdown; consumers need markdown, HTML\n * and EmDash Portable Text. This parses the markdown **once** into a small block\n * model, and the three outputs render from that.\n *\n * The subset is **closed by construction** — we author every template, so the\n * parser does not need to be a markdown implementation, it needs to be exactly\n * as capable as the templates are. That is why it *throws* on anything outside\n * the subset rather than passing it through: an unrecognised construct that\n * silently degrades to a paragraph is how a published policy ends up with a\n * literal `| --- |` in it. A template that grows a table fails the test suite\n * instead.\n *\n * Supported, and nothing else:\n * block `#`/`##`/`###` headings, `- ` bullets, `> ` quote, paragraphs\n * inline `**strong**`, `` `code` ``\n *\n * HTML rendering delegates to `nodesToHtml` from `@getvitops/utils`, which\n * already solves escaping and void elements — this module maps to `ContentNode`\n * and stops there.\n */\nimport { nodesToHtml, type ContentNode } from '@getvitops/utils';\n\nexport interface Span {\n text: string;\n strong?: boolean;\n code?: boolean;\n}\n\nexport type Block =\n | { kind: 'heading'; level: 1 | 2 | 3; spans: Span[] }\n | { kind: 'paragraph'; spans: Span[] }\n | { kind: 'list'; items: Span[][] }\n | { kind: 'quote'; spans: Span[] };\n\n/** Constructs that look like markdown but are outside the subset. */\nconst UNSUPPORTED: [RegExp, string][] = [\n [/^#{4,}\\s/, 'headings deeper than ###'],\n [/^\\s*\\d+[.)]\\s/, 'ordered lists'],\n [/^\\s*```/, 'code fences'],\n [/^\\s*\\|/, 'tables'],\n [/^\\s*[*+]\\s/, 'bullets other than `- `'],\n [/^\\s+-\\s/, 'nested lists'],\n];\n\n// Bold and code spans, in one pass so a `**` inside backticks stays literal.\nconst INLINE = /(\\*\\*[^*]+\\*\\*|`[^`]+`)/g;\n\nfunction parseInline(text: string, where: string): Span[] {\n const spans: Span[] = [];\n let last = 0;\n for (const m of text.matchAll(INLINE)) {\n const token = m[0];\n if (m.index > last) spans.push({ text: text.slice(last, m.index) });\n if (token.startsWith('`')) spans.push({ text: token.slice(1, -1), code: true });\n else spans.push({ text: token.slice(2, -2), strong: true });\n last = m.index + token.length;\n }\n if (last < text.length) spans.push({ text: text.slice(last) });\n\n // Check what's left as literal text, so `**bold**` doesn't trip the `*` guard\n // and a cookie name like `_ga` (already inside a code span) doesn't either.\n for (const span of spans) {\n if (span.strong || span.code) continue;\n if (/!?\\[[^\\]]*\\]\\(/.test(span.text))\n throw new Error(\n `legal template uses links or images, which are outside the subset: ${where}`,\n );\n if (span.text.includes('**'))\n throw new Error(`legal template has an unmatched \\`**\\`: ${where}`);\n if (span.text.includes('`'))\n throw new Error(`legal template has an unmatched backtick: ${where}`);\n }\n return spans;\n}\n\n/** Markdown (our subset) → blocks. Throws on anything it does not model. */\nexport function parseMarkdown(md: string): Block[] {\n const blocks: Block[] = [];\n const lines = md.split('\\n');\n let paragraph: string[] = [];\n\n const flush = () => {\n if (paragraph.length === 0) return;\n const text = paragraph.join(' ');\n blocks.push({ kind: 'paragraph', spans: parseInline(text, text.slice(0, 60)) });\n paragraph = [];\n };\n\n for (const line of lines) {\n for (const [re, what] of UNSUPPORTED)\n if (re.test(line))\n throw new Error(`legal template uses ${what}, outside the subset: ${line}`);\n\n if (line.trim() === '') {\n flush();\n continue;\n }\n\n const heading = /^(#{1,3})\\s+(.*)$/.exec(line);\n if (heading) {\n flush();\n blocks.push({\n kind: 'heading',\n level: heading[1]!.length as 1 | 2 | 3,\n spans: parseInline(heading[2]!.trim(), line),\n });\n continue;\n }\n\n const quote = /^>\\s+(.*)$/.exec(line);\n if (quote) {\n flush();\n blocks.push({ kind: 'quote', spans: parseInline(quote[1]!.trim(), line) });\n continue;\n }\n\n const bullet = /^-\\s+(.*)$/.exec(line);\n if (bullet) {\n flush();\n const item = parseInline(bullet[1]!.trim(), line);\n // Consecutive `- ` lines are one list; a blank line between them starts a\n // new one, which is what markdown means and what the templates rely on.\n const prev = blocks[blocks.length - 1];\n if (prev?.kind === 'list') prev.items.push(item);\n else blocks.push({ kind: 'list', items: [item] });\n continue;\n }\n\n paragraph.push(line.trim());\n }\n flush();\n return blocks;\n}\n\n// ── ContentNode / HTML ──────────────────────────────────────────────────────────\n\nfunction spanNodes(spans: Span[]): ContentNode[] {\n return spans.map((s) =>\n s.strong ? { tag: 'strong', text: s.text } : s.code ? { tag: 'code', text: s.text } : s.text,\n );\n}\n\n/**\n * Blocks → `ContentNode[]`, the framework-agnostic tree the site config already\n * uses for `templates` of type `nodes` and `NodeRenderer.astro` already renders.\n */\nexport function toContentNodes(blocks: Block[]): ContentNode[] {\n return blocks.map((b): ContentNode => {\n switch (b.kind) {\n case 'heading':\n return { tag: `h${b.level}`, children: spanNodes(b.spans) };\n case 'paragraph':\n return { tag: 'p', children: spanNodes(b.spans) };\n case 'quote':\n return { tag: 'blockquote', children: [{ tag: 'p', children: spanNodes(b.spans) }] };\n case 'list':\n return {\n tag: 'ul',\n children: b.items.map((item) => ({ tag: 'li', children: spanNodes(item) })),\n };\n }\n });\n}\n\nexport function toHtmlFragment(blocks: Block[]): string {\n return nodesToHtml(toContentNodes(blocks));\n}\n\n// ── Portable Text (EmDash) ──────────────────────────────────────────────────────\n\n/**\n * Blocks → EmDash Portable Text, matching the shape already seeded in\n * `packages/create/templates/emdash/seed/seed.json`.\n *\n * Two deliberate mappings:\n * - the `# ` heading is **dropped** — in EmDash the page title is a field\n * (`data.title`), and repeating it as the first content block renders twice;\n * - the review blockquote becomes a `vitops.banner` with `tone: \"warning\"`,\n * which is exactly the block the hand-written placeholder pages used.\n *\n * `_key`s are derived from position rather than randomness, so regenerating an\n * unchanged config produces an identical seed and a clean diff.\n */\nexport function toPortableText(blocks: Block[], prefix: string): unknown[] {\n const out: unknown[] = [];\n blocks.forEach((b, i) => {\n const key = `${prefix}-${i}`;\n if (b.kind === 'heading' && b.level === 1) return;\n\n if (b.kind === 'quote') {\n out.push({\n _type: 'vitops.banner',\n _key: key,\n message: b.spans.map((s) => s.text).join(''),\n tone: 'warning',\n dismissible: false,\n });\n return;\n }\n\n const block = (spans: Span[], k: string, extra: Record<string, unknown>) => ({\n _type: 'block',\n _key: k,\n markDefs: [],\n children: spans.map((s, j) => ({\n _type: 'span',\n _key: `${k}-${j}`,\n text: s.text,\n marks: [s.strong && 'strong', s.code && 'code'].filter(Boolean),\n })),\n ...extra,\n });\n\n if (b.kind === 'list') {\n b.items.forEach((item, j) =>\n out.push(block(item, `${key}-${j}`, { style: 'normal', listItem: 'bullet', level: 1 })),\n );\n return;\n }\n\n out.push(block(b.spans, key, { style: b.kind === 'heading' ? `h${b.level}` : 'normal' }));\n });\n return out;\n}\n","/**\n * Pieces every legal template shares.\n *\n * Kept deliberately tiny: anything that grows here is prose leaking out of the\n * jurisdiction-specific templates into a shared file, which is how a document\n * ends up asserting something that isn't true of the body of law it claims to\n * follow. Formatting helpers belong here; sentences almost never do.\n */\nimport type { PolicyVars } from '../derive.ts';\n\n/**\n * The banner every generated document opens with.\n *\n * Not optional and not configurable. These documents are rendered from a\n * template by a build tool, not drafted for a specific business by someone who\n * can be asked follow-up questions — and the one failure mode with real\n * consequences is a consumer publishing one as-is. It is a blockquote so it\n * renders as a callout in HTML and as a warning banner in EmDash.\n */\nexport const REVIEW_NOTICE =\n \"> Generated from this site's configuration. It is a starting point, not legal advice — have it reviewed before you publish it, and make sure it matches what your site actually does.\";\n\n/** A markdown bullet list. Empty in, empty out — never a stray `-`. */\nexport function bullets(items: string[]): string {\n return items.map((item) => `- ${item}`).join('\\n');\n}\n\n/**\n * Taken from config rather than the clock, so a rebuild of an unchanged config\n * produces a byte-identical document.\n */\nexport function updatedLine(v: Pick<PolicyVars, 'lastUpdated'>): string {\n return v.lastUpdated ? `\\nLast updated: ${v.lastUpdated}\\n` : '';\n}\n","/**\n * Cookie notice — Canada.\n *\n * The one document here that is almost entirely derived: which cookies a site\n * sets follows from which providers it uses, and the config already knows that.\n * The prose is a frame around `v.processors` and `v.cookieCategories`.\n *\n * Rendered as headings and bullets rather than a table, deliberately — the\n * markdown subset the renderer supports is closed, and a table would widen it\n * for one document. Bullets also survive a narrow viewport, which a four-column\n * cookie table does not.\n */\nimport { list, type PolicyVars } from '../derive.ts';\nimport { bullets, REVIEW_NOTICE, updatedLine } from './shared.ts';\n\nexport function cookiesCa(v: PolicyVars): string {\n return `# Cookie Notice\n${updatedLine(v)}\n${REVIEW_NOTICE}\n\nThis notice explains how ${v.businessName} uses cookies and similar technologies on ${v.url} (the \"Site\"). It supplements our Privacy Policy.\n\n## What Cookies Are\n\nA cookie is a small text file that a website asks your browser to store. Cookies let a site remember things between pages and between visits — for example, that you have already dismissed a message. Similar technologies, such as local storage, do much the same thing.\n\n## What We Use Them For\n\n${bullets(v.cookiePurposes)}\n\nCookies used on this Site may track:\n\n${bullets(v.cookieTracked)}\n\n${providersSection(v)}${categoriesSection(v)}\n## Your Choices\n\n${bullets(v.cookieOptOutOptions)}\n\nMost browsers let you see which cookies are stored, delete them individually or in bulk, and block them entirely. Blocking all cookies will stop parts of the Site from working as intended.\n\n## Contact\n\nIf you have questions about our use of cookies, please contact us at ${v.mailingAddress}.\n`;\n}\n\n/**\n * \"This site sets no cookies\" is a real and increasingly common answer — a\n * cookieless analytics provider is a selling point, not an omission. Saying it\n * plainly beats an empty section that reads as an oversight.\n *\n * But it is only true if the site sets none of its **own**, which is why\n * `firstPartyCookies` is checked alongside the processors: a site running\n * attribution with a cookieless analytics provider sets `_ac` and no third-party\n * cookie at all, and the old wording would have declared it cookie-free.\n */\nfunction providersSection(v: PolicyVars): string {\n const setting = v.processors.filter((p) => p.cookies?.length);\n const cookieless = v.processors.filter((p) => p.cookies?.length === 0);\n const own = v.firstPartyCookies;\n\n const ownSection = own.length\n ? `\\n### Cookies We Set Ourselves\\n\\n${bullets(\n own.map((c) => `\\`${c.name}\\` — ${c.purpose}. Kept for ${c.retention}.`),\n )}\\n`\n : '';\n\n if (setting.length === 0) {\n const named = cookieless.length\n ? ` The third party ${cookieless.length === 1 ? 'service' : 'services'} we use on this Site — ${list(\n cookieless.map((p) => p.name),\n )} — ${cookieless.length === 1 ? 'does' : 'do'} not set cookies of ${\n cookieless.length === 1 ? 'its' : 'their'\n } own.`\n : '';\n const none = own.length\n ? `Beyond the cookies strictly necessary to serve and secure the Site, no third party sets cookies through this Site.${named}`\n : `Beyond the cookies strictly necessary to serve and secure the Site, we do not set cookies.${named}`;\n return `## Cookies Set on This Site\n\n${none}\n${ownSection}`;\n }\n\n return `## Cookies Set on This Site\n\n${bullets(\n setting.map(\n (p) =>\n // Cookie names go in code spans, not bare: `_ga, _gid` in running markdown\n // is a matched pair of underscores, which a downstream renderer turns into\n // emphasis and eats the names.\n `**${p.name}** (${p.purpose}) — ${(p.cookies ?? []).map((c) => `\\`${c}\\``).join(', ')}${\n p.privacyUrl ? `. Privacy policy: ${p.privacyUrl}` : ''\n }`,\n ),\n)}\n${\n cookieless.length\n ? `\\nWe also use ${list(cookieless.map((p) => p.name))}, which ${\n cookieless.length === 1 ? 'does' : 'do'\n } not set cookies of ${cookieless.length === 1 ? 'its' : 'their'} own.\\n`\n : ''\n}${ownSection}`;\n}\n\n/** Only meaningful when a consent tool actually offers the categories. */\nfunction categoriesSection(v: PolicyVars): string {\n if (v.consentModel === 'none' || v.cookieCategories.length === 0) return '';\n return `\n## Cookie Categories\n\nOur consent controls group cookies into the following categories, which you can accept or decline${\n v.consentModel === 'opt-in'\n ? ' before any non-essential cookie is set'\n : ' at any time after your first visit'\n }:\n\n${bullets(v.cookieCategories)}\n`;\n}\n","/**\n * Privacy policy — Canada (PIPEDA).\n *\n * Ported from the pandoc prototype at `packages/core/legal-templates/`. Two\n * things changed in the port and both are load-bearing:\n *\n * 1. `${var}` is now real TypeScript interpolation rather than a pandoc Lua\n * filter, so an unresolved variable is a compile error. The filter left\n * unknown keys as the literal text `${key}` — which would ship a live\n * privacy policy containing `${countries}`.\n * 2. Lists are built from arrays, not by splicing a string into a fixed bullet.\n * An empty derived value used to produce a stray `- ; and` bullet.\n *\n * The prose is jurisdiction-specific: it names the Office of the Privacy\n * Commissioner of Canada and frames transfers as \"outside of Canada\". Do not\n * reuse it for another jurisdiction — add a sibling template instead.\n */\n// `list` is a formatting helper, the same class as `bullets` — the connectives\n// (\"including\", \"in the case of\") stay in the prose below, where they belong.\nimport { list, type PolicyVars } from '../derive.ts';\nimport { bullets, REVIEW_NOTICE, updatedLine } from './shared.ts';\n\nexport function privacyCa(v: PolicyVars): string {\n return `# Privacy Policy\n${updatedLine(v)}\n${REVIEW_NOTICE}\n\nThis is the privacy policy of ${v.businessName} (\"Business\"). It summarizes what personal information we collect and how we use and disclose this information.\n\nBy using our website (the \"Site\"), you signify your consent to the terms of our Privacy Policy. If you do not agree with any terms of this Privacy Policy, please do not use this Site or submit any personal information to us, or use the preference tools we provide to adjust your settings. This Privacy Policy also describes certain choices you have on how we use your personal information.\n\nWe reserve the right to modify this Privacy Policy at any time. We will reflect any such modifications to this Privacy Policy on our Site. We suggest that you periodically consult this Privacy Policy. Your continued use of the Site after any such changes constitutes your acceptance of this Privacy Policy, as revised.\n\n**Privacy Policy Summary.**\n\n${bullets([\n 'What Personal Information We Collect',\n 'How We Use Personal Information',\n 'How We Share Personal Information',\n 'Your Choices',\n])}\n\n## Full Privacy Policy\n\n### What Personal Information We Collect and How We Collect It\n\nPersonal information is information about an identifiable individual. We collect personal information only for purposes that a reasonable person would consider appropriate in the circumstances and only with your knowledge and consent, except where otherwise required or permitted by law. Business collects personal information when you voluntarily provide it through our Site or when you provide it to us through other means. For example, we may collect personal information when you:\n\n${bullets(v.collectionReasons)}\n\nThe personal information we may collect will depend on the service you request and may include:\n\n${bullets(v.piiCollected)}\n\n### How Business Collects Information Through Technological Means\n\nWhen you visit our Site, we may collect information that is automatically sent to us by your web browser. This information may include:\n\n${bullets(v.techInfo)}\n\nWe use this information to:\n\n${bullets(v.techInfoPurposes)}\n\nThe amount of information that is sent by your web browser depends on the browser and settings you use. Please refer to the instructions provided by your browser if you want to learn more about what information it sends to websites you visit or how you may change or restrict this.\n\nBusiness may use cookies and other similar devices on this Site to enhance functionality. These devices may track information which includes:\n\n${bullets(v.cookieTracked)}\n\nWe use this information to:\n\n${bullets(v.cookiePurposes)}\n\nIf you wish to disable cookies, refer to your browser help menu to learn how.${v.cookieTool ? ` ${v.cookieTool}` : ''}\n\n### How Business Uses and Discloses Personal Information\n\nThe personal information we collect may be used by Business for the purposes for which it was collected, as provided in this Privacy Policy, or for other purposes that are disclosed to you and to which you consent.\n\nFor example, we may use your personal information to:\n\n${bullets(v.usePurposes)}\n\n${providersSection(v)}\n\nBusiness reserves the right to transfer personal information in the event that we merge with or are acquired by a third party. We also may disclose your personal information for any other purpose required or permitted by law or to which you consent.\n\n### Your Choices\n\n${bullets(v.optOutOptions)}\n\n### How We Protect Personal Information\n\nThe security of your personal information is important to us. We protect your personal information in our control through appropriate security safeguards against loss, theft, unauthorized access, disclosure, copying, use or modification. These safeguards include physical measures (such as locked filing cabinets), organizational measures (such as employee training and restricted access), and technological measures (such as encryption and passwords). Personal information may be accessed by persons within our organization who require such access to carry out the purposes described in this Privacy Policy, or such other purposes as permitted or required by law. Personal information we collect is maintained with the source of the information at ${v.url}.\n\nWe retain personal information that we collect only as long as necessary for the purposes for which it was collected or to meet legal requirements. We destroy personal information when it is no longer needed for such purposes.${v.retention ? ` In general, we keep personal information for ${v.retention}.` : ''}\n\nIt is important to understand that no security measures are absolute. We cannot guarantee the safety of any information you provide to us.\n${transferSection(v)}\n### Accessing and Correcting Your Personal Information\n\nYou have a right to access your personal information and to request a correction to it if you believe it is inaccurate. If you have submitted personal information and would like to have access to it, or if you would like to have it corrected, please contact us using the contact information provided below. We may require you verify your identity before allowing you to access your personal information.\n\n### How to Contact Us\n\nIf you have any questions regarding this Privacy Policy, to submit a complaint, or to access or correct your information, please contact our Privacy Officer at ${v.mailingAddress}. If you are not satisfied with our response to your privacy concerns, you may contact the Office of the Privacy Commissioner of Canada at www.priv.gc.ca or 1-800-282-1376.\n`;\n}\n\n/**\n * Named separately because a site with no third parties at all should not claim\n * to have service providers, and one with them owes the reader their identity —\n * \"we may share with service providers\" without naming them is the vaguest and\n * least useful sentence a policy can contain.\n */\nfunction providersSection(v: PolicyVars): string {\n if (v.processors.length === 0)\n return 'We do not transfer personal information to third party service providers.';\n return `We may transfer personal information to third party service providers that assist us with carrying out these purposes. When we transfer personal information to service providers, we require them to protect the information in a manner consistent with our privacy practices and applicable privacy laws. These service providers are:\n\n${bullets(\n v.processors.map(\n (p) => `${p.name}, for ${p.purpose}${p.privacyUrl ? ` (privacy policy: ${p.privacyUrl})` : ''}`,\n ),\n)}\n\nWe remain responsible for personal information in the possession of our service providers.`;\n}\n\n/**\n * Omitted entirely when nothing leaves the country — a false claim otherwise.\n *\n * Two clauses, because storage and legal reach are two facts and the OPC's concern\n * is foreign **access**, not merely foreign storage. A provider can hold data in\n * Canada and still be compellable abroad (Azure in a Canadian region), and a\n * provider can hold only one category of data abroad (a Canadian tenant whose\n * identity data sits in the US). One sentence could state neither.\n *\n * The closer is shared: it is true of whichever clauses appear.\n */\nfunction transferSection(v: PolicyVars): string {\n const clauses = [storageClause(v), operatorClause(v)].filter(Boolean);\n if (clauses.length === 0) return '';\n return `\n### We May Transfer Personal Information to Other Countries\n\n${clauses.join('\\n\\n')}\n\nAs a result, this information may be subject to access requests from governments, courts or law enforcement in those jurisdictions according to laws in those jurisdictions.\n`;\n}\n\n/**\n * Where the information rests.\n *\n * A scoped location gets its own sentence rather than joining the \"including …\"\n * list: folded in, a reader would take it to cover everything the provider holds,\n * which is a broader claim than the config made.\n */\nfunction storageClause(v: PolicyVars): string {\n const scoped = list(v.scopedStorage.map((s) => `${s.country}, in the case of ${s.scope}`));\n if (v.storageCountries)\n return `Some or all of the personal information we collect may be stored or processed in jurisdictions outside of Canada, including ${v.storageCountries}.${\n scoped\n ? ` Certain categories of personal information are held outside of Canada even where the rest is not: ${scoped}.`\n : ''\n }`;\n if (scoped)\n return `Certain categories of the personal information we collect are stored or processed outside of Canada: ${scoped}.`;\n return '';\n}\n\n/** The Azure-in-Canada case: the information never moves, and foreign law still reaches it. */\nfunction operatorClause(v: PolicyVars): string {\n if (!v.operatorCountries) return '';\n return `Some of the service providers we use are established in, or controlled from, jurisdictions outside of Canada, including ${v.operatorCountries}. Personal information those providers handle on our behalf may be subject to the laws of those jurisdictions even when it is stored in Canada.`;\n}\n","/**\n * Terms of service — Canada.\n *\n * Unlike the privacy policy, this has no prototype in the repo to port: the\n * prose is new. It is written as **generic website terms** — the clauses almost\n * every informational site needs (acceptable use, intellectual property,\n * disclaimer, limitation of liability, governing law) and nothing more.\n *\n * It deliberately does NOT cover the things that actually vary between\n * businesses and carry the most risk: sales and refunds, subscriptions and\n * renewals, user-generated content and its moderation, accounts and\n * termination, professional advice, or anything sector-regulated. A site doing\n * any of those needs clauses drafted for it — the review banner says so, and\n * this file should not grow them, because a template that half-covers payments\n * is more dangerous than one that visibly omits them.\n */\nimport type { PolicyVars } from '../derive.ts';\nimport { bullets, REVIEW_NOTICE, updatedLine } from './shared.ts';\n\nexport function termsCa(v: PolicyVars): string {\n return `# Terms of Service\n${updatedLine(v)}\n${REVIEW_NOTICE}\n\nThese terms govern your use of ${v.url} (the \"Site\"), operated by ${v.businessName} (\"we\", \"us\"). By accessing or using the Site, you agree to these terms. If you do not agree to them, please do not use the Site.\n\nWe may change these terms from time to time. The version published on the Site is the one that applies, and your continued use of the Site after a change means you accept the revised terms.\n\n## Use of the Site\n\nYou may use the Site for lawful purposes only. You agree not to:\n\n${bullets([\n 'use the Site in any way that breaches any applicable law or regulation',\n 'attempt to gain unauthorized access to the Site, its servers, or any connected system',\n 'interfere with or disrupt the operation of the Site, including by introducing malicious code',\n 'collect or harvest information about other users of the Site',\n 'reproduce, duplicate, or resell any part of the Site except as these terms permit',\n])}\n\nWe may suspend or withdraw access to the Site, in whole or in part, at any time and without notice.\n\n## Intellectual Property\n\nUnless stated otherwise, the content of the Site — including text, graphics, logos, and layout — is owned by or licensed to us and is protected by copyright and other intellectual property laws. You may view, download, and print content from the Site for your own personal, non-commercial use. Any other use requires our prior written permission.\n\n## Accuracy of Information\n\nWe take reasonable care to keep the Site accurate and current, but we make no representation or warranty that the content is complete, accurate, or up to date. Content on the Site is provided for general information only and should not be relied on as advice for your particular circumstances.\n\n## Third Party Links and Services\n\nThe Site may link to, or rely on, websites and services operated by others. We do not control those sites and services and are not responsible for their content, availability, or practices. A link is not an endorsement.\n\n## Disclaimer\n\n**The Site is provided \"as is\" and \"as available\", without warranty of any kind, whether express or implied.** To the fullest extent permitted by law, we disclaim all warranties, including implied warranties of merchantability, fitness for a particular purpose, and non-infringement. We do not warrant that the Site will be uninterrupted, secure, or error free.\n\n## Limitation of Liability\n\n**To the fullest extent permitted by law, we will not be liable for any indirect, incidental, special, consequential, or punitive damages, or for any loss of profits, revenue, data, or goodwill, arising out of or in connection with your use of the Site** — whether the claim is based in contract, tort, or any other legal theory, and whether or not we were advised of the possibility of such damages.\n\nNothing in these terms excludes or limits liability that cannot be excluded or limited under applicable law.\n\n## Privacy\n\nOur handling of personal information is described in our Privacy Policy, which forms part of these terms.\n\n## Governing Law\n\nThese terms are governed by the laws of ${governingLaw(v)}. You agree to the exclusive jurisdiction of the courts of that jurisdiction for any dispute arising out of or in connection with these terms or the Site.\n\n## Contact\n\nIf you have questions about these terms, please contact us at ${v.mailingAddress}.\n`;\n}\n\n/**\n * Canadian law is split between the provinces and the federal Parliament, so the\n * conventional clause names both. Without a province we can only name the\n * country — better a broader clause than one asserting a province we guessed.\n */\nfunction governingLaw(v: PolicyVars): string {\n if (v.governingLaw) return v.governingLaw;\n return v.governingProvince\n ? `${v.governingProvince} and the federal laws of ${v.governingCountry} applicable therein`\n : v.governingCountry;\n}\n","/**\n * The jurisdiction registry.\n *\n * Adding a jurisdiction is: author the three templates, add one key here, add\n * one member to `JURISDICTIONS` in `config.ts`. The `satisfies` below makes the\n * second and third steps a compile error if you skip either — a config could\n * otherwise name a jurisdiction with no templates behind it and silently render\n * against the wrong body of law.\n *\n * Every jurisdiction owes all three documents. A partial set would mean\n * `legal.termsOfService.enabled` silently emitting nothing.\n */\nimport type { Jurisdiction } from '../../config.ts';\nimport type { PolicyVars } from '../derive.ts';\nimport { cookiesCa } from './cookies.ca.ts';\nimport { privacyCa } from './privacy.ca.ts';\nimport { termsCa } from './terms.ca.ts';\n\nexport type LegalDoc = 'privacy' | 'terms' | 'cookies';\n\nexport type DocSet = Record<LegalDoc, (v: PolicyVars) => string>;\n\nexport const TEMPLATES = {\n ca: { privacy: privacyCa, terms: termsCa, cookies: cookiesCa },\n} satisfies Record<Jurisdiction, DocSet>;\n\n/** Stable output order, independent of which docs a given config enables. */\nexport const DOC_ORDER: LegalDoc[] = ['privacy', 'terms', 'cookies'];\n\n/** Output filename stem per document — also the Bricks shortcode's allowlist. */\nexport const DOC_SLUGS: Record<LegalDoc, string> = {\n privacy: 'privacy-policy',\n terms: 'terms-of-service',\n cookies: 'cookie-notice',\n};\n","/**\n * Generate a site's legal documents from its config.\n *\n * Shaped after `generateDocs` rather than after a `generate()` format, and the\n * reason is structural: `generate()` is keyed to a **`DesignSystem`**, while a\n * privacy policy renders from a **`Config`**. Bolting it on as a `Format`\n * would mean a format that ignores its own input. So this is a sibling public\n * function that returns a `{ relPath: content }` map and lets each caller write\n * it where it belongs — the CLI to stdout or a directory, the bricks build into\n * `dist/legal/`, the Astro integration into a content collection.\n *\n * Pure: no filesystem, no clock, no shared state.\n */\nimport { derivePolicyVars, type PolicyVars } from './derive.ts';\nimport { parseMarkdown, toContentNodes, toHtmlFragment, toPortableText } from './render.ts';\nimport { DOC_ORDER, DOC_SLUGS, TEMPLATES, type LegalDoc } from './templates/index.ts';\nimport type { Config } from '../config.ts';\nimport type { ContentNode } from '@getvitops/utils';\n\nexport type LegalOutput = 'md' | 'html' | 'portable-text';\n\nexport interface GenerateLegalOptions {\n /** Which documents to render. Defaults to those enabled in the config. */\n docs?: LegalDoc[];\n /** Output format. Default `md`. */\n output?: LegalOutput;\n}\n\nconst EXT: Record<LegalOutput, string> = {\n md: 'md',\n html: 'html',\n 'portable-text': 'json',\n};\n\n/** Which documents the config asks for, in a stable order. */\nexport function enabledDocs(cfg: Config): LegalDoc[] {\n const legal = cfg.site.legal;\n const on: Record<LegalDoc, boolean> = {\n privacy: !!legal?.privacyPolicy?.enabled,\n terms: !!legal?.termsOfService?.enabled,\n cookies: !!legal?.cookieConsent?.enabled,\n };\n return DOC_ORDER.filter((d) => on[d]);\n}\n\n/** Render one document to markdown. The other outputs derive from this. */\nexport function renderMarkdown(cfg: Config, doc: LegalDoc, vars?: PolicyVars): string {\n const jurisdiction = cfg.site.legal?.jurisdiction ?? 'ca';\n // `validateConfig` rejects an unregistered jurisdiction, so this is a guard for\n // callers that skipped validation rather than an expected path.\n const set = TEMPLATES[jurisdiction];\n if (!set) throw new Error(`no legal templates for jurisdiction \"${jurisdiction}\"`);\n return set[doc](vars ?? derivePolicyVars(cfg));\n}\n\n/**\n * Render one document as a `ContentNode` tree — the framework-agnostic shape the\n * site config already uses for `templates` of type `nodes`, so an Astro consumer\n * can hand it to `NodeRenderer` instead of injecting a string of HTML.\n */\nexport function renderNodes(cfg: Config, doc: LegalDoc): ContentNode[] {\n return toContentNodes(parseMarkdown(renderMarkdown(cfg, doc)));\n}\n\n/**\n * Every enabled legal document, keyed by output path.\n *\n * Documents are keyed by filename (`privacy-policy.md`) rather than by document\n * id so a caller can write the map verbatim.\n */\nexport function generateLegal(\n cfg: Config,\n opts: GenerateLegalOptions = {},\n): Record<string, string> {\n const output = opts.output ?? 'md';\n const docs = opts.docs ?? enabledDocs(cfg);\n // Derived once: every document asserts the same facts, and re-deriving per\n // document would let them disagree if the derivation ever stopped being pure.\n const vars = derivePolicyVars(cfg);\n\n const out: Record<string, string> = {};\n for (const doc of docs) {\n const md = renderMarkdown(cfg, doc, vars);\n const slug = DOC_SLUGS[doc];\n const content =\n output === 'md'\n ? md\n : output === 'html'\n ? toHtmlFragment(parseMarkdown(md))\n : JSON.stringify(toPortableText(parseMarkdown(md), slug), null, 2) + '\\n';\n out[`${slug}.${EXT[output]}`] = content;\n }\n return out;\n}\n\nexport { derivePolicyVars, type PolicyVars } from './derive.ts';\nexport {\n detectProcessorKeys,\n KNOWN_PROCESSORS,\n processorsMissingLocation,\n resolveProcessors,\n} from './providers.ts';\nexport type { KnownProcessorKey, Processor, ProcessorStorage } from './providers.ts';\nexport { parseMarkdown, toContentNodes, toHtmlFragment, toPortableText } from './render.ts';\nexport type { Block, Span } from './render.ts';\nexport { DOC_ORDER, DOC_SLUGS, TEMPLATES } from './templates/index.ts';\nexport type { DocSet, LegalDoc } from './templates/index.ts';\n","/**\n * Build an SVG sprite from an icon `include` map.\n *\n * This is the delivery path for consumers that cannot run an icon integration:\n * Bricks/WordPress, EmDash's renderers, anything rendering HTML outside an Astro\n * build. Markup is `<svg><use href=\"…/icons.svg#ph--caret-down\"/></svg>` — no\n * runtime JS and no network call, which is what keeps it inside the tier rules\n * (a runtime-fetching element would be behaviour JS with no fallback to enhance).\n *\n * The icon DATA comes from the `@iconify-json/*` collections, which stay optional\n * peers loaded dynamically: `@iconify-json/ph` alone is ~4.5 MB and the semantic\n * map spans five sets, so depending on them directly would be indefensible for\n * every consumer who never asks for a sprite.\n */\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { IconifyJSON } from '@iconify/types';\nimport { getIconData, iconToSVG, replaceIDs } from '@iconify/utils';\n\nexport interface IconSpriteOptions {\n /** Exactly `generateIconInclude()`'s shape: collection → icon names. */\n include: Record<string, string[]>;\n /**\n * Extra ids pointing at an already-included icon, e.g. `{ 'icon-menu': 'ph:list' }`,\n * so a consumer can reference a semantic name without knowing the set.\n */\n aliases?: Record<string, string>;\n /**\n * Directory to resolve `@iconify-json/*` from. Defaults to `process.cwd()`.\n *\n * Load-bearing: the collections are the CONSUMER's dependency, not this\n * package's, so a bare `import('@iconify-json/ph/…')` from inside the\n * generator resolves against the generator's own node_modules and misses them\n * entirely — which reads as \"not installed\" on a project that has them.\n */\n resolveFrom?: string;\n /** Injected in tests so the emitter can run without any @iconify-json/* installed. */\n loadSet?: (prefix: string) => Promise<IconifyJSON | null>;\n}\n\nexport interface IconSpriteResult {\n svg: string;\n /** Every `<symbol>` id emitted, in order. */\n ids: string[];\n /** `prefix:name` entries that were asked for but not found. */\n missing: string[];\n}\n\n/**\n * `ph:caret-down` → `ph--caret-down`.\n *\n * The one place this grammar lives. `Icon.astro` mirrors it and `icon.test.ts`\n * guards the pair, because a drift here resolves `<use>` to nothing and renders\n * as an empty box rather than an error.\n */\nexport function spriteId(qualified: string): string {\n return qualified.replace(':', '--');\n}\n\n/**\n * Default loader: the collection JSON shipped by `@iconify-json/<prefix>`.\n *\n * Resolved through a `createRequire` rooted at the consumer's directory, then\n * imported by absolute path — a bare specifier would resolve against this\n * package instead, where the collections deliberately aren't installed.\n */\nasync function loadCollection(prefix: string, from: string): Promise<IconifyJSON | null> {\n try {\n const req = createRequire(pathToFileURL(join(from, 'noop.js')));\n const path = req.resolve(`@iconify-json/${prefix}/icons.json`);\n const mod = await import(pathToFileURL(path).href, { with: { type: 'json' } });\n return (mod.default ?? mod) as IconifyJSON;\n } catch {\n return null;\n }\n}\n\nexport async function buildIconSprite(o: IconSpriteOptions): Promise<IconSpriteResult> {\n const from = o.resolveFrom ?? process.cwd();\n const load = o.loadSet ?? ((prefix: string) => loadCollection(prefix, from));\n const symbols: string[] = [];\n const ids: string[] = [];\n const missing: string[] = [];\n /** qualified name → its rendered body+viewBox, so an alias can reuse it. */\n const rendered = new Map<string, { viewBox: string; body: string }>();\n\n for (const [prefix, names] of Object.entries(o.include)) {\n if (!names?.length) continue;\n const set = await load(prefix);\n if (!set) {\n throw new Error(\n `[vitops icons] Cannot build the sprite: the \"${prefix}\" icon set is not installed. ` +\n `Run \\`pnpm add -D @iconify-json/${prefix}\\`, or drop it from your icons config.`,\n );\n }\n for (const name of names) {\n // getIconData resolves aliases and parent chains, so `include` can name\n // either a real icon or one of the set's own aliases.\n const data = getIconData(set, name);\n if (!data) {\n missing.push(`${prefix}:${name}`);\n continue;\n }\n const built = iconToSVG(data, { height: 'none' });\n // MANDATORY. Two icons carrying the same internal gradient/clip id would\n // otherwise collide once concatenated into one document, and the second\n // silently renders with the first's paint.\n const body = replaceIDs(built.body);\n const id = spriteId(`${prefix}:${name}`);\n rendered.set(`${prefix}:${name}`, { viewBox: built.attributes.viewBox, body });\n ids.push(id);\n symbols.push(`<symbol id=\"${id}\" viewBox=\"${built.attributes.viewBox}\">${body}</symbol>`);\n }\n }\n\n for (const [alias, target] of Object.entries(o.aliases ?? {})) {\n const hit = rendered.get(target);\n if (!hit) {\n missing.push(`${target} (aliased as ${alias})`);\n continue;\n }\n // The body is DUPLICATED rather than nested as <use href=\"#target\"> inside\n // the symbol. Nested-use is legal but unreliable precisely under an\n // external-file <use>, which is exactly how this sprite is consumed; a\n // handful of duplicated paths in a ~40 KB file is the cheaper trade.\n ids.push(alias);\n symbols.push(`<symbol id=\"${alias}\" viewBox=\"${hit.viewBox}\">${hit.body}</symbol>`);\n }\n\n const svg =\n `<svg xmlns=\"http://www.w3.org/2000/svg\" style=\"display:none\" aria-hidden=\"true\">` +\n symbols.join('') +\n `</svg>\\n`;\n\n return { svg, ids, missing };\n}\n\n/**\n * One icon's renderable parts, for inlining into markup.\n *\n * Exists because `<Icon />` cannot go through astro-icon: its `./components`\n * entry is a TypeScript file that Vite must transform, so it can only be\n * reached by a statically-analysable import — and a static import is exactly\n * what made the optional peer mandatory for anyone rendering Popover, Details\n * or Drawer. Reading the collection directly sidesteps the peer entirely and\n * shares this file's loader with the sprite, so both paths draw the same glyph.\n */\nexport async function loadIconSvg(\n qualified: string,\n opts?: { resolveFrom?: string; loadSet?: (prefix: string) => Promise<IconifyJSON | null> },\n): Promise<{ viewBox: string; body: string } | null> {\n const i = qualified.indexOf(':');\n if (i <= 0) return null;\n const prefix = qualified.slice(0, i);\n const name = qualified.slice(i + 1);\n const from = opts?.resolveFrom ?? process.cwd();\n const load = opts?.loadSet ?? ((p: string) => loadCollection(p, from));\n const set = await load(prefix);\n if (!set) return null;\n const data = getIconData(set, name);\n if (!data) return null;\n const built = iconToSVG(data, { height: 'none' });\n // Same id-collision guard as the sprite: several inlined icons share one\n // document, so an un-rewritten gradient id would cross-render.\n return { viewBox: built.attributes.viewBox, body: replaceIDs(built.body) };\n}\n","/**\n * Pure, parameterized port of the Vitops design-system generator.\n *\n * `generate({ input, format, outDir })` reads a consumer's `design-system.json`,\n * validates it, and emits consumer-ready output for the chosen format into\n * `outDir`. Unlike the original CWD-bound script it mutates no shared state: every\n * generated token layer is built in memory and either bundled (css/bricks) or\n * inlined (tailwind) before writing.\n *\n * Framework-static assets (the hand-written CSS partials, the Bricks PHP + loader,\n * and the pre-built JS bundles) live under `assets/` in this package and are read /\n * copied from there — they are the same for every consumer.\n */\nimport { readFileSync, writeFileSync, mkdirSync, cpSync, existsSync, readdirSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createHash } from 'node:crypto';\nimport { transform } from 'lightningcss';\nimport { validate, type DesignSystem } from './schema.ts';\nimport { generateDocs } from './docs.ts';\nimport { emitDesignMd } from './design-md.ts';\nimport { generateLegal } from './legal/index.ts';\nimport { buildIconSprite } from './icons-sprite.ts';\nimport { resolveInput, resolveConfig, type Config } from './config.ts';\nimport { generateIconInclude, resolveIcon } from '@getvitops/utils';\nimport {\n BASE_HOOK,\n DARK_SEL,\n SYSTEM_DARK_SEL,\n TW_CLASH,\n type RoleSpec,\n roleHue,\n roleKind,\n} from './shared.ts';\nimport {\n checkContrast,\n expandPalette,\n functionalRole,\n ladderWarnings,\n monotonicityErrors,\n NUMERIC_STEPS,\n tokenClass,\n tokenVar,\n type ExpandedHue,\n type FunctionalRole,\n} from './tokens.ts';\n\nexport type Format = 'bricks' | 'css' | 'tailwind' | 'design';\n\n/**\n * Formats that emit a stylesheet. `design` is the odd one out — it emits a\n * single `DESIGN.md` brief and no CSS at all — so anything that expects to\n * import the generator's output (the Vite plugin's injected stylesheet, the\n * Astro integration) types against this narrower set.\n */\nexport type StylesheetFormat = Exclude<Format, 'design'>;\n\nexport interface GenerateOptions {\n /**\n * The config to build from — a path, or an already-parsed object.\n *\n * **Either kind is accepted.** A bare `design-system.json`, or the larger\n * `Config` that embeds one (commonly `company.json` / `site.json`), in\n * which case the design system is `designSystem.themes[theme]` with its\n * `extends` chain resolved. The two are told apart by shape, not by filename —\n * see `isConfig`.\n *\n * Passing a site config here also supplies `site`, so the site-level facts\n * generation depends on (`designSystem.defaultColorScheme`, the legal\n * documents, the icon sprite) don't need the same path declared twice. Each of\n * those is still gated on a field in that config, so nothing new appears\n * unless the config asks for it.\n */\n input: string | DesignSystem | Config;\n /** Output target. Default: 'bricks'. */\n format?: Format;\n /** Directory to write outputs into. Default: 'dist'. */\n outDir?: string;\n /** Override the framework asset root (advanced/testing). */\n assetsDir?: string;\n /**\n * Which `designSystem.themes` entry to build. Default: the config's\n * `defaultTheme`, else `default`. An error on a bare `design-system.json`,\n * which holds one design system and no themes map.\n */\n theme?: string;\n /**\n * Environment whose A/B variant applies to the site config, wherever it came\n * from (`input` or `site`). Default: `'production'`.\n */\n siteEnv?: string;\n /**\n * The site config, when it is a *different* file from `input` — enabling\n * legal-document output into `<outDir>/legal/*.html` and supplying\n * `designSystem.defaultColorScheme`.\n *\n * Redundant when `input` is already a site config; set both and this one wins.\n */\n site?: string | Config;\n /**\n * Emit the `prefers-color-scheme: dark` block (see `BuildOptions`).\n *\n * Normally this comes from the site config's `designSystem.defaultColorScheme: \"system\"`, which\n * is where the fact belongs. This is the escape hatch for consumers with a\n * `design-system.json` and no site config at all: requiring a whole\n * `Config` — which must carry a full `designSystem` — to set one boolean\n * would be out of proportion. Set explicitly, it wins over the site config.\n */\n systemColorScheme?: boolean;\n}\n\nexport interface GenerateResult {\n format: Format;\n outDir: string;\n written: string[];\n}\n\nconst HERE = dirname(fileURLToPath(import.meta.url));\nconst DEFAULT_ASSETS = join(HERE, '..', 'assets');\n\n// ── colour machinery ─────────────────────────────────────────────────────────\n// Every hue is an 11-step numeric OKLCH scale on a shared lightness ladder (see\n// tokens.ts); every role resolves to `--color-<target>-<role>[-<variant>]`.\n// Dark mode re-points which step each token reads; the solid family is stable.\nconst UTILITY_PROPS: Record<string, string> = {\n bg: 'background-color',\n text: 'color',\n icon: 'color',\n border: 'border-color',\n outline: 'outline-color',\n fill: 'fill',\n stroke: 'stroke',\n};\n\n/**\n * Which token target a utility family draws from. Four families have tokens of\n * their own; the other three are aliases, because an SVG fill wants the icon\n * tier (3:1, may run vivid) and an outline wants the border tier — minting\n * separate tokens for them would be three more things to keep in contrast.\n */\nconst UTILITY_SOURCE: Record<string, string> = {\n bg: 'bg',\n text: 'text',\n icon: 'icon',\n border: 'border',\n outline: 'border',\n fill: 'icon',\n stroke: 'icon',\n};\n\n/** The target segment of a token key (`bg-solid-bold` → `bg`). */\nconst targetOf = (key: string): string => {\n const i = key.indexOf('-');\n return i === -1 ? key : key.slice(0, i);\n};\n\nexport interface ColorUtility {\n /** Class name, without the leading dot. */\n cls: string;\n /** CSS property the class sets. */\n prop: string;\n /** `var(--…)` reference the class resolves to. */\n value: string;\n}\n\n/**\n * The framework's container breakpoints. `sm-`/`md-`/`lg-`/`xl-` prefixes in the\n * css/bricks formats; `@sm:`/`@md:`/… in tailwind, where they are registered as\n * `--container-*` in `@theme` and Tailwind expands the variants itself.\n */\nexport const BREAKPOINTS: readonly (readonly [string, string])[] = [\n ['sm', '30rem'],\n ['md', '48rem'],\n ['lg', '64rem'],\n ['xl', '80rem'],\n] as const;\n\n/**\n * Gap utilities over the space scale, emitted from one list into all three\n * formats — same arrangement as `roleColorUtilities`, for the same reason.\n *\n * These did not exist. `vitops docs css` advertised a `g` class that was never\n * emitted, so the honest answer for a css/bricks consumer was an inline\n * `style=\"gap: …\"`, which is what this repo's own `index.html` does throughout.\n * Tailwind does not fill the hole either: the fluid space steps are deliberately\n * kept OUT of Tailwind's `--spacing-*` namespace (named keys there shadow the\n * size scales — `max-w-7xl` would resolve to `var(--spacing-7xl)`), so `gap-md`\n * is not something Tailwind can derive on its own. Measured against\n * tailwindcss@4.3.3: an explicit `@utility gap-md` is honoured, coexists with\n * the built-in numeric `gap-4`, and picks up variants (`@md:gap-md`).\n *\n * The whole matrix is emitted rather than a useful-looking subset: an undefined\n * step produces no rule and no error in either format, so a missing\n * `md-gap-x-2xl` would be indistinguishable from a working one.\n */\nexport function gapUtilities(steps: { name: string }[]): ColorUtility[] {\n const FAMILIES: [string, string][] = [\n ['gap', 'gap'],\n ['gap-x', 'column-gap'],\n ['gap-y', 'row-gap'],\n ];\n return steps.flatMap(({ name }) =>\n FAMILIES.map(([prefix, prop]) => ({\n cls: `${prefix}-${name}`,\n prop,\n value: `var(--space-${name})`,\n })),\n );\n}\n\n/**\n * Every role colour utility, each class name emitted EXACTLY once.\n *\n * There is now a single axis. The target lives *inside* the token name, so\n * `bg-danger-muted` and `text-danger-muted` are different tokens and the\n * collision the old plane/stop precedence rule existed to arbitrate cannot\n * arise. Both the css/bricks and tailwind paths render from this one list, which\n * is what keeps the three formats in step; `format-parity.test.ts` holds them\n * there.\n *\n * The class name IS the token name minus `--color-`, so there is no separate\n * naming rule to drift — see `tokenClass` in tokens.ts.\n */\nexport function roleColorUtilities(\n roles: readonly FunctionalRole[],\n utilities: readonly string[],\n): ColorUtility[] {\n const out: ColorUtility[] = [];\n for (const fr of roles) {\n for (const fam of utilities) {\n const source = UTILITY_SOURCE[fam];\n if (source == null) continue;\n for (const key of Object.keys(fr.light)) {\n if (targetOf(key) !== source) continue;\n const canonical = tokenClass(fr.role, key);\n // Alias families keep the token but rename the leading segment:\n // `border-danger-bold` → `outline-danger-bold`.\n const cls = fam === source ? canonical : fam + canonical.slice(source.length);\n out.push({\n cls,\n prop: UTILITY_PROPS[fam] as string,\n value: `var(${tokenVar(fr.role, key)})`,\n });\n }\n }\n }\n return out;\n}\n\n/** Render the shared set as plain rules (css/bricks formats). */\nconst colorUtilityRules = (u: ColorUtility[]): string =>\n u.map(({ cls, prop, value }) => `.${cls} { ${prop}: ${value}; }`).join('\\n');\n\nconst decls = (obj: Record<string, string>, indent = ' ') =>\n Object.entries(obj)\n .map(([k, v]) => `${indent}${k}: ${v};`)\n .join('\\n');\n\n// ── fluid modular scale ───────────────────────────────────────────────────────\ninterface ScaleConfig {\n base: string;\n ratio: number;\n steps?: number;\n names?: string[];\n baseStep?: number;\n baseline?: string;\n fluid?: { minVw: string; maxVw: string; minRatio: number };\n}\ninterface ScaleStep {\n name: string;\n value: string;\n max: string;\n offset: number;\n}\nconst round = (n: number) => Number(n.toFixed(4)).toString();\nconst rem = (v: string) => parseFloat(v);\nconst buildScale = (s: ScaleConfig): ScaleStep[] => {\n const names = s.names ?? Array.from({ length: s.steps ?? 0 }, (_, i) => String(i + 1));\n const base = rem(s.base);\n const baseStep = s.baseStep ?? Math.ceil(names.length / 2);\n const baselineIdx = s.baseline ? names.indexOf(s.baseline) : baseStep - 1;\n return names.map((name, i) => {\n const k = i - (baseStep - 1);\n const vMax = base * Math.pow(s.ratio, k);\n const max = `${round(vMax)}rem`;\n let value = max;\n if (s.fluid) {\n const { minVw, maxVw, minRatio } = s.fluid;\n const vMin = base * Math.pow(minRatio, k);\n const lo = Math.min(vMin, vMax);\n const hi = Math.max(vMin, vMax);\n if (lo !== hi) {\n const slope = (vMax - vMin) / (rem(maxVw) - rem(minVw));\n const intercept = vMin - slope * rem(minVw);\n const sign = slope < 0 ? '-' : '+';\n const pref = `calc(${round(intercept)}rem ${sign} ${round(Math.abs(slope * 100))}vw)`;\n value = `clamp(${round(lo)}rem, ${pref}, ${round(hi)}rem)`;\n }\n }\n return { name, value, max, offset: i - baselineIdx };\n });\n};\n\n// ── typography ─────────────────────────────────────────────────────────────────\ninterface TypographyRole {\n family?: string;\n [key: string]: string | number | undefined;\n}\nconst TYPO_KEYMAP: Record<string, [string, string]> = {\n family: ['font-family', 'ff'],\n size: ['font-size', 'fs'],\n weight: ['font-weight', 'fw'],\n style: ['font-style', 'fst'],\n 'line-height': ['line-height', 'lh'],\n tracking: ['letter-spacing', 'ls'],\n 'text-decoration': ['text-decoration', 'td'],\n 'text-transform': ['text-transform', 'tt'],\n 'text-wrap': ['text-wrap', 'tw'],\n color: ['color', 'color'],\n};\n/**\n * Wrong spellings worth naming explicitly, because each is a plausible reading of\n * the key it isn't. `transform`/`decoration` were documented in the schema for a\n * while and shipped title-case navigation to production; `letter-spacing` and\n * `font-*` are the natural guesses for keys we chose to shorten.\n */\nconst ALSO_MEANT: Record<string, string> = {\n transform: 'text-transform',\n decoration: 'text-decoration',\n 'letter-spacing': 'tracking',\n wrap: 'text-wrap',\n 'font-family': 'family',\n 'font-size': 'size',\n 'font-weight': 'weight',\n 'font-style': 'style',\n lineHeight: 'line-height',\n};\nconst TYPO_IDENTITY: Record<string, string> = {\n 'font-style': 'normal',\n 'letter-spacing': 'normal',\n 'text-decoration': 'none',\n 'text-transform': 'none',\n 'text-wrap': 'wrap',\n};\n\n// ── animation state defaults ─────────────────────────────────────────────────\nconst STATE_DEFAULT: Record<string, string> = {\n opacity: '1',\n 'translate-x': '0',\n 'translate-y': '0',\n 'scale-x': '1',\n 'scale-y': '1',\n rotate: '0deg',\n blur: '0px',\n shadow: '0 0 0 transparent',\n brightness: '1',\n grayscale: '0',\n contrast: '1',\n saturate: '1',\n sepia: '0',\n 'hue-rotate': '0deg',\n clip: 'none',\n // The layout stage. `.transition` only declares `height` inside\n // `@supports (interpolate-size: allow-keywords)`, since `0 → auto` is not\n // interpolable without it — but the default belongs here either way, so the\n // flip resolves to the element's natural height rather than to nothing.\n height: 'auto',\n};\n\ninterface Pattern {\n group?: string;\n overrides?: Record<string, string>;\n element?: string;\n class?: string;\n fill?: boolean;\n default_role?: string;\n base?: Record<string, string>;\n states?: Record<string, Record<string, unknown>>;\n roles?: string[];\n}\n\nconst id = (key: string) => createHash('sha256').update(key).digest('hex').slice(0, 6);\n\n/**\n * The in-memory output of building a design system. String fields are CSS/JSON\n * ready to write; the generated CSS partials feed the css/bricks bundler.\n */\ninterface Built {\n generated: Record<string, string>; // filename (under generated/) -> css\n bricksColorsNamed: string;\n bricksColorsSemantic: string;\n bricksVariables: string;\n tokensJson: string;\n designManifest: string;\n tailwind: string;\n designMd: string;\n // captured for the tailwind bundler\n twTypeTokensCss: string;\n twPatternTokensCss: string;\n patternsCss: string;\n}\n\n// Exported for tests only — deliberately NOT re-exported from index.ts, so the\n// package's public API stays `generate` / `generateDocs` / `validate`.\nexport interface BuildOptions {\n /**\n * Also flip to dark when the OS asks and no explicit choice has been made —\n * `@media (prefers-color-scheme: dark)`.\n *\n * A build flag rather than a `DesignSystem` field: it describes what a *site*\n * wants, not what the system defines, so it comes from the site config's\n * `designSystem.defaultColorScheme` and `generate()` stays keyed to a `DesignSystem`.\n * Off by default, because turning it on flips a site dark for dark-OS users.\n */\n systemColorScheme?: boolean;\n}\n\nexport function build(\n ds: DesignSystem,\n format: Format,\n assetsDir: string,\n buildOpts: BuildOptions = {},\n): Built {\n const BRICKS = format === 'bricks';\n // Every hue expands to its 11-step numeric OKLCH scale; every role resolves\n // to functional tokens over its hue. Dark mode is the automatic flip.\n const expandedPalette = expandPalette(ds.colors.palette as Record<string, unknown>);\n const roleMap = ds.colors.roles as Record<string, RoleSpec>;\n const scaleRoles: FunctionalRole[] = [];\n for (const [role, spec] of Object.entries(roleMap)) {\n const hueName = roleHue(spec);\n const hue = expandedPalette[hueName];\n if (hue == null) throw new Error(`role \"${role}\" references unknown palette hue \"${hueName}\"`);\n scaleRoles.push(functionalRole(role, hueName, hue, roleKind(spec)));\n }\n // Found by name AND kind. Only a surface-kind role has a bare `bg` token, and\n // `--surface-glass` / `.glass` / `--overlay` are written against\n // `--color-bg-surface` — so matching on the name alone emitted three\n // declarations pointing at a token that does not exist whenever `surface` was\n // authored as a bare hue string (the shorthand for `chromatic`). Skipping them\n // is the honest outcome: the config did not ask for a surface.\n const surfaceRole = scaleRoles.find((r) => r.role === 'surface' && 'bg' in r.light);\n if (!surfaceRole && roleMap['surface'] != null)\n console.warn(\n `[vitops] colors.roles.surface is chromatic, so no --color-bg-surface exists — ` +\n `skipping --surface-glass, --overlay and .glass. Declare it as ` +\n `{ \"hue\": \"…\", \"kind\": \"surface\" } if you meant a surface role.`,\n );\n // The focus ring is role-less by default, so it needs one nominated source.\n // `ui-primary` is the interaction hue — a ring in the brand colour would drift\n // away from the buttons and links it appears on.\n const focusRole = scaleRoles.find((r) => r.role === 'ui-primary') ?? scaleRoles[0];\n\n // A pinned brand colour that sits off the shared lightness ladder is legal —\n // the author asked for that exact colour — but past ~0.03 L the hue reads\n // visibly heavier or lighter than its siblings at that step, so say so.\n for (const w of ladderWarnings(expandedPalette)) console.warn(`[vitops] ${w}`);\n\n // A pinned colour far enough off the ladder can leave the ramp non-monotonic —\n // some step lighter than the one above it. That is an error, not a warning:\n // `snap`, the mode-stable solid family and the dark tables all assume the\n // order, so an inverted ramp runs hover states backwards. Same reasoning as the\n // contrast contract below — this is exactly the drift the fixed ladder exists\n // to eliminate, and it is always author-caused, so it is always actionable.\n {\n const errors = monotonicityErrors(expandedPalette);\n if (errors.length) throw new Error(errors.join('\\n'));\n }\n\n // The contrast contract runs at BUILD time, not only in tests: a consumer\n // editing their own palette has no test suite, and an illegible pairing that\n // ships is far more expensive than a build that stops. Chromatic roles are\n // checked against the surface planes they actually sit on, since coloured text\n // appears over the page far more often than over its own tint.\n {\n const numericOf = (hueName: string) => expandedPalette[hueName]?.numeric ?? {};\n const resolve = (val: string): string => {\n const m = /^var\\(--color-([a-z0-9-]+)-(\\d+)\\)$/.exec(val);\n return m ? (numericOf(m[1] as string)[m[2] as never] ?? val) : val;\n };\n const planeKeys = ['bg', 'bg-muted', 'bg-x-muted'] as const;\n const surfaceBg = surfaceRole\n ? {\n light: planeKeys.flatMap((k) =>\n surfaceRole.light[k] ? [resolve(surfaceRole.light[k] as string)] : [],\n ),\n dark: planeKeys.flatMap((k) =>\n surfaceRole.dark[k] ? [resolve(surfaceRole.dark[k] as string)] : [],\n ),\n }\n : undefined;\n const failures = scaleRoles.flatMap((fr) => checkContrast(fr, numericOf, surfaceBg));\n if (failures.length)\n throw new Error(\n `colour contrast contract failed (${failures.length} pairing${\n failures.length === 1 ? '' : 's'\n }):\\n ${failures.join('\\n ')}`,\n );\n }\n const patterns = ds.patterns;\n const shadows = ds.shadows;\n const typography = ds.typography;\n const UTILITIES = (ds.colors.utilities ?? ['bg', 'text', 'icon', 'border']).filter(\n (u) => u in UTILITY_PROPS,\n );\n\n const generated: Record<string, string> = {};\n\n /**\n * The two background utilities that aren't derived from the palette, so\n * neither the generated scale nor Bricks' own palette import produces them.\n *\n * They exist to undo a pattern's fill — `class=\"card bg-transparent\"` for a\n * flat, border-only card. Tailwind ships both as built-ins, so the tailwind\n * format deliberately emits neither and defers, exactly as it does for the\n * `TW_CLASH` names.\n */\n const NON_PALETTE_BG =\n `/* Undo a pattern's fill (Tailwind provides these natively in that format). */\\n` +\n `.bg-transparent { background-color: transparent; }\\n` +\n `.bg-inherit { background-color: inherit; }\\n`;\n\n // ── color.css ──────────────────────────────────────────────────────────────\n if (BRICKS) {\n generated['color.css'] =\n '/* Colours provided by Bricks (palette import generates tokens + utilities). */\\n' +\n NON_PALETTE_BG;\n } else {\n let css = `/* GENERATED from design-system.json — do not edit by hand. */\\n:root {\\n`;\n css += ` color-scheme: light;\\n`;\n css += ` /* Hue scales (numeric steps, 50 = tinted near-white … 950 = tinted near-black) */\\n`;\n for (const [name, hue] of Object.entries(expandedPalette))\n for (const [n, hex] of Object.entries(hue.numeric))\n css += ` --color-${name}-${n}: ${hex};\\n`;\n css += `\\n /* Role tokens (the public API) */\\n`;\n for (const fr of scaleRoles)\n for (const [t, val] of Object.entries(fr.light))\n css += ` ${tokenVar(fr.role, t)}: ${val};\\n`;\n if (focusRole) {\n css += `\\n /* Focus ring — a boundary, so it takes the solid tone, not a border tint. */\\n`;\n css += ` --color-border-focus: ${focusRole.light['bg-solid']};\\n`;\n }\n if (surfaceRole) {\n css += `\\n /* Translucent surface + scrim */\\n`;\n css += ` --surface-glass: color-mix(in oklch, var(--color-bg-surface) 72%, transparent);\\n`;\n css += ` --overlay: color-mix(in oklch, var(--color-${surfaceRole.hue}-950) 45%, transparent);\\n`;\n }\n css += `}\\n\\n`;\n // Dark appearance: the automatic functional flip (solid stays mode-stable).\n {\n let fb = '';\n for (const fr of scaleRoles)\n for (const [t, val] of Object.entries(fr.dark))\n if (fr.light[t] !== val) fb += ` ${tokenVar(fr.role, t)}: ${val};\\n`;\n if (surfaceRole)\n fb += ` --overlay: color-mix(in oklch, var(--color-${surfaceRole.hue}-950) 60%, transparent);\\n`;\n if (fb) {\n css += `/* Functional role tokens (dark) */\\n`;\n css += `${DARK_SEL} {\\n color-scheme: dark;\\n${fb}}\\n\\n`;\n // The same delta again, for \"no explicit choice + a dark OS\". Opt-in,\n // because switching it on flips a site dark for dark-OS users.\n //\n // This is what makes <wc-color-scheme-toggle>'s \"System\" position mean\n // anything: System *removes* data-theme, so with only the block above it\n // fell through to light on every machine. It also gives a no-JS page the\n // OS appearance, which the toggle alone never could.\n //\n // Yes, `fb` is emitted twice. It is a delta — only the tokens whose dark\n // value differs, and the raw hue ramps never re-point — and two identical\n // runs of text compress to almost nothing, so the cost is far below what\n // a second full colour layer would suggest.\n if (buildOpts.systemColorScheme)\n css +=\n `/* Functional role tokens (dark) — OS preference, no explicit choice */\\n` +\n `@media (prefers-color-scheme: dark) {\\n` +\n ` ${SYSTEM_DARK_SEL} {\\n color-scheme: dark;\\n${fb.replace(/^ {2}/gm, ' ')} }\\n}\\n\\n`;\n }\n }\n // Raw hue steps, then the role set. One axis means every class here is\n // emitted exactly once by construction — no precedence rule, and no reliance\n // on the minifier dropping a shadowed rule.\n css += `/* Colour utilities — ${UTILITIES.join(', ')} */\\n`;\n for (const [name, hue] of Object.entries(expandedPalette))\n for (const n of Object.keys(hue.numeric))\n css +=\n UTILITIES.map(\n (cls) => `.${cls}-${name}-${n} { ${UTILITY_PROPS[cls]}: var(--color-${name}-${n}); }`,\n ).join('\\n') + '\\n';\n css += `\\n/* Role utilities (the public API) */\\n`;\n css += `${colorUtilityRules(roleColorUtilities(scaleRoles, UTILITIES))}\\n`;\n if (surfaceRole)\n css += `.glass { background-color: var(--surface-glass); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }\\n`;\n css += NON_PALETTE_BG;\n generated['color.css'] = css;\n }\n\n // ── shadows.css ──────────────────────────────────────────────────────────────\n {\n const entries = Object.entries(shadows ?? {});\n let sh = `/* GENERATED drop-shadow tokens + utilities — do not edit by hand. */\\n`;\n if (entries.length) {\n sh += `:root {\\n`;\n for (const [name, value] of entries) sh += ` --shadow-${name}: ${value};\\n`;\n sh += `}\\n\\n`;\n for (const [name] of entries)\n sh += `.drop-shadow-${name} { filter: drop-shadow(var(--shadow-${name})); }\\n`;\n }\n generated['shadows.css'] = sh;\n }\n\n // ── scales ───────────────────────────────────────────────────────────────────\n const typeSteps = ds.typeScale ? buildScale(ds.typeScale as ScaleConfig) : [];\n const spaceSteps = ds.spaceScale ? buildScale(ds.spaceScale as ScaleConfig) : [];\n const textMax: Record<string, string> = Object.fromEntries(\n typeSteps.map((s) => [`text-${s.name}`, s.max]),\n );\n\n const typographyFamilies = typography?.families ?? {};\n\n // The recognised key set is closed (TYPO_KEYMAP), and an unrecognised key is\n // dropped rather than emitted — so a typo, or one of the plausible-but-wrong\n // short forms (`transform` for `text-transform`, `decoration` for\n // `text-decoration`), produces a role that looks configured and renders\n // unstyled. That is invisible in the output and survives review, so say it here\n // rather than leaving it to be noticed on a live page.\n {\n const known = new Set(Object.keys(TYPO_KEYMAP));\n for (const [role, spec] of Object.entries(typography?.roles ?? {}))\n for (const key of Object.keys(spec as TypographyRole)) {\n if (known.has(key)) continue;\n const near = ALSO_MEANT[key];\n console.warn(\n `[vitops] typography.roles.${role}: unknown key \"${key}\" — ignored` +\n (near ? `. Did you mean \"${near}\"?` : `. Recognised: ${[...known].join(', ')}.`),\n );\n }\n }\n const withScaleFallback = (v: string) =>\n v.replace(/var\\(\\s*(--text-[\\w-]+)\\s*\\)/g, (m, name) =>\n textMax[name.slice(2)] ? `var(${name}, ${textMax[name.slice(2)]})` : m,\n );\n const roleDecls = (role: string, spec: TypographyRole): Record<string, string> => {\n const out: Record<string, string> = {};\n for (const [key, [prop, sfx]] of Object.entries(TYPO_KEYMAP)) {\n const identity = TYPO_IDENTITY[prop];\n if (spec[key] == null && identity == null) continue;\n const raw =\n spec[key] == null\n ? (identity as string)\n : key === 'family'\n ? (typographyFamilies[spec.family as string] ?? String(spec.family))\n : key === 'size'\n ? withScaleFallback(String(spec[key]))\n : String(spec[key]);\n out[prop] = `var(--${role}-${sfx}, ${raw})`;\n }\n return out;\n };\n\n // ── type-tokens.css ──────────────────────────────────────────────────────────\n let twTypeTokensCss = '';\n if (BRICKS) {\n generated['type-tokens.css'] =\n '/* Fonts + type/space scales provided by Bricks (Font + Variables managers). */\\n';\n } else {\n const root: Record<string, string> = {};\n for (const [name, stack] of Object.entries(ds.fonts ?? {})) root[`--font-${name}`] = stack;\n for (const s of typeSteps) root[`--text-${s.name}`] = s.value;\n for (const s of spaceSteps) root[`--space-${s.name}`] = s.value;\n const css =\n `/* GENERATED font families + fluid type/space scales — do not edit by hand.\\n` +\n ` --font-* are STACKS ONLY; no @font-face is emitted here. Load webfonts with\\n` +\n ` Astro's fonts: config and point the token at the family's cssVariable. */\\n` +\n `:root {\\n${decls(root)}\\n}\\n`;\n twTypeTokensCss = css;\n generated['type-tokens.css'] = css;\n }\n\n // ── spacing.css (gap utilities) ──────────────────────────────────────────────\n // Emitted for css AND bricks: the `--space-*` tokens come from this file in the\n // css format and from Bricks' Variables import in the bricks format, but the\n // class names are ours either way — Bricks generates utility classes only for\n // the colour palette.\n {\n const gaps = gapUtilities(spaceSteps);\n let sp = `/* GENERATED gap utilities — do not edit by hand. */\\n`;\n if (gaps.length) {\n for (const { cls, prop, value } of gaps) sp += `.${cls} { ${prop}: ${value}; }\\n`;\n for (const [bp, width] of BREAKPOINTS) {\n sp += `\\n@container (min-width: ${width}) {\\n`;\n for (const { cls, prop, value } of gaps) sp += ` .${bp}-${cls} { ${prop}: ${value}; }\\n`;\n sp += `}\\n`;\n }\n }\n generated['spacing.css'] = sp;\n }\n\n // ── tokens.css (pattern token cascade) ───────────────────────────────────────\n let twPatternTokensCss = '';\n {\n const tDefaults = patterns?.defaults ?? {};\n const tRadii = patterns?.radii ?? {};\n const tGroups = patterns?.groups ?? {};\n const tZ = patterns?.z ?? {};\n const tItems = (patterns?.items ?? {}) as Record<string, Pattern>;\n const root: Record<string, string> = {};\n for (const [prop, val] of Object.entries(tDefaults)) root[`--${prop}-default`] = val;\n if (!BRICKS) for (const [name, val] of Object.entries(tRadii)) root[`--br-${name}`] = val;\n for (const [group, props] of Object.entries(tGroups))\n for (const [prop, val] of Object.entries(props)) root[`--${prop}-${group}`] = val;\n for (const [name, n] of Object.entries(tZ)) root[`--z-tier-${name}`] = String(n);\n const aliases: Record<string, string> = {};\n for (const [name, p] of Object.entries(tItems)) {\n if (!p.group) continue;\n for (const prop of Object.keys(tGroups[p.group] ?? {}))\n aliases[`--${prop}-${name}-group`] = `var(--${prop}-${p.group})`;\n for (const [prop, val] of Object.entries(p.overrides ?? {}))\n aliases[`--${prop}-${name}-group`] = val;\n }\n let tok = `/* GENERATED pattern token cascade — do not edit by hand. */\\n:root {\\n`;\n tok += decls(root) + '\\n';\n if (Object.keys(aliases).length) tok += '\\n' + decls(aliases) + '\\n';\n tok += `}\\n`;\n twPatternTokensCss = tok;\n generated['tokens.css'] = tok;\n }\n\n // ── typography.css (.font-* roles) ───────────────────────────────────────────\n {\n const roles = (typography?.roles ?? {}) as Record<string, TypographyRole>;\n const headings = typography?.headings ?? {};\n let typo = `/* GENERATED typography roles — do not edit by hand. */\\n`;\n for (const [role, spec] of Object.entries(roles))\n typo += `.font-${role} {\\n${decls(roleDecls(role, spec))}\\n}\\n`;\n for (const [tag, role] of Object.entries(headings))\n if (roles[role]) typo += `${tag} {\\n${decls(roleDecls(role, roles[role]))}\\n}\\n`;\n generated['typography.css'] = typo;\n }\n\n // ── patterns.css (component interaction patterns) ────────────────────────────\n // `sel` is a *builder* taking the state's pseudo, not a finished selector, and\n // that indirection is load-bearing rather than stylistic: an element pattern\n // has to place the pseudo INSIDE its `:where()`, because `:where()` zeroes the\n // element but a pseudo appended outside it still counts. `:where(a, .link):hover`\n // is 0-1-0 — the same weight as `.cta-brand-primary` — so the link pattern's\n // hover colour tied with every `<a class=\"cta\">` and won on source order,\n // turning a filled CTA's text dark mid-hover. `:where(a:hover, .link:hover)` is\n // a true 0-0-0 and loses to any explicit class, which is what the base rule\n // already promised. It returns a list because an element pattern emits both\n // `:where(el, .cls).role` and `.cls-role`.\n const stateRules = (\n sel: (pseudo: string) => string[],\n role: string | null,\n states: Record<string, Record<string, unknown>>,\n colorProp: 'background-color' | 'color' = 'background-color',\n ) => {\n let out = '';\n for (const [state, spec] of Object.entries(states)) {\n const body: string[] = [];\n // `step` intensifies the pattern's colour: fills swap solid → solid-bold;\n // text swaps the bold emphasis stop → x-bold.\n if (typeof spec.step === 'number' && role) {\n const stateVar =\n colorProp === 'background-color'\n ? `var(--color-bg-${role}-${spec.step >= 1 ? 'solid-bold' : 'solid'})`\n : spec.step >= 1\n ? `var(--color-text-${role}-bold)`\n : `var(--color-text-${role})`;\n body.push(`${colorProp}: ${stateVar};`);\n }\n if (typeof spec.scale === 'number') body.push(`scale: ${spec.scale};`);\n if (typeof spec.lift === 'string') body.push(`translate: 0 calc(-1 * ${spec.lift});`);\n if (typeof spec.shadow === 'string' && shadows?.[spec.shadow])\n body.push(`filter: drop-shadow(var(--shadow-${spec.shadow}));`);\n else if (spec.shadow === true)\n body.push(`box-shadow: var(--lift-shadow, 0 8px 20px -6px rgb(0 0 0 / 0.25));`);\n if (spec.ring === true) {\n // A focus ring has to be *seen*, so it uses the solid tone rather than a\n // decorative border tint. `--color-border-focus` is the role-less\n // default, emitted once from ui-primary and contrast-checked as a\n // non-text boundary.\n const ringColor = role ? `var(--color-bg-${role}-solid)` : `var(--color-border-focus)`;\n body.push(`outline: none;`, `box-shadow: 0 0 0 3px ${ringColor};`);\n }\n if (spec.css && typeof spec.css === 'object')\n for (const [k, v] of Object.entries(spec.css as Record<string, string>))\n body.push(`${k}: ${v};`);\n if (!body.length) continue;\n const pseudo =\n state === 'hover'\n ? ':hover'\n : state === 'active'\n ? ':active'\n : state === 'focus-visible'\n ? ':focus-visible'\n : `:${state}`;\n const rule = `${sel(pseudo).join(',\\n')} {\\n ${body.join('\\n ')}\\n}\\n`;\n out += state === 'hover' ? `@media (hover: hover) {\\n${rule}}\\n` : rule;\n }\n return out;\n };\n\n let pat = `/* GENERATED component patterns — do not edit by hand. */\\n`;\n pat += `/* Interaction transitions for patterned elements (independent props compose). */\\n`;\n for (const [pname, p] of Object.entries((patterns?.items ?? {}) as Record<string, Pattern>)) {\n if (!p.base) continue;\n const states = p.states ?? {};\n // `class` defaults to the pattern key only for class-only patterns, so an\n // `element`-only entry never sprouts a surprise class.\n const cls = p.class ?? (p.element ? undefined : pname);\n // Element patterns style at zero specificity (`:where(…)`) so any explicit\n // class — a louder pattern, or a component's own BEM rule — wins without\n // !important. Class-only patterns stay unwrapped at 0-1-0, or they'd lose to\n // every utility. With both, the element and the class share one rule, which\n // is what lets `.btn` / `.link` be applied to any tag.\n //\n // `pseudo` goes inside the `:where()` so a state rule keeps that promise —\n // see the note on `stateRules`. `extra` (a role class) stays outside it,\n // since the variant is meant to carry a class's weight.\n const elementSel = (extra = '', pseudo = '') =>\n `:where(${[p.element, cls && `.${cls}`]\n .filter(Boolean)\n .map((s) => `${s}${pseudo}`)\n .join(', ')})${extra}`;\n const defaultSel = p.element ? elementSel() : `.${cls}`;\n const defaultSelFor = (pseudo: string) =>\n p.element ? [elementSel('', pseudo)] : [`.${cls}${pseudo}`];\n const defaultRole = p.default_role ?? null;\n const base = { ...p.base };\n // Explicit `fill` wins; otherwise infer, keeping the historical name-based\n // special cases so existing consumer configs don't shift behaviour.\n const fills =\n p.fill ??\n (pname === 'button' ||\n pname === 'badge' ||\n base['background-color'] != null ||\n base['background'] != null);\n const colorProp: 'background-color' | 'color' = fills ? 'background-color' : 'color';\n pat += `${defaultSel} {\\n`;\n const hasStates = Object.keys(states).length > 0;\n if (hasStates) {\n pat += ` transition-property: translate, scale, rotate, filter, box-shadow, background-color, color;\\n`;\n pat += ` transition-duration: var(--interact-duration, 200ms);\\n`;\n pat += ` transition-timing-function: var(--interact-easing, ease);\\n`;\n pat += ` translate: 0 0; scale: 1; rotate: 0deg;\\n`;\n }\n if (defaultRole && fills && base['background-color'] == null && base['background'] == null)\n base['background-color'] = `var(--color-bg-${defaultRole}-solid)`;\n const wrappedBase: Record<string, string> = {};\n for (const [prop, val] of Object.entries(base)) {\n const sfx = BASE_HOOK[prop];\n wrappedBase[prop] = sfx ? `var(--${sfx}-${pname}, ${val})` : String(val);\n }\n pat += decls(wrappedBase) + '\\n}\\n';\n pat += stateRules(defaultSelFor, defaultRole, states, colorProp);\n for (const role of p.roles ?? []) {\n // Element patterns take the role as a bare class (`<button class=\"danger\">`)\n // AND as the `<pattern>-<role>` form that class patterns use, so the same\n // variant reaches a non-element host (`<a class=\"btn btn-danger\">`). Both\n // land at 0-1-0 — the element half stays inside :where() so a role variant\n // can't outrank a plain class the way `button.danger` (0-1-1) used to.\n const variantSelsFor = (pseudo: string) =>\n p.element\n ? [elementSel(`.${role}`, pseudo), ...(cls ? [`.${cls}-${role}${pseudo}`] : [])]\n : [`.${cls}-${role}${pseudo}`];\n const variantSels = variantSelsFor('');\n // Fills sit on the role's solid and pair with the foreground computed\n // against it; text variants use the role's text token, which is the one\n // guaranteed legible over a surface in both appearances.\n const variantColorDecl = fills\n ? `background-color: var(--color-bg-${role}-solid); color: var(--color-text-on-${role})`\n : `color: var(--color-text-${role})`;\n pat += `${variantSels.join(',\\n')} { ${variantColorDecl}; }\\n`;\n pat += stateRules(variantSelsFor, role, states, colorProp);\n }\n pat += '\\n';\n }\n generated['patterns.css'] = pat;\n\n // ── animation-effects.css ────────────────────────────────────────────────────\n {\n const anim = ds.animations ?? {};\n const asStr = (v: string | number) => String(v);\n const block = (sel: string, d: Record<string, string>) => `.${sel} {\\n${decls(d)}\\n}\\n`;\n let out = `/* GENERATED animation effects + journeys — do not edit by hand. */\\n`;\n for (const [name, e] of Object.entries(anim.effects ?? {})) {\n const d: Record<string, string> = { '--_anim': e.kf };\n for (const [k, v] of Object.entries(e.css ?? {})) d[k] = asStr(v);\n for (const [k, v] of Object.entries(e.vars ?? {})) d[`--${k}`] = asStr(v);\n out += block(name, d);\n }\n const base = anim.journeys?.base ?? {};\n for (const parts of anim.journeys?.compose ?? []) {\n const d: Record<string, string> = {\n '--_anim': parts.map((p) => `${p}-journey`).join(', '),\n // A journey is entry → hold → exit (keyframes at 0%/100% hidden,\n // 25%–75% held), so it needs the long range that a one-shot entrance\n // doesn't. It starts on the same pivot as `.animate-view` — the\n // element's midpoint 15% into the viewport, which is `entry 50%` plus\n // 10vh (see the note on .animate-view in core's animation.css) — and\n // runs to the end of the exit phase, so the hold occupies the middle of\n // the crossing rather than the bottom edge of the screen.\n //\n // The END is spelled `exit 100%` rather than the equivalent bare `exit`,\n // because lightningcss misparses the shorthand: an omitted offset on the\n // END defaults to 0% there instead of the spec's 100%, so `entry exit`\n // bundled as `entry exit 0%` and every journey snapped back to its hidden\n // `from` state as the element reached the top of the viewport. Guarded by\n // animation-effects.test.ts, which asserts on the BUNDLED css.\n 'animation-range': 'entry calc(50% + 10vh) exit 100%',\n };\n for (const p of parts)\n for (const [k, v] of Object.entries(base[p] ?? {})) d[`--${k}`] = asStr(v);\n out += block(`${parts.join('-')}-journey`, d);\n }\n // Each state matches the element itself OR its direct parent, mirroring the\n // precedent animation.css already sets for the trigger driver\n // (`:is(.is-active, [data-active]) > .animate-trigger`). The parent form is\n // load-bearing, not a convenience: a `hover-reveal-*` element rests at\n // `clip-path: inset(0 100% 0 0)`, and clip-path clips HIT-TESTING as well as\n // painting — so with `:hover` alone the element has zero hittable area and\n // can never receive the hover that would reveal it. Same specificity (0,2,0)\n // as the self form, so nothing reorders.\n const STATES: [string, (s: string) => string][] = [\n ['hover', (s) => `.${s}:hover, :hover > .${s}`],\n ['focus', (s) => `.${s}:focus-visible, :focus-within > .${s}`],\n ['active', (s) => `.${s}.is-active, .${s}[data-active]`],\n // The top layer's own state. A popover/dialog rests CLOSED at the effect's\n // `from` values and flips to `to` when it opens — the same shape as hover,\n // so it costs one row here rather than a bespoke driver, and every effect\n // gains `open-<fx>` in all three formats for free. `:popover-open` covers\n // the Popover API; `[open]` covers `<dialog open>` (and `<details open>`,\n // which is a legitimate use of the same flip).\n //\n // The MECHANISM a top-layer element additionally needs — `display`/`overlay`\n // in transition-property with `allow-discrete`, plus the `@starting-style`\n // that makes the entry run at all — is not per-effect, so it lives once in\n // animation.css rather than being multiplied across every effect here.\n ['open', (s) => `.${s}:popover-open, .${s}[open]`],\n ];\n out += `\\n/* State-flip variants — compose with .transition (hover-/focus-/active-<fx>). */\\n`;\n // Every keyframe family gets state variants, `layout` included: `.transition`\n // covers `height` inside `@supports (interpolate-size: allow-keywords)`, and\n // the `layout` keyframe depends on exactly the same feature — so excluding\n // layout here bought no portability, it only made `hover-size-grow` a class\n // that resolved to nothing while the docs advertised it.\n for (const [name, e] of Object.entries(anim.effects ?? {})) {\n const props: Record<string, { from?: string; to?: string }> = {};\n for (const [k, v] of Object.entries(e.vars ?? {})) {\n const m = /^(.*)-(from|to)$/.exec(k);\n if (m) (props[m[1] as string] ??= {})[m[2] as 'from' | 'to'] = asStr(v);\n }\n // The effect's own `css` block travels with the variant too — `size-grow`\n // declares `overflow: clip`, without which a collapsed (0-height) box\n // spills its content instead of hiding it.\n const rest: Record<string, string> = {};\n for (const [k, v] of Object.entries(e.css ?? {})) rest[k] = asStr(v);\n for (const [p, ft] of Object.entries(props)) {\n if (ft.from != null && ft.from !== STATE_DEFAULT[p]) rest[`--${p}-from`] = ft.from;\n if (ft.to != null && ft.to !== STATE_DEFAULT[p]) rest[`--${p}-to`] = ft.to;\n }\n const flip: Record<string, string> = Object.fromEntries(\n Object.keys(props).map((p) => [`--t-${p}`, `var(--${p}-to, ${STATE_DEFAULT[p]})`]),\n );\n if (Object.keys(rest).length)\n out += `${STATES.map(([s]) => `.${s}-${name}`).join(', ')} {\\n${decls(rest)}\\n}\\n`;\n for (const [s, sel] of STATES) out += `${sel(`${s}-${name}`)} {\\n${decls(flip)}\\n}\\n`;\n }\n generated['animation-effects.css'] = out;\n }\n\n // ── Bricks palettes ──────────────────────────────────────────────────────────\n // Named = the hue scales (numeric steps); Semantic = the functional role\n // tokens with their automatic light/dark pairing.\n const namedColors: unknown[] = [];\n for (const [name, hue] of Object.entries(expandedPalette))\n for (const [n, hex] of Object.entries(hue.numeric)) {\n const token = `${name}-${n}`;\n namedColors.push({\n raw: `var(--color-${token})`,\n light: hex,\n id: id(`named:${token}`),\n utilityClasses: UTILITIES,\n });\n }\n const semanticColors: unknown[] = [];\n for (const fr of scaleRoles)\n for (const [t, light] of Object.entries(fr.light)) {\n const dark = fr.dark[t] as string;\n semanticColors.push({\n raw: `var(${tokenVar(fr.role, t)})`,\n light,\n darkModeEnabled: light !== dark,\n dark,\n id: id(`semantic:${fr.role}-${t}`),\n utilityClasses: UTILITIES,\n });\n }\n const bricksColorsNamed = JSON.stringify(\n { id: id('palette:named'), name: 'Named', colors: namedColors },\n null,\n 2,\n );\n const bricksColorsSemantic = JSON.stringify(\n { id: id('palette:semantic'), name: 'Semantic', colors: semanticColors },\n null,\n 2,\n );\n\n // ── Bricks Global Variables (fonts + scales) ─────────────────────────────────\n const bricksVariables = (() => {\n type BrxScale = { scale: number; scaleName: string };\n type BrxVar = { id: string; name: string; value: string; category?: string; scale?: BrxScale };\n type BrxCat = { id: string; name: string; scale: Record<string, unknown>; utilityClasses: [] };\n const scaleMeta = (scope: string, prefix: string, s: ScaleConfig, names: string[]) => {\n const px = Math.round(rem(s.base) * 16);\n const lo = s.fluid?.minRatio ?? s.ratio;\n return {\n scaleScope: scope,\n scaleType: 'tshirt',\n scaleNames: names,\n prefix,\n minFontSize: px,\n minScaleRatio: lo,\n minScaleRatioSelect: lo,\n maxFontSize: px,\n maxScaleRatio: s.ratio,\n maxScaleRatioSelect: s.ratio,\n baseline: s.baseline ?? names[Math.floor((names.length - 1) / 2)],\n };\n };\n const categories: BrxCat[] = [];\n const variables: BrxVar[] = [];\n const addScale = (\n label: string,\n scope: string,\n prefix: string,\n cfg: ScaleConfig | undefined,\n steps: ScaleStep[],\n ) => {\n if (!cfg || !steps.length) return;\n const names = steps.map((s) => s.name);\n const catId = id(`varcat:${scope}`);\n categories.push({\n id: catId,\n name: label,\n scale: scaleMeta(scope, prefix, cfg, names),\n utilityClasses: [],\n });\n for (const st of steps)\n variables.push({\n id: id(`var:${prefix}${st.name}`),\n name: `${prefix}${st.name}`,\n value: st.value,\n category: catId,\n scale: { scale: st.offset, scaleName: st.name },\n });\n };\n addScale('Typography', 'typography', 'text-', ds.typeScale as ScaleConfig, typeSteps);\n addScale('Spacing', 'spacing', 'space-', ds.spaceScale as ScaleConfig, spaceSteps);\n for (const [name, stack] of Object.entries(ds.fonts ?? {}))\n variables.push({ id: id(`var:font-${name}`), name: `font-${name}`, value: stack });\n for (const [name, val] of Object.entries(ds.patterns?.radii ?? {}))\n variables.push({ id: id(`var:br-${name}`), name: `br-${name}`, value: val });\n return JSON.stringify({ variables, categories }, null, 2);\n })();\n\n // ── tokens.json (trimmed token export for programmatic consumers) ────────────\n const numericPalette = Object.fromEntries(\n Object.entries(expandedPalette).map(([k, v]) => [k, v.numeric]),\n );\n const tokensJson = JSON.stringify(\n {\n colors: {\n palette: numericPalette,\n roles: roleMap,\n functional: Object.fromEntries(\n scaleRoles.map((fr) => [fr.role, { light: fr.light, dark: fr.dark }]),\n ),\n },\n fonts: ds.fonts ?? {},\n text: Object.fromEntries(typeSteps.map((s) => [s.name, s.value])),\n spacing: Object.fromEntries(spaceSteps.map((s) => [s.name, s.value])),\n shadows: shadows ?? {},\n radii: ds.patterns?.radii ?? {},\n },\n null,\n 2,\n );\n\n // ── design-manifest.json (live-editor manifest; css format) ──────────────────\n const designManifest = (() => {\n const reverseIndex: Record<string, string> = {};\n // A numeric step maps back to that step's `anchors` entry, NOT to the hue's\n // `seed`: the seed regenerates the whole ramp (and every step would collapse\n // to one path, so editing two steps of a hue would silently keep only one),\n // whereas `anchors.<step>` is precisely the per-step override (see schema.ts).\n for (const [name, hue] of Object.entries(expandedPalette))\n for (const n of Object.keys(hue.numeric))\n reverseIndex[`--color-${name}-${n}`] = `colors.palette.${name}.anchors.${n}`;\n // `kind` travels with the role so the editor picks the right `roleTokens`\n // variant on a remap — it used to infer that from `role === 'surface'`, which\n // silently did the wrong thing for any other surface-kind role.\n const colorRoles = Object.entries(roleMap).map(([name, spec]) => ({\n name,\n ramp: roleHue(spec),\n kind: roleKind(spec),\n }));\n // Per-hue token sets, so a client (the live editor) can re-point a role at\n // another hue. It can't derive these itself: `text-on` is a computed contrast\n // literal, not a var() ref. One variant per role KIND, because the two kinds\n // emit different token sets — a chromatic role has no bare `bg`, a surface\n // role has no solid tints.\n //\n // Keys are token keys (`bg`, `text-on`, `border-bold`, …) — the same ones\n // `tokenVar()` turns into `--color-<target>-<role>[-<variant>]`.\n const roleTokens = Object.fromEntries(\n Object.entries(expandedPalette).map(([hueName, hue]) => {\n const chromatic = functionalRole('_', hueName, hue, 'chromatic');\n const surface = functionalRole('_', hueName, hue, 'surface');\n return [\n hueName,\n {\n chromatic: { light: chromatic.light, dark: chromatic.dark },\n surface: { light: surface.light, dark: surface.dark },\n },\n ];\n }),\n );\n const typoRoles = (typography?.roles ?? {}) as Record<string, TypographyRole>;\n const hooks: Record<string, { prop: string; key: string }> = {};\n for (const [key, [prop, sfx]] of Object.entries(TYPO_KEYMAP)) hooks[sfx] = { prop, key };\n // Index EVERY hook for every role, not just the ones the role already\n // declares. The editor builds its control set from `typography.hooks` (all\n // of TYPO_KEYMAP), so a role that omits `tracking` still gets a `--<role>-ls`\n // control; without an entry here that edit previews live and is then dropped\n // as \"skipped\" on save. The path is a valid place to write whether or not it\n // exists yet — `roles` is an open record and the patch deep-merges.\n for (const role of Object.keys(typoRoles))\n for (const [key, [, sfx]] of Object.entries(TYPO_KEYMAP))\n reverseIndex[`--${role}-${sfx}`] = `typography.roles.${role}.${key}`;\n const pDefaults = patterns?.defaults ?? {};\n const pRadii = patterns?.radii ?? {};\n const pGroups = patterns?.groups ?? {};\n const pItems = (patterns?.items ?? {}) as Record<string, Pattern>;\n for (const prop of Object.keys(pDefaults))\n reverseIndex[`--${prop}-default`] = `patterns.defaults.${prop}`;\n for (const [group, props] of Object.entries(pGroups))\n for (const prop of Object.keys(props))\n reverseIndex[`--${prop}-${group}`] = `patterns.groups.${group}.${prop}`;\n const items = Object.entries(pItems).map(([name, p]) => {\n const base = p.base ?? {};\n const wrappable = Object.keys(base)\n .filter((prop) => prop in BASE_HOOK)\n .map((prop) => ({ sfx: BASE_HOOK[prop] as string, prop }));\n for (const { sfx, prop } of wrappable)\n reverseIndex[`--${sfx}-${name}`] = `patterns.items.${name}.base.${prop}`;\n return { name, group: p.group ?? null, base, wrappable, roles: p.roles ?? [] };\n });\n // Radii last, and only where a pattern hasn't already claimed the var: a\n // `patterns.radii` key that equals a pattern name collides on `--br-<name>`\n // (e.g. radii `card` vs the `card` pattern — a live collision in the example\n // config). The pattern's BASE_HOOK is the documented override, so it wins,\n // and `validate()` surfaces the collision as a warning so it isn't silent.\n for (const name of Object.keys(pRadii))\n if (!(`--br-${name}` in reverseIndex))\n reverseIndex[`--br-${name}`] = `patterns.radii.${name}`;\n return JSON.stringify(\n {\n colors: {\n ramps: Object.keys(expandedPalette),\n steps: NUMERIC_STEPS,\n palette: numericPalette,\n roles: colorRoles,\n roleTokens,\n },\n typography: {\n roles: Object.keys(typoRoles),\n hooks,\n families: typographyFamilies,\n specs: typoRoles,\n },\n scales: {\n text: typeSteps.map((s) => ({ name: s.name, value: s.value, max: s.max })),\n space: spaceSteps.map((s) => ({ name: s.name, value: s.value, max: s.max })),\n },\n fonts: ds.fonts ?? {},\n patterns: { defaults: pDefaults, radii: pRadii, groups: pGroups, items },\n shadows: shadows ?? {},\n reverseIndex,\n },\n null,\n 2,\n );\n })();\n\n // ── Tailwind bundle ──────────────────────────────────────────────────────────\n // Only the tailwind format consumes this (see `generate`), and assembling it\n // reads every framework partial off disk — so skip the work for css/bricks.\n const tailwind =\n format !== 'tailwind'\n ? ''\n : emitTailwind({\n ds,\n expandedPalette,\n scaleRoles,\n shadows,\n typeSteps,\n spaceSteps,\n typography,\n roleDecls,\n twTypeTokensCss,\n twPatternTokensCss,\n patternsCss: pat,\n assetsDir,\n utilities: UTILITIES,\n systemColorScheme: buildOpts.systemColorScheme === true,\n });\n\n // ── DESIGN.md ────────────────────────────────────────────────────────────────\n // Same deal as the tailwind bundle: only its own format consumes it, so the\n // other three don't pay for building it.\n const designMd =\n format !== 'design'\n ? ''\n : emitDesignMd({ ds, expandedPalette, scaleRoles, typeSteps, spaceSteps, shadows });\n\n return {\n generated,\n bricksColorsNamed,\n bricksColorsSemantic,\n bricksVariables,\n tokensJson,\n designManifest,\n tailwind,\n designMd,\n twTypeTokensCss,\n twPatternTokensCss,\n patternsCss: pat,\n };\n}\n\n// ── Tailwind emitter ──────────────────────────────────────────────────────────\ninterface TwCtx {\n ds: DesignSystem;\n expandedPalette: Record<string, ExpandedHue>;\n scaleRoles: FunctionalRole[];\n shadows: Record<string, string> | undefined;\n typeSteps: ScaleStep[];\n spaceSteps: ScaleStep[];\n typography: DesignSystem['typography'];\n roleDecls: (role: string, spec: TypographyRole) => Record<string, string>;\n twTypeTokensCss: string;\n twPatternTokensCss: string;\n patternsCss: string;\n assetsDir: string;\n /**\n * The configured `colors.utilities`. Was previously hardcoded to\n * bg/text/border at the emit site, so a consumer who enabled `outline`/\n * `fill`/`stroke` got them in css/bricks but not tailwind.\n */\n utilities: string[];\n /** `BuildOptions.systemColorScheme` — see the OS-preference block below. */\n systemColorScheme: boolean;\n}\n\nfunction emitTailwind(ctx: TwCtx): string {\n const {\n ds,\n expandedPalette,\n scaleRoles,\n shadows,\n typeSteps,\n spaceSteps,\n typography,\n roleDecls,\n twTypeTokensCss,\n twPatternTokensCss,\n patternsCss,\n assetsDir,\n utilities,\n } = ctx;\n const cssDir = join(assetsDir, 'css');\n const nl = (arr: string[]) => arr.filter(Boolean).join('\\n');\n const parts: string[] = [\n `/* GENERATED for Tailwind v4 (Astro) — do not edit by hand.\\n` +\n ` Class reference: npx vitops docs classes · All topics: npx vitops docs\\n` +\n ` Fonts below are STACKS ONLY — this file loads no webfonts. Load them with\\n` +\n ` Astro's fonts: config and point the token at the family's cssVariable. */`,\n ];\n parts.push(`@import \"tailwindcss\";\\n`);\n\n const theme: string[] = [];\n theme.push(` /* Hue scales → bg-<hue>-<step> text-* border-* (numeric, 50…950) */`);\n for (const [name, hue] of Object.entries(expandedPalette))\n for (const [n, hex] of Object.entries(hue.numeric))\n theme.push(` --color-${name}-${n}: ${hex};`);\n theme.push(`\\n /* Fonts → font-* (stacks only; no @font-face is emitted — see header) */`);\n for (const [name, stack] of Object.entries(ds.fonts ?? {}))\n theme.push(` --font-${name}: ${stack};`);\n theme.push(`\\n /* Fluid type scale → text-* */`);\n for (const s of typeSteps) theme.push(` --text-${s.name}: ${s.value};`);\n // Fluid space steps are NOT put in Tailwind's --spacing-* namespace: named\n // spacing keys shadow the size scales (e.g. `max-w-7xl` would resolve to\n // var(--spacing-7xl) ≈ 6rem and collapse layouts). They ship as --space-*\n // (matching the css format) in a plain :root below; use var(--space-<name>)\n // or the TW4 arbitrary form p-(--space-md). Numeric spacing (p-4 …) keeps\n // Tailwind's default --spacing multiplier.\n theme.push(`\\n /* Drop-shadows → shadow-* */`);\n for (const [name, value] of Object.entries(shadows ?? {}))\n theme.push(` --shadow-${name}: ${value};`);\n theme.push(`\\n /* Container breakpoints → @sm:/@md:/@lg:/@xl: */`);\n for (const [name, val] of BREAKPOINTS) theme.push(` --container-${name}: ${val};`);\n parts.push(`@theme {\\n${theme.join('\\n')}\\n}\\n`);\n\n if (spaceSteps.length)\n parts.push(\n `/* Fluid space scale — var(--space-<name>) or p-(--space-<name>) */\\n:root {\\n` +\n spaceSteps.map((s) => ` --space-${s.name}: ${s.value};`).join('\\n') +\n `\\n}\\n`,\n );\n\n // Role tokens go in a plain :root block, NOT @theme — including the emphasis\n // stops, despite those living in the --color-* namespace. The @utility set\n // below is the public API.\n //\n // This is load-bearing, not stylistic. Measured against tailwindcss@4.3.3:\n // when a token is in @theme AND an @utility of the derived name exists,\n // Tailwind merges both into one rule with the @theme declaration LAST, and it\n // does so regardless of source order. Putting `--color-<role>-<stop>` in\n // @theme would therefore silently substitute the stop for the plane on the\n // five colliding classes — including `text-<role>-muted` (step 800 → 300) and\n // `text-<role>-x-muted` (600 → 100), i.e. exactly the tokens tokens.ts's APCA\n // test guarantees are readable. Raw hue scales are safe in @theme because no\n // @utility competes for those names.\n if (scaleRoles.length) {\n let fn = '';\n for (const fr of scaleRoles)\n for (const [t, val] of Object.entries(fr.light)) fn += ` ${tokenVar(fr.role, t)}: ${val};\\n`;\n const focus = scaleRoles.find((r) => r.role === 'ui-primary') ?? scaleRoles[0];\n if (focus) fn += ` --color-border-focus: ${focus.light['bg-solid']};\\n`;\n // Same precondition as the css path: only a surface-kind role has the bare\n // `bg` token these two declarations read.\n const surface = scaleRoles.find((r) => r.role === 'surface' && 'bg' in r.light);\n if (surface) {\n fn += ` --surface-glass: color-mix(in oklch, var(--color-bg-surface) 72%, transparent);\\n`;\n fn += ` --overlay: color-mix(in oklch, var(--color-${surface.hue}-950) 45%, transparent);\\n`;\n }\n parts.push(`/* Role tokens (the public API) */\\n:root {\\n${fn}}\\n`);\n }\n\n parts.push(\n `/* ── Framework tokens (consumed by the inlined components) ── */\\n` +\n `${twTypeTokensCss}\\n${twPatternTokensCss}`,\n );\n\n // Dark appearance: the automatic functional flip (solid stays mode-stable).\n let darkBlock = '';\n for (const fr of scaleRoles)\n for (const [t, val] of Object.entries(fr.dark))\n if (fr.light[t] !== val) darkBlock += ` ${tokenVar(fr.role, t)}: ${val};\\n`;\n {\n const surface = scaleRoles.find((r) => r.role === 'surface');\n if (surface)\n darkBlock += ` --overlay: color-mix(in oklch, var(--color-${surface.hue}-950) 60%, transparent);\\n`;\n }\n if (darkBlock) {\n parts.push(\n `/* Functional role tokens (dark) */\\n${DARK_SEL} {\\n color-scheme: dark;\\n${darkBlock}}\\n`,\n );\n // Same opt-in OS-preference block as the css/bricks path — see the comment\n // there. Emitted unlayered here for the same reason the rest of this format\n // is: Tailwind owns the layering, and role tokens must stay out of `@theme`.\n if (ctx.systemColorScheme)\n parts.push(\n `/* Functional role tokens (dark) — OS preference, no explicit choice */\\n` +\n `@media (prefers-color-scheme: dark) {\\n ${SYSTEM_DARK_SEL} {\\n` +\n ` color-scheme: dark;\\n${darkBlock.replace(/^ {2}/gm, ' ')} }\\n}\\n`,\n );\n }\n\n parts.push(\n `/* State variant for the active flip (hover/focus-visible are built in). */\\n` +\n `@custom-variant is-active (&.is-active, &[data-active]);\\n`,\n );\n\n // `typography.headings` — the bare-element → role bindings, the same rules the\n // css/bricks path emits into typography.css. This format used to emit only the\n // `@utility font-<role>` half, so a Tailwind consumer's <h1> and <body> got no\n // role styling at all: no family, no size, no text-wrap.\n //\n // Tailwind's `base` layer, deliberately. It puts these behind BOTH `@utility\n // font-<role>` (utilities layer) and the patterns (components layer), matching\n // css/bricks — where typography.css sits in vitops.utilities and the bare tag\n // selector loses to `.font-<role>` on specificity rather than on layer. Emitted\n // unlayered, an `h1` rule here would beat every Tailwind utility.\n {\n const roles = (typography?.roles ?? {}) as Record<string, TypographyRole>;\n const bindings = Object.entries(typography?.headings ?? {}).filter(([, r]) => roles[r]);\n if (bindings.length)\n parts.push(\n `/* Bare-element type roles (typography.headings) */\\n@layer base {\\n` +\n bindings\n .map(\n ([tag, role]) =>\n ` ${tag} {\\n${decls(roleDecls(role, roles[role] as TypographyRole), ' ')}\\n }`,\n )\n .join('\\n') +\n `\\n}\\n`,\n );\n }\n\n const util: string[] = [];\n if (scaleRoles.length) {\n util.push(`/* Role colour utilities (the public API) */`);\n // Same source as the css/bricks formats — the two used to diverge because\n // this path re-parsed the other's generated strings and only ever ran the\n // functional half. See roleColorUtilities().\n for (const { cls, prop, value } of roleColorUtilities(scaleRoles, utilities))\n util.push(`@utility ${cls} {\\n ${prop}: ${value};\\n}`);\n if (scaleRoles.some((r) => r.role === 'surface' && 'bg' in r.light))\n util.push(\n `@utility glass {\\n background-color: var(--surface-glass);\\n backdrop-filter: blur(12px);\\n -webkit-backdrop-filter: blur(12px);\\n}`,\n );\n }\n util.push(`/* Typography roles */`);\n for (const [role, spec] of Object.entries(\n (typography?.roles ?? {}) as Record<string, TypographyRole>,\n ))\n util.push(`@utility font-${role} {\\n${decls(roleDecls(role, spec))}\\n}`);\n util.push(`\\n/* Animation effects (pair with .transition or a driver) */`);\n const asStr = (v: string | number) => String(v);\n for (const [name, e] of Object.entries(ds.animations?.effects ?? {})) {\n const d: Record<string, string> = { '--_anim': e.kf };\n for (const [k, v] of Object.entries(e.css ?? {})) d[k] = asStr(v);\n for (const [k, v] of Object.entries(e.vars ?? {})) d[`--${k}`] = asStr(v);\n util.push(`@utility ${name} {\\n${decls(d)}\\n}`);\n // No `kf` filter — see the css path. `flip-size-grow` is as real as\n // `flip-fade-in`; both rest on `.transition`, which covers height behind\n // `@supports (interpolate-size: allow-keywords)`.\n const props = new Set<string>();\n for (const k of Object.keys(e.vars ?? {})) {\n const m = /^(.*)-(from|to)$/.exec(k);\n if (m) props.add(m[1] as string);\n }\n const flip = Object.fromEntries(\n [...props].map((p) => [`--t-${p}`, `var(--${p}-to, ${STATE_DEFAULT[p]})`]),\n );\n util.push(`@utility flip-${name} {\\n${decls(flip)}\\n}`);\n }\n util.push(`\\n/* Split — internal fractions (pair split with a ratio) */`);\n // The `.split` PATTERN itself is not here — it is emitted into `@layer\n // components` with the rest of the structure, so `flex-col` beats it by layer\n // exactly as it does in css/bricks. Only its modifiers are utilities.\n //\n // That placement costs `@md:split`, and nothing recovers it. Measured against\n // tailwindcss@4.3.3: `@utility` throws \"`@utility` cannot be nested\" inside\n // `@layer`, AND inside a file pulled in with `@import … layer(…)` — the layer\n // clause is itself a nesting context. A `@custom-variant` doesn't help either:\n // a variant applied to a components-layer class emits nothing, because variants\n // attach to utility candidates only. `md-flex-row` says \"become a row at md\" in\n // every format, so the loss is a bare `<bp>-split` that had no unique job.\n //\n // `order`, not `row-reverse`, so the swap applies on whichever axis the split\n // is currently on — which is the point: it decides which panel comes FIRST,\n // and that is mostly a question about the stacked state. `reading-flow` keeps\n // focus order with the visual order where supported; until that is broad,\n // only one of the two panels should hold focusable content (WCAG 2.4.3).\n util.push(\n `@utility split-reverse {\\n reading-flow: flex-visual;\\n & > :first-child { order: 1; }\\n}`,\n );\n const RATIOS: [number, number][] = [\n [1, 2],\n [2, 1],\n [1, 3],\n [3, 1],\n [1, 4],\n [4, 1],\n [2, 3],\n [3, 2],\n ];\n for (const [a, b] of RATIOS)\n util.push(\n `@utility split-${a}-${b} {\\n flex-direction: row;\\n --_split-a: ${a};\\n --_split-b: ${b};\\n}`,\n );\n // Not derivable from `@theme`: the fluid space steps are deliberately kept out\n // of Tailwind's `--spacing-*` namespace (see the note above the `:root` block),\n // so `gap-md` has to be an explicit utility here. Verified against\n // tailwindcss@4.3.3 to win over the built-in functional `gap-*` and to accept\n // variants (`@md:gap-md`), which is why no per-breakpoint classes are emitted.\n const gaps = gapUtilities(spaceSteps);\n if (gaps.length) {\n util.push(`\\n/* Gap — the fluid space scale (var(--space-<name>)) */`);\n for (const { cls, prop, value } of gaps)\n util.push(`@utility ${cls} {\\n ${prop}: ${value};\\n}`);\n }\n util.push(`\\n/* Track placement (inside .centered) */`);\n for (const track of ['measure', 'breakout', 'spotlight', 'fullbleed'])\n util.push(`@utility ${track} {\\n grid-column: ${track};\\n}`);\n\n // `layout.css` is skipped wholesale in this format and a subset re-emitted\n // above, which left these two families missing from tailwind ENTIRELY — not\n // dropped via TW_CLASH, just never re-emitted. Unlike the `<bp>-` classes they\n // have no Tailwind equivalent to fall back on, and unlike a misspelt class\n // `vitops lint` cannot flag them, because they are not anchored to the\n // consumer's config. A consumer who used them got silence and no styling.\n util.push(`\\n/* Auto-fit grid — column count is content-driven, unlike .split */`);\n util.push(\n `@utility grid-auto {\\n display: grid;\\n gap: var(--grid-gap, 1rem);\\n` +\n ` grid-template-columns: repeat(auto-fit, minmax(var(--grid-min, 13rem), 1fr));\\n` +\n // Was missing here while layout.css carried it, so in THIS format a\n // `<ul class=\"grid-auto\">` inside `.rhythm` kept the `li + li` margin: the\n // grid stretched the row to the tallest and the first cell alone looked\n // vertically offset — the exact symptom layout.css warns about.\n ` &:is(ul, ol) > li + li { margin-block-start: 0; }\\n}`,\n );\n // Applied to the SECOND element of a pair, to override the rhythm it inherited.\n util.push(`\\n/* Vertical-rhythm overrides (mirrors layout.css) */`);\n for (const pair of [\n 'h-p',\n 'p-p',\n 'p-h',\n 'h-h',\n 'p-list',\n 'list-p',\n 'li-li',\n 'text-media',\n 'media-text',\n ])\n util.push(\n `@utility m-${pair} {\\n margin-top: calc(var(--rhythm-base) * var(--rhythm-${pair}));\\n}`,\n );\n for (const [name, mult] of [\n ['0', null],\n ['xs', '0.25'],\n ['s', '0.5'],\n ['m', '1'],\n ['l', '1.5'],\n ['xl', '2'],\n ] as const)\n util.push(\n `@utility m-${name} {\\n margin-top: ${mult == null ? '0' : `calc(var(--rhythm-base) * ${mult})`};\\n}`,\n );\n parts.push(util.join('\\n') + '\\n');\n\n // Structure mirrors layout.css (kept literal for parity with the original emitter).\n parts.push(`/* ── Structure (mirrors src/css/layout.css) ── */\n:root {\n --rhythm-scale: 1;\n --rhythm-base: calc(1rlh * var(--rhythm-scale));\n --rhythm-h-p: 0.4;\n --rhythm-p-p: 0.9;\n --rhythm-p-h: 1.6;\n --rhythm-h-h: 0.6;\n --rhythm-p-list: 0.5;\n --rhythm-list-p: 0.9;\n --rhythm-li-li: 0.3;\n --rhythm-text-media: 1.2;\n --rhythm-media-text: 1.2;\n --width-measure: 65ch;\n --width-breakout: 90ch;\n --width-spotlight: 120ch;\n --gutter: clamp(1rem, 4cqi, 3rem);\n}\n\nbody {\n container-type: inline-size;\n /* Named so \\`patterns/scroll-target.css\\`'s \\`@container body (…)\\` queries\n resolve — .toc-layout/.toc-sidebar/.toc-inline. Those partials are inlined\n into this bundle verbatim, so dropping the name (as this literal did) left\n the TOC permanently in its narrow layout in the tailwind format only. */\n container-name: body;\n}\n\n/* Class-level structure rules live in \\`components\\` so track/spacing utilities\n (@layer utilities — later in the layer order) can override them; unlayered\n CSS would beat ALL layered utilities regardless of specificity (e.g.\n \\`.centered > *\\` pinning children to \\`measure\\` over \\`.spotlight\\`). */\n@layer components {\n.rhythm {\n display: flow-root;\n}\n.rhythm > * + * {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-p-p));\n}\n.rhythm > :where(h1, h2, h3, h4, h5, h6) + p {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-h-p));\n}\n.rhythm > p + :where(h1, h2, h3, h4, h5, h6) {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-p-h));\n}\n.rhythm > :where(h1, h2, h3, h4, h5, h6) + :where(h1, h2, h3, h4, h5, h6) {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-h-h));\n}\n.rhythm > p + :where(ul, ol) {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-p-list));\n}\n.rhythm > :where(ul, ol) + p {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-list-p));\n}\n.rhythm :where(ul, ol) > li + li {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-li-li));\n}\n.rhythm > :where(p, h1, h2, h3, h4, h5, h6, ul, ol) + :where(figure, img, picture, video) {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-text-media));\n}\n.rhythm > :where(figure, img, picture, video) + :where(p, h1, h2, h3, h4, h5, h6, ul, ol) {\n margin-top: calc(var(--rhythm-base) * var(--rhythm-media-text));\n}\n\n.centered {\n --_measure: min(var(--width-measure), 100% - var(--gutter) * 2);\n --_breakout: minmax(0, calc((var(--width-breakout) - var(--width-measure)) / 2));\n --_spotlight: minmax(0, calc((var(--width-spotlight) - var(--width-breakout)) / 2));\n position: relative;\n display: grid;\n grid-template-columns:\n [fullbleed-start] minmax(var(--gutter), 1fr)\n [spotlight-start] var(--_spotlight)\n [breakout-start] var(--_breakout)\n [measure-start] var(--_measure) [measure-end]\n var(--_breakout) [breakout-end]\n var(--_spotlight) [spotlight-end]\n minmax(var(--gutter), 1fr) [fullbleed-end];\n}\n.centered > * {\n grid-column: measure;\n}\n\n.region {\n padding-block: clamp(\n var(--region-space-min, 3rem),\n var(--region-space, 8vh),\n var(--region-space-max, 8rem)\n );\n}\n\n/* \\`.split\\` is a PATTERN, so it belongs here rather than in an \\`@utility\\` — that\n is what makes \\`flex-col\\` beat it by layer instead of by a source-order race\n whose winner depends on Tailwind's property-based sort of custom utilities.\n Its ratio/reversal modifiers stay utilities. Mirrors layout.css, where each\n rule's rationale is written out; in short: \\`min-inline-size: 0\\` because a flex\n item's automatic minimum is its min-content size; the ratio as a flex BASIS\n rather than a grow factor, because grow shares out only the free space and a\n child's padding is not part of it; scoped to a two-child split because a ratio\n is a pair contract and a middle child with no basis would collapse to zero;\n \\`box-sizing: border-box\\` because a basis only sizes the border box on a\n border-box item (Tailwind's preflight sets it, the other formats' reset does). */\n.split {\n display: flex;\n flex-direction: row;\n}\n.split > * {\n flex: 1;\n box-sizing: border-box;\n min-inline-size: 0;\n}\n.split > :first-child {\n flex-grow: var(--_split-a, 1);\n}\n.split > :last-child {\n flex-grow: var(--_split-b, 1);\n}\n.split > :first-child:nth-last-child(2) {\n flex-basis: ${splitBasis('--_split-a')};\n}\n.split > :nth-child(2):last-child {\n flex-basis: ${splitBasis('--_split-b')};\n}\n}\n`);\n\n // Same layering rationale as the structure block above. Guarded on existence\n // like componentPartialOrder below: `assets/**` is a gitignored build artifact\n // that `vp test` does not produce, so an unguarded read makes the tailwind\n // format untestable in a clean checkout — which is how an 87-class vocabulary\n // gap between css and tailwind went unnoticed. The token layer still emits.\n const animPath = join(cssDir, 'animation.css');\n const animEngine = existsSync(animPath) ? readFileSync(animPath, 'utf8') : '';\n if (animEngine)\n parts.push(\n `/* ── Animation engine (animation.css) ── */\\n@layer components {\\n${animEngine}\\n}`,\n );\n // Patterns live in Tailwind's `components` layer so single-purpose utilities\n // (@layer utilities — declared later in the layer order) override them, e.g.\n // `.text-on-ui-primary` beating the link pattern's element-level `a { color }`.\n // Unlayered CSS would win over ALL layered utilities regardless of specificity.\n parts.push(`/* ── Component patterns ── */\\n@layer components {\\n${patternsCss}\\n}`);\n\n // Component + structural partials: the full framework library, minus the\n // Tailwind-owned utility layer. Sourced live from the CSS partials (in index.css\n // cascade order) so this never goes stale, then run through stripForTailwind\n // (dropping the TW_CLASH names Tailwind provides itself).\n const droppedClashes = new Set<string>();\n let droppedVariantBlocks = 0;\n /**\n * Is this `@container (min-width: …)` block a PRE-EXPANDED VARIANT block —\n * i.e. only `.sm-*`/`.md-*`/`.lg-*`/`.xl-*` utility classes, which Tailwind\n * regenerates on demand as `@md:`?\n *\n * Anything else in a container query is component *behaviour*, not a variant,\n * and dropping it breaks the component. `sitenav.css` is the case that caught\n * this: its `@container (min-width: 48rem) { .sitenav--bp-md { … } }` is what\n * switches the nav to its desktop layout, and blanket-dropping every\n * container block meant the tailwind format shipped a nav stuck in mobile.\n */\n const isVariantBlock = (raw: string): boolean => {\n const open = raw.indexOf('{');\n const body = raw.slice(open + 1, raw.lastIndexOf('}'));\n const selectors: string[] = [];\n let depth = 0;\n let start = 0;\n for (let i = 0; i < body.length; i++) {\n const ch = body[i];\n if (ch === '{') {\n if (depth === 0) selectors.push(body.slice(start, i));\n depth++;\n } else if (ch === '}') {\n depth--;\n if (depth === 0) start = i + 1;\n }\n }\n const names = selectors\n .flatMap((s) => s.split(','))\n .map((s) => s.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '').trim())\n .filter(Boolean);\n return names.length > 0 && names.every((n) => /^\\.(sm|md|lg|xl)-/.test(n));\n };\n const stripForTailwind = (css: string): string => {\n const kept: string[] = [];\n let depth = 0;\n let start = 0;\n let preludeEnd = -1;\n for (let i = 0; i < css.length; i++) {\n const ch = css[i];\n if (ch === '/' && css[i + 1] === '*') {\n const end = css.indexOf('*/', i + 2);\n i = end === -1 ? css.length : end + 1;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n i += 1;\n while (i < css.length && css[i] !== ch) i += css[i] === '\\\\' ? 2 : 1;\n continue;\n }\n if (ch === '{') {\n if (depth === 0) preludeEnd = i;\n depth++;\n } else if (ch === '}') {\n depth--;\n if (depth === 0) {\n const raw = css.slice(start, i + 1).trim();\n const prelude = css\n .slice(start, preludeEnd)\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .trim();\n const clash = /^\\.([A-Za-z0-9_-]+)/.exec(prelude);\n const name = clash?.[1] as string | undefined;\n if (/^@container\\s*\\(\\s*min-width:/.test(prelude) && isVariantBlock(raw))\n droppedVariantBlocks++;\n else if (name && TW_CLASH.has(name) && !CLASH_KEEP.has(name)) droppedClashes.add(name);\n else if (raw) kept.push(raw);\n start = i + 1;\n }\n }\n }\n return kept.join('\\n\\n');\n };\n\n const partials = componentPartialOrder(cssDir);\n const componentCss = partials\n .map((rel) => {\n const css = readFileSync(join(cssDir, rel), 'utf8');\n return `/* ── ${rel} ── */\\n${stripForTailwind(css)}`;\n })\n .join('\\n\\n');\n // Same layering rationale as the patterns block above. `componentPartialOrder`\n // already returns [] when assets are absent, so this is empty in that case.\n if (componentCss)\n parts.push(\n `/* ── Component + structural partials (Tailwind-clashing utilities dropped) ── */\\n` +\n `/* Dropped ${droppedVariantBlocks} pre-expanded breakpoint block(s) — write @sm:/@md:/@lg:/@xl: instead.\\n` +\n ` Dropped ${droppedClashes.size} clashing utilit(ies) Tailwind provides itself:\\n` +\n ` ${[...droppedClashes].sort().join(' ') || '(none)'} */\\n` +\n `@layer components {\\n${componentCss}\\n}`,\n );\n\n return nl(parts) + '\\n';\n}\n\n/**\n * Partials the tailwind format does NOT inline, because it re-creates them by\n * hand: the engine (`global.css` — Tailwind's preflight covers the reset;\n * `animation.css` — read directly and wrapped in `@layer components`), and the\n * two layout partials, whose utilities are re-emitted as `@utility` and whose\n * structure is re-emitted in the `@layer components` literal.\n *\n * **Every partial mapped to `vitops.utilities` must be listed here.** Inlining a\n * utility family lands it in tailwind's `@layer components`, the exact inversion\n * the layer split exists to remove — and it fails SILENTLY, because each of those\n * classes already exists as an `@utility` that wins on layer anyway. You would get\n * ~30 dead rules and no test failure. `format-parity.test.ts` asserts the\n * implication structurally rather than spot-checking the output.\n *\n * The implication is one-way: `layout.css` is skipped while sitting in\n * `vitops.components`, because its structure is re-emitted by hand.\n */\n/**\n * Framework COMPONENTS whose class name collides with a Tailwind utility, and\n * which must therefore survive the `TW_CLASH` strip.\n *\n * The clash test matches a rule's leading `.<name>`, which is right for a\n * single-purpose utility (Tailwind ships its own) and wrong for a pattern that\n * merely shares the name. `patterns/sticky.css` opens `.sticky { … }` and was\n * being deleted from the tailwind bundle WHOLESALE — the `--_sticky-offset`\n * wiring, the z-index, and every `&.sticky--bottom`/`--inline-start` variant —\n * so a consumer writing `class=\"sticky sticky--bottom\"` got bare\n * `position: sticky` and nothing else.\n *\n * `table` is here for the same reason but was never actually hit: `table.css`'s\n * prelude is `table,\\n.table`, which doesn't start with `.`, so the regex missed\n * it by luck. Listing it makes that explicit rather than accidental.\n */\nconst CLASH_KEEP: ReadonlySet<string> = new Set(['sticky', 'table']);\n\nexport const TAILWIND_SKIP: ReadonlySet<string> = new Set([\n 'global.css',\n 'animation.css',\n 'layout.css',\n 'layout-utilities.css',\n // Everything left here after the reveal family moved to patterns/reveal.css is\n // either a TW_CLASH name (display, sr-only, text-wrap) or a pre-expanded\n // variant block, so the strip already emptied it — reading it was pure waste,\n // and leaving it out made the invariant above look violated when it wasn't.\n 'utilities.css',\n]);\n\n/**\n * The component/structural CSS partials to inline into the Tailwind bundle, in\n * index.css cascade order. Everything the aggregator imports EXCEPT `TAILWIND_SKIP`\n * and the generated token layer (Tailwind builds its own via @theme).\n */\nfunction componentPartialOrder(cssDir: string): string[] {\n const indexPath = join(cssDir, 'index.css');\n const order: string[] = [];\n const seen = new Set<string>();\n const text = existsSync(indexPath) ? readFileSync(indexPath, 'utf8') : '';\n for (const m of text.matchAll(/@import\\s+['\"]\\.\\/([^'\"]+)['\"]/g)) {\n const rel = m[1] as string;\n if (rel.startsWith('generated/')) continue;\n if (TAILWIND_SKIP.has(rel)) continue;\n if (!seen.has(rel) && existsSync(join(cssDir, rel))) {\n seen.add(rel);\n order.push(rel);\n }\n }\n // Fallback: if no index.css, inline utilities + every pattern partial.\n if (!order.length) {\n if (existsSync(join(cssDir, 'utilities.css'))) order.push('utilities.css');\n const pdir = join(cssDir, 'patterns');\n if (existsSync(pdir))\n for (const f of readdirSync(pdir).sort()) if (f.endsWith('.css')) order.push(`patterns/${f}`);\n }\n return order;\n}\n\n// ── CSS bundling (css + bricks formats) ───────────────────────────────────────\n\n/** The bundle's cascade layers, in precedence order (last wins). */\nexport const CSS_LAYERS = ['vitops.base', 'vitops.components', 'vitops.utilities'] as const;\n\n/**\n * Which layer each `index.css` chunk belongs to. Anything unmapped defaults to\n * `vitops.components` — the safe default, since an unrecognised partial is far\n * more likely to be a component than a utility family.\n *\n * The split is by what the file *emits*, not what it's named:\n * • base — the UA reset and the pure `:root` token blocks.\n * • components — the animation engine, structural layout, and every pattern.\n * • utilities — the single-purpose classes that must be able to override a\n * pattern (`bg-*`, `drop-shadow-*`, `font-*`, effects, …).\n *\n * `color.css` and `shadows.css` each mix a `:root` block with utility classes\n * and go to `utilities` whole. That is safe because custom-property resolution\n * is NOT source-order dependent — a `:root` block declared after a rule that\n * reads it still resolves.\n *\n * `layout.css` is genuinely mixed (structural `.rhythm`/`.centered` AND\n * `.m-*`/`.flex`/`.split-*` utilities) and stays in `components` whole, so its\n * utility half still can't override a pattern. Splitting it is a separate\n * change; see the 0.9.0 changelog.\n */\nexport const CHUNK_LAYER: Record<string, (typeof CSS_LAYERS)[number]> = {\n 'global.css': 'vitops.base',\n 'generated/type-tokens.css': 'vitops.base',\n 'generated/tokens.css': 'vitops.base',\n 'generated/color.css': 'vitops.utilities',\n 'generated/shadows.css': 'vitops.utilities',\n 'generated/typography.css': 'vitops.utilities',\n 'generated/animation-effects.css': 'vitops.utilities',\n 'generated/spacing.css': 'vitops.utilities',\n 'layout-utilities.css': 'vitops.utilities',\n 'utilities.css': 'vitops.utilities',\n};\n\n/**\n * A `.split` child's flex basis. The ratio is a BASIS rather than a grow factor\n * because grow shares out only the FREE space, which a child's padding is not\n * part of — so a padded column came out wider than its sibling by exactly its\n * horizontal padding. Must stay character-identical to layout.css; the parity\n * suite matches this expression against both.\n */\nexport const splitBasis = (v: '--_split-a' | '--_split-b'): string =>\n `calc(var(${v}, 1) / (var(--_split-a, 1) + var(--_split-b, 1)) * 100%)`;\n\n/** The layer a partial's rules are wrapped in; unmapped partials are components. */\nexport const layerForPartial = (rel: string): (typeof CSS_LAYERS)[number] =>\n CHUNK_LAYER[rel] ?? 'vitops.components';\n\n/**\n * Assemble the full stylesheet by resolving index.css's @import order against the\n * static partials (from assets) and the freshly generated token partials (in\n * memory), then minify with lightningcss. No @import survives, so no disk\n * resolution / shared `generated/` dir is needed.\n *\n * Each chunk is wrapped in a cascade layer. This is what lets a single-purpose\n * utility override a component pattern — `class=\"card bg-danger-muted\"` — which\n * previously depended on source order and so silently did nothing here while\n * working in the tailwind format, where Tailwind's own layers already ordered\n * them correctly.\n *\n * Consequence worth knowing: unlayered CSS beats ALL layered CSS regardless of\n * specificity, so a consumer's own stylesheet now wins over the framework by\n * default. That is deliberate — it is the override story every layered\n * framework ships — but it means an unlayered *reset* will beat framework\n * component rules it used to lose to. Such a reset belongs in a layer declared\n * before `vitops.base` (see the `<style>` block in this repo's index.html).\n */\nfunction bundleCss(\n generated: Record<string, string>,\n assetsDir: string,\n minify: boolean,\n): { code: string; map: string | undefined } {\n const cssDir = join(assetsDir, 'css');\n const indexPath = join(cssDir, 'index.css');\n const index = readFileSync(indexPath, 'utf8');\n const chunks: string[] = [];\n for (const line of index.split('\\n')) {\n const m = /@import\\s+['\"]\\.\\/([^'\"]+)['\"]/.exec(line);\n if (!m) continue;\n const rel = m[1] as string;\n const body = rel.startsWith('generated/')\n ? (generated[rel.slice('generated/'.length)] ?? '')\n : readFileSync(join(cssDir, rel), 'utf8');\n if (!body.trim()) continue;\n chunks.push(`@layer ${layerForPartial(rel)} {\\n${body}\\n}`);\n }\n // `/*!` rather than `/*`: lightningcss strips ordinary comments when\n // minifying, and both the css and bricks bundles are minified — so a plain\n // banner would never reach the file anyone actually opens. Whoever opens this\n // is looking for a class name; point them at the live reference.\n const banner =\n `/*! GENERATED by @getvitops/generator — do not edit by hand.\\n` +\n ` Class reference: npx vitops docs classes · All topics: npx vitops docs */\\n`;\n // Declare the order up front so it is explicit rather than an artifact of\n // which chunk happened to appear first.\n const merged = banner + `@layer ${CSS_LAYERS.join(', ')};\\n` + chunks.join('\\n');\n const res = transform({\n filename: 'styles.css',\n code: Buffer.from(merged),\n minify,\n sourceMap: minify,\n });\n return {\n code: res.code.toString(),\n map: res.map ? res.map.toString() : undefined,\n };\n}\n\n// ── public generate() ─────────────────────────────────────────────────────────\n/**\n * Read `input` as whichever config kind it is, and return the design system to\n * build from plus the site config if that is what it was.\n *\n * The design system is validated here rather than in `resolveInput` so the error\n * can name where it came from: a theme inside a site config reports its `themes`\n * path, which is the difference between \"your config is wrong\" and \"your config\n * is wrong *here*\" when the file is a few hundred lines of company facts.\n */\nfunction loadInput(\n input: string | DesignSystem | Config,\n opts: { theme?: string; siteEnv?: string },\n): { ds: DesignSystem; config?: Config } {\n const raw = typeof input === 'string' ? JSON.parse(readFileSync(input, 'utf8')) : input;\n const resolved = resolveInput(raw, opts);\n const result = validate(resolved.designSystem);\n if (!result.ok) {\n const where =\n resolved.theme != null\n ? `design system at designSystem.themes.${resolved.theme}`\n : 'design-system.json';\n const lines = result.errors\n .slice(0, 12)\n .map((e) => ` • ${e.path.join('.') || '(root)'}: ${e.message}`)\n .join('\\n');\n throw new Error(`Invalid ${where}:\\n${lines}`);\n }\n for (const w of result.warnings) console.warn(`[vitops] ${w}`);\n return { ds: result.data, ...(resolved.config ? { config: resolved.config } : {}) };\n}\n\nexport async function generate(options: GenerateOptions): Promise<GenerateResult> {\n const format: Format = options.format ?? 'bricks';\n const outDir = options.outDir ?? 'dist';\n const assetsDir = options.assetsDir ?? DEFAULT_ASSETS;\n const { ds, config: embedded } = loadInput(options.input, {\n ...(options.theme != null ? { theme: options.theme } : {}),\n ...(options.siteEnv != null ? { siteEnv: options.siteEnv } : {}),\n });\n // Loaded before `build` because `designSystem.defaultColorScheme` decides what\n // the colour layer emits. (It is read again below for legal documents;\n // resolving twice would validate twice and double any warning.)\n //\n // An explicit `site` wins over one embedded in `input` — it is the more\n // specific statement, and the two are the same file in every case but the one\n // where a consumer deliberately split them.\n const config = options.site != null ? loadConfigFile(options.site, options.siteEnv) : embedded;\n const built = build(ds, format, assetsDir, {\n systemColorScheme:\n options.systemColorScheme ?? config?.designSystem?.defaultColorScheme === 'system',\n });\n mkdirSync(outDir, { recursive: true });\n const written: string[] = [];\n const put = (rel: string, content: string) => {\n const p = join(outDir, rel);\n mkdirSync(dirname(p), { recursive: true });\n writeFileSync(p, content);\n written.push(p);\n };\n\n if (format === 'design') {\n // Deliberately the only output: DESIGN.md conventionally lives at the repo\n // root next to AGENTS.md, not in a build directory, so this format is meant\n // to be run with `--out .` — writing a stylesheet alongside it would be\n // surprising. Compose it when you want both: `--format css,design`.\n put('DESIGN.md', built.designMd);\n } else if (format === 'tailwind') {\n put('tailwind.css', built.tailwind);\n put('tokens.json', built.tokensJson);\n } else if (format === 'css') {\n const { code } = bundleCss(built.generated, assetsDir, true);\n put('styles.css', code);\n put('tokens.json', built.tokensJson);\n put('design-manifest.json', built.designManifest);\n } else {\n // bricks: bundled minified CSS + Bricks import JSON + copied JS/PHP/docs.\n const { code, map } = bundleCss(built.generated, assetsDir, true);\n put('styles.min.css', map ? code + `\\n/*# sourceMappingURL=styles.min.css.map */` : code);\n if (map) put('styles.min.css.map', map);\n put('bricks-colors-named.json', built.bricksColorsNamed);\n put('bricks-colors-semantic.json', built.bricksColorsSemantic);\n put('bricks-variables.json', built.bricksVariables);\n put('tokens.json', built.tokensJson);\n // Framework-static JS bundles → outDir root (theme enqueues them).\n const jsDir = join(assetsDir, 'js');\n if (existsSync(jsDir)) {\n cpSync(jsDir, outDir, { recursive: true });\n for (const f of readdirSync(jsDir)) written.push(join(outDir, f));\n }\n // Bricks PHP elements + loader → outDir/bricks.\n const bricksSrc = join(assetsDir, 'bricks');\n if (existsSync(bricksSrc)) {\n cpSync(bricksSrc, join(outDir, 'bricks'), { recursive: true });\n written.push(join(outDir, 'bricks'));\n }\n // OKF docs bundle (generated per-config) → outDir/docs.\n const docs = generateDocs(ds, assetsDir);\n for (const [rel, content] of Object.entries(docs)) put(join('docs', rel), content);\n }\n\n // Legal documents → outDir/legal, as HTML fragments.\n //\n // Opt-in via `site`, and emitted for every format that emits files at all —\n // passing a site config and silently getting nothing back would be the\n // surprising behaviour. `design` is excluded because it emits DESIGN.md and\n // deliberately nothing else.\n //\n // HTML rather than markdown because this is the fragment a WordPress theme,\n // a Bricks shortcode or a plain page can include with no build step of its own.\n if (config != null && format !== 'design') {\n const legal = generateLegal(config, { output: 'html' });\n for (const [name, content] of Object.entries(legal)) put(join('legal', name), content);\n\n // Icon sprite → outDir/icons.svg.\n //\n // Opt-in via `icons.sprite`, because building it needs the @iconify-json/*\n // collections and most consumers render icons through their framework's own\n // integration instead. This is the path for the ones that can't: Bricks,\n // EmDash renderers, any plain HTML — `<use href=\"…/icons.svg#id\">`, no JS.\n const icons = config.site.icons as\n | { sprite?: boolean; ui?: string; brand?: string; weight?: string; semantic?: string[] }\n | undefined;\n if (icons?.sprite) {\n const { ui, brand, weight, semantic, sprite: _sprite, ...sets } = icons;\n const include = generateIconInclude({\n ...(ui ? { ui } : {}),\n ...(brand ? { brand } : {}),\n ...(weight ? { weight } : {}),\n ...(semantic ? { semantic } : {}),\n ...sets,\n });\n // Semantic names get a set-independent alias (`icon-menu`) alongside the\n // qualified id, so markup written against a sprite survives a set swap —\n // the same guarantee `resolveIcon` gives Astro consumers.\n const aliases: Record<string, string> = {};\n for (const name of semantic ?? []) {\n try {\n aliases[`icon-${name}`] = resolveIcon(name, ui ?? 'fa7-solid', weight ? { weight } : {});\n } catch {\n // Already reported by generateIconInclude, which throws on the same input.\n }\n }\n const built = await buildIconSprite({ include, aliases });\n put('icons.svg', built.svg);\n if (built.missing.length)\n console.warn(\n `[vitops] icons.sprite: ${built.missing.length} icon(s) were not found and are ` +\n `absent from the sprite: ${built.missing.join(', ')}.`,\n );\n }\n }\n\n return { format, outDir, written };\n}\n\nfunction loadConfigFile(input: string | Config, siteEnv?: string): Config {\n const raw = typeof input === 'string' ? JSON.parse(readFileSync(input, 'utf8')) : input;\n // resolveConfig validates and throws with one issue per line.\n return resolveConfig(raw, siteEnv);\n}\n","/**\n * @getvitops/generator — public API.\n *\n * Turn a `design-system.json` into platform outputs (Bricks, standalone CSS,\n * Tailwind v4). The `zod/mini` schema is the single source of truth: types,\n * validation, and the published JSON Schema all derive from it.\n */\nexport { generate, roleColorUtilities } from './generate.ts';\nexport type {\n GenerateOptions,\n GenerateResult,\n Format,\n StylesheetFormat,\n ColorUtility,\n} from './generate.ts';\n\n// Exposed so `vitops lint` can ask what the generator emits instead of\n// re-deriving the vocabulary and drifting from it.\nexport { expandPalette, functionalRole } from './tokens.ts';\nexport type { ExpandedHue, FunctionalRole } from './tokens.ts';\n\nexport {\n generateDocs,\n renderInlineMarkdown,\n schemaTreeNodes,\n type JsonSchemaNode,\n type SchemaTreeNode,\n type SchemaTreeOptions,\n} from './docs.ts';\n\n// Which tiers provide each pattern, and the call to make. Authored + drift-guarded;\n// see tiers.ts for why it can't be derived from naming convention.\nexport {\n TIERS,\n TIER_NAMES,\n tierPatterns,\n tierTags,\n type Tier,\n type TierAstro,\n type TierCss,\n type TierEntry,\n type TierProjection,\n type TierWc,\n} from './tiers.ts';\n/**\n * SVG sprite emitter. `spriteId` is the id grammar `<use href=\"…#id\">` targets;\n * @getvitops/astro's Icon.astro mirrors it, so treat it as a shared contract.\n */\nexport { buildIconSprite, loadIconSvg, spriteId } from './icons-sprite.ts';\nexport type { IconSpriteOptions, IconSpriteResult } from './icons-sprite.ts';\nexport { NUMERIC_STEPS } from './tokens.ts';\nexport {\n TW_CLASH,\n BASE_HOOK,\n DARK_SEL,\n REQUIRED_ROLES,\n ROLE_TOKEN_KEYS,\n roleHue,\n roleKind,\n} from './shared.ts';\nexport type { RoleSpec } from './shared.ts';\nexport { tokenVar, tokenClass, CONTRAST } from './tokens.ts';\n// The pre-1.0 colour-grammar rename, built from a config's own role names.\n// `vitops lint --fix` applies it to consumer source; `validate()` reports it\n// inside a design-system.json. One table, both surfaces.\nexport { movedTokens } from './token-refs.ts';\nexport type { RoleKind } from './tokens.ts';\n\nexport {\n DesignSystemSchema,\n jsonSchema,\n SCHEMA_URL,\n SCHEMA_LOCAL_PATH,\n validate,\n} from './schema.ts';\nexport type { DesignSystem, ValidationResult } from './schema.ts';\nexport {\n ConfigSchema,\n SiteFontSchema,\n configJsonSchema,\n CONFIG_SCHEMA_URL,\n validateConfig,\n resolveConfig,\n resolvePrivacyContact,\n resolveTheme,\n // Every entry point that takes a config goes through these, so a consumer who\n // keeps their tokens inside the larger three-section config points the same\n // option at that file rather than maintaining a second one.\n isConfig,\n resolveInput,\n stripNulls,\n deepMerge,\n JURISDICTIONS,\n JURISDICTION_COUNTRIES,\n AD_PROVIDERS,\n} from './config.ts';\nexport type {\n AdProvider,\n SiteAdProperty,\n ContactObject,\n Jurisdiction,\n PostalAddress,\n ResolvedInput,\n Config,\n OrganizationConfig,\n SiteSection,\n SiteFont,\n SiteIndexNow,\n SiteIndexing,\n SiteSearchConsole,\n ConfigValidationResult,\n} from './config.ts';\n\n// Legal documents. A sibling of `generateDocs`, not a `generate()` format:\n// `generate()` is keyed to a DesignSystem, and these render from a Config.\nexport {\n generateLegal,\n enabledDocs,\n renderMarkdown,\n renderNodes,\n derivePolicyVars,\n detectProcessorKeys,\n processorsMissingLocation,\n resolveProcessors,\n KNOWN_PROCESSORS,\n parseMarkdown,\n toContentNodes,\n toHtmlFragment,\n toPortableText,\n DOC_ORDER,\n DOC_SLUGS,\n TEMPLATES,\n} from './legal/index.ts';\nexport type {\n GenerateLegalOptions,\n LegalDoc,\n LegalOutput,\n PolicyVars,\n Processor,\n ProcessorStorage,\n KnownProcessorKey,\n Block,\n Span,\n DocSet,\n} from './legal/index.ts';\n\nimport { SCHEMA_LOCAL_PATH, type DesignSystem } from './schema.ts';\n\n/**\n * A minimal but complete starter design system, used by `vitops init`. It\n * validates against the schema and generates real output in every format, so a\n * new project can `vitops generate` immediately and then tune from here.\n */\nexport function defaultConfig(): DesignSystem {\n return {\n // The installed copy, not the unpinned unpkg URL — see SCHEMA_LOCAL_PATH.\n $schema: SCHEMA_LOCAL_PATH,\n colors: {\n // Each hue is generated as an 11-step OKLCH scale from its seed.\n palette: {\n brand: { seed: '#2e9b73' },\n ink: { seed: '#3f4a5c' },\n sky: { seed: '#2f7bc0' },\n sun: { seed: '#d08a1f' },\n rose: { seed: '#c74a42' },\n },\n // role → hue. Tokens (--color-<target>-<role>-<variant>) derive from the\n // hue's scale; dark mode flips automatically. `kind: \"surface\"` marks the\n // page/panel colours, which get a bare `bg-<role>`; the bare-string form\n // means chromatic, so a signal colour says tint-or-solid rather than\n // leaving \"how loud?\" to a guess.\n roles: {\n neutral: { hue: 'ink', kind: 'surface' },\n surface: { hue: 'ink', kind: 'surface' },\n 'ui-primary': 'brand',\n 'brand-primary': 'brand',\n info: 'sky',\n success: 'brand',\n warning: 'sun',\n danger: 'rose',\n },\n utilities: ['bg', 'text', 'icon', 'border'],\n },\n shadows: {\n sm: '0 1px 2px rgb(0 0 0 / 0.08)',\n md: '0 4px 6px rgb(0 0 0 / 0.12)',\n lg: '0 10px 15px rgb(0 0 0 / 0.18)',\n },\n fonts: {\n display: 'system-ui, -apple-system, \"Segoe UI\", sans-serif',\n sans: 'system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif',\n mono: 'ui-monospace, \"SF Mono\", Menlo, monospace',\n },\n typeScale: {\n base: '1rem',\n names: ['2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl'],\n baseStep: 4,\n baseline: 'm',\n ratio: 1.2,\n fluid: { minVw: '22.5rem', maxVw: '80rem', minRatio: 1.12 },\n },\n spaceScale: {\n base: '1rem',\n names: ['2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl'],\n baseStep: 4,\n baseline: 'm',\n ratio: 1.25,\n fluid: { minVw: '22.5rem', maxVw: '80rem', minRatio: 1.2 },\n },\n patterns: {\n defaults: {\n ds: 'none',\n b: '1px solid var(--color-border-surface-muted)',\n br: '0.375rem',\n p: '1rem',\n fs: '1rem',\n },\n // No `card` key here: a radii key named after a pattern collides on `--br-<name>`,\n // shadowing that pattern's override hook and leaving its `-group` alias unreachable\n // (validate() warns about exactly this). `card` is in the `panel` group, which already\n // carries the same 0.5rem, so dropping it is value-preserving.\n radii: { pill: '999px', circle: '50%' },\n groups: {\n control: {\n ds: 'var(--ds-default)',\n b: 'var(--b-default)',\n br: 'var(--br-default)',\n p: '0.5em 1em',\n fs: 'var(--fs-default)',\n },\n panel: {\n ds: 'var(--shadow-md)',\n b: 'var(--b-default)',\n br: '0.5rem',\n p: '1rem',\n fs: 'var(--fs-default)',\n },\n },\n z: { raised: 1, sticky: 100, overlay: 200, top: 1000 },\n items: {\n // Affordance tier: bare <button> and .btn share one zero-specificity rule,\n // so any explicit class (including .cta) overrides it.\n btn: {\n group: 'control',\n element: 'button',\n class: 'btn',\n fill: false,\n // Geometry resolves through the group alias layer (`--<prop>-btn-group`),\n // so the mapping to the `control` group lives in CSS and stays editable;\n // `overrides` restate only what this tier does differently.\n overrides: { b: '1px solid transparent', fs: 'inherit' },\n base: {\n display: 'inline-flex',\n 'align-items': 'center',\n 'justify-content': 'center',\n gap: '0.4em',\n padding: 'var(--p-btn-group)',\n 'border-radius': 'var(--br-btn-group)',\n border: 'var(--b-btn-group)',\n 'box-shadow': 'var(--ds-btn-group)',\n background: 'transparent',\n color: 'inherit',\n 'font-family': 'inherit',\n 'font-size': 'var(--fs-btn-group)',\n 'font-weight': 'inherit',\n 'text-decoration': 'none',\n cursor: 'pointer',\n },\n states: {\n hover: { step: 1, css: { 'background-color': 'var(--color-bg-surface-muted)' } },\n 'focus-visible': { ring: true },\n },\n roles: [],\n },\n // Persuasion tier: opt-in, works on any element (<a>, <button>, <summary>).\n cta: {\n group: 'control',\n class: 'cta',\n fill: true,\n // `ui-primary`, not `brand-primary`: a CTA is a prominent *interface*\n // affordance, and its prominence already comes from fill/weight/padding.\n // Keeping it on the ui role means the whole interaction family (btn,\n // link, cta) shares one hue lineage — otherwise focus rings change\n // colour depending on which tier you tabbed onto. Brand stays reachable\n // as an explicit `.cta-brand-primary` variant.\n default_role: 'ui-primary',\n overrides: { p: '0.75em 1.5em', b: 'none', ds: 'var(--shadow-sm)', fs: 'inherit' },\n base: {\n display: 'inline-flex',\n 'align-items': 'center',\n 'justify-content': 'center',\n gap: '0.5em',\n padding: 'var(--p-cta-group)',\n 'border-radius': 'var(--br-cta-group)',\n border: 'var(--b-cta-group)',\n 'font-family': 'inherit',\n 'font-size': 'var(--fs-cta-group)',\n 'font-weight': '600',\n 'text-decoration': 'none',\n cursor: 'pointer',\n color: 'var(--color-text-on-ui-primary)',\n 'box-shadow': 'var(--ds-cta-group)',\n },\n states: {\n hover: { step: 1, lift: '1px' },\n active: { scale: 0.97 },\n 'focus-visible': { ring: true },\n },\n roles: [],\n },\n card: {\n group: 'panel',\n class: 'card',\n base: {\n 'border-radius': 'var(--br-card-group)',\n padding: '1.5rem',\n background: 'var(--color-bg-surface)',\n border: 'var(--b-card-group)',\n 'box-shadow': 'var(--ds-card-group)',\n },\n states: {},\n roles: [],\n },\n },\n },\n typography: {\n families: {\n display: 'var(--font-display)',\n sans: 'var(--font-sans)',\n code: 'var(--font-mono, ui-monospace, monospace)',\n },\n // `text-wrap` is stated on every role because omitting it is NOT \"inherit\":\n // it is emitted at its identity (`wrap`) so role classes fully reset one\n // another, which would cancel the `pretty` a role inherits from body.\n roles: {\n display: {\n family: 'display',\n size: 'var(--text-3xl)',\n weight: 700,\n 'line-height': '1.05',\n tracking: '-0.03em',\n 'text-wrap': 'balance',\n },\n heading: {\n family: 'display',\n size: 'var(--text-xl)',\n weight: 600,\n 'line-height': '1.3',\n 'text-wrap': 'balance',\n },\n body: {\n family: 'sans',\n size: 'var(--text-m)',\n weight: 400,\n 'line-height': '1.55',\n 'text-wrap': 'pretty',\n },\n },\n // `body` binds base page typography to the body role, so prose inherits it\n // and the role's tokens stay the single place it's edited.\n headings: { body: 'body', h1: 'display', h2: 'heading', h3: 'heading' },\n },\n animations: {\n effects: {\n 'fade-in': { kf: 'composite', vars: { 'opacity-from': 0 } },\n 'slide-up': {\n kf: 'composite',\n vars: { 'translate-y-from': 'var(--slide-distance, 2rem)' },\n },\n },\n journeys: {\n // Each part must declare the `from` endpoint its keyframe reads — an\n // empty `slide` leaves slide-journey animating translate 0 → 0, i.e. a\n // journey that silently doesn't slide. Same var as the `slide-up`\n // effect above, so `--slide-distance` tunes both.\n base: {\n fade: { 'opacity-from': 0 },\n slide: { 'translate-y-from': 'var(--slide-distance, 2rem)' },\n },\n compose: [['fade'], ['slide'], ['fade', 'slide']],\n },\n },\n };\n}\n"],"mappings":"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"}