@universalcms/connect 0.13.4 → 0.18.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.
Files changed (32) hide show
  1. package/README.md +4 -4
  2. package/dist/cli.mjs +4 -3
  3. package/dist/guided.mjs +41 -1
  4. package/dist/native-website-server.mjs +47 -16
  5. package/dist/native-website.mjs +28 -23
  6. package/dist/publication.css +5 -0
  7. package/dist/publication.mjs +10 -4
  8. package/dist/react-publication.mjs +23 -1
  9. package/dist/react-website.d.mts +1 -1
  10. package/dist/react-website.mjs +5 -3
  11. package/dist/templates/next-theme/app/[[...cmsPath]]/page.tsx +13 -4
  12. package/dist/templates/next-theme/app/api/cms-source/route.ts +10 -0
  13. package/dist/templates/next-theme/app/api/universalcms/[endpoint]/route.ts +2 -2
  14. package/dist/templates/next-theme/app/api/universalcms/form/route.ts +8 -0
  15. package/dist/templates/next-theme/app/cms-preview/page.tsx +28 -0
  16. package/dist/templates/next-theme/app/globals.css +94 -10
  17. package/dist/templates/next-theme/app/layout.tsx +11 -1
  18. package/dist/templates/next-theme/app/not-found.tsx +6 -3
  19. package/dist/templates/next-theme/app/robots.txt/route.ts +2 -2
  20. package/dist/templates/next-theme/app/sitemap.xml/route.ts +2 -2
  21. package/dist/templates/next-theme/components/site-chrome.tsx +38 -0
  22. package/dist/templates/next-theme/lib/universalcms.ts +11 -0
  23. package/dist/templates/next-theme/next.config.mjs +17 -1
  24. package/dist/theme-client.d.mts +4 -0
  25. package/dist/theme-client.mjs +70 -0
  26. package/dist/theme-preview.mjs +149 -0
  27. package/dist/theme.d.mts +9 -2
  28. package/dist/theme.mjs +190 -3
  29. package/dist/vendor/react-document.mjs +12 -3
  30. package/dist/vendor/react-preview-protocol.mjs +45 -0
  31. package/dist/website-schema.mjs +19 -4
  32. package/package.json +4 -2
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # @universalcms/connect
2
2
 
3
3
  Local, deterministic website setup without AI. Universal CMS stays hosted; this
4
- package creates a website integration, not a CMS installation. Version 0.13.4 is
4
+ package creates a website integration, not a CMS installation. Version 0.18.0 is
5
5
  prepared locally; this repository does not establish its public npm availability.
6
6
 
7
7
  ## Quick start
@@ -264,7 +264,7 @@ custom adapter still requires review, not forced overwriting.
264
264
  For an operator's downloaded artifact, the installation is:
265
265
 
266
266
  ```sh
267
- npm install --save-prod ./vendor/universalcms-connect-0.13.4.tgz
267
+ npm install --save-prod ./vendor/universalcms-connect-0.18.0.tgz
268
268
  ```
269
269
 
270
270
  Use your project's package manager. These paths are examples for downloaded
@@ -541,7 +541,7 @@ npx --no-install universalcms-connect init \
541
541
  --environment 22222222-2222-4222-8222-222222222222
542
542
  ```
543
543
 
544
- After a public release, `npx @universalcms/connect@0.13.4 init` is the equivalent
544
+ After a public release, `npx @universalcms/connect@0.18.0 init` is the equivalent
545
545
  registry entry point. Copy the real IDs/API origin from **Developer setup**.
546
546
  Missing values are prompted in a terminal; `--non-interactive` fails instead.
547
547
  Init prints a plan. Run the same command with `--apply` after reviewing it.
@@ -591,7 +591,7 @@ The CMS button reads the website's **`/api/cms-source`** endpoint. Current Next.
591
591
  prepares delivery scaffolding. React/Vite setup serves its reviewed public manifest through the normal dev command.
592
592
  Custom exporters need their explicit adapter; a delivery check alone is insufficient.
593
593
 
594
- Use the CMS's reviewed 0.13.4 package for the staged commands and current source
594
+ Use the CMS's reviewed 0.18.0 package for the staged commands and current source
595
595
  discovery. Review source diagnostics and complete public
596
596
  mappings for unsupported pages. Restart the website using its normal server command, then run:
597
597
 
package/dist/cli.mjs CHANGED
@@ -20,7 +20,7 @@ import { WEBSITE_SECTIONS } from './website-http.mjs';
20
20
  import { setupSource, applySourcePlan, syncSource, readSourceSettings } from './source-setup.mjs';
21
21
  import { processIo, runCreate, runGuided } from './guided.mjs';
22
22
 
23
- const help = `Universal CMS connector 0.13.4
23
+ const help = `Universal CMS connector 0.18.0
24
24
 
25
25
  Quick start (recommended) — run in your website folder:
26
26
  npx @universalcms/connect@latest --cms https://YOUR_CMS_ADDRESS
@@ -37,6 +37,7 @@ Quick start (recommended) — run in your website folder:
37
37
 
38
38
  New website managed entirely from the CMS (pages, posts, menus, design):
39
39
  npx @universalcms/connect@latest create my-website --cms https://YOUR_CMS_ADDRESS
40
+ Add --from ../existing-site to bring over its pages and menus (Next.js).
40
41
 
41
42
  Individual steps (advanced):
42
43
  Usage: universalcms-connect <start|inspect-pages|review-pages|preflight|review-routes|review-layout|connect|setup|setup-settings|check-settings|server-key|setup-source|sync-source|finalize-source|analyze|init|check|check-source|check-publication> [options]
@@ -335,7 +336,7 @@ async function ask(prompt) {
335
336
 
336
337
  function guidedArguments(args) {
337
338
  if (args[0] === 'start') args = args.slice(1);
338
- const names = new Set(['--cms', '--code', '--project']), options = {};
339
+ const names = new Set(['--cms', '--code', '--project', '--from']), options = {};
339
340
  for (let index = 0; index < args.length; index++) {
340
341
  const name = args[index];
341
342
  if (Object.hasOwn(options, name)) throw new SetupError('Each option can be given once.');
@@ -356,7 +357,7 @@ async function main() {
356
357
  const options = guidedArguments(rest);
357
358
  if (!process.stdin.isTTY || !process.stderr.isTTY) throw new SetupError('This setup needs an interactive terminal.');
358
359
  const io = processIo({ ask, write: value => process.stdout.write(value) });
359
- await runCreate(process.cwd(), name ?? (await ask('Folder name for the new website: ')).trim(), { cms: options['--cms'], code: options['--code'] }, io);
360
+ await runCreate(process.cwd(), name ?? (await ask('Folder name for the new website: ')).trim(), { cms: options['--cms'], code: options['--code'], from: options['--from'] }, io);
360
361
  return;
361
362
  }
362
363
  if (first === undefined || first === 'start' || first.startsWith('--')) {
package/dist/guided.mjs CHANGED
@@ -21,6 +21,7 @@ import { checkPublication } from './publication-check.mjs';
21
21
  import { finalizeSource } from './source-finalize.mjs';
22
22
  import { preflightSetup } from './preflight.mjs';
23
23
  import { planSettingsOnly, SETTINGS_ONLY_FILE } from './settings-only-setup.mjs';
24
+ import { discoverSite } from './site-discovery.mjs';
24
25
  import { applyEnvironment, planEnvironment } from './setup-environment.mjs';
25
26
  import { themeConfiguration } from './theme.mjs';
26
27
 
@@ -382,6 +383,11 @@ export async function runGuided(directory, options, io) {
382
383
 
383
384
  // A Universal CMS theme website only needs pairing and its private key.
384
385
  if (await readProjectFile(root, THEME_FILE) !== null) {
386
+ const connectedTheme = await readConnection(root).catch(() => null);
387
+ if (connectedTheme && !options.reset && !options.code && (await readSetupEnvironment(root)).keyConfigured && await readProjectFile(root, IMPORT_FILE) !== null) {
388
+ await closeImport(root, connectedTheme, io);
389
+ return themeDone(root, connectedTheme, await packageManager(root, manifest), false, io);
390
+ }
385
391
  const cms = cmsOrigin(options.cms ?? io.env.UNIVERSALCMS_URL ?? '') ?? fail('Add --cms with your Universal CMS address.');
386
392
  const approval = options.code ? { code: options.code } : await waitForBrowserApproval({ cms, io, request: { origin: suggestedOrigin(manifest, null) ?? `http://localhost:${THEME_PORT}`, project: path.basename(root).slice(0, 80), framework: 'Universal CMS theme' } });
