@getvitops/generator 8.2.0 → 8.3.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/assets/css/index.css +8 -0
  3. package/assets/css/patterns/callout.css +39 -0
  4. package/assets/css/patterns/embed.css +39 -0
  5. package/assets/css/patterns/forms.css +14 -0
  6. package/assets/css/patterns/logos.css +45 -0
  7. package/assets/css/patterns/section.css +61 -0
  8. package/assets/css/patterns/sitenav.css +262 -0
  9. package/assets/css/patterns/stats.css +61 -0
  10. package/assets/css/patterns/steps.css +98 -0
  11. package/assets/css/patterns/tone.css +38 -0
  12. package/assets/css/patterns/widget-area.css +22 -0
  13. package/assets/js/elements.js +3 -3
  14. package/config.schema.json +126 -10
  15. package/dist/{config-BfcWKH-5.mjs → config-D5xuz8--.mjs} +79 -15
  16. package/dist/config-D5xuz8--.mjs.map +1 -0
  17. package/dist/config.d.mts +77 -18
  18. package/dist/config.d.mts.map +1 -1
  19. package/dist/config.mjs +1 -1
  20. package/dist/index.d.mts +40 -3
  21. package/dist/index.d.mts.map +1 -1
  22. package/dist/index.mjs +574 -42
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/{schema-BV2n2phj.d.mts → schema-C-P9dF9F.d.mts} +49 -3
  25. package/dist/schema-C-P9dF9F.d.mts.map +1 -0
  26. package/dist/{tokens-C1RJwFeG.mjs → tokens-CaIGQQLk.mjs} +56 -11
  27. package/dist/tokens-CaIGQQLk.mjs.map +1 -0
  28. package/dist/{tokens-BzBbTeTi.d.mts → tokens-DH5cpvKd.d.mts} +24 -7
  29. package/dist/tokens-DH5cpvKd.d.mts.map +1 -0
  30. package/dist/tokens.d.mts +1 -1
  31. package/dist/tokens.mjs +1 -1
  32. package/package.json +4 -4
  33. package/schema.json +95 -5
  34. package/dist/config-BfcWKH-5.mjs.map +0 -1
  35. package/dist/config-Bhg3Xv3D.mjs +0 -1774
  36. package/dist/config-Bhg3Xv3D.mjs.map +0 -1
  37. package/dist/schema-BV2n2phj.d.mts.map +0 -1
  38. package/dist/tokens-BzBbTeTi.d.mts.map +0 -1
  39. package/dist/tokens-C1RJwFeG.mjs.map +0 -1
@@ -68,6 +68,10 @@
68
68
  "type": "string"
69
69
  },
70
70
  "description": "Step → colour overrides (hex or oklch()) pinned VERBATIM at those steps. Every other step takes its lightness from the shared ladder, with chroma and hue interpolated between the anchors — so an anchor is reproduced exactly and is the only step allowed off the ladder. An explicit anchor overrides the seed at that step; two anchors that resolve to the same step are an error."
71
+ },
72
+ "acknowledgeOffLadder": {
73
+ "type": "boolean",
74
+ "description": "Acknowledge that this hue deliberately pins colours off the shared lightness ladder (typically to match an existing brand palette exactly). Silences the per-step \"off the ladder\" build warnings for THIS hue only; the monotonicity and contrast checks still run."
71
75
  }
72
76
  },
73
77
  "required": [
@@ -98,6 +102,10 @@
98
102
  }
99
103
  ],
100
104
  "description": "Fixed brand kit: authored tones placed verbatim at their nearest steps plus tinted off-white/off-black endpoints; no interpolation. Either an ordered light → dark array or a step → colour map."
105
+ },
106
+ "acknowledgeOffLadder": {
107
+ "type": "boolean",
108
+ "description": "Acknowledge that this hue deliberately pins colours off the shared lightness ladder (typically to match an existing brand palette exactly). Silences the per-step \"off the ladder\" build warnings for THIS hue only; the monotonicity and contrast checks still run."
101
109
  }
102
110
  },
103
111
  "required": [
@@ -135,6 +143,21 @@
135
143
  "chromatic"
136
144
  ],
137
145
  "description": "`surface` — a page/panel colour: gets a bare `bg-<role>` plus the full emphasis range and text scale. `chromatic` (default) — a signal colour: tints and solids only, no bare `bg-<role>`."
146
+ },
147
+ "solid": {
148
+ "description": "Ramp step (100…900) the role's solid family starts from; default 600. `bg-<role>-solid` is this step and `-solid-bold` / `-solid-x-bold` walk one and two rungs DARKER, so `solid: 400` gives 400 → 500 → 600. Use it when the brand colour is bright and lives lower on the ramp (a yellow at 400) instead of reaching for raw `bg-<hue>-<step>` classes. Like the default family it is the same in light and dark. The contrast check still runs on the pair this produces.",
149
+ "type": [
150
+ "number",
151
+ "string"
152
+ ]
153
+ },
154
+ "foreground": {
155
+ "type": "string",
156
+ "enum": [
157
+ "light",
158
+ "dark"
159
+ ],
160
+ "description": "Polarity of `text-on-<role>`, the foreground for a filled surface. Default is whichever of near-white / near-black has more contrast on the solid. Set `\"dark\"` so a bright fill carries dark text (or `\"light\"` for the reverse). The build still fails if the forced pair is below APCA Lc 60."
138
161
  }
139
162
  },
140
163
  "required": [
@@ -164,13 +187,31 @@
164
187
  "additionalProperties": false
165
188
  },
166
189
  "shadows": {
167
- "description": "Named shadows → `--shadow-<name>` tokens and `.drop-shadow-<name>` utilities. Values are shadow parameter lists (offset/blur/colour). Each token feeds two consumers with different grammars — `box-shadow` (pattern geometry, via the `--ds-*` group aliases) and `filter: drop-shadow(…)` (the utilities and the `shadow:` state shortcut) — so values must stay in the intersection: **one layer, no spread radius, no `inset`**. `drop-shadow()` rejects all three, and rejecting them invalidates the whole filter, so the shadow vanishes rather than degrading.",
190
+ "description": "Named shadows → `--shadow-<name>` tokens and `.drop-shadow-<name>` utilities. A value is either a string (below) or `{ \"box\"?: string, \"drop\"?: string }` for a shadow that needs the two grammars to differ: `box` is what `--shadow-<name>` holds and what `box-shadow` consumers (pattern geometry, `--ds-*`) read, so it MAY use spread, `inset` and several layers; `drop` is emitted as `--shadow-<name>-drop` and is what `.drop-shadow-<name>` and the `shadow:` state shortcut read, so it must obey the drop-shadow() limits. Omit `drop` and no drop-shadow utility is emitted for that name; omit `box` and `--shadow-<name>` takes the `drop` value. The plain string form keeps working and feeds both consumers from one value. For that string form: each token feeds two consumers with different grammars — `box-shadow` (pattern geometry, via the `--ds-*` group aliases) and `filter: drop-shadow(…)` (the utilities and the `shadow:` state shortcut) — so values must stay in the intersection: **one layer, no spread radius, no `inset`**. `drop-shadow()` rejects all three, and rejecting them invalidates the whole filter, so the shadow vanishes rather than degrading.",
168
191
  "type": "object",
169
192
  "propertyNames": {
170
193
  "type": "string"
171
194
  },
172
195
  "additionalProperties": {
173
- "type": "string"
196
+ "anyOf": [
197
+ {
198
+ "type": "string"
199
+ },
200
+ {
201
+ "type": "object",
202
+ "properties": {
203
+ "box": {
204
+ "type": "string",
205
+ "description": "`box-shadow` value: spread, `inset` and multiple layers allowed."
206
+ },
207
+ "drop": {
208
+ "type": "string",
209
+ "description": "`drop-shadow()` value: one layer, at most three lengths, no `inset`."
210
+ }
211
+ },
212
+ "additionalProperties": false
213
+ }
214
+ ]
174
215
  }
175
216
  },
176
217
  "fonts": {
@@ -184,7 +225,7 @@
184
225
  }
185
226
  },
186
227
  "typeScale": {
187
- "description": "Fluid modular TYPE scale → `--text-<name>` tokens, consumed by typography roles and text-size utilities.",
228
+ "description": "Fluid modular TYPE scale → `--text-<name>` tokens, consumed by typography roles and text-size utilities.\n\n**Recipe for marketing headings:** one ratio cannot serve both a ~16px body and a ~76px hero — a ratio big enough for the hero collapses the small end to unreadable. Extend `names` upward instead of raising the ratio: keep `base` ≈ \"1rem\" at the body step, `ratio` ≈ 1.2 at `maxVw` (≈ 1.125–1.15 `minRatio` at `minVw` so headings tame on phones), and add names (`4xl`, `5xl`) for the display sizes — the steps above `baseStep` are what headings read, the steps below it only need `xs`/`sm`. Aim the largest named step at your hero (≈ 4.5–5rem at `maxVw`), then point the `display`/`title` roles at those steps rather than hand-writing `clamp()` in a role. If a step still needs its own value, set that role's `size` literally — roles may bypass the scale.",
188
229
  "type": "object",
189
230
  "properties": {
190
231
  "base": {
@@ -245,6 +286,55 @@
245
286
  ],
246
287
  "additionalProperties": false
247
288
  },
289
+ "layout": {
290
+ "type": "object",
291
+ "properties": {
292
+ "widths": {
293
+ "type": "object",
294
+ "properties": {
295
+ "measure": {
296
+ "type": "string",
297
+ "description": "Reading column → `--width-measure` (framework default 65ch)."
298
+ },
299
+ "breakout": {
300
+ "type": "string",
301
+ "description": "`.breakout` track → `--width-breakout` (default 90ch)."
302
+ },
303
+ "spotlight": {
304
+ "type": "string",
305
+ "description": "`.spotlight` track → `--width-spotlight` (default 120ch)."
306
+ },
307
+ "nav": {
308
+ "type": "string",
309
+ "description": "Navigation column beside content → `--width-nav` (default 16rem)."
310
+ }
311
+ },
312
+ "additionalProperties": false,
313
+ "description": "Content track widths for `.centered`. In `ch` so the reading measure stays character-based; keep measure ≤ breakout ≤ spotlight."
314
+ },
315
+ "regionSpace": {
316
+ "type": "object",
317
+ "properties": {
318
+ "min": {
319
+ "type": "string",
320
+ "description": "Floor → `--region-space-min` (default 3rem)."
321
+ },
322
+ "preferred": {
323
+ "type": "string",
324
+ "description": "Preferred value → `--region-space` (default 8vh)."
325
+ },
326
+ "max": {
327
+ "type": "string",
328
+ "description": "Ceiling → `--region-space-max` (default 8rem)."
329
+ }
330
+ },
331
+ "additionalProperties": false,
332
+ "description": "Vertical padding of `.region`: `padding-block: clamp(min, preferred, max)`."
333
+ }
334
+ },
335
+ "additionalProperties": false,
336
+ "description": "Optional layout tokens. Each key you set is emitted as a `:root` custom property (css, bricks and tailwind formats); each you omit keeps the framework default. Lets the live editor tune widths and region spacing instead of a hand-written override stylesheet."
337
+ },
248
338
  "spaceScale": {
249
339
  "description": "Fluid modular SPACE scale → `--space-<name>` tokens, consumed by spacing/gap utilities and vertical rhythm.",
250
340
  "type": "object",
@@ -466,7 +556,7 @@
466
556
  "number"
467
557
  ]
468
558
  },