387
393
  const paired = await redeem(cms, approval.code, approval.verifier, io.fetch);
@@ -527,6 +533,33 @@ function themeDone(root, connection, manager, created, io) {
527
533
  return { connected: true, mode: 'theme', done: true };
528
534
  }
529
535
 
536
+ export const IMPORT_FILE = '.universalcms/import.json';
537
+
538
+ /** Read a previous Next.js website's pages (text, headings, images, links) and menus, without running it. */
539
+ export async function collectPreviousSite(from, io) {
540
+ const oldRoot = await projectRoot(from).catch(() => fail(`The folder ${from} was not found. Point --from at your existing website folder (the one with package.json).`));
541
+ const manifest = await manifestOf(oldRoot);
542
+ if (!manifest.dependencies?.next && !manifest.devDependencies?.next) fail('Moving content automatically supports Next.js (App Router) websites in this version. Nothing was changed.');
543
+ const { collectSource } = await import('./source-collect.mjs');
544
+ const collected = await collectSource({ root: oldRoot, locale: 'en' });
545
+ const discovered = await discoverSite(oldRoot);
546
+ io.write(`✔ Found ${collected.entries.length} page${collected.entries.length === 1 ? '' : 's'} and ${discovered.navigation.header.length + discovered.navigation.footer.length} menu links in ${path.basename(oldRoot)}\n`);
547
+ if (collected.diagnostics?.unsupported) io.write(` (${collected.diagnostics.unsupported} page${collected.diagnostics.unsupported === 1 ? '' : 's'} with dynamic content were skipped — recreate them in the CMS)\n`);
548
+ return { entries: collected.entries, pages: discovered.pages, navigation: discovered.navigation };
549
+ }
550
+
551
+ /** After the CMS import, the copy of the previous website's content is removed. */
552
+ async function closeImport(root, connection, io) {
553
+ if (await readProjectFile(root, IMPORT_FILE) === null) return;
554
+ const setup = `${connection.adminOrigin}/sites/${connection.siteId}#setup?environmentId=${connection.environmentId}`;
555
+ io.write(`\nNext, bring your previous website's pages and menus into the CMS:\n Start this website (npm run dev), then open Developer setup:\n ${setup}\n Click “Connect & fetch content” and “Import into Header & footer”.\n`);
556
+ await io.openUrl(setup);
557
+ const answer = (await io.ask('\nDid the CMS show “Website content fetched”? [y/N] ')).trim().toLowerCase();
558
+ if (!['y', 'yes'].includes(answer)) { io.write('No problem — the import stays available. Run the same command in this folder again when it is done.\n'); return; }
559
+ await rm(path.join(root, IMPORT_FILE), { force: true });
560
+ io.write('✔ Import finished; the copied content was removed from this folder\n');
561
+ }
562
+
530
563
  /** `create <folder>`: start a new website rendered entirely from Universal CMS. */
531
564
  export async function runCreate(parent, name, options, io) {
532
565
  if (typeof name !== 'string' || !/^[a-z0-9][a-z0-9._-]{0,63}$/i.test(name)) fail('Choose a simple folder name for the new website, for example: my-website');
@@ -541,6 +574,7 @@ export async function runCreate(parent, name, options, io) {
541
574
  }
542
575
  })();
543
576
  io.write(`\nUniversal CMS · create a new website in ${name}\n`);
577
+ const previous = options.from ? await collectPreviousSite(path.resolve(parent, options.from), io) : null;
544
578
  // Copy into a temporary sibling first so a failed copy never leaves a half-made folder.
545
579
  const staging = `${root}.universalcms-${randomBytes(4).toString('hex')}`;
546
580
  await cp(fileURLToPath(new URL('./templates/next-theme/', import.meta.url)), staging, { recursive: true, errorOnExist: true, force: false });
@@ -561,7 +595,13 @@ export async function runCreate(parent, name, options, io) {
561
595
  const paired = await redeem(cms, approval.code, approval.verifier, io.fetch);
562
596
  io.write(`✔ Approved: ${paired.siteName || 'your website'} (${paired.connection.websiteOrigin})\n`);
563
597
  await connectTheme(root, paired, io);
564
- return themeDone(root, paired.connection, 'npm', true, io);
598
+ if (previous) {
599
+ await writeFile(path.join(root, IMPORT_FILE), `${JSON.stringify({ version: 1, siteId: paired.connection.siteId, environmentId: paired.connection.environmentId, ...previous })}\n`);
600
+ io.write('✔ Previous website content saved for import\n');
601
+ }
602
+ const result = themeDone(root, paired.connection, 'npm', true, io);
603
+ if (previous) io.write(`\n Then import your previous content: run “npx @universalcms/connect@latest” inside ${name} and follow the steps.\n`);
604
+ return result;
565
605
  }
566
606
 
567
607
  /** Ask the running website's settings endpoint, as the CMS admin does. */