469
- "description": "A bag of CSS-ish keys, each mapped to a declaration plus a `--<role>-<sfx>` override hook. The recognised set is **closed**: `family`, `size`, `weight`, `style`, `line-height`, `tracking` (→ `letter-spacing`), `text-transform`, `text-decoration`, `text-wrap`, `color`. Note the last four are spelled with their full CSS property names — `transform` and `decoration` are NOT accepted. Anything unrecognised is **ignored**, not passed through, so the generator warns rather than emitting it: a silently-dropped `transform: uppercase` is how title-case navigation reaches production. Note also that `style`, `text-transform`, `text-decoration` and `text-wrap` are emitted on **every** role at their identity value (`normal`/`none`/`none`/`wrap`) whether declared or not, so applying one role class over another fully resets it — which means **omitting `text-wrap` is not \"inherit\"**: it emits `text-wrap: wrap` and cancels the `pretty` the role would otherwise inherit from a `pretty` ancestor such as a `body`-mapped role. Declare it on every role — `balance` for heading-like roles, `pretty` for copy, `wrap` for short single-line labels."
559
+ "description": "A bag of CSS-ish keys, each mapped to a declaration plus a `--<role>-<sfx>` override hook. The recognised set is **closed**: `family`, `size`, `weight`, `style`, `line-height`, `tracking` (→ `letter-spacing`), `text-transform`, `text-decoration`, `text-wrap`, `color`. The canonical spellings of the last four are their full CSS property names (`text-transform`, `text-decoration`, …); `transform` and `decoration` are accepted as aliases of the first two and normalised to them. Anything unrecognised is **ignored**, not passed through, so the generator warns rather than emitting it: a silently-dropped key (a typo for `text-transform`, say) is how title-case navigation reaches production. Note also that `style`, `text-transform`, `text-decoration` and `text-wrap` are emitted on **every** role at their identity value (`normal`/`none`/`none`/`wrap`) whether declared or not, so applying one role class over another fully resets it — which means **omitting `text-wrap` is not \"inherit\"**: it emits `text-wrap: wrap` and cancels the `pretty` the role would otherwise inherit from a `pretty` ancestor such as a `body`-mapped role. Declare it on every role — `balance` for heading-like roles, `pretty` for copy, `wrap` for short single-line labels."
470
560
  }
471
561
  },
472
562
  "headings": {
@@ -604,7 +694,7 @@
604
694
  "type": "string"
605
695
  },
606
696
  "defaultColorScheme": {
607
- "description": "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.",
697
+ "description": "Initial appearance. `\"dark\"` makes the site DARK-ONLY: the dark tokens become the `:root` appearance (with `color-scheme: dark`), no light block or `data-theme` flip is emitted, and the light-mode contrast checks are skipped — so a palette that only works dark (bright fills with dark text, for example) builds. Do not ship `<wc-color-scheme-toggle>` on such a site. `\"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.",
608
698
  "type": "string",
609
699
  "enum": [
610
700
  "light",
@@ -694,6 +784,7 @@
694
784
  "type": "object",
695
785
  "properties": {
696
786
  "streetAddress": {
787
+ "description": "Street line. Optional: a business with no public street address (home-based, service-area) omits it, and the generated legal documents and JSON-LD simply leave the line out.",
697
788
  "type": "string"
698
789
  },
699
790
  "addressLocality": {
@@ -713,12 +804,28 @@
713
804
  }
714
805
  },
715
806
  "required": [
716
- "streetAddress",
717
807
  "addressLocality",
718
808
  "addressCountry"
719
809
  ],
720
810
  "additionalProperties": false
721
811
  },
812
+ "description": {
813
+ "description": "One or two sentences on what the organization does → JSON-LD `description` and a fallback for SEO. Localisable.",
814
+ "anyOf": [
815
+ {
816
+ "type": "string"
817
+ },
818
+ {
819
+ "type": "object",
820
+ "propertyNames": {
821
+ "type": "string"
822
+ },
823
+ "additionalProperties": {
824
+ "type": "string"
825
+ }
826
+ }
827
+ ]
828
+ },
722
829
  "taxID": {
723
830
  "description": "Tax identification number.",
724
831
  "type": "string"
@@ -759,6 +866,7 @@
759
866
  "type": "object",
760
867
  "properties": {
761
868
  "streetAddress": {
869
+ "description": "Street line. Optional: a business with no public street address (home-based, service-area) omits it, and the generated legal documents and JSON-LD simply leave the line out.",
762
870
  "type": "string"
763
871
  },
764
872
  "addressLocality": {
@@ -778,7 +886,6 @@
778
886
  }
779
887
  },
780
888
  "required": [
781
- "streetAddress",
782
889
  "addressLocality",
783
890
  "addressCountry"
784
891
  ],
@@ -849,6 +956,7 @@
849
956
  "type": "object",
850
957
  "properties": {
851
958
  "streetAddress": {
959
+ "description": "Street line. Optional: a business with no public street address (home-based, service-area) omits it, and the generated legal documents and JSON-LD simply leave the line out.",
852
960
  "type": "string"
853
961
  },
854
962
  "addressLocality": {
@@ -868,7 +976,6 @@
868
976
  }
869
977
  },
870
978
  "required": [
871
- "streetAddress",
872
979
  "addressLocality",
873
980
  "addressCountry"
874
981
  ],
@@ -2954,7 +3061,8 @@
2954
3061
  "description": "Which legal template set the generated documents use. Default `ca`.",
2955
3062
  "type": "string",
2956
3063
  "enum": [
2957
- "ca"
3064
+ "ca",
3065
+ "qc"
2958
3066
  ]
2959
3067
  },
2960
3068
  "privacyPolicy": {
@@ -2995,6 +3103,7 @@
2995
3103
  "type": "object",
2996
3104
  "properties": {
2997
3105
  "streetAddress": {
3106
+ "description": "Street line. Optional: a business with no public street address (home-based, service-area) omits it, and the generated legal documents and JSON-LD simply leave the line out.",
2998
3107
  "type": "string"
2999
3108
  },
3000
3109
  "addressLocality": {
@@ -3014,7 +3123,6 @@
3014
3123
  }
3015
3124
  },
3016
3125
  "required": [
3017
- "streetAddress",
3018
3126
  "addressLocality",
3019
3127
  "addressCountry"
3020
3128
  ],
@@ -3026,6 +3134,14 @@
3026
3134
  }
3027
3135
  ]
3028
3136
  },
3137
+ "privacyOfficerTitle": {
3138
+ "description": "Title of the person in charge of the protection of personal information (e.g. \"President\"). Quebec Law 25 requires the title and contact details to be published; the `qc` templates print it beside the `privacyOfficer` contact. Not asserted when absent.",
3139
+ "type": "string"
3140
+ },
3141
+ "impactAssessments": {
3142
+ "description": "Attests that a privacy impact assessment is carried out before personal information is communicated outside Quebec (Law 25, s. 17). The `qc` privacy policy states that assurance only when this is `true` — a fact the config cannot otherwise know, so it is never assumed.",
3143
+ "type": "boolean"
3144
+ },
3029
3145
  "retention": {
3030
3146
  "description": "How long personal information is kept, in prose (e.g. \"24 months after last contact\").",
3031
3147
  "type": "string"
@@ -1,4 +1,4 @@
1
- import { a as expandPalette, b as roleHue, d as tokenVar, g as ROLE_TOKEN_KEYS, h as REQUIRED_ROLES, o as functionalRole, x as roleKind } from "./tokens-C1RJwFeG.mjs";
1
+ import { C as roleKind, S as roleHue, _ as ROLE_TOKEN_KEYS, a as expandPalette, d as tokenVar, g as REQUIRED_ROLES, n as NUMERIC_STEPS, o as functionalRole } from "./tokens-CaIGQQLk.mjs";
2
2
  import { AD_PROVIDERS, AdPropertySchema, AdProviderSchema, BIGIN_DATA_CENTERS, CRM_PROVIDERS, CrmSchema, DeploymentSchema, IndexNowSchema, IndexingSchema, LocalizableSchema, NotificationsSchema, ReviewLocationSchema, ReviewsSchema, SearchConsoleSchema, SearchConsoleSetupSchema, SecuritySchema, SeoSchema, TrackingSchema, desc } from "@getvitops/config";
3
3
  import * as z from "@zod/mini";
4
4
  import { AD_PLATFORMS } from "@getvitops/utils/ads";
@@ -311,11 +311,16 @@ function tokenRefIssues(ds) {
311
311
  const CssDecls = desc(z.record(z.string(), z.string()), "A CSS declaration block: property → value. Values stay strings (they can be hex, var(), clamp(), keywords, …); the generator, not the schema, interprets them.");
312
312
  const Scalar = z.union([z.string(), z.number()]);
313
313
  const VarMap = z.record(z.string(), Scalar);
314
+ const AckOffLadder = z.optional(desc(z.boolean(), "Acknowledge that this hue deliberately pins colours off the shared lightness ladder (typically to match an existing brand palette exactly). Silences the per-step \"off the ladder\" build warnings for THIS hue only; the monotonicity and contrast checks still run."));
314
315
  const SeededRamp = desc(z.strictObject({
315
316
  seed: desc(z.string(), "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."),
316
- anchors: z.optional(desc(z.record(z.string(), z.string()), "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."))
317
+ anchors: z.optional(desc(z.record(z.string(), z.string()), "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.")),
318
+ acknowledgeOffLadder: AckOffLadder
317
319
  }), "Seeded hue: the 11-step scale is GENERATED in OKLCH from `seed` (anchors pin specific steps).");
318
- const FixedRamp = desc(z.strictObject({ tones: desc(z.union([z.array(z.string()), z.record(z.string(), z.string())]), "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.") }), "Fixed hue: authored brand tones used verbatim; no generation.");
320
+ const FixedRamp = desc(z.strictObject({
321
+ tones: desc(z.union([z.array(z.string()), z.record(z.string(), z.string())]), "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."),
322
+ acknowledgeOffLadder: AckOffLadder
323
+ }), "Fixed hue: authored brand tones used verbatim; no generation.");
319
324
  const Ramp = desc(z.union([SeededRamp, FixedRamp]), "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.");
320
325
  /**
321
326
  * A role points at a hue, and optionally declares its kind. The bare-string form
@@ -324,7 +329,9 @@ const Ramp = desc(z.union([SeededRamp, FixedRamp]), "A palette hue, authored one
324
329
  */
325
330
  const RoleSpecSchema = z.union([desc(z.string(), "A palette hue name. Shorthand for `{ hue, kind: \"chromatic\" }`."), z.strictObject({
326
331
  hue: desc(z.string(), "The palette hue this role resolves to."),
327
- kind: z.optional(desc(z.enum(["surface", "chromatic"]), "`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>`."))
332
+ kind: z.optional(desc(z.enum(["surface", "chromatic"]), "`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>`.")),
333
+ solid: z.optional(desc(z.union([z.number(), z.string()]), "Ramp step (100…900) the role's solid family starts from; default 600. `bg-<role>-solid` is this step and `-solid-bold` / `-solid-x-bold` walk one and two rungs DARKER, so `solid: 400` gives 400 → 500 → 600. Use it when the brand colour is bright and lives lower on the ramp (a yellow at 400) instead of reaching for raw `bg-<hue>-<step>` classes. Like the default family it is the same in light and dark. The contrast check still runs on the pair this produces.")),
334
+ foreground: z.optional(desc(z.enum(["light", "dark"]), "Polarity of `text-on-<role>`, the foreground for a filled surface. Default is whichever of near-white / near-black has more contrast on the solid. Set `\"dark\"` so a bright fill carries dark text (or `\"light\"` for the reverse). The build still fails if the forced pair is below APCA Lc 60."))
328
335
  })]);
329
336
  const UtilityName = z.enum([
330
337
  "bg",
@@ -337,9 +344,13 @@ const UtilityName = z.enum([
337
344
  ]);
338
345
  const Colors = desc(z.strictObject({
339
346
  palette: desc(z.record(z.string(), Ramp), "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."),
340
- roles: desc(z.record(z.string(), RoleSpecSchema), `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.`),
347
+ roles: desc(z.record(z.string(), RoleSpecSchema), `Maps semantic role names onto palette hues. Role names are ARBITRARY — add a key and the generator emits that role's token set (\`--color-<target>-<role>[-<variant>]\` for target bg/text/icon/border), its dark-mode flip and its utility classes.\n\nA value is either a hue name (\`"danger": "rust"\`) or \`{ "hue": …, "kind": "surface" | "chromatic" }\`. **The kind decides the shape of the token set.** \`chromatic\` (the default, and what the bare-string form means) is a signal colour: its backgrounds split into tints (\`bg-<role>-x-muted\`/\`-muted\`) and solids (\`bg-<role>-solid[-bold|-x-bold]\`), with deliberately **no bare \`bg-<role>\`** — "how loud?" is a question the author answers. \`surface\` is a page/panel colour: it has a bare \`bg-<role>\` plus the full emphasis range and text scale.\n\nDark mode flips automatically; there is no per-appearance scheme grammar. The solid family and its computed \`text-on-<role>\` foreground stay mode-stable so a filled button keeps its identity. \n\n**Contrast is enforced at build time, in both appearances** (APCA Lc): body text ≥ 75, secondary and muted text (\`text-muted\`) ≥ **60 against the page plane** it sits on, icons and guaranteed boundaries ≥ 45, and \`text-on-<role>\` ≥ 60 on the role's solid. So a mockup's muted grey that lands near Lc 57 fails the build — lighten the anchor on a dark page (or darken it on a light one) until it clears 60. \`text-x-muted\`/\`text-xx-muted\` are exempt (placeholders, disabled). A role can move its fill off the default step 600 with \`solid\`, and pin the polarity of its on-colour with \`foreground\`; a dark-only site (\`defaultColorScheme: "dark"\`) is only checked in dark. Six roles are a required core, because the shipped framework CSS references them with no fallback: ${REQUIRED_ROLES.join(", ")}. Conventional additions are ui-secondary/accent, brand-secondary, info and success.`),
341
348
  utilities: z.optional(desc(z.array(UtilityName), "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."))
342
349
  }), "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.");
350
+ const Shadow = z.union([z.string(), z.strictObject({
351
+ box: z.optional(desc(z.string(), "`box-shadow` value: spread, `inset` and multiple layers allowed.")),
352
+ drop: z.optional(desc(z.string(), "`drop-shadow()` value: one layer, at most three lengths, no `inset`."))
353
+ })]);
343
354
  const Scale = z.strictObject({
344
355
  base: desc(z.string(), "Anchor size (a CSS length, e.g. \"1rem\") — the value at `baseStep`."),
345
356
  ratio: desc(z.number(), "Modular ratio between adjacent steps at large viewports."),
@@ -371,7 +382,7 @@ const Patterns = desc(z.strictObject({
371
382
  z: desc(z.optional(z.record(z.string(), z.number())), "Z-index tiers → `--z-tier-<name>`."),
372
383
  items: desc(z.optional(z.record(z.string(), Pattern)), "The component patterns to emit, keyed by name.")
373
384
  }), "Component patterns and their token cascade: `defaults` → `groups` → per-pattern `overrides`, plus shape (`radii`) and z-index primitives.");
374
- const TypographyRole = desc(z.record(z.string(), Scalar), "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.");
385
+ const TypographyRole = desc(z.record(z.string(), Scalar), "A bag of CSS-ish keys, each mapped to a declaration plus a `--<role>-<sfx>` override hook. The recognised set is **closed**: `family`, `size`, `weight`, `style`, `line-height`, `tracking` (→ `letter-spacing`), `text-transform`, `text-decoration`, `text-wrap`, `color`. The canonical spellings of the last four are their full CSS property names (`text-transform`, `text-decoration`, …); `transform` and `decoration` are accepted as aliases of the first two and normalised to them. Anything unrecognised is **ignored**, not passed through, so the generator warns rather than emitting it: a silently-dropped key (a typo for `text-transform`, say) is how title-case navigation reaches production. Note also that `style`, `text-transform`, `text-decoration` and `text-wrap` are emitted on **every** role at their identity value (`normal`/`none`/`none`/`wrap`) whether declared or not, so applying one role class over another fully resets it — which means **omitting `text-wrap` is not \"inherit\"**: it emits `text-wrap: wrap` and cancels the `pretty` the role would otherwise inherit from a `pretty` ancestor such as a `body`-mapped role. Declare it on every role — `balance` for heading-like roles, `pretty` for copy, `wrap` for short single-line labels.");
375
386
  const Typography = desc(z.strictObject({
376
387
  families: desc(z.optional(z.record(z.string(), z.string())), "Role-facing family aliases → CSS font values, usually referencing the top-level `fonts` tokens (e.g. \"var(--font-display)\")."),
377
388
  roles: desc(z.optional(z.record(z.string(), TypographyRole)), "Semantic type roles (display, title, heading, body, quote, caption, eyebrow, code, lead, footnote, tag, …), each emitted as a `font-<role>` class."),
@@ -389,6 +400,20 @@ const Animations = desc(z.strictObject({
389
400
  compose: desc(z.optional(z.array(z.array(z.string()))), "Combinations of base parts, each emitted as a `.<parts>-journey` class.")
390
401
  })), "Multi-part journey classes composed from `base` building blocks.")
391
402
  }), "Animation effect + journey classes (pure value layers). The animation engine itself — keyframes, drivers, floats, utilities — is static framework CSS, not configured here.");
403
+ const Length = z.string();
404
+ const Layout = desc(z.strictObject({
405
+ widths: z.optional(desc(z.strictObject({
406
+ measure: z.optional(desc(Length, "Reading column → `--width-measure` (framework default 65ch).")),
407
+ breakout: z.optional(desc(Length, "`.breakout` track → `--width-breakout` (default 90ch).")),
408
+ spotlight: z.optional(desc(Length, "`.spotlight` track → `--width-spotlight` (default 120ch).")),
409
+ nav: z.optional(desc(Length, "Navigation column beside content → `--width-nav` (default 16rem)."))
410
+ }), "Content track widths for `.centered`. In `ch` so the reading measure stays character-based; keep measure ≤ breakout ≤ spotlight.")),
411
+ regionSpace: z.optional(desc(z.strictObject({
412
+ min: z.optional(desc(Length, "Floor → `--region-space-min` (default 3rem).")),
413
+ preferred: z.optional(desc(Length, "Preferred value → `--region-space` (default 8vh).")),
414
+ max: z.optional(desc(Length, "Ceiling → `--region-space-max` (default 8rem)."))
415
+ }), "Vertical padding of `.region`: `padding-block: clamp(min, preferred, max)`."))
416
+ }), "Optional layout tokens. Each key you set is emitted as a `:root` custom property (css, bricks and tailwind formats); each you omit keeps the framework default. Lets the live editor tune widths and region spacing instead of a hand-written override stylesheet.");
392
417
  const DesignSystemSchema = z.strictObject({
393
418
  $schema: desc(z.optional(z.string()), "URL of the published JSON Schema (stamped by `vitops init`) so editors provide autocomplete + validation."),
394
419
  meta: desc(z.optional(z.strictObject({
@@ -396,9 +421,10 @@ const DesignSystemSchema = z.strictObject({
396
421
  description: desc(z.optional(z.string()), "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.")
397
422
  })), "Brand identity for agent-facing output. Consumed only by the `design` format (`DESIGN.md`); it emits no CSS and no tokens."),
398
423
  colors: Colors,
399
- shadows: desc(z.optional(z.record(z.string(), z.string())), "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."),
424
+ shadows: desc(z.optional(z.record(z.string(), Shadow)), "Named shadows → `--shadow-<name>` tokens and `.drop-shadow-<name>` utilities. A value is either a string (below) or `{ \"box\"?: string, \"drop\"?: string }` for a shadow that needs the two grammars to differ: `box` is what `--shadow-<name>` holds and what `box-shadow` consumers (pattern geometry, `--ds-*`) read, so it MAY use spread, `inset` and several layers; `drop` is emitted as `--shadow-<name>-drop` and is what `.drop-shadow-<name>` and the `shadow:` state shortcut read, so it must obey the drop-shadow() limits. Omit `drop` and no drop-shadow utility is emitted for that name; omit `box` and `--shadow-<name>` takes the `drop` value. The plain string form keeps working and feeds both consumers from one value. For that string form: each token feeds two consumers with different grammars — `box-shadow` (pattern geometry, via the `--ds-*` group aliases) and `filter: drop-shadow(…)` (the utilities and the `shadow:` state shortcut) — so values must stay in the intersection: **one layer, no spread radius, no `inset`**. `drop-shadow()` rejects all three, and rejecting them invalidates the whole filter, so the shadow vanishes rather than degrading."),
400
425
  fonts: desc(z.optional(z.record(z.string(), z.string())), "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."),
401
- typeScale: desc(z.optional(Scale), "Fluid modular TYPE scale → `--text-<name>` tokens, consumed by typography roles and text-size utilities."),
426
+ typeScale: desc(z.optional(Scale), "Fluid modular TYPE scale → `--text-<name>` tokens, consumed by typography roles and text-size utilities.\n\n**Recipe for marketing headings:** one ratio cannot serve both a ~16px body and a ~76px hero — a ratio big enough for the hero collapses the small end to unreadable. Extend `names` upward instead of raising the ratio: keep `base` ≈ \"1rem\" at the body step, `ratio` ≈ 1.2 at `maxVw` (≈ 1.125–1.15 `minRatio` at `minVw` so headings tame on phones), and add names (`4xl`, `5xl`) for the display sizes — the steps above `baseStep` are what headings read, the steps below it only need `xs`/`sm`. Aim the largest named step at your hero (≈ 4.5–5rem at `maxVw`), then point the `display`/`title` roles at those steps rather than hand-writing `clamp()` in a role. If a step still needs its own value, set that role's `size` literally — roles may bypass the scale."),
427
+ layout: z.optional(Layout),
402
428
  spaceScale: desc(z.optional(Scale), "Fluid modular SPACE scale → `--space-<name>` tokens, consumed by spacing/gap utilities and vertical rhythm."),
403
429
  patterns: z.optional(Patterns),
404
430
  typography: z.optional(Typography),
@@ -473,7 +499,8 @@ const dropShadowIssue = (value) => {
473
499
  const RAMP_KEYS = /* @__PURE__ */ new Set([
474
500
  "seed",
475
501
  "anchors",
476
- "tones"
502
+ "tones",
503
+ "acknowledgeOffLadder"
477
504
  ]);
478
505
  /**
479
506
  * Replace the bare "Invalid input" a failed union produces with the reason.
@@ -536,13 +563,44 @@ function validate(input) {
536
563
  warnings: []
537
564
  };
538
565
  }
566
+ for (const [role, spec] of Object.entries(roles)) {
567
+ if (typeof spec === "string" || spec.solid == null) continue;
568
+ const step = String(spec.solid);
569
+ if (!NUMERIC_STEPS.includes(step) || step === "50" || step === "950") return {
570
+ ok: false,
571
+ data: void 0,
572
+ errors: [{
573
+ code: "custom",
574
+ path: [
575
+ "colors",
576
+ "roles",
577
+ role,
578
+ "solid"
579
+ ],
580
+ message: `solid step "${step}" is not one of 100, 200, … 900`
581
+ }],
582
+ warnings: []
583
+ };
584
+ }
539
585
  const warnings = [];
540
586
  const missing = REQUIRED_ROLES.filter((r) => roles[r] == null);
541
587
  if (missing.length) warnings.push(`colors.roles is missing ${missing.map((r) => `"${r}"`).join(", ")} — the framework's own component CSS references ${missing.length === 1 ? "it" : "them"} with no fallback, so those components will render uncoloured. Add any role you like, but keep these defined.`);
542
588
  const radii = Object.keys(result.data.patterns?.radii ?? {});
543
589
  const items = new Set(Object.keys(result.data.patterns?.items ?? {}));
544
590
  for (const name of radii) if (items.has(name)) warnings.push(`patterns.radii.${name} collides with the "${name}" pattern on --br-${name}; the pattern's override hook wins — rename the radius`);
545
- for (const [name, value] of Object.entries(result.data.shadows ?? {})) {
591
+ for (const [name, spec] of Object.entries(result.data.shadows ?? {})) {
592
+ if (typeof spec !== "string" && spec.box == null && spec.drop == null) return {
593
+ ok: false,
594
+ data: void 0,
595
+ errors: [{
596
+ code: "custom",
597
+ path: ["shadows", name],
598
+ message: "a split shadow needs at least one of `box` and `drop`"
599
+ }],
600
+ warnings: []
601
+ };
602
+ const value = typeof spec === "string" ? spec : spec.drop;
603
+ if (value == null) continue;
546
604
  const issue = dropShadowIssue(value);
547
605
  if (issue) warnings.push(`shadows.${name} carries ${issue}, which \`filter: drop-shadow()\` rejects — \`.drop-shadow-${name}\` will render no shadow at all (the token still works as a \`box-shadow\`). Use one layer of at most three lengths.`);
548
606
  }
@@ -652,7 +710,7 @@ const DesignSystemBlock = desc(z.strictObject({
652
710
  "light",
653
711
  "dark",
654
712
  "system"
655
- ])), "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.")
713
+ ])), "Initial appearance. `\"dark\"` makes the site DARK-ONLY: the dark tokens become the `:root` appearance (with `color-scheme: dark`), no light block or `data-theme` flip is emitted, and the light-mode contrast checks are skipped — so a palette that only works dark (bright fills with dark text, for example) builds. Do not ship `<wc-color-scheme-toggle>` on such a site. `\"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.")
656
714
  }), "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: … }`.");
657
715
  const LocaleSchema = z.strictObject({
658
716
  name: desc(z.string(), "Display name of the locale (e.g. \"English\")."),
@@ -672,7 +730,7 @@ const DomainAliasSchema = z.strictObject({
672
730
  environment: z.optional(z.string())
673
731
  });
674
732
  const PostalAddressSchema = desc(z.strictObject({
675
- streetAddress: z.string(),
733
+ streetAddress: desc(z.optional(z.string()), "Street line. Optional: a business with no public street address (home-based, service-area) omits it, and the generated legal documents and JSON-LD simply leave the line out."),
676
734
  addressLocality: desc(z.string(), "City."),
677
735
  addressRegion: desc(z.optional(z.string()), "State / province."),
678
736
  postalCode: z.optional(z.string()),
@@ -755,6 +813,7 @@ const OrganizationSchema = z.strictObject({
755
813
  email: desc(z.optional(z.email()), "General contact address. Also the last fallback for privacy requests — see `contact`."),
756
814
  phone: desc(z.optional(z.string()), "General contact telephone number."),
757
815
  address: desc(z.optional(PostalAddressSchema), "Registered/mailing address. Its `addressRegion` and `addressCountry` are what the governing-law clause of the generated terms of service defaults to."),
816
+ description: desc(z.optional(LocalizableSchema), "One or two sentences on what the organization does → JSON-LD `description` and a fallback for SEO. Localisable."),
758
817
  taxID: desc(z.optional(z.string()), "Tax identification number."),
759
818
  vatID: desc(z.optional(z.string()), "VAT identification number."),
760
819
  sameAs: desc(z.optional(z.array(z.url())), "Profile URLs → JSON-LD `sameAs` (mirrors `links`).")
@@ -990,7 +1049,7 @@ const PlanSchema = z.strictObject({
990
1049
  * anything without a registered template. Add a member here and a matching entry
991
1050
  * in `legal/templates/index.ts` — the two are checked against each other.
992
1051
  */
993
- const JURISDICTIONS = ["ca"];
1052
+ const JURISDICTIONS = ["ca", "qc"];
994
1053
  const JurisdictionSchema = z.enum(JURISDICTIONS);
995
1054
  /**
996
1055
  * The country each template set frames cross-border transfers as *leaving*.
@@ -1005,7 +1064,10 @@ const JurisdictionSchema = z.enum(JURISDICTIONS);
1005
1064
  * `governingCountry`.) `satisfies` makes a new jurisdiction unable to forget it,
1006
1065
  * the same guard style as `TEMPLATES`.
1007
1066
  */
1008
- const JURISDICTION_COUNTRIES = { ca: "Canada" };
1067
+ const JURISDICTION_COUNTRIES = {
1068
+ ca: "Canada",
1069
+ qc: "Quebec"
1070
+ };
1009
1071
  /**
1010
1072
  * A third party that receives personal information. The generator derives the
1011
1073
  * ones it can see (analytics IDs, Turnstile, the deploy platform); this is for
@@ -1083,6 +1145,8 @@ const SiteSectionSchema = z.strictObject({
1083
1145
  url: z.optional(z.url()),
1084
1146
  lastUpdated: z.optional(IsoDate),
1085
1147
  privacyOfficer: desc(z.optional(ContactConfigSchema), "Who privacy requests go to. Falls back to `contact`, then `primaryLocation`."),
1148
+ privacyOfficerTitle: desc(z.optional(z.string()), "Title of the person in charge of the protection of personal information (e.g. \"President\"). Quebec Law 25 requires the title and contact details to be published; the `qc` templates print it beside the `privacyOfficer` contact. Not asserted when absent."),
1149
+ impactAssessments: desc(z.optional(z.boolean()), "Attests that a privacy impact assessment is carried out before personal information is communicated outside Quebec (Law 25, s. 17). The `qc` privacy policy states that assurance only when this is `true` — a fact the config cannot otherwise know, so it is never assumed."),
1086
1150
  retention: desc(z.optional(z.string()), "How long personal information is kept, in prose (e.g. \"24 months after last contact\")."),
1087
1151
  processors: desc(z.optional(z.array(ProcessorSchema)), "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.")
1088
1152
  })),
@@ -1740,4 +1804,4 @@ function formatConfig(value, col = 0, indent = 0) {
1740
1804
  }
1741
1805
 
1742
1806
  export { jsonSchema as A, resolveTheme as C, DesignSystemSchema as D, validateConfig as E, movedTokens as M, SCHEMA_LOCAL_PATH as O, resolvePrivacyContact as S, stripNulls as T, getAt as _, CONFIG_VERSION as a, resolveConfig as b, JURISDICTIONS as c, SiteFontSchema as d, configJsonSchema as f, formatConfig as g, experimentDimensionWarnings as h, CONFIG_SCHEMA_URL as i, validate as j, SCHEMA_URL as k, JURISDICTION_COUNTRIES as l, designSystemPath as m, BIGIN_DATA_CENTERS as n, CRM_PROVIDERS as o, deepMerge as p, CONFIG_SCHEMA_LOCAL_PATH as r, ConfigSchema as s, AD_PROVIDERS as t, PLAN_CAPABILITIES as u, isConfig as v, setAt as w, resolveInput as x, mergePatch as y };
1743
- //# sourceMappingURL=config-BfcWKH-5.mjs.map
1807
+ //# sourceMappingURL=config-D5xuz8--.mjs.map