@@ -11719,10 +11719,17 @@ function CmsForm({ definition, entryId, blockId, revisionId, variant, endpoint,
11719
11719
  // ../react/src/index.tsx
11720
11720
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
11721
11721
  var supported2 = /* @__PURE__ */ new Set(["paragraph", "heading", "quote", "list", "code", "image", "gallery", "button", "divider", "spacer", "faq", "table", "embed", "form", "section", "columns"]);
11722
- var styles = { align: ["left", "center", "right"], size: ["small", "normal", "large"], tone: ["default", "muted", "accent", "inverse"], spaceAbove: ["none", "small", "medium", "large"], spaceBelow: ["none", "small", "medium", "large"], hideOnMobile: [true], hideOnDesktop: [true] };
11722
+ var styles = { align: ["left", "center", "right"], size: ["small", "normal", "large"], tone: ["default", "muted", "accent", "inverse"], spaceAbove: ["none", "small", "medium", "large"], spaceBelow: ["none", "small", "medium", "large"], hideOnMobile: [true], hideOnDesktop: [true], padding: ["none", "small", "medium", "large"], radius: ["none", "small", "medium", "large", "pill"], border: [true], weight: ["normal", "medium", "bold"], maxWidth: ["narrow", "normal", "full"], animation: ["fade-up", "fade-in", "zoom-in", "slide-left"] };
11723
+ function blockColors(block2) {
11724
+ const style = record(block2.style), hex2 = (value) => typeof value === "string" && /^#[0-9a-fA-F]{6}$/.test(value) ? value : void 0;
11725
+ const color = hex2(style.textColor), background = hex2(style.background);
11726
+ if (!color && !background) return void 0;
11727
+ return { ...color ? { "--cms-block-color": color, color } : {}, ...background ? { "--cms-block-background": background, background } : {} };
11728
+ }
11723
11729
  function blockClasses(block2) {
11724
11730
  const style = record(block2.style);
11725
- return ["cms-block", `cms-block-${text(block2.type)}`, ...Object.entries(styles).flatMap(([key, allowed]) => allowed.includes(style[key]) ? [`cms-${key}-${String(style[key])}`] : [])].join(" ");
11731
+ const mobile = record(style.mobile), phone = ["align", "size", "padding", "spaceAbove", "spaceBelow"];
11732
+ return ["cms-block", `cms-block-${text(block2.type)}`, ...Object.entries(styles).flatMap(([key, allowed]) => allowed.includes(style[key]) ? [`cms-${key}-${String(style[key])}`] : []), ...phone.flatMap((key) => styles[key].includes(mobile[key]) ? [`cms-m-${key}-${String(mobile[key])}`] : [])].join(" ");
11726
11733
  }
11727
11734
  function image(data, key) {
11728
11735
  const src = safeUrl(data.url, false);
@@ -11847,7 +11854,7 @@ function CmsDocument({ document: document2, components = {}, entryId, revisionId
11847
11854
  }
11848
11855
  }
11849
11856
  const anchor = text(record(block2.style).anchor);
11850
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { id: /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(anchor) ? anchor : void 0, className: `${blockClasses(block2)}${preview && id2 === selectedId ? " cms-selected" : ""}`, ...preview ? { "data-cms-block": id2, "data-cms-type": type } : {}, children: node }, id2 || index);
11857
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { id: /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(anchor) ? anchor : void 0, className: `${blockClasses(block2)}${preview && id2 === selectedId ? " cms-selected" : ""}`, style: blockColors(block2), ...preview ? { "data-cms-block": id2, "data-cms-type": type } : {}, children: node }, id2 || index);
11851
11858
  }
11852
11859
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: ["cms-document", className].filter(Boolean).join(" "), children: renderMany(document2.blocks, "root") });
11853
11860
  }
@@ -12790,9 +12797,10 @@ function publicEntry(value) {
12790
12797
  const raw = record2(value), entry2 = validatePublishedDocumentEntry(value, { kind: text2(raw.kind, 40), slug: text2(raw.slug, 160), locale: text2(raw.locale, 35) });
12791
12798
  return { ...entry2, ...Object.fromEntries(["path", "seo", "author", "categories", "tags", "translations", "canonicalUrl", "publishedAt"].map((name) => [name, raw[name]])) };
12792
12799
  }
12793
- function CmsWebsitePage({ scope, pathname, initialEntry, initialResult, initialSettings, chrome = true }) {
12800
+ var FormEndpoint = (0, import_react5.createContext)(void 0);
12801
+ function CmsWebsitePage({ scope, pathname, initialEntry, initialResult, initialSettings, chrome = true, formEndpoint }) {
12794
12802
  const path2 = pathname ?? (typeof window === "undefined" ? "/" : window.location.pathname);
12795
- return /* @__PURE__ */ import_react5.default.createElement(WebsitePageLoader, { key: `${scope}:${path2}`, scope, pathname: path2, initialEntry, initialResult, initialSettings, chrome });
12803
+ return /* @__PURE__ */ import_react5.default.createElement(FormEndpoint.Provider, { value: formEndpoint }, /* @__PURE__ */ import_react5.default.createElement(WebsitePageLoader, { key: `${scope}:${path2}`, scope, pathname: path2, initialEntry, initialResult, initialSettings, chrome }));
12796
12804
  }
12797
12805
  function WebsitePageLoader({ scope, pathname, initialEntry, initialResult, initialSettings, chrome }) {
12798
12806
  const [page, setPage] = (0, import_react5.useState)(() => {
@@ -12885,7 +12893,7 @@ function PublishedPage({ entry: entry2, pathname, related }) {
12885
12893
  }, [entry2, presentation.showTableOfContents]);
12886
12894
  const route2 = (0, import_react5.useMemo)(() => ({ identity: { kind: entry2.kind, slug: entry2.slug, locale: entry2.locale }, baseline: entry2.document, bindings: {} }), [entry2]);
12887
12895
  const publishedDate = Number.isFinite(Date.parse(entry2.publishedAt)) ? new Date(entry2.publishedAt).toLocaleDateString(entry2.locale) : "";
12888
- return /* @__PURE__ */ import_react5.default.createElement("main", { className: `cms-website-page cms-website-layout-${presentation.layout}` }, presentation.showBreadcrumbs && /* @__PURE__ */ import_react5.default.createElement("nav", { "aria-label": "Breadcrumbs" }, /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: "/" }, "Home"), /* @__PURE__ */ import_react5.default.createElement("span", { "aria-hidden": "true" }, " / "), /* @__PURE__ */ import_react5.default.createElement("span", { "aria-current": "page" }, entry2.document.title)), /* @__PURE__ */ import_react5.default.createElement("h1", null, entry2.document.title), entry2.document.excerpt && /* @__PURE__ */ import_react5.default.createElement("p", { className: "cms-website-excerpt" }, entry2.document.excerpt), presentation.showDate && publishedDate && /* @__PURE__ */ import_react5.default.createElement("time", { dateTime: entry2.publishedAt }, publishedDate), presentation.showFeaturedImage && presentation.featuredImage.url && /* @__PURE__ */ import_react5.default.createElement("img", { className: "cms-website-featured", src: presentation.featuredImage.url, alt: presentation.featuredImage.alt, referrerPolicy: "no-referrer" }), !!headings.length && /* @__PURE__ */ import_react5.default.createElement("nav", { className: "cms-website-toc", "aria-label": "Table of contents" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "On this page"), /* @__PURE__ */ import_react5.default.createElement("ul", null, headings.map((item) => /* @__PURE__ */ import_react5.default.createElement("li", { key: item.id }, /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: `${pathname}#${encodeURIComponent(item.id)}` }, item.title))))), /* @__PURE__ */ import_react5.default.createElement("div", { ref: content }, /* @__PURE__ */ import_react5.default.createElement(PublishedDocumentProvider, { initialEntry: entry2, pathname, route: route2 }, /* @__PURE__ */ import_react5.default.createElement(CmsPublishedDocument, null))), presentation.author && /* @__PURE__ */ import_react5.default.createElement("aside", { className: "cms-website-author", "aria-label": "About the author" }, presentation.author.avatarUrl && /* @__PURE__ */ import_react5.default.createElement("img", { src: presentation.author.avatarUrl, alt: "", loading: "lazy", referrerPolicy: "no-referrer" }), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", null, presentation.author.url ? /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: presentation.author.url }, presentation.author.name) : presentation.author.name), /* @__PURE__ */ import_react5.default.createElement("p", null, presentation.author.jobTitle), /* @__PURE__ */ import_react5.default.createElement("p", null, presentation.author.bio))), (presentation.categories.length > 0 || presentation.tags.length > 0) && /* @__PURE__ */ import_react5.default.createElement("nav", { className: "cms-website-terms", "aria-label": "Categories and tags" }, [...presentation.categories, ...presentation.tags].map((term2, index) => /* @__PURE__ */ import_react5.default.createElement(SafeLink, { key: `${term2.id}:${index}`, url: term2.path }, term2.name))), presentation.showShare && /* @__PURE__ */ import_react5.default.createElement(SharePage, { title: entry2.document.title, path: entry2.path || pathname }), presentation.showRelated && Array.isArray(related) && related.length > 0 && /* @__PURE__ */ import_react5.default.createElement("aside", { className: "cms-website-related" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "Related content"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "cms-website-cards" }, related.slice(0, 6).map((value, index) => {
12896
+ return /* @__PURE__ */ import_react5.default.createElement("main", { className: `cms-website-page cms-website-layout-${presentation.layout}` }, presentation.showBreadcrumbs && /* @__PURE__ */ import_react5.default.createElement("nav", { "aria-label": "Breadcrumbs" }, /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: "/" }, "Home"), /* @__PURE__ */ import_react5.default.createElement("span", { "aria-hidden": "true" }, " / "), /* @__PURE__ */ import_react5.default.createElement("span", { "aria-current": "page" }, entry2.document.title)), /* @__PURE__ */ import_react5.default.createElement("h1", null, entry2.document.title), entry2.document.excerpt && /* @__PURE__ */ import_react5.default.createElement("p", { className: "cms-website-excerpt" }, entry2.document.excerpt), presentation.showDate && publishedDate && /* @__PURE__ */ import_react5.default.createElement("time", { dateTime: entry2.publishedAt }, publishedDate), presentation.showFeaturedImage && presentation.featuredImage.url && /* @__PURE__ */ import_react5.default.createElement("img", { className: "cms-website-featured", src: presentation.featuredImage.url, alt: presentation.featuredImage.alt, referrerPolicy: "no-referrer" }), !!headings.length && /* @__PURE__ */ import_react5.default.createElement("nav", { className: "cms-website-toc", "aria-label": "Table of contents" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "On this page"), /* @__PURE__ */ import_react5.default.createElement("ul", null, headings.map((item) => /* @__PURE__ */ import_react5.default.createElement("li", { key: item.id }, /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: `${pathname}#${encodeURIComponent(item.id)}` }, item.title))))), /* @__PURE__ */ import_react5.default.createElement("div", { ref: content }, /* @__PURE__ */ import_react5.default.createElement(PublishedDocumentProvider, { initialEntry: entry2, pathname, route: route2, formEndpoint: (0, import_react5.useContext)(FormEndpoint) }, /* @__PURE__ */ import_react5.default.createElement(CmsPublishedDocument, null))), presentation.author && /* @__PURE__ */ import_react5.default.createElement("aside", { className: "cms-website-author", "aria-label": "About the author" }, presentation.author.avatarUrl && /* @__PURE__ */ import_react5.default.createElement("img", { src: presentation.author.avatarUrl, alt: "", loading: "lazy", referrerPolicy: "no-referrer" }), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", null, presentation.author.url ? /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: presentation.author.url }, presentation.author.name) : presentation.author.name), /* @__PURE__ */ import_react5.default.createElement("p", null, presentation.author.jobTitle), /* @__PURE__ */ import_react5.default.createElement("p", null, presentation.author.bio))), (presentation.categories.length > 0 || presentation.tags.length > 0) && /* @__PURE__ */ import_react5.default.createElement("nav", { className: "cms-website-terms", "aria-label": "Categories and tags" }, [...presentation.categories, ...presentation.tags].map((term2, index) => /* @__PURE__ */ import_react5.default.createElement(SafeLink, { key: `${term2.id}:${index}`, url: term2.path }, term2.name))), presentation.showShare && /* @__PURE__ */ import_react5.default.createElement(SharePage, { title: entry2.document.title, path: entry2.path || pathname }), presentation.showRelated && Array.isArray(related) && related.length > 0 && /* @__PURE__ */ import_react5.default.createElement("aside", { className: "cms-website-related" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "Related content"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "cms-website-cards" }, related.slice(0, 6).map((value, index) => {
12889
12897
  const row = record2(value);
12890
12898
  return publicHref(row.path)?.startsWith("/") ? /* @__PURE__ */ import_react5.default.createElement("article", { key: index }, /* @__PURE__ */ import_react5.default.createElement("h3", null, /* @__PURE__ */ import_react5.default.createElement(SafeLink, { url: row.path }, text2(row.title, 200))), /* @__PURE__ */ import_react5.default.createElement("p", null, text2(row.excerpt, 500))) : null;
12891
12899
  }))));
@@ -12987,8 +12995,15 @@ var styleValues = {
12987
12995
  size: ["small", "normal", "large"],
12988
12996
  tone: ["default", "muted", "accent", "inverse"],
12989
12997
  spaceAbove: ["none", "small", "medium", "large"],
12990
- spaceBelow: ["none", "small", "medium", "large"]
12998
+ spaceBelow: ["none", "small", "medium", "large"],
12999
+ padding: ["none", "small", "medium", "large"],
13000
+ radius: ["none", "small", "medium", "large", "pill"],
13001
+ weight: ["normal", "medium", "bold"],
13002
+ maxWidth: ["narrow", "normal", "full"],
13003
+ animation: ["fade-up", "fade-in", "zoom-in", "slide-left"]
12991
13004
  };
13005
+ var mobileStyle = (style) => !own(style, "mobile") || object(style.mobile) && Object.keys(style.mobile).every((key) => ["align", "size", "padding", "spaceAbove", "spaceBelow"].includes(key)) && ["align", "size", "padding", "spaceAbove", "spaceBelow"].every((key) => optionalEnum(style.mobile, key, styleValues[key]));
13006
+ var styleHex = (style, key) => !own(style, key) || typeof style[key] === "string" && /^#[0-9a-fA-F]{6}$/.test(style[key]);
12992
13007
  var optionalEnum = (value, key, choices) => !own(value, key) || choices.includes(value[key]);
12993
13008
  var optionalString = (value, key, max) => !own(value, key) || boundedString(value[key], max);
12994
13009
  var optionalBoolean = (value, key) => !own(value, key) || typeof value[key] === "boolean";
@@ -13043,11 +13058,11 @@ function validDocument(document2) {
13043
13058
  return values.every((block2) => {
13044
13059
  if (!object(block2) || !uuid2.test(block2.id) || ids.has(block2.id) || ids.size >= 400 || block2.version !== 1 || !boundedString(block2.text, 3e4)) return false;
13045
13060
  ids.add(block2.id);
13046
- if (block2.style !== void 0 && (!object(block2.style) || Object.entries(styleValues).some(([key, values2]) => !optionalEnum(block2.style, key, values2)) || !optionalBoolean(block2.style, "hideOnMobile") || !optionalBoolean(block2.style, "hideOnDesktop") || own(block2.style, "anchor") && (!boundedString(block2.style.anchor, 80) || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(block2.style.anchor)))) return false;
13061
+ if (block2.style !== void 0 && (!object(block2.style) || Object.entries(styleValues).some(([key, values2]) => !optionalEnum(block2.style, key, values2)) || !optionalBoolean(block2.style, "hideOnMobile") || !optionalBoolean(block2.style, "hideOnDesktop") || !optionalBoolean(block2.style, "border") || !styleHex(block2.style, "textColor") || !styleHex(block2.style, "background") || !mobileStyle(block2.style) || own(block2.style, "anchor") && (!boundedString(block2.style.anchor, 80) || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(block2.style.anchor)))) return false;
13047
13062
  if (leafTypes.has(block2.type)) return leafData(block2);
13048
13063
  const d = block2.data;
13049
13064
  if (!object(d)) return false;
13050
- if (block2.type === "section" && level === 0) return optionalEnum(d, "background", ["none", "muted", "accent", "dark"]) && optionalEnum(d, "padding", ["none", "small", "medium", "large"]) && optionalEnum(d, "width", ["normal", "wide", "full"]) && blocks(d.blocks, 1, 100);
13065
+ if (block2.type === "section" && level === 0) return optionalEnum(d, "background", ["none", "muted", "accent", "dark"]) && optionalEnum(d, "padding", ["none", "small", "medium", "large"]) && optionalEnum(d, "width", ["normal", "wide", "full"]) && (!own(d, "globalId") || typeof d.globalId === "string" && uuid2.test(d.globalId)) && blocks(d.blocks, 1, 100);
13051
13066
  if (block2.type === "columns" && level < 2) return optionalEnum(d, "layout", ["1-1", "1-2", "2-1", "1-1-1", "1-1-1-1"]) && optionalEnum(d, "gap", ["small", "medium", "large"]) && optionalBoolean(d, "stackOnMobile") && Array.isArray(d.columns) && d.columns.length === (d.layout ?? "1-1").split("-").length && d.columns.every((column) => blocks(column, 2, 50));
13052
13067
  return false;
13053
13068
  });
@@ -13078,12 +13093,13 @@ var dataKeys = {
13078
13093
  table: ["header", "rows"],
13079
13094
  embed: ["url", "provider", "aspect"],
13080
13095
  form: ["formKey", "submitLabel", "successMessage", "consentText"],
13081
- section: ["background", "padding", "width"],
13096
+ section: ["background", "padding", "width", "globalId"],
13082
13097
  columns: ["layout", "gap", "stackOnMobile"]
13083
13098
  };
13084
13099
  function publicBlock(block2) {
13085
13100
  const result = pick(block2, ["id", "type", "version", "text"]);
13086
- if (object(block2.style)) result.style = pick(block2.style, [...Object.keys(styleValues), "hideOnMobile", "hideOnDesktop", "anchor"]);
13101
+ if (object(block2.style)) result.style = pick(block2.style, [...Object.keys(styleValues), "hideOnMobile", "hideOnDesktop", "border", "textColor", "background", "anchor"]);
13102
+ if (result.style && object(block2.style.mobile)) result.style.mobile = pick(block2.style.mobile, ["align", "size", "padding", "spaceAbove", "spaceBelow"]);
13087
13103
  if (object(block2.data)) {
13088
13104
  const data = pick(block2.data, dataKeys[block2.type] ?? []);
13089
13105
  if (block2.type === "gallery") data.images = block2.data.images.map((image2) => pick(image2, ["id", "url", "alt", "width", "height", "srcset"]));
@@ -13849,8 +13865,8 @@ var require_util = __commonJS2({
13849
13865
  function uint8ArrayToBase64url(bytes) {
13850
13866
  return uint8ArrayToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
13851
13867
  }
13852
- function hexToUint8Array(hex) {
13853
- const cleanHex = hex.replace(/^0x/, "");
13868
+ function hexToUint8Array(hex2) {
13869
+ const cleanHex = hex2.replace(/^0x/, "");
13854
13870
  if (cleanHex.length % 2 !== 0) {
13855
13871
  throw new Error("Invalid hex string length");
13856
13872
  }
@@ -32044,7 +32060,7 @@ var require_schemas2 = __commonJS2({
32044
32060
  exports.jwt = jwt;
32045
32061
  exports.stringFormat = stringFormat;
32046
32062
  exports.hostname = hostname;
32047
- exports.hex = hex;
32063
+ exports.hex = hex2;
32048
32064
  exports.hash = hash;
32049
32065
  exports.number = number;
32050
32066
  exports.int = int;
@@ -32630,7 +32646,7 @@ var require_schemas2 = __commonJS2({
32630
32646
  function hostname(_params) {
32631
32647
  return core._stringFormat(exports.ZodCustomStringFormat, "hostname", core.regexes.hostname, _params);
32632
32648
  }
32633
- function hex(_params) {
32649
+ function hex2(_params) {
32634
32650
  return core._stringFormat(exports.ZodCustomStringFormat, "hex", core.regexes.hex, _params);
32635
32651
  }
32636
32652
  function hash(alg, params) {
@@ -34843,7 +34859,11 @@ var link2 = import_zod.z.object({ label: import_zod.z.string().trim().min(1).max
34843
34859
  var links = import_zod.z.array(link2).max(40);
34844
34860
  var headerLink = link2.extend({ url: link2.shape.url.optional(), children: import_zod.z.array(link2).max(20).optional() }).refine((value) => value.url !== void 0 || (value.children?.length ?? 0) > 0, { message: "Header links without dropdown children need a URL", path: ["url"] });
34845
34861
  var footerGroup = import_zod.z.object({ title: import_zod.z.string().trim().min(1).max(80), links: import_zod.z.array(link2).max(20) });
34862
+ var designFonts = ["system", "Inter", "Roboto", "Open Sans", "Lato", "Poppins", "Montserrat", "Nunito", "Merriweather", "Playfair Display", "Lora", "Source Serif 4"];
34863
+ var hex = import_zod.z.string().regex(/^#[0-9a-fA-F]{6}$/);
34864
+ var designColors = import_zod.z.object({ primary: hex, primaryText: hex, background: hex, surface: hex, text: hex, mutedText: hex, border: hex });
34846
34865
  var configurationSchemas = {
34866
+ design: import_zod.z.object({ colors: designColors, typography: import_zod.z.object({ bodyFont: import_zod.z.enum(designFonts), headingFont: import_zod.z.enum(designFonts), baseSize: import_zod.z.number().int().min(14).max(20), headingWeight: import_zod.z.union([import_zod.z.literal(500), import_zod.z.literal(600), import_zod.z.literal(700), import_zod.z.literal(800)]) }), layout: import_zod.z.object({ containerWidth: import_zod.z.number().int().min(720).max(1440), radius: import_zod.z.number().int().min(0).max(24), spacing: import_zod.z.enum(["compact", "comfortable", "spacious"]) }), buttons: import_zod.z.object({ style: import_zod.z.enum(["solid", "outline", "soft"]), shape: import_zod.z.enum(["square", "rounded", "pill"]), uppercase: import_zod.z.boolean() }), header: import_zod.z.object({ layout: import_zod.z.enum(["left", "centered", "split"]), sticky: import_zod.z.boolean(), ctaLabel: import_zod.z.string().max(40), ctaUrl: import_zod.z.string().max(2048) }).optional(), footer: import_zod.z.object({ layout: import_zod.z.enum(["simple", "centered", "columns"]), showSocial: import_zod.z.boolean() }).optional() }),
34847
34867
  branding: import_zod.z.object({ description: import_zod.z.string().max(2e3), logoUrl: url, faviconUrl: url, logoAlt: text3, accentColor: import_zod.z.string().regex(/^#[0-9a-fA-F]{6}$/) }),
34848
34868
  social: import_zod.z.object({ profiles: import_zod.z.array(socialProfile).max(20), alignment: import_zod.z.enum(["left", "center", "right"]).optional() }),
34849
34869
  seo: import_zod.z.object({
@@ -34904,6 +34924,15 @@ var styleSchema = import_zod2.z.object({
34904
34924
  spaceBelow: import_zod2.z.enum(["none", "small", "medium", "large"]).optional(),
34905
34925
  hideOnMobile: import_zod2.z.boolean().optional(),
34906
34926
  hideOnDesktop: import_zod2.z.boolean().optional(),
34927
+ textColor: import_zod2.z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
34928
+ background: import_zod2.z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
34929
+ padding: import_zod2.z.enum(["none", "small", "medium", "large"]).optional(),
34930
+ radius: import_zod2.z.enum(["none", "small", "medium", "large", "pill"]).optional(),
34931
+ border: import_zod2.z.boolean().optional(),
34932
+ weight: import_zod2.z.enum(["normal", "medium", "bold"]).optional(),
34933
+ maxWidth: import_zod2.z.enum(["narrow", "normal", "full"]).optional(),
34934
+ mobile: import_zod2.z.object({ align: import_zod2.z.enum(["left", "center", "right"]).optional(), size: import_zod2.z.enum(["small", "normal", "large"]).optional(), padding: import_zod2.z.enum(["none", "small", "medium", "large"]).optional(), spaceAbove: import_zod2.z.enum(["none", "small", "medium", "large"]).optional(), spaceBelow: import_zod2.z.enum(["none", "small", "medium", "large"]).optional() }).strict().optional(),
34935
+ animation: import_zod2.z.enum(["fade-up", "fade-in", "zoom-in", "slide-left"]).optional(),
34907
34936
  anchor: import_zod2.z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(80).optional()
34908
34937
  });
34909
34938
  var id = import_zod2.z.string().uuid();
@@ -34968,6 +34997,8 @@ var sectionSchema = block("section", import_zod2.z.object({
34968
34997
  background: import_zod2.z.enum(["none", "muted", "accent", "dark"]).default("none"),
34969
34998
  padding: import_zod2.z.enum(["none", "small", "medium", "large"]).default("medium"),
34970
34999
  width: import_zod2.z.enum(["normal", "wide", "full"]).default("normal"),
35000
+ /** Linked to a saved site section: websites show that section's current content. */
35001
+ globalId: import_zod2.z.string().uuid().optional(),
34971
35002
  blocks: import_zod2.z.array(import_zod2.z.union([leafSchema, columnsSchema])).max(100)
34972
35003
  }));
34973
35004
  var blockSchema = import_zod2.z.union([leafSchema, columnsSchema, sectionSchema]);
@@ -35172,7 +35203,7 @@ function serializeNativeWebsite(value) {
35172
35203
  var website_default = ".cms-website { --cms-website-accent: #2563eb; }\n.cms-website-header:empty, .cms-website-footer:empty { display: none; }\n.cms-website-header, .cms-website-footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem clamp(1rem, 4vw, 3rem); color: inherit; background: inherit; }\n.cms-website-header:not(:has(> *)), .cms-website-footer:not(:has(> *)) { display: none; }\n.cms-website-header { border-bottom: 1px solid color-mix(in srgb, currentColor 15%, transparent); }\n.cms-website-footer { border-top: 1px solid color-mix(in srgb, currentColor 15%, transparent); }\n.cms-website a { overflow-wrap: anywhere; }\n.cms-website-header a, .cms-website-footer a, .cms-website-supplement a, .cms-website-page a { color: var(--cms-website-accent); }\n.cms-website-branding { max-width: 40rem; }\n.cms-website-branding img { display: block; max-width: min(15rem, 70vw); max-height: 4rem; width: auto; height: auto; object-fit: contain; }\n.cms-website-branding p { margin: .5rem 0 0; font-size: .9rem; }\n.cms-website-navigation { max-width: 100%; }\n.cms-website-navigation ul, .cms-website-social, .cms-website-languages, .cms-website-terms { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.25rem; margin: 0; padding: 0; list-style: none; }\n.cms-website-navigation a, .cms-website-navigation summary, .cms-website-social a, .cms-website-languages a, .cms-website-terms a { display: inline-flex; gap: .5rem; align-items: center; min-height: 2.75rem; }\n.cms-website-navigation details { position: relative; }\n.cms-website-navigation summary { cursor: pointer; }\n.cms-website-navigation summary::after { content: '\u2304'; margin-inline-start: .3rem; }\n.cms-website-navigation details > ul { position: absolute; z-index: 40; top: 100%; min-width: 12rem; max-width: min(20rem, 85vw); flex-direction: column; align-items: stretch; gap: 0; padding: .5rem 1rem; border: 1px solid #64748b; border-radius: .5rem; color: #0f172a; background: #fff; box-shadow: 0 .5rem 1.5rem #0002; }\n.cms-website-footer-groups { display: flex; gap: 2rem; flex-wrap: wrap; }\n.cms-website-footer-groups h2 { font-size: 1rem; margin: .75rem 0; }\n.cms-website-footer-groups ul { flex-direction: column; align-items: start; gap: 0; }\n.cms-website-social img { width: 1.25rem; height: 1.25rem; object-fit: contain; }\n.cms-website-align-left { justify-content: flex-start; }.cms-website-align-center { justify-content: center; }.cms-website-align-right { justify-content: flex-end; }\n.cms-website-languages [aria-current=page] { font-weight: 700; text-decoration: underline; }\n.cms-website-page { width: min(100% - 2rem, 72rem); margin: 0 auto; padding: 3rem 0; overflow-wrap: anywhere; }\n.cms-website-page.cms-website-layout-narrow, .cms-website-native.cms-website-layout-narrow { max-width: 48rem; margin-inline: auto; }\n.cms-website-page.cms-website-layout-wide { width: min(100% - 2rem, 90rem); }\n.cms-website-native.cms-website-layout-standard { max-width: 80rem; margin-inline: auto; }\n.cms-website-native.cms-website-layout-wide { max-width: 100%; }\n.cms-website-page > h1 { font-size: clamp(2rem, 5vw, 3.5rem); line-height: 1.15; margin: 1rem 0; }\n.cms-website-excerpt { font-size: 1.15rem; line-height: 1.7; }\n.cms-website-featured { display: block; width: 100%; height: auto; max-height: 36rem; object-fit: cover; margin: 1.5rem 0; border-radius: .75rem; }\n.cms-website-toc, .cms-website-author, .cms-website-related { margin-block: 2rem; padding: 1.25rem; border: 1px solid color-mix(in srgb, currentColor 20%, transparent); border-radius: .75rem; }\n.cms-website-toc h2, .cms-website-author h2, .cms-website-related h2 { font-size: 1.25rem; }\n.cms-website-author { display: flex; align-items: flex-start; gap: 1rem; }\n.cms-website-author img { width: 4rem; height: 4rem; object-fit: cover; border-radius: 50%; }\n.cms-website-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); gap: 1.5rem; }\n.cms-website-cards article { padding: 1rem; border: 1px solid color-mix(in srgb, currentColor 20%, transparent); border-radius: .5rem; }\n.cms-website-share { display: flex; gap: .75rem; align-items: center; margin-block: 1rem; }\n.cms-website-share button, .cms-website-preferences, .cms-website-consent button { min-height: 2.75rem; padding: .5rem 1rem; font: inherit; border: 1px solid #64748b; border-radius: .4rem; cursor: pointer; background: transparent; color: inherit; }\n.cms-website-supplement { margin: 1rem clamp(1rem, 4vw, 3rem); }\n.cms-website-consent { position: fixed; z-index: 1000; bottom: 1rem; width: min(32rem, calc(100vw - 2rem)); max-height: calc(100dvh - 2rem); overflow-y: auto; box-sizing: border-box; padding: 1.25rem; border: 1px solid #cbd5e1; border-radius: .75rem; background: #fff; color: #0f172a; box-shadow: 0 .5rem 3rem #0003; font: 1rem/1.5 system-ui, sans-serif; }\n.cms-website-consent h2 { margin: 0 0 .5rem; font-size: 1.25rem; }.cms-website-consent p { margin: .5rem 0; }\n.cms-website-consent fieldset { margin: 1rem 0; padding: .75rem; }.cms-website-consent label { display: flex; align-items: center; gap: .5rem; min-height: 2.75rem; }.cms-website-consent input { width: 1.2rem; height: 1.2rem; }\n.cms-website-consent-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1rem; }\n.cms-website-bottom-left { left: 1rem; }.cms-website-bottom-right { right: 1rem; }.cms-website-bottom-center { left: 50%; transform: translateX(-50%); }\n.cms-website-error { margin: 4rem auto; padding: 1rem; max-width: 48rem; }\n.cms-website :focus-visible { outline: 3px solid var(--cms-website-accent); outline-offset: 3px; }\n@media(max-width: 640px) { .cms-website-header, .cms-website-footer { align-items: stretch; flex-direction: column; }.cms-website-navigation details > ul { position: static; max-width: 100%; }.cms-website-page { padding-block: 1.5rem; }.cms-website-author { flex-wrap: wrap; } }\n";
35173
35204
 
35174
35205
  // native-css:/Users/jasmeet/Codex/Universal-CMS/integrations/react/src/styles.css
35175
- var styles_default = ".cms-document{overflow-wrap:anywhere}.cms-document img{max-width:100%;height:auto}.cms-document pre,.cms-table-scroll{overflow-x:auto}.cms-document figure{margin:0}.cms-document blockquote{border-inline-start:3px solid currentColor;padding-inline-start:1rem}.cms-document table{border-collapse:collapse;width:100%}.cms-document th,.cms-document td{border:1px solid #8886;padding:.6rem;text-align:start}.cms-gallery,.cms-columns{display:grid;gap:1rem}.cms-grid-2,.cms-layout-1-1{grid-template-columns:repeat(2,minmax(0,1fr))}.cms-grid-3,.cms-layout-1-1-1{grid-template-columns:repeat(3,minmax(0,1fr))}.cms-grid-4,.cms-layout-1-1-1-1{grid-template-columns:repeat(4,minmax(0,1fr))}.cms-layout-1-2{grid-template-columns:minmax(0,1fr) minmax(0,2fr)}.cms-layout-2-1{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}.cms-gap-small{gap:.5rem}.cms-gap-large{gap:2rem}.cms-embed{border:0;width:100%;height:auto}.cms-button{display:inline-block;padding:.65rem 1rem;border:1px solid currentColor;border-radius:.4rem}.cms-button-link{border:0;padding:0}.cms-form fieldset{border:0;padding:0;display:grid;gap:1rem}.cms-form-field{display:grid;gap:.35rem}.cms-form input,.cms-form textarea,.cms-form select{font:inherit;max-width:100%;padding:.6rem}.cms-form input[type=checkbox]{margin-inline-end:.5rem}.cms-selected{outline:2px solid #2563eb;outline-offset:3px}.cms-align-left{text-align:left}.cms-align-center{text-align:center}.cms-align-right{text-align:right}.cms-size-small{font-size:.875em}.cms-size-large{font-size:1.25em}.cms-tone-muted{opacity:.75}.cms-tone-accent{color:var(--cms-accent,#2563eb)}.cms-tone-inverse,.cms-section-dark{background:#20242c;color:#fff}.cms-section-muted{background:#8881}.cms-section-accent{background:var(--cms-accent,#2563eb);color:#fff}.cms-padding-small{padding:.75rem}.cms-padding-medium{padding:1.5rem}.cms-padding-large{padding:3rem}.cms-width-normal{max-width:70rem;margin-inline:auto}.cms-width-wide{max-width:90rem;margin-inline:auto}.cms-spaceAbove-small{margin-top:.5rem}.cms-spaceAbove-medium{margin-top:1rem}.cms-spaceAbove-large{margin-top:2rem}.cms-spaceBelow-small{margin-bottom:.5rem}.cms-spaceBelow-medium{margin-bottom:1rem}.cms-spaceBelow-large{margin-bottom:2rem}.cms-spaceAbove-none{margin-top:0}.cms-spaceBelow-none{margin-bottom:0}@media(min-width:641px){.cms-hideOnDesktop-true{display:none}}@media(max-width:640px){.cms-hideOnMobile-true{display:none}.cms-stack,.cms-gallery{grid-template-columns:minmax(0,1fr)}.cms-padding-large{padding:1.5rem}}\n\n.cms-document .cms-block,.cms-document .cms-column{min-width:0}.cms-block-paragraph>p,.cms-block-heading>h2,.cms-block-heading>h3,.cms-block-heading>h4,.cms-block-quote>blockquote,.cms-document figcaption,.cms-block-faq p{white-space:pre-line}.cms-image-align-left{text-align:left}.cms-image-align-center{text-align:center}.cms-image-align-right{text-align:right}.cms-image-align-full img{width:100%}.cms-document .cms-image-align-left img,.cms-document .cms-image-align-center img,.cms-document .cms-image-align-right img{display:inline-block}.cms-gallery img{width:100%;height:auto}.cms-table-scroll:focus-visible{outline:2px solid var(--cms-accent,#2563eb);outline-offset:3px}\n";
35206
+ var styles_default = ".cms-document{overflow-wrap:anywhere}.cms-document img{max-width:100%;height:auto}.cms-document pre,.cms-table-scroll{overflow-x:auto}.cms-document figure{margin:0}.cms-document blockquote{border-inline-start:3px solid currentColor;padding-inline-start:1rem}.cms-document table{border-collapse:collapse;width:100%}.cms-document th,.cms-document td{border:1px solid #8886;padding:.6rem;text-align:start}.cms-gallery,.cms-columns{display:grid;gap:1rem}.cms-grid-2,.cms-layout-1-1{grid-template-columns:repeat(2,minmax(0,1fr))}.cms-grid-3,.cms-layout-1-1-1{grid-template-columns:repeat(3,minmax(0,1fr))}.cms-grid-4,.cms-layout-1-1-1-1{grid-template-columns:repeat(4,minmax(0,1fr))}.cms-layout-1-2{grid-template-columns:minmax(0,1fr) minmax(0,2fr)}.cms-layout-2-1{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}.cms-gap-small{gap:.5rem}.cms-gap-large{gap:2rem}.cms-embed{border:0;width:100%;height:auto}.cms-button{display:inline-block;padding:.65rem 1rem;border:1px solid currentColor;border-radius:.4rem}.cms-button-link{border:0;padding:0}.cms-form fieldset{border:0;padding:0;display:grid;gap:1rem}.cms-form-field{display:grid;gap:.35rem}.cms-form input,.cms-form textarea,.cms-form select{font:inherit;max-width:100%;padding:.6rem}.cms-form input[type=checkbox]{margin-inline-end:.5rem}.cms-selected{outline:2px solid #2563eb;outline-offset:3px}.cms-align-left{text-align:left}.cms-align-center{text-align:center}.cms-align-right{text-align:right}.cms-size-small{font-size:.875em}.cms-size-large{font-size:1.25em}.cms-tone-muted{opacity:.75}.cms-tone-accent{color:var(--cms-accent,#2563eb)}.cms-tone-inverse,.cms-section-dark{background:#20242c;color:#fff}.cms-section-muted{background:#8881}.cms-section-accent{background:var(--cms-accent,#2563eb);color:#fff}.cms-padding-small{padding:.75rem}.cms-padding-medium{padding:1.5rem}.cms-padding-large{padding:3rem}.cms-width-normal{max-width:70rem;margin-inline:auto}.cms-width-wide{max-width:90rem;margin-inline:auto}.cms-spaceAbove-small{margin-top:.5rem}.cms-spaceAbove-medium{margin-top:1rem}.cms-spaceAbove-large{margin-top:2rem}.cms-spaceBelow-small{margin-bottom:.5rem}.cms-spaceBelow-medium{margin-bottom:1rem}.cms-spaceBelow-large{margin-bottom:2rem}.cms-spaceAbove-none{margin-top:0}.cms-spaceBelow-none{margin-bottom:0}@media(min-width:641px){.cms-hideOnDesktop-true{display:none}}@media(max-width:640px){.cms-hideOnMobile-true{display:none}.cms-stack,.cms-gallery{grid-template-columns:minmax(0,1fr)}.cms-padding-large{padding:1.5rem}}\n\n.cms-document .cms-block,.cms-document .cms-column{min-width:0}.cms-block-paragraph>p,.cms-block-heading>h2,.cms-block-heading>h3,.cms-block-heading>h4,.cms-block-quote>blockquote,.cms-document figcaption,.cms-block-faq p{white-space:pre-line}.cms-image-align-left{text-align:left}.cms-image-align-center{text-align:center}.cms-image-align-right{text-align:right}.cms-image-align-full img{width:100%}.cms-document .cms-image-align-left img,.cms-document .cms-image-align-center img,.cms-document .cms-image-align-right img{display:inline-block}.cms-gallery img{width:100%;height:auto}.cms-table-scroll:focus-visible{outline:2px solid var(--cms-accent,#2563eb);outline-offset:3px}\n\n.cms-preview-toolbar{display:flex;gap:2px;padding:3px;border-radius:8px;background:#1c1940;box-shadow:0 6px 18px rgb(0 0 0/18%)}.cms-preview-toolbar button{width:28px;height:28px;border:0;border-radius:6px;background:transparent;color:#fff;font:600 13px/1 system-ui,sans-serif;cursor:pointer}.cms-preview-toolbar button:hover{background:rgb(255 255 255/14%)}.cms-inline-editing{outline:none;cursor:text;caret-color:currentColor}\n.cms-padding-none{padding:0}.cms-padding-small{padding:.75rem}.cms-padding-medium{padding:1.5rem}.cms-padding-large{padding:3rem}.cms-radius-none{border-radius:0}.cms-radius-small{border-radius:.375rem}.cms-radius-medium{border-radius:.75rem}.cms-radius-large{border-radius:1.25rem}.cms-radius-pill{border-radius:999px}.cms-border-true{border:1px solid color-mix(in srgb,currentColor 18%,transparent)}.cms-weight-normal{font-weight:400}.cms-weight-medium{font-weight:500}.cms-weight-bold{font-weight:700}.cms-maxWidth-narrow{max-width:42rem;margin-inline:auto}.cms-maxWidth-normal{max-width:64rem;margin-inline:auto}.cms-maxWidth-full{max-width:none}\n@media (max-width:760px){.cms-m-align-left{text-align:left!important}.cms-m-align-center{text-align:center!important}.cms-m-align-right{text-align:right!important}.cms-m-size-small{font-size:.875em!important}.cms-m-size-normal{font-size:1em!important}.cms-m-size-large{font-size:1.25em!important}.cms-m-padding-none{padding:0!important}.cms-m-padding-small{padding:.75rem!important}.cms-m-padding-medium{padding:1.25rem!important}.cms-m-padding-large{padding:2.5rem!important}.cms-m-spaceAbove-none{margin-top:0!important}.cms-m-spaceAbove-small{margin-top:.5rem!important}.cms-m-spaceAbove-medium{margin-top:1.25rem!important}.cms-m-spaceAbove-large{margin-top:2.5rem!important}.cms-m-spaceBelow-none{margin-bottom:0!important}.cms-m-spaceBelow-small{margin-bottom:.5rem!important}.cms-m-spaceBelow-medium{margin-bottom:1.25rem!important}.cms-m-spaceBelow-large{margin-bottom:2.5rem!important}}\n.cms-preview-drag{display:grid;place-items:center;width:28px;height:28px;border-radius:6px;color:#fff;cursor:grab;font:600 14px/1 system-ui,sans-serif}.cms-preview-drag:hover{background:rgb(255 255 255/14%)}\n";
35176
35207
 
35177
35208
  // src/native-website-server.tsx
35178
35209
  function renderNativeWebsite(value, childrenHtml = "") {