@bettercms-ai/types 1.48.0 → 1.49.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.
- package/dist/index.d.ts +35 -5
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/block.ts","../src/number-format.ts","../src/block-bindings.ts","../src/sectionSpace.ts","../src/blockStyle.ts","../src/component.ts","../src/slot-child.ts","../src/layout-lucide-icons.ts","../src/layout.ts","../src/dock-icon-names.ts","../src/dock-budget.ts","../src/button-link-pairing.ts","../src/button-look.ts","../src/link-value.ts","../src/video-value.ts","../src/table-value.ts","../src/content-model.ts","../src/locator.ts","../src/sections.ts"],"sourcesContent":["/**\n * ContentBlock — a discriminated union of all CMS block types.\n * Each block has a `type` discriminator and a `props` object\n * whose shape matches the block type.\n */\n\nimport type { SectionSpaceToken, SpaceStepToken } from \"./sectionSpace.js\";\nimport type { ButtonIcon, ButtonVariant } from \"./button-look.js\";\n\n// ── Block style (FLO-264) ──────────────────────────────────────────────────────\n// A uniform, BOUNDED set of design tokens any block may carry (sibling to `props`).\n// Tokens map to fixed CSS values in the renderer (`styleTokensToCss`) so styling\n// reaches the live site WITHOUT arbitrary CSS. Additive + fully optional.\n\nexport type SpaceToken = \"none\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\nexport type ColorToken = \"none\" | \"white\" | \"black\" | \"muted\" | \"mutedBg\" | \"primary\" | \"accent\";\nexport type AlignToken = \"left\" | \"center\" | \"right\";\n/** 3xl/4xl/5xl (2.25/3/4rem) were added for headings, whose size now paints on the <hN> itself. */\nexport type FontSizeToken = \"sm\" | \"base\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\" | \"4xl\" | \"5xl\";\nexport type WeightToken = \"normal\" | \"medium\" | \"semibold\" | \"bold\";\nexport type RadiusToken = \"none\" | \"sm\" | \"md\" | \"lg\" | \"full\";\n\n// Section design (task 4) — the per-instance design a section carries on the page.\nexport type ThemeToken = \"inherit\" | \"light\" | \"dark\";\nexport type BgToken = \"none\" | \"surface\" | \"muted\" | \"accent\" | \"dark\" | \"custom\";\nexport type ContentWidthToken = \"narrow\" | \"default\" | \"wide\" | \"full\";\nexport type CornerToken = \"0\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\";\nexport type ShadowToken = \"0\" | \"s\" | \"m\" | \"l\" | \"xl\";\n\nexport interface BlockStyle {\n // Legacy token set (FLO-264). Where these overlap the section fields below\n // (background, radius, padding), the section field WINS in the renderer.\n paddingY?: SpaceToken;\n paddingX?: SpaceToken;\n marginTop?: SpaceToken;\n marginBottom?: SpaceToken;\n background?: ColorToken;\n textColor?: ColorToken;\n align?: AlignToken;\n fontSize?: FontSizeToken;\n weight?: WeightToken;\n radius?: RadiusToken;\n /** A free corner radius in px (0–96), V2's Alt-drag \"Custom · free\" value. Wins over `radius`. */\n radiusPx?: number;\n /** An image cropped to this ratio, filling its column (V2's media frame). @see imageFrameCss */\n aspect?: \"16/9\" | \"16/7\" | \"4/3\" | \"4/5\" | \"1/1\";\n /** The frame's ratio on a phone (≤767px); unset keeps `aspect`. The hosted lane draws it. */\n aspectMobile?: \"16/9\" | \"16/7\" | \"4/3\" | \"4/5\" | \"1/1\";\n /** The block's top gap on a phone (≤767px), in px (0–240); unset keeps `marginTop`. The hosted lane draws it. */\n marginTopMobilePx?: number;\n /** A heading whose column is its measure: the hosted page's heading width limit (`type.headingMeasure`) skips it. */\n measure?: \"column\";\n\n // Section design (task 4).\n theme?: ThemeToken;\n bg?: BgToken;\n /** Only read when `bg === \"custom\"`. Hex only. */\n bgCustom?: string;\n /** Padding sliders, in px (0–240). Legacy: a `space*` token below wins where both are set. */\n paddingTop?: number;\n paddingBottom?: number;\n paddingSides?: number;\n /** Section spacing as token steps (see sectionSpace.ts). Only the top may pull under the nav. */\n spaceTop?: SectionSpaceToken;\n spaceBottom?: Exclude<SectionSpaceToken, \"section-space-nav-overlap\">;\n spaceSides?: SpaceStepToken;\n contentWidth?: ContentWidthToken;\n /** A free content width in px (320–2400), V2's Alt-drag \"Custom · free\" value. Wins over `contentWidth`. */\n contentWidthPx?: number;\n /**\n * Where the constrained content column sits, when `contentWidth` constrains it.\n *\n * Split out of `align`, which still means text alignment and is still the fallback when this\n * is unset — so everything written before the split renders byte-identically. The two were one\n * token until anything MEASURED a section's text alignment: copying a source site's\n * `text-align: left` would otherwise also shove its column to the page edge.\n */\n contentAlign?: AlignToken;\n fullHeight?: boolean;\n /** 0–100. */\n opacity?: number;\n corner?: CornerToken;\n shadow?: ShadowToken;\n borderTop?: boolean;\n borderBottom?: boolean;\n /** All four sides, `1px solid currentColor` — an outline button's border follows its text colour. */\n border?: boolean;\n /** 🔴 The one free-form string. MUST go through `safeCssUrl()` before reaching CSS. */\n bgImage?: string;\n /** A button's look while the pointer is over it. Only the paint changes; unset keys keep the rest. */\n hover?: BlockHoverStyle;\n /**\n * Breakpoints the block is hidden on (`display:none` there only; the block stays in the HTML).\n * All three is \"Hide on this page\": the block is kept for the editor but no published lane\n * emits it (`hiddenEverywhere`, `visibleBlocks`). Bands: see `BREAKPOINTS`.\n */\n hideOn?: Array<\"mobile\" | \"tablet\" | \"desktop\">;\n}\n\n/** The paint a button swaps to on hover: fill, text colour, and the all-round border. */\nexport interface BlockHoverStyle {\n bg?: BgToken;\n bgCustom?: string;\n textColor?: ColorToken;\n border?: boolean;\n}\n\n// ── Visibility window ─────────────────────────────────────────────────────────\n// When a block (or a Layout Section) is shown. A sibling of `style`, not a key of it: a window\n// decides WHETHER the block renders, never how it is painted.\n\n/**\n * Both bounds are INSTANTS: ISO 8601 with an offset, stored normalized to UTC seconds\n * (`2026-11-27T00:00:00Z`). Shown from `from` (inclusive) until `until` (exclusive); a missing\n * bound is open. An absent or null window is always shown.\n */\nexport interface VisibilityWindow {\n from?: string;\n until?: string;\n}\n\nexport type WindowState = \"live\" | \"pending\" | \"expired\";\n\n/** `2026-11-27T09:00+01:00`: a date, a time and an offset. A string with no offset names no instant. */\nconst WINDOW_INSTANT = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?(Z|[+-]\\d{2}:\\d{2})$/;\n\n/**\n * A written window, normalized for storage, or the code it is refused with. null, undefined and\n * an object with neither bound are all \"no window\". UTC at seconds precision makes the stored\n * strings sort in time order, which the due scan (`list_due_window_projects`) relies on.\n */\nexport function normalizeWindow(\n value: unknown,\n): { window: VisibilityWindow | null } | { error: \"invalid_window\" | \"window_inverted\" } {\n if (value == null) return { window: null };\n if (typeof value !== \"object\" || Array.isArray(value)) return { error: \"invalid_window\" };\n const out: VisibilityWindow = {};\n for (const [key, raw] of Object.entries(value as Record<string, unknown>)) {\n if (key !== \"from\" && key !== \"until\") return { error: \"invalid_window\" };\n if (raw == null) continue;\n const at = typeof raw === \"string\" && WINDOW_INSTANT.test(raw) ? Date.parse(raw) : NaN;\n // `Date.parse` rolls 30 February over into March; a day its month does not have is refused.\n const day = Number(String(raw).slice(8, 10));\n if (Number.isNaN(at) || new Date(Date.UTC(Number(String(raw).slice(0, 4)), Number(String(raw).slice(5, 7)) - 1, day)).getUTCDate() !== day) {\n return { error: \"invalid_window\" };\n }\n out[key] = `${new Date(at).toISOString().slice(0, 19)}Z`;\n }\n // Equal bounds are refused too: a window that opens and closes at the same instant never shows.\n if (out.from && out.until && out.from >= out.until) return { error: \"window_inverted\" };\n return { window: out.from || out.until ? out : null };\n}\n\n/**\n * Where `now` falls in a block's or Section's `window`. THE one reading of a window: every\n * renderer, the delivery lanes and the in-place publish decide through it (or `inWindow`).\n *\n * `now` is an argument, never read from a clock here, so one request compares every block\n * against the same instant. Bounds are compared as instants, so a stored offset cannot shift\n * one. A bound that does not parse is read as open: a hand-edited row shows rather than vanishes.\n */\nexport function windowState(item: unknown, now: Date | number): WindowState {\n const w = item && typeof item === \"object\" ? (item as { window?: unknown }).window : undefined;\n if (!w || typeof w !== \"object\") return \"live\";\n const at = typeof now === \"number\" ? now : now.getTime();\n const { from, until } = w as { from?: unknown; until?: unknown };\n const start = typeof from === \"string\" ? Date.parse(from) : NaN;\n const end = typeof until === \"string\" ? Date.parse(until) : NaN;\n if (!Number.isNaN(end) && at >= end) return \"expired\";\n if (!Number.isNaN(start) && at < start) return \"pending\";\n return \"live\";\n}\n\n/** Is the block or Section shown at `now`? No window is always shown. */\nexport const inWindow = (item: unknown, now: Date | number): boolean => windowState(item, now) === \"live\";\n\n/**\n * Is the block hidden on every breakpoint (`style.hideOn` names mobile, tablet AND desktop)? That\n * is the editor's \"Hide on this page\": the block stays in the stored tree, so Show brings it back\n * as it was, but no published lane emits it. Not a window: it does not depend on `now`.\n */\nexport function hiddenEverywhere(item: unknown): boolean {\n const style = item && typeof item === \"object\" ? (item as { style?: unknown }).style : undefined;\n const raw = style && typeof style === \"object\" ? (style as { hideOn?: unknown }).hideOn : undefined;\n return Array.isArray(raw) && raw.includes(\"mobile\") && raw.includes(\"tablet\") && raw.includes(\"desktop\");\n}\n\n/** `list` mapped through `fn`, or `list` itself when `fn` changed nothing. */\nfunction mapSame<T>(list: T[], fn: (item: T) => T): T[] {\n let changed = false;\n const out = list.map((item) => {\n const next = fn(item);\n if (next !== item) changed = true;\n return next;\n });\n return changed ? out : list;\n}\n\n/** A container block with its nested lists pruned (`visibleBlocks`), or the block itself when none changed. */\nfunction withVisibleChildren<B extends { type?: unknown; props?: unknown }>(block: B, now: Date | number): B {\n const p = (block.props ?? {}) as Record<string, unknown>;\n const key = block.type === \"section\" ? \"children\" : block.type === \"columns\" ? \"columns\" : block.type === \"slider\" ? \"slides\" : block.type === \"tabs\" ? \"tabs\" : null;\n if (!key || !Array.isArray(p[key])) return block;\n const held = p[key] as unknown[];\n const next =\n key === \"children\"\n ? visibleBlocks(held, now)\n : key === \"columns\"\n ? mapSame(held, (column) => visibleBlocks(column, now))\n : // A slide or a tab panel: `{ id, children }`.\n mapSame(held, (row) => {\n const children = (row as { children?: unknown } | null)?.children;\n const shown = visibleBlocks(children, now);\n return shown === children ? row : { ...(row as object), children: shown };\n });\n return next === held ? block : { ...block, props: { ...p, [key]: next } };\n}\n\n/**\n * The blocks shown at `now`: every block outside its window, and every block hidden on all\n * breakpoints (`hiddenEverywhere`), removed at any depth (a section's children, columns, slides,\n * tab panels). What a published lane renders, collects from and delivers.\n *\n * Returns the SAME array when nothing is removed, so a tree with no window costs one walk and\n * every consumer downstream is handed exactly what it was handed before windows existed.\n * Non-array input is returned as it came.\n */\nexport function visibleBlocks<T>(blocks: T, now: Date | number): T {\n if (!Array.isArray(blocks)) return blocks;\n const shown = (blocks as unknown[]).filter((block) => inWindow(block, now) && !hiddenEverywhere(block));\n const pruned = mapSame(shown, (block) =>\n block && typeof block === \"object\" ? withVisibleChildren(block as { type?: unknown; props?: unknown }, now) : block,\n );\n return (shown.length === blocks.length && pruned === shown ? blocks : pruned) as T;\n}\n\n// ── Heading ──────────────────────────────────────────────────────────────────\n\nexport interface HeadingProps {\n text: string;\n level?: 1 | 2 | 3;\n}\n\nexport interface HeadingBlock {\n type: \"heading\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: HeadingProps;\n}\n\n// ── Text ─────────────────────────────────────────────────────────────────────\n\nexport interface TextProps {\n html: string;\n /** @see RichTextProps.level — the same payload takes the same level. */\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nexport interface TextBlock {\n type: \"text\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: TextProps;\n}\n\n/**\n * A rich-text block: the same HTML payload as `text`, authored through a real editor.\n *\n * WHY A SEPARATE TYPE RATHER THAN CHANGING `text`. Every `text` block already on a live page\n * holds an HTML string that the delivery renderer injects as-is. Repurposing that type would\n * mean migrating published content, and getting it wrong renders visible markup to visitors.\n * A new type costs nothing at rest and leaves existing pages untouched.\n *\n * The payload is deliberately IDENTICAL to TextProps (an HTML string) so the two are\n * interchangeable at the renderer: delivery treats them the same, and the difference is\n * entirely in how an author edits them — `text` is a plain field, `richtext` gets the\n * formatting surface.\n */\n/**\n * A Portable Text node — the structured form of rich text.\n *\n * Kept alongside `html` rather than replacing it, so nothing already published moves. The\n * structure exists because an HTML string cannot carry INTENT: a colour is a hex with no\n * notion of which brand token produced it, an embedded component is a div with no reference\n * to resolve, and neither can be read back by tooling. Nodes can carry all of that.\n */\nexport interface PortableTextNode {\n _type: string;\n _key?: string;\n /** Block style — \"normal\", \"h2\", \"blockquote\". */\n style?: string;\n text?: string;\n children?: PortableTextNode[];\n /** Marks on a span: \"strong\", \"em\", or a token reference like \"color:brand-accent\". */\n marks?: string[];\n /** An embedded component or reference resolves through these. */\n schemaKey?: string;\n _ref?: string;\n fields?: Record<string, unknown>;\n}\n\nexport interface PortableTextDocument {\n version: 1;\n content: PortableTextNode[];\n}\n\nexport interface RichTextProps {\n /**\n * The RENDERED CACHE. Delivery reads this, so the fast path stays a string interpolation\n * and every page published before `content` existed keeps rendering byte-identically.\n */\n html: string;\n /**\n * The SOURCE OF TRUTH, when present — `content` always wins over `html`.\n *\n * Optional on purpose: this is the same envelope the field values already use\n * (`{ format, value, html }`), where `html` is likewise derived. Any writer that sets\n * `html` alone on a block that HAS `content` must delete `content` in the same write, or\n * the stale string silently shadows the newer structure.\n */\n content?: PortableTextDocument;\n /**\n * Render the rich copy AS `<h1>`–`<h6>` instead of a paragraph container, so a title keeps\n * its inline marks (a brand-coloured span) AND its heading semantics. Absent ⇒ ordinary rich\n * text, as before. Set ⇒ the value must be ONE line of inline copy; the write schema refuses\n * more. A component prop of type `number` or `select` can target `props.level`.\n */\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nexport interface RichTextBlock {\n type: \"richtext\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: RichTextProps;\n}\n\n// ── Image ────────────────────────────────────────────────────────────────────\n\nexport interface ImageProps {\n src: string;\n alt: string;\n width?: number;\n height?: number;\n caption?: string;\n /**\n * THIS placement's focal point (V2's `srcFocal`): 0–1 fractions of the SOURCE picture, drawn as\n * `object-position` inside the crop window `src`'s `?rect=` serves. Absent or null = centred.\n */\n focal?: { x: number; y: number } | null;\n /**\n * THIS placement is decorative (V2's `srcDecorative`): rendered with `alt=\"\"`. The page's own,\n * never the shared media asset's, so one Undo reverses it with the alt.\n */\n decorative?: boolean;\n}\n\nexport interface ImageBlock {\n type: \"image\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: ImageProps;\n}\n\n// ── Button ───────────────────────────────────────────────────────────────────\n\nexport interface ButtonProps {\n text: string;\n href: string;\n /**\n * One of the fixed names, which render `bcms-btn-{variant}`, or the value of a look of the\n * project's own Button family (@see buttonLookValue). Absent ⇒ \"primary\".\n */\n variant?: ButtonVariant | (string & {});\n /** Padding + font-size step. Absent ⇒ \"md\", today's button. sm/lg render `bcms-btn-sm|lg`. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Stretch to the column's width. Absent ⇒ false. true renders `bcms-btn-full`. */\n fullWidth?: boolean;\n /** Draw a trailing arrow after the text. Absent ⇒ false. */\n arrow?: boolean;\n /** A leading icon from `BUTTON_ICONS`. Absent, null or off the list ⇒ none. */\n icon?: ButtonIcon | null;\n /** Open the link in a new tab (`target=\"_blank\" rel=\"noopener noreferrer\"`). Absent ⇒ false. */\n newTab?: boolean;\n /** `nofollow`, `sponsored` or `ugc`; joins the anchor's rel. Absent ⇒ none. */\n rel?: \"nofollow\" | \"sponsored\" | \"ugc\";\n /** `\"code\"`: the click is the site's own script, so it renders `<button type=\"button\">` and `href` is \"\". Absent ⇒ a link. */\n action?: \"code\";\n}\n\nexport interface ButtonBlock {\n type: \"button\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: ButtonProps;\n}\n\n// ── Spacer ───────────────────────────────────────────────────────────────────\n\nexport interface SpacerProps {\n height: number; // in px\n}\n\nexport interface SpacerBlock {\n type: \"spacer\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: SpacerProps;\n}\n\n// ── Columns ───────────────────────────────────────────────────────────────────\n\nexport interface ColumnsProps {\n columns: ContentBlock[][]; // array of column slots, each slot is an array of blocks\n gap?: number; // in px\n}\n\nexport interface ColumnsBlock {\n type: \"columns\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: ColumnsProps;\n}\n\n// ── Video ────────────────────────────────────────────────────────────────────\n\nexport interface VideoProps {\n url: string;\n poster?: string;\n autoplay?: boolean;\n loop?: boolean;\n /**\n * What is said in the video (CPO-093). The block carries its own because its url may be a\n * pasted provider link with no library asset to hang one from. Rendered as <details> after\n * the player and published in the .md twin.\n */\n transcript?: string;\n}\n\nexport interface VideoBlock {\n type: \"video\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: VideoProps;\n}\n\n// ── Form ─────────────────────────────────────────────────────────────────────\n\nexport interface FormProps {\n formId: string; // references forms.id (a nanoid). Resolved against delivered forms at render time.\n}\n\nexport interface FormBlock {\n type: \"form\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: FormProps;\n}\n\n// ── Section (recursive container) ──────────────────────────────────────────────\n\nexport interface SectionProps {\n children: ContentBlock[];\n background?: string;\n paddingY?: number; // in px\n maxWidth?: number; // in px\n}\n\nexport interface SectionBlock {\n type: \"section\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: SectionProps;\n}\n\n// ── Navbar ─────────────────────────────────────────────────────────────────────\n\nexport interface NavLink {\n label: string;\n href: string;\n}\n\nexport interface NavbarProps {\n logo?: { src: string; alt: string; href?: string };\n logoAlt?: string;\n links: NavLink[];\n mobileMenu?: boolean;\n cta?: { text: string; href: string };\n}\n\nexport interface NavbarBlock {\n type: \"navbar\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: NavbarProps;\n}\n\n// ── Footer ─────────────────────────────────────────────────────────────────────\n\nexport interface FooterColumn {\n heading?: string;\n links: NavLink[];\n}\n\nexport interface FooterProps {\n columns: FooterColumn[];\n copyright?: string;\n}\n\nexport interface FooterBlock {\n type: \"footer\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: FooterProps;\n}\n\n// ── Slider / Carousel (recursive container, client-hydrated) ────────────────────\n\nexport interface SlideItem {\n id: string;\n children: ContentBlock[];\n}\n\nexport interface SliderProps {\n slides: SlideItem[];\n autoplay?: boolean;\n interval?: number; // in ms\n loop?: boolean;\n}\n\nexport interface SliderBlock {\n type: \"slider\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: SliderProps;\n}\n\n// ── Tabs (recursive container, client-hydrated) ─────────────────────────────────\n\nexport interface TabItem {\n id: string;\n label: string;\n children: ContentBlock[];\n}\n\nexport interface TabsProps {\n tabs: TabItem[];\n}\n\nexport interface TabsBlock {\n type: \"tabs\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: TabsProps;\n}\n\n// ── Component instance (Webflow-style reusable symbol) ──────────────────────────\n// References a reusable component by id. `overrides` maps a component prop key\n// (declared in the component's `props[]` allowlist) to a value, applied to the\n// component's block tree at render time. Resolved against delivered components.\n\nexport interface ComponentProps {\n componentId: string;\n overrides?: Record<string, unknown>;\n /** Phase A: the page field group this placement renders (its copy + bindings live there). */\n bind?: string;\n /**\n * Phase B: where each override's copy CAME FROM — `{ <propKey>: \"<page field path>\" }`.\n *\n * Written when a placement takes ownership of its copy (`bind` is deleted at the same moment),\n * and it is not decoration:\n * - the COVERAGE METER counts a block-lane declaration\n * (`data-bcms-block=\"<id>\"` + `data-bcms-field=\"<id>__overrides.<propKey>\"`) as bound for\n * the page path named here, so a converted page does not read as a site that lost its\n * bindings;\n * - it is how the componentize lane still recognises WHICH GROUP an instance renders once\n * `bind` is gone — without it a second run would mint a second instance for the same band.\n * A `table` prop names its repeater's path (`faq.items`); every row path under it is that one\n * declaration's, because the prop holds every row.\n */\n source?: Record<string, string>;\n /**\n * A bound placement whose page spells its fields differently from the component's props — a\n * locale copy (`/fr`) placed on its default-locale twin's component: `{ <propKey>: \"<this page's\n * field path>\" }`. Readers resolve a prop's copy through it before `bind`, since the twin's own\n * group keys (`personnalisez-titre`) are not the component's (`customize-title`). Written only\n * while `bind` is; dropped with it when the instance takes its copy.\n */\n bindPaths?: Record<string, string>;\n}\n\nexport interface ComponentBlock {\n type: \"component\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: ComponentProps;\n}\n\n// ── Collection (the entries of the page this block sits on) ─────────────────────\n//\n// LANE-AWARE, and that is the whole idea. A dynamic page's `blockJson` is BOTH what\n// `/blog` renders and the template interpolated into every `/blog/<slug>`. One array\n// cannot be an index and a post layout — unless the one block that differs between them\n// knows which lane it is in. The route supplies that (see CollectionCtx in render-page.ts):\n//\n// /blog → this block renders a card per published entry\n// /blog/my-post → this block renders THAT entry's detail; every other block in the\n// array is interpolated with {{placeholders}} exactly as before\n//\n// So no second template column, no migration, and a page without a collection block\n// behaves byte-identically to before.\n//\n// Scope is IMPLIED by default: a collection lists the entries of the page it sits on, which\n// is precisely the set whose detail URLs are /<thisPage>/<slug>. `source` names another model\n// for a listing that is not that page's own (\"latest posts\" on the home page).\n\nexport interface CollectionProps {\n /** Component rendered once per entry, interpolated with {{field}} and {{url}}. Omit for a built-in card. */\n cardComponentId?: string;\n /** Component rendered for the single entry on a detail URL. Omit to fall back to the generic field layout. */\n detailComponentId?: string;\n /** Built-in card only. Defaults to \"title\" / no excerpt. */\n titleField?: string;\n excerptField?: string;\n /** Max cards to render. Defaults to 20. */\n limit?: number;\n /** \"newest\" (default) reverses the reader's created_at ordering. */\n order?: \"newest\" | \"oldest\";\n emptyText?: string;\n /**\n * List the published entries of ANOTHER model, on any page (\"latest posts\" on the home page).\n * Absent: the entries of the page this block sits on, as above. A model of another project or\n * workspace lists nothing. A sourced block is always a card list, on a detail URL too.\n */\n source?: { modelId: string };\n /** Sourced lists only. The Delivery API's filter grammar; field keys are the model's own. */\n filters?: CollectionFilter[];\n /** Sourced lists only. The Delivery API's sort grammar (`-publishedAt,title`); wins over `order`. */\n sort?: string;\n /** Sourced lists only. Entry ids rendered first, in this order; counted against `limit`. */\n pinnedIds?: string[];\n /** Sourced lists only. On an entry's detail URL, leave that entry out (\"related posts\"). */\n excludeCurrent?: boolean;\n}\n\nexport interface CollectionFilter {\n /** A field key of the source model, or `slug`, `publishedAt`, `locale`. */\n field: string;\n op: \"eq\" | \"ne\" | \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"contains\" | \"in\";\n /** `in` takes a comma-separated list. */\n value: string | number | boolean;\n}\n\nexport interface CollectionBlock {\n type: \"collection\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: CollectionProps;\n}\n\n// ── Union ─────────────────────────────────────────────────────────────────────\n\nexport type ContentBlock =\n | CollectionBlock\n | HeadingBlock\n | TextBlock\n | RichTextBlock\n | ImageBlock\n | ButtonBlock\n | SpacerBlock\n | ColumnsBlock\n | VideoBlock\n | FormBlock\n | SectionBlock\n | NavbarBlock\n | FooterBlock\n | SliderBlock\n | TabsBlock\n | ComponentBlock;\n\n/** Literal union of all block type discriminators. */\nexport type BlockType = ContentBlock[\"type\"];\n\n/**\n * Type guard — narrows an unknown block to `ContentBlock`.\n *\n * @example\n * const block = maybeBlock as unknown;\n * if (isBlock(block)) {\n * // block is ContentBlock here\n * }\n */\nexport function isBlock(value: unknown): value is ContentBlock {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"type\" in value &&\n typeof (value as Record<string, unknown>)[\"type\"] === \"string\"\n );\n}\n\n/**\n * Extract the `type` discriminator from a block, or `null` if not a block.\n *\n * @example\n * const block = { type: \"heading\", id: \"1\", props: { text: \"Hi\" } };\n * getBlockType(block); // \"heading\"\n * getBlockType({ not: \"a block\" }); // null\n */\nexport function getBlockType(value: unknown): BlockType | null {\n if (isBlock(value)) return value.type;\n return null;\n}\n","/**\n * How a `number` field's value is SHOWN: `config.format` on the field.\n *\n * An imported site shows `$1,299.00`, `38%`, `12,000+`, `4 900 €`. The value an author edits and\n * Delivery returns is the number (`1299`, `38`, `12000`, `4900`); everything around the digits is\n * presentation, read once off the built page and kept here. The contract both halves hold:\n *\n * formatNumber(parseNumberText(text).value, parseNumberText(text).format) === text\n *\n * so a page nobody edited is published byte for byte, and an edited value is shown the way the\n * site showed the old one. `parseNumberText` answers null for anything it cannot give back\n * exactly, and that text stays a text field.\n *\n * Pure, and in this package because three programs read it: the import (parse), the publish\n * writers (format) and the dashboard's number input (format, for the preview beside the box).\n */\n\n/** `config.format` of a `number` field. Every key optional; absent = none. */\nexport interface NumberFieldFormat {\n /** Shown before the digits: `$`, `€ `, `+`, `(`, `~`. */\n prefix?: string;\n /** Shown after the digits: `%`, `+`, `k`, ` / month`, ` €`, `)`. */\n suffix?: string;\n /** Thousands separator: `,` `.` ` ` (also no-break and narrow no-break space) `'`. `\"\"` or absent = none. */\n group?: string;\n /** Decimal mark, `.` unless the site writes `,`. */\n decimal?: \".\" | \",\";\n /** Fraction digits always shown (`2` for `£3.20`). A value with more keeps its own, up to six. */\n decimals?: number;\n}\n\nconst GROUPS = [\",\", \".\", \" \", \"\\u00a0\", \"\\u202f\", \"'\", \"\\u2019\"] as const;\n/** Languages that write `1.234,5`: there a lone `.` before three digits is a thousands mark. */\nconst COMMA_DECIMAL = /^(de|es|it|nl|pt|id|tr|da|fr|sv|nb|no|fi|pl|cs|ru|uk|el|ro|hu|sk|sl|hr|bg)\\b/i;\n/** …and of those, the ones that group with a space. */\nconst SPACE_GROUP = /^(fr|sv|nb|no|fi|pl|cs|ru|uk|sk|hu|bg)\\b/i;\n\n/** A magnitude or unit mark that reads as part of the number. Closed: `3D`, `5G` and `1st` are words. */\nconst UNIT = \"(?:[kKmMbBxsdgh]|bn|hr|hrs|min|ms|kg|mg|lb|lbs|oz|km|cm|mm|mi|ft|[kKMGT]B|px|pt|°[CF]?)\";\nconst SUFFIX = new RegExp(`^(?:\\\\s?(?:\\\\p{Sc}|[%‰×]|${UNIT}))?\\\\+?(?:\\\\s?/\\\\s?\\\\p{L}{1,10}){0,2}[)\\\\]*†]?$`, \"u\");\n/** Up to three marks that are no letter, digit, separator or minus: a currency, `+`, `~`, `(`, and a space after. */\nconst PREFIX = /^(?:[^\\p{L}\\p{N}\\s.,'\\u2019#№\\-−–—]{1,3}\\s?)?$/u;\n\nconst fractionDigits = (value: number): number => {\n const text = value.toFixed(6).replace(/0+$/, \"\");\n return text.length - text.indexOf(\".\") - 1;\n};\n\n/** The format a stored `config.format` holds, with anything malformed dropped: a bad row never throws at publish. */\nexport function readNumberFormat(raw: unknown): NumberFieldFormat {\n const o = raw && typeof raw === \"object\" && !Array.isArray(raw) ? (raw as Record<string, unknown>) : {};\n const text = (v: unknown, max: number): string | undefined => (typeof v === \"string\" && v.length <= max && !/\\p{Nd}/u.test(v) ? v : undefined);\n const prefix = text(o.prefix, 8);\n const suffix = text(o.suffix, 24);\n const group = typeof o.group === \"string\" && (GROUPS as readonly string[]).includes(o.group) ? o.group : undefined;\n const decimal = o.decimal === \",\" ? \",\" : undefined;\n const decimals = typeof o.decimals === \"number\" && Number.isInteger(o.decimals) && o.decimals > 0 && o.decimals <= 6 ? o.decimals : undefined;\n return {\n ...(prefix ? { prefix } : {}),\n ...(suffix ? { suffix } : {}),\n // A group mark that is also the decimal mark would print a number nobody can read back.\n ...(group && group !== (decimal ?? \".\") ? { group } : {}),\n ...(decimal ? { decimal } : {}),\n ...(decimals ? { decimals } : {}),\n };\n}\n\n/** The number as the site shows it. A value that is no finite number prints as nothing. */\nexport function formatNumber(value: number, format: NumberFieldFormat = {}): string {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return \"\";\n const places = Math.max(format.decimals ?? 0, Math.min(6, fractionDigits(value)));\n const [int, frac] = Math.abs(value).toFixed(places).split(\".\") as [string, string | undefined];\n const grouped = format.group ? int.replace(/\\B(?=(\\d{3})+(?!\\d))/g, format.group) : int;\n return `${value < 0 ? \"-\" : \"\"}${format.prefix ?? \"\"}${grouped}${frac ? `${format.decimal ?? \".\"}${frac}` : \"\"}${format.suffix ?? \"\"}`;\n}\n\n/**\n * A text that is ONE number and its presentation, or null.\n *\n * Null, on purpose, for: words around the number (`From £2,400`, `3 products`), a leading zero\n * (`01`, `007`: a step marker, a code), digits grouped any other way than in threes (a phone\n * number), two decimal marks (`1.2.3`), a minus (a dash is as often an ornament), an ordinal, and\n * anything `formatNumber` would not print back exactly.\n *\n * `lang` (a BCP 47 tag) settles the one ambiguity, `1.234` and `1,234`, and names the thousands\n * mark of a number too short to show one. `machine`: an attribute a script reads (`data-target`),\n * which is plain digits and stays so.\n */\nexport function parseNumberText(text: string, opts: { lang?: string | null; machine?: boolean } = {}): { value: number; format: NumberFieldFormat } | null {\n if (typeof text !== \"string\" || text.length === 0 || text.length > 40) return null;\n const digits = /\\d/.exec(text);\n if (!digits) return null;\n const start = digits.index;\n const body = /^\\d[\\d.,'\\u2019 \\u00a0\\u202f]*\\d|^\\d/.exec(text.slice(start))![0];\n const prefix = text.slice(0, start);\n const suffix = text.slice(start + body.length);\n if (/\\d/.test(suffix) || !PREFIX.test(prefix) || !SUFFIX.test(suffix)) return null;\n if (opts.machine && (prefix || suffix || !/^\\d+(\\.\\d+)?$/.test(body))) return null;\n // `(213)` closes what it opened, and nothing else may.\n if (/[)\\]]$/.test(suffix) !== /^[([]/.test(prefix)) return null;\n\n const commaLang = COMMA_DECIMAL.test(opts.lang ?? \"\");\n const marks = [...body].filter((c) => !/\\d/.test(c));\n const kinds = [...new Set(marks)];\n let group: string | undefined;\n let decimal: \".\" | \",\" | undefined;\n if (kinds.length > 2) return null;\n if (kinds.length === 2) {\n // Two marks: the last one is the decimal mark, once; the other groups.\n const last = marks[marks.length - 1]!;\n if ((last !== \".\" && last !== \",\") || marks.filter((m) => m === last).length !== 1) return null;\n decimal = last;\n group = kinds.find((k) => k !== last)!;\n } else if (kinds.length === 1) {\n const mark = kinds[0]!;\n const tail = body.slice(body.lastIndexOf(mark) + 1);\n const lone = marks.length === 1 && (mark === \".\" || mark === \",\");\n // `1,5` and `3.20` can only be a decimal; `1,234` reads by the language, `1.234` too.\n const asDecimal = lone && (tail.length !== 3 || body.indexOf(mark) > 3 || /^0/.test(body) || (mark === \".\" ? !commaLang : commaLang));\n if (asDecimal) decimal = mark as \".\" | \",\";\n else group = mark;\n }\n if ((group !== undefined && group === decimal) || (group && !(GROUPS as readonly string[]).includes(group))) return null;\n const [intPart, frac = \"\"] = decimal ? (body.split(decimal) as [string, string?]) : [body];\n const whole = group ? intPart.split(group) : [intPart];\n if (group && (whole.length < 2 || !/^[1-9]\\d{0,2}$/.test(whole[0]!) || whole.slice(1).some((g) => !/^\\d{3}$/.test(g)))) return null;\n const int = whole.join(\"\");\n if (!/^\\d+$/.test(int) || (int.length > 1 && int.startsWith(\"0\")) || int.length + frac.length > 15 || (decimal && !/^\\d+$/.test(frac))) return null;\n\n const value = Number(frac ? `${int}.${frac}` : int);\n // Too short to show a thousands mark: the language's, so `640` edited to `1200` reads `1,200`.\n // Four digits and more with none is the site's own choice (`2019`), kept.\n if (!group && !opts.machine && int.length < 4) group = SPACE_GROUP.test(opts.lang ?? \"\") ? \"\\u00a0\" : commaLang ? \".\" : \",\";\n // A site that groups with `.` (or writes in a language that does) marks its decimals with `,`.\n if (!decimal && (group === \".\" || (commaLang && !opts.machine))) decimal = \",\";\n if (group === (decimal ?? \".\")) group = undefined;\n const format: NumberFieldFormat = {\n ...(prefix ? { prefix } : {}),\n ...(suffix ? { suffix } : {}),\n ...(group ? { group } : {}),\n ...(decimal === \",\" ? { decimal } : {}),\n ...(frac ? { decimals: frac.length } : {}),\n };\n return Number.isFinite(value) && frac.length <= 6 && formatNumber(value, format) === text ? { value, format } : null;\n}\n","/**\n * The ONE declaration of which block props the Visual Editor can address.\n *\n * Four renderers stamp `data-bcms-field` — the hosted renderer, the Next SDK, the Astro SDK\n * and (for minting keys rather than markup) the dashboard's `buildBlockPageDoc`. Until this\n * file existed each carried its own hand-written list, they disagreed by two props, and the\n * dashboard's copy said so in a comment while having nothing to enforce it. A block listed in\n * one and missing from another does not error: it simply never binds, or it binds to a node\n * that resolves to no field. Both failures are silent, which is why they survived.\n *\n * This file is the declaration. The renderers remain the implementation — only they know which\n * ELEMENT carries a value — and `block-binding-coverage.test.ts` asserts the two agree.\n *\n * ── Two kinds of address, because an element is not an attribute ────────────────────────────\n *\n * `data-bcms-field` addresses ONE element. That is enough for a heading's text or an image's\n * src, and not enough for an image's `alt`: the `<img>` already carries a binding, and an\n * element cannot hold two. Entries that name an `attr` are therefore emitted on a SECOND\n * attribute, `data-bcms-props`, whose grammar is:\n *\n * <address>|<kind>|<domAttribute>[;<address>|<kind>|<domAttribute>]*\n *\n * No JSON, because the values are already constrained: an address is grammar A\n * (`[A-Za-z0-9_$-]`, `.`, `[n]`), and kinds and attributes are plain identifiers. A split on\n * two characters parses it, in any language, with no escaping.\n *\n * ── Path templates ──────────────────────────────────────────────────────────────────────────\n *\n * `[]` marks an array the renderer walks. `expandBlockBindings` substitutes real indices from a\n * block's actual props, so `links[].label` on a three-link navbar yields three concrete\n * addresses and on an empty one yields none. `parseFieldPath`/`setFieldPath` in the dashboard\n * have handled N indices since FLO-949; the cap was in what the renderer offered, not in what\n * the writer could persist.\n */\nimport type { ContentBlock, BlockType } from \"./block.js\";\n\n/**\n * How the editor paints a value, and whether it may take a caret.\n *\n * `text`/`richtext` are inline-editable. `image` selects and swaps through the media picker.\n * `url` never takes a caret — a URL typed onto the page has nowhere to report a malformed\n * value — so it is edited in the element toolbar. `array` is a repeater slot: selectable and\n * locatable, edited in the dock.\n *\n * `document` is a whole Portable Text body: selectable as ONE container, repainted whole from the\n * form, and edited per keyed block inside it. It is not a longer `richtext` — a Body stamped\n * `richtext` goes into the rich-text lane, where an opt-out rewrites the value as an `{html}`\n * envelope and the document's own block structure is destroyed.\n */\nexport type BindingKind = \"text\" | \"richtext\" | \"image\" | \"document\" | \"url\" | \"number\" | \"array\";\n\nexport interface BlockBinding {\n /** Path template in grammar A, relative to the block's `props`. `[]` = an array to walk. */\n readonly path: string;\n readonly kind: BindingKind;\n /**\n * The DOM attribute this value lives in, when it is not the element's own text or `src`.\n * Present ⇒ the renderer emits it on `data-bcms-props`, never on `data-bcms-field`.\n */\n readonly attr?: string;\n}\n\n/**\n * Props deliberately absent, and still absent for the original reason:\n *\n * `spacer.height`, `columns.gap`, `section.background` and every `style` token — design, not\n * content. They are edited in the Design accordion, where a slider can express a bounded\n * range that free typing on the page cannot.\n *\n * `text.html` when Portable Text is present — `html` is a cache derived from `content`, so\n * advertising it would persist an ignored sibling and the next frame would read as a revert.\n * The renderer suppresses it; the expander cannot see `content`, so the branch stays there.\n *\n * `component.overrides.*` — instance-scoped, so it cannot be a static template. The renderer\n * derives those addresses per instance from the definition's declared props.\n */\nexport const BLOCK_BINDINGS: Partial<Record<BlockType, readonly BlockBinding[]>> = {\n heading: [{ path: \"text\", kind: \"text\" }],\n text: [{ path: \"html\", kind: \"richtext\" }],\n richtext: [{ path: \"html\", kind: \"richtext\" }],\n image: [\n { path: \"src\", kind: \"image\" },\n { path: \"caption\", kind: \"text\" },\n { path: \"alt\", kind: \"text\", attr: \"alt\" },\n ],\n button: [\n { path: \"text\", kind: \"text\" },\n { path: \"href\", kind: \"url\", attr: \"href\" },\n ],\n video: [\n { path: \"url\", kind: \"url\", attr: \"src\" },\n { path: \"poster\", kind: \"url\", attr: \"poster\" },\n ],\n navbar: [\n { path: \"logo.src\", kind: \"image\" },\n { path: \"logo.alt\", kind: \"text\", attr: \"alt\" },\n { path: \"links[].label\", kind: \"text\" },\n { path: \"links[].href\", kind: \"url\", attr: \"href\" },\n { path: \"cta.text\", kind: \"text\" },\n { path: \"cta.href\", kind: \"url\", attr: \"href\" },\n ],\n footer: [\n { path: \"copyright\", kind: \"text\" },\n { path: \"columns[].heading\", kind: \"text\" },\n { path: \"columns[].links[].label\", kind: \"text\" },\n { path: \"columns[].links[].href\", kind: \"url\", attr: \"href\" },\n ],\n tabs: [{ path: \"tabs[].label\", kind: \"text\" }],\n};\n\n/** One concrete, writable address on one block. */\nexport interface ExpandedBinding extends BlockBinding {\n /** The template with every `[]` replaced by a real index, e.g. `links[2].href`. */\n readonly path: string;\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/**\n * Read a grammar-A path — dotted object keys and zero or more `[n]` indices.\n *\n * Positional, exactly like the dashboard's `parseFieldPath`: a dotted segment is always an\n * object key and a bracketed one always an index, so `links.0` reads the string key \"0\" and\n * misses, rather than being quietly treated as `links[0]`. Any miss returns undefined; nothing\n * here throws, because a template that does not resolve must yield no address, not an error.\n *\n * EXPORTED because a second reader of this grammar now exists: `@bettercms-ai/convert` commits a\n * build-time helper into a customer's repository, and that helper must resolve a path exactly the\n * way the editor does or a converted template renders a fallback where a value exists. The helper\n * itself carries an inlined copy (it lands in a repo where our packages do not exist) and a parity\n * test pins the copy to this original.\n */\nexport function readPath(root: unknown, path: string): unknown {\n let cursor: unknown = root;\n for (const segment of path.split(\".\")) {\n if (!segment) return undefined;\n const key = segment.replace(/\\[\\d+\\]/g, \"\");\n if (key) {\n if (!isRecord(cursor)) return undefined;\n cursor = cursor[key];\n }\n for (const index of segment.matchAll(/\\[(\\d+)\\]/g)) {\n if (!Array.isArray(cursor)) return undefined;\n cursor = cursor[Number(index[1])];\n }\n }\n return cursor;\n}\n\n/** Substitute the FIRST `[]` with every real index, then recurse for any deeper array. */\nfunction expandTemplate(binding: BlockBinding, props: unknown, path: string): ExpandedBinding[] {\n const at = path.indexOf(\"[]\");\n if (at < 0) return [{ ...binding, path }];\n\n const head = path.slice(0, at);\n const tail = path.slice(at + 2);\n const array = readPath(props, head);\n if (!Array.isArray(array)) return [];\n\n return array.flatMap((_item, index) =>\n expandTemplate(binding, props, `${head}[${index}]${tail}`),\n );\n}\n\n/**\n * Every concrete address a block actually offers right now.\n *\n * Array templates expand against the array's real length, so an address is only ever minted\n * for an element that exists. That is the load-bearing property: `setFieldPath` refuses to\n * fabricate an array member, so an address for `links[3]` on a two-link navbar would be a\n * binding the writer rejects — the \"advertises an edit that silently fails\" failure this whole\n * grammar exists to avoid.\n *\n * A prop whose KEY is absent does NOT expand, and that is not a nicety. `setFieldPath` refuses\n * to create a final key unless `createMissingObjects` is set, which only component overrides\n * pass — so an address for a key the block does not carry is a write the editor would reject.\n * An empty string still expands: `\"\"` is a value, and clearing a heading must not make it\n * uneditable.\n */\nexport function expandBlockBindings(block: ContentBlock): ExpandedBinding[] {\n const declared = BLOCK_BINDINGS[block.type];\n if (!declared) return [];\n const props = (block as { props?: unknown }).props;\n if (!isRecord(props)) return [];\n return declared\n .flatMap((binding) => expandTemplate(binding, props, binding.path))\n .filter((binding) => readPath(props, binding.path) !== undefined);\n}\n\n/** The `data-bcms-props` value for a block's attribute bindings, or \"\" when it has none. */\nexport function formatPropsAttribute(\n entries: readonly { address: string; kind: BindingKind; attr: string }[],\n): string {\n return entries.map((e) => `${e.address}|${e.kind}|${e.attr}`).join(\";\");\n}\n\n/** Parse a `data-bcms-props` value. Malformed entries are dropped, never guessed at. */\nexport function parsePropsAttribute(\n value: string | null | undefined,\n): { address: string; kind: BindingKind; attr: string }[] {\n if (!value) return [];\n return value\n .split(\";\")\n .map((entry) => entry.split(\"|\"))\n .filter((parts): parts is [string, BindingKind, string] => parts.length === 3 && parts.every(Boolean))\n .map(([address, kind, attr]) => ({ address, kind, attr }));\n}\n\n/** The shape of a declared component prop this module needs: where it points, and its key. */\ninterface PropTarget {\n key?: string;\n target?: { blockId?: string; path?: string };\n}\n\n/**\n * `<defBlockId>__<prop>` → `<instanceBlockId>__overrides.<propKey>`, for one placed component.\n *\n * Shared by every renderer, because the mapping is a property of the DEFINITION and not of any\n * one output format. A component's block ids belong to the definition and are shared by every\n * instance of it, so `<defBlockId>__text` addresses no instance's value — which is why component\n * subtrees used to render unannotated, and why the SDKs (which never had that suppression)\n * stamped definition-scoped addresses that resolve to no field and, on a component placed twice,\n * collide into a duplicate that drops BOTH copies.\n *\n * The definition already states the mapping in `props[].target`. This only re-keys that\n * statement into the address the editor writes through. Nothing is inferred: a prop with no\n * target produces no entry, so it keeps its dock control and stays uneditable on the canvas,\n * which is the truthful outcome rather than a broken one.\n */\n/**\n * The definition-scoped key a declared prop POINTS AT — `<defBlockId>__<path>`, the same\n * grammar `expandBlockBindings` produces for a block's own bindings.\n *\n * Exported so the \"which leaves does no prop reach?\" check and the address minter below read\n * the key from ONE place. They ask opposite questions of the same mapping, and two spellings\n * of `.replace(/^props\\./, \"\")` is precisely how a leaf ends up counted as bound by one and\n * unbound by the other. Null when the prop declares no target — which is the honest answer:\n * such a prop reaches nothing.\n */\nexport function componentPropTargetKey(prop: PropTarget | undefined): string | null {\n if (!prop?.key || !prop.target?.blockId) return null;\n return `${prop.target.blockId}__${String(prop.target.path ?? \"\").replace(/^props\\./, \"\")}`;\n}\n\n/**\n * `owner` is the address of the rich-text field an instance is EMBEDDED in. Its `_key` is unique\n * only within that field, so the instance is named `<owner>#<_key>` — the same grammar a\n * rich-text node's own address uses — giving `<owner>#<_key>__overrides.<propKey>`.\n */\nexport function componentInstanceAddresses(\n instanceBlockId: string,\n props: readonly PropTarget[] | undefined,\n owner?: string,\n): Map<string, string> {\n const instance = owner ? `${owner}#${instanceBlockId}` : instanceBlockId;\n const out = new Map<string, string>();\n for (const prop of props ?? []) {\n if (!prop?.key || !prop.target?.blockId) continue;\n const from = componentPropTargetKey(prop)!;\n // Two props aimed at one target would make the address ambiguous; first declaration wins\n // and the duplicate is dropped rather than silently overwriting it.\n if (!out.has(from)) out.set(from, `${instance}__overrides.${prop.key}`);\n }\n return out;\n}\n","/**\n * Section spacing as TOKEN STEPS — the ONE list of names and default sizes, shared by the save\n * schema and every renderer. A stored value is always a token (`section-space-large`), never a\n * pixel; it renders as `var(--bcms-section-space-large,88px)`, so a site with a token registry\n * restyles every section at once and a site without one still gets the default rhythm.\n *\n * 🔴 The px table is twinned with the dashboard's `tokenScales.ts` preview table. Change both.\n */\nexport const SECTION_SPACE_TOKENS = [\n \"section-space-none\",\n // V2's six-step band rhythm (None · XS · S · M · L · XL); added after the five, so nothing stored moves.\n \"section-space-xsmall\",\n \"section-space-small\",\n \"section-space-medium\",\n \"section-space-large\",\n \"section-space-xlarge\",\n \"section-space-nav-overlap\",\n] as const;\nexport const SPACE_STEP_TOKENS = [\"space-none\", \"space-s\", \"space-m\", \"space-l\", \"space-xl\"] as const;\n\nexport type SectionSpaceToken = (typeof SECTION_SPACE_TOKENS)[number];\nexport type SpaceStepToken = (typeof SPACE_STEP_TOKENS)[number];\n\n/** A negative band that pulls content under the nav makes sense at the TOP of a section only. */\nexport const SPACE_BOTTOM_TOKENS = SECTION_SPACE_TOKENS.filter(\n (t): t is Exclude<SectionSpaceToken, \"section-space-nav-overlap\"> => t !== \"section-space-nav-overlap\",\n);\n\nconst SPACE_TOKEN_PX: Record<SectionSpaceToken | SpaceStepToken, string> = {\n \"section-space-none\": \"0px\",\n \"section-space-xsmall\": \"16px\",\n \"section-space-small\": \"32px\",\n // V2's band px (site/context.tsx PAD: none 0 · xs 16 · sm 32 · md 56 · lg 88 · xl 128).\n \"section-space-medium\": \"56px\",\n \"section-space-large\": \"88px\",\n \"section-space-xlarge\": \"128px\",\n \"section-space-nav-overlap\": \"-72px\",\n \"space-none\": \"0px\",\n \"space-s\": \"8px\",\n \"space-m\": \"16px\",\n \"space-l\": \"32px\",\n \"space-xl\": \"64px\",\n};\n\n/**\n * What `spaceSides` accepts: the old inner `space-*` steps (still read, as they always rendered)\n * and the section steps the V2 Sides handle writes — the same six as the top and bottom.\n */\nexport const SIDE_SPACE_TOKENS = [...SPACE_STEP_TOKENS, ...SPACE_BOTTOM_TOKENS] as const;\n\n/** V2: side spacing never renders under 16px (`Math.max(16, spacingPx(...))`). */\nexport const SIDE_SPACE_MIN_PX = 16;\n\n/**\n * The side padding for a `spaceSides` token. A section step is floored at 16px as V2 does; an old\n * `space-*` step renders exactly as before, so no stored section moves. \"\" for an unknown token.\n */\nexport function sideSpaceCss(token: unknown): string {\n const css = spaceTokenCss(token);\n if (!css || !(SPACE_BOTTOM_TOKENS as readonly string[]).includes(token as string)) return css;\n return `max(${SIDE_SPACE_MIN_PX}px,${css})`;\n}\n\n/**\n * V2's site gutter: a band's content never touches its edge. The hosted renderer's own section\n * wrapper (`div.bcms-block`) carrying the band rhythm (a top or bottom step or px — only a section\n * carries one) with no side value at all gets 16px sides. Only that wrapper: a site's own section\n * root keeps its own side padding, which an inline 16px would override.\n */\nexport function sideFloorApplies(style: Record<string, unknown>): boolean {\n const band = style.spaceTop !== undefined || style.spaceBottom !== undefined || typeof style.paddingTop === \"number\" || typeof style.paddingBottom === \"number\";\n return band && style.spaceSides === undefined && typeof style.paddingSides !== \"number\" && style.paddingX === undefined;\n}\n\n/** `var(--bcms-<token>,<px>)`, or \"\" for anything that is not a known token (closed set). */\nexport function spaceTokenCss(token: unknown): string {\n const px = typeof token === \"string\" ? SPACE_TOKEN_PX[token as SectionSpaceToken] : undefined;\n return px ? `var(--bcms-${token},${px})` : \"\";\n}\n","/**\n * FLO-264 — bounded block-style tokens → CSS. Framework-agnostic (returns a plain\n * declaration object, no React types) so every renderer shares ONE mapping: the\n * headless @bettercms-ai/next adapter, @bettercms-ai/ui, and (string form) the hosted\n * render-page.ts. Unknown tokens are dropped — closed set, no arbitrary CSS.\n */\nimport type { BlockStyle } from \"./block.js\";\nimport { SPACE_BOTTOM_TOKENS, sideSpaceCss, spaceTokenCss } from \"./sectionSpace.js\";\n\nconst SPACE_PX: Record<string, string> = { none: \"0\", xs: \"4px\", sm: \"8px\", md: \"16px\", lg: \"32px\", xl: \"64px\" };\n// 🔴 Twinned with FONT_SIZE_REM / WEIGHT in src/lib/sites/render-page.ts (the hosted lane) — the\n// cross-lane parity suite (packages/astro/src/__tests__/parity.test.ts) compares them verbatim.\nconst FONT_SIZE_REM: Record<string, string> = {\n sm: \"0.875rem\",\n base: \"1rem\",\n lg: \"1.25rem\",\n xl: \"1.5rem\",\n \"2xl\": \"2rem\",\n \"3xl\": \"2.25rem\",\n \"4xl\": \"3rem\",\n \"5xl\": \"4rem\",\n};\nconst WEIGHT: Record<string, number> = { normal: 400, medium: 500, semibold: 600, bold: 700 };\nconst RADIUS_PX: Record<string, string> = { none: \"0\", sm: \"4px\", md: \"8px\", lg: \"16px\", full: \"9999px\" };\n/**\n * V2's media frame (`aspect-[16/7]` + `cs-r2` on the image wrapper, site/hero.tsx and content.tsx):\n * the picture fills its column, is cropped to the ratio (cover), and takes the theme's large media\n * corner, the card radius x 1.8 as V2's `cs-r2 = calc(var(--cs-r) * 1.8)`. A block's own `radius` /\n * `radiusPx` still wins over that corner. 🔴 Every lane reads this one function (hosted, Next, Astro).\n */\nexport const IMAGE_ASPECTS = [\"16/9\", \"16/7\", \"4/3\", \"4/5\", \"1/1\"] as const;\nexport type ImageAspect = (typeof IMAGE_ASPECTS)[number];\nexport const IMAGE_FRAME_RADIUS = \"calc(var(--bcms-radius-card,14px) * 1.8)\";\nexport function imageFrameCss(style: unknown): { display: \"block\"; width: string; aspectRatio: string; objectFit: \"cover\"; borderRadius?: string } | null {\n if (!style || typeof style !== \"object\") return null;\n const s = style as Record<string, unknown>;\n if (typeof s.aspect !== \"string\" || !(IMAGE_ASPECTS as readonly string[]).includes(s.aspect)) return null;\n const ownRadius = (typeof s.radius === \"string\" && RADIUS_PX[s.radius] != null) || (typeof s.radiusPx === \"number\" && Number.isFinite(s.radiusPx));\n return {\n // Block, as V2's preflight draws an <img>: inline, it sat on a text baseline and the box ran\n // ~7px taller than the picture (445px image in a 452px box at 1280).\n display: \"block\",\n width: \"100%\",\n aspectRatio: s.aspect.replace(\"/\", \" / \"),\n objectFit: \"cover\",\n ...(ownRadius ? {} : { borderRadius: IMAGE_FRAME_RADIUS }),\n };\n}\nconst COLOR_HEX: Record<string, string> = { white: \"#ffffff\", black: \"#111111\", muted: \"#6b7280\", mutedBg: \"#f3f4f6\", primary: \"#111111\", accent: \"#4f46e5\" };\n\n// Section design (theme, fill, image, corners, shadow, content column). 🔴 Twinned with THEME_CSS,\n// BG_HEX, CORNER_PX, SHADOW_CSS, HAIRLINE and CONTENT_WIDTH_PX in src/lib/sites/render-page.ts;\n// src/__tests__/sites/block-style-parity.test.ts pins the two lanes to the same declarations.\nconst THEME: Record<string, { colorScheme: string; background: string; color: string }> = {\n light: { colorScheme: \"light\", background: \"#ffffff\", color: \"#111111\" },\n dark: { colorScheme: \"dark\", background: \"#0b0b0d\", color: \"#f7f8f8\" },\n};\nconst BG_HEX: Record<string, string> = {\n surface: \"var(--bcms-bg-surface,#ffffff)\",\n muted: \"var(--bcms-bg-muted,#f3f4f6)\",\n accent: \"var(--bcms-bg-accent,#4f46e5)\",\n dark: \"var(--bcms-bg-dark,#0b0b0d)\",\n};\n// Under `theme:\"dark\"` the light palette's fills resolve to the dark scheme's own (V2 `themeVars`).\n// Twin: DARK_BG_HEX in render-page.ts.\nconst DARK_BG_HEX: Record<string, string> = { surface: \"#0b0b0d\", muted: \"#1c1c1e\" };\n// A fill that IS a scheme brings its text (V2 `themeVars`: dark = paper on ink, brand = light text on\n// the brand fill). The accent text is WCAG-derived from the real accent (`--bcms-on-accent`). Twin:\n// FILL_SCHEME_CSS in render-page.ts.\nconst FILL_SCHEME: Record<string, { colorScheme: string; color: string }> = {\n dark: { colorScheme: \"dark\", color: \"#f7f8f8\" },\n accent: { colorScheme: \"var(--bcms-accent-scheme,dark)\", color: \"var(--bcms-on-accent,#ffffff)\" },\n};\nconst CORNER_PX: Record<string, string> = { \"0\": \"0\", s: \"4px\", m: \"8px\", l: \"16px\", xl: \"24px\", \"2xl\": \"32px\" };\nconst SHADOW_CSS: Record<string, string> = {\n \"0\": \"none\",\n s: \"0 1px 2px rgba(0,0,0,.06)\",\n m: \"0 4px 12px rgba(0,0,0,.08)\",\n l: \"0 10px 24px rgba(0,0,0,.10)\",\n xl: \"0 24px 48px rgba(0,0,0,.14)\",\n};\nconst HAIRLINE = \"1px solid rgba(0,0,0,.10)\";\n/** `full` is absent on purpose: a full-width column has no max-width, so no inner box at all. */\nconst CONTENT_WIDTH_PX: Record<string, string> = { narrow: \"640px\", default: \"1024px\", wide: \"1280px\" };\n\n/**\n * Where a block's `hideOn` bands start and end: mobile at most 767px, tablet 768-1023px, desktop\n * 1024px and up (the dock's 390 / 810 / 1280 canvases fall one in each band). A site's CSS\n * carries these numbers, so changing one shifts every published site's media queries.\n */\nexport const BREAKPOINTS = { mobile: 767, tablet: 1023 } as const;\n\n/**\n * The ONE stylesheet behind `data-bcms-hide=\"mobile tablet\"`. `!important` because a block's own\n * inline `display` (`fullHeight` writes `display:flex`) would otherwise beat it. `display:none`\n * also takes the block out of the accessibility tree at that width. Hosted pages inline it in\n * the head, `<BcmsBlocks>` emits it when a block uses `hideOn`, and a site that renders its own\n * markup puts it in its global CSS.\n */\nexport const RESPONSIVE_CSS =\n `@media(max-width:${BREAKPOINTS.mobile}px){[data-bcms-hide~=\"mobile\"]{display:none!important}}` +\n `@media(min-width:${BREAKPOINTS.mobile + 1}px) and (max-width:${BREAKPOINTS.tablet}px){[data-bcms-hide~=\"tablet\"]{display:none!important}}` +\n `@media(min-width:${BREAKPOINTS.tablet + 1}px){[data-bcms-hide~=\"desktop\"]{display:none!important}}`;\n\n/**\n * The `data-bcms-hide` value for a block style (`\"mobile tablet\"`), or \"\" when it hides nowhere.\n * Closed set, fixed order, so a hand-edited row cannot put anything else into an attribute.\n * All three is \"\" too: such a block is not emitted on a published lane at all (`visibleBlocks`),\n * and the editor's lane draws it whole, marked `data-bcms-hidden`, so the author can find it.\n */\nexport function hideOnAttr(style: unknown): string {\n const raw = style && typeof style === \"object\" ? (style as { hideOn?: unknown }).hideOn : undefined;\n if (!Array.isArray(raw)) return \"\";\n const on = ([\"mobile\", \"tablet\", \"desktop\"] as const).filter((b) => raw.includes(b));\n return on.length === 3 ? \"\" : on.join(\" \");\n}\n\n/** True when any block in the tree hides somewhere; lets a lane skip `RESPONSIVE_CSS` when unused. */\nexport function usesHideOn(blocks: unknown): boolean {\n let found = false;\n // A replacer visits every key at any depth, so columns, slides and component trees are covered.\n JSON.stringify(blocks ?? null, (k, v) => {\n if (k === \"hideOn\" && hideOnAttr({ hideOn: v })) found = true;\n return v;\n });\n return found;\n}\n\nconst HEX = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;\n\nconst clamp = (n: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, n));\n/** A map entry by OWN key only, so a token like `constructor` can never reach CSS. */\nconst own = <T>(map: Record<string, T>, key: unknown): T | undefined =>\n typeof key === \"string\" && Object.prototype.hasOwnProperty.call(map, key) ? map[key] : undefined;\n\n/**\n * 🔴 The ONE place a free-form string is allowed near CSS: `bgImage` is author-supplied, so it is\n * rejected — never escaped — unless it is an http(s) or root-relative url with nothing that could\n * end a `url(…)` token or start a new declaration (quotes, parens, backslash, `;`, whitespace).\n * Returns \"\" for anything it does not fully trust. Twin of `safeCssUrl` in render-page.ts.\n */\nexport function safeCssUrl(raw: unknown): string {\n if (typeof raw !== \"string\") return \"\";\n const url = raw.trim();\n if (!url || url.length > 2000) return \"\";\n if (/[\"'()\\\\;]|\\s/.test(url)) return \"\";\n if (url.startsWith(\"//\")) return \"\";\n if (url.startsWith(\"/\")) return url;\n return /^https?:\\/\\//i.test(url) ? url : \"\";\n}\n\n/** A CSS declaration object (key → value) usable as a React `style` prop, or undefined when empty. */\nexport function blockStyleToCss(style: BlockStyle | undefined): Record<string, string | number> | undefined {\n if (!style || typeof style !== \"object\") return undefined;\n const s = style as Record<string, string>;\n const css: Record<string, string | number> = {};\n if (s.paddingY && SPACE_PX[s.paddingY] != null) { css.paddingTop = SPACE_PX[s.paddingY]!; css.paddingBottom = SPACE_PX[s.paddingY]!; }\n if (s.paddingX && SPACE_PX[s.paddingX] != null) { css.paddingLeft = SPACE_PX[s.paddingX]!; css.paddingRight = SPACE_PX[s.paddingX]!; }\n // Token steps win over the legacy padding above: they are what the section design panel writes.\n const top = spaceTokenCss(s.spaceTop);\n const bottom = (SPACE_BOTTOM_TOKENS as readonly string[]).includes(s.spaceBottom ?? \"\") ? spaceTokenCss(s.spaceBottom) : \"\";\n const sides = sideSpaceCss(s.spaceSides);\n const navOverlap = s.spaceTop === \"section-space-nav-overlap\";\n if (top && !navOverlap) css.paddingTop = top;\n if (bottom) css.paddingBottom = bottom;\n if (sides) { css.paddingLeft = sides; css.paddingRight = sides; }\n if (s.marginTop && SPACE_PX[s.marginTop] != null) css.marginTop = SPACE_PX[s.marginTop]!;\n // Nav-overlap is the one NEGATIVE step, and negative padding is invalid (computes 0): under a\n // sticky nav the background slides up (negative margin, set after the legacy margin so the token\n // wins) and the content clears it (the same length back as padding), as in `styleTokensToCss`.\n if (top && navOverlap) { css.marginTop = top; css.paddingTop = `calc(-1 * ${top})`; }\n if (s.marginBottom && SPACE_PX[s.marginBottom] != null) css.marginBottom = SPACE_PX[s.marginBottom]!;\n if (s.background && COLOR_HEX[s.background]) css.background = COLOR_HEX[s.background]!;\n if (s.textColor && COLOR_HEX[s.textColor]) css.color = COLOR_HEX[s.textColor]!;\n if (s.align === \"left\" || s.align === \"center\" || s.align === \"right\") css.textAlign = s.align;\n if (s.fontSize && FONT_SIZE_REM[s.fontSize]) css.fontSize = FONT_SIZE_REM[s.fontSize]!;\n if (s.weight && WEIGHT[s.weight] != null) css.fontWeight = WEIGHT[s.weight]!;\n if (s.radius && RADIUS_PX[s.radius] != null) css.borderRadius = RADIUS_PX[s.radius]!;\n const rpx = (style as Record<string, unknown>).radiusPx;\n if (typeof rpx === \"number\" && Number.isFinite(rpx)) css.borderRadius = `${clamp(Math.round(rpx), 0, 96)}px`;\n\n // ── Section design ─────────────────────────────────────────────────────────\n // The same precedence as the hosted `styleTokensToCss`: theme before `bg` (so an explicit fill\n // wins), a token step before the px slider, `corner` over the legacy `radius`, and the legacy\n // all-round `border` last. Keys a later rule overrides keep their first position, so a style\n // without these tokens produces exactly the object it always did.\n const theme = own(THEME, s.theme);\n if (theme) { css.colorScheme = theme.colorScheme; css.background = theme.background; css.color = theme.color; }\n if (s.bg === \"custom\") { if (HEX.test(s.bgCustom ?? \"\")) css.background = s.bgCustom!; }\n else if (own(BG_HEX, s.bg)) {\n css.background = (s.theme === \"dark\" && own(DARK_BG_HEX, s.bg)) || own(BG_HEX, s.bg)!;\n const fill = own(FILL_SCHEME, s.bg);\n if (fill) { css.colorScheme = fill.colorScheme; css.color = fill.color; }\n }\n const bgImage = safeCssUrl(s.bgImage);\n // Unquoted, as on the hosted lane: `safeCssUrl` already refuses every character that could end it.\n if (bgImage) { css.backgroundImage = `url(${bgImage})`; css.backgroundSize = \"cover\"; css.backgroundPosition = \"center\"; }\n const n = style as Record<string, unknown>;\n if (!top && typeof n.paddingTop === \"number\") css.paddingTop = `${clamp(n.paddingTop, 0, 240)}px`;\n if (!bottom && typeof n.paddingBottom === \"number\") css.paddingBottom = `${clamp(n.paddingBottom, 0, 240)}px`;\n if (!sides && typeof n.paddingSides === \"number\") {\n const px = `${clamp(n.paddingSides, 0, 240)}px`;\n css.paddingLeft = px; css.paddingRight = px;\n }\n if (n.fullHeight === true) { css.minHeight = \"100vh\"; css.display = \"flex\"; css.flexDirection = \"column\"; css.justifyContent = \"center\"; }\n if (typeof n.opacity === \"number\") css.opacity = clamp(n.opacity, 0, 100) / 100;\n // overflow:hidden so a background image / child corner actually clips to the radius.\n if (own(CORNER_PX, s.corner) != null) { css.borderRadius = own(CORNER_PX, s.corner)!; css.overflow = \"hidden\"; }\n if (own(SHADOW_CSS, s.shadow)) css.boxShadow = own(SHADOW_CSS, s.shadow)!;\n if (n.borderTop === true) css.borderTop = HAIRLINE;\n if (n.borderBottom === true) css.borderBottom = HAIRLINE;\n if ((style as BlockStyle).border === true) css.border = \"1px solid currentColor\";\n return Object.keys(css).length ? css : undefined;\n}\n\n/**\n * The content column: the declarations for the INNER box a renderer nests between a block's\n * style wrapper (`blockStyleToCss`, which carries the full-bleed background) and the block itself.\n * The outer box can't constrain width without shrinking its own background, so a width needs a\n * second box. `undefined` when there is no column (no `contentWidth`, `full`, or unknown) — a\n * renderer then emits no inner box at all.\n *\n * Placement is `contentAlign`, falling back to `align`. `align` alone used to mean both text\n * alignment (outer box) and column placement (here); `contentAlign` split them, and the fallback\n * keeps every style written before the split rendering identically. Twin: `styleTokensToInnerCss`\n * in render-page.ts, which the hosted lane serialises as `max-width:…;margin:…`.\n */\nexport function blockStyleToInnerCss(style: BlockStyle | undefined): { maxWidth: string; margin: string } | undefined {\n if (!style || typeof style !== \"object\") return undefined;\n const s = style as Record<string, string>;\n const free = (style as Record<string, unknown>).contentWidthPx;\n const max = typeof free === \"number\" && Number.isFinite(free) ? `${clamp(Math.round(free), 320, 2400)}px` : own(CONTENT_WIDTH_PX, s.contentWidth);\n if (!max) return undefined;\n const placement = s.contentAlign ?? s.align;\n const margin = placement === \"left\" ? \"0 auto 0 0\" : placement === \"right\" ? \"0 0 0 auto\" : \"0 auto\";\n return { maxWidth: max, margin };\n}\n\n/**\n * HEADING-STYLE-PAINT — a heading's own size and weight, for the `<hN>` element itself.\n *\n * `blockStyleToCss` puts `fontSize`/`fontWeight` on the block's WRAPPER, where a heading ignores\n * them: the UA `hN{font-weight:bold}` beats the inherited weight at every level, and the UA em\n * size MULTIPLIES the wrapper's (an h2 is 1.5em of it). Painting the same two tokens inline on\n * the heading makes them absolute and exact. The wrapper keeps them too, unchanged, so no DOM or\n * wrapper byte moves; a heading that sets neither gets `undefined` ⇒ no `style` attribute at all.\n *\n * `h1SizeSet` — B9: when the hosted page's presentation sets `type.h1Size`, that owns the size of\n * every h1, so the per-element size is skipped on an h1 (weight still paints). The SDK lanes have\n * no presentation manifest and never pass it. PRESENTATION-HEADING-SCALE will extend the same\n * rule to h2–h6 once per-level knobs exist.\n *\n * Key order is fontSize then fontWeight on every lane, so the parity suite compares verbatim.\n */\nexport function headingPaintCss(\n style: BlockStyle | undefined,\n opts: { level?: number; h1SizeSet?: boolean } = {},\n): { fontSize?: string; fontWeight?: number } | undefined {\n if (!style || typeof style !== \"object\") return undefined;\n const s = style as Record<string, string>;\n const css: { fontSize?: string; fontWeight?: number } = {};\n const sizeOwnedByPresentation = opts.level === 1 && opts.h1SizeSet === true;\n if (!sizeOwnedByPresentation && s.fontSize && FONT_SIZE_REM[s.fontSize]) css.fontSize = FONT_SIZE_REM[s.fontSize]!;\n if (s.weight && WEIGHT[s.weight] != null) css.fontWeight = WEIGHT[s.weight]!;\n return css.fontSize !== undefined || css.fontWeight !== undefined ? css : undefined;\n}\n\n/**\n * Style keys that PLACE a block. A button keeps only these on its wrapper; the rest paints the\n * `<a>` itself. On the wrapper (where every other block's style goes) a fill, theme or corner\n * painted a box BEHIND the anchor, which kept its variant's own fill. 🔴 Twin of `PLACEMENT_KEYS`\n * in src/lib/sites/render-page.ts; src/__tests__/sites/block-style-parity.test.ts pins the two.\n */\nexport const BUTTON_PLACEMENT_KEYS = [\n \"align\",\n \"contentAlign\",\n \"contentWidth\",\n \"marginTop\",\n \"marginBottom\",\n \"fullHeight\",\n \"spaceTop\",\n \"spaceBottom\",\n \"hideOn\",\n] as const;\nconst PLACEMENT = new Set<string>(BUTTON_PLACEMENT_KEYS);\n\n/**\n * A button's style split in two: `placement` (the keys its wrapper keeps — feed it to\n * `blockStyleToCss` / `blockStyleToInnerCss` exactly like any block's style) and `paint`, the\n * declarations for the `<a>` itself. `bg: \"none\"` paints the anchor transparent (and inherits the\n * text colour unless one is set), so it clears the variant's fill instead of doing nothing.\n * `hover` is not painted: the hosted lane draws it with classes its own stylesheet styles.\n * Either half is `undefined` when empty, so an unstyled button gets no wrapper and no `style`.\n */\nexport function splitButtonStyle(style: BlockStyle | undefined): {\n placement: BlockStyle | undefined;\n paint: Record<string, string | number> | undefined;\n} {\n if (!style || typeof style !== \"object\") return { placement: undefined, paint: undefined };\n const placement: Record<string, unknown> = {};\n const rest: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(style)) {\n if (k === \"hover\") continue;\n (PLACEMENT.has(k) ? placement : rest)[k] = v;\n }\n const paint = { ...blockStyleToCss(rest as BlockStyle) };\n if (rest.bg === \"none\") {\n paint.background = \"transparent\";\n if (!rest.textColor) paint.color = \"inherit\";\n }\n return {\n placement: Object.keys(placement).length ? (placement as BlockStyle) : undefined,\n paint: Object.keys(paint).length ? paint : undefined,\n };\n}\n\n// ── Field styles (C3, imported sites) ─────────────────────────────────────────\n\n/**\n * The style keys a PAGE FIELD takes (`pages.field_styles`, keyed by field path): its width and\n * placement, the space above and below it, its text alignment, font size and weight, and `size` — a\n * whole element's Small / Large (a button's). Every key but `size` is a `BlockStyle` key, so it\n * keeps the token set and the CSS table it already has — a field never gets a second scale.\n * 🔴 Twin: `FIELD_STYLE_KEYS` in the dashboard's fieldStyle.ts.\n */\nexport const FIELD_STYLE_KEYS = [\"contentWidth\", \"contentAlign\", \"marginTop\", \"marginBottom\", \"align\", \"fontSize\", \"weight\", \"size\"] as const;\nexport type FieldStyleKey = (typeof FIELD_STYLE_KEYS)[number];\n/** A field element's Small / Large. Medium is UNSET — no \"md\" token is ever stored. */\nexport type FieldSize = \"sm\" | \"lg\";\n/**\n * `size` → the element's `zoom`, which scales the WHOLE element (padding, font, icon, border) — what\n * Small / Large mean for a button whose CSS the site wrote. Any other value (`md` included) paints\n * nothing. 🔴 Inlined in the convert helper (`STYLE_SIZE_ZOOM`), parity-tested against this table.\n */\nexport const FIELD_SIZE_ZOOM: Readonly<Record<FieldSize, string>> = { sm: \"0.875\", lg: \"1.125\" };\n/** One field's style. */\nexport type FieldStyle = Pick<BlockStyle, Exclude<FieldStyleKey, \"size\">> & { size?: FieldSize };\n/** A page's field styles, keyed by field path (the `data-bcms-field` address). */\nexport type FieldStyles = Record<string, FieldStyle>;\n\nconst FIELD_KEY_SET = new Set<string>(FIELD_STYLE_KEYS);\n\n/** Only the field keys of `style` (an empty object for none). */\nexport function pickFieldStyle(style: BlockStyle | Record<string, unknown> | null | undefined): FieldStyle {\n const out: Record<string, unknown> = {};\n if (!style || typeof style !== \"object\") return out as FieldStyle;\n for (const [k, v] of Object.entries(style)) if (FIELD_KEY_SET.has(k) && v != null) out[k] = v;\n return out as FieldStyle;\n}\n\n/**\n * A field's declarations, for its OWN element (`fieldAttrs`). Spacing, alignment, size and weight are\n * `blockStyleToCss`'s. The width is `blockStyleToInnerCss`'s column, drawn on the element itself —\n * a field has no wrapper to nest a column in — so its placement becomes left/right margins, and\n * the vertical margins the spacing set stay. `size` (`FIELD_SIZE_ZOOM`) is LAST, so a style without\n * it keeps the exact declarations, in the exact order, it always had. `undefined` when nothing\n * applies (no `style` at all).\n */\nexport function fieldStyleToCss(style: BlockStyle | Record<string, unknown> | null | undefined): Record<string, string | number> | undefined {\n const picked = pickFieldStyle(style);\n const css: Record<string, string | number> = { ...blockStyleToCss(picked as BlockStyle) };\n Object.assign(css, blockStyleToColumnCss(picked as BlockStyle));\n const zoom = own(FIELD_SIZE_ZOOM, picked.size);\n if (zoom) css.zoom = zoom;\n return Object.keys(css).length ? css : undefined;\n}\n\n/**\n * The content column (`contentWidth` placed by `contentAlign`, falling back to `align`) as the\n * declarations for a box that IS the column — a site's own inner container (`sectionColumnAttrs`)\n * or a field's own element (`fieldStyleToCss`). Same max-width table as `blockStyleToInnerCss`;\n * the placement is left/right margins only, never the `margin` shorthand, so the box keeps its\n * own vertical margins. `undefined` when there is no column (unset, `full`, unknown).\n */\nexport function blockStyleToColumnCss(style: BlockStyle | undefined): { maxWidth: string; marginLeft: string; marginRight: string } | undefined {\n const column = blockStyleToInnerCss(style);\n if (!column || !style) return undefined;\n const placement = style.contentAlign ?? style.align;\n return { maxWidth: column.maxWidth, marginLeft: placement === \"left\" ? \"0\" : \"auto\", marginRight: placement === \"right\" ? \"0\" : \"auto\" };\n}\n\n/** `fieldStyleToCss` as an inline `style` string (`paddingTop` → `padding-top`), \"\" when empty. */\nexport function fieldStyleCssText(style: BlockStyle | Record<string, unknown> | null | undefined): string {\n const css = fieldStyleToCss(style);\n return css\n ? Object.entries(css)\n .map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}:${v}`)\n .join(\";\")\n : \"\";\n}\n","/**\n * Component — a reusable, Webflow-style block tree (a \"symbol\").\n *\n * A component is authored once and placed across pages via `component` blocks\n * (see `ComponentBlock` in `./block.ts`). Its definition lives in `blockJson`;\n * `props` declares a flat allowlist of values an instance may override.\n */\nimport type { BlockStyle, ContentBlock, VisibilityWindow } from \"./block.js\";\nimport type { ChoiceOption, ContentModelFieldUi, FieldsetKind, OpenMode, ShowIf, UiBefore, UiOrigin } from \"./content-model.js\";\nimport type { DockIconName } from \"./dock-icon-names.js\";\nimport type { VariantInputMapping } from \"./layout.js\";\n\n/**\n * The category a component belongs to (drives library grouping + icons). The first eight\n * are structural (what the component IS); the last four are the \"Add a section\" library\n * tabs (where it appears). One varchar column, not a PG enum — widening is code-only.\n */\n/**\n * 🔴 THE STRUCTURE DOCTRINE — one sentence, one home, spliced into every surface that builds a page.\n *\n * It lives HERE, beside the component contract it describes, because there are THREE places that teach\n * an agent how to build a page and they drifted apart:\n * • `packages/mcp/src/tools.ts` — the MCP tool descriptions (external agents)\n * • `src/lib/ai/agent.ts` — the in-product Studio Agent's system prompt\n * • `packages/mcp/src/prompts.ts` — the authoring playbook, which a tool call does not carry\n *\n * Only the playbook explained sections. `create_page` taught the SCHEMA axis in detail (\"each visual\n * section becomes a nested field\") and said nothing about STRUCTURE; the Studio Agent's prompt named\n * \"pages & reusable components (structure/layout)\" without ever mentioning `sectionType`.\n *\n * Measured consequence, production 2026-08-18: project `acme` has three components, ALL with\n * `section_type = (none)`, and its home page is 18 loose top-level blocks with ZERO sections. Every\n * generated page came out flat, so the visual editor's section lane — outline, name, move, duplicate,\n * delete, variant swap — had nothing to attach to. The editor was faithfully showing pages that were\n * never built out of sections.\n *\n * A constant rather than three paraphrases, because updating some of them is exactly how this happened.\n */\nexport const SECTION_DOCTRINE =\n \"STRUCTURE (separate from schema): a page is composed of SECTIONS. NEVER build a page out of loose top-level heading/text/image/button/spacer blocks — they cannot be moved, duplicated or swapped as a unit, the visual editor cannot outline or name them, and every one of them becomes its own section in the editor. A hero of a headline, a lede and two CTAs is ONE section, not four. TWO SHAPES, and the choice is about REUSE. (1) A band that appears on more than one page, or that needs layout variants, is a COMPONENT with a `sectionType` — see create_component. Components sharing a `sectionType` are that section's VARIANTS (one Hero: 'Centered' for the home page and 'Two-column' for about, same prop keys so a swap keeps the content). This is also the only shape the editor's 'Add a section' picker can insert, and the only one that gets a family name and a variant switcher. (2) A genuinely one-off band on a single page is a `section` BLOCK whose `props.children` hold its blocks. THE TRADEOFF, stated in the present tense because it is real today: inside a component, ONLY the leaves a declared prop TARGETS are click-to-edit on the canvas — each declared prop's `target` is re-keyed to that PLACEMENT's own override address, so editing it changes this page and not the shared definition. A prop with no `target` still SHOWS as a dock control, but its override reaches no rendered slot, so editing it changes nothing on the page. Copy that no prop points at is worse still: no binding and no control, unreachable from click-to-edit AND from the dock, changeable only by editing the component definition, which rewrites every page that places it. A `section` block's children stay click-to-edit unconditionally. So when you choose a component, DECLARE A PROP — WITH A `target` — for every string, link and image a marketer will ever touch; a component with un-propped editable copy is the defect, not the component. In the dock an unset prop shows EMPTY and inherits the definition's default, so set props explicitly when you want the current copy visible there. An IMPORTED site's components are its own (read the repo); its nav, footer and modals are the Layout. On a blank site, do not hand-write a band's JSON: start from a built-in section blueprint (list_components returns locked `builtin:*` blueprints with no projectId — hero-centered, hero-split, feature-grid-three, cta-banner and more), each already rooted in a `section` block with its editable leaves declared as props. INLINE its blockJson as a `section` block for a one-off band; for a recurring band, materialize it with create_component `from` so it becomes project-scoped before implementation validation, Output or publication. Direct `builtin:*` component references exist only for legacy delivery compatibility. Two consecutive call-to-action buttons are two sibling `button` blocks inside the same section — never a `columns` block, which is a `repeat(N,1fr)` grid and would stretch each CTA to half the container. Buttons are inline-level and flow side by side on their own.\";\n\nexport type ComponentCategory =\n | \"navbar\"\n | \"footer\"\n | \"button\"\n | \"section\"\n | \"slider\"\n | \"tabs\"\n | \"form\"\n | \"custom\"\n | \"hero\"\n | \"content\"\n | \"social-proof\"\n | \"conversion\";\n\n/**\n * A single overridable field on a component. `target` points at the block + JSON\n * path inside `blockJson` the override writes to (e.g. blockId \"cta\", path\n * \"props.text\"). Keeping overrides a declared allowlist (not arbitrary nested\n * rewrites) keeps instance data small and the contract explicit.\n */\n/**\n * THE prop vocabulary. One list, imported everywhere a prop type is enumerated.\n *\n * It exists as a value (not just a union) because four places used to spell it out by hand —\n * this file, the Drizzle schema, `COMPONENT_PROP_TYPES` in the backend's Zod schemas, and the\n * MCP tool shape — and the MCP copy is the dangerous one: `update_component` REPLACES the whole\n * `props` array, so a type its enum omits cannot be echoed back, and an agent that reads a\n * component and writes it straight back DESTROYS every prop of that type with a 200.\n *\n * Order is not semantic; append rather than re-sort, so a diff stays readable.\n */\nexport const COMPONENT_PROP_TYPES = [\n \"text\",\n \"richtext\",\n \"image\",\n \"url\",\n \"boolean\",\n \"number\",\n \"select\",\n \"group\",\n \"table\",\n \"slot\",\n \"form\",\n // The seven below each store what the same-named content-model FIELD stores (`icon` and\n // `multiselect` have no field twin; see the value notes on ComponentPropDef.type).\n \"link\",\n \"button\",\n \"date\",\n \"color\",\n \"file\",\n \"icon\",\n \"multiselect\",\n // V2 schema language (F1.x). `object` is ONE nested value of named `config.fields`, stored as\n // `{ [childKey]: value }` like the model field `object`; the six after it store what the\n // same-named content-model FIELD stores (`location` is the V2 geopoint) and are judged by\n // that field's validator.\n \"object\",\n \"datetime\",\n \"slug\",\n \"email\",\n \"phone\",\n \"json\",\n \"location\",\n // V2 leaves, each storing what the same-named content-model FIELD stores: a taxonomy string[],\n // a rating number, a code value (`{ language?, code }` or a string).\n \"tags\",\n \"rating\",\n \"code\",\n // CMS items, as the same-named content-model FIELDS store them: an entry id (or a polymorphic\n // `{ entryId, modelSlug }`), and a list of them. Delivery hydrates them like an entry's.\n \"reference\",\n \"multi-reference\",\n // V2 chrome types, each storing what the same-named content-model FIELD stores: a video value,\n // a primitive list (`config.itemType`), and multi-line text (the field lane's V2 `text`).\n \"video\",\n \"array\",\n \"longtext\",\n] as const;\n\nexport type ComponentPropType = (typeof COMPONENT_PROP_TYPES)[number];\n\n/**\n * The value a `form` prop STORES: just the id. The form itself is a Form document and stays the\n * single source of truth for its fields — a component references one, it never re-declares it.\n *\n * `.strict()` at the write boundary, so a client that POSTs a hydrated form object alongside the\n * id gets a 400 rather than a silent strip.\n *\n * There is deliberately NO resolved twin of this shape. Every renderer already receives forms the\n * same way — a catalogue beside the blocks (`BcmsBlocks({blocks, forms})`, the site renderer's\n * forms map) — and looks the id up in it. A hydrated `{formId, form}` prop value would be a shape\n * that exists nowhere in delivery.\n */\nexport interface ComponentFormPropRef {\n formId: string;\n}\n\nexport interface ComponentPropDef {\n key: string;\n label: string;\n target: { blockId: string; path: string };\n /**\n * `slot` holds ONE nested component instance — the component-level twin of the\n * content-model field type `component-ref` (see content-model.ts), named differently for\n * the same reason that one is: `component` already means a BLOCK type. Its value is\n * `{ componentId, overrides }` and its `target.path` is `props`, so filling a slot writes\n * that object over an empty `component` block's props.\n *\n * With `config.multiple` it holds a LIST of them and targets a container's child list\n * (`props.children` on a `section`, `props.columns.<n>` on a `columns`): the resolver writes\n * one `component` block per item there, so every renderer draws them as ordinary children.\n * @see slotItems\n *\n * On a PAGE a slot fill is a LIVE reference; a published ENTRY freezes it (resolveDeep).\n */\n /**\n * The EDITOR contract, not a storage one: `applyOverrides` writes the value at\n * `target.path` whatever its shape, so `type` decides which control the inspector renders\n * and what shape that control produces (FLO-1020).\n *\n * number → a number (heading.level, columns.count)\n * select → one string from `config.options`\n * group → an object keyed by `config.fields`\n * table → an array of such objects (slider.slides); with `config.mode: \"data\"` instead ONE\n * V2 `TableValue` (typed, keyed columns × keyed rows, table-value.ts), the value a\n * `table` FIELD stores. Aimed at a text or richtext block's `props.html` it renders\n * as the semantic HTML table. With `config.mode: \"types\"` a V2 polymorphic list: rows of\n * several item types (`config.itemTypes`), each row naming its type in `_type`.\n * link → an href string (URL, internal path or #fragment)\n * button → ONE `ButtonValue` (button-look.ts): label, href and look as a unit, never a text prop plus\n * a url prop that drift apart. Targets the `props` of a `button` block.\n * date → `YYYY-MM-DD`\n * color → a hex colour (`#RGB`, `#RRGGBB`, `#RRGGBBAA`)\n * file → `{ url, name?, size? }`, or a bare URL string\n * icon → a BetterCMS icon name (`DOCK_ICON_NAMES`), or an uploaded icon as an image value\n * multiselect → a `string[]`, each one of `config.options`\n * object → ONE `{ [childKey]: value }` keyed by `config.fields` (the V2 model-field `object`)\n * datetime · slug · email · phone · json · location → what the same-named model FIELD stores\n * tags · rating · code → what the same-named model FIELD stores (a string[], a number,\n * `{ language?, code }` or a string)\n * reference · multi-reference → what the same-named model FIELD stores: an entry id, or a\n * list of them (`config.contentModelId`, or `polymorphic` + `allowedModelSlugs`;\n * `min`/`max` on the list). Delivery and preview hydrate the ids in a page's overrides\n * to entries at the read's `depth`; a plain-text slot renders the entry's title.\n * video → a URL string or `{ url, poster?, autoplay?, loop?, transcript? }` (the video\n * block's props; aimed at a video block it lands as them) @see VideoValue\n * array → a list of `config.itemType` values: text, number, date, image, link or richtext\n * (the model field's primitive `array`; a list of objects is a `table`)\n * longtext → a multi-line string (the model field `longtext`; `text` is one line)\n */\n type: ComponentPropType;\n defaultValue?: unknown;\n /**\n * EDITOR HINTS (playbook §12). Stored in the props JSON, so no migration.\n *\n * 🔴 `required` IS NOT ENFORCED AT WRITE TIME, deliberately. Nothing on the write path\n * refuses an override that omits a required prop — a placement saves either way — because\n * the alternative is a component definition that can retroactively make already-saved pages\n * unsaveable. It is a marker the dashboard renders and `get_site_composition` counts, which\n * is the honest shape: the receipt names what is missing instead of the write refusing it.\n */\n required?: boolean;\n /** Hint shown under the control, muted. */\n helpText?: string;\n /** Server-owned: who wrote `helpText`. */\n helpSource?: \"auto\" | \"human\" | \"agent\";\n /** Ghost text inside a text-ish control. */\n placeholder?: string;\n /**\n * Editor-only conditional visibility: show this prop's control only while sibling props (by\n * key) hold these values. The save schema refuses a key no prop of the component declares.\n */\n showIf?: ShowIf;\n /** V2 editor-only keys, as on a model field. @see ContentModelField.helpMore */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /**\n * F1.x: a list prop's items (a table's rows) distinct; on a table sub-field, no two rows share\n * the value. Refused (`unique_prop_scope`) on a top-level scalar: nothing to be unique across.\n */\n unique?: boolean;\n /** `object` / `group` / `table`: how the value (or each row) opens when edited. */\n openMode?: OpenMode;\n /**\n * The content-model field's `readOnly` / `lockReason` pair, as STORED MARKERS only: the\n * editor may render the prop read-only, and no write of a prop value is refused for them.\n */\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2 per-field localization (the locale chip): a stored marker, as on a model field. */\n localized?: boolean;\n /** Per-type settings; the save schema enforces that each is present on the type needing it. */\n config?: {\n /** `slot` — a pick allowlist. */\n componentIds?: string[];\n /** `slot` — the value is a list of instances, not one. @see slotItems */\n multiple?: boolean;\n /** `slot` with `multiple` — bounds on the list. `maxItems` defaults to {@link SLOT_MAX_ITEMS}. */\n minItems?: number;\n maxItems?: number;\n /**\n * `slot` — per-child layout settings (V2 `slotSettings`, e.g. a bento span): what a V2 child's\n * `_settings` holds (`{ _key, _type, _settings, ...props }`, slot-child.ts). Leaf sub-fields.\n */\n slotSettings?: ComponentSubField[];\n /**\n * `table` with `mode: \"types\"` — a V2 polymorphic list: each row is ONE of these item types,\n * named by the row's `_type` (`{ _key?, _type, ...values }`), its values keyed by that type's `fields`.\n */\n itemTypes?: Array<{\n name: string;\n label?: string;\n fields: ComponentSubField[];\n /** How a row of this type reads collapsed: title/subtitle/media name THIS type's fields (dotted ok, e.g. `table.caption`). */\n preview?: { title?: string; subtitle?: string; media?: string; fallback?: string; icon?: DockIconName };\n /** The row icon for this type, a dock icon name. */\n icon?: DockIconName;\n }>;\n /**\n * `select` / `multiselect` — the choices. Required, and a default must be one of them. `{ label, value }`\n * when the stored value is not what an author should read (a component id, for instance).\n */\n options?: Array<string | ChoiceOption>;\n /** `group` / `table` / `object` — the sub-shape; 10 levels at most, counting the prop (MAX_FIELD_DEPTH). */\n fields?: ComponentSubField[];\n /**\n * `table` — which value it holds: `\"rows\"` (the default, an array of `fields` rows) or\n * `\"data\"` (one V2 TableValue, with the table field's options beside it: columnTypes,\n * lockColumns, minRows, maxRows, maxColumns, requireCaption, …). A data table has no `fields`.\n */\n mode?: \"rows\" | \"data\" | \"types\";\n /** `number` — bounds for the control; `multiselect` / `tags` / `multi-reference` — how many items. */\n min?: number;\n max?: number;\n step?: number;\n /** `number` — V2 `validation.min / max`: the error bounds, which win over `min` / `max`. */\n validation?: { min?: number; max?: number };\n /** `text` / `url` / `richtext` — length in characters (richtext: its plain text). */\n minLength?: number;\n maxLength?: number;\n /** `text` / `url` — a regex (≤ 200 characters) and the message shown when it does not match. */\n pattern?: string;\n patternMessage?: string;\n /** `reference` / `multi-reference` — the target model, or `polymorphic` with an allowlist of model slugs. */\n contentModelId?: string;\n polymorphic?: boolean;\n allowedModelSlugs?: string[];\n } & Record<string, unknown>;\n /**\n * AUTHORING CHROME — the same object a content-model FIELD carries ({@link ContentModelFieldUi}),\n * deliberately: an agent that has learned `ui` once has learned it on both lanes.\n *\n * A SIBLING of `config`, not a member of it. `config` is a loose bag, so a `config.ui` already\n * survived the write — and that is the problem this key fixes: surviving is not declared, and\n * an undeclared prop is a typo that saves cleanly and renders as nothing.\n *\n * WHERE EACH KEY IS LEGAL differs from the field lane, because the vocabulary does:\n * `preview`/`layout` on `group`, `table` and `slot`; `reorderable` on `table` ALONE, the only\n * prop type whose value is a list. The save schema refuses the rest with the valid set named.\n */\n ui?: ComponentPropUi;\n /** Server-owned provenance of this prop's chrome. @see UiOrigin */\n uiOrigin?: UiOrigin;\n /** Server-owned revert point. @see UiBefore */\n uiBefore?: UiBefore;\n /** `true`: no placement the last release inspected renders this prop — hidden, never deleted. `false`: a person keeps it shown. */\n stale?: boolean;\n}\n\n/**\n * A top-level prop's dock group. Props have no fieldsets column, so the group rides inline: the\n * first prop to carry an `id` defines it (label, kind, icon, collapsed), later props name `{id}`.\n */\nexport interface PropGroup {\n id: string;\n /** 1–32 chars. Required on the defining prop. */\n label?: string;\n kind?: Exclude<FieldsetKind, \"tab\">;\n icon?: DockIconName;\n collapsed?: boolean;\n /** V2 fieldset keys (CPO D45), on the defining prop: a line under the header (≤200), members side by side, a static header, a breakpoint switcher, and its place among the groups (0–99; absent = where its first prop sits). */\n description?: string;\n columns?: 1 | 2;\n collapsible?: boolean;\n layout?: \"stack\" | \"breakpoints\";\n order?: number;\n}\n\n/**\n * A top-level prop's dock tab (V2 kit schema `groups`: Content | Design | Media | Settings | …).\n * Define-once like {@link PropGroup}: the first prop naming an `id` sets label/icon/order, later\n * props name `{ id }`. At most 8 tabs; never on a sub-field; one group's members share one tab.\n */\nexport interface PropTab {\n id: string;\n /** 1–40 chars, unique per component (case-insensitive). Required on the defining prop. */\n label?: string;\n icon?: DockIconName;\n /** 0–99; the tab's place among the tabs (absent = where its first prop sits). */\n order?: number;\n}\n\n/** A prop's `ui`: the field-lane chrome plus its inline {@link PropGroup} and {@link PropTab}. */\nexport type ComponentPropUi = ContentModelFieldUi & { group?: PropGroup; tab?: PropTab };\n\n/** One field inside a `group` / `object` prop or a `table` row. Recursive, 10 levels at most counting the prop (MAX_FIELD_DEPTH). */\nexport interface ComponentSubField {\n key: string;\n label: string;\n /**\n * No `form`: a form in a table row would mean N form documents per component with no way to\n * author them — the second field model this design exists to avoid. A `slot` sub-field IS\n * accepted by the API (V2 kit entries: an instance in an object or a row, `{ componentId,\n * overrides? }` at its key, the slot prop's config keys); this type still leaves it out to stay\n * assignable to the `packages/db` schema mirror, and widens together with it.\n */\n type: Exclude<ComponentPropDef[\"type\"], \"slot\" | \"form\">;\n defaultValue?: unknown;\n /** The same editor hints as the prop above, one level down. @see ComponentPropDef */\n required?: boolean;\n helpText?: string;\n helpSource?: \"auto\" | \"human\" | \"agent\";\n placeholder?: string;\n options?: Array<string | ChoiceOption>;\n /** The V2 editor keys, one level down. `showIf` names SIBLING sub-fields. @see ComponentPropDef */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /** On a table's sub-field: no two rows share the value; on a list: no item repeats. */\n unique?: boolean;\n openMode?: OpenMode;\n showIf?: ShowIf;\n /** The prop's `ui`, inline group included: V2 fieldsets nest, so sub-fields group too. */\n ui?: ComponentPropUi;\n /** V2 sub-field read-only / developer lock: stored markers, as on the prop. `\"developer\"` needs a lockReason. */\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2 per-field localization: a stored marker, as on the prop. */\n localized?: boolean;\n /** CANONICAL. A nested `group`/`table`/`object`'s own sub-shape. */\n fields?: ComponentSubField[];\n /**\n * A READ-ONLY MIRROR of `options`/`fields`, in the shape `ComponentPropDef` puts them in.\n *\n * 🔴 WHY A SECOND COPY EXISTS AT ALL. A `group`/`table` PROP declares its sub-shape under\n * `config.fields`; a sub-field of one declares its own under a bare `fields`. So a consumer\n * walking a nested table has to switch shape after the first level, and the componentize lane's\n * repo half (`@bettercms-ai/convert --componentize`) walks exactly that — it reads one node\n * shape at every depth. Mirroring the sub-shape here lets it, without the CMS having to\n * describe a nested table differently from a top-level one.\n *\n * `fields` is the authority. The save schema REFUSES a node whose mirror disagrees with it\n * (`componentPropDefSchema`), because two copies that may drift are worse than one awkward\n * shape — an editor that rewrote `fields` alone would leave a stale row description behind.\n */\n config?: { fields?: ComponentSubField[]; options?: Array<string | ChoiceOption> } & Record<string, unknown>;\n}\n\n/** The value a `slot` prop holds — the draft half of a `component-ref`, deliberately. */\nexport interface SlotValue {\n componentId: string;\n overrides?: Record<string, unknown>;\n}\n\n/**\n * One child of a `multiple` slot: a {@link SlotValue} that may also carry the two placement keys a\n * `component` block has. The child block is built with them, so it hides per breakpoint and\n * shows inside its window exactly as a block placed by hand does.\n */\nexport interface SlotItem extends SlotValue {\n style?: BlockStyle;\n window?: VisibilityWindow;\n}\n\n/** How many children a `multiple` slot holds when its prop sets no `config.maxItems`. */\nexport const SLOT_MAX_ITEMS = 12;\n/** The most `config.maxItems` may ask for: one placement never expands into more blocks than this. */\nexport const SLOT_ITEMS_CAP = 50;\n\n/**\n * A slot value as a list of its instances, whichever shape it was stored in: `[]` for nothing,\n * one item for a single `{ componentId, overrides }`, the array's own items for a `multiple`\n * slot. An item with no `componentId` names no component and is left out.\n *\n * THE one reading of a slot value. A walker that tests `value.componentId` alone sees a\n * `multiple` slot as empty, and for a \"where used\" answer or a delete guard that is a component\n * removed from under the pages that hold it.\n */\nexport function slotItems(value: unknown): SlotItem[] {\n const list = Array.isArray(value) ? value : [value];\n const out: SlotItem[] = [];\n for (const item of list) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n const o = item as Record<string, unknown>;\n if (typeof o.componentId === \"string\" && o.componentId !== \"\") out.push(item as SlotItem);\n // A V2 slot child (`{ _key, _type, ...props }`, slot-child.ts): `_type` is the component id and\n // the child ITSELF is the overrides, so a walker that writes into them writes into the stored\n // value. applyOverrides reads declared prop keys only; the `_` keys are never a prop's.\n else if (typeof o.componentId !== \"string\" && typeof o._type === \"string\" && o._type !== \"\") out.push({ componentId: o._type, overrides: o });\n }\n return out;\n}\n\n/**\n * A component is a DRAFT until published; only the published copy reaches a visitor.\n * Mirrors pages and entries. See migration 0186_component_draft_live_split.sql.\n */\nexport type ComponentStatus = \"draft\" | \"published\";\n\n/**\n * Archive state (FLO-1012), deliberately SEPARATE from `ComponentStatus`.\n *\n * Archive takes a component out of the working set — hidden from the components list by\n * default, not offered in the visual editor's insert surfaces — while every existing usage\n * keeps serving. It is not unpublish (which pulls the live copy and re-bakes every page that\n * embeds it) and it is not delete.\n *\n * It is a timestamp rather than a third `status` value because a component can be published\n * AND archived; collapsing the two would lose the bit restore has to put back.\n */\n\n/**\n * How ONE instance of a component reads as a ROW in a parent's slot list (\"Open Rosa Delgado,\n * 2 of 5\"): the V2 /kit schema's document-level `preview`. `title`, `subtitle` and `media` each\n * name a TOP-LEVEL prop key (the API refuses any other with `preview_key_unknown`); `fallback` is\n * the literal row label while the title prop is empty; `icon` the row's icon while it has no media.\n * Draft-only authoring chrome: never part of the publish snapshot.\n */\nexport interface ComponentPreview {\n title?: string;\n subtitle?: string;\n media?: string;\n fallback?: string;\n icon?: DockIconName;\n}\n\nexport interface Component {\n id: string;\n workspaceId: string;\n projectId?: string | null;\n name: string;\n slug: string;\n category: ComponentCategory;\n /**\n * Section library: the family this component is a LAYOUT of, e.g. \"Hero\". `name` is the\n * layout label (\"Centered\"), so components sharing a sectionType are selectable variants\n * of one section. Null/absent = an ordinary component, not shown in the section library.\n */\n sectionType?: string | null;\n /** First-class variant family membership; exact workspace/project scope is enforced in DB. */\n variantGroupId?: string | null;\n variantInputMappings?: VariantInputMapping[];\n /** Placement governance: `*`, `slug:<page-slug>`, and/or `type:<page-type>`. */\n allowedOn: string[];\n description?: string | null;\n /** The DRAFT definition. Every builder/autosave/import write path targets these two. */\n blockJson: ContentBlock[];\n props: ComponentPropDef[];\n /** How an instance reads as a row in a parent's slot list. Null/absent = unset. @see ComponentPreview */\n preview?: ComponentPreview | null;\n /** The block icon (a /kit schema's document-level `icon`): root crumb, slot rows, slot child frames. Null/absent = unset. */\n icon?: DockIconName | null;\n status: ComponentStatus;\n /** When it left the working set, or null/absent while active. @see ComponentStatus */\n archivedAt?: string | Date | null;\n /** Derived from `archivedAt`, so a client never has to know the column. */\n archived?: boolean;\n /**\n * The LIVE snapshot get_components_by_handle() serves. Null until the first publish.\n * Returned by GET-one (the Compare view needs it), omitted from list rows for payload.\n */\n publishedBlockJson?: ContentBlock[] | null;\n publishedProps?: ComponentPropDef[] | null;\n publishedAt?: string | null; // ISO 8601\n /**\n * Computed in SQL on list/get, never stored:\n * status='published' AND (blockJson or props has diverged from its published copy).\n * An exact jsonb compare, so it self-clears when an edit is reverted.\n */\n pendingChanges?: boolean;\n thumbnail?: string | null;\n createdAt: string; // ISO 8601\n updatedAt: string; // ISO 8601\n}\n\n/**\n * Public/delivery projection — the fields a renderer needs to resolve instances.\n *\n * DELIBERATELY UNCHANGED by the 0186 draft/live split: delivery aliases\n * publishedBlockJson -> blockJson, so every already-deployed site and every\n * bcms-content.json on disk keeps a byte-identical wire shape. Do not add `status` here —\n * delivery only ever returns published rows, so it would always be the same constant.\n */\nexport interface DeliveryComponent {\n id: string;\n /** The project the component belongs to. */\n projectId?: string | null;\n /** The component's preview image in the editor's library, when it has one. */\n thumbnail?: string | null;\n name: string;\n slug: string;\n category: ComponentCategory;\n sectionType?: string | null;\n blockJson: ContentBlock[];\n props: ComponentPropDef[];\n}\n","/**\n * V2 slot children (DESIGN.md, V2 `engine/slot.tsx`): blocks inside a block, stored INLINE as\n * `{ _key, _type, _variant?, _settings?, ...values }`. The block's own values sit at the child's\n * root, beside four reserved keys:\n *\n * _key the child's stable identity (reorders, diffs, React keys). Unique in its slot.\n * _type the block type: a `kind: 'block'` model's SLUG on a model's `slot` field, a\n * component's ID on a `slot` prop.\n * _variant a block variant (layout) name. Model slots only: a component variant is its own\n * component in BetterCMS, so a prop slot names it in `_type`.\n * _settings per-child layout settings, keyed by the slot's `slotSettings`.\n *\n * The same `_key` / `_type` pair discriminates the items of a polymorphic list prop (a `table` prop\n * with `config.mode: \"types\"`): `_type` names one of its `config.itemTypes`.\n *\n * Pure: shape only. Whether a block type exists, is allowed, and whether a child's values fit it,\n * is the caller's (it knows the block models or the components).\n */\n\n/** The reserved keys of a slot child; every other key is one of the block's own values. */\nexport const SLOT_CHILD_KEYS = [\"_key\", \"_type\", \"_variant\", \"_settings\"] as const;\nconst RESERVED: ReadonlySet<string> = new Set(SLOT_CHILD_KEYS);\n\n/** One block inside a V2 slot. @see SLOT_CHILD_KEYS */\nexport interface SlotChild {\n _key: string;\n _type: string;\n _variant?: string;\n _settings?: Record<string, unknown>;\n [value: string]: unknown;\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> => !!v && typeof v === \"object\" && !Array.isArray(v);\n\n/** Is this a V2 slot child (an object naming its block type in `_type`)? */\nexport const isSlotChild = (v: unknown): v is SlotChild => isRecord(v) && typeof v._type === \"string\" && v._type !== \"\";\n\n/** A slot child's own values: everything but the reserved keys (a new object; the values are shared). */\nexport function slotChildValues(child: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(child)) if (!RESERVED.has(k)) out[k] = v;\n return out;\n}\n\nexport type SlotShapeProblem = { path: Array<string | number>; code: string; message: string };\n\nexport type SlotShapeOptions = {\n /** Bounds on the list. `max` is clamped by the caller's hard cap. */\n min?: number;\n max?: number;\n /** Does the slot declare `slotSettings`? A `_settings` is refused without them. */\n settings?: boolean;\n /** May a child name a `_variant`? (model slots yes, prop slots no) */\n variants?: boolean;\n /** What the list is called in messages (\"Body\", \"slot 'cards'\"). */\n label?: string;\n /** What `_type` names, for messages (\"a block model slug\", \"a component id\"). */\n typeNoun?: string;\n};\n\n/**\n * Why a value cannot be a slot's list of children, each at its path inside the value (`[2, \"_key\"]`),\n * codes first in each message. Shape only: a list of objects, each with a non-empty `_key` (unique)\n * and `_type`, `_variant` a string where allowed, `_settings` an object where declared, no other\n * `_`-prefixed key (a typo'd reserved key would otherwise be stored as a value nothing reads).\n */\nexport function slotShapeProblems(value: unknown, opts: SlotShapeOptions = {}): SlotShapeProblem[] {\n const label = opts.label ?? \"slot\";\n const noun = opts.typeNoun ?? \"a block type\";\n if (!Array.isArray(value)) return [{ path: [], code: \"slot_value_invalid\", message: `slot_value_invalid: ${label} must be a list of blocks ({ _key, _type, ...values })` }];\n const out: SlotShapeProblem[] = [];\n if (opts.max !== undefined && value.length > opts.max) out.push({ path: [], code: \"slot_too_many\", message: `slot_too_many: ${label} holds at most ${opts.max} blocks, got ${value.length}` });\n if (opts.min !== undefined && value.length < opts.min) out.push({ path: [], code: \"slot_too_few\", message: `slot_too_few: ${label} needs at least ${opts.min} blocks, got ${value.length}` });\n const keys = new Set<string>();\n value.forEach((child, i) => {\n if (!isRecord(child)) {\n out.push({ path: [i], code: \"slot_value_invalid\", message: `slot_value_invalid: ${label}: block ${i + 1} must be an object { _key, _type, ...values }` });\n return;\n }\n if (typeof child._key !== \"string\" || child._key.trim() === \"\") {\n out.push({ path: [i, \"_key\"], code: \"slot_child_key_required\", message: `slot_child_key_required: ${label}: block ${i + 1} needs a _key (a non-empty string)` });\n } else if (keys.has(child._key)) {\n out.push({ path: [i, \"_key\"], code: \"slot_child_key_duplicate\", message: `slot_child_key_duplicate: ${label}: _key '${child._key}' is used by two blocks` });\n } else keys.add(child._key);\n if (typeof child._type !== \"string\" || child._type.trim() === \"\") {\n out.push({ path: [i, \"_type\"], code: \"slot_child_type_required\", message: `slot_child_type_required: ${label}: block ${i + 1} needs a _type (${noun})` });\n }\n if (child._variant !== undefined) {\n if (!opts.variants) out.push({ path: [i, \"_variant\"], code: \"slot_variant_unsupported\", message: `slot_variant_unsupported: ${label}: a component variant is its own component; name it in _type` });\n else if (typeof child._variant !== \"string\" || child._variant === \"\") out.push({ path: [i, \"_variant\"], code: \"slot_value_invalid\", message: `slot_value_invalid: ${label}: _variant must be a variant name` });\n }\n if (child._settings !== undefined) {\n if (!opts.settings) out.push({ path: [i, \"_settings\"], code: \"slot_settings_undeclared\", message: `slot_settings_undeclared: ${label} declares no slotSettings, so a block holds no _settings` });\n else if (!isRecord(child._settings)) out.push({ path: [i, \"_settings\"], code: \"slot_value_invalid\", message: `slot_value_invalid: ${label}: _settings must be an object keyed by the slot's slotSettings` });\n }\n for (const k of Object.keys(child)) {\n if (k.startsWith(\"_\") && !RESERVED.has(k)) {\n out.push({ path: [i, k], code: \"slot_child_key_unknown\", message: `slot_child_key_unknown: ${label}: '${k}' is not a slot key (${SLOT_CHILD_KEYS.join(\", \")}); a block's values have no leading underscore` });\n }\n }\n });\n return out;\n}\n\n/** `rows[2]._key`-style path text for a problem path. */\nexport const slotPathString = (path: Array<string | number>): string =>\n path.map((s, i) => (typeof s === \"number\" ? `[${s}]` : i === 0 ? s : `.${s}`)).join(\"\");\n","/**\n * Generated from lucide-react@1.8.0 dynamic icon names.\n * Legacy CamelCase identifiers remain valid for existing Layout documents.\n */\nexport const LAYOUT_SECTION_ICONS: readonly string[] = Object.freeze([\n \"LayoutPanelTop\",\n \"PanelTop\",\n \"PanelBottom\",\n \"Menu\",\n \"Navigation\",\n \"Megaphone\",\n \"GalleryHorizontal\",\n \"Rows3\",\n \"Grid2X2\",\n \"FileText\",\n \"Link\",\n \"Contact\",\n \"BadgeInfo\",\n \"Sparkles\",\n \"a-arrow-down\",\n \"a-arrow-up\",\n \"a-large-small\",\n \"accessibility\",\n \"activity\",\n \"air-vent\",\n \"airplay\",\n \"alarm-clock-check\",\n \"alarm-check\",\n \"alarm-clock-minus\",\n \"alarm-minus\",\n \"alarm-clock-off\",\n \"alarm-clock-plus\",\n \"alarm-plus\",\n \"alarm-clock\",\n \"alarm-smoke\",\n \"album\",\n \"align-center-horizontal\",\n \"align-center-vertical\",\n \"align-end-horizontal\",\n \"align-end-vertical\",\n \"align-horizontal-distribute-center\",\n \"align-horizontal-distribute-end\",\n \"align-horizontal-distribute-start\",\n \"align-horizontal-justify-center\",\n \"align-horizontal-justify-end\",\n \"align-horizontal-justify-start\",\n \"align-horizontal-space-around\",\n \"align-horizontal-space-between\",\n \"align-start-horizontal\",\n \"align-start-vertical\",\n \"align-vertical-distribute-center\",\n \"align-vertical-distribute-end\",\n \"align-vertical-distribute-start\",\n \"align-vertical-justify-center\",\n \"align-vertical-justify-end\",\n \"align-vertical-justify-start\",\n \"align-vertical-space-around\",\n \"align-vertical-space-between\",\n \"ambulance\",\n \"ampersand\",\n \"ampersands\",\n \"amphora\",\n \"anchor\",\n \"angry\",\n \"annoyed\",\n \"antenna\",\n \"anvil\",\n \"aperture\",\n \"app-window-mac\",\n \"app-window\",\n \"apple\",\n \"archive-restore\",\n \"archive-x\",\n \"archive\",\n \"armchair\",\n \"arrow-big-down-dash\",\n \"arrow-big-down\",\n \"arrow-big-left-dash\",\n \"arrow-big-left\",\n \"arrow-big-right-dash\",\n \"arrow-big-right\",\n \"arrow-big-up-dash\",\n \"arrow-big-up\",\n \"arrow-down-0-1\",\n \"arrow-down-01\",\n \"arrow-down-1-0\",\n \"arrow-down-10\",\n \"arrow-down-a-z\",\n \"arrow-down-az\",\n \"arrow-down-from-line\",\n \"arrow-down-left\",\n \"arrow-down-narrow-wide\",\n \"arrow-down-right\",\n \"arrow-down-to-dot\",\n \"arrow-down-to-line\",\n \"arrow-down-up\",\n \"arrow-down-wide-narrow\",\n \"sort-desc\",\n \"arrow-down-z-a\",\n \"arrow-down-za\",\n \"arrow-down\",\n \"arrow-left-from-line\",\n \"arrow-left-right\",\n \"arrow-left-to-line\",\n \"arrow-left\",\n \"arrow-right-from-line\",\n \"arrow-right-left\",\n \"arrow-right-to-line\",\n \"arrow-right\",\n \"arrow-up-0-1\",\n \"arrow-up-01\",\n \"arrow-up-1-0\",\n \"arrow-up-10\",\n \"arrow-up-a-z\",\n \"arrow-up-az\",\n \"arrow-up-down\",\n \"arrow-up-from-dot\",\n \"arrow-up-from-line\",\n \"arrow-up-left\",\n \"arrow-up-narrow-wide\",\n \"sort-asc\",\n \"arrow-up-right\",\n \"arrow-up-to-line\",\n \"arrow-up-wide-narrow\",\n \"arrow-up-z-a\",\n \"arrow-up-za\",\n \"arrow-up\",\n \"arrows-up-from-line\",\n \"asterisk\",\n \"at-sign\",\n \"atom\",\n \"audio-lines\",\n \"audio-waveform\",\n \"award\",\n \"axe\",\n \"axis-3d\",\n \"axis-3-d\",\n \"baby\",\n \"backpack\",\n \"badge-alert\",\n \"badge-cent\",\n \"badge-check\",\n \"verified\",\n \"badge-dollar-sign\",\n \"badge-euro\",\n \"badge-indian-rupee\",\n \"badge-info\",\n \"badge-japanese-yen\",\n \"badge-minus\",\n \"badge-percent\",\n \"badge-plus\",\n \"badge-pound-sterling\",\n \"badge-question-mark\",\n \"badge-help\",\n \"badge-russian-ruble\",\n \"badge-swiss-franc\",\n \"badge-turkish-lira\",\n \"badge-x\",\n \"badge\",\n \"baggage-claim\",\n \"balloon\",\n \"ban\",\n \"banana\",\n \"bandage\",\n \"banknote-arrow-down\",\n \"banknote-arrow-up\",\n \"banknote-x\",\n \"banknote\",\n \"barcode\",\n \"barrel\",\n \"baseline\",\n \"bath\",\n \"battery-charging\",\n \"battery-full\",\n \"battery-low\",\n \"battery-medium\",\n \"battery-plus\",\n \"battery-warning\",\n \"battery\",\n \"beaker\",\n \"bean-off\",\n \"bean\",\n \"bed-double\",\n \"bed-single\",\n \"bed\",\n \"beef-off\",\n \"beef\",\n \"beer-off\",\n \"beer\",\n \"bell-dot\",\n \"bell-electric\",\n \"bell-minus\",\n \"bell-off\",\n \"bell-plus\",\n \"bell-ring\",\n \"bell\",\n \"between-horizontal-end\",\n \"between-horizonal-end\",\n \"between-horizontal-start\",\n \"between-horizonal-start\",\n \"between-vertical-end\",\n \"between-vertical-start\",\n \"biceps-flexed\",\n \"bike\",\n \"binary\",\n \"binoculars\",\n \"biohazard\",\n \"bird\",\n \"birdhouse\",\n \"bitcoin\",\n \"blend\",\n \"blinds\",\n \"blocks\",\n \"bluetooth-connected\",\n \"bluetooth-off\",\n \"bluetooth-searching\",\n \"bluetooth\",\n \"bold\",\n \"bolt\",\n \"bomb\",\n \"bone\",\n \"book-a\",\n \"book-alert\",\n \"book-audio\",\n \"book-check\",\n \"book-copy\",\n \"book-dashed\",\n \"book-template\",\n \"book-down\",\n \"book-headphones\",\n \"book-heart\",\n \"book-image\",\n \"book-key\",\n \"book-lock\",\n \"book-marked\",\n \"book-minus\",\n \"book-open-check\",\n \"book-open-text\",\n \"book-open\",\n \"book-plus\",\n \"book-search\",\n \"book-text\",\n \"book-type\",\n \"book-up-2\",\n \"book-up\",\n \"book-user\",\n \"book-x\",\n \"book\",\n \"bookmark-check\",\n \"bookmark-minus\",\n \"bookmark-off\",\n \"bookmark-plus\",\n \"bookmark-x\",\n \"bookmark\",\n \"boom-box\",\n \"bot-message-square\",\n \"bot-off\",\n \"bot\",\n \"bottle-wine\",\n \"bow-arrow\",\n \"box\",\n \"boxes\",\n \"braces\",\n \"curly-braces\",\n \"brackets\",\n \"brain-circuit\",\n \"brain-cog\",\n \"brain\",\n \"brick-wall-fire\",\n \"brick-wall-shield\",\n \"brick-wall\",\n \"briefcase-business\",\n \"briefcase-conveyor-belt\",\n \"briefcase-medical\",\n \"briefcase\",\n \"bring-to-front\",\n \"brush-cleaning\",\n \"brush\",\n \"bubbles\",\n \"bug-off\",\n \"bug-play\",\n \"bug\",\n \"building-2\",\n \"building\",\n \"bus-front\",\n \"bus\",\n \"cable-car\",\n \"cable\",\n \"cake-slice\",\n \"cake\",\n \"calculator\",\n \"calendar-1\",\n \"calendar-arrow-down\",\n \"calendar-arrow-up\",\n \"calendar-check-2\",\n \"calendar-check\",\n \"calendar-clock\",\n \"calendar-cog\",\n \"calendar-days\",\n \"calendar-fold\",\n \"calendar-heart\",\n \"calendar-minus-2\",\n \"calendar-minus\",\n \"calendar-off\",\n \"calendar-plus-2\",\n \"calendar-plus\",\n \"calendar-range\",\n \"calendar-search\",\n \"calendar-sync\",\n \"calendar-x-2\",\n \"calendar-x\",\n \"calendar\",\n \"calendars\",\n \"camera-off\",\n \"camera\",\n \"candy-cane\",\n \"candy-off\",\n \"candy\",\n \"cannabis-off\",\n \"cannabis\",\n \"captions-off\",\n \"captions\",\n \"subtitles\",\n \"car-front\",\n \"car-taxi-front\",\n \"car\",\n \"caravan\",\n \"card-sim\",\n \"carrot\",\n \"case-lower\",\n \"case-sensitive\",\n \"case-upper\",\n \"cassette-tape\",\n \"cast\",\n \"castle\",\n \"cat\",\n \"cctv-off\",\n \"cctv\",\n \"chart-area\",\n \"area-chart\",\n \"chart-bar-big\",\n \"bar-chart-horizontal-big\",\n \"chart-bar-decreasing\",\n \"chart-bar-increasing\",\n \"chart-bar-stacked\",\n \"chart-bar\",\n \"bar-chart-horizontal\",\n \"chart-candlestick\",\n \"candlestick-chart\",\n \"chart-column-big\",\n \"bar-chart-big\",\n \"chart-column-decreasing\",\n \"chart-column-increasing\",\n \"bar-chart-4\",\n \"chart-column-stacked\",\n \"chart-column\",\n \"bar-chart-3\",\n \"chart-gantt\",\n \"chart-line\",\n \"line-chart\",\n \"chart-network\",\n \"chart-no-axes-column-decreasing\",\n \"chart-no-axes-column-increasing\",\n \"bar-chart\",\n \"chart-no-axes-column\",\n \"bar-chart-2\",\n \"chart-no-axes-combined\",\n \"chart-no-axes-gantt\",\n \"gantt-chart\",\n \"chart-pie\",\n \"pie-chart\",\n \"chart-scatter\",\n \"scatter-chart\",\n \"chart-spline\",\n \"check-check\",\n \"check-line\",\n \"check\",\n \"chef-hat\",\n \"cherry\",\n \"chess-bishop\",\n \"chess-king\",\n \"chess-knight\",\n \"chess-pawn\",\n \"chess-queen\",\n \"chess-rook\",\n \"chevron-down\",\n \"chevron-first\",\n \"chevron-last\",\n \"chevron-left\",\n \"chevron-right\",\n \"chevron-up\",\n \"chevrons-down-up\",\n \"chevrons-down\",\n \"chevrons-left-right-ellipsis\",\n \"chevrons-left-right\",\n \"chevrons-left\",\n \"chevrons-right-left\",\n \"chevrons-right\",\n \"chevrons-up-down\",\n \"chevrons-up\",\n \"church\",\n \"cigarette-off\",\n \"cigarette\",\n \"circle-alert\",\n \"alert-circle\",\n \"circle-arrow-down\",\n \"arrow-down-circle\",\n \"circle-arrow-left\",\n \"arrow-left-circle\",\n \"circle-arrow-out-down-left\",\n \"arrow-down-left-from-circle\",\n \"circle-arrow-out-down-right\",\n \"arrow-down-right-from-circle\",\n \"circle-arrow-out-up-left\",\n \"arrow-up-left-from-circle\",\n \"circle-arrow-out-up-right\",\n \"arrow-up-right-from-circle\",\n \"circle-arrow-right\",\n \"arrow-right-circle\",\n \"circle-arrow-up\",\n \"arrow-up-circle\",\n \"circle-check-big\",\n \"check-circle\",\n \"circle-check\",\n \"check-circle-2\",\n \"circle-chevron-down\",\n \"chevron-down-circle\",\n \"circle-chevron-left\",\n \"chevron-left-circle\",\n \"circle-chevron-right\",\n \"chevron-right-circle\",\n \"circle-chevron-up\",\n \"chevron-up-circle\",\n \"circle-dashed\",\n \"circle-divide\",\n \"divide-circle\",\n \"circle-dollar-sign\",\n \"circle-dot-dashed\",\n \"circle-dot\",\n \"circle-ellipsis\",\n \"circle-equal\",\n \"circle-fading-arrow-up\",\n \"circle-fading-plus\",\n \"circle-gauge\",\n \"gauge-circle\",\n \"circle-minus\",\n \"minus-circle\",\n \"circle-off\",\n \"circle-parking-off\",\n \"parking-circle-off\",\n \"circle-parking\",\n \"parking-circle\",\n \"circle-pause\",\n \"pause-circle\",\n \"circle-percent\",\n \"percent-circle\",\n \"circle-pile\",\n \"circle-play\",\n \"play-circle\",\n \"circle-plus\",\n \"plus-circle\",\n \"circle-pound-sterling\",\n \"circle-power\",\n \"power-circle\",\n \"circle-question-mark\",\n \"help-circle\",\n \"circle-help\",\n \"circle-slash-2\",\n \"circle-slashed\",\n \"circle-slash\",\n \"circle-small\",\n \"circle-star\",\n \"circle-stop\",\n \"stop-circle\",\n \"circle-user-round\",\n \"user-circle-2\",\n \"circle-user\",\n \"user-circle\",\n \"circle-x\",\n \"x-circle\",\n \"circle\",\n \"circuit-board\",\n \"citrus\",\n \"clapperboard\",\n \"clipboard-check\",\n \"clipboard-clock\",\n \"clipboard-copy\",\n \"clipboard-list\",\n \"clipboard-minus\",\n \"clipboard-paste\",\n \"clipboard-pen-line\",\n \"clipboard-signature\",\n \"clipboard-pen\",\n \"clipboard-edit\",\n \"clipboard-plus\",\n \"clipboard-type\",\n \"clipboard-x\",\n \"clipboard\",\n \"clock-1\",\n \"clock-10\",\n \"clock-11\",\n \"clock-12\",\n \"clock-2\",\n \"clock-3\",\n \"clock-4\",\n \"clock-5\",\n \"clock-6\",\n \"clock-7\",\n \"clock-8\",\n \"clock-9\",\n \"clock-alert\",\n \"clock-arrow-down\",\n \"clock-arrow-up\",\n \"clock-check\",\n \"clock-fading\",\n \"clock-plus\",\n \"clock\",\n \"closed-caption\",\n \"cloud-alert\",\n \"cloud-backup\",\n \"cloud-check\",\n \"cloud-cog\",\n \"cloud-download\",\n \"download-cloud\",\n \"cloud-drizzle\",\n \"cloud-fog\",\n \"cloud-hail\",\n \"cloud-lightning\",\n \"cloud-moon-rain\",\n \"cloud-moon\",\n \"cloud-off\",\n \"cloud-rain-wind\",\n \"cloud-rain\",\n \"cloud-snow\",\n \"cloud-sun-rain\",\n \"cloud-sun\",\n \"cloud-sync\",\n \"cloud-upload\",\n \"upload-cloud\",\n \"cloud\",\n \"cloudy\",\n \"clover\",\n \"club\",\n \"code-xml\",\n \"code-2\",\n \"code\",\n \"coffee\",\n \"cog\",\n \"coins\",\n \"columns-2\",\n \"columns\",\n \"columns-3-cog\",\n \"columns-settings\",\n \"table-config\",\n \"columns-3\",\n \"panels-left-right\",\n \"columns-4\",\n \"combine\",\n \"command\",\n \"compass\",\n \"component\",\n \"computer\",\n \"concierge-bell\",\n \"cone\",\n \"construction\",\n \"contact-round\",\n \"contact-2\",\n \"contact\",\n \"container\",\n \"contrast\",\n \"cookie\",\n \"cooking-pot\",\n \"copy-check\",\n \"copy-minus\",\n \"copy-plus\",\n \"copy-slash\",\n \"copy-x\",\n \"copy\",\n \"copyleft\",\n \"copyright\",\n \"corner-down-left\",\n \"corner-down-right\",\n \"corner-left-down\",\n \"corner-left-up\",\n \"corner-right-down\",\n \"corner-right-up\",\n \"corner-up-left\",\n \"corner-up-right\",\n \"cpu\",\n \"creative-commons\",\n \"credit-card\",\n \"croissant\",\n \"crop\",\n \"cross\",\n \"crosshair\",\n \"crown\",\n \"cuboid\",\n \"cup-soda\",\n \"currency\",\n \"cylinder\",\n \"dam\",\n \"database-backup\",\n \"database-search\",\n \"database-zap\",\n \"database\",\n \"decimals-arrow-left\",\n \"decimals-arrow-right\",\n \"delete\",\n \"dessert\",\n \"diameter\",\n \"diamond-minus\",\n \"diamond-percent\",\n \"percent-diamond\",\n \"diamond-plus\",\n \"diamond\",\n \"dice-1\",\n \"dice-2\",\n \"dice-3\",\n \"dice-4\",\n \"dice-5\",\n \"dice-6\",\n \"dices\",\n \"diff\",\n \"disc-2\",\n \"disc-3\",\n \"disc-album\",\n \"disc\",\n \"divide\",\n \"dna-off\",\n \"dna\",\n \"dock\",\n \"dog\",\n \"dollar-sign\",\n \"donut\",\n \"door-closed-locked\",\n \"door-closed\",\n \"door-open\",\n \"dot\",\n \"download\",\n \"drafting-compass\",\n \"drama\",\n \"drill\",\n \"drone\",\n \"droplet-off\",\n \"droplet\",\n \"droplets\",\n \"drum\",\n \"drumstick\",\n \"dumbbell\",\n \"ear-off\",\n \"ear\",\n \"earth-lock\",\n \"earth\",\n \"globe-2\",\n \"eclipse\",\n \"egg-fried\",\n \"egg-off\",\n \"egg\",\n \"ellipse\",\n \"ellipsis-vertical\",\n \"more-vertical\",\n \"ellipsis\",\n \"more-horizontal\",\n \"equal-approximately\",\n \"equal-not\",\n \"equal\",\n \"eraser\",\n \"ethernet-port\",\n \"euro\",\n \"ev-charger\",\n \"expand\",\n \"external-link\",\n \"eye-closed\",\n \"eye-off\",\n \"eye\",\n \"factory\",\n \"fan\",\n \"fast-forward\",\n \"feather\",\n \"fence\",\n \"ferris-wheel\",\n \"file-archive\",\n \"file-axis-3d\",\n \"file-axis-3-d\",\n \"file-badge\",\n \"file-badge-2\",\n \"file-box\",\n \"file-braces-corner\",\n \"file-json-2\",\n \"file-braces\",\n \"file-json\",\n \"file-chart-column-increasing\",\n \"file-bar-chart\",\n \"file-chart-column\",\n \"file-bar-chart-2\",\n \"file-chart-line\",\n \"file-line-chart\",\n \"file-chart-pie\",\n \"file-pie-chart\",\n \"file-check-corner\",\n \"file-check-2\",\n \"file-check\",\n \"file-clock\",\n \"file-code-corner\",\n \"file-code-2\",\n \"file-code\",\n \"file-cog\",\n \"file-cog-2\",\n \"file-diff\",\n \"file-digit\",\n \"file-down\",\n \"file-exclamation-point\",\n \"file-warning\",\n \"file-headphone\",\n \"file-audio\",\n \"file-audio-2\",\n \"file-heart\",\n \"file-image\",\n \"file-input\",\n \"file-key\",\n \"file-key-2\",\n \"file-lock\",\n \"file-lock-2\",\n \"file-minus-corner\",\n \"file-minus-2\",\n \"file-minus\",\n \"file-music\",\n \"file-output\",\n \"file-pen-line\",\n \"file-signature\",\n \"file-pen\",\n \"file-edit\",\n \"file-play\",\n \"file-video\",\n \"file-plus-corner\",\n \"file-plus-2\",\n \"file-plus\",\n \"file-question-mark\",\n \"file-question\",\n \"file-scan\",\n \"file-search-corner\",\n \"file-search-2\",\n \"file-search\",\n \"file-signal\",\n \"file-volume-2\",\n \"file-sliders\",\n \"file-spreadsheet\",\n \"file-stack\",\n \"file-symlink\",\n \"file-terminal\",\n \"file-text\",\n \"file-type-corner\",\n \"file-type-2\",\n \"file-type\",\n \"file-up\",\n \"file-user\",\n \"file-video-camera\",\n \"file-video-2\",\n \"file-volume\",\n \"file-x-corner\",\n \"file-x-2\",\n \"file-x\",\n \"file\",\n \"files\",\n \"film\",\n \"fingerprint-pattern\",\n \"fingerprint\",\n \"fire-extinguisher\",\n \"fish-off\",\n \"fish-symbol\",\n \"fish\",\n \"fishing-hook\",\n \"fishing-rod\",\n \"flag-off\",\n \"flag-triangle-left\",\n \"flag-triangle-right\",\n \"flag\",\n \"flame-kindling\",\n \"flame\",\n \"flashlight-off\",\n \"flashlight\",\n \"flask-conical-off\",\n \"flask-conical\",\n \"flask-round\",\n \"flip-horizontal-2\",\n \"flip-vertical-2\",\n \"flower-2\",\n \"flower\",\n \"focus\",\n \"fold-horizontal\",\n \"fold-vertical\",\n \"folder-archive\",\n \"folder-check\",\n \"folder-clock\",\n \"folder-closed\",\n \"folder-code\",\n \"folder-cog\",\n \"folder-cog-2\",\n \"folder-dot\",\n \"folder-down\",\n \"folder-git-2\",\n \"folder-git\",\n \"folder-heart\",\n \"folder-input\",\n \"folder-kanban\",\n \"folder-key\",\n \"folder-lock\",\n \"folder-minus\",\n \"folder-open-dot\",\n \"folder-open\",\n \"folder-output\",\n \"folder-pen\",\n \"folder-edit\",\n \"folder-plus\",\n \"folder-root\",\n \"folder-search-2\",\n \"folder-search\",\n \"folder-symlink\",\n \"folder-sync\",\n \"folder-tree\",\n \"folder-up\",\n \"folder-x\",\n \"folder\",\n \"folders\",\n \"footprints\",\n \"forklift\",\n \"form\",\n \"forward\",\n \"frame\",\n \"frown\",\n \"fuel\",\n \"fullscreen\",\n \"funnel-plus\",\n \"funnel-x\",\n \"filter-x\",\n \"funnel\",\n \"filter\",\n \"gallery-horizontal-end\",\n \"gallery-horizontal\",\n \"gallery-thumbnails\",\n \"gallery-vertical-end\",\n \"gallery-vertical\",\n \"gamepad-2\",\n \"gamepad-directional\",\n \"gamepad\",\n \"gauge\",\n \"gavel\",\n \"gem\",\n \"georgian-lari\",\n \"ghost\",\n \"gift\",\n \"git-branch-minus\",\n \"git-branch-plus\",\n \"git-branch\",\n \"git-commit-horizontal\",\n \"git-commit\",\n \"git-commit-vertical\",\n \"git-compare-arrows\",\n \"git-compare\",\n \"git-fork\",\n \"git-graph\",\n \"git-merge-conflict\",\n \"git-merge\",\n \"git-pull-request-arrow\",\n \"git-pull-request-closed\",\n \"git-pull-request-create-arrow\",\n \"git-pull-request-create\",\n \"git-pull-request-draft\",\n \"git-pull-request\",\n \"glass-water\",\n \"glasses\",\n \"globe-lock\",\n \"globe-off\",\n \"globe-x\",\n \"globe\",\n \"goal\",\n \"gpu\",\n \"graduation-cap\",\n \"grape\",\n \"grid-2x2-check\",\n \"grid-2-x-2-check\",\n \"grid-2x2-plus\",\n \"grid-2-x-2-plus\",\n \"grid-2x2-x\",\n \"grid-2-x-2-x\",\n \"grid-2x2\",\n \"grid-2-x-2\",\n \"grid-3x2\",\n \"grid-3x3\",\n \"grid\",\n \"grid-3-x-3\",\n \"grip-horizontal\",\n \"grip-vertical\",\n \"grip\",\n \"group\",\n \"guitar\",\n \"ham\",\n \"hamburger\",\n \"hammer\",\n \"hand-coins\",\n \"hand-fist\",\n \"hand-grab\",\n \"grab\",\n \"hand-heart\",\n \"hand-helping\",\n \"helping-hand\",\n \"hand-metal\",\n \"hand-platter\",\n \"hand\",\n \"handbag\",\n \"handshake\",\n \"hard-drive-download\",\n \"hard-drive-upload\",\n \"hard-drive\",\n \"hard-hat\",\n \"hash\",\n \"hat-glasses\",\n \"haze\",\n \"hd\",\n \"hdmi-port\",\n \"heading-1\",\n \"heading-2\",\n \"heading-3\",\n \"heading-4\",\n \"heading-5\",\n \"heading-6\",\n \"heading\",\n \"headphone-off\",\n \"headphones\",\n \"headset\",\n \"heart-crack\",\n \"heart-handshake\",\n \"heart-minus\",\n \"heart-off\",\n \"heart-plus\",\n \"heart-pulse\",\n \"heart\",\n \"heater\",\n \"helicopter\",\n \"hexagon\",\n \"highlighter\",\n \"history\",\n \"hop-off\",\n \"hop\",\n \"hospital\",\n \"hotel\",\n \"hourglass\",\n \"house-heart\",\n \"house-plug\",\n \"house-plus\",\n \"house-wifi\",\n \"house\",\n \"home\",\n \"ice-cream-bowl\",\n \"ice-cream-2\",\n \"ice-cream-cone\",\n \"ice-cream\",\n \"id-card-lanyard\",\n \"id-card\",\n \"image-down\",\n \"image-minus\",\n \"image-off\",\n \"image-play\",\n \"image-plus\",\n \"image-up\",\n \"image-upscale\",\n \"image\",\n \"images\",\n \"import\",\n \"inbox\",\n \"indian-rupee\",\n \"infinity\",\n \"info\",\n \"inspection-panel\",\n \"italic\",\n \"iteration-ccw\",\n \"iteration-cw\",\n \"japanese-yen\",\n \"joystick\",\n \"kanban\",\n \"kayak\",\n \"key-round\",\n \"key-square\",\n \"key\",\n \"keyboard-music\",\n \"keyboard-off\",\n \"keyboard\",\n \"lamp-ceiling\",\n \"lamp-desk\",\n \"lamp-floor\",\n \"lamp-wall-down\",\n \"lamp-wall-up\",\n \"lamp\",\n \"land-plot\",\n \"landmark\",\n \"languages\",\n \"laptop-minimal-check\",\n \"laptop-minimal\",\n \"laptop-2\",\n \"laptop\",\n \"lasso-select\",\n \"lasso\",\n \"laugh\",\n \"layers-2\",\n \"layers-plus\",\n \"layers\",\n \"layers-3\",\n \"layout-dashboard\",\n \"layout-grid\",\n \"layout-list\",\n \"layout-panel-left\",\n \"layout-panel-top\",\n \"layout-template\",\n \"leaf\",\n \"leafy-green\",\n \"lectern\",\n \"lens-concave\",\n \"lens-convex\",\n \"library-big\",\n \"library\",\n \"life-buoy\",\n \"ligature\",\n \"lightbulb-off\",\n \"lightbulb\",\n \"line-dot-right-horizontal\",\n \"line-squiggle\",\n \"line-style\",\n \"link-2-off\",\n \"link-2\",\n \"link\",\n \"list-check\",\n \"list-checks\",\n \"list-chevrons-down-up\",\n \"list-chevrons-up-down\",\n \"list-collapse\",\n \"list-end\",\n \"list-filter-plus\",\n \"list-filter\",\n \"list-indent-decrease\",\n \"outdent\",\n \"indent-decrease\",\n \"list-indent-increase\",\n \"indent\",\n \"indent-increase\",\n \"list-minus\",\n \"list-music\",\n \"list-ordered\",\n \"list-plus\",\n \"list-restart\",\n \"list-start\",\n \"list-todo\",\n \"list-tree\",\n \"list-video\",\n \"list-x\",\n \"list\",\n \"loader-circle\",\n \"loader-2\",\n \"loader-pinwheel\",\n \"loader\",\n \"locate-fixed\",\n \"locate-off\",\n \"locate\",\n \"lock-keyhole-open\",\n \"unlock-keyhole\",\n \"lock-keyhole\",\n \"lock-open\",\n \"unlock\",\n \"lock\",\n \"log-in\",\n \"log-out\",\n \"logs\",\n \"lollipop\",\n \"luggage\",\n \"magnet\",\n \"mail-check\",\n \"mail-minus\",\n \"mail-open\",\n \"mail-plus\",\n \"mail-question-mark\",\n \"mail-question\",\n \"mail-search\",\n \"mail-warning\",\n \"mail-x\",\n \"mail\",\n \"mailbox\",\n \"mails\",\n \"map-minus\",\n \"map-pin-check-inside\",\n \"map-pin-check\",\n \"map-pin-house\",\n \"map-pin-minus-inside\",\n \"map-pin-minus\",\n \"map-pin-off\",\n \"map-pin-pen\",\n \"location-edit\",\n \"map-pin-plus-inside\",\n \"map-pin-plus\",\n \"map-pin-search\",\n \"map-pin-x-inside\",\n \"map-pin-x\",\n \"map-pin\",\n \"map-pinned\",\n \"map-plus\",\n \"map\",\n \"mars-stroke\",\n \"mars\",\n \"martini\",\n \"maximize-2\",\n \"maximize\",\n \"medal\",\n \"megaphone-off\",\n \"megaphone\",\n \"meh\",\n \"memory-stick\",\n \"menu\",\n \"merge\",\n \"message-circle-check\",\n \"message-circle-code\",\n \"message-circle-dashed\",\n \"message-circle-heart\",\n \"message-circle-more\",\n \"message-circle-off\",\n \"message-circle-plus\",\n \"message-circle-question-mark\",\n \"message-circle-question\",\n \"message-circle-reply\",\n \"message-circle-warning\",\n \"message-circle-x\",\n \"message-circle\",\n \"message-square-check\",\n \"message-square-code\",\n \"message-square-dashed\",\n \"message-square-diff\",\n \"message-square-dot\",\n \"message-square-heart\",\n \"message-square-lock\",\n \"message-square-more\",\n \"message-square-off\",\n \"message-square-plus\",\n \"message-square-quote\",\n \"message-square-reply\",\n \"message-square-share\",\n \"message-square-text\",\n \"message-square-warning\",\n \"message-square-x\",\n \"message-square\",\n \"messages-square\",\n \"metronome\",\n \"mic-off\",\n \"mic-vocal\",\n \"mic-2\",\n \"mic\",\n \"microchip\",\n \"microscope\",\n \"microwave\",\n \"milestone\",\n \"milk-off\",\n \"milk\",\n \"minimize-2\",\n \"minimize\",\n \"minus\",\n \"mirror-rectangular\",\n \"mirror-round\",\n \"monitor-check\",\n \"monitor-cloud\",\n \"monitor-cog\",\n \"monitor-dot\",\n \"monitor-down\",\n \"monitor-off\",\n \"monitor-pause\",\n \"monitor-play\",\n \"monitor-smartphone\",\n \"monitor-speaker\",\n \"monitor-stop\",\n \"monitor-up\",\n \"monitor-x\",\n \"monitor\",\n \"moon-star\",\n \"moon\",\n \"motorbike\",\n \"mountain-snow\",\n \"mountain\",\n \"mouse-left\",\n \"mouse-off\",\n \"mouse-pointer-2-off\",\n \"mouse-pointer-2\",\n \"mouse-pointer-ban\",\n \"mouse-pointer-click\",\n \"mouse-pointer\",\n \"mouse-right\",\n \"mouse\",\n \"move-3d\",\n \"move-3-d\",\n \"move-diagonal-2\",\n \"move-diagonal\",\n \"move-down-left\",\n \"move-down-right\",\n \"move-down\",\n \"move-horizontal\",\n \"move-left\",\n \"move-right\",\n \"move-up-left\",\n \"move-up-right\",\n \"move-up\",\n \"move-vertical\",\n \"move\",\n \"music-2\",\n \"music-3\",\n \"music-4\",\n \"music\",\n \"navigation-2-off\",\n \"navigation-2\",\n \"navigation-off\",\n \"navigation\",\n \"network\",\n \"newspaper\",\n \"nfc\",\n \"non-binary\",\n \"notebook-pen\",\n \"notebook-tabs\",\n \"notebook-text\",\n \"notebook\",\n \"notepad-text-dashed\",\n \"notepad-text\",\n \"nut-off\",\n \"nut\",\n \"octagon-alert\",\n \"alert-octagon\",\n \"octagon-minus\",\n \"octagon-pause\",\n \"pause-octagon\",\n \"octagon-x\",\n \"x-octagon\",\n \"octagon\",\n \"omega\",\n \"option\",\n \"orbit\",\n \"origami\",\n \"package-2\",\n \"package-check\",\n \"package-minus\",\n \"package-open\",\n \"package-plus\",\n \"package-search\",\n \"package-x\",\n \"package\",\n \"paint-bucket\",\n \"paint-roller\",\n \"paintbrush-vertical\",\n \"paintbrush-2\",\n \"paintbrush\",\n \"palette\",\n \"panda\",\n \"panel-bottom-close\",\n \"panel-bottom-dashed\",\n \"panel-bottom-inactive\",\n \"panel-bottom-open\",\n \"panel-bottom\",\n \"panel-left-close\",\n \"sidebar-close\",\n \"panel-left-dashed\",\n \"panel-left-inactive\",\n \"panel-left-open\",\n \"sidebar-open\",\n \"panel-left-right-dashed\",\n \"panel-left\",\n \"sidebar\",\n \"panel-right-close\",\n \"panel-right-dashed\",\n \"panel-right-inactive\",\n \"panel-right-open\",\n \"panel-right\",\n \"panel-top-bottom-dashed\",\n \"panel-top-close\",\n \"panel-top-dashed\",\n \"panel-top-inactive\",\n \"panel-top-open\",\n \"panel-top\",\n \"panels-left-bottom\",\n \"panels-right-bottom\",\n \"panels-top-left\",\n \"layout\",\n \"paperclip\",\n \"parentheses\",\n \"parking-meter\",\n \"party-popper\",\n \"pause\",\n \"paw-print\",\n \"pc-case\",\n \"pen-line\",\n \"edit-3\",\n \"pen-off\",\n \"pen-tool\",\n \"pen\",\n \"edit-2\",\n \"pencil-line\",\n \"pencil-off\",\n \"pencil-ruler\",\n \"pencil\",\n \"pentagon\",\n \"percent\",\n \"person-standing\",\n \"philippine-peso\",\n \"phone-call\",\n \"phone-forwarded\",\n \"phone-incoming\",\n \"phone-missed\",\n \"phone-off\",\n \"phone-outgoing\",\n \"phone\",\n \"pi\",\n \"piano\",\n \"pickaxe\",\n \"picture-in-picture-2\",\n \"picture-in-picture\",\n \"piggy-bank\",\n \"pilcrow-left\",\n \"pilcrow-right\",\n \"pilcrow\",\n \"pill-bottle\",\n \"pill\",\n \"pin-off\",\n \"pin\",\n \"pipette\",\n \"pizza\",\n \"plane-landing\",\n \"plane-takeoff\",\n \"plane\",\n \"play\",\n \"plug-2\",\n \"plug-zap\",\n \"plug-zap-2\",\n \"plug\",\n \"plus\",\n \"pocket-knife\",\n \"podcast\",\n \"pointer-off\",\n \"pointer\",\n \"popcorn\",\n \"popsicle\",\n \"pound-sterling\",\n \"power-off\",\n \"power\",\n \"presentation\",\n \"printer-check\",\n \"printer-x\",\n \"printer\",\n \"projector\",\n \"proportions\",\n \"puzzle\",\n \"pyramid\",\n \"qr-code\",\n \"quote\",\n \"rabbit\",\n \"radar\",\n \"radiation\",\n \"radical\",\n \"radio-off\",\n \"radio-receiver\",\n \"radio-tower\",\n \"radio\",\n \"radius\",\n \"rainbow\",\n \"rat\",\n \"ratio\",\n \"receipt-cent\",\n \"receipt-euro\",\n \"receipt-indian-rupee\",\n \"receipt-japanese-yen\",\n \"receipt-pound-sterling\",\n \"receipt-russian-ruble\",\n \"receipt-swiss-franc\",\n \"receipt-text\",\n \"receipt-turkish-lira\",\n \"receipt\",\n \"rectangle-circle\",\n \"rectangle-ellipsis\",\n \"form-input\",\n \"rectangle-goggles\",\n \"rectangle-horizontal\",\n \"rectangle-vertical\",\n \"recycle\",\n \"redo-2\",\n \"redo-dot\",\n \"redo\",\n \"refresh-ccw-dot\",\n \"refresh-ccw\",\n \"refresh-cw-off\",\n \"refresh-cw\",\n \"refrigerator\",\n \"regex\",\n \"remove-formatting\",\n \"repeat-1\",\n \"repeat-2\",\n \"repeat\",\n \"replace-all\",\n \"replace\",\n \"reply-all\",\n \"reply\",\n \"rewind\",\n \"ribbon\",\n \"road\",\n \"rocket\",\n \"rocking-chair\",\n \"roller-coaster\",\n \"rose\",\n \"rotate-3d\",\n \"rotate-3-d\",\n \"rotate-ccw-key\",\n \"rotate-ccw-square\",\n \"rotate-ccw\",\n \"rotate-cw-square\",\n \"rotate-cw\",\n \"route-off\",\n \"route\",\n \"router\",\n \"rows-2\",\n \"rows\",\n \"rows-3\",\n \"panels-top-bottom\",\n \"rows-4\",\n \"rss\",\n \"ruler-dimension-line\",\n \"ruler\",\n \"russian-ruble\",\n \"sailboat\",\n \"salad\",\n \"sandwich\",\n \"satellite-dish\",\n \"satellite\",\n \"saudi-riyal\",\n \"save-all\",\n \"save-off\",\n \"save\",\n \"scale-3d\",\n \"scale-3-d\",\n \"scale\",\n \"scaling\",\n \"scan-barcode\",\n \"scan-eye\",\n \"scan-face\",\n \"scan-heart\",\n \"scan-line\",\n \"scan-qr-code\",\n \"scan-search\",\n \"scan-text\",\n \"scan\",\n \"school\",\n \"scissors-line-dashed\",\n \"scissors\",\n \"scooter\",\n \"screen-share-off\",\n \"screen-share\",\n \"scroll-text\",\n \"scroll\",\n \"search-alert\",\n \"search-check\",\n \"search-code\",\n \"search-slash\",\n \"search-x\",\n \"search\",\n \"section\",\n \"send-horizontal\",\n \"send-horizonal\",\n \"send-to-back\",\n \"send\",\n \"separator-horizontal\",\n \"separator-vertical\",\n \"server-cog\",\n \"server-crash\",\n \"server-off\",\n \"server\",\n \"settings-2\",\n \"settings\",\n \"shapes\",\n \"share-2\",\n \"share\",\n \"sheet\",\n \"shell\",\n \"shelving-unit\",\n \"shield-alert\",\n \"shield-ban\",\n \"shield-check\",\n \"shield-cog-corner\",\n \"shield-cog\",\n \"shield-ellipsis\",\n \"shield-half\",\n \"shield-minus\",\n \"shield-off\",\n \"shield-plus\",\n \"shield-question-mark\",\n \"shield-question\",\n \"shield-user\",\n \"shield-x\",\n \"shield-close\",\n \"shield\",\n \"ship-wheel\",\n \"ship\",\n \"shirt\",\n \"shopping-bag\",\n \"shopping-basket\",\n \"shopping-cart\",\n \"shovel\",\n \"shower-head\",\n \"shredder\",\n \"shrimp\",\n \"shrink\",\n \"shrub\",\n \"shuffle\",\n \"sigma\",\n \"signal-high\",\n \"signal-low\",\n \"signal-medium\",\n \"signal-zero\",\n \"signal\",\n \"signature\",\n \"signpost-big\",\n \"signpost\",\n \"siren\",\n \"skip-back\",\n \"skip-forward\",\n \"skull\",\n \"slash\",\n \"slice\",\n \"sliders-horizontal\",\n \"sliders-vertical\",\n \"sliders\",\n \"smartphone-charging\",\n \"smartphone-nfc\",\n \"smartphone\",\n \"smile-plus\",\n \"smile\",\n \"snail\",\n \"snowflake\",\n \"soap-dispenser-droplet\",\n \"sofa\",\n \"solar-panel\",\n \"soup\",\n \"space\",\n \"spade\",\n \"sparkle\",\n \"sparkles\",\n \"stars\",\n \"speaker\",\n \"speech\",\n \"spell-check-2\",\n \"spell-check\",\n \"spline-pointer\",\n \"spline\",\n \"split\",\n \"spool\",\n \"sport-shoe\",\n \"spotlight\",\n \"spray-can\",\n \"sprout\",\n \"square-activity\",\n \"activity-square\",\n \"square-arrow-down-left\",\n \"arrow-down-left-square\",\n \"square-arrow-down-right\",\n \"arrow-down-right-square\",\n \"square-arrow-down\",\n \"arrow-down-square\",\n \"square-arrow-left\",\n \"arrow-left-square\",\n \"square-arrow-out-down-left\",\n \"arrow-down-left-from-square\",\n \"square-arrow-out-down-right\",\n \"arrow-down-right-from-square\",\n \"square-arrow-out-up-left\",\n \"arrow-up-left-from-square\",\n \"square-arrow-out-up-right\",\n \"arrow-up-right-from-square\",\n \"square-arrow-right-enter\",\n \"square-arrow-right-exit\",\n \"square-arrow-right\",\n \"arrow-right-square\",\n \"square-arrow-up-left\",\n \"arrow-up-left-square\",\n \"square-arrow-up-right\",\n \"arrow-up-right-square\",\n \"square-arrow-up\",\n \"arrow-up-square\",\n \"square-asterisk\",\n \"asterisk-square\",\n \"square-bottom-dashed-scissors\",\n \"scissors-square-dashed-bottom\",\n \"square-centerline-dashed-horizontal\",\n \"flip-horizontal\",\n \"square-centerline-dashed-vertical\",\n \"flip-vertical\",\n \"square-chart-gantt\",\n \"gantt-chart-square\",\n \"square-gantt-chart\",\n \"square-check-big\",\n \"check-square\",\n \"square-check\",\n \"check-square-2\",\n \"square-chevron-down\",\n \"chevron-down-square\",\n \"square-chevron-left\",\n \"chevron-left-square\",\n \"square-chevron-right\",\n \"chevron-right-square\",\n \"square-chevron-up\",\n \"chevron-up-square\",\n \"square-code\",\n \"code-square\",\n \"square-dashed-bottom-code\",\n \"square-dashed-bottom\",\n \"square-dashed-kanban\",\n \"kanban-square-dashed\",\n \"square-dashed-mouse-pointer\",\n \"mouse-pointer-square-dashed\",\n \"square-dashed-text\",\n \"text-selection\",\n \"text-select\",\n \"square-dashed-top-solid\",\n \"square-dashed\",\n \"box-select\",\n \"square-divide\",\n \"divide-square\",\n \"square-dot\",\n \"dot-square\",\n \"square-equal\",\n \"equal-square\",\n \"square-function\",\n \"function-square\",\n \"square-kanban\",\n \"kanban-square\",\n \"square-library\",\n \"library-square\",\n \"square-m\",\n \"m-square\",\n \"square-menu\",\n \"menu-square\",\n \"square-minus\",\n \"minus-square\",\n \"square-mouse-pointer\",\n \"inspect\",\n \"square-parking-off\",\n \"parking-square-off\",\n \"square-parking\",\n \"parking-square\",\n \"square-pause\",\n \"square-pen\",\n \"pen-box\",\n \"edit\",\n \"pen-square\",\n \"square-percent\",\n \"percent-square\",\n \"square-pi\",\n \"pi-square\",\n \"square-pilcrow\",\n \"pilcrow-square\",\n \"square-play\",\n \"play-square\",\n \"square-plus\",\n \"plus-square\",\n \"square-power\",\n \"power-square\",\n \"square-radical\",\n \"square-round-corner\",\n \"square-scissors\",\n \"scissors-square\",\n \"square-sigma\",\n \"sigma-square\",\n \"square-slash\",\n \"slash-square\",\n \"square-split-horizontal\",\n \"split-square-horizontal\",\n \"square-split-vertical\",\n \"split-square-vertical\",\n \"square-square\",\n \"square-stack\",\n \"square-star\",\n \"square-stop\",\n \"square-terminal\",\n \"terminal-square\",\n \"square-user-round\",\n \"user-square-2\",\n \"square-user\",\n \"user-square\",\n \"square-x\",\n \"x-square\",\n \"square\",\n \"squares-exclude\",\n \"squares-intersect\",\n \"squares-subtract\",\n \"squares-unite\",\n \"squircle-dashed\",\n \"squircle\",\n \"squirrel\",\n \"stamp\",\n \"star-half\",\n \"star-off\",\n \"star\",\n \"step-back\",\n \"step-forward\",\n \"stethoscope\",\n \"sticker\",\n \"sticky-note\",\n \"stone\",\n \"store\",\n \"stretch-horizontal\",\n \"stretch-vertical\",\n \"strikethrough\",\n \"subscript\",\n \"sun-dim\",\n \"sun-medium\",\n \"sun-moon\",\n \"sun-snow\",\n \"sun\",\n \"sunrise\",\n \"sunset\",\n \"superscript\",\n \"swatch-book\",\n \"swiss-franc\",\n \"switch-camera\",\n \"sword\",\n \"swords\",\n \"syringe\",\n \"table-2\",\n \"table-cells-merge\",\n \"table-cells-split\",\n \"table-columns-split\",\n \"table-of-contents\",\n \"table-properties\",\n \"table-rows-split\",\n \"table\",\n \"tablet-smartphone\",\n \"tablet\",\n \"tablets\",\n \"tag\",\n \"tags\",\n \"tally-1\",\n \"tally-2\",\n \"tally-3\",\n \"tally-4\",\n \"tally-5\",\n \"tangent\",\n \"target\",\n \"telescope\",\n \"tent-tree\",\n \"tent\",\n \"terminal\",\n \"test-tube-diagonal\",\n \"test-tube-2\",\n \"test-tube\",\n \"test-tubes\",\n \"text-align-center\",\n \"align-center\",\n \"text-align-end\",\n \"align-right\",\n \"text-align-justify\",\n \"align-justify\",\n \"text-align-start\",\n \"text\",\n \"align-left\",\n \"text-cursor-input\",\n \"text-cursor\",\n \"text-initial\",\n \"letter-text\",\n \"text-quote\",\n \"text-search\",\n \"text-wrap\",\n \"wrap-text\",\n \"theater\",\n \"thermometer-snowflake\",\n \"thermometer-sun\",\n \"thermometer\",\n \"thumbs-down\",\n \"thumbs-up\",\n \"ticket-check\",\n \"ticket-minus\",\n \"ticket-percent\",\n \"ticket-plus\",\n \"ticket-slash\",\n \"ticket-x\",\n \"ticket\",\n \"tickets-plane\",\n \"tickets\",\n \"timer-off\",\n \"timer-reset\",\n \"timer\",\n \"toggle-left\",\n \"toggle-right\",\n \"toilet\",\n \"tool-case\",\n \"toolbox\",\n \"tornado\",\n \"torus\",\n \"touchpad-off\",\n \"touchpad\",\n \"towel-rack\",\n \"tower-control\",\n \"toy-brick\",\n \"tractor\",\n \"traffic-cone\",\n \"train-front-tunnel\",\n \"train-front\",\n \"train-track\",\n \"tram-front\",\n \"train\",\n \"transgender\",\n \"trash-2\",\n \"trash\",\n \"tree-deciduous\",\n \"tree-palm\",\n \"palmtree\",\n \"tree-pine\",\n \"trees\",\n \"trending-down\",\n \"trending-up-down\",\n \"trending-up\",\n \"triangle-alert\",\n \"alert-triangle\",\n \"triangle-dashed\",\n \"triangle-right\",\n \"triangle\",\n \"trophy\",\n \"truck-electric\",\n \"truck\",\n \"turkish-lira\",\n \"turntable\",\n \"turtle\",\n \"tv-minimal-play\",\n \"tv-minimal\",\n \"tv-2\",\n \"tv\",\n \"type-outline\",\n \"type\",\n \"umbrella-off\",\n \"umbrella\",\n \"underline\",\n \"undo-2\",\n \"undo-dot\",\n \"undo\",\n \"unfold-horizontal\",\n \"unfold-vertical\",\n \"ungroup\",\n \"university\",\n \"school-2\",\n \"unlink-2\",\n \"unlink\",\n \"unplug\",\n \"upload\",\n \"usb\",\n \"user-check\",\n \"user-cog\",\n \"user-key\",\n \"user-lock\",\n \"user-minus\",\n \"user-pen\",\n \"user-plus\",\n \"user-round-check\",\n \"user-check-2\",\n \"user-round-cog\",\n \"user-cog-2\",\n \"user-round-key\",\n \"user-round-minus\",\n \"user-minus-2\",\n \"user-round-pen\",\n \"user-round-plus\",\n \"user-plus-2\",\n \"user-round-search\",\n \"user-round-x\",\n \"user-x-2\",\n \"user-round\",\n \"user-2\",\n \"user-search\",\n \"user-star\",\n \"user-x\",\n \"user\",\n \"users-round\",\n \"users-2\",\n \"users\",\n \"utensils-crossed\",\n \"fork-knife-crossed\",\n \"utensils\",\n \"fork-knife\",\n \"utility-pole\",\n \"van\",\n \"variable\",\n \"vault\",\n \"vector-square\",\n \"vegan\",\n \"venetian-mask\",\n \"venus-and-mars\",\n \"venus\",\n \"vibrate-off\",\n \"vibrate\",\n \"video-off\",\n \"video\",\n \"videotape\",\n \"view\",\n \"voicemail\",\n \"volleyball\",\n \"volume-1\",\n \"volume-2\",\n \"volume-off\",\n \"volume-x\",\n \"volume\",\n \"vote\",\n \"wallet-cards\",\n \"wallet-minimal\",\n \"wallet-2\",\n \"wallet\",\n \"wallpaper\",\n \"wand-sparkles\",\n \"wand-2\",\n \"wand\",\n \"warehouse\",\n \"washing-machine\",\n \"watch\",\n \"waves-arrow-down\",\n \"waves-arrow-up\",\n \"waves-ladder\",\n \"waves\",\n \"waypoints\",\n \"webcam\",\n \"webhook-off\",\n \"webhook\",\n \"weight-tilde\",\n \"weight\",\n \"wheat-off\",\n \"wheat\",\n \"whole-word\",\n \"wifi-cog\",\n \"wifi-high\",\n \"wifi-low\",\n \"wifi-off\",\n \"wifi-pen\",\n \"wifi-sync\",\n \"wifi-zero\",\n \"wifi\",\n \"wind-arrow-down\",\n \"wind\",\n \"wine-off\",\n \"wine\",\n \"workflow\",\n \"worm\",\n \"wrench\",\n \"x-line-top\",\n \"x\",\n \"zap-off\",\n \"zap\",\n \"zodiac-aquarius\",\n \"zodiac-aries\",\n \"zodiac-cancer\",\n \"zodiac-capricorn\",\n \"zodiac-gemini\",\n \"zodiac-leo\",\n \"zodiac-libra\",\n \"zodiac-ophiuchus\",\n \"zodiac-pisces\",\n \"zodiac-sagittarius\",\n \"zodiac-scorpio\",\n \"zodiac-taurus\",\n \"zodiac-virgo\",\n \"zoom-in\",\n \"zoom-out\",\n]);\n\nexport const LAYOUT_SECTION_ICON_SET: ReadonlySet<string> = new Set(LAYOUT_SECTION_ICONS);\nexport type LayoutSectionIcon = string;\n","/** Stable identifiers used by every project and page layout document. */\nexport const PAGE_CONTENT_ANCHOR_ID = \"page-content\" as const;\nexport const NAVIGATION_SECTION_ID = \"navigation\" as const;\nexport const FOOTER_SECTION_ID = \"footer\" as const;\n\n/** Locked transport/validation set shared by authoring surfaces and the server. */\nexport {\n LAYOUT_SECTION_ICONS,\n LAYOUT_SECTION_ICON_SET,\n type LayoutSectionIcon,\n} from \"./layout-lucide-icons.js\";\nimport type { LayoutSectionIcon } from \"./layout-lucide-icons.js\";\nimport { inWindow, type VisibilityWindow } from \"./block.js\";\n\nexport type LayoutZone = \"above-page-content\" | \"below-page-content\";\nexport type ReservedLayoutSection = \"navigation\" | \"footer\";\n\nexport type LayoutScalarFieldType =\n | \"text\"\n | \"longtext\"\n | \"richtext\"\n | \"number\"\n | \"toggle\"\n | \"date\"\n | \"image\"\n | \"file\"\n | \"link\"\n /** A call to action as one value, `{ label, href, variant? }`: what a page's `button` field holds. */\n | \"button\"\n | \"email\"\n | \"phone\"\n | \"select\"\n | \"color\"\n | \"json\"\n | \"reference\"\n | \"multi-reference\";\n\nexport type LayoutFieldType = LayoutScalarFieldType | \"group\" | \"repeater\";\n\n/** A recursive, stable-ID field contract shared by Sections and variant inputs. */\nexport interface LayoutFieldDefinition {\n id: string;\n slug: string;\n label: string;\n type: LayoutFieldType;\n required?: boolean;\n defaultValue?: unknown;\n config?: {\n options?: Array<{ label: string; value: string }>;\n referenceModelId?: string;\n minItems?: number;\n maxItems?: number;\n } & Record<string, unknown>;\n /** Required for group/repeater; forbidden for scalar fields. */\n fields?: LayoutFieldDefinition[];\n /** Shown to editors under the field. */\n helpText?: string;\n /** Server-owned: who wrote `helpText`. */\n helpSource?: \"auto\" | \"human\" | \"agent\";\n /** `true`: no route the last release inspected renders this field — hidden, never deleted. `false`: a person keeps it shown. */\n stale?: boolean;\n /** false: a page may not override this value; the Global value renders on every page. Absent = true. */\n overridable?: boolean;\n /** Shown where the page editor would have offered the field. Required when overridable is false. */\n lockReason?: string;\n}\n\n/** The canonical public input contract all variants in a group implement. */\nexport type CanonicalInputDefinition = LayoutFieldDefinition;\n\n/** Maps one canonical input onto one or more internal component prop paths. */\nexport interface VariantInputMapping {\n inputId: string;\n targets: Array<{ blockId: string; path: string }>;\n}\n\nexport interface ComponentVariantGroup {\n id: string;\n workspaceId: string;\n projectId?: string | null;\n name: string;\n slug: string;\n canonicalInputs: CanonicalInputDefinition[];\n status: \"draft\" | \"published\";\n}\n\nexport interface LayoutFieldItem {\n id: string;\n kind: \"field\";\n fieldId: string;\n}\n\nexport interface LayoutComponentItem {\n id: string;\n kind: \"component\";\n componentId: string;\n variantGroupId?: string;\n bindings: Array<{ inputId: string; fieldId: string }>;\n literalValues?: Record<string, unknown>;\n}\n\nexport type LayoutSectionItem = LayoutFieldItem | LayoutComponentItem;\n\nexport interface LayoutSection {\n id: string;\n name: string;\n slug: string;\n icon: string;\n zone: LayoutZone;\n orderKey: string;\n reserved?: ReservedLayoutSection;\n fields: LayoutFieldDefinition[];\n items: LayoutSectionItem[];\n /** What this Section is and which pages show it — for editors; no build reads it. */\n description?: string;\n /** Server-owned: who wrote `description`. */\n helpSource?: \"auto\" | \"human\" | \"agent\";\n /**\n * The language this Section is a VARIANT for — BCP-47, lowercase (`fr`, `pt-br`).\n *\n * A localized site renders ONE header per route, not two: `/fr/*` shows the French header in\n * the slot the base header holds everywhere else. So a variant is not a Section of its own in\n * the render order. It never renders unless a resolver is handed its locale, and then it takes\n * its base's place — zone, order and reserved slot included — rather than sitting beside it.\n * Set together with `variantOf`; `validateLayout` names every way the pair can be malformed.\n */\n locale?: string;\n /** The stable id of the base Section this variant replaces on routes in `locale`. */\n variantOf?: string;\n /**\n * When the Section is shown (an announcement bar, a seasonal band). Absent = always. It is the\n * SLOT's: a locale variant shows when its base does, whatever the variant's own row says.\n */\n window?: VisibilityWindow;\n}\n\nexport interface LayoutStructureDocument {\n version: 1;\n pageContentAnchor: { id: typeof PAGE_CONTENT_ANCHOR_ID };\n sections: LayoutSection[];\n}\n\nexport interface LayoutDataDocument {\n version: 1;\n sections: Record<string, { fields: Record<string, unknown> }>;\n}\n\nexport type PageLayoutOverrideState =\n | \"inherit\"\n | \"override-content\"\n | \"customize-structure\"\n | \"disable\";\n\nexport interface PageSectionPlacement {\n zone: LayoutZone;\n afterSectionId?: string;\n beforeSectionId?: string;\n localOrderKey: string;\n}\n\nexport type PageLayoutSectionOverride =\n | { sectionId: string; state: \"inherit\" }\n | { sectionId: string; state: \"override-content\"; values: Record<string, unknown> }\n | {\n sectionId: string;\n state: \"customize-structure\";\n section: LayoutSection;\n data: { fields: Record<string, unknown> };\n /** Retained when the inherited Section is later deleted. */\n placement: PageSectionPlacement;\n }\n | { sectionId: string; state: \"disable\" };\n\nexport interface PageOnlyLayoutSection {\n section: LayoutSection;\n data: { fields: Record<string, unknown> };\n placement: PageSectionPlacement;\n}\n\nexport type PageLayoutSectionStructureOverride =\n | { sectionId: string; state: \"inherit\" }\n | { sectionId: string; state: \"override-content\" }\n | { sectionId: string; state: \"customize-structure\"; section: LayoutSection; placement: PageSectionPlacement }\n | { sectionId: string; state: \"disable\" };\n\n/** Persisted in pages.layout_override_structure_json. */\nexport interface PageLayoutOverrideStructureDocument {\n version: 1;\n sections: PageLayoutSectionStructureOverride[];\n pageOnlySections: Array<{ section: LayoutSection; placement: PageSectionPlacement }>;\n}\n\n/** Persisted independently so values can be patched without rewriting structure. */\nexport interface PageLayoutOverrideDataDocument {\n version: 1;\n sections: Record<string, { fields: Record<string, unknown> }>;\n pageOnlySections: Record<string, { fields: Record<string, unknown> }>;\n}\n\n/** Canonical in-memory form consumed by the pure resolver. */\nexport interface PageLayoutOverrideDocument {\n version: 1;\n sections: PageLayoutSectionOverride[];\n pageOnlySections: PageOnlyLayoutSection[];\n}\n\n/** Canonical, discriminated Management/MCP authoring transport. Authority is derived from type. */\nexport type ManagementLayoutCommand =\n | { type: \"set-section-values\"; sectionId: string; values: Record<string, unknown> }\n | { type: \"set-field-value\"; sectionId: string; fieldId: string; value: unknown }\n | { type: \"add-component\"; sectionId: string; componentId: string; variantGroupId?: string; bindings?: LayoutComponentItem[\"bindings\"]; literalValues?: Record<string, unknown> }\n | { type: \"remove-item\"; sectionId: string; itemId: string }\n | { type: \"move-component\"; sectionId: string; itemId: string; index: number }\n | { type: \"move-item\"; sectionId: string; itemId: string; index: number }\n | { type: \"swap-component-variant\"; sectionId: string; itemId: string; componentId: string }\n | { type: \"set-page-state\"; sectionId: string; state: PageLayoutOverrideState | \"reset\" }\n | { type: \"set-section-state\"; sectionId: string; state: PageLayoutOverrideState | \"reset\" }\n | { type: \"add-section\"; name: string; icon: LayoutSectionIcon; zone: \"before_page\" | \"after_page\"; window?: VisibilityWindow }\n | { type: \"restore-section\"; section: LayoutSection; data: { fields: Record<string, unknown> }; placement?: PageSectionPlacement }\n | { type: \"update-section\"; sectionId: string; name?: string; icon?: LayoutSectionIcon; slug?: string; zone?: LayoutZone; orderKey?: string; description?: string; window?: VisibilityWindow | null }\n | { type: \"remove-section\"; sectionId: string }\n | { type: \"move-section\"; sectionId: string; afterId?: string | null; beforeId?: string | null }\n | { type: \"add-field\"; sectionId: string; parentFieldId?: string; field?: LayoutFieldDefinition; fieldType?: LayoutFieldType }\n | { type: \"update-field\"; sectionId: string; fieldId: string; patch: Partial<Omit<LayoutFieldDefinition, \"id\">> }\n | { type: \"remove-field\"; sectionId: string; fieldId: string }\n | { type: \"move-field\"; sectionId: string; itemId: string; index: number }\n | { type: \"set-bindings\"; sectionId: string; itemId: string; bindings: LayoutComponentItem[\"bindings\"]; literalValues?: Record<string, unknown> };\n\nexport type ResolvedLayoutNode =\n | { kind: \"page-content\"; id: typeof PAGE_CONTENT_ANCHOR_ID }\n | {\n kind: \"section\";\n id: string;\n section: LayoutSection;\n data: { fields: Record<string, unknown> };\n source: \"inherit\" | \"override-content\" | \"customize-structure\" | \"page-only\" | \"detached\";\n };\n\nexport interface DeliveredLayout {\n version: 1;\n nodes: Array<\n | { kind: \"page-content\"; id: typeof PAGE_CONTENT_ANCHOR_ID }\n | { kind: \"section\"; id: string; slug: string; name: string; source: Extract<ResolvedLayoutNode, { kind: \"section\" }>[\"source\"] }\n >;\n sections: Record<string, {\n id: string;\n slug: string;\n name: string;\n /**\n * Present ONLY on a locale variant (`LayoutSection.locale`/`variantOf`), so a base entry is\n * byte-identical to what it was before variants existed. The Global Layout delivers every\n * variant under its own slug beside the bases; a page delivers the variant its route's\n * locale swapped in, under the SLOT's slug — the one its `nodes` entry names.\n */\n locale?: string;\n variantOf?: string;\n /** Present only on a Section that has one. A published read never delivers a Section outside it. */\n window?: VisibilityWindow;\n fields: Record<string, unknown>;\n items: Array<\n | {\n id: string;\n kind: \"field\";\n fieldId: string;\n /** The stored value, unchanged. */\n value: unknown;\n /**\n * Present only when the field holds references: `value` with them hydrated (depth 1),\n * as Delivery serves an entry's (an entry → `{ id, slug, title, data, … }`, a page /\n * form / collection target → `{ kind, id, title, slug, url }`). A published read\n * resolves published targets only; one that did not resolve stays as stored.\n */\n resolved?: unknown;\n }\n | {\n id: string;\n kind: \"component\";\n componentId: string;\n variantGroupId?: string;\n canonicalInputs: CanonicalInputDefinition[];\n bindings: LayoutComponentItem[\"bindings\"];\n canonicalValues: Record<string, unknown>;\n resolvedProps: Record<string, unknown>;\n /**\n * `prop.key` → canonical `inputId` — the relation `resolvedProps` consumes and throws\n * away (`output[prop.key] = canonicalValues[mapping.inputId]`).\n *\n * Without it a renderer holds a component prop key and NO address: `logoAlt`/`links`/\n * `cta` are the component's own bare keys, and nothing relates them back to the layout\n * field a write must land on. With it the chain closes — `prop.key` → `inputId` →\n * (`bindings`, already delivered above) → `fieldId` → `set-field-value(sectionId,\n * fieldId)`. That is what makes global chrome click-to-edit (FLO-1179).\n *\n * Additive and always present (`{}` when the item has no variant mappings), so an\n * older consumer that ignores it is byte-identical to before.\n */\n propInputs: Record<string, string>;\n blocks: unknown[];\n }\n >;\n }>;\n}\n\n/**\n * A Layout structure as a visitor is served it at `now`: every Section outside its window\n * removed, and with a removed base its locale variants (a variant only ever renders in its base's\n * slot). The same document when nothing is removed, and anything that is not one as it came.\n */\nexport function visibleLayoutStructure<T>(structure: T, now: Date | number): T {\n const sections = (structure as { sections?: unknown } | null | undefined)?.sections;\n if (!Array.isArray(sections)) return structure;\n const hidden = new Set(\n (sections as LayoutSection[]).filter((section) => section && !section.variantOf && !inWindow(section, now)).map((section) => section.id),\n );\n if (hidden.size === 0) return structure;\n return {\n ...(structure as object),\n sections: (sections as LayoutSection[]).filter((section) => !hidden.has(section?.variantOf ?? section?.id)),\n } as T;\n}\n\n/**\n * A delivered Layout as a visitor is served it at `now`: the nodes whose Section is outside its\n * window removed, with their `sections` entries and any variant delivered beside a removed base.\n * Applied AFTER any cache, so a cached Layout never serves a Section past its boundary. The same\n * object when nothing is removed.\n */\nexport function visibleDeliveredLayout<T extends DeliveredLayout | null | undefined>(layout: T, now: Date | number): T {\n if (!layout) return layout;\n const hiddenIds = new Set<string>();\n const hiddenSlugs = new Set<string>();\n for (const node of layout.nodes) {\n if (node.kind !== \"section\" || inWindow(layout.sections[node.slug], now)) continue;\n hiddenIds.add(node.id);\n hiddenSlugs.add(node.slug);\n }\n if (hiddenIds.size === 0) return layout;\n return {\n ...layout,\n nodes: layout.nodes.filter((node) => node.kind !== \"section\" || !hiddenIds.has(node.id)),\n sections: Object.fromEntries(\n Object.entries(layout.sections).filter(([slug, section]) => !hiddenSlugs.has(slug) && !(section.variantOf && hiddenIds.has(section.variantOf))),\n ),\n } as T;\n}\n","/**\n * Generated by scripts/gen-dock-icon-names.mjs from the vendored icon tarball\n * (sha256 0691620e50bdf453c2fed06224d9dc52d521574ab254a149eba47664b92fb889)\n * and the vendored line-icon subset (sha256 06cd85d602d1104d962ed8ace64f6c4d64846ee50bd62bd328252c9d8f697b75).\n * Do not edit by hand: rerun the script (`--check` fails CI on drift).\n *\n * The closed vocabulary for `ui.icon` (field ui, fieldsets, prop ui.group). `as const` because a\n * z.enum needs the literal tuple; a `readonly string[]` would type every string as valid.\n */\nexport const DOCK_ICON_NAMES = [\n \"abc\",\n \"access-denied\",\n \"activity\",\n \"add\",\n \"add-circle\",\n \"add-comment\",\n \"add-document\",\n \"add-user\",\n \"address-book\",\n \"adjustments\",\n \"adjustments-horizontal\",\n \"alarm\",\n \"alert-triangle\",\n \"align-left\",\n \"api\",\n \"app-window\",\n \"apple\",\n \"apps\",\n \"archive\",\n \"arrow-back-up\",\n \"arrow-down\",\n \"arrow-guide\",\n \"arrow-left\",\n \"arrow-right\",\n \"arrow-top-right\",\n \"arrow-up\",\n \"arrows-diagonal\",\n \"arrows-down\",\n \"arrows-exchange\",\n \"arrows-horizontal\",\n \"arrows-left-right\",\n \"arrows-shuffle\",\n \"arrows-sort\",\n \"article\",\n \"aspect-ratio\",\n \"asterisk\",\n \"award\",\n \"axis-x\",\n \"backpack\",\n \"badge\",\n \"badge-cc\",\n \"badges\",\n \"bar-chart\",\n \"basket\",\n \"bell\",\n \"bill\",\n \"binary-document\",\n \"block-content\",\n \"block-element\",\n \"blockquote\",\n \"bold\",\n \"bolt\",\n \"book\",\n \"book-2\",\n \"bookmark\",\n \"bookmark-filled\",\n \"books\",\n \"bottle\",\n \"box\",\n \"brand-dribbble\",\n \"brand-facebook\",\n \"brand-instagram\",\n \"brand-linkedin\",\n \"brand-pinterest\",\n \"brand-tiktok\",\n \"brand-x\",\n \"brand-youtube\",\n \"briefcase\",\n \"broadcast\",\n \"browser\",\n \"bug\",\n \"building\",\n \"building-skyscraper\",\n \"building-store\",\n \"bulb-filled\",\n \"bulb-outline\",\n \"calculator\",\n \"calendar\",\n \"calendar-dollar\",\n \"calendar-event\",\n \"calendar-exclamation\",\n \"calendar-off\",\n \"calendar-plus\",\n \"calendar-star\",\n \"calendar-time\",\n \"camera\",\n \"campfire\",\n \"carousel-horizontal\",\n \"case\",\n \"cash\",\n \"category\",\n \"category-2\",\n \"chart-area\",\n \"chart-arrows\",\n \"chart-bar\",\n \"chart-bar-popular\",\n \"chart-donut\",\n \"chart-dots\",\n \"chart-line\",\n \"chart-upward\",\n \"check\",\n \"checkbox\",\n \"checklist\",\n \"checkmark\",\n \"checkmark-circle\",\n \"chef-hat\",\n \"chevron-down\",\n \"chevron-left\",\n \"chevron-right\",\n \"chevron-up\",\n \"chevrons-right\",\n \"circle\",\n \"circle-check\",\n \"circle-dot\",\n \"circle-number-1\",\n \"circle-plus\",\n \"click\",\n \"clipboard\",\n \"clipboard-image\",\n \"clipboard-text\",\n \"clock\",\n \"clock-check\",\n \"clock-hour-4\",\n \"close\",\n \"close-circle\",\n \"code\",\n \"code-block\",\n \"cog\",\n \"collapse\",\n \"color-wheel\",\n \"columns\",\n \"columns-2\",\n \"columns-3\",\n \"comment\",\n \"component\",\n \"compose\",\n \"compose-sparkles\",\n \"confetti\",\n \"controls\",\n \"cookie\",\n \"copy\",\n \"credit-card\",\n \"crop\",\n \"cube\",\n \"currency-dollar\",\n \"dashboard\",\n \"database\",\n \"database-search\",\n \"desktop\",\n \"device-desktop\",\n \"device-mobile\",\n \"device-tablet\",\n \"devices\",\n \"diamond\",\n \"discount\",\n \"document\",\n \"document-pdf\",\n \"document-remove\",\n \"document-sheet\",\n \"document-text\",\n \"document-video\",\n \"document-word\",\n \"document-zip\",\n \"documents\",\n \"door-exit\",\n \"dot\",\n \"double-chevron-down\",\n \"double-chevron-left\",\n \"double-chevron-right\",\n \"double-chevron-up\",\n \"double-quote\",\n \"download\",\n \"drag-handle\",\n \"drop\",\n \"droplet\",\n \"droplet-half\",\n \"earth-americas\",\n \"earth-globe\",\n \"edit\",\n \"egg\",\n \"ellipsis-horizontal\",\n \"ellipsis-vertical\",\n \"empty\",\n \"enter\",\n \"enter-right\",\n \"envelope\",\n \"equal\",\n \"error-filled\",\n \"error-outline\",\n \"error-screen\",\n \"expand\",\n \"eye-closed\",\n \"eye-off\",\n \"eye-open\",\n \"face-happy\",\n \"face-indifferent\",\n \"face-sad\",\n \"feather\",\n \"feedback\",\n \"file\",\n \"file-certificate\",\n \"file-code\",\n \"file-download\",\n \"file-text\",\n \"filter\",\n \"flag\",\n \"flame\",\n \"flask\",\n \"focus-2\",\n \"folder\",\n \"folders\",\n \"forms\",\n \"frame\",\n \"generate\",\n \"gift\",\n \"git-branch\",\n \"github\",\n \"grid-dots\",\n \"groq\",\n \"hammer\",\n \"hand-finger\",\n \"hanger\",\n \"hash\",\n \"headphones\",\n \"headset\",\n \"heart\",\n \"heart-filled\",\n \"heart-handshake\",\n \"help-circle\",\n \"highlight\",\n \"history\",\n \"home\",\n \"hourglass\",\n \"ice-cream\",\n \"id-badge\",\n \"id-badge-2\",\n \"image\",\n \"image-remove\",\n \"images\",\n \"inbox\",\n \"infinity\",\n \"info-circle\",\n \"info-filled\",\n \"info-outline\",\n \"info-square-rounded\",\n \"inline\",\n \"inline-element\",\n \"input-search\",\n \"insert-above\",\n \"insert-below\",\n \"italic\",\n \"joystick\",\n \"json\",\n \"language\",\n \"launch\",\n \"layout\",\n \"layout-align-center\",\n \"layout-board\",\n \"layout-board-split\",\n \"layout-bottombar\",\n \"layout-bottombar-expand\",\n \"layout-cards\",\n \"layout-columns\",\n \"layout-dashboard\",\n \"layout-grid\",\n \"layout-list\",\n \"layout-navbar\",\n \"layout-rows\",\n \"layout-sidebar\",\n \"layout-sidebar-right\",\n \"leaf\",\n \"leave\",\n \"lemon\",\n \"library-photo\",\n \"lifebuoy\",\n \"link\",\n \"link-removed\",\n \"linkedin\",\n \"list\",\n \"list-check\",\n \"list-details\",\n \"list-numbers\",\n \"list-tree\",\n \"lock\",\n \"logo-js\",\n \"logo-ts\",\n \"mail\",\n \"map-2\",\n \"map-pin\",\n \"map-pins\",\n \"marker\",\n \"marker-removed\",\n \"master-detail\",\n \"math-function\",\n \"meat\",\n \"menu\",\n \"message\",\n \"message-2\",\n \"message-check\",\n \"message-circle\",\n \"message-circle-2\",\n \"message-plus\",\n \"message-star\",\n \"microphone\",\n \"microphone-slash\",\n \"mobile-device\",\n \"mood-empty\",\n \"moon\",\n \"movie\",\n \"news\",\n \"notes\",\n \"number\",\n \"ok-hand\",\n \"olist\",\n \"overage\",\n \"package\",\n \"packages\",\n \"palette\",\n \"panel-left\",\n \"panel-right\",\n \"paperclip\",\n \"pause\",\n \"pencil\",\n \"phone\",\n \"photo\",\n \"photo-scan\",\n \"photo-search\",\n \"pig-money\",\n \"pin\",\n \"pin-filled\",\n \"pin-removed\",\n \"play\",\n \"player-play\",\n \"player-track-next\",\n \"playlist-add\",\n \"plug\",\n \"plug-connected\",\n \"plus-minus\",\n \"point\",\n \"presentation\",\n \"printer\",\n \"progress-50\",\n \"progress-75\",\n \"projects\",\n \"publish\",\n \"qrcode\",\n \"quote\",\n \"read-only\",\n \"receipt\",\n \"recycle\",\n \"redo\",\n \"refresh\",\n \"remove\",\n \"remove-circle\",\n \"repeat\",\n \"reset\",\n \"restore\",\n \"retrieve\",\n \"retry\",\n \"revert\",\n \"robot\",\n \"rocket\",\n \"rosette\",\n \"route\",\n \"ruler\",\n \"ruler-measure\",\n \"salad\",\n \"scale\",\n \"schema\",\n \"school\",\n \"search\",\n \"section\",\n \"select\",\n \"send\",\n \"server\",\n \"settings\",\n \"share\",\n \"shield-check\",\n \"shield-lock\",\n \"shopping-bag\",\n \"shopping-cart\",\n \"shopping-cart-plus\",\n \"signature\",\n \"sitemap\",\n \"slideshow\",\n \"sort\",\n \"sort-descending\",\n \"spacing-vertical\",\n \"sparkle\",\n \"sparkles\",\n \"speakerphone\",\n \"spinner\",\n \"split-horizontal\",\n \"split-vertical\",\n \"square\",\n \"stack\",\n \"stack-2\",\n \"stack-compact\",\n \"stairs\",\n \"stairs-up\",\n \"star\",\n \"star-filled\",\n \"stars\",\n \"stop\",\n \"strikethrough\",\n \"string\",\n \"subtask\",\n \"sun\",\n \"superscript\",\n \"sync\",\n \"table\",\n \"table-options\",\n \"tablet-device\",\n \"tag\",\n \"tags\",\n \"target\",\n \"task\",\n \"template\",\n \"tent\",\n \"terminal\",\n \"terminal-2\",\n \"text\",\n \"th-large\",\n \"th-list\",\n \"thumb-up\",\n \"thumbs-down\",\n \"thumbs-up\",\n \"ticket\",\n \"tiers\",\n \"timeline\",\n \"toggle-arrow-right\",\n \"toggle-right\",\n \"token\",\n \"tool\",\n \"tools-kitchen-2\",\n \"transfer\",\n \"translate\",\n \"trash\",\n \"trend-upward\",\n \"triangle-outline\",\n \"trolley\",\n \"truck\",\n \"truck-delivery\",\n \"truncate\",\n \"twitter\",\n \"typography\",\n \"ulist\",\n \"unarchive\",\n \"underline\",\n \"undo\",\n \"unknown\",\n \"unlink\",\n \"unlock\",\n \"unpublish\",\n \"upload\",\n \"user\",\n \"user-circle\",\n \"user-plus\",\n \"user-search\",\n \"user-star\",\n \"users\",\n \"users-group\",\n \"versions\",\n \"video\",\n \"vocabulary\",\n \"vs\",\n \"warning-filled\",\n \"warning-outline\",\n \"weight\",\n \"world\",\n \"wrench\",\n \"zoom-question\",\n] as const;\n\nexport type DockIconName = (typeof DOCK_ICON_NAMES)[number];\n\nexport const DOCK_ICON_NAME_SET: ReadonlySet<string> = new Set<string>(DOCK_ICON_NAMES);\n","/**\n * The dock's click budget, as ONE pure function both ends read (V9): the backend's next-steps\n * rules call it on live data, and the dashboard's reach test measures its RENDERED dock against the\n * golden this module emits (src/__tests__/fixtures/dock-budget.golden.json). No dependencies.\n *\n * A SCREEN is one navigation level of the dock, modelled on what the dock renders:\n * - `root` the lane's first screen: the page fields, a page section, or a component's props;\n * - `list` a repeatable's items, one branch hop below the row that opens it (a repeater, an\n * `array` with a repeatable zone, a `table` prop, `modular`);\n * - `item` one item of that list, a second hop. `modular` has no item screen: its items are\n * other models.\n * A non-repeatable zone (`group`, `array` + zones.nonRepeatable, a `group` prop) is NOT a screen.\n * It renders inline as a group, collapsed only when its own `ui.collapsed` is true. An array with\n * BOTH zones is that group with one more row, the branch that opens its list.\n *\n * On a screen:\n * - fieldsets with no `kind` are FLAT (V2): members render ungrouped, in document order;\n * - `kind:\"group\"` is a disclosure placed at its first member; `collapsed` costs 1 activation;\n * - `kind:\"row\"` is ONE leaf, however many members it holds;\n * - `kind:\"tab\"`, root screens only: a strip renders only with ≥2 non-empty tabs. Tab 1 is the\n * first panel, each later tab costs 1 activation, untabbed fields are PINNED above the strip,\n * and a group/row with `tab: <id>` sits in that tab. Below the root a tab reference is flat.\n * - component props join a group through `ui.group`; the first prop naming an id defines it.\n *\n * Budget, per screen (DOCK_BUDGET holds the limits):\n * - ungroupedLeaves: rows outside any group (a leaf, a row fieldset, a branch), as the max over\n * panels of pinned + panel. No picker term: tabs are capped at 3, so the strip never overflows.\n * - maxGroupLeaves: the largest group's own rows (a nested group counts in its own entry).\n * - depth: branch hops from the lane's root screen.\n * - maxActivations: the dearest value on the screen counted from the lane's root: +1 per branch\n * hop, +1 per collapsed group, +1 for a non-first tab. A screen with no values costs its entry.\n */\n\nexport const DOCK_BUDGET = { ungrouped: 8, group: 12, depth: 3, activations: 2 } as const;\n\nexport type DockLane = \"page-fields\" | \"page-section\" | \"component\";\n\nexport interface DockBudget {\n ungroupedLeaves: number;\n maxGroupLeaves: number;\n depth: number;\n maxActivations: number;\n}\n\n/** One row on a screen. Keys are paths from the screen's own fields (`hero.title`). */\nexport type DockNode =\n | { kind: \"leaf\"; key: string }\n | { kind: \"row\"; id: string; keys: string[] }\n | { kind: \"branch\"; key: string }\n | { kind: \"group\"; id: string; collapsed: boolean; nodes: DockNode[] };\n\nexport interface DockScreen {\n /** `<lane>`, then `/<branch key>` per list and `/item` per item: `page-fields/quotes/item`. */\n id: string;\n lane: DockLane;\n kind: \"root\" | \"list\" | \"item\";\n title: string;\n depth: number;\n /** Activations spent reaching this screen from the lane's root. */\n entry: number;\n pinned: DockNode[];\n /** One panel per tab, in fieldset order. Empty when no strip renders. */\n tabs: DockNode[][];\n}\n\n/** The structural subset of a model field or component prop that this module reads. */\nexport interface DockFieldLike {\n key: string;\n label?: string;\n type: string;\n fieldsetId?: string;\n ui?: { collapsed?: boolean; group?: DockPropGroupLike } | null;\n config?: unknown;\n /** Legacy `group`/`repeater` children, and a component sub-field's own children. */\n fields?: DockFieldLike[];\n}\n\nexport interface DockFieldsetLike {\n id: string;\n name?: string;\n kind?: \"group\" | \"row\" | \"tab\";\n collapsed?: boolean;\n tab?: string;\n}\n\nexport interface DockPropGroupLike {\n id: string;\n label?: string;\n kind?: \"group\" | \"row\";\n collapsed?: boolean;\n}\n\ntype Config = {\n fields?: DockFieldLike[];\n zones?: { nonRepeatable?: DockFieldLike[]; repeatable?: { fields?: DockFieldLike[] } };\n};\n\n/** A repeatable's item fields (null: no item screen), or undefined when the field is no list. */\nfunction listItems(f: DockFieldLike): DockFieldLike[] | null | undefined {\n const c = (f.config ?? {}) as Config;\n if (f.type === \"repeater\") return f.fields ?? [];\n if (f.type === \"table\") return c.fields ?? f.fields ?? [];\n if (f.type === \"array\" && c.zones?.repeatable) return c.zones.repeatable.fields ?? [];\n if (f.type === \"modular\" || f.type === \"slot\") return null;\n return undefined;\n}\n\n/** An inline zone's fields, or undefined when the field is not one. */\nfunction zoneFields(f: DockFieldLike): DockFieldLike[] | undefined {\n const c = (f.config ?? {}) as Config;\n // A V2 `object` (a prop or a model field) is one nested object, laid out inline as a group is.\n if (f.type === \"group\" || f.type === \"object\") return c.fields ?? f.fields ?? [];\n if (f.type === \"array\" && c.zones?.nonRepeatable) return c.zones.nonRepeatable;\n return undefined;\n}\n\ninterface Branch {\n key: string;\n field: DockFieldLike;\n items: DockFieldLike[] | null;\n}\n\n/**\n * Lay one sibling level out into pinned rows and tab panels. `branches` collects every branch row\n * with the in-screen cost of reaching it, so the caller can open its screens.\n */\nfunction layout(\n fields: DockFieldLike[],\n fieldsets: DockFieldsetLike[],\n root: boolean,\n): { pinned: DockNode[]; tabs: DockNode[][]; branches: Map<string, Branch> } {\n const byId = new Map(fieldsets.map((s) => [s.id, s]));\n const tabIds = root ? fieldsets.filter((s) => s.kind === \"tab\").map((s) => s.id) : [];\n const tabOf = (s: DockFieldsetLike | undefined): string | undefined =>\n s?.kind === \"tab\" ? s.id : s?.tab !== undefined && byId.get(s.tab)?.kind === \"tab\" ? s.tab : undefined;\n const nonEmpty = new Set(\n fields.map((f) => tabOf(byId.get(f.fieldsetId ?? \"\"))).filter((t) => t && tabIds.includes(t)),\n );\n const strip = nonEmpty.size >= 2;\n\n const branches = new Map<string, Branch>();\n const nodeFor = (f: DockFieldLike, path: string): DockNode => {\n const key = `${path}${f.key}`;\n const zone = zoneFields(f);\n const items = listItems(f);\n if (zone) {\n const nodes = zone.map((z) => nodeFor(z, `${key}.`));\n // An array with BOTH zones: its list opens from a row inside its group, so it is measured too.\n if (zone.length > 0 && items?.length) {\n branches.set(key, { key, field: f, items });\n nodes.push({ kind: \"branch\", key });\n }\n return { kind: \"group\", id: key, collapsed: f.ui?.collapsed === true, nodes };\n }\n if (items !== undefined) {\n branches.set(key, { key, field: f, items });\n return { kind: \"branch\", key };\n }\n return { kind: \"leaf\", key };\n };\n\n const pinned: DockNode[] = [];\n const panels = new Map<string, DockNode[]>(strip ? tabIds.filter((t) => nonEmpty.has(t)).map((t) => [t, []]) : []);\n const containers = new Map<string, DockNode>();\n for (const f of fields) {\n const node = nodeFor(f, \"\");\n const set = byId.get(f.fieldsetId ?? \"\");\n const target = (strip && panels.get(tabOf(set) ?? \"\")) || pinned;\n if (set?.kind !== \"group\" && set?.kind !== \"row\") {\n target.push(node);\n continue;\n }\n let box = containers.get(set.id);\n if (!box) {\n box =\n set.kind === \"row\"\n ? { kind: \"row\", id: set.id, keys: [] }\n : { kind: \"group\", id: set.id, collapsed: set.collapsed === true, nodes: [] };\n containers.set(set.id, box);\n target.push(box);\n }\n if (box.kind === \"row\") box.keys.push(f.key);\n else if (box.kind === \"group\") box.nodes.push(node);\n }\n return { pinned, tabs: [...panels.values()], branches };\n}\n\n/** Cheapest in-screen cost of each value and branch row, keyed by node key. */\nfunction walkCosts(screen: DockScreen): { values: number[]; branchCost: Map<string, number> } {\n const values: number[] = [];\n const branchCost = new Map<string, number>();\n const walk = (nodes: DockNode[], cost: number): void => {\n for (const n of nodes) {\n if (n.kind === \"group\") walk(n.nodes, cost + (n.collapsed ? 1 : 0));\n else if (n.kind === \"branch\") branchCost.set(n.key, cost);\n else values.push(cost);\n }\n };\n walk(screen.pinned, 0);\n screen.tabs.forEach((panel, i) => walk(panel, i === 0 ? 0 : 1));\n return { values, branchCost };\n}\n\n/**\n * Every screen of one lane, root first. Pass `props` for a component lane (its `fields` and\n * `fieldsets` are then ignored): a prop's `ui.group` becomes the fieldset it joins.\n */\nexport function dockScreens(\n source: { fields?: DockFieldLike[] | null; fieldsets?: DockFieldsetLike[] | null },\n lane: DockLane,\n props?: DockFieldLike[] | null,\n): DockScreen[] {\n let fields = source.fields ?? [];\n let fieldsets = source.fieldsets ?? [];\n if (props) {\n fieldsets = [];\n fields = props.map((p) => {\n const g = p.ui?.group;\n if (!g) return p;\n if (!fieldsets.some((s) => s.id === g.id)) {\n fieldsets.push({ id: g.id, name: g.label, kind: g.kind ?? \"group\", collapsed: g.collapsed });\n }\n return { ...p, fieldsetId: g.id };\n });\n }\n\n const screens: DockScreen[] = [];\n const open = (\n id: string,\n kind: DockScreen[\"kind\"],\n title: string,\n depth: number,\n entry: number,\n level: DockFieldLike[] | null,\n ): void => {\n const laid = level ? layout(level, fieldsets, kind === \"root\") : null;\n const screen: DockScreen = {\n id,\n lane,\n kind,\n title,\n depth,\n entry,\n pinned: laid?.pinned ?? [],\n tabs: laid?.tabs ?? [],\n };\n screens.push(screen);\n if (!laid) return;\n const { branchCost } = walkCosts(screen);\n for (const b of laid.branches.values()) {\n const listId = `${id}/${b.key}`;\n const listEntry = entry + (branchCost.get(b.key) ?? 0) + 1;\n const label = b.field.label ?? b.field.key;\n open(listId, \"list\", label, depth + 1, listEntry, null);\n if (b.items) open(`${listId}/item`, \"item\", `${label} item`, depth + 2, listEntry + 1, b.items);\n }\n };\n open(lane, \"root\", lane === \"component\" ? \"Component\" : lane === \"page-fields\" ? \"Page fields\" : \"Section\", 0, 0, fields);\n return screens;\n}\n\nexport function dockBudget(screen: DockScreen): DockBudget {\n const rows = (nodes: DockNode[]): number => nodes.filter((n) => n.kind !== \"group\").length;\n let maxGroupLeaves = 0;\n const groups = (nodes: DockNode[]): void => {\n for (const n of nodes) {\n if (n.kind !== \"group\") continue;\n maxGroupLeaves = Math.max(maxGroupLeaves, rows(n.nodes));\n groups(n.nodes);\n }\n };\n groups(screen.pinned);\n screen.tabs.forEach(groups);\n const pinned = rows(screen.pinned);\n const { values } = walkCosts(screen);\n return {\n ungroupedLeaves: screen.tabs.length ? Math.max(...screen.tabs.map((p) => pinned + rows(p))) : pinned,\n maxGroupLeaves,\n depth: screen.depth,\n maxActivations: screen.entry + (values.length ? Math.max(...values) : 0),\n };\n}\n","/**\n * THE button-link pairing rule, pure: which two sibling fields render as ONE button unit (the words\n * on the button + where it goes). The dashboard folds them together; the backend refuses a write\n * that splits such a pair across fieldsets (`pair_split`). One copy, so both ends agree.\n *\n * Presentation only: a pair keeps its own keys, values and writers.\n *\n * 1. A key is split into words whatever its spelling (`hero_cta_label`, `ctaText`, `button-link`);\n * a dotted path counts only its last segment.\n * 2. The LAST word is the role: `label text title cta button btn name` are TEXT roles, `href link\n * url to` LINK roles. Everything before it is the STEM.\n * 3. A text candidate is a text-typed field (`text`, `string`) with a text role. A key that is a\n * button noun (`cta`, `primaryButton`) also offers its full key as a stem.\n * 4. A link candidate is a link-typed field (`link`, `url`), or a text-typed field with a link role\n * that is not a media address (`image_url`). A link-typed field whose last word is not a link\n * role offers both its stem and its full key.\n * 5. Two fields pair when their stem holds EXACTLY one text and one link candidate. Three or more\n * candidates on a stem: none pair. A field that would pair two ways pairs neither way.\n *\n * 0. Before all of that, an importer's spelling pairs outright (@see derivedPairs):\n * `<stem>-href` (link-typed) with the one text keyed `<stem>`, or `<stem>` with its tag swapped.\n *\n * When the key's words say nothing, the visible LABEL is read the same way, its stems namespaced\n * (`label:`) so a label reading only ever meets another label reading.\n */\n\nconst TEXT_ROLES: ReadonlySet<string> = new Set([\"label\", \"text\", \"title\", \"cta\", \"button\", \"btn\", \"name\"]);\nconst LINK_ROLES: ReadonlySet<string> = new Set([\"href\", \"link\", \"url\", \"to\"]);\nconst BUTTON_NOUNS: ReadonlySet<string> = new Set([\"cta\", \"button\", \"btn\"]);\nconst TEXT_TYPES: ReadonlySet<string> = new Set([\"text\", \"string\"]);\nconst LINK_TYPES: ReadonlySet<string> = new Set([\"link\", \"url\"]);\nconst MEDIA = /image|img|photo|video|avatar|logo|icon|thumb|poster|embed|src|og|favicon/i;\n\n/** What the rule needs to know about one field. */\nexport interface ButtonLinkCandidate {\n key: string;\n type?: string;\n label?: string;\n /** The current value, when known: a structured value never pairs as text. */\n value?: unknown;\n}\n\n/** `hero_cta_primary_label` / `ctaText` / `primaryButton-link` → lowercase words. */\nexport function keyWords(key: string): string[] {\n const leaf = key.split(\".\").pop() ?? \"\";\n return leaf\n .replace(/([a-z\\d])([A-Z])/g, \"$1 $2\")\n .replace(/([A-Z]+)([A-Z][a-z])/g, \"$1 $2\")\n .split(/[\\s_-]+/)\n .filter(Boolean)\n .map((word) => word.toLowerCase());\n}\n\ntype Role = { role: \"text\" | \"link\"; stems: string[] };\n\nfunction roleFromWords(candidate: ButtonLinkCandidate, words: string[]): Role | null {\n const type = (candidate.type ?? \"\").toLowerCase();\n const value = candidate.value;\n if (!(value === undefined || value === null || typeof value === \"string\")) return null;\n if (!words.length) return null;\n const last = words[words.length - 1]!;\n const stem = words.slice(0, -1).join(\"_\");\n const full = words.join(\"_\");\n if (LINK_TYPES.has(type)) return { role: \"link\", stems: LINK_ROLES.has(last) ? [stem] : [stem, full] };\n if (!TEXT_TYPES.has(type)) return null;\n if (LINK_ROLES.has(last)) {\n if (MEDIA.test(candidate.key) || MEDIA.test(candidate.label ?? \"\")) return null;\n return { role: \"link\", stems: [stem] };\n }\n if (TEXT_ROLES.has(last)) return { role: \"text\", stems: BUTTON_NOUNS.has(last) ? [stem, full] : [stem] };\n return null;\n}\n\n/** The role one field plays, with every stem it offers, or null. */\nexport function candidateRole(candidate: ButtonLinkCandidate): Role | null {\n const fromKey = roleFromWords(candidate, keyWords(candidate.key));\n if (fromKey) return fromKey;\n const label = candidate.label?.trim();\n if (!label) return null;\n const fromLabel = roleFromWords(candidate, keyWords(label.replace(/\\s+/g, \"_\")));\n return fromLabel ? { role: fromLabel.role, stems: fromLabel.stems.map((stem) => `label:${stem}`) } : null;\n}\n\n/** Element words an importer writes into a key: the tag the copy sat in, never part of its name. */\nconst TAG_SEGMENTS: ReadonlySet<string> = new Set([\"a\", \"span\", \"button\", \"div\", \"strong\"]);\n\nconst isScalarText = (value: unknown): boolean => value === undefined || value === null || typeof value === \"string\";\n\n/**\n * The pairs an IMPORTER's spelling names outright, before any role is read.\n *\n * Derive keys a call to action by the element it found it in: `equip-a-start-exploring-href` (link)\n * beside `equip-span-start-exploring` (text). Neither key ends in a role word, so the role pass\n * cannot pair them. Here a link-typed `<stem>-href` / `<stem>_href` pairs with the ONE text field\n * keyed `<stem>`, or `<stem>` with exactly one tag segment (a/span/button/div/strong) swapped for\n * another. Two candidate texts: none pairs.\n */\nexport function derivedPairs(candidates: readonly ButtonLinkCandidate[]): Map<number, { pair: string; role: \"text\" | \"link\" }> {\n const out = new Map<number, { pair: string; role: \"text\" | \"link\" }>();\n const leaf = (key: string) => key.split(\".\").pop() ?? \"\";\n const isText = (c: ButtonLinkCandidate) =>\n TEXT_TYPES.has((c.type ?? \"\").toLowerCase()) && isScalarText(c.value) && !/[-_]href$/i.test(leaf(c.key));\n const sameButTag = (a: string, b: string) => {\n if (a === b) return true;\n const x = a.split(/[-_]/);\n const y = b.split(/[-_]/);\n if (x.length !== y.length) return false;\n let swapped = 0;\n for (let i = 0; i < x.length; i++) {\n if (x[i] === y[i]) continue;\n if (!TAG_SEGMENTS.has(x[i]!) || !TAG_SEGMENTS.has(y[i]!)) return false;\n swapped++;\n }\n return swapped === 1;\n };\n candidates.forEach((link, linkIndex) => {\n if (out.has(linkIndex) || !LINK_TYPES.has((link.type ?? \"\").toLowerCase()) || !isScalarText(link.value)) return;\n const key = leaf(link.key);\n const suffix = /[-_]href$/i.exec(key);\n if (!suffix) return;\n const stem = key.slice(0, suffix.index);\n const parent = link.key.slice(0, link.key.length - key.length);\n const texts = candidates\n .map((text, textIndex) => ({ text, textIndex }))\n .filter(\n ({ text, textIndex }) =>\n textIndex !== linkIndex &&\n !out.has(textIndex) &&\n isText(text) &&\n text.key.startsWith(parent) &&\n sameButTag(leaf(text.key), stem),\n );\n if (texts.length !== 1) return;\n const pair = `${texts[0]!.textIndex}:${linkIndex}`;\n out.set(texts[0]!.textIndex, { pair, role: \"text\" });\n out.set(linkIndex, { pair, role: \"link\" });\n });\n return out;\n}\n\n/** Every unambiguous pair in one sibling list, as `[textIndex, linkIndex]`, in list order. */\nexport function buttonLinkPairs(candidates: readonly ButtonLinkCandidate[]): Array<[number, number]> {\n const derived = derivedPairs(candidates);\n const roles = candidates.map((candidate, index) => {\n const half = derived.get(index);\n return half ? { role: half.role, stems: [`derived:${half.pair}`] } : candidateRole(candidate);\n });\n const byStem = new Map<string, { text: Set<number>; link: Set<number> }>();\n roles.forEach((role, index) => {\n if (!role) return;\n for (const stem of new Set(role.stems)) {\n const bucket = byStem.get(stem) ?? { text: new Set<number>(), link: new Set<number>() };\n bucket[role.role].add(index);\n byStem.set(stem, bucket);\n }\n });\n\n const ambiguous = new Set<number>();\n const proposals = new Map<string, [number, number]>();\n for (const bucket of byStem.values()) {\n if (bucket.text.size + bucket.link.size >= 3) {\n for (const index of [...bucket.text, ...bucket.link]) ambiguous.add(index);\n continue;\n }\n if (bucket.text.size === 1 && bucket.link.size === 1) {\n const pair: [number, number] = [[...bucket.text][0]!, [...bucket.link][0]!];\n proposals.set(pair.join(\":\"), pair);\n }\n }\n\n const uses = new Map<number, number>();\n for (const [text, link] of proposals.values()) {\n uses.set(text, (uses.get(text) ?? 0) + 1);\n uses.set(link, (uses.get(link) ?? 0) + 1);\n }\n return [...proposals.values()]\n .filter(([t, l]) => !ambiguous.has(t) && !ambiguous.has(l) && uses.get(t) === 1 && uses.get(l) === 1)\n .sort((a, b) => Math.min(...a) - Math.min(...b));\n}\n","/**\n * A button block's LOOK beyond size: its variant, an optional leading icon and an optional\n * trailing arrow. The ONE source of the names: the renderer draws from it, the validation schema\n * allow-lists from it, and the dashboard's copy is pinned to it by a parity test.\n *\n * <a class=\"bcms-btn bcms-btn-{variant}\">[<svg class=\"bcms-btn-icon\">]Text[<svg class=\"bcms-btn-arrow\">]</a>\n *\n * Icons are the BetterCMS icon set (`@bettercms-ai/icons`, 472 icons): the same names a field's\n * `ui.icon` takes (`DOCK_ICON_NAMES`), drawn from its plain-SVG `markup` export, so the hosted\n * renderer, the SDKs and the dashboard's picker all draw the same artwork.\n */\nimport { ICON_MARKUP, iconSvg } from \"@bettercms-ai/icons/markup\";\nimport { DOCK_ICON_NAMES, DOCK_ICON_NAME_SET, type DockIconName } from \"./dock-icon-names.js\";\nimport { LINK_RELS, isLinkObject, isScriptHref, linkAnchorOf, linkHref, linkValueProblem, type LinkRel, type LinkValue } from \"./link-value.js\";\n\nexport { LINK_RELS, type LinkRel };\n\nexport const BUTTON_VARIANTS = [\"primary\", \"secondary\", \"tertiary\", \"brand\", \"dark\", \"light\", \"outline\", \"link\"] as const;\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number];\n\n/** Each icon's inner SVG markup (viewBox `0 0 25 25`), by name. */\nexport const BUTTON_ICONS: Readonly<Record<DockIconName, string>> = ICON_MARKUP;\nexport type ButtonIcon = DockIconName;\nexport const BUTTON_ICON_NAMES = DOCK_ICON_NAMES;\n\n/** A stored variant as it renders: anything off the list is Primary. */\nexport function buttonVariantOf(value: unknown): ButtonVariant {\n return BUTTON_VARIANTS.includes(value as ButtonVariant) ? (value as ButtonVariant) : \"primary\";\n}\n\n/**\n * How an IMPORTED site draws one look of its Button family: the classes its own stylesheet PAINTS\n * the look by, the `data-variant` it keys the look on when it uses one, and the paint classes of\n * every other spelling of the same look (`also`), which a publish takes off the anchor with the rest.\n * A look comes in sizes: `size` are the classes that size its most-used spelling and `sizeAlso`\n * those of the others. A publish leaves a button's size classes on it and adds `size` only to a\n * button that has none. Measured from the built site and stored on the look's button block as\n * `props.siteLook`.\n */\nexport interface ButtonSiteLook {\n classes: string[];\n attrs?: { \"data-variant\"?: string };\n also?: string[];\n size?: string[];\n sizeAlso?: string[];\n}\n\n/** A class token as a publish may write it onto an anchor. */\nconst SITE_CLASS = /^[^\\s\"'<>`=]{1,64}$/;\nconst LOOK_VALUE = /^[a-z0-9][a-z0-9-]{0,63}$/;\n\n/** A button block's `props.siteLook`, read defensively: null when it names nothing to paint with. */\nexport function buttonSiteLookOf(value: unknown): ButtonSiteLook | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const v = value as { classes?: unknown; attrs?: Record<string, unknown>; also?: unknown; size?: unknown; sizeAlso?: unknown };\n const tokens = (list: unknown): string[] => (Array.isArray(list) ? list.filter((c): c is string => typeof c === \"string\" && SITE_CLASS.test(c)) : []);\n const variant = v.attrs?.[\"data-variant\"];\n const classes = tokens(v.classes);\n const also = tokens(v.also);\n const size = tokens(v.size);\n const sizeAlso = tokens(v.sizeAlso);\n const attrs = typeof variant === \"string\" && LOOK_VALUE.test(variant) ? { \"data-variant\": variant } : undefined;\n if (classes.length === 0 && !attrs) return null;\n return {\n classes,\n ...(attrs ? { attrs } : {}),\n ...(also.length ? { also } : {}),\n ...(size.length ? { size } : {}),\n ...(sizeAlso.length ? { sizeAlso } : {}),\n };\n}\n\n/**\n * The value a `button` stores to pick one look of the project's Button family: what the site's own\n * `data-variant` calls the look when it keys on one, the look's component slug otherwise. A\n * publish writes it back as the anchor's `data-variant`.\n */\nexport function buttonLookValue(slug: string, siteLook: ButtonSiteLook | null): string {\n return siteLook?.attrs?.[\"data-variant\"] ?? slug;\n}\n\n/** Is this a value that could name a family look (or one of the fixed names)? */\nexport function isButtonLookValue(value: unknown): value is string {\n return typeof value === \"string\" && LOOK_VALUE.test(value);\n}\n\n/** A stored icon as it renders: anything off the list is no icon. */\nexport function buttonIconOf(value: unknown): ButtonIcon | null {\n return typeof value === \"string\" && DOCK_ICON_NAME_SET.has(value) ? (value as ButtonIcon) : null;\n}\n\n/** One icon as inline SVG sized to the button's text, hidden from assistive tech (the label names the button). */\nexport function buttonIconSvg(name: ButtonIcon, cls: \"bcms-btn-icon\" | \"bcms-btn-arrow\"): string {\n return iconSvg(name, cls);\n}\n\n// ── The `button` field type: one button as one value ─────────────────────────────────────────\n\nexport const BUTTON_SIZES = [\"sm\", \"md\", \"lg\"] as const;\nexport type ButtonSizeName = (typeof BUTTON_SIZES)[number];\n\n/**\n * The value a `button` field stores: the words, the link and the look, as Sanity stores a button\n * object. Only `label` and `href` are required; every look key is optional and absent reads as\n * today's default (Primary, medium, no arrow, no icon, same tab).\n */\n/**\n * The target and rel attributes of an anchor, as one string. A new tab keeps the `noopener\n * noreferrer` pair; a link relation joins it in the SAME rel attribute, so an anchor never\n * carries two.\n */\nexport function anchorTargetRel(newTab: boolean, rel?: unknown): string {\n const tokens = [...(newTab ? [\"noopener\", \"noreferrer\"] : []), ...(LINK_RELS.includes(rel as LinkRel) ? [rel as string] : [])];\n return `${newTab ? ' target=\"_blank\"' : \"\"}${tokens.length ? ` rel=\"${tokens.join(\" \")}\"` : \"\"}`;\n}\n\n/**\n * What a button does when the site's own code decides it: `<button type=\"button\">` opening a\n * dialog, accepting cookies, starting a tour. Such a button has no destination to store, so the\n * value says so outright instead of carrying an empty href nobody can tell from a forgotten one.\n */\nexport const BUTTON_ACTIONS = [\"code\"] as const;\nexport type ButtonAction = (typeof BUTTON_ACTIONS)[number];\n\n/** Is this stored value a button whose action is the site's code (no href, never an anchor)? */\nexport function isCodeButton(value: unknown): boolean {\n return !!value && typeof value === \"object\" && (value as { action?: unknown }).action === \"code\";\n}\n\nexport interface ButtonValue {\n label: string;\n /**\n * A plain href, or a link object (@see LinkValue) whose newTab / rel apply when the button sets\n * none. Absent (or empty) only beside `action: \"code\"`.\n */\n href?: string | LinkValue;\n /** `\"code\"`: the click is the site's own script. The label and the look are edited; no href, no new tab, no rel. */\n action?: ButtonAction;\n variant?: ButtonVariant;\n size?: ButtonSizeName;\n arrow?: boolean;\n icon?: ButtonIcon | null;\n newTab?: boolean;\n /** Sponsored, untrusted or user-generated destination. Absent ⇒ no rel beyond a new tab's own. */\n rel?: LinkRel;\n /** Stretch across its column, label centred. Absent ⇒ the button's own width. */\n fullWidth?: boolean;\n}\n\n/**\n * A stored button value as it renders: `rel`, `action` and `fullWidth` stay optional (present only\n * when set, so a value that never named them reads byte-for-byte as before), every other key is filled.\n */\nexport type ReadButtonValue = Required<Omit<ButtonValue, \"rel\" | \"href\" | \"action\" | \"fullWidth\">> & Pick<ButtonValue, \"rel\" | \"action\"> & { href: string; fullWidth?: true };\n\n/**\n * A button's destination as a string. `href` is a string, or — on a value written by an editor\n * that stores links as objects — a link object `{ type, href, ref?, … }`, whose `href` is read.\n */\nconst hrefOf = linkHref;\n\n/** A stored button value as it renders: every key read through the same allow-lists as a block. */\nexport function readButtonValue(value: unknown): ReadButtonValue {\n const v = (value && typeof value === \"object\" ? value : {}) as Record<string, unknown>;\n // A link object's own newTab / rel count when the button sets none of its own.\n const link = isLinkObject(v.href) ? linkAnchorOf(v.href) : null;\n const rel = v.rel ?? link?.rel;\n // A code-action button goes nowhere: whatever href, new tab or rel rode along is not read.\n const code = v.action === \"code\";\n return {\n label: typeof v.label === \"string\" ? v.label : \"\",\n href: code ? \"\" : (hrefOf(v.href) ?? \"\"),\n variant: buttonVariantOf(v.variant),\n size: BUTTON_SIZES.includes(v.size as ButtonSizeName) ? (v.size as ButtonSizeName) : \"md\",\n arrow: v.arrow === true,\n icon: buttonIconOf(v.icon),\n newTab: code ? false : v.newTab === undefined ? link?.newTab === true : v.newTab === true,\n ...(!code && LINK_RELS.includes(rel as LinkRel) ? { rel: rel as LinkRel } : {}),\n ...(code ? { action: \"code\" as const } : {}),\n ...(v.fullWidth === true ? { fullWidth: true as const } : {}),\n };\n}\n\n/** The named refusal of a `button` value whose `fullWidth` is not true or false. */\nexport const BUTTON_FULL_WIDTH_INVALID = \"button_full_width_invalid\";\n\n/**\n * Why a button value's `fullWidth` is refused, or null. Introduced-only: a value whose `fullWidth`\n * is the one `previous` already stored saves (values written before the key was checked keep\n * saving), so only a write that BRINGS a non-boolean is refused. Kept out of `buttonValueProblem`,\n * which also runs baseline-free at readiness and publish.\n */\nexport function buttonFullWidthProblem(value: unknown, previous?: unknown): string | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const fullWidth = (value as Record<string, unknown>).fullWidth;\n if (fullWidth === undefined || typeof fullWidth === \"boolean\") return null;\n const before = previous && typeof previous === \"object\" ? (previous as Record<string, unknown>).fullWidth : undefined;\n if (before !== undefined && JSON.stringify(before) === JSON.stringify(fullWidth)) return null;\n return `${BUTTON_FULL_WIDTH_INVALID}: fullWidth must be true or false`;\n}\n\n/**\n * Why a value is not a button, or null when it is. Look keys are checked only when present.\n * `looks` are the values that pick a look of the project's own Button family (@see\n * buttonLookValue): a variant is one of those or one of the fixed names.\n */\nexport function buttonValueProblem(value: unknown, looks?: ReadonlySet<string>): string | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return \"must be a { label, href } button\";\n const v = value as Record<string, unknown>;\n if (typeof v.label !== \"string\") return \"needs a label\";\n if (v.action !== undefined && !BUTTON_ACTIONS.includes(v.action as ButtonAction)) return `has an unknown action \"${String(v.action)}\" (code, or none for a link)`;\n if (v.action === \"code\") {\n // The site's script owns the click: a destination here would be a second, silent answer.\n if (v.href !== undefined && v.href !== null && v.href !== \"\") return 'takes no href with action \"code\"';\n if (v.newTab === true || v.rel !== undefined) return 'takes no newTab or rel with action \"code\"';\n } else if (hrefOf(v.href) === null) return 'needs an href (or action \"code\" for a button the site\\'s script handles)';\n if (isLinkObject(v.href)) {\n const problem = linkValueProblem(v.href);\n if (problem) return `href ${problem}`;\n }\n if (v.variant !== undefined && !BUTTON_VARIANTS.includes(v.variant as ButtonVariant) && !(typeof v.variant === \"string\" && looks?.has(v.variant))) {\n return `has an unknown variant \"${String(v.variant)}\"${looks?.size ? ` (this project's looks: ${[...looks].join(\", \")})` : \"\"}`;\n }\n if (v.size !== undefined && !BUTTON_SIZES.includes(v.size as ButtonSizeName)) return `has an unknown size \"${String(v.size)}\"`;\n if (v.arrow !== undefined && typeof v.arrow !== \"boolean\") return \"arrow must be true or false\";\n if (v.newTab !== undefined && typeof v.newTab !== \"boolean\") return \"newTab must be true or false\";\n if (v.rel !== undefined && !LINK_RELS.includes(v.rel as LinkRel)) return `has an unknown rel \"${String(v.rel)}\" (nofollow, sponsored or ugc)`;\n if (v.icon !== undefined && v.icon !== null && buttonIconOf(v.icon) === null) return `has an unknown icon \"${String(v.icon)}\"`;\n return null;\n}\n\n// ── A Button component instance's look ───────────────────────────────────────────────────────\n\n/** The look keys an instance of a Button component may override, beside its label and link. */\nexport const BUTTON_LOOK_KEYS = [\"variant\", \"size\", \"arrow\", \"icon\", \"newTab\", \"fullWidth\"] as const;\nexport type ButtonLookKey = (typeof BUTTON_LOOK_KEYS)[number];\n\n/**\n * A `button` PROP's value as the `button` BLOCK props it writes, for every lane that applies an\n * instance's overrides. `label` lands on `text`, and only the keys the value names come back, so\n * an override carrying a label alone keeps the definition's href and look.\n */\nexport function buttonBlockProps(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return {};\n const v = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n if (typeof v.label === \"string\") out.text = v.label;\n if (v.action === \"code\") {\n // Drawn as `<button type=\"button\">`: no destination, and none of a link's new tab or rel.\n out.action = \"code\";\n out.href = \"\";\n for (const key of BUTTON_LOOK_KEYS) if (key in v && key !== \"newTab\") out[key] = v[key];\n return out;\n }\n const href = hrefOf(v.href);\n // An instance's overrides are an open record nobody validated: a script href renders as \"#\",\n // with none of the link's new tab or rel.\n const script = href !== null && isScriptHref(href);\n if (href !== null) out.href = script ? \"#\" : href;\n // A block's href is a string: a link object's newTab / rel move onto the block beside it. The\n // object describes the WHOLE anchor (linkAnchorOf), so its same tab or \"follow\" (no rel) clears\n // the block's own, unless the button value sets its own newTab or rel.\n if (isLinkObject(v.href) && !script) {\n const link = linkAnchorOf(v.href)!;\n out.newTab = link.newTab;\n out.rel = link.rel;\n }\n if (v.rel !== undefined) out.rel = v.rel;\n for (const key of BUTTON_LOOK_KEYS) if (key in v) out[key] = v[key];\n return out;\n}\n\ninterface PropDefLike {\n key: string;\n label?: string;\n type?: string;\n target: { blockId: string; path: string };\n}\ninterface ComponentLike<P extends PropDefLike> {\n category?: string | null;\n blockJson?: unknown;\n props?: readonly P[] | null;\n}\n\n/** The id of a tree's ONLY `button` block, at any depth; null for none or several. */\nfunction soleButtonId(blockJson: unknown): string | null {\n const ids: string[] = [];\n const walk = (list: unknown): void => {\n if (!Array.isArray(list)) return;\n for (const b of list as Array<{ id?: unknown; type?: unknown; props?: { children?: unknown; columns?: unknown } }>) {\n if (b?.type === \"button\" && typeof b.id === \"string\") ids.push(b.id);\n walk(b?.props?.children);\n if (Array.isArray(b?.props?.columns)) for (const column of b.props.columns) walk(column);\n }\n };\n walk(blockJson);\n return ids.length === 1 ? ids[0]! : null;\n}\n\nconst LOOK_PROP_TYPE: Record<ButtonLookKey, string> = { variant: \"text\", size: \"text\", arrow: \"boolean\", icon: \"text\", newTab: \"boolean\", fullWidth: \"boolean\" };\nconst LOOK_PROP_LABEL: Record<ButtonLookKey, string> = { variant: \"Style\", size: \"Size\", arrow: \"Show arrow\", icon: \"Leading icon\", newTab: \"Open in new tab\", fullWidth: \"Full width\" };\n\n/**\n * A component's prop declarations, plus — on a Button component (category `button`, one button\n * block) — a look prop for every `BUTTON_LOOK_KEYS` key it does not declare itself, each driving\n * that block's `props.<key>`. So an INSTANCE of any Button carries its own look in its overrides\n * (`{ text, href, variant, arrow, … }`) with nothing to backfill: every renderer that applies\n * overrides passes this instead of `props`. Any other component is returned as declared, so a\n * section with one CTA never has a stray `variant` override land on its button.\n */\nexport function withButtonLookProps<P extends PropDefLike>(def: ComponentLike<P>): P[] {\n const props = [...(def.props ?? [])];\n if (def.category !== \"button\") return props;\n const blockId = soleButtonId(def.blockJson);\n if (!blockId) return props;\n for (const key of BUTTON_LOOK_KEYS) {\n if (props.some((p) => p.key === key)) continue;\n props.push({ key, label: LOOK_PROP_LABEL[key], type: LOOK_PROP_TYPE[key], target: { blockId, path: `props.${key}` } } as P);\n }\n return props;\n}\n\n/**\n * One instance of a Button component as a `ButtonValue` — the definition's button with the\n * instance's overrides written onto it — for a site rendering the instance with `BcmsButton`.\n * Null when the component is not a Button (not category `button`, or not exactly one button).\n */\nexport function buttonValueOfInstance<P extends PropDefLike>(def: ComponentLike<P>, overrides: Record<string, unknown> | null | undefined): ReadButtonValue | null {\n if (def.category !== \"button\") return null;\n const blockId = soleButtonId(def.blockJson);\n if (!blockId) return null;\n const found: { props?: Record<string, unknown> }[] = [];\n const walk = (list: unknown): void => {\n if (!Array.isArray(list)) return;\n for (const b of list as Array<{ id?: unknown; props?: { children?: unknown; columns?: unknown } }>) {\n if (b?.id === blockId) found.push(b as { props?: Record<string, unknown> });\n walk(b?.props?.children);\n if (Array.isArray(b?.props?.columns)) for (const column of b.props.columns) walk(column);\n }\n };\n walk(def.blockJson);\n const props: Record<string, unknown> = { ...(found[0]?.props ?? {}) };\n for (const p of withButtonLookProps(def)) {\n if (p.target.blockId !== blockId || !overrides || !(p.key in overrides)) continue;\n if (p.type === \"button\") Object.assign(props, buttonBlockProps(overrides[p.key]));\n else if (p.target.path.startsWith(\"props.\")) props[p.target.path.slice(\"props.\".length)] = overrides[p.key];\n }\n return readButtonValue({ ...props, label: props.text });\n}\n\n","/**\n * A LINK VALUE: what a `link` field, a `link` prop and a button's `href` store.\n *\n * Two shapes, both valid forever:\n * - a plain href string (\"/about\", \"https://example.com\"), which is what every value stored\n * before the V2 link element holds;\n * - the V2 link object (dashboard kit `controls/link.tsx`, `LinkValue` after `finalizeLink`):\n * `{ type, href, title?, newTab?, target?, rel?, section?, ref? }`.\n *\n * `href` is always the final href the site renders (`mailto:`, `tel:`, `#anchor` included), so a\n * reader that only wants a destination reads `href` and nothing else. `ref` is the id of the page\n * or CMS item a `page` / `entry` link points at: the write path checks it exists and delivery\n * resolves it like a reference. Keys the kit writes beside these (`pageId`, `entryId`, `assetId`,\n * `anchor`, `email`, `subject`, `phone`, `label`) are kept as sent.\n */\n\n/** A link's relation beyond a new tab's own `noopener noreferrer`. */\nexport const LINK_RELS = [\"nofollow\", \"sponsored\", \"ugc\"] as const;\nexport type LinkRel = (typeof LINK_RELS)[number];\n\n/**\n * What a link points at. `section` is the kit's spelling of `anchor` (a `#fragment` on the page);\n * both are accepted and stored as sent.\n */\nexport const LINK_VALUE_TYPES = [\"url\", \"page\", \"entry\", \"email\", \"phone\", \"anchor\", \"section\", \"file\"] as const;\nexport type LinkValueType = (typeof LINK_VALUE_TYPES)[number];\n\nexport interface LinkValue {\n type?: LinkValueType;\n href: string;\n title?: string;\n newTab?: boolean;\n /** Legacy mirror of `newTab`; must agree with it. */\n target?: \"_self\" | \"_blank\";\n /** Absent = a normal link (the kit's \"follow\" is dropped on write). */\n rel?: LinkRel;\n /** The `#anchor` on the target page. */\n section?: string;\n /** The page id (`type: \"page\"`) or entry id (`type: \"entry\"`) this link points at. */\n ref?: string;\n}\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> => !!v && typeof v === \"object\" && !Array.isArray(v);\n\n/** A link object (`{ href: string, … }`), as opposed to a plain href string. */\nexport function isLinkObject(value: unknown): value is LinkValue & Record<string, unknown> {\n return isPlainObject(value) && typeof value.href === \"string\";\n}\n\n/** A link value's destination: the string itself, or the object's `href`. Null for anything else. */\nexport function linkHref(value: unknown): string | null {\n if (typeof value === \"string\") return value;\n return isLinkObject(value) ? value.href : null;\n}\n\n/** The page or entry a `page` / `entry` link points at, or null. Reads `ref`, then the kit's `pageId` / `entryId`. */\nexport function linkRefOf(value: unknown): { kind: \"page\" | \"entry\"; id: string } | null {\n if (!isLinkObject(value) || (value.type !== \"page\" && value.type !== \"entry\")) return null;\n const id = value.ref ?? (value.type === \"page\" ? value.pageId : value.entryId);\n return typeof id === \"string\" && id.length > 0 ? { kind: value.type, id } : null;\n}\n\n/** `javascript:`, `data:` and `vbscript:`, also behind the control characters a URL parser strips. */\nexport const isScriptHref = (href: string): boolean =>\n /^(javascript|data|vbscript):/i.test(href.replace(/[\\u0000- \\u007F]/g, \"\"));\n\nconst newTabOf = (v: Record<string, unknown>): boolean => v.newTab === true || (v.newTab === undefined && v.target === \"_blank\");\n\n/**\n * Why a link OBJECT is not a link value, or null when it is. The href's own grammar (which schemes,\n * which relative forms) is the caller's rule; this refuses only what no link may be.\n * Messages start with `link_value_invalid:` so every surface can name the refusal.\n */\nexport function linkValueProblem(value: unknown): string | null {\n if (!isPlainObject(value)) return \"link_value_invalid: must be an href string or a link object { type, href, … }\";\n const v = value;\n if (typeof v.href !== \"string\") return \"link_value_invalid: needs an href string\";\n if (isScriptHref(v.href)) return \"link_value_invalid: script links (javascript:, data:, vbscript:) aren't allowed\";\n if (v.type !== undefined && !LINK_VALUE_TYPES.includes(v.type as LinkValueType)) {\n return `link_value_invalid: unknown type \"${String(v.type)}\" (${LINK_VALUE_TYPES.join(\", \")})`;\n }\n for (const key of [\"title\", \"section\", \"ref\"] as const) {\n if (v[key] !== undefined && typeof v[key] !== \"string\") return `link_value_invalid: ${key} must be a string`;\n }\n if (v.ref !== undefined && v.type !== \"page\" && v.type !== \"entry\") return \"link_value_invalid: ref is the target of a page or entry link\";\n if (v.newTab !== undefined && typeof v.newTab !== \"boolean\") return \"link_value_invalid: newTab must be true or false\";\n if (v.target !== undefined && v.target !== \"_self\" && v.target !== \"_blank\") return 'link_value_invalid: target must be \"_self\" or \"_blank\"';\n if (typeof v.newTab === \"boolean\" && v.target !== undefined && v.newTab !== (v.target === \"_blank\")) {\n return \"link_value_invalid: newTab and target disagree\";\n }\n // The kit's \"follow\" (a normal link) is not a rel: the write normalizer drops it before this runs.\n if (v.rel !== undefined && !LINK_RELS.includes(v.rel as LinkRel)) {\n return `link_value_invalid: unknown rel \"${String(v.rel)}\" (nofollow, sponsored or ugc)`;\n }\n return null;\n}\n\n/**\n * A link value as it is stored: a string as sent; an object with the kit's `rel: \"follow\"` dropped\n * (no rel IS a normal link), `newTab` filled from a lone `target`, a page/entry link's\n * `pageId` / `entryId` copied to `ref`, and the read-only `resolved` dropped. Never invents a destination.\n */\nexport function normalizeLinkValue<T>(value: T): T {\n if (!isLinkObject(value)) return value;\n const out: Record<string, unknown> = { ...value };\n // `resolved` is what a delivery read adds (the target page or entry); a client that writes a\n // read value back must not store a stale copy of its target.\n delete out.resolved;\n if (out.rel === \"follow\") delete out.rel;\n if (out.newTab === undefined && out.target !== undefined) out.newTab = out.target === \"_blank\";\n const ref = linkRefOf(out);\n if (ref && out.ref === undefined) out.ref = ref.id;\n return out as T;\n}\n\n/** What an anchor for this link value carries: its href, whether it opens a new tab, and its rel. */\nexport function linkAnchorOf(value: unknown): { href: string; newTab: boolean; rel?: LinkRel } | null {\n if (typeof value === \"string\") return { href: value, newTab: false };\n if (!isLinkObject(value)) return null;\n return {\n href: value.href,\n newTab: newTabOf(value),\n ...(LINK_RELS.includes(value.rel as LinkRel) ? { rel: value.rel as LinkRel } : {}),\n };\n}\n","/**\n * The V2 video value (DESIGN.md §6.2, §8.15): a pasted provider link or a file URL, as a bare\n * string or as `{ url, poster?, autoplay?, loop?, transcript? }`.\n *\n * The object's keys are the `video` block's own props (`VideoProps`, block.ts), so a video prop\n * aimed at a video block lands as that block's props unchanged, and a video field renders the way\n * the block does. Any other key is refused by name (`video_value_invalid`), never dropped.\n */\n\n/** The keys a video object may carry: exactly the `video` block's props. */\nexport const VIDEO_VALUE_KEYS = [\"url\", \"poster\", \"autoplay\", \"loop\", \"transcript\"] as const;\n\n/** A video value's object form. A bare string is the same value with only `url`. */\nexport interface VideoValue {\n url: string;\n poster?: string;\n autoplay?: boolean;\n loop?: boolean;\n transcript?: string;\n}\n\n/** Same cap as the video block's transcript (CPO-093). */\nexport const VIDEO_TRANSCRIPT_MAX = 100_000;\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> => typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/** A URL a video or poster may hold: an http(s) URL or a site path. \"\" is an unset one. */\nconst isVideoUrl = (s: string): boolean => s === \"\" || /^https?:\\/\\/[^\\s]+$/i.test(s.trim()) || /^\\/(?!\\/)\\S*$/.test(s.trim());\n\n/** The url a video value plays, or null when it holds none (a bare string is its url). */\nexport function videoUrlOf(value: unknown): string | null {\n const url = typeof value === \"string\" ? value : isPlainObject(value) ? value.url : undefined;\n return typeof url === \"string\" && url.trim() !== \"\" ? url.trim() : null;\n}\n\n/** Why `value` is not a video value, or null when it is. Every message starts `video_value_invalid:`. */\nexport function videoValueProblem(value: unknown): string | null {\n if (typeof value === \"string\") return isVideoUrl(value) ? null : \"video_value_invalid: url must be an http(s) URL or a site path\";\n if (!isPlainObject(value)) return \"video_value_invalid: must be a URL string or { url, poster?, autoplay?, loop?, transcript? }\";\n const unknown = Object.keys(value).find((k) => !(VIDEO_VALUE_KEYS as readonly string[]).includes(k));\n if (unknown !== undefined) return `video_value_invalid: unknown key \"${unknown}\" (${VIDEO_VALUE_KEYS.join(\", \")})`;\n if (typeof value.url !== \"string\") return \"video_value_invalid: needs a url string\";\n if (!isVideoUrl(value.url)) return \"video_value_invalid: url must be an http(s) URL or a site path\";\n if (value.poster !== undefined && (typeof value.poster !== \"string\" || !isVideoUrl(value.poster))) {\n return \"video_value_invalid: poster must be an http(s) URL or a site path\";\n }\n for (const key of [\"autoplay\", \"loop\"] as const) {\n if (value[key] !== undefined && typeof value[key] !== \"boolean\") return `video_value_invalid: ${key} must be true or false`;\n }\n if (value.transcript !== undefined && (typeof value.transcript !== \"string\" || value.transcript.length > VIDEO_TRANSCRIPT_MAX)) {\n return `video_value_invalid: transcript must be a string of ${VIDEO_TRANSCRIPT_MAX} characters or fewer`;\n }\n return null;\n}\n","/**\n * The V2 TABLE value (CPO D42; V2 `src/schema/table.ts`): typed, keyed columns × keyed rows.\n *\n * What a `table` FIELD stores, and what a `table` PROP stores when its `config.mode` is `\"data\"`.\n * A `table` prop with no mode (or `mode: \"rows\"`) is the older shape, an array of row objects\n * keyed by `config.fields`, and is not this value.\n *\n * { id?, caption, notes?, headerRow, headerColumn, columns: [{ _key, label, type, … }],\n * columnGroups?, rowGroups?, rows: [{ _key, cells: { [columnKey]: cell }, group?, footer?, type?, highlight? }],\n * footnotes?, filterable?, design?, jsonLd? }\n *\n * A cell is a bare value (string, number, boolean, null, a link `{ label, href, newTab?, rel? }`, a\n * reference `{ ref, label?, href? }`) or `{ value, type?, note? }` when it needs its own type or a\n * footnote. Body cells never merge: only group headers span.\n *\n * One renderer for every read lane: {@link renderTableHtml} (hosted pages), {@link tableToMarkdown}\n * (the `.md` twin), {@link tableSearchText} (site search). A reference cell renders what a read\n * resolved onto it (`resolved`), then its stored `label` / `href`, then its id.\n *\n * Every refusal is named (`table_value_invalid`, `table_caption_required`, `table_limit_exceeded`,\n * `table_column_type_not_allowed`, `table_columns_locked`, `link_value_invalid`) at the value's own\n * path, and no key is dropped: an unknown one is refused by name.\n */\nimport { isScriptHref, LINK_RELS } from \"./link-value.js\";\n\nexport const TABLE_COLUMN_TYPES = [\"text\", \"number\", \"money\", \"boolean\", \"rating\", \"link\", \"richtext-inline\", \"reference\"] as const;\nexport type TableColumnType = (typeof TABLE_COLUMN_TYPES)[number];\nexport const TABLE_RESPONSIVE = [\"scroll\", \"stack\", \"cards\"] as const;\nexport type TableResponsive = (typeof TABLE_RESPONSIVE)[number];\nexport const TABLE_JSONLD_TYPES = [\"none\", \"ItemList\", \"Dataset\", \"Offers\"] as const;\nexport type TableJsonLdType = (typeof TABLE_JSONLD_TYPES)[number];\n\n/** Hard limits, whatever a field allows: past these a table is a dataset, not page content. */\nexport const TABLE_LIMITS = { columns: 50, rows: 1000, cellChars: 5000, captionChars: 300, notesChars: 2000, keyChars: 64, labelChars: 300 } as const;\n\nexport interface TableColumn {\n _key: string;\n label: string;\n type: TableColumnType;\n description?: string;\n unit?: string;\n currency?: string;\n decimals?: number;\n align?: \"start\" | \"center\" | \"end\";\n sortable?: boolean;\n group?: string;\n trueLabel?: string;\n falseLabel?: string;\n max?: number;\n refTo?: string[];\n highlight?: boolean;\n}\nexport interface TableGroup { _key: string; label: string }\nexport interface TableLink { label: string; href: string; newTab?: boolean; rel?: \"follow\" | \"nofollow\" | \"ugc\" | \"sponsored\" }\n/** What a read that resolves references writes onto a reference cell (never stored). */\nexport interface TableRefResolved { kind: \"page\" | \"entry\"; id: string; title: string; slug: string | null; url: string | null }\nexport interface TableRef { ref: string; label?: string; href?: string; resolved?: TableRefResolved }\nexport type TableCellValue = string | number | boolean | null | TableLink | TableRef;\nexport interface TableCellObject { value: TableCellValue; type?: TableColumnType; note?: string }\nexport type TableCell = TableCellValue | TableCellObject;\nexport interface TableRow {\n _key: string;\n cells: Record<string, TableCell | undefined>;\n group?: string;\n footer?: boolean;\n type?: TableColumnType;\n highlight?: boolean;\n}\nexport interface TableFootnote { _key: string; text: string }\nexport interface TableValue {\n id?: string;\n caption: string;\n notes?: string;\n headerRow: boolean;\n headerColumn: boolean;\n columns: TableColumn[];\n columnGroups?: TableGroup[];\n rowGroups?: TableGroup[];\n rows: TableRow[];\n footnotes?: TableFootnote[];\n filterable?: boolean;\n design?: { responsive?: TableResponsive; sticky?: boolean; striped?: boolean; density?: \"compact\" | \"comfortable\"; hideCaption?: boolean };\n jsonLd?: { type: TableJsonLdType; axis?: \"rows\" | \"columns\"; priceRow?: string };\n}\n\n/** The field-level options (`config` of a `table` field, or of a `table` prop in `mode: \"data\"`). */\nexport interface TableFieldOptions {\n columnTypes?: TableColumnType[];\n lockColumns?: boolean;\n minRows?: number;\n maxRows?: number;\n maxColumns?: number;\n requireCaption?: boolean;\n allowGroups?: boolean;\n allowFootnotes?: boolean;\n allowNote?: boolean;\n settings?: { headers?: boolean; totals?: boolean; phones?: TableResponsive[]; highlight?: boolean; sticky?: boolean; sort?: boolean; search?: boolean };\n jsonLd?: Exclude<TableJsonLdType, \"none\">[];\n}\n\nconst isObj = (v: unknown): v is Record<string, unknown> => !!v && typeof v === \"object\" && !Array.isArray(v);\n\n/** A value shaped like a table (`columns` and `rows` arrays): what a walker hands to the table lane. */\nexport const isTableValue = (v: unknown): v is TableValue => isObj(v) && Array.isArray(v.columns) && Array.isArray(v.rows);\nexport const isTableCellObject = (c: unknown): c is TableCellObject => isObj(c) && \"value\" in c;\nexport const isTableRef = (v: unknown): v is TableRef => isObj(v) && \"ref\" in v;\nexport const isTableLink = (v: unknown): v is TableLink => isObj(v) && !(\"ref\" in v) && \"href\" in v;\n\n/** A cell's value, unwrapped from `{ value, … }`. */\nexport const tableCellValue = (c: unknown): TableCellValue => (c === undefined ? null : isTableCellObject(c) ? c.value : (c as TableCellValue));\n/** The type that judges a cell: its own, then its row's, then its column's. */\nexport const tableCellType = (col: TableColumn, row?: TableRow, c?: unknown): TableColumnType => (isTableCellObject(c) && c.type) || row?.type || col.type;\n\n// ── validation ─────────────────────────────────────────────────────────────────────────────────\n\nexport type TableProblem = { path: Array<string | number>; code: string; message: string };\n\nconst TOP_KEYS = new Set([\"id\", \"caption\", \"notes\", \"headerRow\", \"headerColumn\", \"columns\", \"columnGroups\", \"rowGroups\", \"rows\", \"footnotes\", \"filterable\", \"design\", \"jsonLd\"]);\nconst COLUMN_KEYS = new Set([\"_key\", \"label\", \"type\", \"description\", \"unit\", \"currency\", \"decimals\", \"align\", \"sortable\", \"group\", \"trueLabel\", \"falseLabel\", \"max\", \"refTo\", \"highlight\"]);\nconst ROW_KEYS = new Set([\"_key\", \"cells\", \"group\", \"footer\", \"type\", \"highlight\"]);\nconst GROUP_KEYS = new Set([\"_key\", \"label\"]);\nconst FOOTNOTE_KEYS = new Set([\"_key\", \"text\"]);\nconst DESIGN_KEYS = new Set([\"responsive\", \"sticky\", \"striped\", \"density\", \"hideCaption\"]);\nconst JSONLD_KEYS = new Set([\"type\", \"axis\", \"priceRow\"]);\nconst CELL_KEYS = new Set([\"value\", \"type\", \"note\"]);\nconst LINK_KEYS = new Set([\"label\", \"href\", \"newTab\", \"rel\"]);\n// `resolved` is what a read writes; a client that echoes a read back is not refused for it (normalize drops it).\nconst REF_KEYS = new Set([\"ref\", \"label\", \"href\", \"resolved\"]);\nconst TABLE_LINK_RELS: readonly string[] = [\"follow\", ...LINK_RELS];\n\nexport type TableCheckOptions = TableFieldOptions & {\n /** The columns a `lockColumns` table must keep (the field's default table): same keys, types and order. */\n lockedColumns?: ReadonlyArray<{ _key: string; type: string }>;\n /** The caller's href grammar (which relative forms a site may hold); script hrefs are always refused. */\n hrefProblem?: (href: string) => string | null;\n};\n\n/**\n * Every reason `value` is not a table this field takes, each at its own path inside the value\n * (`rows[2].cells.price`). Empty when it is one. Cells whose words do not match their column's type\n * (text in a number column) are accepted, as V2 accepts them: the type decides formatting, and the\n * editor warns. A cell OBJECT must match its type (a link in a link cell, a reference in a reference\n * cell), so nothing is stored that the renderer would drop.\n */\nexport function tableValueProblems(value: unknown, opts: TableCheckOptions = {}): TableProblem[] {\n const out: TableProblem[] = [];\n const bad = (path: Array<string | number>, message: string, code = \"table_value_invalid\") => out.push({ path, code, message: `${code}: ${message}` });\n if (!isTableValue(value)) {\n bad([], \"a table is { caption, headerRow, headerColumn, columns: [{ _key, label, type }], rows: [{ _key, cells }] }\");\n return out;\n }\n const t = value as unknown as Record<string, unknown>;\n const unknownKeys = (o: Record<string, unknown>, allowed: Set<string>, at: Array<string | number>) => {\n for (const k of Object.keys(o)) if (!allowed.has(k)) bad([...at, k], `unknown key \"${k}\" (${[...allowed].join(\", \")})`);\n };\n const str = (v: unknown, at: Array<string | number>, what: string, max: number, required = false) => {\n if (v === undefined && !required) return;\n if (typeof v !== \"string\") bad(at, `${what} must be a string`);\n else if (v.length > max) bad(at, `${what} is ${v.length} characters; at most ${max}`, \"table_limit_exceeded\");\n };\n const bool = (v: unknown, at: Array<string | number>, what: string) => {\n if (v !== undefined && typeof v !== \"boolean\") bad(at, `${what} must be true or false`);\n };\n const oneOf = (v: unknown, at: Array<string | number>, what: string, allowed: readonly string[]) => {\n if (v !== undefined && !allowed.includes(v as string)) bad(at, `${what} must be one of ${allowed.join(\", \")}`);\n };\n unknownKeys(t, TOP_KEYS, []);\n str(t.id, [\"id\"], \"id\", TABLE_LIMITS.keyChars);\n str(t.caption, [\"caption\"], \"caption\", TABLE_LIMITS.captionChars, true);\n if (typeof t.caption === \"string\" && t.caption.trim() === \"\" && opts.requireCaption !== false) {\n bad([\"caption\"], \"give the table a caption that says what it compares (it names the table for screen readers and search)\", \"table_caption_required\");\n }\n str(t.notes, [\"notes\"], \"notes\", TABLE_LIMITS.notesChars);\n if (t.notes !== undefined && opts.allowNote === false && typeof t.notes === \"string\" && t.notes.trim() !== \"\") bad([\"notes\"], \"this table takes no note (config.allowNote is false)\");\n bool(t.headerRow, [\"headerRow\"], \"headerRow\");\n bool(t.headerColumn, [\"headerColumn\"], \"headerColumn\");\n bool(t.filterable, [\"filterable\"], \"filterable\");\n if (t.design !== undefined) {\n if (!isObj(t.design)) bad([\"design\"], \"design must be an object\");\n else {\n const d = t.design;\n unknownKeys(d, DESIGN_KEYS, [\"design\"]);\n oneOf(d.responsive, [\"design\", \"responsive\"], \"design.responsive\", TABLE_RESPONSIVE);\n oneOf(d.density, [\"design\", \"density\"], \"design.density\", [\"compact\", \"comfortable\"]);\n for (const k of [\"sticky\", \"striped\", \"hideCaption\"]) bool(d[k], [\"design\", k], `design.${k}`);\n }\n }\n\n // Groups and footnotes first: columns, rows and cells name them.\n const keyed = (list: unknown, at: string, keys: Set<string>, textKey: \"label\" | \"text\", allowed: boolean): Set<string> => {\n const seen = new Set<string>();\n if (list === undefined) return seen;\n if (!Array.isArray(list)) {\n bad([at], `${at} must be an array`);\n return seen;\n }\n if (!allowed && list.length > 0) bad([at], `this table takes no ${at === \"footnotes\" ? \"footnotes (config.allowFootnotes is false)\" : \"row groups (config.allowGroups is false)\"}`);\n list.forEach((g, i) => {\n if (!isObj(g)) return bad([at, i], `${at}[${i}] must be an object`);\n unknownKeys(g, keys, [at, i]);\n if (typeof g._key !== \"string\" || g._key === \"\" || g._key.length > TABLE_LIMITS.keyChars) bad([at, i, \"_key\"], `needs a _key string of 1 to ${TABLE_LIMITS.keyChars} characters`);\n else if (seen.has(g._key)) bad([at, i, \"_key\"], `_key \"${g._key}\" is used twice`);\n else seen.add(g._key);\n str(g[textKey], [at, i, textKey], textKey, textKey === \"text\" ? TABLE_LIMITS.notesChars : TABLE_LIMITS.labelChars, true);\n });\n return seen;\n };\n const colGroups = keyed(t.columnGroups, \"columnGroups\", GROUP_KEYS, \"label\", true);\n const rowGroups = keyed(t.rowGroups, \"rowGroups\", GROUP_KEYS, \"label\", opts.allowGroups !== false);\n const notes = keyed(t.footnotes, \"footnotes\", FOOTNOTE_KEYS, \"text\", opts.allowFootnotes !== false);\n\n const columns = t.columns as unknown[];\n const maxColumns = Math.min(opts.maxColumns ?? TABLE_LIMITS.columns, TABLE_LIMITS.columns);\n if (columns.length > maxColumns) bad([\"columns\"], `${columns.length} columns; at most ${maxColumns}`, \"table_limit_exceeded\");\n const cols = new Map<string, TableColumn>();\n columns.forEach((c, i) => {\n const at = [\"columns\", i];\n if (!isObj(c)) return bad(at, `columns[${i}] must be an object`);\n unknownKeys(c, COLUMN_KEYS, at);\n if (typeof c._key !== \"string\" || c._key === \"\" || c._key.length > TABLE_LIMITS.keyChars) bad([...at, \"_key\"], `needs a _key string of 1 to ${TABLE_LIMITS.keyChars} characters`);\n else if (cols.has(c._key)) bad([...at, \"_key\"], `_key \"${c._key}\" is used twice`);\n str(c.label, [...at, \"label\"], \"label\", TABLE_LIMITS.labelChars, true);\n if (!TABLE_COLUMN_TYPES.includes(c.type as TableColumnType)) bad([...at, \"type\"], `type must be one of ${TABLE_COLUMN_TYPES.join(\", \")}`);\n else if (opts.columnTypes && !opts.columnTypes.includes(c.type as TableColumnType)) {\n bad([...at, \"type\"], `a ${String(c.type)} column is not offered here (config.columnTypes: ${opts.columnTypes.join(\", \")})`, \"table_column_type_not_allowed\");\n }\n str(c.description, [...at, \"description\"], \"description\", TABLE_LIMITS.notesChars);\n str(c.unit, [...at, \"unit\"], \"unit\", 16);\n if (c.currency !== undefined && (typeof c.currency !== \"string\" || !/^[A-Z]{3}$/.test(c.currency))) bad([...at, \"currency\"], \"currency must be an ISO 4217 code such as USD\");\n if (c.decimals !== undefined && (!Number.isInteger(c.decimals) || (c.decimals as number) < 0 || (c.decimals as number) > 10)) bad([...at, \"decimals\"], \"decimals must be a whole number from 0 to 10\");\n if (c.max !== undefined && (!Number.isInteger(c.max) || (c.max as number) < 1 || (c.max as number) > 10)) bad([...at, \"max\"], \"max must be a whole number from 1 to 10\");\n oneOf(c.align, [...at, \"align\"], \"align\", [\"start\", \"center\", \"end\"]);\n for (const k of [\"sortable\", \"highlight\"]) bool(c[k], [...at, k], k);\n str(c.trueLabel, [...at, \"trueLabel\"], \"trueLabel\", TABLE_LIMITS.labelChars);\n str(c.falseLabel, [...at, \"falseLabel\"], \"falseLabel\", TABLE_LIMITS.labelChars);\n if (c.group !== undefined && (typeof c.group !== \"string\" || !colGroups.has(c.group))) bad([...at, \"group\"], `group \"${String(c.group)}\" is not a key of columnGroups`);\n if (c.refTo !== undefined && (!Array.isArray(c.refTo) || c.refTo.some((r) => typeof r !== \"string\" || r === \"\"))) bad([...at, \"refTo\"], 'refTo must be a list of collection ids or \"page\"');\n if (typeof c._key === \"string\" && c._key !== \"\" && !cols.has(c._key)) cols.set(c._key, c as unknown as TableColumn);\n });\n if (opts.lockColumns && opts.lockedColumns) {\n const want = opts.lockedColumns.map((c) => `${c._key}:${c.type}`).join(\",\");\n const got = columns.map((c) => (isObj(c) ? `${String(c._key)}:${String(c.type)}` : \"?\")).join(\",\");\n if (want !== got) bad([\"columns\"], `this table's columns are set by its developer (config.lockColumns): keep ${opts.lockedColumns.map((c) => c._key).join(\", \")}, in that order, with their types`, \"table_columns_locked\");\n }\n\n const rows = t.rows as unknown[];\n const maxRows = Math.min(opts.maxRows ?? TABLE_LIMITS.rows, TABLE_LIMITS.rows);\n const body = rows.filter((r) => !(isObj(r) && r.footer === true)).length;\n if (rows.length > TABLE_LIMITS.rows || body > maxRows) bad([\"rows\"], `${body} rows; at most ${maxRows}`, \"table_limit_exceeded\");\n if (opts.minRows !== undefined && body < opts.minRows) bad([\"rows\"], `${body} rows; at least ${opts.minRows}`, \"table_rows_min\");\n const rowKeys = new Set<string>();\n rows.forEach((r, i) => {\n const at = [\"rows\", i];\n if (!isObj(r)) return bad(at, `rows[${i}] must be an object`);\n unknownKeys(r, ROW_KEYS, at);\n if (typeof r._key !== \"string\" || r._key === \"\" || r._key.length > TABLE_LIMITS.keyChars) bad([...at, \"_key\"], `needs a _key string of 1 to ${TABLE_LIMITS.keyChars} characters`);\n else if (rowKeys.has(r._key)) bad([...at, \"_key\"], `_key \"${r._key}\" is used twice`);\n else rowKeys.add(r._key);\n if (r.group !== undefined && (typeof r.group !== \"string\" || !rowGroups.has(r.group))) bad([...at, \"group\"], `group \"${String(r.group)}\" is not a key of rowGroups`);\n bool(r.footer, [...at, \"footer\"], \"footer\");\n bool(r.highlight, [...at, \"highlight\"], \"highlight\");\n oneOf(r.type, [...at, \"type\"], \"type\", TABLE_COLUMN_TYPES);\n if (!isObj(r.cells)) return bad([...at, \"cells\"], \"cells must be an object keyed by column _key\");\n for (const [k, cell] of Object.entries(r.cells)) {\n const cAt = [...at, \"cells\", k];\n const col = cols.get(k);\n if (!col) {\n bad(cAt, `no column has _key \"${k}\"`);\n continue;\n }\n cellProblems(cell, col, r as unknown as TableRow, cAt, notes, opts, bad);\n }\n });\n return out;\n}\n\nfunction cellProblems(\n cell: unknown,\n col: TableColumn,\n row: TableRow,\n at: Array<string | number>,\n notes: Set<string>,\n opts: TableCheckOptions,\n bad: (path: Array<string | number>, message: string, code?: string) => void,\n): void {\n if (cell === undefined || cell === null) return;\n let v: unknown = cell;\n let vAt = at;\n if (isTableCellObject(cell)) {\n for (const k of Object.keys(cell)) if (!CELL_KEYS.has(k)) bad([...at, k], `unknown key \"${k}\" (value, type, note)`);\n if (cell.type !== undefined && !TABLE_COLUMN_TYPES.includes(cell.type)) bad([...at, \"type\"], `type must be one of ${TABLE_COLUMN_TYPES.join(\", \")}`);\n if (cell.note !== undefined && (typeof cell.note !== \"string\" || !notes.has(cell.note))) bad([...at, \"note\"], `note \"${String(cell.note)}\" is not a key of footnotes`);\n v = cell.value;\n vAt = [...at, \"value\"];\n if (v === null) return;\n }\n const type = tableCellType(col, row, cell);\n if (typeof v === \"string\") {\n if (v.length > TABLE_LIMITS.cellChars) bad(vAt, `a cell holds at most ${TABLE_LIMITS.cellChars} characters`, \"table_limit_exceeded\");\n return;\n }\n if (typeof v === \"number\") {\n if (!Number.isFinite(v)) bad(vAt, \"a number cell must be finite\");\n return;\n }\n if (typeof v === \"boolean\") return;\n if (!isObj(v)) return bad(vAt, \"a cell holds text, a number, true / false, a link { label, href } or a reference { ref }\");\n if (\"ref\" in v) {\n if (type !== \"reference\") return bad(vAt, `a reference { ref } belongs in a reference cell; this cell is ${type}`);\n for (const k of Object.keys(v)) if (!REF_KEYS.has(k)) bad([...vAt, k], `unknown key \"${k}\" (ref, label, href)`);\n if (typeof v.ref !== \"string\" || v.ref === \"\") bad([...vAt, \"ref\"], \"ref must be the id of a page or an entry\");\n if (v.label !== undefined && typeof v.label !== \"string\") bad([...vAt, \"label\"], \"label must be a string\");\n if (v.href !== undefined && (typeof v.href !== \"string\" || isScriptHref(v.href))) bad([...vAt, \"href\"], \"href must be a link the site can hold (no script links)\", \"link_value_invalid\");\n return;\n }\n if (type !== \"link\") return bad(vAt, `a link { label, href } belongs in a link cell; this cell is ${type}`);\n for (const k of Object.keys(v)) if (!LINK_KEYS.has(k)) bad([...vAt, k], `unknown key \"${k}\" (label, href, newTab, rel)`);\n if (typeof v.label !== \"string\" && v.label !== undefined) bad([...vAt, \"label\"], \"label must be a string\");\n if (typeof v.href !== \"string\") return bad([...vAt, \"href\"], \"needs an href string\", \"link_value_invalid\");\n if (isScriptHref(v.href)) return bad([...vAt, \"href\"], \"script links (javascript:, data:, vbscript:) aren't allowed\", \"link_value_invalid\");\n const grammar = v.href !== \"\" ? opts.hrefProblem?.(v.href) : null;\n if (grammar) bad([...vAt, \"href\"], grammar, \"link_value_invalid\");\n if (v.newTab !== undefined && typeof v.newTab !== \"boolean\") bad([...vAt, \"newTab\"], \"newTab must be true or false\", \"link_value_invalid\");\n if (v.rel !== undefined && !TABLE_LINK_RELS.includes(v.rel as string)) bad([...vAt, \"rel\"], `rel must be one of ${TABLE_LINK_RELS.join(\", \")}`, \"link_value_invalid\");\n}\n\n/** A {@link TableProblem}'s path as the dotted / indexed string error maps use: `rows[2].cells.price`. */\nexport function tablePathString(path: ReadonlyArray<string | number>): string {\n return path.map((s, i) => (typeof s === \"number\" ? `[${s}]` : i === 0 ? s : `.${s}`)).join(\"\");\n}\n\n/**\n * The stored form of a table value: explicit `headerRow` / `headerColumn`, and no `resolved` on a\n * reference cell (a read writes it; a client echoing a read back must not store it). Everything\n * else is kept as sent. A value that is not table-shaped is returned as is, for the validator.\n */\nexport function normalizeTableValue<T>(value: T): T {\n if (!isTableValue(value)) return value;\n const t = structuredClone(value) as unknown as TableValue;\n t.headerRow = t.headerRow !== false;\n t.headerColumn = t.headerColumn === true;\n for (const r of t.rows) {\n if (!isObj(r) || !isObj(r.cells)) continue;\n for (const c of Object.values(r.cells)) {\n const v = isTableCellObject(c) ? c.value : c;\n if (isTableRef(v)) delete (v as TableRef).resolved;\n }\n }\n return t as unknown as T;\n}\n\n/** The value as the renderers read it: the header flags' defaults, nothing removed (a read's `resolved` is what they print). */\nconst readTable = (v: TableValue): TableValue => ({ ...v, headerRow: v.headerRow !== false, headerColumn: v.headerColumn === true });\n\n/** Every reference cell a table holds: the object (resolved in place by a read), its id, path and column's `refTo`. */\nexport function tableRefCells(value: unknown): Array<{ cell: TableRef; id: string; path: Array<string | number>; refTo: string[] | null }> {\n if (!isTableValue(value)) return [];\n const cols = new Map(value.columns.filter(isObj).map((c) => [c._key, c]));\n const out: Array<{ cell: TableRef; id: string; path: Array<string | number>; refTo: string[] | null }> = [];\n value.rows.forEach((r, i) => {\n if (!isObj(r) || !isObj(r.cells)) return;\n for (const [k, c] of Object.entries(r.cells)) {\n const col = cols.get(k);\n if (!col) continue;\n const v = isTableCellObject(c) ? c.value : c;\n if (!isTableRef(v) || typeof v.ref !== \"string\" || v.ref === \"\" || tableCellType(col, r, c) !== \"reference\") continue;\n out.push({ cell: v, id: v.ref, path: [\"rows\", i, \"cells\", k, ...(isTableCellObject(c) ? [\"value\"] : [])], refTo: Array.isArray(col.refTo) && col.refTo.length ? col.refTo : null });\n }\n });\n return out;\n}\n\n// ── text, HTML, Markdown ───────────────────────────────────────────────────────────────────────\n\nconst strip = (s: string) => s.replace(/<[^>]*>/g, \"\").replace(/ /g, \" \").replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/"/g, '\"').replace(/'/g, \"'\");\nconst TRUE_WORDS = new Set([\"✓\", \"✔\", \"✔️\", \"☑\", \"✅\", \"yes\", \"y\", \"true\", \"included\", \"available\", \"supported\", \"check\", \"●\"]);\nconst FALSE_WORDS = new Set([\"✗\", \"✕\", \"✖\", \"❌\", \"×\", \"x\", \"no\", \"n\", \"false\", \"not included\", \"unavailable\", \"not available\", \"unsupported\", \"—\", \"–\", \"-\", \"○\"]);\nfunction toBool(v: unknown): boolean | null {\n if (typeof v === \"boolean\") return v;\n if (typeof v !== \"string\") return null;\n const s = strip(v).trim().toLowerCase();\n return TRUE_WORDS.has(s) ? true : FALSE_WORDS.has(s) ? false : null;\n}\nfunction toNumber(v: unknown): number | null {\n if (typeof v === \"number\") return Number.isFinite(v) ? v : null;\n if (typeof v !== \"string\") return null;\n const s = v.replace(/[,\\s]/g, \"\").replace(/[^\\d.+-]/g, \"\");\n return s && /^[+-]?\\d*\\.?\\d+$/.test(s) ? Number(s) : null;\n}\nconst formatNumber = (n: number, decimals?: number) =>\n new Intl.NumberFormat(\"en-US\", decimals != null ? { minimumFractionDigits: decimals, maximumFractionDigits: decimals } : { maximumFractionDigits: 6 }).format(n);\nfunction formatMoney(n: number, currency = \"USD\", decimals?: number) {\n try {\n const whole = Number.isInteger(n) && decimals == null;\n return new Intl.NumberFormat(\"en-US\", { style: \"currency\", currency, minimumFractionDigits: whole ? 0 : (decimals ?? 2), maximumFractionDigits: whole ? 0 : (decimals ?? 2) }).format(n);\n } catch {\n return `${formatNumber(n, decimals)} ${currency}`;\n }\n}\nconst isEmptyCell = (v: TableCellValue) => v == null || v === \"\" || (isObj(v) && !(isTableRef(v) ? v.ref : (v as TableLink).label || (v as TableLink).href));\nconst refLabel = (r: TableRef) => r.resolved?.title || r.label || r.ref;\nconst refHref = (r: TableRef) => r.resolved?.url ?? r.href;\n\n/** The words a cell says (Markdown, search, screen readers). Booleans say their words, never a tick. */\nexport function tableCellText(col: TableColumn, row: TableRow | undefined, c: unknown): string {\n const v = tableCellValue(c);\n if (isEmptyCell(v)) return \"\";\n switch (tableCellType(col, row, c)) {\n case \"boolean\": {\n const b = toBool(v);\n return b == null ? strip(String(v)) : b ? col.trueLabel || \"Included\" : col.falseLabel || \"Not included\";\n }\n case \"number\": {\n const n = toNumber(v);\n return n == null ? strip(String(v)) : `${formatNumber(n, col.decimals)}${col.unit ? (/^[%°]/.test(col.unit) ? col.unit : ` ${col.unit}`) : \"\"}`;\n }\n case \"money\": {\n const n = toNumber(v);\n return n == null ? strip(String(v)) : formatMoney(n, col.currency || \"USD\", col.decimals);\n }\n case \"rating\": {\n const n = toNumber(v);\n return n == null ? strip(String(v)) : `${formatNumber(n, 1).replace(/\\.0$/, \"\")} out of ${col.max ?? 5}`;\n }\n case \"link\":\n return isObj(v) ? String((v as TableLink).label || (v as TableLink).href || \"\") : strip(String(v));\n case \"reference\":\n return isTableRef(v) ? refLabel(v) : strip(String(v));\n default:\n return isObj(v) ? String((v as TableLink).label ?? \"\") : strip(String(v)).replace(/\\s+/g, \" \").trim();\n }\n}\n\nconst esc = (s: string) => s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\nconst escAttr = (s: string) => esc(s).replace(/\"/g, \""\");\nconst safeHref = (h: string) => (isScriptHref(h) ? \"#\" : h);\nconst INLINE_TAGS = new Set([\"strong\", \"b\", \"em\", \"i\", \"u\", \"s\", \"del\", \"code\", \"a\", \"br\", \"sup\", \"sub\", \"mark\", \"small\", \"abbr\"]);\n/** Inline rich text in a cell: only inline marks and safe links survive. */\nfunction sanitizeInline(html: string): string {\n return html\n .replace(/<(script|style|iframe|object|embed|template)\\b[\\s\\S]*?<\\/\\1>/gi, \"\")\n .replace(/<\\/?([a-z][a-z0-9]*)\\b([^>]*)>/gi, (m, tag: string, attrs: string) => {\n const t = tag.toLowerCase();\n if (!INLINE_TAGS.has(t)) return \"\";\n const name = t === \"b\" ? \"strong\" : t === \"i\" ? \"em\" : t;\n if (m.startsWith(\"</\")) return `</${name}>`;\n if (t === \"a\") {\n const href = attrs.match(/href\\s*=\\s*(\"([^\"]*)\"|'([^']*)')/i);\n return `<a href=\"${escAttr(safeHref(href ? (href[2] ?? href[3] ?? \"\") : \"\"))}\">`;\n }\n if (t === \"abbr\") {\n const title = attrs.match(/title\\s*=\\s*\"([^\"]*)\"/i);\n return title ? `<abbr title=\"${escAttr(title[1]!)}\">` : \"<abbr>\";\n }\n return `<${name}>`;\n });\n}\nconst alignOf = (col: TableColumn, t: TableColumnType) => col.align ?? (t === \"number\" || t === \"money\" || t === \"rating\" ? \"end\" : \"start\");\n\n/** Rows in display order: ungrouped body rows, then each row group in order, then footer rows. */\nfunction orderedRows(t: TableValue) {\n const groups = (t.rowGroups ?? []).filter(isObj);\n const known = new Set(groups.map((g) => g._key));\n const body = t.rows.filter((r) => isObj(r) && !r.footer);\n const loose = body.filter((r) => !r.group || !known.has(r.group));\n const bodies: { group?: TableGroup; rows: TableRow[] }[] = [];\n if (loose.length || !groups.length) bodies.push({ rows: loose });\n for (const g of groups) {\n const rows = body.filter((r) => r.group === g._key);\n if (rows.length) bodies.push({ group: g, rows });\n }\n return { bodies, foot: t.rows.filter((r) => isObj(r) && r.footer) };\n}\n\nfunction cellHtml(t: TableValue, col: TableColumn, row: TableRow, c: unknown, fn: Map<string, number>, asHeader: boolean): { inner: string; align: string } {\n const v = tableCellValue(c);\n const type = tableCellType(col, row, c);\n const note = isTableCellObject(c) ? c.note : undefined;\n const n = note ? fn.get(note) : undefined;\n const sup = n ? `<sup><a href=\"#${escAttr(t.id ?? \"tbl\")}-fn-${n}\" aria-label=\"Note ${n}\">${n}</a></sup>` : \"\";\n let inner: string;\n if (isEmptyCell(v)) inner = asHeader ? \"\" : `<span aria-hidden=\"true\" class=\"bt-dash\">—</span><span class=\"bt-sr\">No value</span>`;\n else\n switch (type) {\n case \"boolean\": {\n const b = toBool(v);\n inner = b == null ? esc(strip(String(v))) : `<span aria-hidden=\"true\" class=\"bt-bool\" data-bool=\"${b}\">${b ? \"✓\" : \"–\"}</span><span class=\"bt-sr\">${esc(b ? col.trueLabel || \"Included\" : col.falseLabel || \"Not included\")}</span>`;\n break;\n }\n case \"rating\": {\n const num = toNumber(v);\n inner = num == null ? esc(strip(String(v))) : `<span aria-hidden=\"true\" class=\"bt-star\">★</span> ${esc(formatNumber(num, 1).replace(/\\.0$/, \"\"))}<span class=\"bt-dim\"> / ${col.max ?? 5}</span>`;\n break;\n }\n case \"link\": {\n const l = isObj(v) ? (v as TableLink) : { label: String(v), href: \"\" };\n const rel = [l.newTab ? \"noopener noreferrer\" : \"\", l.rel && l.rel !== \"follow\" ? l.rel : \"\"].filter(Boolean).join(\" \");\n inner = l.href ? `<a href=\"${escAttr(safeHref(l.href))}\"${l.newTab ? ' target=\"_blank\"' : \"\"}${rel ? ` rel=\"${rel}\"` : \"\"}>${esc(l.label || l.href)}</a>` : esc(l.label ?? \"\");\n break;\n }\n case \"reference\": {\n if (!isTableRef(v)) {\n inner = esc(strip(String(v)));\n break;\n }\n const href = refHref(v);\n inner = href ? `<a href=\"${escAttr(safeHref(href))}\">${esc(refLabel(v))}</a>` : esc(refLabel(v));\n break;\n }\n case \"richtext-inline\":\n inner = sanitizeInline(String(isObj(v) ? ((v as TableLink).label ?? \"\") : v));\n break;\n default:\n inner = esc(type === \"number\" || type === \"money\" ? tableCellText(col, row, c) : isObj(v) ? String((v as TableLink).label ?? \"\") : strip(String(v)));\n }\n return { inner: inner + sup, align: alignOf(col, type) };\n}\n\n/**\n * The few rules every rendered table needs wherever it lands (a hosted page, a prop's `props.html`,\n * a code site): screen-reader-only words, the scroll region, cell padding. Scoped to `.bt-table`\n * and carried in the figure, so a page without a table ships none of it.\n */\nexport const TABLE_CSS =\n \".bt-table .bt-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\" +\n \".bt-table .bt-scroll{overflow-x:auto}.bt-table table{border-collapse:collapse;width:100%}\" +\n \".bt-table th,.bt-table td{padding:8px 12px;border-bottom:1px solid #e5e5e5;text-align:start;vertical-align:top}\" +\n '.bt-table [data-align=\"end\"]{text-align:end}.bt-table [data-align=\"center\"]{text-align:center}' +\n \".bt-table caption{text-align:start;font-weight:600;padding-bottom:8px}.bt-table .bt-notes{font-size:.9em;margin-top:8px}\";\n\n/**\n * The table as semantic HTML (published form: no editing marks): `<figure class=\"bt-table\">` ›\n * `<table>` with caption, column-group headers, `<thead>`, one `<tbody>` per row group, `<tfoot>`,\n * then notes and footnotes. Stack / cards layouts restate the table roles (CSS display drops them).\n */\nexport function renderTableHtml(input: TableValue): string {\n const t = readTable(input);\n const id = (t.id ?? \"tbl\").replace(/[^\\w-]/g, \"\") || \"tbl\";\n const cols = t.columns.filter(isObj);\n const n = cols.length;\n if (!n) return \"\";\n const fn = new Map((t.footnotes ?? []).filter(isObj).map((f, i) => [f._key, i + 1]));\n const groups = (t.columnGroups ?? []).filter((g) => isObj(g) && cols.some((c) => c.group === g._key));\n const hasNotes = !!t.notes || fn.size > 0;\n const responsive = t.design?.responsive ?? \"scroll\";\n const fig: string[] = [];\n const attrs = [\n `class=\"bt-table\"`,\n `data-responsive=\"${escAttr(responsive)}\"`,\n t.design?.sticky ? `data-sticky=\"true\"` : \"\",\n t.design?.striped ? `data-striped=\"true\"` : \"\",\n t.design?.density === \"compact\" ? `data-density=\"compact\"` : \"\",\n ].filter(Boolean);\n fig.push(`<figure ${attrs.join(\" \")}><style>${TABLE_CSS}</style>`);\n fig.push(`<div class=\"bt-scroll\" role=\"region\" tabindex=\"0\" aria-labelledby=\"${id}-caption\">`);\n fig.push(`<table${hasNotes ? ` aria-describedby=\"${id}-notes\"` : \"\"}>`);\n fig.push(`<caption id=\"${id}-caption\"${t.design?.hideCaption ? ` class=\"bt-sr\"` : \"\"}>${esc(t.caption || \"Table\")}</caption>`);\n if (t.headerRow) {\n fig.push(\"<thead>\");\n if (groups.length) {\n const cells: string[] = [];\n for (let i = 0; i < n; ) {\n const g = cols[i]!.group ? groups.find((x) => x._key === cols[i]!.group) : undefined;\n if (!g) {\n cells.push(\"<td></td>\");\n i++;\n continue;\n }\n let span = 1;\n while (i + span < n && cols[i + span]!.group === g._key) span++;\n cells.push(`<th scope=\"colgroup\"${span > 1 ? ` colspan=\"${span}\"` : \"\"}>${esc(g.label)}</th>`);\n i += span;\n }\n fig.push(`<tr>${cells.join(\"\")}</tr>`);\n }\n fig.push(\n `<tr>${cols\n .map((c, i) => {\n if (i === 0 && t.headerColumn && !String(c.label ?? \"\").trim()) return \"<td></td>\";\n const align = alignOf(c, c.type);\n return `<th scope=\"col\"${align !== \"start\" ? ` data-align=\"${align}\"` : \"\"}${c.highlight ? ` data-highlight=\"true\"` : \"\"}${c.description ? ` title=\"${escAttr(c.description)}\"` : \"\"}>${esc(c.label || `Column ${i + 1}`)}</th>`;\n })\n .join(\"\")}</tr>`,\n );\n fig.push(\"</thead>\");\n }\n const rowHtml = (r: TableRow) => {\n const cells = cols.map((c, i) => {\n const asTh = t.headerColumn && i === 0;\n const { inner, align } = cellHtml(t, c, r, isObj(r.cells) ? r.cells[c._key] : undefined, fn, asTh);\n const a = `${align !== \"start\" ? ` data-align=\"${align}\"` : \"\"}${c.highlight ? ` data-highlight=\"true\"` : \"\"}`;\n return asTh ? `<th scope=\"row\"${a}>${inner}</th>` : `<td data-label=\"${escAttr(c.label || `Column ${i + 1}`)}\"${a}>${inner}</td>`;\n });\n return `<tr${r.highlight ? ` data-highlight=\"true\"` : \"\"}>${cells.join(\"\")}</tr>`;\n };\n const { bodies, foot } = orderedRows(t);\n for (const b of bodies) {\n fig.push(\"<tbody>\");\n if (b.group) fig.push(`<tr class=\"bt-group\"><th scope=\"rowgroup\" colspan=\"${n}\">${esc(b.group.label)}</th></tr>`);\n fig.push(b.rows.map(rowHtml).join(\"\"));\n fig.push(\"</tbody>\");\n }\n if (foot.length) fig.push(`<tfoot>${foot.map(rowHtml).join(\"\")}</tfoot>`);\n fig.push(\"</table></div>\");\n if (hasNotes) {\n fig.push(`<div class=\"bt-notes\" id=\"${id}-notes\">`);\n if (t.notes) fig.push(`<p>${esc(t.notes)}</p>`);\n if (fn.size) fig.push(`<ol>${(t.footnotes ?? []).filter(isObj).map((f, i) => `<li id=\"${id}-fn-${i + 1}\">${esc(f.text)}</li>`).join(\"\")}</ol>`);\n fig.push(\"</div>\");\n }\n fig.push(\"</figure>\");\n const html = fig.join(\"\");\n return responsive === \"stack\" || responsive === \"cards\"\n ? html\n .replace(/<table(?=[\\s>])/, '<table role=\"table\"')\n .replace(/<(thead|tbody|tfoot)(?=[\\s>])/g, '<$1 role=\"rowgroup\"')\n .replace(/<tr(?=[\\s>])/g, '<tr role=\"row\"')\n .replace(/<th scope=\"(col|colgroup)\"/g, '<th role=\"columnheader\" scope=\"$1\"')\n .replace(/<th scope=\"(row|rowgroup)\"/g, '<th role=\"rowheader\" scope=\"$1\"')\n .replace(/<td(?=[\\s>])/g, '<td role=\"cell\"')\n : html;\n}\n\n/**\n * Text a Markdown reader must not parse as HTML: `<` and `>` as entities (they render as the\n * characters), as the HTML table escapes them. A link target `](…)` is left as written.\n */\nconst mdSafe = (s: string) => s.replace(/(\\]\\([^)]*\\))|[<>]/g, (m: string, link?: string) => link ?? (m === \"<\" ? \"<\" : \">\"));\nconst mdCell = (s: string) => mdSafe(s).replace(/\\\\/g, \"\\\\\\\\\").replace(/\\|/g, \"\\\\|\").replace(/\\s*\\n\\s*/g, \" \").trim();\nconst inlineMd = (html: string): string =>\n strip(\n sanitizeInline(html)\n .replace(/<(strong)>([\\s\\S]*?)<\\/\\1>/g, \"**$2**\")\n .replace(/<(em)>([\\s\\S]*?)<\\/\\1>/g, \"_$2_\")\n .replace(/<code>([\\s\\S]*?)<\\/code>/g, \"`$1`\")\n .replace(/<a href=\"([^\"]*)\">([\\s\\S]*?)<\\/a>/g, (_m, h: string, l: string) => `[${l}](${h.replace(/&/g, \"&\")})`)\n .replace(/<br>/g, \" \"),\n );\n\n/**\n * The table as GFM: the caption in bold above, one header row (a column group prefixes its\n * columns: \"Sizes · Chest\"), a row group as a bold label row, then notes, column descriptions and\n * footnotes. Booleans say their words. Links and resolved references are Markdown links.\n */\nexport function tableToMarkdown(input: TableValue): string {\n const t = readTable(input);\n const cols = t.columns.filter(isObj);\n if (!cols.length) return \"\";\n const groups = new Map((t.columnGroups ?? []).filter(isObj).map((g) => [g._key, g.label]));\n const fn = new Map((t.footnotes ?? []).filter(isObj).map((f, i) => [f._key, i + 1]));\n const pfx = (t.id ?? \"t\").replace(/[^\\w-]/g, \"\") || \"t\";\n const line = (cells: string[]) => `| ${cells.join(\" | \")} |`;\n const head = cols.map((c, i) => mdCell([c.group && groups.get(c.group), c.label || (i === 0 && t.headerColumn ? \"\" : `Column ${i + 1}`)].filter(Boolean).join(\" · \")) || \" \");\n const sep = cols.map((c) => (alignOf(c, c.type) === \"end\" ? \"---:\" : alignOf(c, c.type) === \"center\" ? \":---:\" : \"---\"));\n const row = (r: TableRow) =>\n line(\n cols.map((c, i) => {\n const cell = isObj(r.cells) ? r.cells[c._key] : undefined;\n const v = tableCellValue(cell);\n const ty = tableCellType(c, r, cell);\n let s = ty === \"richtext-inline\" && typeof v === \"string\" ? inlineMd(v) : tableCellText(c, r, cell);\n if (ty === \"link\" && isTableLink(v) && v.href && !isScriptHref(v.href)) s = `[${s}](${v.href})`;\n if (ty === \"reference\" && isTableRef(v)) {\n const href = refHref(v);\n if (href && !isScriptHref(href)) s = `[${s}](${href})`;\n }\n if (!s && !(t.headerColumn && i === 0)) s = \"—\";\n if (t.headerColumn && i === 0 && s) s = `**${s}**`;\n const note = isTableCellObject(cell) ? cell.note : undefined;\n if (note && fn.get(note)) s += `[^${pfx}-${fn.get(note)}]`;\n return mdCell(s) || \" \";\n }),\n );\n const out: string[] = [`**${mdCell(t.caption || \"Table\")}**`, \"\", line(head), line(sep)];\n const { bodies, foot } = orderedRows(t);\n for (const b of bodies) {\n if (b.group) out.push(line([`**${mdCell(b.group.label)}**`, ...cols.slice(1).map(() => \" \")]));\n b.rows.forEach((r) => out.push(row(r)));\n }\n foot.forEach((r) => out.push(row(r)));\n const after: string[] = [];\n if (t.notes) after.push(mdSafe(t.notes));\n const described = cols.filter((c) => c.description);\n if (described.length) after.push(mdSafe(described.map((c) => `${c.label}: ${c.description}`).join(\". \") + \".\"));\n if (fn.size) after.push((t.footnotes ?? []).filter(isObj).map((f, i) => `[^${pfx}-${i + 1}]: ${mdSafe(f.text)}`).join(\"\\n\"));\n return [out.join(\"\\n\"), ...after].join(\"\\n\\n\");\n}\n\n/** The words a table holds, for site search: caption, notes, headers, group labels, every cell's text, footnotes. */\nexport function tableSearchText(input: unknown): string {\n if (!isTableValue(input)) return \"\";\n const t = input;\n const cols = t.columns.filter(isObj);\n const parts: string[] = [t.caption, t.notes ?? \"\"];\n for (const c of cols) parts.push(c.label, c.description ?? \"\");\n for (const g of [...(t.columnGroups ?? []), ...(t.rowGroups ?? [])]) if (isObj(g)) parts.push(g.label);\n for (const r of t.rows) {\n if (!isObj(r) || !isObj(r.cells)) continue;\n for (const c of cols) {\n const cell = r.cells[c._key];\n parts.push(tableCellType(c, r, cell) === \"richtext-inline\" ? strip(String(tableCellValue(cell) ?? \"\")) : tableCellText(c, r, cell));\n }\n }\n for (const f of t.footnotes ?? []) if (isObj(f)) parts.push(f.text);\n return parts.filter((p) => typeof p === \"string\" && p.trim() !== \"\").map((p) => p.trim()).join(\" \");\n}\n","import type { DockIconName } from \"./dock-icon-names.js\";\nimport type { NumberFieldFormat } from \"./number-format.js\";\n\n/** Longest `description` a choice option may carry: one line under its label (V2's longest is 71). */\nexport const OPTION_DESCRIPTION_MAX = 140;\n\n/**\n * One choice of a select / multiselect / tags field or prop. Values are judged by `value` alone;\n * `icon` (a dock icon name, bettercms://icons/dock) and `description` (one line under the label)\n * are editor chrome. A bare string is a choice whose label is its value.\n */\nexport interface ChoiceOption {\n label: string;\n value: string;\n /** A `DockIconName`, typed as a string so a stored row (db `ComponentPropDef`) stays assignable. */\n icon?: string;\n description?: string;\n}\n\n/**\n * ContentModel — the structured content model (schema) for a workspace.\n * Defines which content fields are available for authors to fill in.\n */\nexport interface ContentModel {\n id: string;\n workspaceId: string;\n name: string;\n description?: string;\n /** 'block' models hold no entries — they are instantiable only inside a `modular` field. */\n kind?: ContentModelKind;\n fields: ContentModelField[];\n /** Authoring-only field grouping for the schema builder. Never affects the API shape. */\n fieldsets?: Fieldset[];\n createdAt: string; // ISO 8601\n updatedAt: string; // ISO 8601\n}\n\n/**\n * Canonical field types. Nesting lives on `array` via `config.zones`\n * (see {@link ArrayZoneConfig}): `group`/`repeater` are accepted as legacy input\n * by the API but normalized to `array` + zones on write, so stored/delivered\n * content never contains them.\n */\nexport type ContentModelFieldType =\n | \"text\"\n | \"richtext\"\n // THE article body — a document canvas, at most one per collection. Stored exactly like\n // `richtext` (same {format, value, html} envelope, same toRichTextEnvelope funnel), so it\n // needed no migration; the editor and the placement are what differ. Named `document`, not\n // `body`, because `placement` already has a \"body\" member: that is the SLOT, this is the\n // TYPE. Authors still see it labelled \"Body\".\n // Declared in FOUR places — keep in lockstep with packages/db/src/schema/content_models.ts,\n // ContentModelFieldOutput and the discriminated union in\n // src/lib/validation/schemas/content.ts. Only tsc catches a miss here, and only because\n // that union is cast `as unknown as` — it will NOT flag the type omission on its own.\n | \"document\"\n | \"image\"\n | \"boolean\"\n | \"number\"\n | \"select\"\n | \"reference\"\n | \"multi-reference\"\n // Same field type, camelCase. NOT a typo and NOT dead: the template seeder and the\n // Webflow migrator write this spelling (they insert via jsonb_populate_recordset,\n // bypassing Zod), and the dashboard's FieldRenderer only switches on camelCase. Real\n // rows carry it — both starter templates ship one — so every consumer of this union\n // must handle BOTH spellings.\n | \"multiReference\"\n | \"array\" // the canonical nesting type — see config.zones\n | \"date\"\n | \"datetime\"\n // ── Builder scalars ────────────────────────────────────────────────────────\n // Offered by the schema builder's field picker. Each one is VALUE-validated in\n // src/lib/content/reference-validation.ts — accepting the type without checking\n // the value would make the picker's promise (\"Validated email address\") a lie.\n | \"longtext\"\n | \"slug\"\n | \"email\"\n | \"phone\"\n | \"link\"\n | \"color\"\n | \"json\"\n | \"file\"\n // ── Component reference ────────────────────────────────────────────────────\n // A slot in the schema that holds ONE component instance. Deliberately NOT\n // named \"component\": that name already belongs to a BLOCK type\n // (componentBlockSchema, src/lib/validation/schemas/content.ts), and this\n // codebase has seven field-type lists that already disagree with each other —\n // reusing the name is how a field type ends up in a block union.\n //\n // The value is a REFERENCE, not an embedded tree:\n // draft (data) { componentId, overrides }\n // published (published_data) + resolved: the frozen block tree\n // Publishing snapshots the resolved component, so editing a component does not\n // silently rewrite entries that were already published.\n | \"component-ref\"\n // ── Modular content ────────────────────────────────────────────────────────\n // An ordered array of POLYMORPHIC block instances, each one an instance of a\n // kind='block' content model. This is the thing `array` + zones cannot express:\n // a repeatable zone has ONE fixed field set, so every item has the same shape,\n // whereas each item here may be any one of the block types the field allows.\n //\n // The stored shape IS the delivered shape — ModularBlock[], verbatim, with no\n // publish-time resolution step (unlike component-ref above). That is deliberate:\n // the one field-shape incident this codebase has had came from a type whose\n // delivered payload differed from its authored one, and `modular` is new enough\n // that no row exists to migrate.\n | \"modular\"\n // ── Section zone ───────────────────────────────────────────────────────────\n // A composable page region. The value is a BLOCK TREE — `ContentBlock[]`, the exact\n // shape `pages.block_json` already holds — NOT the flat ModularBlock[] that `modular`\n // above uses. `config.allowedSections` names which section slugs may be inserted.\n //\n // Why not just reuse `modular`, which is otherwise the same idea: page content is\n // RECURSIVE. `columns` holds ContentBlock[][], and `section`/`slider`/`tabs` each hold\n // `children: ContentBlock[]`. A flat {__id,__type,data} item cannot carry those subtrees\n // without inventing a nesting encoding, and any encoding changes what renderBlocks emits\n // — which would make migrating an existing page into one of these fields lossy. 10 live\n // pages carry container blocks today, so this is not hypothetical.\n //\n // Sharing the block tree is what makes the rest free: renderBlocks, the page builder's\n // tree ops, and the content-lock walker (which duck-types a block as {id,type,props})\n // all work on this value unchanged.\n | \"sections\"\n // ── Location ───────────────────────────────────────────────────────────────\n // { lat, lng, label? }. No existing type can stand in for it: `json` accepts\n // anything and two `number` fields cannot be validated as a coordinate pair.\n | \"location\"\n // One button as one value: { label, href, variant?, size?, arrow?, icon?, newTab? }\n // (`ButtonValue`, button-look.ts). A leaf with no config, like `location`.\n | \"button\"\n // A string[] of `config.options` values (tags when `config.allowCustom`), and a BetterCMS icon\n // name (DOCK_ICON_NAMES) or an uploaded icon as an image value. Leaves, like `location`.\n | \"multiselect\"\n | \"icon\"\n // V2 schema language: ONE nested object of named `fields`, stored as `{ [childKey]: value }`.\n // Unlike legacy `group` it is kept as `object` on write (not normalized into array zones).\n | \"object\"\n // V2 leaves (DESIGN.md §6.6 D47, §8.4, §8.21): a taxonomy string[] (`config.options` suggestions,\n // `max`, `allowCustom`), a 0..`config.max` rating number, and `{ language?, code }` or a string.\n | \"tags\"\n | \"rating\"\n | \"code\"\n // V2 video (DESIGN.md §6.2, §8.15): a URL string, or `{ url, poster?, autoplay?, loop?, transcript? }`\n // (the video block's own props). @see VideoValue\n | \"video\"\n // V2 table (CPO D42): typed, keyed columns × keyed rows, `TableValue` (table-value.ts). The\n // field's `config` holds its options (columnTypes, lockColumns, minRows, maxRows, …).\n | \"table\"\n // V2 slot: blocks inside a block, INLINE: `{ _key, _type, _variant?, _settings?, ...values }[]`\n // (slot-child.ts), `_type` a kind='block' model's slug from `config.blockSlugs`. Unlike `modular`\n // ({ __id, __type, data }) a child's values sit at its root, as V2 stores them.\n | \"slot\";\n\n/** One block instance inside a `modular` field's value. */\nexport interface ModularBlock {\n /** Stable across reorders — the React key AND the diff identity. Never the array index. */\n __id: string;\n /** The block model's SLUG. Reserved keys are `__`-prefixed so an authored field\n * named `type` cannot collide with the discriminator. */\n __type: string;\n /** The block's own field values, in the same envelopes top-level fields use\n * (image `{url, altText}`, richtext `{format, value, html}`). */\n data: Record<string, unknown>;\n}\n\nexport interface LocationValue {\n lat: number;\n lng: number;\n label?: string;\n}\n\nexport type ContentModelKind = \"model\" | \"block\";\n\n/**\n * How a fieldset renders in the dock. ABSENT ≡ today's flat list (V2): a legacy `{id, name}`\n * fieldset never regroups anything.\n * - `group` a disclosure; `row` ≤3 pairable scalars on one line; `tab` one of ≤3 top-level tabs.\n */\nexport type FieldsetKind = \"group\" | \"row\" | \"tab\";\n\n/** Who last shaped a path's authoring chrome. Server-owned: a client echo is discarded. */\nexport type UiOrigin = \"human\" | \"agent\" | \"derived\";\n\n/**\n * The chrome a field had before the first agent write over a non-agent state, kept so a human\n * can revert it. Server-owned, like {@link UiOrigin}.\n */\nexport interface UiBefore {\n ui?: ContentModelFieldUi;\n fieldsetId?: string;\n /** Index among the field's siblings at the time. */\n position: number;\n label?: string;\n helpText?: string;\n /** The V2 editor keys, snapshotted with the rest so a Revert restores them. */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n openMode?: OpenMode;\n}\n\n/**\n * A fieldset's chrome before the first agent change over a human/derived (or unstamped) state,\n * kept so a person can revert it. `label` is the set's `name`. Server-owned, like {@link UiOrigin}:\n * frozen while the origin stays `agent`, cleared by a human or derived change, carried by id.\n */\nexport interface FieldsetUiBefore {\n label: string;\n ui: {\n kind?: FieldsetKind;\n tab?: string;\n icon?: DockIconName;\n collapsed?: boolean;\n collapsible?: boolean;\n columns?: 1 | 2;\n layout?: \"stack\" | \"breakpoints\";\n };\n /** Its index among the model's fieldsets before the agent's change; absent on older snapshots. */\n position?: number;\n}\n\n/** A named, UI-only grouping of a model's fields. Order is the array index. */\nexport interface Fieldset {\n id: string;\n name: string;\n /** One line shown under the card title in the editor. Editor-only. */\n description?: string;\n kind?: FieldsetKind;\n icon?: DockIconName;\n /** A `group` that starts closed. */\n collapsed?: boolean;\n /** A group/row that sits inside this `kind:\"tab\"` fieldset. */\n tab?: string;\n /** `false`: a static heading with no toggle. */\n collapsible?: boolean;\n /** `2`: short fields side by side. */\n columns?: 1 | 2;\n /** `breakpoints`: its per-screen-size `object` fields (desktop, tablet, phone; joined by `fieldsetId`) shown as ONE group with a switcher. */\n layout?: \"stack\" | \"breakpoints\";\n uiOrigin?: UiOrigin;\n uiBefore?: FieldsetUiBefore;\n}\n\n/**\n * Nested-content config for an `array` field. A zone holds ordinary fields, and a\n * zone field may itself be an `array` with its own zones, so nesting is recursive\n * to any depth.\n * - `nonRepeatable` — a single fixed block of fields (former `group`).\n * - `repeatable` — a repeating list of field-objects (former `repeater`).\n * Mutually exclusive with the primitive form (`config.itemType`).\n */\nexport interface ArrayZoneConfig {\n nonRepeatable?: ContentModelField[];\n repeatable?: {\n fields: ContentModelField[];\n minItems?: number;\n maxItems?: number;\n };\n}\n\n/** Per-type config for a field (the typed shape behind the loose `config` bag). */\nexport interface FieldConfig {\n /**\n * primitive array: list of scalars, or of images, links or rich text (V2 `array` of one\n * primitive), each item judged by its own type's validator.\n */\n itemType?: \"text\" | \"number\" | \"date\" | \"image\" | \"link\" | \"richtext\";\n /** nested array: zoned fields (recursive) */\n zones?: ArrayZoneConfig;\n /** reference / multi-reference */\n contentModelId?: string;\n min?: number;\n max?: number;\n /** number: how the value is shown on the site (`$1,299.00`, `38%`). @see NumberFieldFormat */\n format?: NumberFieldFormat;\n /** A derived field whose value lives in an ATTRIBUTE and is written there: `aria-label`, or the `data-target` a count-up script reads. */\n attr?: string;\n /** date / datetime */\n includeTime?: boolean;\n /**\n * date / datetime with a time: \"site\" (the project's own zone), an IANA zone name, or V2 `true`\n * (the editor picks a zone) / `false` (no zone, ≡ absent). When set (not false), a stored value\n * must carry `Z` or a numeric offset, so it names one instant in every region.\n */\n timezone?: string | boolean;\n /** modular / slot: SLUGS of the kind='block' models this field accepts. Non-empty. */\n blockSlugs?: string[];\n /** slot: per-child layout settings, what each child's `_settings` holds (leaf fields). */\n slotSettings?: ContentModelField[];\n /** modular: bounds on how many block instances the field may hold; a primitive array (itemType): how many items. */\n minItems?: number;\n maxItems?: number;\n /**\n * sections: SLUGS of the sections an author may insert into this zone.\n *\n * Deliberately NOT named `blockSlugs`. That key means \"kind='block' content models\" and is\n * read by ModularField; these are section-registry slugs resolved from a different place.\n * One key meaning two things is how `blockModels`/`blockSlugs` already drifted apart in the\n * dashboard — a distinct name costs nothing and cannot be confused at a call site.\n *\n * ⚠ ABSENT ≠ EMPTY:\n * absent → UNRESTRICTED, every registry section may be inserted\n * [] → DENY ALL, a deliberate empty restriction\n * [a, b] → only those\n * `[]` means DENY here to match `components.allowed_on` (migration 0190), so two adjacent\n * allow-lists never disagree about what empty means.\n *\n * Absent rather than \"all current slugs\" because the registry GROWS — it is fed by repo\n * pushes and project components, so materializing today's slugs at field-creation time would\n * silently exclude every section shipped afterwards.\n *\n * NOT READ DIRECTLY. Insertability is this list INTERSECTED with the component's `allowedOn`\n * (where that section may be placed), computed by one resolver so the two cannot drift.\n *\n * Enforced on NEW picks only. Narrowing the list later must never invalidate sections an\n * author already placed, the same rule modular's blockSlugs and component-ref's allowlist\n * follow.\n */\n allowedSections?: string[];\n /** Durable project-local authored Zone mode. Legacy zones omit this key. */\n mode?: \"authored-v2\";\n /** Durable Zone id. Present when `mode` is `authored-v2`. */\n zoneId?: string;\n /** Explicit migration acknowledgement while the legacy allowlist remains readable. */\n legacyResolved?: boolean;\n /** number: a V2 scale (stepped range, numeric or token steps, units, presets, custom escape hatch). */\n scale?: NumberScale;\n /** number: V2 `numeric.unit`, what it counts (\"%\", \"USD\", \"days\"), shown beside the input. 1–24 chars. */\n unit?: string;\n /** number: V2 `validation.min / max`, the error bounds; they win over `min` / `max` (the input's range). */\n validation?: { min?: number; max?: number };\n /** text / longtext / richtext: length in characters (richtext: its plain text). */\n minLength?: number;\n maxLength?: number;\n /** text / longtext: a regex (≤ 200 characters) and the message shown when a value does not match it. */\n pattern?: string;\n patternMessage?: string;\n legacyMappings?: Record<string, string>;\n /**\n * image: `\"icon\"` marks an inline SVG icon the import derived (its value a `data:image/svg+xml`\n * url or an `image/svg+xml` asset). The editor offers an icon picker for it, and the dock budget\n * and the field-pruning guards leave it alone: an icon is editable content, never markup to tidy.\n */\n media?: \"icon\";\n /** multiselect / tags: the choices (tags: suggestions unless allowCustom is false). */\n options?: Array<string | ChoiceOption>;\n [key: string]: unknown;\n}\n\nexport type ScaleUnit = \"px\" | \"%\" | \"rem\" | \"em\" | \"vw\" | \"vh\";\n\n/** A V2 scale's custom value: a number in one of the scale's units. */\nexport interface ScaleCustomValue {\n value: number;\n unit: ScaleUnit;\n}\n\n/**\n * A number field's `config.scale` (V2 scale.ts, CPO D41). The value a field with a scale stores is\n * a bare number (range or numeric steps), a token step's string value, or a {@link ScaleCustomValue}\n * when `allowCustom` is set (within its bounds).\n */\nexport interface NumberScale {\n steps:\n | { min: number; max: number; step?: number }\n | Array<{ value: number; label?: string }>\n | Array<{ value: string; label: string; title?: string; px?: number; css?: string }>;\n units?: ScaleUnit[];\n defaultUnit?: ScaleUnit;\n /** Fixed values only (false, absent) or fixed + custom: `true`, or the custom value's bounds. */\n allowCustom?:\n | boolean\n | { min?: number | Partial<Record<ScaleUnit, number>>; max?: number | Partial<Record<ScaleUnit, number>>; units?: ScaleUnit[]; step?: number };\n presets?: Array<{ label?: string; value: number | string | ScaleCustomValue }>;\n}\n\n/** V2: how a compound field (an `object`, or an array's rows) opens when edited. Editor-only. */\nexport type OpenMode = \"inline\" | \"drill\" | \"popover\" | \"dialog\";\n\n/**\n * Where a field renders in the entry editor.\n *\n * AUTHORING ONLY — this has no delivery or storage effect. It does not change the\n * shape of `data`, is not read by any renderer in @bettercms-ai/next or /astro, and\n * cannot move a value onto or off a published page. It decides one thing: where the\n * control sits while somebody is writing.\n *\n * Granularity is REGION-level, never interleaved between body blocks: the canvas is\n * `[hero slots] → [free block flow] → [inline fields] → [panel fields in the drawer]`.\n * A field cannot be positioned \"between two paragraphs\" — there is no coordinate space\n * for that, and inventing one would mean mounting form controls inside the Lexical tree.\n *\n * - `cover` / `title` / `excerpt` / `body` — the four hero slots, rendered unlabelled\n * and typographically native. SCHEMA-LEVEL ONLY: a per-entry override may never\n * claim one, or one author's click renders anonymous 40px text over anonymous text\n * on that entry alone.\n * - `inline` — in the canvas, below the block flow, labelled.\n * - `panel` — in the drawer.\n *\n * ABSENT is meaningful and is the default for every model that predates this: the\n * editor falls back to its title-gated heuristic. Only an explicit value promotes a\n * field past that gate.\n */\nexport type ContentModelFieldPlacement = \"cover\" | \"title\" | \"excerpt\" | \"body\" | \"inline\" | \"panel\";\n\n/**\n * Editor-only conditional visibility: the field (or component prop) shows only while the\n * sibling keys its rules name hold these values. `isSet` reads no `value`: it passes once the\n * source holds anything (`false` and `0` count; \"\", null and an empty list do not).\n */\nexport interface ShowIfRule {\n field: string;\n /**\n * `notEmpty` ≡ `isSet`; `empty` passes while the source holds nothing. Neither reads `value`.\n * `notIn` is `in` negated. `gt` / `lt` compare numbers: `value` is one number as a string, and a\n * source that holds no number fails the rule.\n */\n op: \"eq\" | \"neq\" | \"in\" | \"notIn\" | \"gt\" | \"lt\" | \"isSet\" | \"notEmpty\" | \"empty\";\n value?: string | string[];\n}\nexport interface ShowIf {\n match: \"all\" | \"any\";\n rules: ShowIfRule[];\n}\n\nexport interface ContentModelField {\n key: string;\n label: string;\n type: ContentModelFieldType;\n /** Shown to editors under the field: what it is for, where it shows, any constraint. Never its value. */\n helpText?: string;\n required?: boolean;\n /**\n * No two entries of the model may hold the same value (trimmed, case-insensitive). On a\n * repeater child, every row of every entry at that path. Scalar types only.\n */\n unique?: boolean;\n defaultValue?: unknown;\n /** select: the choices (multiselect / tags keep theirs on `config.options`). */\n options?: Array<string | ChoiceOption>;\n /** Per-type config. For `array`: either `itemType` (primitive) or `zones` (nested). */\n config?: FieldConfig | null;\n /** `object`: its child fields. */\n fields?: ContentModelField[];\n /** `object` / `array`: how the value (or each row) opens when edited. */\n openMode?: OpenMode;\n /** Longer help behind the ⓘ next to the label. Editor-only. */\n helpMore?: string;\n /** Tuck into the closed \"Advanced\" section. Editor-only. */\n advanced?: boolean;\n /** A soft limit the editor warns at, never a refusal. */\n recommendedMax?: number;\n /**\n * Which fieldset this field renders under in the schema builder. Authoring-only: it is\n * never delivered and cannot move a value — see {@link Fieldset}.\n */\n fieldsetId?: string;\n /**\n * Authoring-only editor placement. See {@link ContentModelFieldPlacement}.\n * Field ORDER is the array index — there is deliberately no `order` property.\n */\n placement?: ContentModelFieldPlacement;\n /** Editor-only conditional visibility; a hidden required field is not required. @see ShowIf */\n showIf?: ShowIf;\n /**\n * A value another system owns (a store, job board or feed id).\n * - `\"developer\"`: only a caller with schema authority (a key with `schema:manage`, a person\n * with schema access) may change the value on an entry, or add or remove this lock. Anyone\n * else is refused with 403 `FIELD_LOCKED`. Needs {@link lockReason}.\n * - `true`: a marker the editor renders read-only. The API does not enforce it.\n */\n readOnly?: true | \"developer\";\n /** Which system owns the value; shown on the refusal. At most 200 characters. */\n lockReason?: string;\n /**\n * V2 per-field localization (the locale chip). Once any field of a schema is marked, a\n * translation row owns only its localized values; the rest are inherited from its source, and a\n * translation write that changes one is 409 `FIELD_NOT_LOCALIZED`. None marked: rows copy as before.\n */\n localized?: boolean;\n /**\n * Authoring chrome — how the field PRESENTS in the editor. Never delivered, never read by a\n * renderer, and never able to move a value; the same contract as {@link placement}.\n *\n * A SIBLING of `config`, not a member of it: `config` is per-type and strict on several\n * types, and the normalizer rebuilds it wholesale for every nesting field — so a `config.ui`\n * survives on leaves and vanishes on exactly the fields `preview` is for.\n *\n * `preview.title` / `preview.media` name a CHILD FIELD KEY of this field (validated on\n * write). Still no `order`: order is the array index, per the note on {@link placement}.\n */\n ui?: ContentModelFieldUi;\n /** Server-owned: who named this field (label, help text). Only an `auto` name may be renamed by a derive. */\n nameSource?: \"auto\" | \"human\";\n /** Server-owned: who wrote `helpText`. @see HelpSource */\n helpSource?: HelpSource;\n /** Server-owned provenance of this field's chrome. @see UiOrigin */\n uiOrigin?: UiOrigin;\n /** Server-owned revert point. @see UiBefore */\n uiBefore?: UiBefore;\n /** `true`: the last release's build renders this field on no route of its page — hidden, never deleted. `false`: a person keeps it shown. */\n stale?: boolean;\n}\n\n/** @see ContentModelField.ui */\nexport interface ContentModelFieldUi {\n /** Start this nesting field's panel collapsed. Absent ≡ the editor's own default. */\n collapsed?: boolean;\n /** How one item of a nesting field summarises itself when collapsed. Keys, not values. */\n preview?: {\n /** Child field key whose value titles the row. */\n title?: string;\n /** Child field key whose value is the row's second line. */\n subtitle?: string;\n /** Child field key whose value is the row's thumbnail. Type is not constrained. */\n media?: string;\n /** A literal row label while the title child is empty (\"Untitled question\"). Not a key. */\n fallback?: string;\n /** The row's icon while it has no media (V2 `preview.icon`). */\n icon?: DockIconName;\n };\n /**\n * How the ITEMS of a nesting field are arranged. ABSENT ≡ `\"list\"` — every field stored\n * before this key existed means `\"list\"`, so a reader must treat undefined as list and never\n * as \"unset, pick something\".\n *\n * Same placement rule as {@link ContentModelFieldUi.preview}: nesting fields only.\n */\n layout?: \"list\" | \"grid\" | \"table\" | \"rows\" | \"chips\" | \"gallery\";\n /**\n * Whether the items of a list may be dragged. ABSENT ≡ `true`, for the same reason — nothing\n * stored today carries it, and everything stored today is reorderable.\n *\n * `false` LOCKS the order: a \"three steps\" band, a semantic nav, a timeline. Valid only where\n * there is a list (a repeatable zone, a `repeater`, or `modular`), so a reader that honours it\n * must disable the sortable behaviour, not just hide the grip — a hidden grip still reorders\n * from the keyboard.\n */\n reorderable?: boolean;\n /**\n * Which editor control a LEAF renders with. ABSENT ≡ the type's default (a dropdown for a\n * `select`, a plain input for a `number`). `segmented` is valid on a single-choice `select`;\n * `slider` on a `number` whose config.min < config.max; `rating` on a `number` with numeric\n * config.min, max and step (stars).\n */\n control?: \"segmented\" | \"slider\" | \"rating\" | \"dropdown\" | \"radio\" | \"cards\" | \"grid\" | \"switch\" | \"checkbox\";\n /** The branch row's icon. Nesting fields only. */\n icon?: DockIconName;\n /** What one item is called (\"Slide\", \"Member\"), 1–24 chars (V2 itemNoun). Nesting fields and lists. */\n itemLabel?: string;\n /** V2 `rows`: the lines a text box opens with (1–40). text / longtext only. */\n rows?: number;\n /** V2 `placeholder` on a field of any type. A prop keeps its own `placeholder`. */\n placeholder?: string;\n /** V2 item identity on a list: the item type's own name (an identifier) and title. */\n itemName?: string;\n itemTitle?: string;\n /** V2 `synced`: the value comes from a global, so an edit applies everywhere. A marker. */\n synced?: { from: string };\n /** V2 `valueShape`: a link / image / button writes a plain string or the object. */\n valueShape?: \"string\" | \"object\";\n /** V2 field access (D58): who sees and who changes it. The editor gates; the backend stores. */\n access?: { view?: \"schema.view\"; edit?: \"schema.manage\" };\n /** V2 `hidden`: true = never shown in the form; false ≡ absent. A conditional hide is `showIf`. */\n hidden?: boolean;\n /**\n * V2 per-item chrome of a `modular` field (`of[i].icon` / `preview`), by block slug: how a row\n * of that block type reads in this field. Each slug is one of `config.blockSlugs`.\n */\n blocks?: Record<string, { icon?: DockIconName; preview?: ContentModelFieldUi[\"preview\"] }>;\n /**\n * A custom dock input, by NAME: the project's own input (built with its site, served on its\n * own inputs origin, never the dashboard's) draws this field instead of the stock control.\n * Data, never code. An unknown name, a disabled input or one that fails to load falls back to\n * the stock control. @see DockInputRef\n */\n input?: DockInputRef;\n}\n\n/**\n * Which custom input draws a field, and which OTHER fields of the same document it may write.\n * `writes` is an allowlist of sibling field keys: the dock refuses any patch outside it, checks\n * each against the target field's own schema, commits all of them at once (If-Match) to the\n * draft only, and undoes them as one step. Absent `writes` ≡ the input writes its own field only.\n */\nexport interface DockInputRef {\n /** The input's name in the project's inputs manifest: lowercase, digits and dashes. */\n name: string;\n /** Sibling field keys this input may also write. */\n writes?: string[];\n}\n\n/**\n * A field inside an array zone — identical to a top-level {@link ContentModelField}.\n * Kept as a named alias so consumers can express \"zone field\" intent; recursion\n * (an array zone field with its own `config.zones`) is supported.\n */\nexport type ZoneField = ContentModelField;\n\n/**\n * Who wrote a help text or a description: the platform's generator (`auto`, rewritten whenever its\n * wording improves), a person in the dashboard (`human`) or an agent over the API (`agent`). Only\n * `auto` text is ever replaced. Server-owned: a client's copy is ignored.\n */\nexport type HelpSource = \"auto\" | \"human\" | \"agent\";\n","/**\n * WHERE an element was on a built page, so a later pass can find it again.\n *\n * This lives in the shared package because BOTH ends of the comparison have to spell an address\n * the same way: the backend derives it from a JSDOM tree at import time, the dashboard computes\n * it from a live iframe tree when a person clicks an unbound element. Two implementations of\n * \"the ancestor chain down from the nearest landmark\" is one implementation too many — the first\n * time they disagree by one tag, a click binds the wrong element.\n *\n * The DOM is typed STRUCTURALLY (`ElementLike`, `LandmarkHost`) so this package needs no DOM lib\n * and stays importable from a node-only build.\n */\n\n/** The landmark tags an address is anchored at, as one CSS selector and as one tag set. */\nexport const LANDMARK_SELECTOR = \"header,nav,footer\";\nconst LANDMARK_TAGS = new Set([\"HEADER\", \"NAV\", \"FOOTER\"]);\n\n/**\n * The THIRD region — a modal, a cookie banner, a pop-up — behind a per-project gate.\n *\n * A `<dialog>` or a `[role=\"dialog\"]` sits at BODY level, outside every landmark, so a banner\n * byte-identical on twelve routes derived twelve copies of itself. It is NOT a stop for\n * `locatorFor`: `region` already names which dialog an element is in, and a second gated rule\n * about where the ancestor chain ends would make the same element's locator differ between a\n * project that derived it as chrome and one that did not.\n */\nexport const DIALOG_SELECTOR = 'dialog,[role=\"dialog\"]';\n\n/**\n * The page's own content. A landmark INSIDE it is the page's, not the site's — under the v2\n * grammar only. @see isChromeLandmark\n */\nexport const MAIN_SELECTOR = 'main,[role=\"main\"]';\n\n/**\n * Which address grammar a page was derived in — the two per-project gates that change what a\n * REGION is. Both off is the original grammar, and `{}` must keep meaning exactly that: every\n * locator stored before a gate existed was spelled in it.\n *\n * `dialogs` — a `<dialog>`/`[role=\"dialog\"]` is a region of its own (the chrome grammar).\n * `landmarks` — landmark grammar v2. @see isChromeLandmark, and `landmarkRegions` for rule (ii).\n */\nexport interface LocatorGrammar {\n dialogs?: boolean;\n landmarks?: boolean;\n}\n\n/**\n * Is this element a landmark that holds SITE chrome — a header, nav or footer that earns a region\n * and a `nav-`/`footer-` key?\n *\n * 🔴 A LANDMARK INSIDE `<main>` IS PAGE COPY. HTML allows a `<nav>` anywhere, and a built page\n * uses one for whatever it likes: a features band's `<nav role=\"tablist\">`, a docs page's\n * prev/next pager in a `<footer>` inside the article. Counted as chrome, the home page's tab list\n * minted nine `nav-` keys that are really the section's copy — keys the Layout's Header section\n * claims by prefix the moment two routes render that band alike, and that componentize reads as\n * chrome everywhere else. The `<main>` is the page saying \"everything in here is mine\", and v2\n * believes it.\n *\n * Gated (`landmarks`), because it moves keys AND regions: a project whose pages were derived\n * with that tab list as `nav#0` holds values under `nav-…` keys, and re-reading them as section\n * copy would strand every one of them.\n *\n * EXCEPT A `<main>` THAT IS THE PAGE SHELL. Plenty of layouts wrap the whole page in it —\n * `<main><Navbar/>{children}<Footer/></main>`, or `role=\"main\"` on the app root — and there the\n * fence would take the site's real masthead and footer away: no region, no `nav-`/`footer-` keys,\n * nothing for the Layout to claim, and a copy of the nav minted into every route. A `<main>` that\n * OPENS with a header/nav and CLOSES with a footer is framing the site, not holding page copy, so\n * its own direct-child landmarks stay chrome. A landmark deeper inside it (a section's tab list)\n * is still page copy, and a `<main>` that only opens with a header (a changelog's title) still\n * fences it.\n */\nexport function isChromeLandmark(\n el: { tagName: string; parentElement: { closest(selectors: string): unknown } | null },\n landmarks: boolean,\n): boolean {\n if (!LANDMARK_TAGS.has(el.tagName)) return false;\n if (!landmarks) return true;\n const fence = el.parentElement?.closest(MAIN_SELECTOR) as ShellCandidate | null | undefined;\n return !fence || ((fence as unknown) === el.parentElement && isPageShell(fence));\n}\n\n/** Tags a framework appends around content that say nothing about the page's shape. */\nconst INERT_TAGS = new Set([\"SCRIPT\", \"STYLE\", \"TEMPLATE\", \"NOSCRIPT\", \"LINK\"]);\ntype ShellCandidate = { children: ArrayLike<{ tagName: string }> };\n\n/** Opens with the masthead (header/nav) and closes with the footer, ignoring inert tags. */\nfunction isPageShell(main: ShellCandidate): boolean {\n const kids = Array.from(main.children).filter((k) => !INERT_TAGS.has(k.tagName));\n const first = kids[0]?.tagName;\n return (first === \"HEADER\" || first === \"NAV\") && kids.length > 1 && kids[kids.length - 1]!.tagName === \"FOOTER\";\n}\n\n/**\n * Best-effort by construction — built-DOM positions do not survive component expansion or\n * conditional rendering — so a consumer that finds no exact match, or finds several, falls back\n * to ambiguity rather than to a guess. The ancestor chain is compared EXACTLY (`atLocator`,\n * annotate-static.ts): a chain that merely contains the stored one is a different element.\n */\nexport interface DerivedLocator {\n /** The landmark it lives in — `header#0`, `nav#1`, `footer#0` — or null for the page body. */\n region: string | null;\n /** Tag names from the nearest landmark (or `<body>`) down to the element's parent. */\n ancestors: string[];\n /** Its index among its parent's element children. */\n siblingIndex: number;\n /**\n * The element's own lower-cased tag name.\n *\n * The cheapest fact that separates two elements a chain-and-index pair calls identical — a\n * `<h2>` and the `<a>` beside it in a rebuilt layout — and the only one a resolver can use to\n * NARROW its candidate list before comparing anything. Absent on locators stored before it\n * existed; a comparer must treat a missing tag as \"matches\".\n */\n tag: string;\n /**\n * The repeater row this value belongs to.\n *\n * On a leaf's field DEFINITION the index is 0 — one definition serves every row — and the\n * brief overrides it with the row it is actually describing (`cards[2].title` → index 2).\n */\n repeat?: { groupKey: string; index: number };\n}\n\n/** The DOM surface `locatorFor` reads. `Element` satisfies it; so does a plain object. */\nexport interface ElementLike {\n tagName: string;\n parentElement: ElementLike | null;\n children: ArrayLike<ElementLike>;\n}\n\n/**\n * `ElementLike` plus the one DOM call the v2 chain needs — whether a landmark sits inside\n * `<main>` (@see isChromeLandmark). `Element` satisfies it. Only the backend derives in v2, so\n * the plain-object surface above stays all the original grammar asks for.\n */\nexport interface LandmarkChainElement extends ElementLike {\n parentElement: LandmarkChainElement | null;\n closest(selectors: string): unknown;\n}\n\n/**\n * The structural address of one element: its ancestor tags and its position among its siblings.\n *\n * Stops at the nearest LANDMARK because that is where a page's structure stops being comparable\n * — a header's internals are the same on every route while the body's are not — and `region`\n * already names which landmark it was.\n *\n * 🔴 UNDER v2 (`landmarks`) THE CHAIN STOPS ONLY AT A CHROME LANDMARK. The stop is only sound\n * because `region` names the landmark it stopped at, and a `<nav>` inside `<main>` names no\n * region under v2. Stopping there anyway threw away the only structure that told two of them\n * apart: two sections' `<nav><a>` both addressed as `{region: null, ancestors: [], 0, a}` — the\n * address of a link sitting directly in `<body>` — where the original grammar said `nav#0` and\n * `nav#1`. So the chain runs on to `<body>` like every other element of the page's copy. An\n * element outside every in-`<main>` landmark stops exactly where it always did, which is what\n * keeps every locator whose region v2 did not move byte-identical. Two landmarks of one shape in\n * two sections of one shape still collide, as two cards always have; every reader refuses an\n * address that names several elements (`atLocator`, the pin replay, `bindElement`).\n */\nexport function locatorFor(el: ElementLike, region: string | null): DerivedLocator;\nexport function locatorFor(el: LandmarkChainElement, region: string | null, landmarks: boolean): DerivedLocator;\nexport function locatorFor(el: ElementLike, region: string | null, landmarks = false): DerivedLocator {\n const ancestors: string[] = [];\n for (\n let parent = el.parentElement;\n // The cast is the overloads' promise: `landmarks` is only ever true for a `LandmarkChainElement`,\n // and `isChromeLandmark` never reads past the tag with it false.\n parent && parent.tagName !== \"BODY\" && !isChromeLandmark(parent as LandmarkChainElement, landmarks);\n parent = parent.parentElement\n ) {\n ancestors.unshift(parent.tagName.toLowerCase());\n }\n const siblings = el.parentElement ? Array.from(el.parentElement.children) : [];\n return {\n region,\n ancestors,\n siblingIndex: Math.max(siblings.indexOf(el), 0),\n tag: el.tagName.toLowerCase(),\n };\n}\n\n/** The DOM surface `landmarkRegions` reads of each element it considers. */\nexport interface LandmarkElement {\n tagName: string;\n parentElement: { closest(selectors: string): unknown } | null;\n matches(selectors: string): boolean;\n}\n\n/**\n * A page's landmark regions: the OUTERMOST `header`/`nav`/`footer` elements, in document order.\n *\n * Outermost, because a `<nav>` inside a `<header>` is one region a visitor sees as one thing —\n * and promoting the two separately would let a site's masthead be half layout, half page.\n *\n * Under the v2 grammar (`landmarks`) regions may NEST, in exactly one way — a dialog inside a\n * landmark is its own region — so a consumer must ask {@link regionOf} which one an element is\n * in, never take the first region that contains it.\n */\nexport function landmarkRegions<E extends LandmarkElement>(\n doc: { querySelectorAll(selectors: string): Iterable<E> },\n /**\n * Count a dialog as a region too — the per-project chrome grammar.\n *\n * OFF by default, and not merely for symmetry: a region name is part of every field's LOCATOR,\n * and a project whose stored locators say `region: null` for a modal's copy must keep being\n * read the same way.\n */\n dialogs = false,\n /**\n * Landmark grammar v2 — the per-project `landmarks` gate. Two rules change, both OFF by default\n * for the reason `dialogs` is:\n *\n * (i) a landmark inside `<main>`/`[role=\"main\"]` is no region. @see isChromeLandmark\n * (ii) a dialog inside a landmark is its OWN region. The auth modals a masthead carries are\n * the commonest dialogs on the web, and outermost-only folded all three into `header#0`:\n * their copy promoted as the header's, and the header could only promote when every\n * route's modals did too. A dialog still folds into an enclosing DIALOG, and a landmark\n * into anything enclosing it — nothing else nests.\n */\n landmarks = false,\n): { slot: string; el: E }[] {\n const counts = new Map<string, number>();\n const out: { slot: string; el: E }[] = [];\n const selector = dialogs ? `${LANDMARK_SELECTOR},${DIALOG_SELECTOR}` : LANDMARK_SELECTOR;\n for (const el of doc.querySelectorAll(selector)) {\n if (!landmarks) {\n if (el.parentElement?.closest(selector)) continue;\n } else if (LANDMARK_TAGS.has(el.tagName)) {\n // A landmark outside `<main>` has no ancestor inside it either, so anything enclosing it is\n // a region — the outermost rule, unchanged.\n if (!isChromeLandmark(el, true) || el.parentElement?.closest(selector)) continue;\n } else if (el.parentElement?.closest(DIALOG_SELECTOR)) {\n continue;\n }\n // The NAME, not the tag: a `[role=\"dialog\"]` is usually a `<div>`, and slotting it as\n // `div#0` would make one site's modal and another's wrapper the same kind of region.\n const name = !LANDMARK_TAGS.has(el.tagName) && el.matches(DIALOG_SELECTOR)\n ? \"dialog\"\n : el.tagName.toLowerCase();\n const n = counts.get(name) ?? 0;\n counts.set(name, n + 1);\n out.push({ slot: `${name}#${n}`, el });\n }\n return out;\n}\n\n/**\n * The region an element is in: the INNERMOST region that contains it, or null for the page body.\n *\n * The last match rather than the first, because regions are in document order and an enclosing\n * region opens before the one nested inside it (v2's dialog in a header). Under every other\n * grammar regions are disjoint and first and last are the same region — which is what keeps a\n * resolver built on this byte-identical for every locator stored before v2.\n */\nexport function regionOf<E extends { contains(other: unknown): boolean }>(\n regions: readonly { slot: string; el: E }[],\n el: unknown,\n): string | null {\n let slot: string | null = null;\n for (const r of regions) if (r.el.contains(el)) slot = r.slot;\n return slot;\n}\n","/**\n * `<BcmsSections>`: which of a page's sections render, in what order, and which block each one is.\n *\n * A code-built page passes every section it can draw as a named SLOT; the CMS page's block list\n * says the order. This is the one place that joins the two, shared by @bettercms-ai/astro and\n * @bettercms-ai/next so a site renders the same list on either. The backend reads a placement's\n * group through the same `placementBindOf`, so a slot's name is the id the platform measured.\n *\n * Pure: no DOM, no framework, no I/O.\n */\n\n/**\n * The tag-shaped heads the derive lane mints keys from (`h1-welcome`, `p-we-build-things`,\n * `img-logo`, `list-benefits`, `a-contact`). A key whose head is one of these names an ELEMENT,\n * not a section family, so it has no group root.\n *\n * 🔴 NOT ONLY TEXT TAGS. Derive also keys a text leaf found by SHAPE by its own tag (`span-dismiss`,\n * `div-samantha-ruiz`, `time-…`) and a media leaf by its kind (`icon-icon`, `bg-…`). Missing here,\n * each of those heads read as a FAMILY: an unmarked announcement bar became components called\n * \"Span\" and \"Icon\".\n */\nexport const TAG_HEADS: ReadonlySet<string> = new Set([\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\",\n \"p\", \"a\", \"img\", \"li\", \"list\", \"blockquote\", \"figcaption\", \"button\", \"summary\", \"dt\", \"dd\", \"th\", \"td\",\n \"pre\", \"label\", \"span\", \"div\", \"time\", \"strong\", \"em\", \"small\", \"b\", \"i\", \"code\",\n \"icon\", \"bg\",\n]);\n\n/** The top-level field key a path belongs to: `hero.title` → `hero`, `faq[0].q` → `faq`. */\nexport const topFieldKeyOf = (path: string): string => path.split(/[.[]/, 1)[0] ?? path;\n\n/**\n * The GROUP a top-level field key belongs to, and whether that group has a real root.\n *\n * Two shapes are groups: a repeater the derive lane already folded (`group-*`), and a family prefix\n * on an authored or renamed key (`hero-title`, `hero.title` → `hero`). Everything else is a bare\n * element key with no family, and grouping those by their tag would mint one section per heading.\n */\nexport function fieldGroupOf(topKey: string, flat = false): { groupKey: string; rooted: boolean } {\n if (topKey.startsWith(\"group-\")) return { groupKey: topKey, rooted: true };\n // A FLAT camelCase key names its family by its first word (`heroTitle`, `heroSubtitle` → `hero`),\n // the way hand-authored starter schemas spell them. Flat only: a nested `featureGrid.items` was\n // always its own group, and re-keying it would move that section's slug and identity.\n const camel = flat ? /^([a-z][a-z0-9]*)[A-Z]/.exec(topKey)?.[1] : undefined;\n if (camel) return TAG_HEADS.has(camel) ? { groupKey: topKey, rooted: false } : { groupKey: camel, rooted: true };\n // 🔴 `-` OR `_`. The importer mints `hero-title`, and every tool text teaches an agent to write\n // `hero_title`: both form a family. `||`, not `??`: a key that STARTS with a separator has an\n // empty head, and an empty group key would fold every such key into one section.\n const head = topKey.split(/[-_]/, 1)[0] || topKey;\n if (TAG_HEADS.has(head)) return { groupKey: topKey, rooted: false };\n return { groupKey: head, rooted: true };\n}\n\n/**\n * The GROUP a placement renders, or null if this block is not a placement of the site's own code.\n *\n * Two spellings: `props.bind` says the group outright; `props.source` (`{ propKey: \"<page path>\" }`)\n * is what is left once the copy moved onto the instance, and the group is derived from it. A\n * section added from the library carries neither, which is how it is told apart: the site's code\n * has nothing to draw it with.\n */\nexport function placementBindOf(block: unknown): string | null {\n if (!block || typeof block !== \"object\" || (block as { type?: unknown }).type !== \"component\") return null;\n const props = (block as { props?: { bind?: unknown; source?: unknown } }).props;\n const bind = props?.bind;\n if (typeof bind === \"string\" && bind) return bind;\n const source = props?.source;\n if (!source || typeof source !== \"object\") return null;\n // The first path that names a FAMILY: a lone `eyebrow` placed in `hero` is not the placement's group.\n const groups = Object.values(source as Record<string, unknown>)\n .filter((path): path is string => typeof path === \"string\" && path.length > 0)\n .map((path) => ({ top: topFieldKeyOf(path), group: fieldGroupOf(topFieldKeyOf(path), path === topFieldKeyOf(path)).groupKey }));\n return (groups.find((g) => g.group !== g.top) ?? groups[0])?.group ?? null;\n}\n\n/**\n * A slot the CMS was not known to hold when the page was wrapped is spelled `code:<bind>`.\n * It matches a block bound to `<bind>` like the bare spelling does; it differs only when no block\n * names it: a `code:` slot then renders where the source has it, a bare one is a removed section.\n */\nexport const CODE_SLOT_PREFIX = \"code:\";\n\n/** The bind a slot answers to: `code:hero` and `hero` → `hero`. */\nexport const slotBindOf = (slot: string): string => (slot.startsWith(CODE_SLOT_PREFIX) ? slot.slice(CODE_SLOT_PREFIX.length) : slot);\n\n/** One thing `<BcmsSections>` renders: the page's own slot (with its block, when one names it), or a CMS block. */\nexport type SectionPlanItem<B> = { slot: string; block: B | null } | { slot: null; block: B };\n\n/**\n * The render order of a page: its slots (in source order) joined with its block list (in CMS order).\n *\n * - No block list (a build with no snapshot, the API down): every slot, in source order, no block.\n * - A block bound to a slot renders that slot at the block's position. Each slot renders once: a\n * second block of the same bind is skipped, as is a bound block the page passed no slot for\n * (the site draws that one somewhere this list cannot reach, so drawing it again would double it).\n * - A block with no bind (a section added from the library) is the CMS's own to draw.\n * - A slot no block names: a `code:` slot always renders, after the source slot before it. A bare\n * slot renders the same way while the list names none of this page's slots (another project's\n * snapshot, a page never placed); once it names one, an unnamed bare slot is a removed section.\n */\nexport function planSections<B>(slots: readonly string[], blocks: readonly B[] | null | undefined): SectionPlanItem<B>[] {\n if (!Array.isArray(blocks)) return slots.map((slot) => ({ slot, block: null }));\n const byBind = new Map<string, string>();\n for (const slot of slots) if (!byBind.has(slotBindOf(slot))) byBind.set(slotBindOf(slot), slot);\n\n const out: SectionPlanItem<B>[] = [];\n const named = new Set<string>();\n for (const block of blocks as readonly B[]) {\n const bind = placementBindOf(block);\n if (bind === null) {\n out.push({ slot: null, block });\n continue;\n }\n const slot = byBind.get(bind);\n if (slot === undefined || named.has(slot)) continue;\n named.add(slot);\n out.push({ slot, block });\n }\n\n const held = named.size > 0;\n slots.forEach((slot, n) => {\n if (named.has(slot) || out.some((item) => item.slot === slot)) return;\n if (held && !slot.startsWith(CODE_SLOT_PREFIX)) return;\n // After the nearest source slot before it that renders; first when none does.\n let at = 0;\n for (let before = n - 1; before >= 0; before--) {\n const found = out.findIndex((item) => item.slot === slots[before]);\n if (found >= 0) {\n at = found + 1;\n break;\n }\n }\n out.splice(at, 0, { slot, block: null });\n });\n return out;\n}\n"],"mappings":";AA4HA,IAAM,iBAAiB;AAOhB,SAAS,gBACd,OACuF;AACvF,MAAI,SAAS,KAAM,QAAO,EAAE,QAAQ,KAAK;AACzC,MAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO,EAAE,OAAO,iBAAiB;AACxF,QAAM,MAAwB,CAAC;AAC/B,aAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAgC,GAAG;AACzE,QAAI,QAAQ,UAAU,QAAQ,QAAS,QAAO,EAAE,OAAO,iBAAiB;AACxE,QAAI,OAAO,KAAM;AACjB,UAAM,KAAK,OAAO,QAAQ,YAAY,eAAe,KAAK,GAAG,IAAI,KAAK,MAAM,GAAG,IAAI;AAEnF,UAAM,MAAM,OAAO,OAAO,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC;AAC3C,QAAI,OAAO,MAAM,EAAE,KAAK,IAAI,KAAK,KAAK,IAAI,OAAO,OAAO,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,OAAO,OAAO,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,WAAW,MAAM,KAAK;AAC1I,aAAO,EAAE,OAAO,iBAAiB;AAAA,IACnC;AACA,QAAI,GAAG,IAAI,GAAG,IAAI,KAAK,EAAE,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,EACvD;AAEA,MAAI,IAAI,QAAQ,IAAI,SAAS,IAAI,QAAQ,IAAI,MAAO,QAAO,EAAE,OAAO,kBAAkB;AACtF,SAAO,EAAE,QAAQ,IAAI,QAAQ,IAAI,QAAQ,MAAM,KAAK;AACtD;AAUO,SAAS,YAAY,MAAe,KAAiC;AAC1E,QAAM,IAAI,QAAQ,OAAO,SAAS,WAAY,KAA8B,SAAS;AACrF,MAAI,CAAC,KAAK,OAAO,MAAM,SAAU,QAAO;AACxC,QAAM,KAAK,OAAO,QAAQ,WAAW,MAAM,IAAI,QAAQ;AACvD,QAAM,EAAE,MAAM,MAAM,IAAI;AACxB,QAAM,QAAQ,OAAO,SAAS,WAAW,KAAK,MAAM,IAAI,IAAI;AAC5D,QAAM,MAAM,OAAO,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI;AAC5D,MAAI,CAAC,OAAO,MAAM,GAAG,KAAK,MAAM,IAAK,QAAO;AAC5C,MAAI,CAAC,OAAO,MAAM,KAAK,KAAK,KAAK,MAAO,QAAO;AAC/C,SAAO;AACT;AAGO,IAAM,WAAW,CAAC,MAAe,QAAgC,YAAY,MAAM,GAAG,MAAM;AAO5F,SAAS,iBAAiB,MAAwB;AACvD,QAAM,QAAQ,QAAQ,OAAO,SAAS,WAAY,KAA6B,QAAQ;AACvF,QAAM,MAAM,SAAS,OAAO,UAAU,WAAY,MAA+B,SAAS;AAC1F,SAAO,MAAM,QAAQ,GAAG,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,SAAS,SAAS;AACzG;AAGA,SAAS,QAAW,MAAW,IAAyB;AACtD,MAAI,UAAU;AACd,QAAM,MAAM,KAAK,IAAI,CAAC,SAAS;AAC7B,UAAM,OAAO,GAAG,IAAI;AACpB,QAAI,SAAS,KAAM,WAAU;AAC7B,WAAO;AAAA,EACT,CAAC;AACD,SAAO,UAAU,MAAM;AACzB;AAGA,SAAS,oBAAmE,OAAU,KAAuB;AAC3G,QAAM,IAAK,MAAM,SAAS,CAAC;AAC3B,QAAM,MAAM,MAAM,SAAS,YAAY,aAAa,MAAM,SAAS,YAAY,YAAY,MAAM,SAAS,WAAW,WAAW,MAAM,SAAS,SAAS,SAAS;AACjK,MAAI,CAAC,OAAO,CAAC,MAAM,QAAQ,EAAE,GAAG,CAAC,EAAG,QAAO;AAC3C,QAAM,OAAO,EAAE,GAAG;AAClB,QAAM,OACJ,QAAQ,aACJ,cAAc,MAAM,GAAG,IACvB,QAAQ,YACN,QAAQ,MAAM,CAAC,WAAW,cAAc,QAAQ,GAAG,CAAC;AAAA;AAAA,IAEpD,QAAQ,MAAM,CAAC,QAAQ;AACrB,YAAM,WAAY,KAAuC;AACzD,YAAM,QAAQ,cAAc,UAAU,GAAG;AACzC,aAAO,UAAU,WAAW,MAAM,EAAE,GAAI,KAAgB,UAAU,MAAM;AAAA,IAC1E,CAAC;AAAA;AACT,SAAO,SAAS,OAAO,QAAQ,EAAE,GAAG,OAAO,OAAO,EAAE,GAAG,GAAG,CAAC,GAAG,GAAG,KAAK,EAAE;AAC1E;AAWO,SAAS,cAAiB,QAAW,KAAuB;AACjE,MAAI,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO;AACnC,QAAM,QAAS,OAAqB,OAAO,CAAC,UAAU,SAAS,OAAO,GAAG,KAAK,CAAC,iBAAiB,KAAK,CAAC;AACtG,QAAM,SAAS;AAAA,IAAQ;AAAA,IAAO,CAAC,UAC7B,SAAS,OAAO,UAAU,WAAW,oBAAoB,OAA8C,GAAG,IAAI;AAAA,EAChH;AACA,SAAQ,MAAM,WAAW,OAAO,UAAU,WAAW,QAAQ,SAAS;AACxE;AA0gBO,SAAS,QAAQ,OAAuC;AAC7D,SACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAQ,MAAkC,MAAM,MAAM;AAE1D;AAUO,SAAS,aAAa,OAAkC;AAC7D,MAAI,QAAQ,KAAK,EAAG,QAAO,MAAM;AACjC,SAAO;AACT;;;ACzuBA,IAAM,SAAS,CAAC,KAAK,KAAK,KAAK,QAAU,UAAU,KAAK,QAAQ;AAEhE,IAAM,gBAAgB;AAEtB,IAAM,cAAc;AAGpB,IAAM,OAAO;AACb,IAAM,SAAS,IAAI,OAAO,oCAA4B,IAAI,wDAAmD,GAAG;AAEhH,IAAM,SAAS;AAEf,IAAM,iBAAiB,CAAC,UAA0B;AAChD,QAAM,OAAO,MAAM,QAAQ,CAAC,EAAE,QAAQ,OAAO,EAAE;AAC/C,SAAO,KAAK,SAAS,KAAK,QAAQ,GAAG,IAAI;AAC3C;AAGO,SAAS,iBAAiB,KAAiC;AAChE,QAAM,IAAI,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,IAAK,MAAkC,CAAC;AACtG,QAAM,OAAO,CAAC,GAAY,QAAqC,OAAO,MAAM,YAAY,EAAE,UAAU,OAAO,CAAC,WAAC,WAAO,GAAC,EAAC,KAAK,CAAC,IAAI,IAAI;AACpI,QAAM,SAAS,KAAK,EAAE,QAAQ,CAAC;AAC/B,QAAM,SAAS,KAAK,EAAE,QAAQ,EAAE;AAChC,QAAM,QAAQ,OAAO,EAAE,UAAU,YAAa,OAA6B,SAAS,EAAE,KAAK,IAAI,EAAE,QAAQ;AACzG,QAAM,UAAU,EAAE,YAAY,MAAM,MAAM;AAC1C,QAAM,WAAW,OAAO,EAAE,aAAa,YAAY,OAAO,UAAU,EAAE,QAAQ,KAAK,EAAE,WAAW,KAAK,EAAE,YAAY,IAAI,EAAE,WAAW;AACpI,SAAO;AAAA,IACL,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA;AAAA,IAE3B,GAAI,SAAS,WAAW,WAAW,OAAO,EAAE,MAAM,IAAI,CAAC;AAAA,IACvD,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,EACjC;AACF;AAGO,SAAS,aAAa,OAAe,SAA4B,CAAC,GAAW;AAClF,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACjE,QAAM,SAAS,KAAK,IAAI,OAAO,YAAY,GAAG,KAAK,IAAI,GAAG,eAAe,KAAK,CAAC,CAAC;AAChF,QAAM,CAAC,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,EAAE,QAAQ,MAAM,EAAE,MAAM,GAAG;AAC7D,QAAM,UAAU,OAAO,QAAQ,IAAI,QAAQ,yBAAyB,OAAO,KAAK,IAAI;AACpF,SAAO,GAAG,QAAQ,IAAI,MAAM,EAAE,GAAG,OAAO,UAAU,EAAE,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,WAAW,GAAG,GAAG,IAAI,KAAK,EAAE,GAAG,OAAO,UAAU,EAAE;AACtI;AAcO,SAAS,gBAAgB,MAAc,OAAoD,CAAC,GAAwD;AACzJ,MAAI,OAAO,SAAS,YAAY,KAAK,WAAW,KAAK,KAAK,SAAS,GAAI,QAAO;AAC9E,QAAM,SAAS,KAAK,KAAK,IAAI;AAC7B,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,QAAQ,OAAO;AACrB,QAAM,OAAO,uCAAuC,KAAK,KAAK,MAAM,KAAK,CAAC,EAAG,CAAC;AAC9E,QAAM,SAAS,KAAK,MAAM,GAAG,KAAK;AAClC,QAAM,SAAS,KAAK,MAAM,QAAQ,KAAK,MAAM;AAC7C,MAAI,KAAK,KAAK,MAAM,KAAK,CAAC,OAAO,KAAK,MAAM,KAAK,CAAC,OAAO,KAAK,MAAM,EAAG,QAAO;AAC9E,MAAI,KAAK,YAAY,UAAU,UAAU,CAAC,gBAAgB,KAAK,IAAI,GAAI,QAAO;AAE9E,MAAI,SAAS,KAAK,MAAM,MAAM,QAAQ,KAAK,MAAM,EAAG,QAAO;AAE3D,QAAM,YAAY,cAAc,KAAK,KAAK,QAAQ,EAAE;AACpD,QAAM,QAAQ,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC;AACnD,QAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;AAChC,MAAI;AACJ,MAAI;AACJ,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,MAAI,MAAM,WAAW,GAAG;AAEtB,UAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,QAAK,SAAS,OAAO,SAAS,OAAQ,MAAM,OAAO,CAAC,MAAM,MAAM,IAAI,EAAE,WAAW,EAAG,QAAO;AAC3F,cAAU;AACV,YAAQ,MAAM,KAAK,CAAC,MAAM,MAAM,IAAI;AAAA,EACtC,WAAW,MAAM,WAAW,GAAG;AAC7B,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,OAAO,KAAK,MAAM,KAAK,YAAY,IAAI,IAAI,CAAC;AAClD,UAAM,OAAO,MAAM,WAAW,MAAM,SAAS,OAAO,SAAS;AAE7D,UAAM,YAAY,SAAS,KAAK,WAAW,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK,KAAK,KAAK,IAAI,MAAM,SAAS,MAAM,CAAC,YAAY;AAC1H,QAAI,UAAW,WAAU;AAAA,QACpB,SAAQ;AAAA,EACf;AACA,MAAK,UAAU,UAAa,UAAU,WAAa,SAAS,CAAE,OAA6B,SAAS,KAAK,EAAI,QAAO;AACpH,QAAM,CAAC,SAAS,OAAO,EAAE,IAAI,UAAW,KAAK,MAAM,OAAO,IAA0B,CAAC,IAAI;AACzF,QAAM,QAAQ,QAAQ,QAAQ,MAAM,KAAK,IAAI,CAAC,OAAO;AACrD,MAAI,UAAU,MAAM,SAAS,KAAK,CAAC,iBAAiB,KAAK,MAAM,CAAC,CAAE,KAAK,MAAM,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,KAAK,CAAC,CAAC,GAAI,QAAO;AAC/H,QAAM,MAAM,MAAM,KAAK,EAAE;AACzB,MAAI,CAAC,QAAQ,KAAK,GAAG,KAAM,IAAI,SAAS,KAAK,IAAI,WAAW,GAAG,KAAM,IAAI,SAAS,KAAK,SAAS,MAAO,WAAW,CAAC,QAAQ,KAAK,IAAI,EAAI,QAAO;AAE/I,QAAM,QAAQ,OAAO,OAAO,GAAG,GAAG,IAAI,IAAI,KAAK,GAAG;AAGlD,MAAI,CAAC,SAAS,CAAC,KAAK,WAAW,IAAI,SAAS,EAAG,SAAQ,YAAY,KAAK,KAAK,QAAQ,EAAE,IAAI,SAAW,YAAY,MAAM;AAExH,MAAI,CAAC,YAAY,UAAU,OAAQ,aAAa,CAAC,KAAK,SAAW,WAAU;AAC3E,MAAI,WAAW,WAAW,KAAM,SAAQ;AACxC,QAAM,SAA4B;AAAA,IAChC,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,YAAY,MAAM,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrC,GAAI,OAAO,EAAE,UAAU,KAAK,OAAO,IAAI,CAAC;AAAA,EAC1C;AACA,SAAO,OAAO,SAAS,KAAK,KAAK,KAAK,UAAU,KAAK,aAAa,OAAO,MAAM,MAAM,OAAO,EAAE,OAAO,OAAO,IAAI;AAClH;;;ACpEO,IAAM,iBAAsE;AAAA,EACjF,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,CAAC;AAAA,EACxC,MAAM,CAAC,EAAE,MAAM,QAAQ,MAAM,WAAW,CAAC;AAAA,EACzC,UAAU,CAAC,EAAE,MAAM,QAAQ,MAAM,WAAW,CAAC;AAAA,EAC7C,OAAO;AAAA,IACL,EAAE,MAAM,OAAO,MAAM,QAAQ;AAAA,IAC7B,EAAE,MAAM,WAAW,MAAM,OAAO;AAAA,IAChC,EAAE,MAAM,OAAO,MAAM,QAAQ,MAAM,MAAM;AAAA,EAC3C;AAAA,EACA,QAAQ;AAAA,IACN,EAAE,MAAM,QAAQ,MAAM,OAAO;AAAA,IAC7B,EAAE,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO;AAAA,EAC5C;AAAA,EACA,OAAO;AAAA,IACL,EAAE,MAAM,OAAO,MAAM,OAAO,MAAM,MAAM;AAAA,IACxC,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM,SAAS;AAAA,EAChD;AAAA,EACA,QAAQ;AAAA,IACN,EAAE,MAAM,YAAY,MAAM,QAAQ;AAAA,IAClC,EAAE,MAAM,YAAY,MAAM,QAAQ,MAAM,MAAM;AAAA,IAC9C,EAAE,MAAM,iBAAiB,MAAM,OAAO;AAAA,IACtC,EAAE,MAAM,gBAAgB,MAAM,OAAO,MAAM,OAAO;AAAA,IAClD,EAAE,MAAM,YAAY,MAAM,OAAO;AAAA,IACjC,EAAE,MAAM,YAAY,MAAM,OAAO,MAAM,OAAO;AAAA,EAChD;AAAA,EACA,QAAQ;AAAA,IACN,EAAE,MAAM,aAAa,MAAM,OAAO;AAAA,IAClC,EAAE,MAAM,qBAAqB,MAAM,OAAO;AAAA,IAC1C,EAAE,MAAM,2BAA2B,MAAM,OAAO;AAAA,IAChD,EAAE,MAAM,0BAA0B,MAAM,OAAO,MAAM,OAAO;AAAA,EAC9D;AAAA,EACA,MAAM,CAAC,EAAE,MAAM,gBAAgB,MAAM,OAAO,CAAC;AAC/C;AAQA,IAAM,WAAW,CAAC,MAChB,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC;AAgBlD,SAAS,SAAS,MAAe,MAAuB;AAC7D,MAAI,SAAkB;AACtB,aAAW,WAAW,KAAK,MAAM,GAAG,GAAG;AACrC,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,MAAM,QAAQ,QAAQ,YAAY,EAAE;AAC1C,QAAI,KAAK;AACP,UAAI,CAAC,SAAS,MAAM,EAAG,QAAO;AAC9B,eAAS,OAAO,GAAG;AAAA,IACrB;AACA,eAAW,SAAS,QAAQ,SAAS,YAAY,GAAG;AAClD,UAAI,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO;AACnC,eAAS,OAAO,OAAO,MAAM,CAAC,CAAC,CAAC;AAAA,IAClC;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,eAAe,SAAuB,OAAgB,MAAiC;AAC9F,QAAM,KAAK,KAAK,QAAQ,IAAI;AAC5B,MAAI,KAAK,EAAG,QAAO,CAAC,EAAE,GAAG,SAAS,KAAK,CAAC;AAExC,QAAM,OAAO,KAAK,MAAM,GAAG,EAAE;AAC7B,QAAM,OAAO,KAAK,MAAM,KAAK,CAAC;AAC9B,QAAM,QAAQ,SAAS,OAAO,IAAI;AAClC,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AAEnC,SAAO,MAAM;AAAA,IAAQ,CAAC,OAAO,UAC3B,eAAe,SAAS,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,IAAI,EAAE;AAAA,EAC3D;AACF;AAiBO,SAAS,oBAAoB,OAAwC;AAC1E,QAAM,WAAW,eAAe,MAAM,IAAI;AAC1C,MAAI,CAAC,SAAU,QAAO,CAAC;AACvB,QAAM,QAAS,MAA8B;AAC7C,MAAI,CAAC,SAAS,KAAK,EAAG,QAAO,CAAC;AAC9B,SAAO,SACJ,QAAQ,CAAC,YAAY,eAAe,SAAS,OAAO,QAAQ,IAAI,CAAC,EACjE,OAAO,CAAC,YAAY,SAAS,OAAO,QAAQ,IAAI,MAAM,MAAS;AACpE;AAGO,SAAS,qBACd,SACQ;AACR,SAAO,QAAQ,IAAI,CAAC,MAAM,GAAG,EAAE,OAAO,IAAI,EAAE,IAAI,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,GAAG;AACxE;AAGO,SAAS,oBACd,OACwD;AACxD,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,SAAO,MACJ,MAAM,GAAG,EACT,IAAI,CAAC,UAAU,MAAM,MAAM,GAAG,CAAC,EAC/B,OAAO,CAAC,UAAkD,MAAM,WAAW,KAAK,MAAM,MAAM,OAAO,CAAC,EACpG,IAAI,CAAC,CAAC,SAAS,MAAM,IAAI,OAAO,EAAE,SAAS,MAAM,KAAK,EAAE;AAC7D;AAiCO,SAAS,uBAAuB,MAA6C;AAClF,MAAI,CAAC,MAAM,OAAO,CAAC,KAAK,QAAQ,QAAS,QAAO;AAChD,SAAO,GAAG,KAAK,OAAO,OAAO,KAAK,OAAO,KAAK,OAAO,QAAQ,EAAE,EAAE,QAAQ,YAAY,EAAE,CAAC;AAC1F;AAOO,SAAS,2BACd,iBACA,OACA,OACqB;AACrB,QAAM,WAAW,QAAQ,GAAG,KAAK,IAAI,eAAe,KAAK;AACzD,QAAM,MAAM,oBAAI,IAAoB;AACpC,aAAW,QAAQ,SAAS,CAAC,GAAG;AAC9B,QAAI,CAAC,MAAM,OAAO,CAAC,KAAK,QAAQ,QAAS;AACzC,UAAM,OAAO,uBAAuB,IAAI;AAGxC,QAAI,CAAC,IAAI,IAAI,IAAI,EAAG,KAAI,IAAI,MAAM,GAAG,QAAQ,eAAe,KAAK,GAAG,EAAE;AAAA,EACxE;AACA,SAAO;AACT;;;ACjQO,IAAM,uBAAuB;AAAA,EAClC;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACO,IAAM,oBAAoB,CAAC,cAAc,WAAW,WAAW,WAAW,UAAU;AAMpF,IAAM,sBAAsB,qBAAqB;AAAA,EACtD,CAAC,MAAoE,MAAM;AAC7E;AAEA,IAAM,iBAAqE;AAAA,EACzE,sBAAsB;AAAA,EACtB,wBAAwB;AAAA,EACxB,uBAAuB;AAAA;AAAA,EAEvB,wBAAwB;AAAA,EACxB,uBAAuB;AAAA,EACvB,wBAAwB;AAAA,EACxB,6BAA6B;AAAA,EAC7B,cAAc;AAAA,EACd,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AACd;AAMO,IAAM,oBAAoB,CAAC,GAAG,mBAAmB,GAAG,mBAAmB;AAGvE,IAAM,oBAAoB;AAM1B,SAAS,aAAa,OAAwB;AACnD,QAAM,MAAM,cAAc,KAAK;AAC/B,MAAI,CAAC,OAAO,CAAE,oBAA0C,SAAS,KAAe,EAAG,QAAO;AAC1F,SAAO,OAAO,iBAAiB,MAAM,GAAG;AAC1C;AAQO,SAAS,iBAAiB,OAAyC;AACxE,QAAM,OAAO,MAAM,aAAa,UAAa,MAAM,gBAAgB,UAAa,OAAO,MAAM,eAAe,YAAY,OAAO,MAAM,kBAAkB;AACvJ,SAAO,QAAQ,MAAM,eAAe,UAAa,OAAO,MAAM,iBAAiB,YAAY,MAAM,aAAa;AAChH;AAGO,SAAS,cAAc,OAAwB;AACpD,QAAM,KAAK,OAAO,UAAU,WAAW,eAAe,KAA0B,IAAI;AACpF,SAAO,KAAK,cAAc,KAAK,IAAI,EAAE,MAAM;AAC7C;;;ACrEA,IAAM,WAAmC,EAAE,MAAM,KAAK,IAAI,OAAO,IAAI,OAAO,IAAI,QAAQ,IAAI,QAAQ,IAAI,OAAO;AAG/G,IAAM,gBAAwC;AAAA,EAC5C,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;AACA,IAAM,SAAiC,EAAE,QAAQ,KAAK,QAAQ,KAAK,UAAU,KAAK,MAAM,IAAI;AAC5F,IAAM,YAAoC,EAAE,MAAM,KAAK,IAAI,OAAO,IAAI,OAAO,IAAI,QAAQ,MAAM,SAAS;AAOjG,IAAM,gBAAgB,CAAC,QAAQ,QAAQ,OAAO,OAAO,KAAK;AAE1D,IAAM,qBAAqB;AAC3B,SAAS,cAAc,OAA4H;AACxJ,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,WAAW,YAAY,CAAE,cAAoC,SAAS,EAAE,MAAM,EAAG,QAAO;AACrG,QAAM,YAAa,OAAO,EAAE,WAAW,YAAY,UAAU,EAAE,MAAM,KAAK,QAAU,OAAO,EAAE,aAAa,YAAY,OAAO,SAAS,EAAE,QAAQ;AAChJ,SAAO;AAAA;AAAA;AAAA,IAGL,SAAS;AAAA,IACT,OAAO;AAAA,IACP,aAAa,EAAE,OAAO,QAAQ,KAAK,KAAK;AAAA,IACxC,WAAW;AAAA,IACX,GAAI,YAAY,CAAC,IAAI,EAAE,cAAc,mBAAmB;AAAA,EAC1D;AACF;AACA,IAAM,YAAoC,EAAE,OAAO,WAAW,OAAO,WAAW,OAAO,WAAW,SAAS,WAAW,SAAS,WAAW,QAAQ,UAAU;AAK5J,IAAM,QAAoF;AAAA,EACxF,OAAO,EAAE,aAAa,SAAS,YAAY,WAAW,OAAO,UAAU;AAAA,EACvE,MAAM,EAAE,aAAa,QAAQ,YAAY,WAAW,OAAO,UAAU;AACvE;AACA,IAAM,SAAiC;AAAA,EACrC,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AACR;AAGA,IAAM,cAAsC,EAAE,SAAS,WAAW,OAAO,UAAU;AAInF,IAAM,cAAsE;AAAA,EAC1E,MAAM,EAAE,aAAa,QAAQ,OAAO,UAAU;AAAA,EAC9C,QAAQ,EAAE,aAAa,kCAAkC,OAAO,gCAAgC;AAClG;AACA,IAAM,YAAoC,EAAE,KAAK,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,IAAI,QAAQ,OAAO,OAAO;AAC/G,IAAM,aAAqC;AAAA,EACzC,KAAK;AAAA,EACL,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,IAAI;AACN;AACA,IAAM,WAAW;AAEjB,IAAM,mBAA2C,EAAE,QAAQ,SAAS,SAAS,UAAU,MAAM,SAAS;AAO/F,IAAM,cAAc,EAAE,QAAQ,KAAK,QAAQ,KAAK;AAShD,IAAM,iBACX,oBAAoB,YAAY,MAAM,2EAClB,YAAY,SAAS,CAAC,sBAAsB,YAAY,MAAM,2EAC9D,YAAY,SAAS,CAAC;AAQrC,SAAS,WAAW,OAAwB;AACjD,QAAM,MAAM,SAAS,OAAO,UAAU,WAAY,MAA+B,SAAS;AAC1F,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO;AAChC,QAAM,KAAM,CAAC,UAAU,UAAU,SAAS,EAAY,OAAO,CAAC,MAAM,IAAI,SAAS,CAAC,CAAC;AACnF,SAAO,GAAG,WAAW,IAAI,KAAK,GAAG,KAAK,GAAG;AAC3C;AAGO,SAAS,WAAW,QAA0B;AACnD,MAAI,QAAQ;AAEZ,OAAK,UAAU,UAAU,MAAM,CAAC,GAAG,MAAM;AACvC,QAAI,MAAM,YAAY,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAG,SAAQ;AACzD,WAAO;AAAA,EACT,CAAC;AACD,SAAO;AACT;AAEA,IAAM,MAAM;AAEZ,IAAM,QAAQ,CAAC,GAAW,IAAY,OAAe,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC;AAEjF,IAAM,MAAM,CAAI,KAAwB,QACtC,OAAO,QAAQ,YAAY,OAAO,UAAU,eAAe,KAAK,KAAK,GAAG,IAAI,IAAI,GAAG,IAAI;AAQlF,SAAS,WAAW,KAAsB;AAC/C,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAM,MAAM,IAAI,KAAK;AACrB,MAAI,CAAC,OAAO,IAAI,SAAS,IAAM,QAAO;AACtC,MAAI,eAAe,KAAK,GAAG,EAAG,QAAO;AACrC,MAAI,IAAI,WAAW,IAAI,EAAG,QAAO;AACjC,MAAI,IAAI,WAAW,GAAG,EAAG,QAAO;AAChC,SAAO,gBAAgB,KAAK,GAAG,IAAI,MAAM;AAC3C;AAGO,SAAS,gBAAgB,OAA4E;AAC1G,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,IAAI;AACV,QAAM,MAAuC,CAAC;AAC9C,MAAI,EAAE,YAAY,SAAS,EAAE,QAAQ,KAAK,MAAM;AAAE,QAAI,aAAa,SAAS,EAAE,QAAQ;AAAI,QAAI,gBAAgB,SAAS,EAAE,QAAQ;AAAA,EAAI;AACrI,MAAI,EAAE,YAAY,SAAS,EAAE,QAAQ,KAAK,MAAM;AAAE,QAAI,cAAc,SAAS,EAAE,QAAQ;AAAI,QAAI,eAAe,SAAS,EAAE,QAAQ;AAAA,EAAI;AAErI,QAAM,MAAM,cAAc,EAAE,QAAQ;AACpC,QAAM,SAAU,oBAA0C,SAAS,EAAE,eAAe,EAAE,IAAI,cAAc,EAAE,WAAW,IAAI;AACzH,QAAM,QAAQ,aAAa,EAAE,UAAU;AACvC,QAAM,aAAa,EAAE,aAAa;AAClC,MAAI,OAAO,CAAC,WAAY,KAAI,aAAa;AACzC,MAAI,OAAQ,KAAI,gBAAgB;AAChC,MAAI,OAAO;AAAE,QAAI,cAAc;AAAO,QAAI,eAAe;AAAA,EAAO;AAChE,MAAI,EAAE,aAAa,SAAS,EAAE,SAAS,KAAK,KAAM,KAAI,YAAY,SAAS,EAAE,SAAS;AAItF,MAAI,OAAO,YAAY;AAAE,QAAI,YAAY;AAAK,QAAI,aAAa,aAAa,GAAG;AAAA,EAAK;AACpF,MAAI,EAAE,gBAAgB,SAAS,EAAE,YAAY,KAAK,KAAM,KAAI,eAAe,SAAS,EAAE,YAAY;AAClG,MAAI,EAAE,cAAc,UAAU,EAAE,UAAU,EAAG,KAAI,aAAa,UAAU,EAAE,UAAU;AACpF,MAAI,EAAE,aAAa,UAAU,EAAE,SAAS,EAAG,KAAI,QAAQ,UAAU,EAAE,SAAS;AAC5E,MAAI,EAAE,UAAU,UAAU,EAAE,UAAU,YAAY,EAAE,UAAU,QAAS,KAAI,YAAY,EAAE;AACzF,MAAI,EAAE,YAAY,cAAc,EAAE,QAAQ,EAAG,KAAI,WAAW,cAAc,EAAE,QAAQ;AACpF,MAAI,EAAE,UAAU,OAAO,EAAE,MAAM,KAAK,KAAM,KAAI,aAAa,OAAO,EAAE,MAAM;AAC1E,MAAI,EAAE,UAAU,UAAU,EAAE,MAAM,KAAK,KAAM,KAAI,eAAe,UAAU,EAAE,MAAM;AAClF,QAAM,MAAO,MAAkC;AAC/C,MAAI,OAAO,QAAQ,YAAY,OAAO,SAAS,GAAG,EAAG,KAAI,eAAe,GAAG,MAAM,KAAK,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC;AAOxG,QAAM,QAAQ,IAAI,OAAO,EAAE,KAAK;AAChC,MAAI,OAAO;AAAE,QAAI,cAAc,MAAM;AAAa,QAAI,aAAa,MAAM;AAAY,QAAI,QAAQ,MAAM;AAAA,EAAO;AAC9G,MAAI,EAAE,OAAO,UAAU;AAAE,QAAI,IAAI,KAAK,EAAE,YAAY,EAAE,EAAG,KAAI,aAAa,EAAE;AAAA,EAAW,WAC9E,IAAI,QAAQ,EAAE,EAAE,GAAG;AAC1B,QAAI,aAAc,EAAE,UAAU,UAAU,IAAI,aAAa,EAAE,EAAE,KAAM,IAAI,QAAQ,EAAE,EAAE;AACnF,UAAM,OAAO,IAAI,aAAa,EAAE,EAAE;AAClC,QAAI,MAAM;AAAE,UAAI,cAAc,KAAK;AAAa,UAAI,QAAQ,KAAK;AAAA,IAAO;AAAA,EAC1E;AACA,QAAM,UAAU,WAAW,EAAE,OAAO;AAEpC,MAAI,SAAS;AAAE,QAAI,kBAAkB,OAAO,OAAO;AAAK,QAAI,iBAAiB;AAAS,QAAI,qBAAqB;AAAA,EAAU;AACzH,QAAM,IAAI;AACV,MAAI,CAAC,OAAO,OAAO,EAAE,eAAe,SAAU,KAAI,aAAa,GAAG,MAAM,EAAE,YAAY,GAAG,GAAG,CAAC;AAC7F,MAAI,CAAC,UAAU,OAAO,EAAE,kBAAkB,SAAU,KAAI,gBAAgB,GAAG,MAAM,EAAE,eAAe,GAAG,GAAG,CAAC;AACzG,MAAI,CAAC,SAAS,OAAO,EAAE,iBAAiB,UAAU;AAChD,UAAM,KAAK,GAAG,MAAM,EAAE,cAAc,GAAG,GAAG,CAAC;AAC3C,QAAI,cAAc;AAAI,QAAI,eAAe;AAAA,EAC3C;AACA,MAAI,EAAE,eAAe,MAAM;AAAE,QAAI,YAAY;AAAS,QAAI,UAAU;AAAQ,QAAI,gBAAgB;AAAU,QAAI,iBAAiB;AAAA,EAAU;AACzI,MAAI,OAAO,EAAE,YAAY,SAAU,KAAI,UAAU,MAAM,EAAE,SAAS,GAAG,GAAG,IAAI;AAE5E,MAAI,IAAI,WAAW,EAAE,MAAM,KAAK,MAAM;AAAE,QAAI,eAAe,IAAI,WAAW,EAAE,MAAM;AAAI,QAAI,WAAW;AAAA,EAAU;AAC/G,MAAI,IAAI,YAAY,EAAE,MAAM,EAAG,KAAI,YAAY,IAAI,YAAY,EAAE,MAAM;AACvE,MAAI,EAAE,cAAc,KAAM,KAAI,YAAY;AAC1C,MAAI,EAAE,iBAAiB,KAAM,KAAI,eAAe;AAChD,MAAK,MAAqB,WAAW,KAAM,KAAI,SAAS;AACxD,SAAO,OAAO,KAAK,GAAG,EAAE,SAAS,MAAM;AACzC;AAcO,SAAS,qBAAqB,OAAiF;AACpH,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,IAAI;AACV,QAAM,OAAQ,MAAkC;AAChD,QAAM,MAAM,OAAO,SAAS,YAAY,OAAO,SAAS,IAAI,IAAI,GAAG,MAAM,KAAK,MAAM,IAAI,GAAG,KAAK,IAAI,CAAC,OAAO,IAAI,kBAAkB,EAAE,YAAY;AAChJ,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,YAAY,EAAE,gBAAgB,EAAE;AACtC,QAAM,SAAS,cAAc,SAAS,eAAe,cAAc,UAAU,eAAe;AAC5F,SAAO,EAAE,UAAU,KAAK,OAAO;AACjC;AAkBO,SAAS,gBACd,OACA,OAAgD,CAAC,GACO;AACxD,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,IAAI;AACV,QAAM,MAAkD,CAAC;AACzD,QAAM,0BAA0B,KAAK,UAAU,KAAK,KAAK,cAAc;AACvE,MAAI,CAAC,2BAA2B,EAAE,YAAY,cAAc,EAAE,QAAQ,EAAG,KAAI,WAAW,cAAc,EAAE,QAAQ;AAChH,MAAI,EAAE,UAAU,OAAO,EAAE,MAAM,KAAK,KAAM,KAAI,aAAa,OAAO,EAAE,MAAM;AAC1E,SAAO,IAAI,aAAa,UAAa,IAAI,eAAe,SAAY,MAAM;AAC5E;AAQO,IAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,YAAY,IAAI,IAAY,qBAAqB;AAUhD,SAAS,iBAAiB,OAG/B;AACA,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO,EAAE,WAAW,QAAW,OAAO,OAAU;AACzF,QAAM,YAAqC,CAAC;AAC5C,QAAM,OAAgC,CAAC;AACvC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,QAAI,MAAM,QAAS;AACnB,KAAC,UAAU,IAAI,CAAC,IAAI,YAAY,MAAM,CAAC,IAAI;AAAA,EAC7C;AACA,QAAM,QAAQ,EAAE,GAAG,gBAAgB,IAAkB,EAAE;AACvD,MAAI,KAAK,OAAO,QAAQ;AACtB,UAAM,aAAa;AACnB,QAAI,CAAC,KAAK,UAAW,OAAM,QAAQ;AAAA,EACrC;AACA,SAAO;AAAA,IACL,WAAW,OAAO,KAAK,SAAS,EAAE,SAAU,YAA2B;AAAA,IACvE,OAAO,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ;AAAA,EAC7C;AACF;AAWO,IAAM,mBAAmB,CAAC,gBAAgB,gBAAgB,aAAa,gBAAgB,SAAS,YAAY,UAAU,MAAM;AAS5H,IAAM,kBAAuD,EAAE,IAAI,SAAS,IAAI,QAAQ;AAM/F,IAAM,gBAAgB,IAAI,IAAY,gBAAgB;AAG/C,SAAS,eAAe,OAA4E;AACzG,QAAM,MAA+B,CAAC;AACtC,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,EAAG,KAAI,cAAc,IAAI,CAAC,KAAK,KAAK,KAAM,KAAI,CAAC,IAAI;AAC5F,SAAO;AACT;AAUO,SAAS,gBAAgB,OAA6G;AAC3I,QAAM,SAAS,eAAe,KAAK;AACnC,QAAM,MAAuC,EAAE,GAAG,gBAAgB,MAAoB,EAAE;AACxF,SAAO,OAAO,KAAK,sBAAsB,MAAoB,CAAC;AAC9D,QAAM,OAAO,IAAI,iBAAiB,OAAO,IAAI;AAC7C,MAAI,KAAM,KAAI,OAAO;AACrB,SAAO,OAAO,KAAK,GAAG,EAAE,SAAS,MAAM;AACzC;AASO,SAAS,sBAAsB,OAA0G;AAC9I,QAAM,SAAS,qBAAqB,KAAK;AACzC,MAAI,CAAC,UAAU,CAAC,MAAO,QAAO;AAC9B,QAAM,YAAY,MAAM,gBAAgB,MAAM;AAC9C,SAAO,EAAE,UAAU,OAAO,UAAU,YAAY,cAAc,SAAS,MAAM,QAAQ,aAAa,cAAc,UAAU,MAAM,OAAO;AACzI;AAGO,SAAS,kBAAkB,OAAwE;AACxG,QAAM,MAAM,gBAAgB,KAAK;AACjC,SAAO,MACH,OAAO,QAAQ,GAAG,EACf,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,QAAQ,UAAU,CAAC,MAAM,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAC3E,KAAK,GAAG,IACX;AACN;;;AC/VO,IAAM,mBACX;AAiCK,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AACF;AA2SO,IAAM,iBAAiB;AAEvB,IAAM,iBAAiB;AAWvB,SAAS,UAAU,OAA4B;AACpD,QAAM,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAClD,QAAM,MAAkB,CAAC;AACzB,aAAW,QAAQ,MAAM;AACvB,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,EAAG;AAC9D,UAAM,IAAI;AACV,QAAI,OAAO,EAAE,gBAAgB,YAAY,EAAE,gBAAgB,GAAI,KAAI,KAAK,IAAgB;AAAA,aAI/E,OAAO,EAAE,gBAAgB,YAAY,OAAO,EAAE,UAAU,YAAY,EAAE,UAAU,GAAI,KAAI,KAAK,EAAE,aAAa,EAAE,OAAO,WAAW,EAAE,CAAC;AAAA,EAC9I;AACA,SAAO;AACT;;;ACvaO,IAAM,kBAAkB,CAAC,QAAQ,SAAS,YAAY,WAAW;AACxE,IAAM,WAAgC,IAAI,IAAI,eAAe;AAW7D,IAAMA,YAAW,CAAC,MAA6C,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC;AAGxG,IAAM,cAAc,CAAC,MAA+BA,UAAS,CAAC,KAAK,OAAO,EAAE,UAAU,YAAY,EAAE,UAAU;AAG9G,SAAS,gBAAgB,OAAyD;AACvF,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,EAAG,KAAI,CAAC,SAAS,IAAI,CAAC,EAAG,KAAI,CAAC,IAAI;AAC3E,SAAO;AACT;AAwBO,SAAS,kBAAkB,OAAgB,OAAyB,CAAC,GAAuB;AACjG,QAAM,QAAQ,KAAK,SAAS;AAC5B,QAAM,OAAO,KAAK,YAAY;AAC9B,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC,EAAE,MAAM,CAAC,GAAG,MAAM,sBAAsB,SAAS,uBAAuB,KAAK,yDAAyD,CAAC;AAC1K,QAAM,MAA0B,CAAC;AACjC,MAAI,KAAK,QAAQ,UAAa,MAAM,SAAS,KAAK,IAAK,KAAI,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,iBAAiB,SAAS,kBAAkB,KAAK,kBAAkB,KAAK,GAAG,gBAAgB,MAAM,MAAM,GAAG,CAAC;AAC7L,MAAI,KAAK,QAAQ,UAAa,MAAM,SAAS,KAAK,IAAK,KAAI,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,gBAAgB,SAAS,iBAAiB,KAAK,mBAAmB,KAAK,GAAG,gBAAgB,MAAM,MAAM,GAAG,CAAC;AAC5L,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,QAAQ,CAAC,OAAO,MAAM;AAC1B,QAAI,CAACA,UAAS,KAAK,GAAG;AACpB,UAAI,KAAK,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,sBAAsB,SAAS,uBAAuB,KAAK,WAAW,IAAI,CAAC,gDAAgD,CAAC;AACxJ;AAAA,IACF;AACA,QAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,KAAK,MAAM,IAAI;AAC9D,UAAI,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,2BAA2B,SAAS,4BAA4B,KAAK,WAAW,IAAI,CAAC,qCAAqC,CAAC;AAAA,IACjK,WAAW,KAAK,IAAI,MAAM,IAAI,GAAG;AAC/B,UAAI,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,4BAA4B,SAAS,6BAA6B,KAAK,WAAW,MAAM,IAAI,0BAA0B,CAAC;AAAA,IAC7J,MAAO,MAAK,IAAI,MAAM,IAAI;AAC1B,QAAI,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,KAAK,MAAM,IAAI;AAChE,UAAI,KAAK,EAAE,MAAM,CAAC,GAAG,OAAO,GAAG,MAAM,4BAA4B,SAAS,6BAA6B,KAAK,WAAW,IAAI,CAAC,mBAAmB,IAAI,IAAI,CAAC;AAAA,IAC1J;AACA,QAAI,MAAM,aAAa,QAAW;AAChC,UAAI,CAAC,KAAK,SAAU,KAAI,KAAK,EAAE,MAAM,CAAC,GAAG,UAAU,GAAG,MAAM,4BAA4B,SAAS,6BAA6B,KAAK,+DAA+D,CAAC;AAAA,eAC1L,OAAO,MAAM,aAAa,YAAY,MAAM,aAAa,GAAI,KAAI,KAAK,EAAE,MAAM,CAAC,GAAG,UAAU,GAAG,MAAM,sBAAsB,SAAS,uBAAuB,KAAK,oCAAoC,CAAC;AAAA,IAChN;AACA,QAAI,MAAM,cAAc,QAAW;AACjC,UAAI,CAAC,KAAK,SAAU,KAAI,KAAK,EAAE,MAAM,CAAC,GAAG,WAAW,GAAG,MAAM,4BAA4B,SAAS,6BAA6B,KAAK,2DAA2D,CAAC;AAAA,eACvL,CAACA,UAAS,MAAM,SAAS,EAAG,KAAI,KAAK,EAAE,MAAM,CAAC,GAAG,WAAW,GAAG,MAAM,sBAAsB,SAAS,uBAAuB,KAAK,iEAAiE,CAAC;AAAA,IAC7M;AACA,eAAW,KAAK,OAAO,KAAK,KAAK,GAAG;AAClC,UAAI,EAAE,WAAW,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,GAAG;AACzC,YAAI,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,0BAA0B,SAAS,2BAA2B,KAAK,MAAM,CAAC,wBAAwB,gBAAgB,KAAK,IAAI,CAAC,iDAAiD,CAAC;AAAA,MAC/M;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAGO,IAAM,iBAAiB,CAAC,SAC7B,KAAK,IAAI,CAAC,GAAG,MAAO,OAAO,MAAM,WAAW,IAAI,CAAC,MAAM,MAAM,IAAI,IAAI,IAAI,CAAC,EAAG,EAAE,KAAK,EAAE;;;ACtGjF,IAAM,uBAA0C,OAAO,OAAO;AAAA,EACnE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;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ACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,E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","names":["isRecord","layout","strip","isPlainObject","formatNumber"]}
|
|
1
|
+
{"version":3,"sources":["../src/block.ts","../src/number-format.ts","../src/block-bindings.ts","../src/sectionSpace.ts","../src/blockStyle.ts","../src/component.ts","../src/slot-child.ts","../src/layout-lucide-icons.ts","../src/layout.ts","../src/dock-icon-names.ts","../src/dock-budget.ts","../src/button-link-pairing.ts","../src/button-look.ts","../src/link-value.ts","../src/video-value.ts","../src/table-value.ts","../src/content-model.ts","../src/locator.ts","../src/sections.ts"],"sourcesContent":["/**\n * ContentBlock — a discriminated union of all CMS block types.\n * Each block has a `type` discriminator and a `props` object\n * whose shape matches the block type.\n */\n\nimport type { SectionSpaceToken, SpaceStepToken } from \"./sectionSpace.js\";\nimport type { ButtonIcon, ButtonVariant } from \"./button-look.js\";\n\n// ── Block style (FLO-264) ──────────────────────────────────────────────────────\n// A uniform, BOUNDED set of design tokens any block may carry (sibling to `props`).\n// Tokens map to fixed CSS values in the renderer (`styleTokensToCss`) so styling\n// reaches the live site WITHOUT arbitrary CSS. Additive + fully optional.\n\nexport type SpaceToken = \"none\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\nexport type ColorToken = \"none\" | \"white\" | \"black\" | \"muted\" | \"mutedBg\" | \"primary\" | \"accent\";\nexport type AlignToken = \"left\" | \"center\" | \"right\";\n/** 3xl/4xl/5xl (2.25/3/4rem) were added for headings, whose size now paints on the <hN> itself. */\nexport type FontSizeToken = \"sm\" | \"base\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\" | \"4xl\" | \"5xl\";\nexport type WeightToken = \"normal\" | \"medium\" | \"semibold\" | \"bold\";\nexport type RadiusToken = \"none\" | \"sm\" | \"md\" | \"lg\" | \"full\";\n\n// Section design (task 4) — the per-instance design a section carries on the page.\nexport type ThemeToken = \"inherit\" | \"light\" | \"dark\";\nexport type BgToken = \"none\" | \"surface\" | \"muted\" | \"accent\" | \"dark\" | \"custom\";\nexport type ContentWidthToken = \"narrow\" | \"default\" | \"wide\" | \"full\";\nexport type CornerToken = \"0\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\";\nexport type ShadowToken = \"0\" | \"s\" | \"m\" | \"l\" | \"xl\";\n\nexport interface BlockStyle {\n // Legacy token set (FLO-264). Where these overlap the section fields below\n // (background, radius, padding), the section field WINS in the renderer.\n paddingY?: SpaceToken;\n paddingX?: SpaceToken;\n marginTop?: SpaceToken;\n marginBottom?: SpaceToken;\n background?: ColorToken;\n textColor?: ColorToken;\n align?: AlignToken;\n fontSize?: FontSizeToken;\n weight?: WeightToken;\n radius?: RadiusToken;\n /** A free corner radius in px (0–96), V2's Alt-drag \"Custom · free\" value. Wins over `radius`. */\n radiusPx?: number;\n /** An image cropped to this ratio, filling its column (V2's media frame). @see imageFrameCss */\n aspect?: \"16/9\" | \"16/7\" | \"4/3\" | \"4/5\" | \"1/1\";\n /** The frame's ratio on a phone (≤767px); unset keeps `aspect`. The hosted lane draws it. */\n aspectMobile?: \"16/9\" | \"16/7\" | \"4/3\" | \"4/5\" | \"1/1\";\n /** The block's top gap on a phone (≤767px), in px (0–240); unset keeps `marginTop`. The hosted lane draws it. */\n marginTopMobilePx?: number;\n /** A heading whose column is its measure: the hosted page's heading width limit (`type.headingMeasure`) skips it. */\n measure?: \"column\";\n\n // Section design (task 4).\n theme?: ThemeToken;\n bg?: BgToken;\n /** Only read when `bg === \"custom\"`. Hex only. */\n bgCustom?: string;\n /** Padding sliders, in px (0–240). Legacy: a `space*` token below wins where both are set. */\n paddingTop?: number;\n paddingBottom?: number;\n paddingSides?: number;\n /** Section spacing as token steps (see sectionSpace.ts). Only the top may pull under the nav. */\n spaceTop?: SectionSpaceToken;\n spaceBottom?: Exclude<SectionSpaceToken, \"section-space-nav-overlap\">;\n spaceSides?: SpaceStepToken;\n contentWidth?: ContentWidthToken;\n /** A free content width in px (320–2400), V2's Alt-drag \"Custom · free\" value. Wins over `contentWidth`. */\n contentWidthPx?: number;\n /**\n * Where the constrained content column sits, when `contentWidth` constrains it.\n *\n * Split out of `align`, which still means text alignment and is still the fallback when this\n * is unset — so everything written before the split renders byte-identically. The two were one\n * token until anything MEASURED a section's text alignment: copying a source site's\n * `text-align: left` would otherwise also shove its column to the page edge.\n */\n contentAlign?: AlignToken;\n fullHeight?: boolean;\n /** 0–100. */\n opacity?: number;\n corner?: CornerToken;\n shadow?: ShadowToken;\n borderTop?: boolean;\n borderBottom?: boolean;\n /** All four sides, `1px solid currentColor` — an outline button's border follows its text colour. */\n border?: boolean;\n /** 🔴 The one free-form string. MUST go through `safeCssUrl()` before reaching CSS. */\n bgImage?: string;\n /** A button's look while the pointer is over it. Only the paint changes; unset keys keep the rest. */\n hover?: BlockHoverStyle;\n /**\n * Breakpoints the block is hidden on (`display:none` there only; the block stays in the HTML).\n * All three is \"Hide on this page\": the block is kept for the editor but no published lane\n * emits it (`hiddenEverywhere`, `visibleBlocks`). Bands: see `BREAKPOINTS`.\n */\n hideOn?: Array<\"mobile\" | \"tablet\" | \"desktop\">;\n}\n\n/** The paint a button swaps to on hover: fill, text colour, and the all-round border. */\nexport interface BlockHoverStyle {\n bg?: BgToken;\n bgCustom?: string;\n textColor?: ColorToken;\n border?: boolean;\n}\n\n// ── Visibility window ─────────────────────────────────────────────────────────\n// When a block (or a Layout Section) is shown. A sibling of `style`, not a key of it: a window\n// decides WHETHER the block renders, never how it is painted.\n\n/**\n * Both bounds are INSTANTS: ISO 8601 with an offset, stored normalized to UTC seconds\n * (`2026-11-27T00:00:00Z`). Shown from `from` (inclusive) until `until` (exclusive); a missing\n * bound is open. An absent or null window is always shown.\n */\nexport interface VisibilityWindow {\n from?: string;\n until?: string;\n}\n\nexport type WindowState = \"live\" | \"pending\" | \"expired\";\n\n/** `2026-11-27T09:00+01:00`: a date, a time and an offset. A string with no offset names no instant. */\nconst WINDOW_INSTANT = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?(Z|[+-]\\d{2}:\\d{2})$/;\n\n/**\n * A written window, normalized for storage, or the code it is refused with. null, undefined and\n * an object with neither bound are all \"no window\". UTC at seconds precision makes the stored\n * strings sort in time order, which the due scan (`list_due_window_projects`) relies on.\n */\nexport function normalizeWindow(\n value: unknown,\n): { window: VisibilityWindow | null } | { error: \"invalid_window\" | \"window_inverted\" } {\n if (value == null) return { window: null };\n if (typeof value !== \"object\" || Array.isArray(value)) return { error: \"invalid_window\" };\n const out: VisibilityWindow = {};\n for (const [key, raw] of Object.entries(value as Record<string, unknown>)) {\n if (key !== \"from\" && key !== \"until\") return { error: \"invalid_window\" };\n if (raw == null) continue;\n const at = typeof raw === \"string\" && WINDOW_INSTANT.test(raw) ? Date.parse(raw) : NaN;\n // `Date.parse` rolls 30 February over into March; a day its month does not have is refused.\n const day = Number(String(raw).slice(8, 10));\n if (Number.isNaN(at) || new Date(Date.UTC(Number(String(raw).slice(0, 4)), Number(String(raw).slice(5, 7)) - 1, day)).getUTCDate() !== day) {\n return { error: \"invalid_window\" };\n }\n out[key] = `${new Date(at).toISOString().slice(0, 19)}Z`;\n }\n // Equal bounds are refused too: a window that opens and closes at the same instant never shows.\n if (out.from && out.until && out.from >= out.until) return { error: \"window_inverted\" };\n return { window: out.from || out.until ? out : null };\n}\n\n/**\n * Where `now` falls in a block's or Section's `window`. THE one reading of a window: every\n * renderer, the delivery lanes and the in-place publish decide through it (or `inWindow`).\n *\n * `now` is an argument, never read from a clock here, so one request compares every block\n * against the same instant. Bounds are compared as instants, so a stored offset cannot shift\n * one. A bound that does not parse is read as open: a hand-edited row shows rather than vanishes.\n */\nexport function windowState(item: unknown, now: Date | number): WindowState {\n const w = item && typeof item === \"object\" ? (item as { window?: unknown }).window : undefined;\n if (!w || typeof w !== \"object\") return \"live\";\n const at = typeof now === \"number\" ? now : now.getTime();\n const { from, until } = w as { from?: unknown; until?: unknown };\n const start = typeof from === \"string\" ? Date.parse(from) : NaN;\n const end = typeof until === \"string\" ? Date.parse(until) : NaN;\n if (!Number.isNaN(end) && at >= end) return \"expired\";\n if (!Number.isNaN(start) && at < start) return \"pending\";\n return \"live\";\n}\n\n/** Is the block or Section shown at `now`? No window is always shown. */\nexport const inWindow = (item: unknown, now: Date | number): boolean => windowState(item, now) === \"live\";\n\n/**\n * Is the block hidden on every breakpoint (`style.hideOn` names mobile, tablet AND desktop)? That\n * is the editor's \"Hide on this page\": the block stays in the stored tree, so Show brings it back\n * as it was, but no published lane emits it. Not a window: it does not depend on `now`.\n */\nexport function hiddenEverywhere(item: unknown): boolean {\n const style = item && typeof item === \"object\" ? (item as { style?: unknown }).style : undefined;\n const raw = style && typeof style === \"object\" ? (style as { hideOn?: unknown }).hideOn : undefined;\n return Array.isArray(raw) && raw.includes(\"mobile\") && raw.includes(\"tablet\") && raw.includes(\"desktop\");\n}\n\n/** `list` mapped through `fn`, or `list` itself when `fn` changed nothing. */\nfunction mapSame<T>(list: T[], fn: (item: T) => T): T[] {\n let changed = false;\n const out = list.map((item) => {\n const next = fn(item);\n if (next !== item) changed = true;\n return next;\n });\n return changed ? out : list;\n}\n\n/** A container block with its nested lists pruned (`visibleBlocks`), or the block itself when none changed. */\nfunction withVisibleChildren<B extends { type?: unknown; props?: unknown }>(block: B, now: Date | number): B {\n const p = (block.props ?? {}) as Record<string, unknown>;\n const key = block.type === \"section\" ? \"children\" : block.type === \"columns\" ? \"columns\" : block.type === \"slider\" ? \"slides\" : block.type === \"tabs\" ? \"tabs\" : null;\n if (!key || !Array.isArray(p[key])) return block;\n const held = p[key] as unknown[];\n const next =\n key === \"children\"\n ? visibleBlocks(held, now)\n : key === \"columns\"\n ? mapSame(held, (column) => visibleBlocks(column, now))\n : // A slide or a tab panel: `{ id, children }`.\n mapSame(held, (row) => {\n const children = (row as { children?: unknown } | null)?.children;\n const shown = visibleBlocks(children, now);\n return shown === children ? row : { ...(row as object), children: shown };\n });\n return next === held ? block : { ...block, props: { ...p, [key]: next } };\n}\n\n/**\n * The blocks shown at `now`: every block outside its window, and every block hidden on all\n * breakpoints (`hiddenEverywhere`), removed at any depth (a section's children, columns, slides,\n * tab panels). What a published lane renders, collects from and delivers.\n *\n * Returns the SAME array when nothing is removed, so a tree with no window costs one walk and\n * every consumer downstream is handed exactly what it was handed before windows existed.\n * Non-array input is returned as it came.\n */\nexport function visibleBlocks<T>(blocks: T, now: Date | number): T {\n if (!Array.isArray(blocks)) return blocks;\n const shown = (blocks as unknown[]).filter((block) => inWindow(block, now) && !hiddenEverywhere(block));\n const pruned = mapSame(shown, (block) =>\n block && typeof block === \"object\" ? withVisibleChildren(block as { type?: unknown; props?: unknown }, now) : block,\n );\n return (shown.length === blocks.length && pruned === shown ? blocks : pruned) as T;\n}\n\n// ── Heading ──────────────────────────────────────────────────────────────────\n\nexport interface HeadingProps {\n text: string;\n level?: 1 | 2 | 3;\n}\n\nexport interface HeadingBlock {\n type: \"heading\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: HeadingProps;\n}\n\n// ── Text ─────────────────────────────────────────────────────────────────────\n\nexport interface TextProps {\n html: string;\n /** @see RichTextProps.level — the same payload takes the same level. */\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nexport interface TextBlock {\n type: \"text\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: TextProps;\n}\n\n/**\n * A rich-text block: the same HTML payload as `text`, authored through a real editor.\n *\n * WHY A SEPARATE TYPE RATHER THAN CHANGING `text`. Every `text` block already on a live page\n * holds an HTML string that the delivery renderer injects as-is. Repurposing that type would\n * mean migrating published content, and getting it wrong renders visible markup to visitors.\n * A new type costs nothing at rest and leaves existing pages untouched.\n *\n * The payload is deliberately IDENTICAL to TextProps (an HTML string) so the two are\n * interchangeable at the renderer: delivery treats them the same, and the difference is\n * entirely in how an author edits them — `text` is a plain field, `richtext` gets the\n * formatting surface.\n */\n/**\n * A Portable Text node — the structured form of rich text.\n *\n * Kept alongside `html` rather than replacing it, so nothing already published moves. The\n * structure exists because an HTML string cannot carry INTENT: a colour is a hex with no\n * notion of which brand token produced it, an embedded component is a div with no reference\n * to resolve, and neither can be read back by tooling. Nodes can carry all of that.\n */\nexport interface PortableTextNode {\n _type: string;\n _key?: string;\n /** Block style — \"normal\", \"h2\", \"blockquote\". */\n style?: string;\n text?: string;\n children?: PortableTextNode[];\n /** Marks on a span: \"strong\", \"em\", or a token reference like \"color:brand-accent\". */\n marks?: string[];\n /** An embedded component or reference resolves through these. */\n schemaKey?: string;\n _ref?: string;\n fields?: Record<string, unknown>;\n}\n\nexport interface PortableTextDocument {\n version: 1;\n content: PortableTextNode[];\n}\n\nexport interface RichTextProps {\n /**\n * The RENDERED CACHE. Delivery reads this, so the fast path stays a string interpolation\n * and every page published before `content` existed keeps rendering byte-identically.\n */\n html: string;\n /**\n * The SOURCE OF TRUTH, when present — `content` always wins over `html`.\n *\n * Optional on purpose: this is the same envelope the field values already use\n * (`{ format, value, html }`), where `html` is likewise derived. Any writer that sets\n * `html` alone on a block that HAS `content` must delete `content` in the same write, or\n * the stale string silently shadows the newer structure.\n */\n content?: PortableTextDocument;\n /**\n * Render the rich copy AS `<h1>`–`<h6>` instead of a paragraph container, so a title keeps\n * its inline marks (a brand-coloured span) AND its heading semantics. Absent ⇒ ordinary rich\n * text, as before. Set ⇒ the value must be ONE line of inline copy; the write schema refuses\n * more. A component prop of type `number` or `select` can target `props.level`.\n */\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n}\n\nexport interface RichTextBlock {\n type: \"richtext\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: RichTextProps;\n}\n\n// ── Image ────────────────────────────────────────────────────────────────────\n\nexport interface ImageProps {\n src: string;\n alt: string;\n width?: number;\n height?: number;\n caption?: string;\n /**\n * THIS placement's focal point (V2's `srcFocal`): 0–1 fractions of the SOURCE picture, drawn as\n * `object-position` inside the crop window `src`'s `?rect=` serves. Absent or null = centred.\n */\n focal?: { x: number; y: number } | null;\n /**\n * THIS placement is decorative (V2's `srcDecorative`): rendered with `alt=\"\"`. The page's own,\n * never the shared media asset's, so one Undo reverses it with the alt.\n */\n decorative?: boolean;\n}\n\nexport interface ImageBlock {\n type: \"image\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: ImageProps;\n}\n\n// ── Button ───────────────────────────────────────────────────────────────────\n\nexport interface ButtonProps {\n text: string;\n href: string;\n /**\n * One of the fixed names, which render `bcms-btn-{variant}`, or the value of a look of the\n * project's own Button family (@see buttonLookValue). Absent ⇒ \"primary\".\n */\n variant?: ButtonVariant | (string & {});\n /** Padding + font-size step. Absent ⇒ \"md\", today's button. sm/lg render `bcms-btn-sm|lg`. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Stretch to the column's width. Absent ⇒ false. true renders `bcms-btn-full`. */\n fullWidth?: boolean;\n /** Draw a trailing arrow after the text. Absent ⇒ false. */\n arrow?: boolean;\n /** A leading icon from `BUTTON_ICONS`. Absent, null or off the list ⇒ none. */\n icon?: ButtonIcon | null;\n /** Open the link in a new tab (`target=\"_blank\" rel=\"noopener noreferrer\"`). Absent ⇒ false. */\n newTab?: boolean;\n /** `nofollow`, `sponsored` or `ugc`; joins the anchor's rel. Absent ⇒ none. */\n rel?: \"nofollow\" | \"sponsored\" | \"ugc\";\n /** `\"code\"`: the click is the site's own script, so it renders `<button type=\"button\">` and `href` is \"\". Absent ⇒ a link. */\n action?: \"code\";\n}\n\nexport interface ButtonBlock {\n type: \"button\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: ButtonProps;\n}\n\n// ── Spacer ───────────────────────────────────────────────────────────────────\n\nexport interface SpacerProps {\n height: number; // in px\n}\n\nexport interface SpacerBlock {\n type: \"spacer\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: SpacerProps;\n}\n\n// ── Columns ───────────────────────────────────────────────────────────────────\n\nexport interface ColumnsProps {\n columns: ContentBlock[][]; // array of column slots, each slot is an array of blocks\n gap?: number; // in px\n}\n\nexport interface ColumnsBlock {\n type: \"columns\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: ColumnsProps;\n}\n\n// ── Video ────────────────────────────────────────────────────────────────────\n\nexport interface VideoProps {\n url: string;\n poster?: string;\n autoplay?: boolean;\n loop?: boolean;\n /**\n * What is said in the video (CPO-093). The block carries its own because its url may be a\n * pasted provider link with no library asset to hang one from. Rendered as <details> after\n * the player and published in the .md twin.\n */\n transcript?: string;\n}\n\nexport interface VideoBlock {\n type: \"video\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: VideoProps;\n}\n\n// ── Form ─────────────────────────────────────────────────────────────────────\n\nexport interface FormProps {\n formId: string; // references forms.id (a nanoid). Resolved against delivered forms at render time.\n}\n\nexport interface FormBlock {\n type: \"form\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: FormProps;\n}\n\n// ── Section (recursive container) ──────────────────────────────────────────────\n\nexport interface SectionProps {\n children: ContentBlock[];\n background?: string;\n paddingY?: number; // in px\n maxWidth?: number; // in px\n}\n\nexport interface SectionBlock {\n type: \"section\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: SectionProps;\n}\n\n// ── Navbar ─────────────────────────────────────────────────────────────────────\n\nexport interface NavLink {\n label: string;\n href: string;\n}\n\nexport interface NavbarProps {\n logo?: { src: string; alt: string; href?: string };\n logoAlt?: string;\n links: NavLink[];\n mobileMenu?: boolean;\n cta?: { text: string; href: string };\n}\n\nexport interface NavbarBlock {\n type: \"navbar\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: NavbarProps;\n}\n\n// ── Footer ─────────────────────────────────────────────────────────────────────\n\nexport interface FooterColumn {\n heading?: string;\n links: NavLink[];\n}\n\nexport interface FooterProps {\n columns: FooterColumn[];\n copyright?: string;\n}\n\nexport interface FooterBlock {\n type: \"footer\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: FooterProps;\n}\n\n// ── Slider / Carousel (recursive container, client-hydrated) ────────────────────\n\nexport interface SlideItem {\n id: string;\n children: ContentBlock[];\n}\n\nexport interface SliderProps {\n slides: SlideItem[];\n autoplay?: boolean;\n interval?: number; // in ms\n loop?: boolean;\n}\n\nexport interface SliderBlock {\n type: \"slider\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: SliderProps;\n}\n\n// ── Tabs (recursive container, client-hydrated) ─────────────────────────────────\n\nexport interface TabItem {\n id: string;\n label: string;\n children: ContentBlock[];\n}\n\nexport interface TabsProps {\n tabs: TabItem[];\n}\n\nexport interface TabsBlock {\n type: \"tabs\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: TabsProps;\n}\n\n// ── Component instance (Webflow-style reusable symbol) ──────────────────────────\n// References a reusable component by id. `overrides` maps a component prop key\n// (declared in the component's `props[]` allowlist) to a value, applied to the\n// component's block tree at render time. Resolved against delivered components.\n\nexport interface ComponentProps {\n componentId: string;\n overrides?: Record<string, unknown>;\n /** Phase A: the page field group this placement renders (its copy + bindings live there). */\n bind?: string;\n /**\n * Phase B: where each override's copy CAME FROM — `{ <propKey>: \"<page field path>\" }`.\n *\n * Written when a placement takes ownership of its copy (`bind` is deleted at the same moment),\n * and it is not decoration:\n * - the COVERAGE METER counts a block-lane declaration\n * (`data-bcms-block=\"<id>\"` + `data-bcms-field=\"<id>__overrides.<propKey>\"`) as bound for\n * the page path named here, so a converted page does not read as a site that lost its\n * bindings;\n * - it is how the componentize lane still recognises WHICH GROUP an instance renders once\n * `bind` is gone — without it a second run would mint a second instance for the same band.\n * A `table` prop names its repeater's path (`faq.items`); every row path under it is that one\n * declaration's, because the prop holds every row.\n */\n source?: Record<string, string>;\n /**\n * A bound placement whose page spells its fields differently from the component's props — a\n * locale copy (`/fr`) placed on its default-locale twin's component: `{ <propKey>: \"<this page's\n * field path>\" }`. Readers resolve a prop's copy through it before `bind`, since the twin's own\n * group keys (`personnalisez-titre`) are not the component's (`customize-title`). Written only\n * while `bind` is; dropped with it when the instance takes its copy.\n */\n bindPaths?: Record<string, string>;\n}\n\nexport interface ComponentBlock {\n type: \"component\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: ComponentProps;\n}\n\n// ── Collection (the entries of the page this block sits on) ─────────────────────\n//\n// LANE-AWARE, and that is the whole idea. A dynamic page's `blockJson` is BOTH what\n// `/blog` renders and the template interpolated into every `/blog/<slug>`. One array\n// cannot be an index and a post layout — unless the one block that differs between them\n// knows which lane it is in. The route supplies that (see CollectionCtx in render-page.ts):\n//\n// /blog → this block renders a card per published entry\n// /blog/my-post → this block renders THAT entry's detail; every other block in the\n// array is interpolated with {{placeholders}} exactly as before\n//\n// So no second template column, no migration, and a page without a collection block\n// behaves byte-identically to before.\n//\n// Scope is IMPLIED by default: a collection lists the entries of the page it sits on, which\n// is precisely the set whose detail URLs are /<thisPage>/<slug>. `source` names another model\n// for a listing that is not that page's own (\"latest posts\" on the home page).\n\nexport interface CollectionProps {\n /** Component rendered once per entry, interpolated with {{field}} and {{url}}. Omit for a built-in card. */\n cardComponentId?: string;\n /** Component rendered for the single entry on a detail URL. Omit to fall back to the generic field layout. */\n detailComponentId?: string;\n /** Built-in card only. Defaults to \"title\" / no excerpt. */\n titleField?: string;\n excerptField?: string;\n /** Max cards to render. Defaults to 20. */\n limit?: number;\n /** \"newest\" (default) reverses the reader's created_at ordering. */\n order?: \"newest\" | \"oldest\";\n emptyText?: string;\n /**\n * List the published entries of ANOTHER model, on any page (\"latest posts\" on the home page).\n * Absent: the entries of the page this block sits on, as above. A model of another project or\n * workspace lists nothing. A sourced block is always a card list, on a detail URL too.\n */\n source?: { modelId: string };\n /** Sourced lists only. The Delivery API's filter grammar; field keys are the model's own. */\n filters?: CollectionFilter[];\n /** Sourced lists only. The Delivery API's sort grammar (`-publishedAt,title`); wins over `order`. */\n sort?: string;\n /** Sourced lists only. Entry ids rendered first, in this order; counted against `limit`. */\n pinnedIds?: string[];\n /** Sourced lists only. On an entry's detail URL, leave that entry out (\"related posts\"). */\n excludeCurrent?: boolean;\n}\n\nexport interface CollectionFilter {\n /** A field key of the source model, or `slug`, `publishedAt`, `locale`. */\n field: string;\n op: \"eq\" | \"ne\" | \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"contains\" | \"in\";\n /** `in` takes a comma-separated list. */\n value: string | number | boolean;\n}\n\nexport interface CollectionBlock {\n type: \"collection\";\n id: string;\n style?: BlockStyle;\n /** Editor-facing display name for this block's dock card. Not rendered. */\n label?: string;\n /** Shown only inside this window. Absent = always. @see VisibilityWindow */\n window?: VisibilityWindow;\n props: CollectionProps;\n}\n\n// ── Union ─────────────────────────────────────────────────────────────────────\n\nexport type ContentBlock =\n | CollectionBlock\n | HeadingBlock\n | TextBlock\n | RichTextBlock\n | ImageBlock\n | ButtonBlock\n | SpacerBlock\n | ColumnsBlock\n | VideoBlock\n | FormBlock\n | SectionBlock\n | NavbarBlock\n | FooterBlock\n | SliderBlock\n | TabsBlock\n | ComponentBlock;\n\n/** Literal union of all block type discriminators. */\nexport type BlockType = ContentBlock[\"type\"];\n\n/**\n * Type guard — narrows an unknown block to `ContentBlock`.\n *\n * @example\n * const block = maybeBlock as unknown;\n * if (isBlock(block)) {\n * // block is ContentBlock here\n * }\n */\nexport function isBlock(value: unknown): value is ContentBlock {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"type\" in value &&\n typeof (value as Record<string, unknown>)[\"type\"] === \"string\"\n );\n}\n\n/**\n * Extract the `type` discriminator from a block, or `null` if not a block.\n *\n * @example\n * const block = { type: \"heading\", id: \"1\", props: { text: \"Hi\" } };\n * getBlockType(block); // \"heading\"\n * getBlockType({ not: \"a block\" }); // null\n */\nexport function getBlockType(value: unknown): BlockType | null {\n if (isBlock(value)) return value.type;\n return null;\n}\n","/**\n * How a `number` field's value is SHOWN: `config.format` on the field.\n *\n * An imported site shows `$1,299.00`, `38%`, `12,000+`, `4 900 €`. The value an author edits and\n * Delivery returns is the number (`1299`, `38`, `12000`, `4900`); everything around the digits is\n * presentation, read once off the built page and kept here. The contract both halves hold:\n *\n * formatNumber(parseNumberText(text).value, parseNumberText(text).format) === text\n *\n * so a page nobody edited is published byte for byte, and an edited value is shown the way the\n * site showed the old one. `parseNumberText` answers null for anything it cannot give back\n * exactly, and that text stays a text field.\n *\n * Pure, and in this package because three programs read it: the import (parse), the publish\n * writers (format) and the dashboard's number input (format, for the preview beside the box).\n */\n\n/** `config.format` of a `number` field. Every key optional; absent = none. */\nexport interface NumberFieldFormat {\n /** Shown before the digits: `$`, `€ `, `+`, `(`, `~`. */\n prefix?: string;\n /** Shown after the digits: `%`, `+`, `k`, ` / month`, ` €`, `)`. */\n suffix?: string;\n /** Thousands separator: `,` `.` ` ` (also no-break and narrow no-break space) `'`. `\"\"` or absent = none. */\n group?: string;\n /** Decimal mark, `.` unless the site writes `,`. */\n decimal?: \".\" | \",\";\n /** Fraction digits always shown (`2` for `£3.20`). A value with more keeps its own, up to six. */\n decimals?: number;\n}\n\nconst GROUPS = [\",\", \".\", \" \", \"\\u00a0\", \"\\u202f\", \"'\", \"\\u2019\"] as const;\n/** Languages that write `1.234,5`: there a lone `.` before three digits is a thousands mark. */\nconst COMMA_DECIMAL = /^(de|es|it|nl|pt|id|tr|da|fr|sv|nb|no|fi|pl|cs|ru|uk|el|ro|hu|sk|sl|hr|bg)\\b/i;\n/** …and of those, the ones that group with a space. */\nconst SPACE_GROUP = /^(fr|sv|nb|no|fi|pl|cs|ru|uk|sk|hu|bg)\\b/i;\n\n/** A magnitude or unit mark that reads as part of the number. Closed: `3D`, `5G` and `1st` are words. */\nconst UNIT = \"(?:[kKmMbBxsdgh]|bn|hr|hrs|min|ms|kg|mg|lb|lbs|oz|km|cm|mm|mi|ft|[kKMGT]B|px|pt|°[CF]?)\";\nconst SUFFIX = new RegExp(`^(?:\\\\s?(?:\\\\p{Sc}|[%‰×]|${UNIT}))?\\\\+?(?:\\\\s?/\\\\s?\\\\p{L}{1,10}){0,2}[)\\\\]*†]?$`, \"u\");\n/** Up to three marks that are no letter, digit, separator or minus: a currency, `+`, `~`, `(`, and a space after. */\nconst PREFIX = /^(?:[^\\p{L}\\p{N}\\s.,'\\u2019#№\\-−–—]{1,3}\\s?)?$/u;\n\nconst fractionDigits = (value: number): number => {\n const text = value.toFixed(6).replace(/0+$/, \"\");\n return text.length - text.indexOf(\".\") - 1;\n};\n\n/** The format a stored `config.format` holds, with anything malformed dropped: a bad row never throws at publish. */\nexport function readNumberFormat(raw: unknown): NumberFieldFormat {\n const o = raw && typeof raw === \"object\" && !Array.isArray(raw) ? (raw as Record<string, unknown>) : {};\n const text = (v: unknown, max: number): string | undefined => (typeof v === \"string\" && v.length <= max && !/\\p{Nd}/u.test(v) ? v : undefined);\n const prefix = text(o.prefix, 8);\n const suffix = text(o.suffix, 24);\n const group = typeof o.group === \"string\" && (GROUPS as readonly string[]).includes(o.group) ? o.group : undefined;\n const decimal = o.decimal === \",\" ? \",\" : undefined;\n const decimals = typeof o.decimals === \"number\" && Number.isInteger(o.decimals) && o.decimals > 0 && o.decimals <= 6 ? o.decimals : undefined;\n return {\n ...(prefix ? { prefix } : {}),\n ...(suffix ? { suffix } : {}),\n // A group mark that is also the decimal mark would print a number nobody can read back.\n ...(group && group !== (decimal ?? \".\") ? { group } : {}),\n ...(decimal ? { decimal } : {}),\n ...(decimals ? { decimals } : {}),\n };\n}\n\n/** The number as the site shows it. A value that is no finite number prints as nothing. */\nexport function formatNumber(value: number, format: NumberFieldFormat = {}): string {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return \"\";\n const places = Math.max(format.decimals ?? 0, Math.min(6, fractionDigits(value)));\n const [int, frac] = Math.abs(value).toFixed(places).split(\".\") as [string, string | undefined];\n const grouped = format.group ? int.replace(/\\B(?=(\\d{3})+(?!\\d))/g, format.group) : int;\n return `${value < 0 ? \"-\" : \"\"}${format.prefix ?? \"\"}${grouped}${frac ? `${format.decimal ?? \".\"}${frac}` : \"\"}${format.suffix ?? \"\"}`;\n}\n\n/**\n * A text that is ONE number and its presentation, or null.\n *\n * Null, on purpose, for: words around the number (`From £2,400`, `3 products`), a leading zero\n * (`01`, `007`: a step marker, a code), digits grouped any other way than in threes (a phone\n * number), two decimal marks (`1.2.3`), a minus (a dash is as often an ornament), an ordinal, and\n * anything `formatNumber` would not print back exactly.\n *\n * `lang` (a BCP 47 tag) settles the one ambiguity, `1.234` and `1,234`, and names the thousands\n * mark of a number too short to show one. `machine`: an attribute a script reads (`data-target`),\n * which is plain digits and stays so.\n */\nexport function parseNumberText(text: string, opts: { lang?: string | null; machine?: boolean } = {}): { value: number; format: NumberFieldFormat } | null {\n if (typeof text !== \"string\" || text.length === 0 || text.length > 40) return null;\n const digits = /\\d/.exec(text);\n if (!digits) return null;\n const start = digits.index;\n const body = /^\\d[\\d.,'\\u2019 \\u00a0\\u202f]*\\d|^\\d/.exec(text.slice(start))![0];\n const prefix = text.slice(0, start);\n const suffix = text.slice(start + body.length);\n if (/\\d/.test(suffix) || !PREFIX.test(prefix) || !SUFFIX.test(suffix)) return null;\n if (opts.machine && (prefix || suffix || !/^\\d+(\\.\\d+)?$/.test(body))) return null;\n // `(213)` closes what it opened, and nothing else may.\n if (/[)\\]]$/.test(suffix) !== /^[([]/.test(prefix)) return null;\n\n const commaLang = COMMA_DECIMAL.test(opts.lang ?? \"\");\n const marks = [...body].filter((c) => !/\\d/.test(c));\n const kinds = [...new Set(marks)];\n let group: string | undefined;\n let decimal: \".\" | \",\" | undefined;\n if (kinds.length > 2) return null;\n if (kinds.length === 2) {\n // Two marks: the last one is the decimal mark, once; the other groups.\n const last = marks[marks.length - 1]!;\n if ((last !== \".\" && last !== \",\") || marks.filter((m) => m === last).length !== 1) return null;\n decimal = last;\n group = kinds.find((k) => k !== last)!;\n } else if (kinds.length === 1) {\n const mark = kinds[0]!;\n const tail = body.slice(body.lastIndexOf(mark) + 1);\n const lone = marks.length === 1 && (mark === \".\" || mark === \",\");\n // `1,5` and `3.20` can only be a decimal; `1,234` reads by the language, `1.234` too.\n const asDecimal = lone && (tail.length !== 3 || body.indexOf(mark) > 3 || /^0/.test(body) || (mark === \".\" ? !commaLang : commaLang));\n if (asDecimal) decimal = mark as \".\" | \",\";\n else group = mark;\n }\n if ((group !== undefined && group === decimal) || (group && !(GROUPS as readonly string[]).includes(group))) return null;\n const [intPart, frac = \"\"] = decimal ? (body.split(decimal) as [string, string?]) : [body];\n const whole = group ? intPart.split(group) : [intPart];\n if (group && (whole.length < 2 || !/^[1-9]\\d{0,2}$/.test(whole[0]!) || whole.slice(1).some((g) => !/^\\d{3}$/.test(g)))) return null;\n const int = whole.join(\"\");\n if (!/^\\d+$/.test(int) || (int.length > 1 && int.startsWith(\"0\")) || int.length + frac.length > 15 || (decimal && !/^\\d+$/.test(frac))) return null;\n\n const value = Number(frac ? `${int}.${frac}` : int);\n // Too short to show a thousands mark: the language's, so `640` edited to `1200` reads `1,200`.\n // Four digits and more with none is the site's own choice (`2019`), kept.\n if (!group && !opts.machine && int.length < 4) group = SPACE_GROUP.test(opts.lang ?? \"\") ? \"\\u00a0\" : commaLang ? \".\" : \",\";\n // A site that groups with `.` (or writes in a language that does) marks its decimals with `,`.\n if (!decimal && (group === \".\" || (commaLang && !opts.machine))) decimal = \",\";\n if (group === (decimal ?? \".\")) group = undefined;\n const format: NumberFieldFormat = {\n ...(prefix ? { prefix } : {}),\n ...(suffix ? { suffix } : {}),\n ...(group ? { group } : {}),\n ...(decimal === \",\" ? { decimal } : {}),\n ...(frac ? { decimals: frac.length } : {}),\n };\n return Number.isFinite(value) && frac.length <= 6 && formatNumber(value, format) === text ? { value, format } : null;\n}\n","/**\n * The ONE declaration of which block props the Visual Editor can address.\n *\n * Four renderers stamp `data-bcms-field` — the hosted renderer, the Next SDK, the Astro SDK\n * and (for minting keys rather than markup) the dashboard's `buildBlockPageDoc`. Until this\n * file existed each carried its own hand-written list, they disagreed by two props, and the\n * dashboard's copy said so in a comment while having nothing to enforce it. A block listed in\n * one and missing from another does not error: it simply never binds, or it binds to a node\n * that resolves to no field. Both failures are silent, which is why they survived.\n *\n * This file is the declaration. The renderers remain the implementation — only they know which\n * ELEMENT carries a value — and `block-binding-coverage.test.ts` asserts the two agree.\n *\n * ── Two kinds of address, because an element is not an attribute ────────────────────────────\n *\n * `data-bcms-field` addresses ONE element. That is enough for a heading's text or an image's\n * src, and not enough for an image's `alt`: the `<img>` already carries a binding, and an\n * element cannot hold two. Entries that name an `attr` are therefore emitted on a SECOND\n * attribute, `data-bcms-props`, whose grammar is:\n *\n * <address>|<kind>|<domAttribute>[;<address>|<kind>|<domAttribute>]*\n *\n * No JSON, because the values are already constrained: an address is grammar A\n * (`[A-Za-z0-9_$-]`, `.`, `[n]`), and kinds and attributes are plain identifiers. A split on\n * two characters parses it, in any language, with no escaping.\n *\n * ── Path templates ──────────────────────────────────────────────────────────────────────────\n *\n * `[]` marks an array the renderer walks. `expandBlockBindings` substitutes real indices from a\n * block's actual props, so `links[].label` on a three-link navbar yields three concrete\n * addresses and on an empty one yields none. `parseFieldPath`/`setFieldPath` in the dashboard\n * have handled N indices since FLO-949; the cap was in what the renderer offered, not in what\n * the writer could persist.\n */\nimport type { ContentBlock, BlockType } from \"./block.js\";\n\n/**\n * How the editor paints a value, and whether it may take a caret.\n *\n * `text`/`richtext` are inline-editable. `image` selects and swaps through the media picker.\n * `url` never takes a caret — a URL typed onto the page has nowhere to report a malformed\n * value — so it is edited in the element toolbar. `array` is a repeater slot: selectable and\n * locatable, edited in the dock.\n *\n * `document` is a whole Portable Text body: selectable as ONE container, repainted whole from the\n * form, and edited per keyed block inside it. It is not a longer `richtext` — a Body stamped\n * `richtext` goes into the rich-text lane, where an opt-out rewrites the value as an `{html}`\n * envelope and the document's own block structure is destroyed.\n */\nexport type BindingKind = \"text\" | \"richtext\" | \"image\" | \"document\" | \"url\" | \"number\" | \"array\";\n\nexport interface BlockBinding {\n /** Path template in grammar A, relative to the block's `props`. `[]` = an array to walk. */\n readonly path: string;\n readonly kind: BindingKind;\n /**\n * The DOM attribute this value lives in, when it is not the element's own text or `src`.\n * Present ⇒ the renderer emits it on `data-bcms-props`, never on `data-bcms-field`.\n */\n readonly attr?: string;\n}\n\n/**\n * Props deliberately absent, and still absent for the original reason:\n *\n * `spacer.height`, `columns.gap`, `section.background` and every `style` token — design, not\n * content. They are edited in the Design accordion, where a slider can express a bounded\n * range that free typing on the page cannot.\n *\n * `text.html` when Portable Text is present — `html` is a cache derived from `content`, so\n * advertising it would persist an ignored sibling and the next frame would read as a revert.\n * The renderer suppresses it; the expander cannot see `content`, so the branch stays there.\n *\n * `component.overrides.*` — instance-scoped, so it cannot be a static template. The renderer\n * derives those addresses per instance from the definition's declared props.\n */\nexport const BLOCK_BINDINGS: Partial<Record<BlockType, readonly BlockBinding[]>> = {\n heading: [{ path: \"text\", kind: \"text\" }],\n text: [{ path: \"html\", kind: \"richtext\" }],\n richtext: [{ path: \"html\", kind: \"richtext\" }],\n image: [\n { path: \"src\", kind: \"image\" },\n { path: \"caption\", kind: \"text\" },\n { path: \"alt\", kind: \"text\", attr: \"alt\" },\n ],\n button: [\n { path: \"text\", kind: \"text\" },\n { path: \"href\", kind: \"url\", attr: \"href\" },\n ],\n video: [\n { path: \"url\", kind: \"url\", attr: \"src\" },\n { path: \"poster\", kind: \"url\", attr: \"poster\" },\n ],\n navbar: [\n { path: \"logo.src\", kind: \"image\" },\n { path: \"logo.alt\", kind: \"text\", attr: \"alt\" },\n { path: \"links[].label\", kind: \"text\" },\n { path: \"links[].href\", kind: \"url\", attr: \"href\" },\n { path: \"cta.text\", kind: \"text\" },\n { path: \"cta.href\", kind: \"url\", attr: \"href\" },\n ],\n footer: [\n { path: \"copyright\", kind: \"text\" },\n { path: \"columns[].heading\", kind: \"text\" },\n { path: \"columns[].links[].label\", kind: \"text\" },\n { path: \"columns[].links[].href\", kind: \"url\", attr: \"href\" },\n ],\n tabs: [{ path: \"tabs[].label\", kind: \"text\" }],\n};\n\n/** One concrete, writable address on one block. */\nexport interface ExpandedBinding extends BlockBinding {\n /** The template with every `[]` replaced by a real index, e.g. `links[2].href`. */\n readonly path: string;\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/**\n * Read a grammar-A path — dotted object keys and zero or more `[n]` indices.\n *\n * Positional, exactly like the dashboard's `parseFieldPath`: a dotted segment is always an\n * object key and a bracketed one always an index, so `links.0` reads the string key \"0\" and\n * misses, rather than being quietly treated as `links[0]`. Any miss returns undefined; nothing\n * here throws, because a template that does not resolve must yield no address, not an error.\n *\n * EXPORTED because a second reader of this grammar now exists: `@bettercms-ai/convert` commits a\n * build-time helper into a customer's repository, and that helper must resolve a path exactly the\n * way the editor does or a converted template renders a fallback where a value exists. The helper\n * itself carries an inlined copy (it lands in a repo where our packages do not exist) and a parity\n * test pins the copy to this original.\n */\nexport function readPath(root: unknown, path: string): unknown {\n let cursor: unknown = root;\n for (const segment of path.split(\".\")) {\n if (!segment) return undefined;\n const key = segment.replace(/\\[\\d+\\]/g, \"\");\n if (key) {\n if (!isRecord(cursor)) return undefined;\n cursor = cursor[key];\n }\n for (const index of segment.matchAll(/\\[(\\d+)\\]/g)) {\n if (!Array.isArray(cursor)) return undefined;\n cursor = cursor[Number(index[1])];\n }\n }\n return cursor;\n}\n\n/** Substitute the FIRST `[]` with every real index, then recurse for any deeper array. */\nfunction expandTemplate(binding: BlockBinding, props: unknown, path: string): ExpandedBinding[] {\n const at = path.indexOf(\"[]\");\n if (at < 0) return [{ ...binding, path }];\n\n const head = path.slice(0, at);\n const tail = path.slice(at + 2);\n const array = readPath(props, head);\n if (!Array.isArray(array)) return [];\n\n return array.flatMap((_item, index) =>\n expandTemplate(binding, props, `${head}[${index}]${tail}`),\n );\n}\n\n/**\n * Every concrete address a block actually offers right now.\n *\n * Array templates expand against the array's real length, so an address is only ever minted\n * for an element that exists. That is the load-bearing property: `setFieldPath` refuses to\n * fabricate an array member, so an address for `links[3]` on a two-link navbar would be a\n * binding the writer rejects — the \"advertises an edit that silently fails\" failure this whole\n * grammar exists to avoid.\n *\n * A prop whose KEY is absent does NOT expand, and that is not a nicety. `setFieldPath` refuses\n * to create a final key unless `createMissingObjects` is set, which only component overrides\n * pass — so an address for a key the block does not carry is a write the editor would reject.\n * An empty string still expands: `\"\"` is a value, and clearing a heading must not make it\n * uneditable.\n */\nexport function expandBlockBindings(block: ContentBlock): ExpandedBinding[] {\n const declared = BLOCK_BINDINGS[block.type];\n if (!declared) return [];\n const props = (block as { props?: unknown }).props;\n if (!isRecord(props)) return [];\n return declared\n .flatMap((binding) => expandTemplate(binding, props, binding.path))\n .filter((binding) => readPath(props, binding.path) !== undefined);\n}\n\n/** The `data-bcms-props` value for a block's attribute bindings, or \"\" when it has none. */\nexport function formatPropsAttribute(\n entries: readonly { address: string; kind: BindingKind; attr: string }[],\n): string {\n return entries.map((e) => `${e.address}|${e.kind}|${e.attr}`).join(\";\");\n}\n\n/** Parse a `data-bcms-props` value. Malformed entries are dropped, never guessed at. */\nexport function parsePropsAttribute(\n value: string | null | undefined,\n): { address: string; kind: BindingKind; attr: string }[] {\n if (!value) return [];\n return value\n .split(\";\")\n .map((entry) => entry.split(\"|\"))\n .filter((parts): parts is [string, BindingKind, string] => parts.length === 3 && parts.every(Boolean))\n .map(([address, kind, attr]) => ({ address, kind, attr }));\n}\n\n/** The shape of a declared component prop this module needs: where it points, and its key. */\ninterface PropTarget {\n key?: string;\n target?: { blockId?: string; path?: string };\n}\n\n/**\n * `<defBlockId>__<prop>` → `<instanceBlockId>__overrides.<propKey>`, for one placed component.\n *\n * Shared by every renderer, because the mapping is a property of the DEFINITION and not of any\n * one output format. A component's block ids belong to the definition and are shared by every\n * instance of it, so `<defBlockId>__text` addresses no instance's value — which is why component\n * subtrees used to render unannotated, and why the SDKs (which never had that suppression)\n * stamped definition-scoped addresses that resolve to no field and, on a component placed twice,\n * collide into a duplicate that drops BOTH copies.\n *\n * The definition already states the mapping in `props[].target`. This only re-keys that\n * statement into the address the editor writes through. Nothing is inferred: a prop with no\n * target produces no entry, so it keeps its dock control and stays uneditable on the canvas,\n * which is the truthful outcome rather than a broken one.\n */\n/**\n * The definition-scoped key a declared prop POINTS AT — `<defBlockId>__<path>`, the same\n * grammar `expandBlockBindings` produces for a block's own bindings.\n *\n * Exported so the \"which leaves does no prop reach?\" check and the address minter below read\n * the key from ONE place. They ask opposite questions of the same mapping, and two spellings\n * of `.replace(/^props\\./, \"\")` is precisely how a leaf ends up counted as bound by one and\n * unbound by the other. Null when the prop declares no target — which is the honest answer:\n * such a prop reaches nothing.\n */\nexport function componentPropTargetKey(prop: PropTarget | undefined): string | null {\n if (!prop?.key || !prop.target?.blockId) return null;\n return `${prop.target.blockId}__${String(prop.target.path ?? \"\").replace(/^props\\./, \"\")}`;\n}\n\n/**\n * `owner` is the address of the rich-text field an instance is EMBEDDED in. Its `_key` is unique\n * only within that field, so the instance is named `<owner>#<_key>` — the same grammar a\n * rich-text node's own address uses — giving `<owner>#<_key>__overrides.<propKey>`.\n */\nexport function componentInstanceAddresses(\n instanceBlockId: string,\n props: readonly PropTarget[] | undefined,\n owner?: string,\n): Map<string, string> {\n const instance = owner ? `${owner}#${instanceBlockId}` : instanceBlockId;\n const out = new Map<string, string>();\n for (const prop of props ?? []) {\n if (!prop?.key || !prop.target?.blockId) continue;\n const from = componentPropTargetKey(prop)!;\n // Two props aimed at one target would make the address ambiguous; first declaration wins\n // and the duplicate is dropped rather than silently overwriting it.\n if (!out.has(from)) out.set(from, `${instance}__overrides.${prop.key}`);\n }\n return out;\n}\n","/**\n * Section spacing as TOKEN STEPS — the ONE list of names and default sizes, shared by the save\n * schema and every renderer. A stored value is always a token (`section-space-large`), never a\n * pixel; it renders as `var(--bcms-section-space-large,88px)`, so a site with a token registry\n * restyles every section at once and a site without one still gets the default rhythm.\n *\n * 🔴 The px table is twinned with the dashboard's `tokenScales.ts` preview table. Change both.\n */\nexport const SECTION_SPACE_TOKENS = [\n \"section-space-none\",\n // V2's six-step band rhythm (None · XS · S · M · L · XL); added after the five, so nothing stored moves.\n \"section-space-xsmall\",\n \"section-space-small\",\n \"section-space-medium\",\n \"section-space-large\",\n \"section-space-xlarge\",\n \"section-space-nav-overlap\",\n] as const;\nexport const SPACE_STEP_TOKENS = [\"space-none\", \"space-s\", \"space-m\", \"space-l\", \"space-xl\"] as const;\n\nexport type SectionSpaceToken = (typeof SECTION_SPACE_TOKENS)[number];\nexport type SpaceStepToken = (typeof SPACE_STEP_TOKENS)[number];\n\n/** A negative band that pulls content under the nav makes sense at the TOP of a section only. */\nexport const SPACE_BOTTOM_TOKENS = SECTION_SPACE_TOKENS.filter(\n (t): t is Exclude<SectionSpaceToken, \"section-space-nav-overlap\"> => t !== \"section-space-nav-overlap\",\n);\n\nconst SPACE_TOKEN_PX: Record<SectionSpaceToken | SpaceStepToken, string> = {\n \"section-space-none\": \"0px\",\n \"section-space-xsmall\": \"16px\",\n \"section-space-small\": \"32px\",\n // V2's band px (site/context.tsx PAD: none 0 · xs 16 · sm 32 · md 56 · lg 88 · xl 128).\n \"section-space-medium\": \"56px\",\n \"section-space-large\": \"88px\",\n \"section-space-xlarge\": \"128px\",\n \"section-space-nav-overlap\": \"-72px\",\n \"space-none\": \"0px\",\n \"space-s\": \"8px\",\n \"space-m\": \"16px\",\n \"space-l\": \"32px\",\n \"space-xl\": \"64px\",\n};\n\n/**\n * What `spaceSides` accepts: the old inner `space-*` steps (still read, as they always rendered)\n * and the section steps the V2 Sides handle writes — the same six as the top and bottom.\n */\nexport const SIDE_SPACE_TOKENS = [...SPACE_STEP_TOKENS, ...SPACE_BOTTOM_TOKENS] as const;\n\n/** V2: side spacing never renders under 16px (`Math.max(16, spacingPx(...))`). */\nexport const SIDE_SPACE_MIN_PX = 16;\n\n/**\n * The side padding for a `spaceSides` token. A section step is floored at 16px as V2 does; an old\n * `space-*` step renders exactly as before, so no stored section moves. \"\" for an unknown token.\n */\nexport function sideSpaceCss(token: unknown): string {\n const css = spaceTokenCss(token);\n if (!css || !(SPACE_BOTTOM_TOKENS as readonly string[]).includes(token as string)) return css;\n return `max(${SIDE_SPACE_MIN_PX}px,${css})`;\n}\n\n/**\n * V2's site gutter: a band's content never touches its edge. The hosted renderer's own section\n * wrapper (`div.bcms-block`) carrying the band rhythm (a top or bottom step or px — only a section\n * carries one) with no side value at all gets 16px sides. Only that wrapper: a site's own section\n * root keeps its own side padding, which an inline 16px would override.\n */\nexport function sideFloorApplies(style: Record<string, unknown>): boolean {\n const band = style.spaceTop !== undefined || style.spaceBottom !== undefined || typeof style.paddingTop === \"number\" || typeof style.paddingBottom === \"number\";\n return band && style.spaceSides === undefined && typeof style.paddingSides !== \"number\" && style.paddingX === undefined;\n}\n\n/** `var(--bcms-<token>,<px>)`, or \"\" for anything that is not a known token (closed set). */\nexport function spaceTokenCss(token: unknown): string {\n const px = typeof token === \"string\" ? SPACE_TOKEN_PX[token as SectionSpaceToken] : undefined;\n return px ? `var(--bcms-${token},${px})` : \"\";\n}\n","/**\n * FLO-264 — bounded block-style tokens → CSS. Framework-agnostic (returns a plain\n * declaration object, no React types) so every renderer shares ONE mapping: the\n * headless @bettercms-ai/next adapter, @bettercms-ai/ui, and (string form) the hosted\n * render-page.ts. Unknown tokens are dropped — closed set, no arbitrary CSS.\n */\nimport type { BlockStyle } from \"./block.js\";\nimport { SPACE_BOTTOM_TOKENS, sideSpaceCss, spaceTokenCss } from \"./sectionSpace.js\";\n\nconst SPACE_PX: Record<string, string> = { none: \"0\", xs: \"4px\", sm: \"8px\", md: \"16px\", lg: \"32px\", xl: \"64px\" };\n// 🔴 Twinned with FONT_SIZE_REM / WEIGHT in src/lib/sites/render-page.ts (the hosted lane) — the\n// cross-lane parity suite (packages/astro/src/__tests__/parity.test.ts) compares them verbatim.\nconst FONT_SIZE_REM: Record<string, string> = {\n sm: \"0.875rem\",\n base: \"1rem\",\n lg: \"1.25rem\",\n xl: \"1.5rem\",\n \"2xl\": \"2rem\",\n \"3xl\": \"2.25rem\",\n \"4xl\": \"3rem\",\n \"5xl\": \"4rem\",\n};\nconst WEIGHT: Record<string, number> = { normal: 400, medium: 500, semibold: 600, bold: 700 };\nconst RADIUS_PX: Record<string, string> = { none: \"0\", sm: \"4px\", md: \"8px\", lg: \"16px\", full: \"9999px\" };\n/**\n * V2's media frame (`aspect-[16/7]` + `cs-r2` on the image wrapper, site/hero.tsx and content.tsx):\n * the picture fills its column, is cropped to the ratio (cover), and takes the theme's large media\n * corner, the card radius x 1.8 as V2's `cs-r2 = calc(var(--cs-r) * 1.8)`. A block's own `radius` /\n * `radiusPx` still wins over that corner. 🔴 Every lane reads this one function (hosted, Next, Astro).\n */\nexport const IMAGE_ASPECTS = [\"16/9\", \"16/7\", \"4/3\", \"4/5\", \"1/1\"] as const;\nexport type ImageAspect = (typeof IMAGE_ASPECTS)[number];\nexport const IMAGE_FRAME_RADIUS = \"calc(var(--bcms-radius-card,14px) * 1.8)\";\nexport function imageFrameCss(style: unknown): { display: \"block\"; width: string; aspectRatio: string; objectFit: \"cover\"; borderRadius?: string } | null {\n if (!style || typeof style !== \"object\") return null;\n const s = style as Record<string, unknown>;\n if (typeof s.aspect !== \"string\" || !(IMAGE_ASPECTS as readonly string[]).includes(s.aspect)) return null;\n const ownRadius = (typeof s.radius === \"string\" && RADIUS_PX[s.radius] != null) || (typeof s.radiusPx === \"number\" && Number.isFinite(s.radiusPx));\n return {\n // Block, as V2's preflight draws an <img>: inline, it sat on a text baseline and the box ran\n // ~7px taller than the picture (445px image in a 452px box at 1280).\n display: \"block\",\n width: \"100%\",\n aspectRatio: s.aspect.replace(\"/\", \" / \"),\n objectFit: \"cover\",\n ...(ownRadius ? {} : { borderRadius: IMAGE_FRAME_RADIUS }),\n };\n}\nconst COLOR_HEX: Record<string, string> = { white: \"#ffffff\", black: \"#111111\", muted: \"#6b7280\", mutedBg: \"#f3f4f6\", primary: \"#111111\", accent: \"#4f46e5\" };\n\n// Section design (theme, fill, image, corners, shadow, content column). 🔴 Twinned with THEME_CSS,\n// BG_HEX, CORNER_PX, SHADOW_CSS, HAIRLINE and CONTENT_WIDTH_PX in src/lib/sites/render-page.ts;\n// src/__tests__/sites/block-style-parity.test.ts pins the two lanes to the same declarations.\nconst THEME: Record<string, { colorScheme: string; background: string; color: string }> = {\n light: { colorScheme: \"light\", background: \"#ffffff\", color: \"#111111\" },\n dark: { colorScheme: \"dark\", background: \"#0b0b0d\", color: \"#f7f8f8\" },\n};\nconst BG_HEX: Record<string, string> = {\n surface: \"var(--bcms-bg-surface,#ffffff)\",\n muted: \"var(--bcms-bg-muted,#f3f4f6)\",\n accent: \"var(--bcms-bg-accent,#4f46e5)\",\n dark: \"var(--bcms-bg-dark,#0b0b0d)\",\n};\n// Under `theme:\"dark\"` the light palette's fills resolve to the dark scheme's own (V2 `themeVars`).\n// Twin: DARK_BG_HEX in render-page.ts.\nconst DARK_BG_HEX: Record<string, string> = { surface: \"#0b0b0d\", muted: \"#1c1c1e\" };\n// A fill that IS a scheme brings its text (V2 `themeVars`: dark = paper on ink, brand = light text on\n// the brand fill). The accent text is WCAG-derived from the real accent (`--bcms-on-accent`). Twin:\n// FILL_SCHEME_CSS in render-page.ts.\nconst FILL_SCHEME: Record<string, { colorScheme: string; color: string }> = {\n dark: { colorScheme: \"dark\", color: \"#f7f8f8\" },\n accent: { colorScheme: \"var(--bcms-accent-scheme,dark)\", color: \"var(--bcms-on-accent,#ffffff)\" },\n};\nconst CORNER_PX: Record<string, string> = { \"0\": \"0\", s: \"4px\", m: \"8px\", l: \"16px\", xl: \"24px\", \"2xl\": \"32px\" };\nconst SHADOW_CSS: Record<string, string> = {\n \"0\": \"none\",\n s: \"0 1px 2px rgba(0,0,0,.06)\",\n m: \"0 4px 12px rgba(0,0,0,.08)\",\n l: \"0 10px 24px rgba(0,0,0,.10)\",\n xl: \"0 24px 48px rgba(0,0,0,.14)\",\n};\nconst HAIRLINE = \"1px solid rgba(0,0,0,.10)\";\n/** `full` is absent on purpose: a full-width column has no max-width, so no inner box at all. */\nconst CONTENT_WIDTH_PX: Record<string, string> = { narrow: \"640px\", default: \"1024px\", wide: \"1280px\" };\n\n/**\n * Where a block's `hideOn` bands start and end: mobile at most 767px, tablet 768-1023px, desktop\n * 1024px and up (the dock's 390 / 810 / 1280 canvases fall one in each band). A site's CSS\n * carries these numbers, so changing one shifts every published site's media queries.\n */\nexport const BREAKPOINTS = { mobile: 767, tablet: 1023 } as const;\n\n/**\n * The ONE stylesheet behind `data-bcms-hide=\"mobile tablet\"`. `!important` because a block's own\n * inline `display` (`fullHeight` writes `display:flex`) would otherwise beat it. `display:none`\n * also takes the block out of the accessibility tree at that width. Hosted pages inline it in\n * the head, `<BcmsBlocks>` emits it when a block uses `hideOn`, and a site that renders its own\n * markup puts it in its global CSS.\n */\nexport const RESPONSIVE_CSS =\n `@media(max-width:${BREAKPOINTS.mobile}px){[data-bcms-hide~=\"mobile\"]{display:none!important}}` +\n `@media(min-width:${BREAKPOINTS.mobile + 1}px) and (max-width:${BREAKPOINTS.tablet}px){[data-bcms-hide~=\"tablet\"]{display:none!important}}` +\n `@media(min-width:${BREAKPOINTS.tablet + 1}px){[data-bcms-hide~=\"desktop\"]{display:none!important}}`;\n\n/**\n * The `data-bcms-hide` value for a block style (`\"mobile tablet\"`), or \"\" when it hides nowhere.\n * Closed set, fixed order, so a hand-edited row cannot put anything else into an attribute.\n * All three is \"\" too: such a block is not emitted on a published lane at all (`visibleBlocks`),\n * and the editor's lane draws it whole, marked `data-bcms-hidden`, so the author can find it.\n */\nexport function hideOnAttr(style: unknown): string {\n const raw = style && typeof style === \"object\" ? (style as { hideOn?: unknown }).hideOn : undefined;\n if (!Array.isArray(raw)) return \"\";\n const on = ([\"mobile\", \"tablet\", \"desktop\"] as const).filter((b) => raw.includes(b));\n return on.length === 3 ? \"\" : on.join(\" \");\n}\n\n/** True when any block in the tree hides somewhere; lets a lane skip `RESPONSIVE_CSS` when unused. */\nexport function usesHideOn(blocks: unknown): boolean {\n let found = false;\n // A replacer visits every key at any depth, so columns, slides and component trees are covered.\n JSON.stringify(blocks ?? null, (k, v) => {\n if (k === \"hideOn\" && hideOnAttr({ hideOn: v })) found = true;\n return v;\n });\n return found;\n}\n\nconst HEX = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;\n\nconst clamp = (n: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, n));\n/** A map entry by OWN key only, so a token like `constructor` can never reach CSS. */\nconst own = <T>(map: Record<string, T>, key: unknown): T | undefined =>\n typeof key === \"string\" && Object.prototype.hasOwnProperty.call(map, key) ? map[key] : undefined;\n\n/**\n * 🔴 The ONE place a free-form string is allowed near CSS: `bgImage` is author-supplied, so it is\n * rejected — never escaped — unless it is an http(s) or root-relative url with nothing that could\n * end a `url(…)` token or start a new declaration (quotes, parens, backslash, `;`, whitespace).\n * Returns \"\" for anything it does not fully trust. Twin of `safeCssUrl` in render-page.ts.\n */\nexport function safeCssUrl(raw: unknown): string {\n if (typeof raw !== \"string\") return \"\";\n const url = raw.trim();\n if (!url || url.length > 2000) return \"\";\n if (/[\"'()\\\\;]|\\s/.test(url)) return \"\";\n if (url.startsWith(\"//\")) return \"\";\n if (url.startsWith(\"/\")) return url;\n return /^https?:\\/\\//i.test(url) ? url : \"\";\n}\n\n/** A CSS declaration object (key → value) usable as a React `style` prop, or undefined when empty. */\nexport function blockStyleToCss(style: BlockStyle | undefined): Record<string, string | number> | undefined {\n if (!style || typeof style !== \"object\") return undefined;\n const s = style as Record<string, string>;\n const css: Record<string, string | number> = {};\n if (s.paddingY && SPACE_PX[s.paddingY] != null) { css.paddingTop = SPACE_PX[s.paddingY]!; css.paddingBottom = SPACE_PX[s.paddingY]!; }\n if (s.paddingX && SPACE_PX[s.paddingX] != null) { css.paddingLeft = SPACE_PX[s.paddingX]!; css.paddingRight = SPACE_PX[s.paddingX]!; }\n // Token steps win over the legacy padding above: they are what the section design panel writes.\n const top = spaceTokenCss(s.spaceTop);\n const bottom = (SPACE_BOTTOM_TOKENS as readonly string[]).includes(s.spaceBottom ?? \"\") ? spaceTokenCss(s.spaceBottom) : \"\";\n const sides = sideSpaceCss(s.spaceSides);\n const navOverlap = s.spaceTop === \"section-space-nav-overlap\";\n if (top && !navOverlap) css.paddingTop = top;\n if (bottom) css.paddingBottom = bottom;\n if (sides) { css.paddingLeft = sides; css.paddingRight = sides; }\n if (s.marginTop && SPACE_PX[s.marginTop] != null) css.marginTop = SPACE_PX[s.marginTop]!;\n // Nav-overlap is the one NEGATIVE step, and negative padding is invalid (computes 0): under a\n // sticky nav the background slides up (negative margin, set after the legacy margin so the token\n // wins) and the content clears it (the same length back as padding), as in `styleTokensToCss`.\n if (top && navOverlap) { css.marginTop = top; css.paddingTop = `calc(-1 * ${top})`; }\n if (s.marginBottom && SPACE_PX[s.marginBottom] != null) css.marginBottom = SPACE_PX[s.marginBottom]!;\n if (s.background && COLOR_HEX[s.background]) css.background = COLOR_HEX[s.background]!;\n if (s.textColor && COLOR_HEX[s.textColor]) css.color = COLOR_HEX[s.textColor]!;\n if (s.align === \"left\" || s.align === \"center\" || s.align === \"right\") css.textAlign = s.align;\n if (s.fontSize && FONT_SIZE_REM[s.fontSize]) css.fontSize = FONT_SIZE_REM[s.fontSize]!;\n if (s.weight && WEIGHT[s.weight] != null) css.fontWeight = WEIGHT[s.weight]!;\n if (s.radius && RADIUS_PX[s.radius] != null) css.borderRadius = RADIUS_PX[s.radius]!;\n const rpx = (style as Record<string, unknown>).radiusPx;\n if (typeof rpx === \"number\" && Number.isFinite(rpx)) css.borderRadius = `${clamp(Math.round(rpx), 0, 96)}px`;\n\n // ── Section design ─────────────────────────────────────────────────────────\n // The same precedence as the hosted `styleTokensToCss`: theme before `bg` (so an explicit fill\n // wins), a token step before the px slider, `corner` over the legacy `radius`, and the legacy\n // all-round `border` last. Keys a later rule overrides keep their first position, so a style\n // without these tokens produces exactly the object it always did.\n const theme = own(THEME, s.theme);\n if (theme) { css.colorScheme = theme.colorScheme; css.background = theme.background; css.color = theme.color; }\n if (s.bg === \"custom\") { if (HEX.test(s.bgCustom ?? \"\")) css.background = s.bgCustom!; }\n else if (own(BG_HEX, s.bg)) {\n css.background = (s.theme === \"dark\" && own(DARK_BG_HEX, s.bg)) || own(BG_HEX, s.bg)!;\n const fill = own(FILL_SCHEME, s.bg);\n if (fill) { css.colorScheme = fill.colorScheme; css.color = fill.color; }\n }\n const bgImage = safeCssUrl(s.bgImage);\n // Unquoted, as on the hosted lane: `safeCssUrl` already refuses every character that could end it.\n if (bgImage) { css.backgroundImage = `url(${bgImage})`; css.backgroundSize = \"cover\"; css.backgroundPosition = \"center\"; }\n const n = style as Record<string, unknown>;\n if (!top && typeof n.paddingTop === \"number\") css.paddingTop = `${clamp(n.paddingTop, 0, 240)}px`;\n if (!bottom && typeof n.paddingBottom === \"number\") css.paddingBottom = `${clamp(n.paddingBottom, 0, 240)}px`;\n if (!sides && typeof n.paddingSides === \"number\") {\n const px = `${clamp(n.paddingSides, 0, 240)}px`;\n css.paddingLeft = px; css.paddingRight = px;\n }\n if (n.fullHeight === true) { css.minHeight = \"100vh\"; css.display = \"flex\"; css.flexDirection = \"column\"; css.justifyContent = \"center\"; }\n if (typeof n.opacity === \"number\") css.opacity = clamp(n.opacity, 0, 100) / 100;\n // overflow:hidden so a background image / child corner actually clips to the radius.\n if (own(CORNER_PX, s.corner) != null) { css.borderRadius = own(CORNER_PX, s.corner)!; css.overflow = \"hidden\"; }\n if (own(SHADOW_CSS, s.shadow)) css.boxShadow = own(SHADOW_CSS, s.shadow)!;\n if (n.borderTop === true) css.borderTop = HAIRLINE;\n if (n.borderBottom === true) css.borderBottom = HAIRLINE;\n if ((style as BlockStyle).border === true) css.border = \"1px solid currentColor\";\n return Object.keys(css).length ? css : undefined;\n}\n\n/**\n * The content column: the declarations for the INNER box a renderer nests between a block's\n * style wrapper (`blockStyleToCss`, which carries the full-bleed background) and the block itself.\n * The outer box can't constrain width without shrinking its own background, so a width needs a\n * second box. `undefined` when there is no column (no `contentWidth`, `full`, or unknown) — a\n * renderer then emits no inner box at all.\n *\n * Placement is `contentAlign`, falling back to `align`. `align` alone used to mean both text\n * alignment (outer box) and column placement (here); `contentAlign` split them, and the fallback\n * keeps every style written before the split rendering identically. Twin: `styleTokensToInnerCss`\n * in render-page.ts, which the hosted lane serialises as `max-width:…;margin:…`.\n */\nexport function blockStyleToInnerCss(style: BlockStyle | undefined): { maxWidth: string; margin: string } | undefined {\n if (!style || typeof style !== \"object\") return undefined;\n const s = style as Record<string, string>;\n const free = (style as Record<string, unknown>).contentWidthPx;\n const max = typeof free === \"number\" && Number.isFinite(free) ? `${clamp(Math.round(free), 320, 2400)}px` : own(CONTENT_WIDTH_PX, s.contentWidth);\n if (!max) return undefined;\n const placement = s.contentAlign ?? s.align;\n const margin = placement === \"left\" ? \"0 auto 0 0\" : placement === \"right\" ? \"0 0 0 auto\" : \"0 auto\";\n return { maxWidth: max, margin };\n}\n\n/**\n * HEADING-STYLE-PAINT — a heading's own size and weight, for the `<hN>` element itself.\n *\n * `blockStyleToCss` puts `fontSize`/`fontWeight` on the block's WRAPPER, where a heading ignores\n * them: the UA `hN{font-weight:bold}` beats the inherited weight at every level, and the UA em\n * size MULTIPLIES the wrapper's (an h2 is 1.5em of it). Painting the same two tokens inline on\n * the heading makes them absolute and exact. The wrapper keeps them too, unchanged, so no DOM or\n * wrapper byte moves; a heading that sets neither gets `undefined` ⇒ no `style` attribute at all.\n *\n * `h1SizeSet` — B9: when the hosted page's presentation sets `type.h1Size`, that owns the size of\n * every h1, so the per-element size is skipped on an h1 (weight still paints). The SDK lanes have\n * no presentation manifest and never pass it. PRESENTATION-HEADING-SCALE will extend the same\n * rule to h2–h6 once per-level knobs exist.\n *\n * Key order is fontSize then fontWeight on every lane, so the parity suite compares verbatim.\n */\nexport function headingPaintCss(\n style: BlockStyle | undefined,\n opts: { level?: number; h1SizeSet?: boolean } = {},\n): { fontSize?: string; fontWeight?: number } | undefined {\n if (!style || typeof style !== \"object\") return undefined;\n const s = style as Record<string, string>;\n const css: { fontSize?: string; fontWeight?: number } = {};\n const sizeOwnedByPresentation = opts.level === 1 && opts.h1SizeSet === true;\n if (!sizeOwnedByPresentation && s.fontSize && FONT_SIZE_REM[s.fontSize]) css.fontSize = FONT_SIZE_REM[s.fontSize]!;\n if (s.weight && WEIGHT[s.weight] != null) css.fontWeight = WEIGHT[s.weight]!;\n return css.fontSize !== undefined || css.fontWeight !== undefined ? css : undefined;\n}\n\n/**\n * Style keys that PLACE a block. A button keeps only these on its wrapper; the rest paints the\n * `<a>` itself. On the wrapper (where every other block's style goes) a fill, theme or corner\n * painted a box BEHIND the anchor, which kept its variant's own fill. 🔴 Twin of `PLACEMENT_KEYS`\n * in src/lib/sites/render-page.ts; src/__tests__/sites/block-style-parity.test.ts pins the two.\n */\nexport const BUTTON_PLACEMENT_KEYS = [\n \"align\",\n \"contentAlign\",\n \"contentWidth\",\n \"marginTop\",\n \"marginBottom\",\n \"fullHeight\",\n \"spaceTop\",\n \"spaceBottom\",\n \"hideOn\",\n] as const;\nconst PLACEMENT = new Set<string>(BUTTON_PLACEMENT_KEYS);\n\n/**\n * A button's style split in two: `placement` (the keys its wrapper keeps — feed it to\n * `blockStyleToCss` / `blockStyleToInnerCss` exactly like any block's style) and `paint`, the\n * declarations for the `<a>` itself. `bg: \"none\"` paints the anchor transparent (and inherits the\n * text colour unless one is set), so it clears the variant's fill instead of doing nothing.\n * `hover` is not painted: the hosted lane draws it with classes its own stylesheet styles.\n * Either half is `undefined` when empty, so an unstyled button gets no wrapper and no `style`.\n */\nexport function splitButtonStyle(style: BlockStyle | undefined): {\n placement: BlockStyle | undefined;\n paint: Record<string, string | number> | undefined;\n} {\n if (!style || typeof style !== \"object\") return { placement: undefined, paint: undefined };\n const placement: Record<string, unknown> = {};\n const rest: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(style)) {\n if (k === \"hover\") continue;\n (PLACEMENT.has(k) ? placement : rest)[k] = v;\n }\n const paint = { ...blockStyleToCss(rest as BlockStyle) };\n if (rest.bg === \"none\") {\n paint.background = \"transparent\";\n if (!rest.textColor) paint.color = \"inherit\";\n }\n return {\n placement: Object.keys(placement).length ? (placement as BlockStyle) : undefined,\n paint: Object.keys(paint).length ? paint : undefined,\n };\n}\n\n// ── Field styles (C3, imported sites) ─────────────────────────────────────────\n\n/**\n * The style keys a PAGE FIELD takes (`pages.field_styles`, keyed by field path): its width and\n * placement, the space above and below it, its text alignment, font size and weight, and `size` — a\n * whole element's Small / Large (a button's). Every key but `size` is a `BlockStyle` key, so it\n * keeps the token set and the CSS table it already has — a field never gets a second scale.\n * 🔴 Twin: `FIELD_STYLE_KEYS` in the dashboard's fieldStyle.ts.\n */\nexport const FIELD_STYLE_KEYS = [\"contentWidth\", \"contentAlign\", \"marginTop\", \"marginBottom\", \"align\", \"fontSize\", \"weight\", \"size\"] as const;\nexport type FieldStyleKey = (typeof FIELD_STYLE_KEYS)[number];\n/** A field element's Small / Large. Medium is UNSET — no \"md\" token is ever stored. */\nexport type FieldSize = \"sm\" | \"lg\";\n/**\n * `size` → the element's `zoom`, which scales the WHOLE element (padding, font, icon, border) — what\n * Small / Large mean for a button whose CSS the site wrote. Any other value (`md` included) paints\n * nothing. 🔴 Inlined in the convert helper (`STYLE_SIZE_ZOOM`), parity-tested against this table.\n */\nexport const FIELD_SIZE_ZOOM: Readonly<Record<FieldSize, string>> = { sm: \"0.875\", lg: \"1.125\" };\n/** One field's style. */\nexport type FieldStyle = Pick<BlockStyle, Exclude<FieldStyleKey, \"size\">> & { size?: FieldSize };\n/** A page's field styles, keyed by field path (the `data-bcms-field` address). */\nexport type FieldStyles = Record<string, FieldStyle>;\n\nconst FIELD_KEY_SET = new Set<string>(FIELD_STYLE_KEYS);\n\n/** Only the field keys of `style` (an empty object for none). */\nexport function pickFieldStyle(style: BlockStyle | Record<string, unknown> | null | undefined): FieldStyle {\n const out: Record<string, unknown> = {};\n if (!style || typeof style !== \"object\") return out as FieldStyle;\n for (const [k, v] of Object.entries(style)) if (FIELD_KEY_SET.has(k) && v != null) out[k] = v;\n return out as FieldStyle;\n}\n\n/**\n * A field's declarations, for its OWN element (`fieldAttrs`). Spacing, alignment, size and weight are\n * `blockStyleToCss`'s. The width is `blockStyleToInnerCss`'s column, drawn on the element itself —\n * a field has no wrapper to nest a column in — so its placement becomes left/right margins, and\n * the vertical margins the spacing set stay. `size` (`FIELD_SIZE_ZOOM`) is LAST, so a style without\n * it keeps the exact declarations, in the exact order, it always had. `undefined` when nothing\n * applies (no `style` at all).\n */\nexport function fieldStyleToCss(style: BlockStyle | Record<string, unknown> | null | undefined): Record<string, string | number> | undefined {\n const picked = pickFieldStyle(style);\n const css: Record<string, string | number> = { ...blockStyleToCss(picked as BlockStyle) };\n Object.assign(css, blockStyleToColumnCss(picked as BlockStyle));\n const zoom = own(FIELD_SIZE_ZOOM, picked.size);\n if (zoom) css.zoom = zoom;\n return Object.keys(css).length ? css : undefined;\n}\n\n/**\n * The content column (`contentWidth` placed by `contentAlign`, falling back to `align`) as the\n * declarations for a box that IS the column — a site's own inner container (`sectionColumnAttrs`)\n * or a field's own element (`fieldStyleToCss`). Same max-width table as `blockStyleToInnerCss`;\n * the placement is left/right margins only, never the `margin` shorthand, so the box keeps its\n * own vertical margins. `undefined` when there is no column (unset, `full`, unknown).\n */\nexport function blockStyleToColumnCss(style: BlockStyle | undefined): { maxWidth: string; marginLeft: string; marginRight: string } | undefined {\n const column = blockStyleToInnerCss(style);\n if (!column || !style) return undefined;\n const placement = style.contentAlign ?? style.align;\n return { maxWidth: column.maxWidth, marginLeft: placement === \"left\" ? \"0\" : \"auto\", marginRight: placement === \"right\" ? \"0\" : \"auto\" };\n}\n\n/** `fieldStyleToCss` as an inline `style` string (`paddingTop` → `padding-top`), \"\" when empty. */\nexport function fieldStyleCssText(style: BlockStyle | Record<string, unknown> | null | undefined): string {\n const css = fieldStyleToCss(style);\n return css\n ? Object.entries(css)\n .map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)}:${v}`)\n .join(\";\")\n : \"\";\n}\n","/**\n * Component — a reusable, Webflow-style block tree (a \"symbol\").\n *\n * A component is authored once and placed across pages via `component` blocks\n * (see `ComponentBlock` in `./block.ts`). Its definition lives in `blockJson`;\n * `props` declares a flat allowlist of values an instance may override.\n */\nimport type { BlockStyle, ContentBlock, VisibilityWindow } from \"./block.js\";\nimport type { ChoiceOption, ContentModelFieldUi, FieldsetKind, OpenMode, ShowIf, UiBefore, UiOrigin } from \"./content-model.js\";\nimport type { DockIconName } from \"./dock-icon-names.js\";\nimport type { VariantInputMapping } from \"./layout.js\";\n\n/**\n * The category a component belongs to (drives library grouping + icons). The first eight\n * are structural (what the component IS); the last four are the \"Add a section\" library\n * tabs (where it appears). One varchar column, not a PG enum — widening is code-only.\n */\n/**\n * 🔴 THE STRUCTURE DOCTRINE — one sentence, one home, spliced into every surface that builds a page.\n *\n * It lives HERE, beside the component contract it describes, because there are THREE places that teach\n * an agent how to build a page and they drifted apart:\n * • `packages/mcp/src/tools.ts` — the MCP tool descriptions (external agents)\n * • `src/lib/ai/agent.ts` — the in-product Studio Agent's system prompt\n * • `packages/mcp/src/prompts.ts` — the authoring playbook, which a tool call does not carry\n *\n * Only the playbook explained sections. `create_page` taught the SCHEMA axis in detail (\"each visual\n * section becomes a nested field\") and said nothing about STRUCTURE; the Studio Agent's prompt named\n * \"pages & reusable components (structure/layout)\" without ever mentioning `sectionType`.\n *\n * Measured consequence, production 2026-08-18: project `acme` has three components, ALL with\n * `section_type = (none)`, and its home page is 18 loose top-level blocks with ZERO sections. Every\n * generated page came out flat, so the visual editor's section lane — outline, name, move, duplicate,\n * delete, variant swap — had nothing to attach to. The editor was faithfully showing pages that were\n * never built out of sections.\n *\n * A constant rather than three paraphrases, because updating some of them is exactly how this happened.\n */\nexport const SECTION_DOCTRINE =\n \"STRUCTURE (separate from schema): a page is composed of SECTIONS. NEVER build a page out of loose top-level heading/text/image/button/spacer blocks — they cannot be moved, duplicated or swapped as a unit, the visual editor cannot outline or name them, and every one of them becomes its own section in the editor. A hero of a headline, a lede and two CTAs is ONE section, not four. TWO SHAPES, and the choice is about REUSE. (1) A band that appears on more than one page, or that needs layout variants, is a COMPONENT with a `sectionType` — see create_component. Components sharing a `sectionType` are that section's VARIANTS (one Hero: 'Centered' for the home page and 'Two-column' for about, same prop keys so a swap keeps the content). This is also the only shape the editor's 'Add a section' picker can insert, and the only one that gets a family name and a variant switcher. (2) A genuinely one-off band on a single page is a `section` BLOCK whose `props.children` hold its blocks. THE TRADEOFF, stated in the present tense because it is real today: inside a component, ONLY the leaves a declared prop TARGETS are click-to-edit on the canvas — each declared prop's `target` is re-keyed to that PLACEMENT's own override address, so editing it changes this page and not the shared definition. A prop with no `target` still SHOWS as a dock control, but its override reaches no rendered slot, so editing it changes nothing on the page. Copy that no prop points at is worse still: no binding and no control, unreachable from click-to-edit AND from the dock, changeable only by editing the component definition, which rewrites every page that places it. A `section` block's children stay click-to-edit unconditionally. So when you choose a component, DECLARE A PROP — WITH A `target` — for every string, link and image a marketer will ever touch; a component with un-propped editable copy is the defect, not the component. In the dock an unset prop shows EMPTY and inherits the definition's default, so set props explicitly when you want the current copy visible there. An IMPORTED site's components are its own (read the repo); its nav, footer and modals are the Layout. On a blank site, do not hand-write a band's JSON: start from a built-in section blueprint (list_components returns locked `builtin:*` blueprints with no projectId — hero-centered, hero-split, feature-grid-three, cta-banner and more), each already rooted in a `section` block with its editable leaves declared as props. INLINE its blockJson as a `section` block for a one-off band; for a recurring band, materialize it with create_component `from` so it becomes project-scoped before implementation validation, Output or publication. Direct `builtin:*` component references exist only for legacy delivery compatibility. Two consecutive call-to-action buttons are two sibling `button` blocks inside the same section — never a `columns` block, which is a `repeat(N,1fr)` grid and would stretch each CTA to half the container. Buttons are inline-level and flow side by side on their own.\";\n\nexport type ComponentCategory =\n | \"navbar\"\n | \"footer\"\n | \"button\"\n | \"section\"\n | \"slider\"\n | \"tabs\"\n | \"form\"\n | \"custom\"\n | \"hero\"\n | \"content\"\n | \"social-proof\"\n | \"conversion\";\n\n/**\n * A single overridable field on a component. `target` points at the block + JSON\n * path inside `blockJson` the override writes to (e.g. blockId \"cta\", path\n * \"props.text\"). Keeping overrides a declared allowlist (not arbitrary nested\n * rewrites) keeps instance data small and the contract explicit.\n */\n/**\n * THE prop vocabulary. One list, imported everywhere a prop type is enumerated.\n *\n * It exists as a value (not just a union) because four places used to spell it out by hand —\n * this file, the Drizzle schema, `COMPONENT_PROP_TYPES` in the backend's Zod schemas, and the\n * MCP tool shape — and the MCP copy is the dangerous one: `update_component` REPLACES the whole\n * `props` array, so a type its enum omits cannot be echoed back, and an agent that reads a\n * component and writes it straight back DESTROYS every prop of that type with a 200.\n *\n * Order is not semantic; append rather than re-sort, so a diff stays readable.\n */\nexport const COMPONENT_PROP_TYPES = [\n \"text\",\n \"richtext\",\n \"image\",\n \"url\",\n \"boolean\",\n \"number\",\n \"select\",\n \"group\",\n \"table\",\n \"slot\",\n \"form\",\n // The seven below each store what the same-named content-model FIELD stores (`icon` and\n // `multiselect` have no field twin; see the value notes on ComponentPropDef.type).\n \"link\",\n \"button\",\n \"date\",\n \"color\",\n \"file\",\n \"icon\",\n \"multiselect\",\n // V2 schema language (F1.x). `object` is ONE nested value of named `config.fields`, stored as\n // `{ [childKey]: value }` like the model field `object`; the six after it store what the\n // same-named content-model FIELD stores (`location` is the V2 geopoint) and are judged by\n // that field's validator.\n \"object\",\n \"datetime\",\n \"slug\",\n \"email\",\n \"phone\",\n \"json\",\n \"location\",\n // V2 leaves, each storing what the same-named content-model FIELD stores: a taxonomy string[],\n // a rating number, a code value (`{ language?, code }` or a string).\n \"tags\",\n \"rating\",\n \"code\",\n // CMS items, as the same-named content-model FIELDS store them: an entry id (or a polymorphic\n // `{ entryId, modelSlug }`), and a list of them. Delivery hydrates them like an entry's.\n \"reference\",\n \"multi-reference\",\n // V2 chrome types, each storing what the same-named content-model FIELD stores: a video value,\n // a primitive list (`config.itemType`), and multi-line text (the field lane's V2 `text`).\n \"video\",\n \"array\",\n \"longtext\",\n] as const;\n\nexport type ComponentPropType = (typeof COMPONENT_PROP_TYPES)[number];\n\n/**\n * The value a `form` prop STORES: just the id. The form itself is a Form document and stays the\n * single source of truth for its fields — a component references one, it never re-declares it.\n *\n * `.strict()` at the write boundary, so a client that POSTs a hydrated form object alongside the\n * id gets a 400 rather than a silent strip.\n *\n * There is deliberately NO resolved twin of this shape. Every renderer already receives forms the\n * same way — a catalogue beside the blocks (`BcmsBlocks({blocks, forms})`, the site renderer's\n * forms map) — and looks the id up in it. A hydrated `{formId, form}` prop value would be a shape\n * that exists nowhere in delivery.\n */\nexport interface ComponentFormPropRef {\n formId: string;\n}\n\nexport interface ComponentPropDef {\n key: string;\n label: string;\n target: { blockId: string; path: string };\n /**\n * `slot` holds ONE nested component instance — the component-level twin of the\n * content-model field type `component-ref` (see content-model.ts), named differently for\n * the same reason that one is: `component` already means a BLOCK type. Its value is\n * `{ componentId, overrides }` and its `target.path` is `props`, so filling a slot writes\n * that object over an empty `component` block's props.\n *\n * With `config.multiple` it holds a LIST of them and targets a container's child list\n * (`props.children` on a `section`, `props.columns.<n>` on a `columns`): the resolver writes\n * one `component` block per item there, so every renderer draws them as ordinary children.\n * @see slotItems\n *\n * On a PAGE a slot fill is a LIVE reference; a published ENTRY freezes it (resolveDeep).\n */\n /**\n * The EDITOR contract, not a storage one: `applyOverrides` writes the value at\n * `target.path` whatever its shape, so `type` decides which control the inspector renders\n * and what shape that control produces (FLO-1020).\n *\n * number → a number (heading.level, columns.count)\n * select → one string from `config.options`\n * group → an object keyed by `config.fields`\n * table → an array of such objects (slider.slides); with `config.mode: \"data\"` instead ONE\n * V2 `TableValue` (typed, keyed columns × keyed rows, table-value.ts), the value a\n * `table` FIELD stores. Aimed at a text or richtext block's `props.html` it renders\n * as the semantic HTML table. With `config.mode: \"types\"` a V2 polymorphic list: rows of\n * several item types (`config.itemTypes`), each row naming its type in `_type`.\n * link → an href string (URL, internal path or #fragment)\n * button → ONE `ButtonValue` (button-look.ts): label, href and look as a unit, never a text prop plus\n * a url prop that drift apart. Targets the `props` of a `button` block.\n * date → `YYYY-MM-DD`\n * color → a hex colour (`#RGB`, `#RRGGBB`, `#RRGGBBAA`)\n * file → `{ url, name?, size? }`, or a bare URL string\n * icon → a BetterCMS icon name (`DOCK_ICON_NAMES`), or an uploaded icon as an image value\n * multiselect → a `string[]`, each one of `config.options`\n * object → ONE `{ [childKey]: value }` keyed by `config.fields` (the V2 model-field `object`)\n * datetime · slug · email · phone · json · location → what the same-named model FIELD stores\n * tags · rating · code → what the same-named model FIELD stores (a string[], a number,\n * `{ language?, code }` or a string)\n * reference · multi-reference → what the same-named model FIELD stores: an entry id, or a\n * list of them (`config.contentModelId`, or `polymorphic` + `allowedModelSlugs`;\n * `min`/`max` on the list). Delivery and preview hydrate the ids in a page's overrides\n * to entries at the read's `depth`; a plain-text slot renders the entry's title.\n * video → a URL string or `{ url, poster?, autoplay?, loop?, transcript? }` (the video\n * block's props; aimed at a video block it lands as them) @see VideoValue\n * array → a list of `config.itemType` values: text, number, date, image, link or richtext\n * (the model field's primitive `array`; a list of objects is a `table`)\n * longtext → a multi-line string (the model field `longtext`; `text` is one line)\n */\n type: ComponentPropType;\n defaultValue?: unknown;\n /**\n * EDITOR HINTS (playbook §12). Stored in the props JSON, so no migration.\n *\n * 🔴 `required` IS NOT ENFORCED AT WRITE TIME, deliberately. Nothing on the write path\n * refuses an override that omits a required prop — a placement saves either way — because\n * the alternative is a component definition that can retroactively make already-saved pages\n * unsaveable. It is a marker the dashboard renders and `get_site_composition` counts, which\n * is the honest shape: the receipt names what is missing instead of the write refusing it.\n */\n required?: boolean;\n /** Hint shown under the control, muted. */\n helpText?: string;\n /** Server-owned: who wrote `helpText`. */\n helpSource?: \"auto\" | \"human\" | \"agent\";\n /** Ghost text inside a text-ish control. */\n placeholder?: string;\n /**\n * Editor-only conditional visibility: show this prop's control only while sibling props (by\n * key) hold these values. The save schema refuses a key no prop of the component declares.\n */\n showIf?: ShowIf;\n /** V2 editor-only keys, as on a model field. @see ContentModelField.helpMore */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /**\n * F1.x: a list prop's items (a table's rows) distinct; on a table sub-field, no two rows share\n * the value. Refused (`unique_prop_scope`) on a top-level scalar: nothing to be unique across.\n */\n unique?: boolean;\n /** `object` / `group` / `table`: how the value (or each row) opens when edited. */\n openMode?: OpenMode;\n /**\n * The content-model field's `readOnly` / `lockReason` pair, as STORED MARKERS only: the\n * editor may render the prop read-only, and no write of a prop value is refused for them.\n */\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2 per-field localization (the locale chip): a stored marker, as on a model field. */\n localized?: boolean;\n /** Per-type settings; the save schema enforces that each is present on the type needing it. */\n config?: {\n /** `slot` — a pick allowlist. */\n componentIds?: string[];\n /** `slot` — the V2 `of.allow` block names it takes (`textBlock`), kept as written; the dock resolves them to components. */\n allow?: string[];\n /**\n * `array` — the V2 item field's own settings (`of[0]`): help under each item, the locale chip,\n * required, and a text / rich text item's length (a text item's pattern). Stored markers.\n */\n item?: { helpText?: string; localized?: boolean; required?: boolean; minLength?: number; maxLength?: number; pattern?: string; patternMessage?: string };\n /** `slot` — the value is a list of instances, not one. @see slotItems */\n multiple?: boolean;\n /** `slot` with `multiple` — bounds on the list. `maxItems` defaults to {@link SLOT_MAX_ITEMS}. */\n minItems?: number;\n maxItems?: number;\n /**\n * `slot` — per-child layout settings (V2 `slotSettings`, e.g. a bento span): what a V2 child's\n * `_settings` holds (`{ _key, _type, _settings, ...props }`, slot-child.ts). Leaf sub-fields.\n */\n slotSettings?: ComponentSubField[];\n /**\n * `table` with `mode: \"types\"` — a V2 polymorphic list: each row is ONE of these item types,\n * named by the row's `_type` (`{ _key?, _type, ...values }`), its values keyed by that type's `fields`.\n */\n itemTypes?: Array<{\n name: string;\n label?: string;\n fields: ComponentSubField[];\n /** How a row of this type reads collapsed: title/subtitle/media name THIS type's fields (dotted ok, e.g. `table.caption`). */\n preview?: { title?: string; subtitle?: string; media?: string; fallback?: string; icon?: DockIconName };\n /** The row icon for this type, a dock icon name. */\n icon?: DockIconName;\n }>;\n /**\n * `select` / `multiselect` — the choices. Required, and a default must be one of them. `{ label, value }`\n * when the stored value is not what an author should read (a component id, for instance).\n */\n options?: Array<string | ChoiceOption>;\n /** `group` / `table` / `object` — the sub-shape; 10 levels at most, counting the prop (MAX_FIELD_DEPTH). */\n fields?: ComponentSubField[];\n /**\n * `table` — which value it holds: `\"rows\"` (the default, an array of `fields` rows) or\n * `\"data\"` (one V2 TableValue, with the table field's options beside it: columnTypes,\n * lockColumns, minRows, maxRows, maxColumns, requireCaption, …). A data table has no `fields`.\n */\n mode?: \"rows\" | \"data\" | \"types\";\n /** `number` — bounds for the control; `multiselect` / `tags` / `multi-reference` — how many items. */\n min?: number;\n max?: number;\n step?: number;\n /** `number` — V2 `validation.min / max`: the error bounds, which win over `min` / `max`. */\n validation?: { min?: number; max?: number };\n /** `text` / `url` / `richtext` — length in characters (richtext: its plain text). */\n minLength?: number;\n maxLength?: number;\n /** `text` / `url` — a regex (≤ 200 characters) and the message shown when it does not match. */\n pattern?: string;\n patternMessage?: string;\n /** `reference` / `multi-reference` — the target model, or `polymorphic` with an allowlist of model slugs. */\n contentModelId?: string;\n polymorphic?: boolean;\n allowedModelSlugs?: string[];\n } & Record<string, unknown>;\n /**\n * AUTHORING CHROME — the same object a content-model FIELD carries ({@link ContentModelFieldUi}),\n * deliberately: an agent that has learned `ui` once has learned it on both lanes.\n *\n * A SIBLING of `config`, not a member of it. `config` is a loose bag, so a `config.ui` already\n * survived the write — and that is the problem this key fixes: surviving is not declared, and\n * an undeclared prop is a typo that saves cleanly and renders as nothing.\n *\n * WHERE EACH KEY IS LEGAL differs from the field lane, because the vocabulary does:\n * `preview`/`layout` on `group`, `table` and `slot`; `reorderable` on `table` ALONE, the only\n * prop type whose value is a list. The save schema refuses the rest with the valid set named.\n */\n ui?: ComponentPropUi;\n /** Server-owned provenance of this prop's chrome. @see UiOrigin */\n uiOrigin?: UiOrigin;\n /** Server-owned revert point. @see UiBefore */\n uiBefore?: UiBefore;\n /** `true`: no placement the last release inspected renders this prop — hidden, never deleted. `false`: a person keeps it shown. */\n stale?: boolean;\n}\n\n/**\n * A top-level prop's dock group. Props have no fieldsets column, so the group rides inline: the\n * first prop to carry an `id` defines it (label, kind, icon, collapsed), later props name `{id}`.\n */\nexport interface PropGroup {\n id: string;\n /** 1–32 chars. Required on the defining prop. */\n label?: string;\n kind?: Exclude<FieldsetKind, \"tab\">;\n icon?: DockIconName;\n collapsed?: boolean;\n /** V2 fieldset keys (CPO D45), on the defining prop: a line under the header (≤200), members side by side, a static header, a breakpoint switcher, and its place among the groups (0–99; absent = where its first prop sits). */\n description?: string;\n columns?: 1 | 2;\n collapsible?: boolean;\n layout?: \"stack\" | \"breakpoints\";\n order?: number;\n}\n\n/**\n * A top-level prop's dock tab (V2 kit schema `groups`: Content | Design | Media | Settings | …).\n * Define-once like {@link PropGroup}: the first prop naming an `id` sets label/icon/order, later\n * props name `{ id }`. At most 8 tabs; never on a sub-field; one group's members share one tab.\n */\nexport interface PropTab {\n id: string;\n /** 1–40 chars, unique per component (case-insensitive). Required on the defining prop. */\n label?: string;\n icon?: DockIconName;\n /** 0–99; the tab's place among the tabs (absent = where its first prop sits). */\n order?: number;\n}\n\n/** A prop's `ui`: the field-lane chrome plus its inline {@link PropGroup} and {@link PropTab}. */\nexport type ComponentPropUi = ContentModelFieldUi & { group?: PropGroup; tab?: PropTab };\n\n/** One field inside a `group` / `object` prop or a `table` row. Recursive, 10 levels at most counting the prop (MAX_FIELD_DEPTH). */\nexport interface ComponentSubField {\n key: string;\n label: string;\n /**\n * No `form`: a form in a table row would mean N form documents per component with no way to\n * author them — the second field model this design exists to avoid. A `slot` sub-field IS\n * accepted by the API (V2 kit entries: an instance in an object or a row, `{ componentId,\n * overrides? }` at its key, the slot prop's config keys), and the `packages/db` schema mirror widened with it.\n */\n type: Exclude<ComponentPropDef[\"type\"], \"form\">;\n defaultValue?: unknown;\n /** The same editor hints as the prop above, one level down. @see ComponentPropDef */\n required?: boolean;\n helpText?: string;\n helpSource?: \"auto\" | \"human\" | \"agent\";\n placeholder?: string;\n options?: Array<string | ChoiceOption>;\n /** The V2 editor keys, one level down. `showIf` names SIBLING sub-fields. @see ComponentPropDef */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /** On a table's sub-field: no two rows share the value; on a list: no item repeats. */\n unique?: boolean;\n openMode?: OpenMode;\n showIf?: ShowIf;\n /** The prop's `ui`, inline group included: V2 fieldsets nest, so sub-fields group too. */\n ui?: ComponentPropUi;\n /** V2 sub-field read-only / developer lock: stored markers, as on the prop. `\"developer\"` needs a lockReason. */\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2 per-field localization: a stored marker, as on the prop. */\n localized?: boolean;\n /** CANONICAL. A nested `group`/`table`/`object`'s own sub-shape. */\n fields?: ComponentSubField[];\n /**\n * A READ-ONLY MIRROR of `options`/`fields`, in the shape `ComponentPropDef` puts them in.\n *\n * 🔴 WHY A SECOND COPY EXISTS AT ALL. A `group`/`table` PROP declares its sub-shape under\n * `config.fields`; a sub-field of one declares its own under a bare `fields`. So a consumer\n * walking a nested table has to switch shape after the first level, and the componentize lane's\n * repo half (`@bettercms-ai/convert --componentize`) walks exactly that — it reads one node\n * shape at every depth. Mirroring the sub-shape here lets it, without the CMS having to\n * describe a nested table differently from a top-level one.\n *\n * `fields` is the authority. The save schema REFUSES a node whose mirror disagrees with it\n * (`componentPropDefSchema`), because two copies that may drift are worse than one awkward\n * shape — an editor that rewrote `fields` alone would leave a stale row description behind.\n */\n config?: { fields?: ComponentSubField[]; options?: Array<string | ChoiceOption> } & Record<string, unknown>;\n}\n\n/** The value a `slot` prop holds — the draft half of a `component-ref`, deliberately. */\nexport interface SlotValue {\n componentId: string;\n overrides?: Record<string, unknown>;\n}\n\n/**\n * One child of a `multiple` slot: a {@link SlotValue} that may also carry the two placement keys a\n * `component` block has. The child block is built with them, so it hides per breakpoint and\n * shows inside its window exactly as a block placed by hand does.\n */\nexport interface SlotItem extends SlotValue {\n style?: BlockStyle;\n window?: VisibilityWindow;\n}\n\n/** How many children a `multiple` slot holds when its prop sets no `config.maxItems`. */\nexport const SLOT_MAX_ITEMS = 12;\n/** The most `config.maxItems` may ask for: one placement never expands into more blocks than this. */\nexport const SLOT_ITEMS_CAP = 50;\n/** The most a `table` prop's rows or an `array` prop's items may be bounded to (`config.maxItems`). */\nexport const LIST_ITEMS_CAP = 500;\n\n/**\n * A slot value as a list of its instances, whichever shape it was stored in: `[]` for nothing,\n * one item for a single `{ componentId, overrides }`, the array's own items for a `multiple`\n * slot. An item with no `componentId` names no component and is left out.\n *\n * THE one reading of a slot value. A walker that tests `value.componentId` alone sees a\n * `multiple` slot as empty, and for a \"where used\" answer or a delete guard that is a component\n * removed from under the pages that hold it.\n */\nexport function slotItems(value: unknown): SlotItem[] {\n const list = Array.isArray(value) ? value : [value];\n const out: SlotItem[] = [];\n for (const item of list) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n const o = item as Record<string, unknown>;\n if (typeof o.componentId === \"string\" && o.componentId !== \"\") out.push(item as SlotItem);\n // A V2 slot child (`{ _key, _type, ...props }`, slot-child.ts): `_type` is the component id and\n // the child ITSELF is the overrides, so a walker that writes into them writes into the stored\n // value. applyOverrides reads declared prop keys only; the `_` keys are never a prop's.\n else if (typeof o.componentId !== \"string\" && typeof o._type === \"string\" && o._type !== \"\") out.push({ componentId: o._type, overrides: o });\n }\n return out;\n}\n\n/**\n * A component is a DRAFT until published; only the published copy reaches a visitor.\n * Mirrors pages and entries. See migration 0186_component_draft_live_split.sql.\n */\nexport type ComponentStatus = \"draft\" | \"published\";\n\n/**\n * Archive state (FLO-1012), deliberately SEPARATE from `ComponentStatus`.\n *\n * Archive takes a component out of the working set — hidden from the components list by\n * default, not offered in the visual editor's insert surfaces — while every existing usage\n * keeps serving. It is not unpublish (which pulls the live copy and re-bakes every page that\n * embeds it) and it is not delete.\n *\n * It is a timestamp rather than a third `status` value because a component can be published\n * AND archived; collapsing the two would lose the bit restore has to put back.\n */\n\n/**\n * How ONE instance of a component reads as a ROW in a parent's slot list (\"Open Rosa Delgado,\n * 2 of 5\"): the V2 /kit schema's document-level `preview`. `title`, `subtitle` and `media` each\n * name a TOP-LEVEL prop key, or a dotted path into one (`slides.0.heading`; the API refuses any\n * other with `preview_key_unknown`); `fallback` is\n * the literal row label while the title prop is empty; `icon` the row's icon while it has no media.\n * Draft-only authoring chrome: never part of the publish snapshot.\n */\nexport interface ComponentPreview {\n title?: string;\n subtitle?: string;\n media?: string;\n fallback?: string;\n icon?: DockIconName;\n}\n\n/**\n * A V2 /kit schema tab (a `groups` entry) NO top-level prop sits in, declared on the component so\n * the schema round-trips: V2 hides a tab with no visible top-level field, and so does the dock. A\n * tab a prop sits in is defined on that prop (`ui.tab`). `order` places it among all the tabs.\n */\nexport interface ComponentTab {\n id: string;\n label: string;\n icon?: DockIconName;\n order?: number;\n}\n\nexport interface Component {\n id: string;\n workspaceId: string;\n projectId?: string | null;\n name: string;\n slug: string;\n category: ComponentCategory;\n /**\n * Section library: the family this component is a LAYOUT of, e.g. \"Hero\". `name` is the\n * layout label (\"Centered\"), so components sharing a sectionType are selectable variants\n * of one section. Null/absent = an ordinary component, not shown in the section library.\n */\n sectionType?: string | null;\n /** First-class variant family membership; exact workspace/project scope is enforced in DB. */\n variantGroupId?: string | null;\n variantInputMappings?: VariantInputMapping[];\n /** Placement governance: `*`, `slug:<page-slug>`, and/or `type:<page-type>`. */\n allowedOn: string[];\n description?: string | null;\n /** The DRAFT definition. Every builder/autosave/import write path targets these two. */\n blockJson: ContentBlock[];\n props: ComponentPropDef[];\n /** How an instance reads as a row in a parent's slot list. Null/absent = unset. @see ComponentPreview */\n preview?: ComponentPreview | null;\n /** The block icon (a /kit schema's document-level `icon`): root crumb, slot rows, slot child frames. Null/absent = unset. */\n icon?: DockIconName | null;\n /** Declared tabs no top-level prop sits in. Null/absent = none. @see ComponentTab */\n tabs?: ComponentTab[] | null;\n status: ComponentStatus;\n /** When it left the working set, or null/absent while active. @see ComponentStatus */\n archivedAt?: string | Date | null;\n /** Derived from `archivedAt`, so a client never has to know the column. */\n archived?: boolean;\n /**\n * The LIVE snapshot get_components_by_handle() serves. Null until the first publish.\n * Returned by GET-one (the Compare view needs it), omitted from list rows for payload.\n */\n publishedBlockJson?: ContentBlock[] | null;\n publishedProps?: ComponentPropDef[] | null;\n publishedAt?: string | null; // ISO 8601\n /**\n * Computed in SQL on list/get, never stored:\n * status='published' AND (blockJson or props has diverged from its published copy).\n * An exact jsonb compare, so it self-clears when an edit is reverted.\n */\n pendingChanges?: boolean;\n thumbnail?: string | null;\n createdAt: string; // ISO 8601\n updatedAt: string; // ISO 8601\n}\n\n/**\n * Public/delivery projection — the fields a renderer needs to resolve instances.\n *\n * DELIBERATELY UNCHANGED by the 0186 draft/live split: delivery aliases\n * publishedBlockJson -> blockJson, so every already-deployed site and every\n * bcms-content.json on disk keeps a byte-identical wire shape. Do not add `status` here —\n * delivery only ever returns published rows, so it would always be the same constant.\n */\nexport interface DeliveryComponent {\n id: string;\n /** The project the component belongs to. */\n projectId?: string | null;\n /** The component's preview image in the editor's library, when it has one. */\n thumbnail?: string | null;\n name: string;\n slug: string;\n category: ComponentCategory;\n sectionType?: string | null;\n blockJson: ContentBlock[];\n props: ComponentPropDef[];\n}\n","/**\n * V2 slot children (DESIGN.md, V2 `engine/slot.tsx`): blocks inside a block, stored INLINE as\n * `{ _key, _type, _variant?, _settings?, ...values }`. The block's own values sit at the child's\n * root, beside four reserved keys:\n *\n * _key the child's stable identity (reorders, diffs, React keys). Unique in its slot.\n * _type the block type: a `kind: 'block'` model's SLUG on a model's `slot` field, a\n * component's ID on a `slot` prop.\n * _variant a block variant (layout) name. Model slots only: a component variant is its own\n * component in BetterCMS, so a prop slot names it in `_type`.\n * _settings per-child layout settings, keyed by the slot's `slotSettings`.\n *\n * The same `_key` / `_type` pair discriminates the items of a polymorphic list prop (a `table` prop\n * with `config.mode: \"types\"`): `_type` names one of its `config.itemTypes`.\n *\n * Pure: shape only. Whether a block type exists, is allowed, and whether a child's values fit it,\n * is the caller's (it knows the block models or the components).\n */\n\n/** The reserved keys of a slot child; every other key is one of the block's own values. */\nexport const SLOT_CHILD_KEYS = [\"_key\", \"_type\", \"_variant\", \"_settings\"] as const;\nconst RESERVED: ReadonlySet<string> = new Set(SLOT_CHILD_KEYS);\n\n/** One block inside a V2 slot. @see SLOT_CHILD_KEYS */\nexport interface SlotChild {\n _key: string;\n _type: string;\n _variant?: string;\n _settings?: Record<string, unknown>;\n [value: string]: unknown;\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> => !!v && typeof v === \"object\" && !Array.isArray(v);\n\n/** Is this a V2 slot child (an object naming its block type in `_type`)? */\nexport const isSlotChild = (v: unknown): v is SlotChild => isRecord(v) && typeof v._type === \"string\" && v._type !== \"\";\n\n/** A slot child's own values: everything but the reserved keys (a new object; the values are shared). */\nexport function slotChildValues(child: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(child)) if (!RESERVED.has(k)) out[k] = v;\n return out;\n}\n\nexport type SlotShapeProblem = { path: Array<string | number>; code: string; message: string };\n\nexport type SlotShapeOptions = {\n /** Bounds on the list. `max` is clamped by the caller's hard cap. */\n min?: number;\n max?: number;\n /** Does the slot declare `slotSettings`? A `_settings` is refused without them. */\n settings?: boolean;\n /** May a child name a `_variant`? (model slots yes, prop slots no) */\n variants?: boolean;\n /** What the list is called in messages (\"Body\", \"slot 'cards'\"). */\n label?: string;\n /** What `_type` names, for messages (\"a block model slug\", \"a component id\"). */\n typeNoun?: string;\n};\n\n/**\n * Why a value cannot be a slot's list of children, each at its path inside the value (`[2, \"_key\"]`),\n * codes first in each message. Shape only: a list of objects, each with a non-empty `_key` (unique)\n * and `_type`, `_variant` a string where allowed, `_settings` an object where declared, no other\n * `_`-prefixed key (a typo'd reserved key would otherwise be stored as a value nothing reads).\n */\nexport function slotShapeProblems(value: unknown, opts: SlotShapeOptions = {}): SlotShapeProblem[] {\n const label = opts.label ?? \"slot\";\n const noun = opts.typeNoun ?? \"a block type\";\n if (!Array.isArray(value)) return [{ path: [], code: \"slot_value_invalid\", message: `slot_value_invalid: ${label} must be a list of blocks ({ _key, _type, ...values })` }];\n const out: SlotShapeProblem[] = [];\n if (opts.max !== undefined && value.length > opts.max) out.push({ path: [], code: \"slot_too_many\", message: `slot_too_many: ${label} holds at most ${opts.max} blocks, got ${value.length}` });\n if (opts.min !== undefined && value.length < opts.min) out.push({ path: [], code: \"slot_too_few\", message: `slot_too_few: ${label} needs at least ${opts.min} blocks, got ${value.length}` });\n const keys = new Set<string>();\n value.forEach((child, i) => {\n if (!isRecord(child)) {\n out.push({ path: [i], code: \"slot_value_invalid\", message: `slot_value_invalid: ${label}: block ${i + 1} must be an object { _key, _type, ...values }` });\n return;\n }\n if (typeof child._key !== \"string\" || child._key.trim() === \"\") {\n out.push({ path: [i, \"_key\"], code: \"slot_child_key_required\", message: `slot_child_key_required: ${label}: block ${i + 1} needs a _key (a non-empty string)` });\n } else if (keys.has(child._key)) {\n out.push({ path: [i, \"_key\"], code: \"slot_child_key_duplicate\", message: `slot_child_key_duplicate: ${label}: _key '${child._key}' is used by two blocks` });\n } else keys.add(child._key);\n if (typeof child._type !== \"string\" || child._type.trim() === \"\") {\n out.push({ path: [i, \"_type\"], code: \"slot_child_type_required\", message: `slot_child_type_required: ${label}: block ${i + 1} needs a _type (${noun})` });\n }\n if (child._variant !== undefined) {\n if (!opts.variants) out.push({ path: [i, \"_variant\"], code: \"slot_variant_unsupported\", message: `slot_variant_unsupported: ${label}: a component variant is its own component; name it in _type` });\n else if (typeof child._variant !== \"string\" || child._variant === \"\") out.push({ path: [i, \"_variant\"], code: \"slot_value_invalid\", message: `slot_value_invalid: ${label}: _variant must be a variant name` });\n }\n if (child._settings !== undefined) {\n if (!opts.settings) out.push({ path: [i, \"_settings\"], code: \"slot_settings_undeclared\", message: `slot_settings_undeclared: ${label} declares no slotSettings, so a block holds no _settings` });\n else if (!isRecord(child._settings)) out.push({ path: [i, \"_settings\"], code: \"slot_value_invalid\", message: `slot_value_invalid: ${label}: _settings must be an object keyed by the slot's slotSettings` });\n }\n for (const k of Object.keys(child)) {\n if (k.startsWith(\"_\") && !RESERVED.has(k)) {\n out.push({ path: [i, k], code: \"slot_child_key_unknown\", message: `slot_child_key_unknown: ${label}: '${k}' is not a slot key (${SLOT_CHILD_KEYS.join(\", \")}); a block's values have no leading underscore` });\n }\n }\n });\n return out;\n}\n\n/** `rows[2]._key`-style path text for a problem path. */\nexport const slotPathString = (path: Array<string | number>): string =>\n path.map((s, i) => (typeof s === \"number\" ? `[${s}]` : i === 0 ? s : `.${s}`)).join(\"\");\n","/**\n * Generated from lucide-react@1.8.0 dynamic icon names.\n * Legacy CamelCase identifiers remain valid for existing Layout documents.\n */\nexport const LAYOUT_SECTION_ICONS: readonly string[] = Object.freeze([\n \"LayoutPanelTop\",\n \"PanelTop\",\n \"PanelBottom\",\n \"Menu\",\n \"Navigation\",\n \"Megaphone\",\n \"GalleryHorizontal\",\n \"Rows3\",\n \"Grid2X2\",\n \"FileText\",\n \"Link\",\n \"Contact\",\n \"BadgeInfo\",\n \"Sparkles\",\n \"a-arrow-down\",\n \"a-arrow-up\",\n \"a-large-small\",\n \"accessibility\",\n \"activity\",\n \"air-vent\",\n \"airplay\",\n \"alarm-clock-check\",\n \"alarm-check\",\n \"alarm-clock-minus\",\n \"alarm-minus\",\n \"alarm-clock-off\",\n \"alarm-clock-plus\",\n \"alarm-plus\",\n \"alarm-clock\",\n \"alarm-smoke\",\n \"album\",\n \"align-center-horizontal\",\n \"align-center-vertical\",\n \"align-end-horizontal\",\n \"align-end-vertical\",\n \"align-horizontal-distribute-center\",\n \"align-horizontal-distribute-end\",\n \"align-horizontal-distribute-start\",\n \"align-horizontal-justify-center\",\n \"align-horizontal-justify-end\",\n \"align-horizontal-justify-start\",\n \"align-horizontal-space-around\",\n \"align-horizontal-space-between\",\n \"align-start-horizontal\",\n \"align-start-vertical\",\n \"align-vertical-distribute-center\",\n \"align-vertical-distribute-end\",\n \"align-vertical-distribute-start\",\n \"align-vertical-justify-center\",\n \"align-vertical-justify-end\",\n \"align-vertical-justify-start\",\n \"align-vertical-space-around\",\n \"align-vertical-space-between\",\n \"ambulance\",\n \"ampersand\",\n \"ampersands\",\n \"amphora\",\n \"anchor\",\n \"angry\",\n \"annoyed\",\n \"antenna\",\n \"anvil\",\n \"aperture\",\n \"app-window-mac\",\n \"app-window\",\n \"apple\",\n \"archive-restore\",\n \"archive-x\",\n \"archive\",\n \"armchair\",\n \"arrow-big-down-dash\",\n \"arrow-big-down\",\n \"arrow-big-left-dash\",\n \"arrow-big-left\",\n \"arrow-big-right-dash\",\n \"arrow-big-right\",\n \"arrow-big-up-dash\",\n \"arrow-big-up\",\n \"arrow-down-0-1\",\n \"arrow-down-01\",\n \"arrow-down-1-0\",\n \"arrow-down-10\",\n \"arrow-down-a-z\",\n \"arrow-down-az\",\n \"arrow-down-from-line\",\n \"arrow-down-left\",\n \"arrow-down-narrow-wide\",\n \"arrow-down-right\",\n \"arrow-down-to-dot\",\n \"arrow-down-to-line\",\n \"arrow-down-up\",\n \"arrow-down-wide-narrow\",\n \"sort-desc\",\n \"arrow-down-z-a\",\n \"arrow-down-za\",\n \"arrow-down\",\n \"arrow-left-from-line\",\n \"arrow-left-right\",\n \"arrow-left-to-line\",\n \"arrow-left\",\n \"arrow-right-from-line\",\n \"arrow-right-left\",\n \"arrow-right-to-line\",\n \"arrow-right\",\n \"arrow-up-0-1\",\n \"arrow-up-01\",\n \"arrow-up-1-0\",\n \"arrow-up-10\",\n \"arrow-up-a-z\",\n \"arrow-up-az\",\n \"arrow-up-down\",\n \"arrow-up-from-dot\",\n \"arrow-up-from-line\",\n \"arrow-up-left\",\n \"arrow-up-narrow-wide\",\n \"sort-asc\",\n \"arrow-up-right\",\n \"arrow-up-to-line\",\n \"arrow-up-wide-narrow\",\n \"arrow-up-z-a\",\n \"arrow-up-za\",\n \"arrow-up\",\n \"arrows-up-from-line\",\n \"asterisk\",\n \"at-sign\",\n \"atom\",\n \"audio-lines\",\n \"audio-waveform\",\n \"award\",\n \"axe\",\n \"axis-3d\",\n \"axis-3-d\",\n \"baby\",\n \"backpack\",\n \"badge-alert\",\n \"badge-cent\",\n \"badge-check\",\n \"verified\",\n \"badge-dollar-sign\",\n \"badge-euro\",\n \"badge-indian-rupee\",\n \"badge-info\",\n \"badge-japanese-yen\",\n \"badge-minus\",\n \"badge-percent\",\n \"badge-plus\",\n \"badge-pound-sterling\",\n \"badge-question-mark\",\n \"badge-help\",\n \"badge-russian-ruble\",\n \"badge-swiss-franc\",\n \"badge-turkish-lira\",\n \"badge-x\",\n \"badge\",\n \"baggage-claim\",\n \"balloon\",\n \"ban\",\n \"banana\",\n \"bandage\",\n \"banknote-arrow-down\",\n \"banknote-arrow-up\",\n \"banknote-x\",\n \"banknote\",\n \"barcode\",\n \"barrel\",\n \"baseline\",\n \"bath\",\n \"battery-charging\",\n \"battery-full\",\n \"battery-low\",\n \"battery-medium\",\n \"battery-plus\",\n \"battery-warning\",\n \"battery\",\n \"beaker\",\n \"bean-off\",\n \"bean\",\n \"bed-double\",\n \"bed-single\",\n \"bed\",\n \"beef-off\",\n \"beef\",\n \"beer-off\",\n \"beer\",\n \"bell-dot\",\n \"bell-electric\",\n \"bell-minus\",\n \"bell-off\",\n \"bell-plus\",\n \"bell-ring\",\n \"bell\",\n \"between-horizontal-end\",\n \"between-horizonal-end\",\n \"between-horizontal-start\",\n \"between-horizonal-start\",\n \"between-vertical-end\",\n \"between-vertical-start\",\n \"biceps-flexed\",\n \"bike\",\n \"binary\",\n \"binoculars\",\n \"biohazard\",\n \"bird\",\n \"birdhouse\",\n \"bitcoin\",\n \"blend\",\n \"blinds\",\n \"blocks\",\n \"bluetooth-connected\",\n \"bluetooth-off\",\n \"bluetooth-searching\",\n \"bluetooth\",\n \"bold\",\n \"bolt\",\n \"bomb\",\n \"bone\",\n \"book-a\",\n \"book-alert\",\n \"book-audio\",\n \"book-check\",\n \"book-copy\",\n \"book-dashed\",\n \"book-template\",\n \"book-down\",\n \"book-headphones\",\n \"book-heart\",\n \"book-image\",\n \"book-key\",\n \"book-lock\",\n \"book-marked\",\n \"book-minus\",\n \"book-open-check\",\n \"book-open-text\",\n \"book-open\",\n \"book-plus\",\n \"book-search\",\n \"book-text\",\n \"book-type\",\n \"book-up-2\",\n \"book-up\",\n \"book-user\",\n \"book-x\",\n \"book\",\n \"bookmark-check\",\n \"bookmark-minus\",\n \"bookmark-off\",\n \"bookmark-plus\",\n \"bookmark-x\",\n \"bookmark\",\n \"boom-box\",\n \"bot-message-square\",\n \"bot-off\",\n \"bot\",\n \"bottle-wine\",\n \"bow-arrow\",\n \"box\",\n \"boxes\",\n \"braces\",\n \"curly-braces\",\n \"brackets\",\n \"brain-circuit\",\n \"brain-cog\",\n \"brain\",\n \"brick-wall-fire\",\n \"brick-wall-shield\",\n \"brick-wall\",\n \"briefcase-business\",\n \"briefcase-conveyor-belt\",\n \"briefcase-medical\",\n \"briefcase\",\n \"bring-to-front\",\n \"brush-cleaning\",\n \"brush\",\n \"bubbles\",\n \"bug-off\",\n \"bug-play\",\n \"bug\",\n \"building-2\",\n \"building\",\n \"bus-front\",\n \"bus\",\n \"cable-car\",\n \"cable\",\n \"cake-slice\",\n \"cake\",\n \"calculator\",\n \"calendar-1\",\n \"calendar-arrow-down\",\n \"calendar-arrow-up\",\n \"calendar-check-2\",\n \"calendar-check\",\n \"calendar-clock\",\n \"calendar-cog\",\n \"calendar-days\",\n \"calendar-fold\",\n \"calendar-heart\",\n \"calendar-minus-2\",\n \"calendar-minus\",\n \"calendar-off\",\n \"calendar-plus-2\",\n \"calendar-plus\",\n \"calendar-range\",\n \"calendar-search\",\n \"calendar-sync\",\n \"calendar-x-2\",\n \"calendar-x\",\n \"calendar\",\n \"calendars\",\n \"camera-off\",\n \"camera\",\n \"candy-cane\",\n \"candy-off\",\n \"candy\",\n \"cannabis-off\",\n \"cannabis\",\n \"captions-off\",\n \"captions\",\n \"subtitles\",\n \"car-front\",\n \"car-taxi-front\",\n \"car\",\n \"caravan\",\n \"card-sim\",\n \"carrot\",\n \"case-lower\",\n \"case-sensitive\",\n \"case-upper\",\n \"cassette-tape\",\n \"cast\",\n \"castle\",\n \"cat\",\n \"cctv-off\",\n \"cctv\",\n \"chart-area\",\n \"area-chart\",\n \"chart-bar-big\",\n \"bar-chart-horizontal-big\",\n \"chart-bar-decreasing\",\n \"chart-bar-increasing\",\n \"chart-bar-stacked\",\n \"chart-bar\",\n \"bar-chart-horizontal\",\n \"chart-candlestick\",\n \"candlestick-chart\",\n \"chart-column-big\",\n \"bar-chart-big\",\n \"chart-column-decreasing\",\n \"chart-column-increasing\",\n \"bar-chart-4\",\n \"chart-column-stacked\",\n \"chart-column\",\n \"bar-chart-3\",\n \"chart-gantt\",\n \"chart-line\",\n \"line-chart\",\n \"chart-network\",\n \"chart-no-axes-column-decreasing\",\n \"chart-no-axes-column-increasing\",\n \"bar-chart\",\n \"chart-no-axes-column\",\n \"bar-chart-2\",\n \"chart-no-axes-combined\",\n \"chart-no-axes-gantt\",\n \"gantt-chart\",\n \"chart-pie\",\n \"pie-chart\",\n \"chart-scatter\",\n \"scatter-chart\",\n \"chart-spline\",\n \"check-check\",\n \"check-line\",\n \"check\",\n \"chef-hat\",\n \"cherry\",\n \"chess-bishop\",\n \"chess-king\",\n \"chess-knight\",\n \"chess-pawn\",\n \"chess-queen\",\n \"chess-rook\",\n \"chevron-down\",\n \"chevron-first\",\n \"chevron-last\",\n \"chevron-left\",\n \"chevron-right\",\n \"chevron-up\",\n \"chevrons-down-up\",\n \"chevrons-down\",\n \"chevrons-left-right-ellipsis\",\n \"chevrons-left-right\",\n \"chevrons-left\",\n \"chevrons-right-left\",\n \"chevrons-right\",\n \"chevrons-up-down\",\n \"chevrons-up\",\n \"church\",\n \"cigarette-off\",\n \"cigarette\",\n \"circle-alert\",\n \"alert-circle\",\n \"circle-arrow-down\",\n \"arrow-down-circle\",\n \"circle-arrow-left\",\n \"arrow-left-circle\",\n \"circle-arrow-out-down-left\",\n \"arrow-down-left-from-circle\",\n \"circle-arrow-out-down-right\",\n \"arrow-down-right-from-circle\",\n \"circle-arrow-out-up-left\",\n \"arrow-up-left-from-circle\",\n \"circle-arrow-out-up-right\",\n \"arrow-up-right-from-circle\",\n \"circle-arrow-right\",\n \"arrow-right-circle\",\n \"circle-arrow-up\",\n \"arrow-up-circle\",\n \"circle-check-big\",\n \"check-circle\",\n \"circle-check\",\n \"check-circle-2\",\n \"circle-chevron-down\",\n \"chevron-down-circle\",\n \"circle-chevron-left\",\n \"chevron-left-circle\",\n \"circle-chevron-right\",\n \"chevron-right-circle\",\n \"circle-chevron-up\",\n \"chevron-up-circle\",\n \"circle-dashed\",\n \"circle-divide\",\n \"divide-circle\",\n \"circle-dollar-sign\",\n \"circle-dot-dashed\",\n \"circle-dot\",\n \"circle-ellipsis\",\n \"circle-equal\",\n \"circle-fading-arrow-up\",\n \"circle-fading-plus\",\n \"circle-gauge\",\n \"gauge-circle\",\n \"circle-minus\",\n \"minus-circle\",\n \"circle-off\",\n \"circle-parking-off\",\n \"parking-circle-off\",\n \"circle-parking\",\n \"parking-circle\",\n \"circle-pause\",\n \"pause-circle\",\n \"circle-percent\",\n \"percent-circle\",\n \"circle-pile\",\n \"circle-play\",\n \"play-circle\",\n \"circle-plus\",\n \"plus-circle\",\n \"circle-pound-sterling\",\n \"circle-power\",\n \"power-circle\",\n \"circle-question-mark\",\n \"help-circle\",\n \"circle-help\",\n \"circle-slash-2\",\n \"circle-slashed\",\n \"circle-slash\",\n \"circle-small\",\n \"circle-star\",\n \"circle-stop\",\n \"stop-circle\",\n \"circle-user-round\",\n \"user-circle-2\",\n \"circle-user\",\n \"user-circle\",\n \"circle-x\",\n \"x-circle\",\n \"circle\",\n \"circuit-board\",\n \"citrus\",\n \"clapperboard\",\n \"clipboard-check\",\n \"clipboard-clock\",\n \"clipboard-copy\",\n \"clipboard-list\",\n \"clipboard-minus\",\n \"clipboard-paste\",\n \"clipboard-pen-line\",\n \"clipboard-signature\",\n \"clipboard-pen\",\n \"clipboard-edit\",\n \"clipboard-plus\",\n \"clipboard-type\",\n \"clipboard-x\",\n \"clipboard\",\n \"clock-1\",\n \"clock-10\",\n \"clock-11\",\n \"clock-12\",\n \"clock-2\",\n \"clock-3\",\n \"clock-4\",\n \"clock-5\",\n \"clock-6\",\n \"clock-7\",\n \"clock-8\",\n \"clock-9\",\n \"clock-alert\",\n \"clock-arrow-down\",\n \"clock-arrow-up\",\n \"clock-check\",\n \"clock-fading\",\n \"clock-plus\",\n \"clock\",\n \"closed-caption\",\n \"cloud-alert\",\n \"cloud-backup\",\n \"cloud-check\",\n \"cloud-cog\",\n \"cloud-download\",\n \"download-cloud\",\n \"cloud-drizzle\",\n \"cloud-fog\",\n \"cloud-hail\",\n \"cloud-lightning\",\n \"cloud-moon-rain\",\n \"cloud-moon\",\n \"cloud-off\",\n \"cloud-rain-wind\",\n \"cloud-rain\",\n \"cloud-snow\",\n \"cloud-sun-rain\",\n \"cloud-sun\",\n \"cloud-sync\",\n \"cloud-upload\",\n \"upload-cloud\",\n \"cloud\",\n \"cloudy\",\n \"clover\",\n \"club\",\n \"code-xml\",\n \"code-2\",\n \"code\",\n \"coffee\",\n \"cog\",\n \"coins\",\n \"columns-2\",\n \"columns\",\n \"columns-3-cog\",\n \"columns-settings\",\n \"table-config\",\n \"columns-3\",\n \"panels-left-right\",\n \"columns-4\",\n \"combine\",\n \"command\",\n \"compass\",\n \"component\",\n \"computer\",\n \"concierge-bell\",\n \"cone\",\n \"construction\",\n \"contact-round\",\n \"contact-2\",\n \"contact\",\n \"container\",\n \"contrast\",\n \"cookie\",\n \"cooking-pot\",\n \"copy-check\",\n \"copy-minus\",\n \"copy-plus\",\n \"copy-slash\",\n \"copy-x\",\n \"copy\",\n \"copyleft\",\n \"copyright\",\n \"corner-down-left\",\n \"corner-down-right\",\n \"corner-left-down\",\n \"corner-left-up\",\n \"corner-right-down\",\n \"corner-right-up\",\n \"corner-up-left\",\n \"corner-up-right\",\n \"cpu\",\n \"creative-commons\",\n \"credit-card\",\n \"croissant\",\n \"crop\",\n \"cross\",\n \"crosshair\",\n \"crown\",\n \"cuboid\",\n \"cup-soda\",\n \"currency\",\n \"cylinder\",\n \"dam\",\n \"database-backup\",\n \"database-search\",\n \"database-zap\",\n \"database\",\n \"decimals-arrow-left\",\n \"decimals-arrow-right\",\n \"delete\",\n \"dessert\",\n \"diameter\",\n \"diamond-minus\",\n \"diamond-percent\",\n \"percent-diamond\",\n \"diamond-plus\",\n \"diamond\",\n \"dice-1\",\n \"dice-2\",\n \"dice-3\",\n \"dice-4\",\n \"dice-5\",\n \"dice-6\",\n \"dices\",\n \"diff\",\n \"disc-2\",\n \"disc-3\",\n \"disc-album\",\n \"disc\",\n \"divide\",\n \"dna-off\",\n \"dna\",\n \"dock\",\n \"dog\",\n \"dollar-sign\",\n \"donut\",\n \"door-closed-locked\",\n \"door-closed\",\n \"door-open\",\n \"dot\",\n \"download\",\n \"drafting-compass\",\n \"drama\",\n \"drill\",\n \"drone\",\n \"droplet-off\",\n \"droplet\",\n \"droplets\",\n \"drum\",\n \"drumstick\",\n \"dumbbell\",\n \"ear-off\",\n \"ear\",\n \"earth-lock\",\n \"earth\",\n \"globe-2\",\n \"eclipse\",\n \"egg-fried\",\n \"egg-off\",\n \"egg\",\n \"ellipse\",\n \"ellipsis-vertical\",\n \"more-vertical\",\n \"ellipsis\",\n \"more-horizontal\",\n \"equal-approximately\",\n \"equal-not\",\n \"equal\",\n \"eraser\",\n \"ethernet-port\",\n \"euro\",\n \"ev-charger\",\n \"expand\",\n \"external-link\",\n \"eye-closed\",\n \"eye-off\",\n \"eye\",\n \"factory\",\n \"fan\",\n \"fast-forward\",\n \"feather\",\n \"fence\",\n \"ferris-wheel\",\n \"file-archive\",\n \"file-axis-3d\",\n \"file-axis-3-d\",\n \"file-badge\",\n \"file-badge-2\",\n \"file-box\",\n \"file-braces-corner\",\n \"file-json-2\",\n \"file-braces\",\n \"file-json\",\n \"file-chart-column-increasing\",\n \"file-bar-chart\",\n \"file-chart-column\",\n \"file-bar-chart-2\",\n \"file-chart-line\",\n \"file-line-chart\",\n \"file-chart-pie\",\n \"file-pie-chart\",\n \"file-check-corner\",\n \"file-check-2\",\n \"file-check\",\n \"file-clock\",\n \"file-code-corner\",\n \"file-code-2\",\n \"file-code\",\n \"file-cog\",\n \"file-cog-2\",\n \"file-diff\",\n \"file-digit\",\n \"file-down\",\n \"file-exclamation-point\",\n \"file-warning\",\n \"file-headphone\",\n \"file-audio\",\n \"file-audio-2\",\n \"file-heart\",\n \"file-image\",\n \"file-input\",\n \"file-key\",\n \"file-key-2\",\n \"file-lock\",\n \"file-lock-2\",\n \"file-minus-corner\",\n \"file-minus-2\",\n \"file-minus\",\n \"file-music\",\n \"file-output\",\n \"file-pen-line\",\n \"file-signature\",\n \"file-pen\",\n \"file-edit\",\n \"file-play\",\n \"file-video\",\n \"file-plus-corner\",\n \"file-plus-2\",\n \"file-plus\",\n \"file-question-mark\",\n \"file-question\",\n \"file-scan\",\n \"file-search-corner\",\n \"file-search-2\",\n \"file-search\",\n \"file-signal\",\n \"file-volume-2\",\n \"file-sliders\",\n \"file-spreadsheet\",\n \"file-stack\",\n \"file-symlink\",\n \"file-terminal\",\n \"file-text\",\n \"file-type-corner\",\n \"file-type-2\",\n \"file-type\",\n \"file-up\",\n \"file-user\",\n \"file-video-camera\",\n \"file-video-2\",\n \"file-volume\",\n \"file-x-corner\",\n \"file-x-2\",\n \"file-x\",\n \"file\",\n \"files\",\n \"film\",\n \"fingerprint-pattern\",\n \"fingerprint\",\n \"fire-extinguisher\",\n \"fish-off\",\n \"fish-symbol\",\n \"fish\",\n \"fishing-hook\",\n \"fishing-rod\",\n \"flag-off\",\n \"flag-triangle-left\",\n \"flag-triangle-right\",\n \"flag\",\n \"flame-kindling\",\n \"flame\",\n \"flashlight-off\",\n \"flashlight\",\n \"flask-conical-off\",\n \"flask-conical\",\n \"flask-round\",\n \"flip-horizontal-2\",\n \"flip-vertical-2\",\n \"flower-2\",\n \"flower\",\n \"focus\",\n \"fold-horizontal\",\n \"fold-vertical\",\n \"folder-archive\",\n \"folder-check\",\n \"folder-clock\",\n \"folder-closed\",\n \"folder-code\",\n \"folder-cog\",\n \"folder-cog-2\",\n \"folder-dot\",\n \"folder-down\",\n \"folder-git-2\",\n \"folder-git\",\n \"folder-heart\",\n \"folder-input\",\n \"folder-kanban\",\n \"folder-key\",\n \"folder-lock\",\n \"folder-minus\",\n \"folder-open-dot\",\n \"folder-open\",\n \"folder-output\",\n \"folder-pen\",\n \"folder-edit\",\n \"folder-plus\",\n \"folder-root\",\n \"folder-search-2\",\n \"folder-search\",\n \"folder-symlink\",\n \"folder-sync\",\n \"folder-tree\",\n \"folder-up\",\n \"folder-x\",\n \"folder\",\n \"folders\",\n \"footprints\",\n \"forklift\",\n \"form\",\n \"forward\",\n \"frame\",\n \"frown\",\n \"fuel\",\n \"fullscreen\",\n \"funnel-plus\",\n \"funnel-x\",\n \"filter-x\",\n \"funnel\",\n \"filter\",\n \"gallery-horizontal-end\",\n \"gallery-horizontal\",\n \"gallery-thumbnails\",\n \"gallery-vertical-end\",\n \"gallery-vertical\",\n \"gamepad-2\",\n \"gamepad-directional\",\n \"gamepad\",\n \"gauge\",\n \"gavel\",\n \"gem\",\n \"georgian-lari\",\n \"ghost\",\n \"gift\",\n \"git-branch-minus\",\n \"git-branch-plus\",\n \"git-branch\",\n \"git-commit-horizontal\",\n \"git-commit\",\n \"git-commit-vertical\",\n \"git-compare-arrows\",\n \"git-compare\",\n \"git-fork\",\n \"git-graph\",\n \"git-merge-conflict\",\n \"git-merge\",\n \"git-pull-request-arrow\",\n \"git-pull-request-closed\",\n \"git-pull-request-create-arrow\",\n \"git-pull-request-create\",\n \"git-pull-request-draft\",\n \"git-pull-request\",\n \"glass-water\",\n \"glasses\",\n \"globe-lock\",\n \"globe-off\",\n \"globe-x\",\n \"globe\",\n \"goal\",\n \"gpu\",\n \"graduation-cap\",\n \"grape\",\n \"grid-2x2-check\",\n \"grid-2-x-2-check\",\n \"grid-2x2-plus\",\n \"grid-2-x-2-plus\",\n \"grid-2x2-x\",\n \"grid-2-x-2-x\",\n \"grid-2x2\",\n \"grid-2-x-2\",\n \"grid-3x2\",\n \"grid-3x3\",\n \"grid\",\n \"grid-3-x-3\",\n \"grip-horizontal\",\n \"grip-vertical\",\n \"grip\",\n \"group\",\n \"guitar\",\n \"ham\",\n \"hamburger\",\n \"hammer\",\n \"hand-coins\",\n \"hand-fist\",\n \"hand-grab\",\n \"grab\",\n \"hand-heart\",\n \"hand-helping\",\n \"helping-hand\",\n \"hand-metal\",\n \"hand-platter\",\n \"hand\",\n \"handbag\",\n \"handshake\",\n \"hard-drive-download\",\n \"hard-drive-upload\",\n \"hard-drive\",\n \"hard-hat\",\n \"hash\",\n \"hat-glasses\",\n \"haze\",\n \"hd\",\n \"hdmi-port\",\n \"heading-1\",\n \"heading-2\",\n \"heading-3\",\n \"heading-4\",\n \"heading-5\",\n \"heading-6\",\n \"heading\",\n \"headphone-off\",\n \"headphones\",\n \"headset\",\n \"heart-crack\",\n \"heart-handshake\",\n \"heart-minus\",\n \"heart-off\",\n \"heart-plus\",\n \"heart-pulse\",\n \"heart\",\n \"heater\",\n \"helicopter\",\n \"hexagon\",\n \"highlighter\",\n \"history\",\n \"hop-off\",\n \"hop\",\n \"hospital\",\n \"hotel\",\n \"hourglass\",\n \"house-heart\",\n \"house-plug\",\n \"house-plus\",\n \"house-wifi\",\n \"house\",\n \"home\",\n \"ice-cream-bowl\",\n \"ice-cream-2\",\n \"ice-cream-cone\",\n \"ice-cream\",\n \"id-card-lanyard\",\n \"id-card\",\n \"image-down\",\n \"image-minus\",\n \"image-off\",\n \"image-play\",\n \"image-plus\",\n \"image-up\",\n \"image-upscale\",\n \"image\",\n \"images\",\n \"import\",\n \"inbox\",\n \"indian-rupee\",\n \"infinity\",\n \"info\",\n \"inspection-panel\",\n \"italic\",\n \"iteration-ccw\",\n \"iteration-cw\",\n \"japanese-yen\",\n \"joystick\",\n \"kanban\",\n \"kayak\",\n \"key-round\",\n \"key-square\",\n \"key\",\n \"keyboard-music\",\n \"keyboard-off\",\n \"keyboard\",\n \"lamp-ceiling\",\n \"lamp-desk\",\n \"lamp-floor\",\n \"lamp-wall-down\",\n \"lamp-wall-up\",\n \"lamp\",\n \"land-plot\",\n \"landmark\",\n \"languages\",\n \"laptop-minimal-check\",\n \"laptop-minimal\",\n \"laptop-2\",\n \"laptop\",\n \"lasso-select\",\n \"lasso\",\n \"laugh\",\n \"layers-2\",\n \"layers-plus\",\n \"layers\",\n \"layers-3\",\n \"layout-dashboard\",\n \"layout-grid\",\n \"layout-list\",\n \"layout-panel-left\",\n \"layout-panel-top\",\n \"layout-template\",\n \"leaf\",\n \"leafy-green\",\n \"lectern\",\n \"lens-concave\",\n \"lens-convex\",\n \"library-big\",\n \"library\",\n \"life-buoy\",\n \"ligature\",\n \"lightbulb-off\",\n \"lightbulb\",\n \"line-dot-right-horizontal\",\n \"line-squiggle\",\n \"line-style\",\n \"link-2-off\",\n \"link-2\",\n \"link\",\n \"list-check\",\n \"list-checks\",\n \"list-chevrons-down-up\",\n \"list-chevrons-up-down\",\n \"list-collapse\",\n \"list-end\",\n \"list-filter-plus\",\n \"list-filter\",\n \"list-indent-decrease\",\n \"outdent\",\n \"indent-decrease\",\n \"list-indent-increase\",\n \"indent\",\n \"indent-increase\",\n \"list-minus\",\n \"list-music\",\n \"list-ordered\",\n \"list-plus\",\n \"list-restart\",\n \"list-start\",\n \"list-todo\",\n \"list-tree\",\n \"list-video\",\n \"list-x\",\n \"list\",\n \"loader-circle\",\n \"loader-2\",\n \"loader-pinwheel\",\n \"loader\",\n \"locate-fixed\",\n \"locate-off\",\n \"locate\",\n \"lock-keyhole-open\",\n \"unlock-keyhole\",\n \"lock-keyhole\",\n \"lock-open\",\n \"unlock\",\n \"lock\",\n \"log-in\",\n \"log-out\",\n \"logs\",\n \"lollipop\",\n \"luggage\",\n \"magnet\",\n \"mail-check\",\n \"mail-minus\",\n \"mail-open\",\n \"mail-plus\",\n \"mail-question-mark\",\n \"mail-question\",\n \"mail-search\",\n \"mail-warning\",\n \"mail-x\",\n \"mail\",\n \"mailbox\",\n \"mails\",\n \"map-minus\",\n \"map-pin-check-inside\",\n \"map-pin-check\",\n \"map-pin-house\",\n \"map-pin-minus-inside\",\n \"map-pin-minus\",\n \"map-pin-off\",\n \"map-pin-pen\",\n \"location-edit\",\n \"map-pin-plus-inside\",\n \"map-pin-plus\",\n \"map-pin-search\",\n \"map-pin-x-inside\",\n \"map-pin-x\",\n \"map-pin\",\n \"map-pinned\",\n \"map-plus\",\n \"map\",\n \"mars-stroke\",\n \"mars\",\n \"martini\",\n \"maximize-2\",\n \"maximize\",\n \"medal\",\n \"megaphone-off\",\n \"megaphone\",\n \"meh\",\n \"memory-stick\",\n \"menu\",\n \"merge\",\n \"message-circle-check\",\n \"message-circle-code\",\n \"message-circle-dashed\",\n \"message-circle-heart\",\n \"message-circle-more\",\n \"message-circle-off\",\n \"message-circle-plus\",\n \"message-circle-question-mark\",\n \"message-circle-question\",\n \"message-circle-reply\",\n \"message-circle-warning\",\n \"message-circle-x\",\n \"message-circle\",\n \"message-square-check\",\n \"message-square-code\",\n \"message-square-dashed\",\n \"message-square-diff\",\n \"message-square-dot\",\n \"message-square-heart\",\n \"message-square-lock\",\n \"message-square-more\",\n \"message-square-off\",\n \"message-square-plus\",\n \"message-square-quote\",\n \"message-square-reply\",\n \"message-square-share\",\n \"message-square-text\",\n \"message-square-warning\",\n \"message-square-x\",\n \"message-square\",\n \"messages-square\",\n \"metronome\",\n \"mic-off\",\n \"mic-vocal\",\n \"mic-2\",\n \"mic\",\n \"microchip\",\n \"microscope\",\n \"microwave\",\n \"milestone\",\n \"milk-off\",\n \"milk\",\n \"minimize-2\",\n \"minimize\",\n \"minus\",\n \"mirror-rectangular\",\n \"mirror-round\",\n \"monitor-check\",\n \"monitor-cloud\",\n \"monitor-cog\",\n \"monitor-dot\",\n \"monitor-down\",\n \"monitor-off\",\n \"monitor-pause\",\n \"monitor-play\",\n \"monitor-smartphone\",\n \"monitor-speaker\",\n \"monitor-stop\",\n \"monitor-up\",\n \"monitor-x\",\n \"monitor\",\n \"moon-star\",\n \"moon\",\n \"motorbike\",\n \"mountain-snow\",\n \"mountain\",\n \"mouse-left\",\n \"mouse-off\",\n \"mouse-pointer-2-off\",\n \"mouse-pointer-2\",\n \"mouse-pointer-ban\",\n \"mouse-pointer-click\",\n \"mouse-pointer\",\n \"mouse-right\",\n \"mouse\",\n \"move-3d\",\n \"move-3-d\",\n \"move-diagonal-2\",\n \"move-diagonal\",\n \"move-down-left\",\n \"move-down-right\",\n \"move-down\",\n \"move-horizontal\",\n \"move-left\",\n \"move-right\",\n \"move-up-left\",\n \"move-up-right\",\n \"move-up\",\n \"move-vertical\",\n \"move\",\n \"music-2\",\n \"music-3\",\n \"music-4\",\n \"music\",\n \"navigation-2-off\",\n \"navigation-2\",\n \"navigation-off\",\n \"navigation\",\n \"network\",\n \"newspaper\",\n \"nfc\",\n \"non-binary\",\n \"notebook-pen\",\n \"notebook-tabs\",\n \"notebook-text\",\n \"notebook\",\n \"notepad-text-dashed\",\n \"notepad-text\",\n \"nut-off\",\n \"nut\",\n \"octagon-alert\",\n \"alert-octagon\",\n \"octagon-minus\",\n \"octagon-pause\",\n \"pause-octagon\",\n \"octagon-x\",\n \"x-octagon\",\n \"octagon\",\n \"omega\",\n \"option\",\n \"orbit\",\n \"origami\",\n \"package-2\",\n \"package-check\",\n \"package-minus\",\n \"package-open\",\n \"package-plus\",\n \"package-search\",\n \"package-x\",\n \"package\",\n \"paint-bucket\",\n \"paint-roller\",\n \"paintbrush-vertical\",\n \"paintbrush-2\",\n \"paintbrush\",\n \"palette\",\n \"panda\",\n \"panel-bottom-close\",\n \"panel-bottom-dashed\",\n \"panel-bottom-inactive\",\n \"panel-bottom-open\",\n \"panel-bottom\",\n \"panel-left-close\",\n \"sidebar-close\",\n \"panel-left-dashed\",\n \"panel-left-inactive\",\n \"panel-left-open\",\n \"sidebar-open\",\n \"panel-left-right-dashed\",\n \"panel-left\",\n \"sidebar\",\n \"panel-right-close\",\n \"panel-right-dashed\",\n \"panel-right-inactive\",\n \"panel-right-open\",\n \"panel-right\",\n \"panel-top-bottom-dashed\",\n \"panel-top-close\",\n \"panel-top-dashed\",\n \"panel-top-inactive\",\n \"panel-top-open\",\n \"panel-top\",\n \"panels-left-bottom\",\n \"panels-right-bottom\",\n \"panels-top-left\",\n \"layout\",\n \"paperclip\",\n \"parentheses\",\n \"parking-meter\",\n \"party-popper\",\n \"pause\",\n \"paw-print\",\n \"pc-case\",\n \"pen-line\",\n \"edit-3\",\n \"pen-off\",\n \"pen-tool\",\n \"pen\",\n \"edit-2\",\n \"pencil-line\",\n \"pencil-off\",\n \"pencil-ruler\",\n \"pencil\",\n \"pentagon\",\n \"percent\",\n \"person-standing\",\n \"philippine-peso\",\n \"phone-call\",\n \"phone-forwarded\",\n \"phone-incoming\",\n \"phone-missed\",\n \"phone-off\",\n \"phone-outgoing\",\n \"phone\",\n \"pi\",\n \"piano\",\n \"pickaxe\",\n \"picture-in-picture-2\",\n \"picture-in-picture\",\n \"piggy-bank\",\n \"pilcrow-left\",\n \"pilcrow-right\",\n \"pilcrow\",\n \"pill-bottle\",\n \"pill\",\n \"pin-off\",\n \"pin\",\n \"pipette\",\n \"pizza\",\n \"plane-landing\",\n \"plane-takeoff\",\n \"plane\",\n \"play\",\n \"plug-2\",\n \"plug-zap\",\n \"plug-zap-2\",\n \"plug\",\n \"plus\",\n \"pocket-knife\",\n \"podcast\",\n \"pointer-off\",\n \"pointer\",\n \"popcorn\",\n \"popsicle\",\n \"pound-sterling\",\n \"power-off\",\n \"power\",\n \"presentation\",\n \"printer-check\",\n \"printer-x\",\n \"printer\",\n \"projector\",\n \"proportions\",\n \"puzzle\",\n \"pyramid\",\n \"qr-code\",\n \"quote\",\n \"rabbit\",\n \"radar\",\n \"radiation\",\n \"radical\",\n \"radio-off\",\n \"radio-receiver\",\n \"radio-tower\",\n \"radio\",\n \"radius\",\n \"rainbow\",\n \"rat\",\n \"ratio\",\n \"receipt-cent\",\n \"receipt-euro\",\n \"receipt-indian-rupee\",\n \"receipt-japanese-yen\",\n \"receipt-pound-sterling\",\n \"receipt-russian-ruble\",\n \"receipt-swiss-franc\",\n \"receipt-text\",\n \"receipt-turkish-lira\",\n \"receipt\",\n \"rectangle-circle\",\n \"rectangle-ellipsis\",\n \"form-input\",\n \"rectangle-goggles\",\n \"rectangle-horizontal\",\n \"rectangle-vertical\",\n \"recycle\",\n \"redo-2\",\n \"redo-dot\",\n \"redo\",\n \"refresh-ccw-dot\",\n \"refresh-ccw\",\n \"refresh-cw-off\",\n \"refresh-cw\",\n \"refrigerator\",\n \"regex\",\n \"remove-formatting\",\n \"repeat-1\",\n \"repeat-2\",\n \"repeat\",\n \"replace-all\",\n \"replace\",\n \"reply-all\",\n \"reply\",\n \"rewind\",\n \"ribbon\",\n \"road\",\n \"rocket\",\n \"rocking-chair\",\n \"roller-coaster\",\n \"rose\",\n \"rotate-3d\",\n \"rotate-3-d\",\n \"rotate-ccw-key\",\n \"rotate-ccw-square\",\n \"rotate-ccw\",\n \"rotate-cw-square\",\n \"rotate-cw\",\n \"route-off\",\n \"route\",\n \"router\",\n \"rows-2\",\n \"rows\",\n \"rows-3\",\n \"panels-top-bottom\",\n \"rows-4\",\n \"rss\",\n \"ruler-dimension-line\",\n \"ruler\",\n \"russian-ruble\",\n \"sailboat\",\n \"salad\",\n \"sandwich\",\n \"satellite-dish\",\n \"satellite\",\n \"saudi-riyal\",\n \"save-all\",\n \"save-off\",\n \"save\",\n \"scale-3d\",\n \"scale-3-d\",\n \"scale\",\n \"scaling\",\n \"scan-barcode\",\n \"scan-eye\",\n \"scan-face\",\n \"scan-heart\",\n \"scan-line\",\n \"scan-qr-code\",\n \"scan-search\",\n \"scan-text\",\n \"scan\",\n \"school\",\n \"scissors-line-dashed\",\n \"scissors\",\n \"scooter\",\n \"screen-share-off\",\n \"screen-share\",\n \"scroll-text\",\n \"scroll\",\n \"search-alert\",\n \"search-check\",\n \"search-code\",\n \"search-slash\",\n \"search-x\",\n \"search\",\n \"section\",\n \"send-horizontal\",\n \"send-horizonal\",\n \"send-to-back\",\n \"send\",\n \"separator-horizontal\",\n \"separator-vertical\",\n \"server-cog\",\n \"server-crash\",\n \"server-off\",\n \"server\",\n \"settings-2\",\n \"settings\",\n \"shapes\",\n \"share-2\",\n \"share\",\n \"sheet\",\n \"shell\",\n \"shelving-unit\",\n \"shield-alert\",\n \"shield-ban\",\n \"shield-check\",\n \"shield-cog-corner\",\n \"shield-cog\",\n \"shield-ellipsis\",\n \"shield-half\",\n \"shield-minus\",\n \"shield-off\",\n \"shield-plus\",\n \"shield-question-mark\",\n \"shield-question\",\n \"shield-user\",\n \"shield-x\",\n \"shield-close\",\n \"shield\",\n \"ship-wheel\",\n \"ship\",\n \"shirt\",\n \"shopping-bag\",\n \"shopping-basket\",\n \"shopping-cart\",\n \"shovel\",\n \"shower-head\",\n \"shredder\",\n \"shrimp\",\n \"shrink\",\n \"shrub\",\n \"shuffle\",\n \"sigma\",\n \"signal-high\",\n \"signal-low\",\n \"signal-medium\",\n \"signal-zero\",\n \"signal\",\n \"signature\",\n \"signpost-big\",\n \"signpost\",\n \"siren\",\n \"skip-back\",\n \"skip-forward\",\n \"skull\",\n \"slash\",\n \"slice\",\n \"sliders-horizontal\",\n \"sliders-vertical\",\n \"sliders\",\n \"smartphone-charging\",\n \"smartphone-nfc\",\n \"smartphone\",\n \"smile-plus\",\n \"smile\",\n \"snail\",\n \"snowflake\",\n \"soap-dispenser-droplet\",\n \"sofa\",\n \"solar-panel\",\n \"soup\",\n \"space\",\n \"spade\",\n \"sparkle\",\n \"sparkles\",\n \"stars\",\n \"speaker\",\n \"speech\",\n \"spell-check-2\",\n \"spell-check\",\n \"spline-pointer\",\n \"spline\",\n \"split\",\n \"spool\",\n \"sport-shoe\",\n \"spotlight\",\n \"spray-can\",\n \"sprout\",\n \"square-activity\",\n \"activity-square\",\n \"square-arrow-down-left\",\n \"arrow-down-left-square\",\n \"square-arrow-down-right\",\n \"arrow-down-right-square\",\n \"square-arrow-down\",\n \"arrow-down-square\",\n \"square-arrow-left\",\n \"arrow-left-square\",\n \"square-arrow-out-down-left\",\n \"arrow-down-left-from-square\",\n \"square-arrow-out-down-right\",\n \"arrow-down-right-from-square\",\n \"square-arrow-out-up-left\",\n \"arrow-up-left-from-square\",\n \"square-arrow-out-up-right\",\n \"arrow-up-right-from-square\",\n \"square-arrow-right-enter\",\n \"square-arrow-right-exit\",\n \"square-arrow-right\",\n \"arrow-right-square\",\n \"square-arrow-up-left\",\n \"arrow-up-left-square\",\n \"square-arrow-up-right\",\n \"arrow-up-right-square\",\n \"square-arrow-up\",\n \"arrow-up-square\",\n \"square-asterisk\",\n \"asterisk-square\",\n \"square-bottom-dashed-scissors\",\n \"scissors-square-dashed-bottom\",\n \"square-centerline-dashed-horizontal\",\n \"flip-horizontal\",\n \"square-centerline-dashed-vertical\",\n \"flip-vertical\",\n \"square-chart-gantt\",\n \"gantt-chart-square\",\n \"square-gantt-chart\",\n \"square-check-big\",\n \"check-square\",\n \"square-check\",\n \"check-square-2\",\n \"square-chevron-down\",\n \"chevron-down-square\",\n \"square-chevron-left\",\n \"chevron-left-square\",\n \"square-chevron-right\",\n \"chevron-right-square\",\n \"square-chevron-up\",\n \"chevron-up-square\",\n \"square-code\",\n \"code-square\",\n \"square-dashed-bottom-code\",\n \"square-dashed-bottom\",\n \"square-dashed-kanban\",\n \"kanban-square-dashed\",\n \"square-dashed-mouse-pointer\",\n \"mouse-pointer-square-dashed\",\n \"square-dashed-text\",\n \"text-selection\",\n \"text-select\",\n \"square-dashed-top-solid\",\n \"square-dashed\",\n \"box-select\",\n \"square-divide\",\n \"divide-square\",\n \"square-dot\",\n \"dot-square\",\n \"square-equal\",\n \"equal-square\",\n \"square-function\",\n \"function-square\",\n \"square-kanban\",\n \"kanban-square\",\n \"square-library\",\n \"library-square\",\n \"square-m\",\n \"m-square\",\n \"square-menu\",\n \"menu-square\",\n \"square-minus\",\n \"minus-square\",\n \"square-mouse-pointer\",\n \"inspect\",\n \"square-parking-off\",\n \"parking-square-off\",\n \"square-parking\",\n \"parking-square\",\n \"square-pause\",\n \"square-pen\",\n \"pen-box\",\n \"edit\",\n \"pen-square\",\n \"square-percent\",\n \"percent-square\",\n \"square-pi\",\n \"pi-square\",\n \"square-pilcrow\",\n \"pilcrow-square\",\n \"square-play\",\n \"play-square\",\n \"square-plus\",\n \"plus-square\",\n \"square-power\",\n \"power-square\",\n \"square-radical\",\n \"square-round-corner\",\n \"square-scissors\",\n \"scissors-square\",\n \"square-sigma\",\n \"sigma-square\",\n \"square-slash\",\n \"slash-square\",\n \"square-split-horizontal\",\n \"split-square-horizontal\",\n \"square-split-vertical\",\n \"split-square-vertical\",\n \"square-square\",\n \"square-stack\",\n \"square-star\",\n \"square-stop\",\n \"square-terminal\",\n \"terminal-square\",\n \"square-user-round\",\n \"user-square-2\",\n \"square-user\",\n \"user-square\",\n \"square-x\",\n \"x-square\",\n \"square\",\n \"squares-exclude\",\n \"squares-intersect\",\n \"squares-subtract\",\n \"squares-unite\",\n \"squircle-dashed\",\n \"squircle\",\n \"squirrel\",\n \"stamp\",\n \"star-half\",\n \"star-off\",\n \"star\",\n \"step-back\",\n \"step-forward\",\n \"stethoscope\",\n \"sticker\",\n \"sticky-note\",\n \"stone\",\n \"store\",\n \"stretch-horizontal\",\n \"stretch-vertical\",\n \"strikethrough\",\n \"subscript\",\n \"sun-dim\",\n \"sun-medium\",\n \"sun-moon\",\n \"sun-snow\",\n \"sun\",\n \"sunrise\",\n \"sunset\",\n \"superscript\",\n \"swatch-book\",\n \"swiss-franc\",\n \"switch-camera\",\n \"sword\",\n \"swords\",\n \"syringe\",\n \"table-2\",\n \"table-cells-merge\",\n \"table-cells-split\",\n \"table-columns-split\",\n \"table-of-contents\",\n \"table-properties\",\n \"table-rows-split\",\n \"table\",\n \"tablet-smartphone\",\n \"tablet\",\n \"tablets\",\n \"tag\",\n \"tags\",\n \"tally-1\",\n \"tally-2\",\n \"tally-3\",\n \"tally-4\",\n \"tally-5\",\n \"tangent\",\n \"target\",\n \"telescope\",\n \"tent-tree\",\n \"tent\",\n \"terminal\",\n \"test-tube-diagonal\",\n \"test-tube-2\",\n \"test-tube\",\n \"test-tubes\",\n \"text-align-center\",\n \"align-center\",\n \"text-align-end\",\n \"align-right\",\n \"text-align-justify\",\n \"align-justify\",\n \"text-align-start\",\n \"text\",\n \"align-left\",\n \"text-cursor-input\",\n \"text-cursor\",\n \"text-initial\",\n \"letter-text\",\n \"text-quote\",\n \"text-search\",\n \"text-wrap\",\n \"wrap-text\",\n \"theater\",\n \"thermometer-snowflake\",\n \"thermometer-sun\",\n \"thermometer\",\n \"thumbs-down\",\n \"thumbs-up\",\n \"ticket-check\",\n \"ticket-minus\",\n \"ticket-percent\",\n \"ticket-plus\",\n \"ticket-slash\",\n \"ticket-x\",\n \"ticket\",\n \"tickets-plane\",\n \"tickets\",\n \"timer-off\",\n \"timer-reset\",\n \"timer\",\n \"toggle-left\",\n \"toggle-right\",\n \"toilet\",\n \"tool-case\",\n \"toolbox\",\n \"tornado\",\n \"torus\",\n \"touchpad-off\",\n \"touchpad\",\n \"towel-rack\",\n \"tower-control\",\n \"toy-brick\",\n \"tractor\",\n \"traffic-cone\",\n \"train-front-tunnel\",\n \"train-front\",\n \"train-track\",\n \"tram-front\",\n \"train\",\n \"transgender\",\n \"trash-2\",\n \"trash\",\n \"tree-deciduous\",\n \"tree-palm\",\n \"palmtree\",\n \"tree-pine\",\n \"trees\",\n \"trending-down\",\n \"trending-up-down\",\n \"trending-up\",\n \"triangle-alert\",\n \"alert-triangle\",\n \"triangle-dashed\",\n \"triangle-right\",\n \"triangle\",\n \"trophy\",\n \"truck-electric\",\n \"truck\",\n \"turkish-lira\",\n \"turntable\",\n \"turtle\",\n \"tv-minimal-play\",\n \"tv-minimal\",\n \"tv-2\",\n \"tv\",\n \"type-outline\",\n \"type\",\n \"umbrella-off\",\n \"umbrella\",\n \"underline\",\n \"undo-2\",\n \"undo-dot\",\n \"undo\",\n \"unfold-horizontal\",\n \"unfold-vertical\",\n \"ungroup\",\n \"university\",\n \"school-2\",\n \"unlink-2\",\n \"unlink\",\n \"unplug\",\n \"upload\",\n \"usb\",\n \"user-check\",\n \"user-cog\",\n \"user-key\",\n \"user-lock\",\n \"user-minus\",\n \"user-pen\",\n \"user-plus\",\n \"user-round-check\",\n \"user-check-2\",\n \"user-round-cog\",\n \"user-cog-2\",\n \"user-round-key\",\n \"user-round-minus\",\n \"user-minus-2\",\n \"user-round-pen\",\n \"user-round-plus\",\n \"user-plus-2\",\n \"user-round-search\",\n \"user-round-x\",\n \"user-x-2\",\n \"user-round\",\n \"user-2\",\n \"user-search\",\n \"user-star\",\n \"user-x\",\n \"user\",\n \"users-round\",\n \"users-2\",\n \"users\",\n \"utensils-crossed\",\n \"fork-knife-crossed\",\n \"utensils\",\n \"fork-knife\",\n \"utility-pole\",\n \"van\",\n \"variable\",\n \"vault\",\n \"vector-square\",\n \"vegan\",\n \"venetian-mask\",\n \"venus-and-mars\",\n \"venus\",\n \"vibrate-off\",\n \"vibrate\",\n \"video-off\",\n \"video\",\n \"videotape\",\n \"view\",\n \"voicemail\",\n \"volleyball\",\n \"volume-1\",\n \"volume-2\",\n \"volume-off\",\n \"volume-x\",\n \"volume\",\n \"vote\",\n \"wallet-cards\",\n \"wallet-minimal\",\n \"wallet-2\",\n \"wallet\",\n \"wallpaper\",\n \"wand-sparkles\",\n \"wand-2\",\n \"wand\",\n \"warehouse\",\n \"washing-machine\",\n \"watch\",\n \"waves-arrow-down\",\n \"waves-arrow-up\",\n \"waves-ladder\",\n \"waves\",\n \"waypoints\",\n \"webcam\",\n \"webhook-off\",\n \"webhook\",\n \"weight-tilde\",\n \"weight\",\n \"wheat-off\",\n \"wheat\",\n \"whole-word\",\n \"wifi-cog\",\n \"wifi-high\",\n \"wifi-low\",\n \"wifi-off\",\n \"wifi-pen\",\n \"wifi-sync\",\n \"wifi-zero\",\n \"wifi\",\n \"wind-arrow-down\",\n \"wind\",\n \"wine-off\",\n \"wine\",\n \"workflow\",\n \"worm\",\n \"wrench\",\n \"x-line-top\",\n \"x\",\n \"zap-off\",\n \"zap\",\n \"zodiac-aquarius\",\n \"zodiac-aries\",\n \"zodiac-cancer\",\n \"zodiac-capricorn\",\n \"zodiac-gemini\",\n \"zodiac-leo\",\n \"zodiac-libra\",\n \"zodiac-ophiuchus\",\n \"zodiac-pisces\",\n \"zodiac-sagittarius\",\n \"zodiac-scorpio\",\n \"zodiac-taurus\",\n \"zodiac-virgo\",\n \"zoom-in\",\n \"zoom-out\",\n]);\n\nexport const LAYOUT_SECTION_ICON_SET: ReadonlySet<string> = new Set(LAYOUT_SECTION_ICONS);\nexport type LayoutSectionIcon = string;\n","/** Stable identifiers used by every project and page layout document. */\nexport const PAGE_CONTENT_ANCHOR_ID = \"page-content\" as const;\nexport const NAVIGATION_SECTION_ID = \"navigation\" as const;\nexport const FOOTER_SECTION_ID = \"footer\" as const;\n\n/** Locked transport/validation set shared by authoring surfaces and the server. */\nexport {\n LAYOUT_SECTION_ICONS,\n LAYOUT_SECTION_ICON_SET,\n type LayoutSectionIcon,\n} from \"./layout-lucide-icons.js\";\nimport type { LayoutSectionIcon } from \"./layout-lucide-icons.js\";\nimport { inWindow, type VisibilityWindow } from \"./block.js\";\n\nexport type LayoutZone = \"above-page-content\" | \"below-page-content\";\nexport type ReservedLayoutSection = \"navigation\" | \"footer\";\n\nexport type LayoutScalarFieldType =\n | \"text\"\n | \"longtext\"\n | \"richtext\"\n | \"number\"\n | \"toggle\"\n | \"date\"\n | \"image\"\n | \"file\"\n | \"link\"\n /** A call to action as one value, `{ label, href, variant? }`: what a page's `button` field holds. */\n | \"button\"\n | \"email\"\n | \"phone\"\n | \"select\"\n | \"color\"\n | \"json\"\n | \"reference\"\n | \"multi-reference\";\n\nexport type LayoutFieldType = LayoutScalarFieldType | \"group\" | \"repeater\";\n\n/** A recursive, stable-ID field contract shared by Sections and variant inputs. */\nexport interface LayoutFieldDefinition {\n id: string;\n slug: string;\n label: string;\n type: LayoutFieldType;\n required?: boolean;\n defaultValue?: unknown;\n config?: {\n options?: Array<{ label: string; value: string }>;\n referenceModelId?: string;\n minItems?: number;\n maxItems?: number;\n } & Record<string, unknown>;\n /** Required for group/repeater; forbidden for scalar fields. */\n fields?: LayoutFieldDefinition[];\n /** Shown to editors under the field. */\n helpText?: string;\n /** Server-owned: who wrote `helpText`. */\n helpSource?: \"auto\" | \"human\" | \"agent\";\n /** `true`: no route the last release inspected renders this field — hidden, never deleted. `false`: a person keeps it shown. */\n stale?: boolean;\n /** false: a page may not override this value; the Global value renders on every page. Absent = true. */\n overridable?: boolean;\n /** Shown where the page editor would have offered the field. Required when overridable is false. */\n lockReason?: string;\n}\n\n/** The canonical public input contract all variants in a group implement. */\nexport type CanonicalInputDefinition = LayoutFieldDefinition;\n\n/** Maps one canonical input onto one or more internal component prop paths. */\nexport interface VariantInputMapping {\n inputId: string;\n targets: Array<{ blockId: string; path: string }>;\n}\n\nexport interface ComponentVariantGroup {\n id: string;\n workspaceId: string;\n projectId?: string | null;\n name: string;\n slug: string;\n canonicalInputs: CanonicalInputDefinition[];\n status: \"draft\" | \"published\";\n}\n\nexport interface LayoutFieldItem {\n id: string;\n kind: \"field\";\n fieldId: string;\n}\n\nexport interface LayoutComponentItem {\n id: string;\n kind: \"component\";\n componentId: string;\n variantGroupId?: string;\n bindings: Array<{ inputId: string; fieldId: string }>;\n literalValues?: Record<string, unknown>;\n}\n\nexport type LayoutSectionItem = LayoutFieldItem | LayoutComponentItem;\n\nexport interface LayoutSection {\n id: string;\n name: string;\n slug: string;\n icon: string;\n zone: LayoutZone;\n orderKey: string;\n reserved?: ReservedLayoutSection;\n fields: LayoutFieldDefinition[];\n items: LayoutSectionItem[];\n /** What this Section is and which pages show it — for editors; no build reads it. */\n description?: string;\n /** Server-owned: who wrote `description`. */\n helpSource?: \"auto\" | \"human\" | \"agent\";\n /**\n * The language this Section is a VARIANT for — BCP-47, lowercase (`fr`, `pt-br`).\n *\n * A localized site renders ONE header per route, not two: `/fr/*` shows the French header in\n * the slot the base header holds everywhere else. So a variant is not a Section of its own in\n * the render order. It never renders unless a resolver is handed its locale, and then it takes\n * its base's place — zone, order and reserved slot included — rather than sitting beside it.\n * Set together with `variantOf`; `validateLayout` names every way the pair can be malformed.\n */\n locale?: string;\n /** The stable id of the base Section this variant replaces on routes in `locale`. */\n variantOf?: string;\n /**\n * When the Section is shown (an announcement bar, a seasonal band). Absent = always. It is the\n * SLOT's: a locale variant shows when its base does, whatever the variant's own row says.\n */\n window?: VisibilityWindow;\n}\n\nexport interface LayoutStructureDocument {\n version: 1;\n pageContentAnchor: { id: typeof PAGE_CONTENT_ANCHOR_ID };\n sections: LayoutSection[];\n}\n\nexport interface LayoutDataDocument {\n version: 1;\n sections: Record<string, { fields: Record<string, unknown> }>;\n}\n\nexport type PageLayoutOverrideState =\n | \"inherit\"\n | \"override-content\"\n | \"customize-structure\"\n | \"disable\";\n\nexport interface PageSectionPlacement {\n zone: LayoutZone;\n afterSectionId?: string;\n beforeSectionId?: string;\n localOrderKey: string;\n}\n\nexport type PageLayoutSectionOverride =\n | { sectionId: string; state: \"inherit\" }\n | { sectionId: string; state: \"override-content\"; values: Record<string, unknown> }\n | {\n sectionId: string;\n state: \"customize-structure\";\n section: LayoutSection;\n data: { fields: Record<string, unknown> };\n /** Retained when the inherited Section is later deleted. */\n placement: PageSectionPlacement;\n }\n | { sectionId: string; state: \"disable\" };\n\nexport interface PageOnlyLayoutSection {\n section: LayoutSection;\n data: { fields: Record<string, unknown> };\n placement: PageSectionPlacement;\n}\n\nexport type PageLayoutSectionStructureOverride =\n | { sectionId: string; state: \"inherit\" }\n | { sectionId: string; state: \"override-content\" }\n | { sectionId: string; state: \"customize-structure\"; section: LayoutSection; placement: PageSectionPlacement }\n | { sectionId: string; state: \"disable\" };\n\n/** Persisted in pages.layout_override_structure_json. */\nexport interface PageLayoutOverrideStructureDocument {\n version: 1;\n sections: PageLayoutSectionStructureOverride[];\n pageOnlySections: Array<{ section: LayoutSection; placement: PageSectionPlacement }>;\n}\n\n/** Persisted independently so values can be patched without rewriting structure. */\nexport interface PageLayoutOverrideDataDocument {\n version: 1;\n sections: Record<string, { fields: Record<string, unknown> }>;\n pageOnlySections: Record<string, { fields: Record<string, unknown> }>;\n}\n\n/** Canonical in-memory form consumed by the pure resolver. */\nexport interface PageLayoutOverrideDocument {\n version: 1;\n sections: PageLayoutSectionOverride[];\n pageOnlySections: PageOnlyLayoutSection[];\n}\n\n/** Canonical, discriminated Management/MCP authoring transport. Authority is derived from type. */\nexport type ManagementLayoutCommand =\n | { type: \"set-section-values\"; sectionId: string; values: Record<string, unknown> }\n | { type: \"set-field-value\"; sectionId: string; fieldId: string; value: unknown }\n | { type: \"add-component\"; sectionId: string; componentId: string; variantGroupId?: string; bindings?: LayoutComponentItem[\"bindings\"]; literalValues?: Record<string, unknown> }\n | { type: \"remove-item\"; sectionId: string; itemId: string }\n | { type: \"move-component\"; sectionId: string; itemId: string; index: number }\n | { type: \"move-item\"; sectionId: string; itemId: string; index: number }\n | { type: \"swap-component-variant\"; sectionId: string; itemId: string; componentId: string }\n | { type: \"set-page-state\"; sectionId: string; state: PageLayoutOverrideState | \"reset\" }\n | { type: \"set-section-state\"; sectionId: string; state: PageLayoutOverrideState | \"reset\" }\n | { type: \"add-section\"; name: string; icon: LayoutSectionIcon; zone: \"before_page\" | \"after_page\"; window?: VisibilityWindow }\n | { type: \"restore-section\"; section: LayoutSection; data: { fields: Record<string, unknown> }; placement?: PageSectionPlacement }\n | { type: \"update-section\"; sectionId: string; name?: string; icon?: LayoutSectionIcon; slug?: string; zone?: LayoutZone; orderKey?: string; description?: string; window?: VisibilityWindow | null }\n | { type: \"remove-section\"; sectionId: string }\n | { type: \"move-section\"; sectionId: string; afterId?: string | null; beforeId?: string | null }\n | { type: \"add-field\"; sectionId: string; parentFieldId?: string; field?: LayoutFieldDefinition; fieldType?: LayoutFieldType }\n | { type: \"update-field\"; sectionId: string; fieldId: string; patch: Partial<Omit<LayoutFieldDefinition, \"id\">> }\n | { type: \"remove-field\"; sectionId: string; fieldId: string }\n | { type: \"move-field\"; sectionId: string; itemId: string; index: number }\n | { type: \"set-bindings\"; sectionId: string; itemId: string; bindings: LayoutComponentItem[\"bindings\"]; literalValues?: Record<string, unknown> };\n\nexport type ResolvedLayoutNode =\n | { kind: \"page-content\"; id: typeof PAGE_CONTENT_ANCHOR_ID }\n | {\n kind: \"section\";\n id: string;\n section: LayoutSection;\n data: { fields: Record<string, unknown> };\n source: \"inherit\" | \"override-content\" | \"customize-structure\" | \"page-only\" | \"detached\";\n };\n\nexport interface DeliveredLayout {\n version: 1;\n nodes: Array<\n | { kind: \"page-content\"; id: typeof PAGE_CONTENT_ANCHOR_ID }\n | { kind: \"section\"; id: string; slug: string; name: string; source: Extract<ResolvedLayoutNode, { kind: \"section\" }>[\"source\"] }\n >;\n sections: Record<string, {\n id: string;\n slug: string;\n name: string;\n /**\n * Present ONLY on a locale variant (`LayoutSection.locale`/`variantOf`), so a base entry is\n * byte-identical to what it was before variants existed. The Global Layout delivers every\n * variant under its own slug beside the bases; a page delivers the variant its route's\n * locale swapped in, under the SLOT's slug — the one its `nodes` entry names.\n */\n locale?: string;\n variantOf?: string;\n /** Present only on a Section that has one. A published read never delivers a Section outside it. */\n window?: VisibilityWindow;\n fields: Record<string, unknown>;\n items: Array<\n | {\n id: string;\n kind: \"field\";\n fieldId: string;\n /** The stored value, unchanged. */\n value: unknown;\n /**\n * Present only when the field holds references: `value` with them hydrated (depth 1),\n * as Delivery serves an entry's (an entry → `{ id, slug, title, data, … }`, a page /\n * form / collection target → `{ kind, id, title, slug, url }`). A published read\n * resolves published targets only; one that did not resolve stays as stored.\n */\n resolved?: unknown;\n }\n | {\n id: string;\n kind: \"component\";\n componentId: string;\n variantGroupId?: string;\n canonicalInputs: CanonicalInputDefinition[];\n bindings: LayoutComponentItem[\"bindings\"];\n canonicalValues: Record<string, unknown>;\n resolvedProps: Record<string, unknown>;\n /**\n * `prop.key` → canonical `inputId` — the relation `resolvedProps` consumes and throws\n * away (`output[prop.key] = canonicalValues[mapping.inputId]`).\n *\n * Without it a renderer holds a component prop key and NO address: `logoAlt`/`links`/\n * `cta` are the component's own bare keys, and nothing relates them back to the layout\n * field a write must land on. With it the chain closes — `prop.key` → `inputId` →\n * (`bindings`, already delivered above) → `fieldId` → `set-field-value(sectionId,\n * fieldId)`. That is what makes global chrome click-to-edit (FLO-1179).\n *\n * Additive and always present (`{}` when the item has no variant mappings), so an\n * older consumer that ignores it is byte-identical to before.\n */\n propInputs: Record<string, string>;\n blocks: unknown[];\n }\n >;\n }>;\n}\n\n/**\n * A Layout structure as a visitor is served it at `now`: every Section outside its window\n * removed, and with a removed base its locale variants (a variant only ever renders in its base's\n * slot). The same document when nothing is removed, and anything that is not one as it came.\n */\nexport function visibleLayoutStructure<T>(structure: T, now: Date | number): T {\n const sections = (structure as { sections?: unknown } | null | undefined)?.sections;\n if (!Array.isArray(sections)) return structure;\n const hidden = new Set(\n (sections as LayoutSection[]).filter((section) => section && !section.variantOf && !inWindow(section, now)).map((section) => section.id),\n );\n if (hidden.size === 0) return structure;\n return {\n ...(structure as object),\n sections: (sections as LayoutSection[]).filter((section) => !hidden.has(section?.variantOf ?? section?.id)),\n } as T;\n}\n\n/**\n * A delivered Layout as a visitor is served it at `now`: the nodes whose Section is outside its\n * window removed, with their `sections` entries and any variant delivered beside a removed base.\n * Applied AFTER any cache, so a cached Layout never serves a Section past its boundary. The same\n * object when nothing is removed.\n */\nexport function visibleDeliveredLayout<T extends DeliveredLayout | null | undefined>(layout: T, now: Date | number): T {\n if (!layout) return layout;\n const hiddenIds = new Set<string>();\n const hiddenSlugs = new Set<string>();\n for (const node of layout.nodes) {\n if (node.kind !== \"section\" || inWindow(layout.sections[node.slug], now)) continue;\n hiddenIds.add(node.id);\n hiddenSlugs.add(node.slug);\n }\n if (hiddenIds.size === 0) return layout;\n return {\n ...layout,\n nodes: layout.nodes.filter((node) => node.kind !== \"section\" || !hiddenIds.has(node.id)),\n sections: Object.fromEntries(\n Object.entries(layout.sections).filter(([slug, section]) => !hiddenSlugs.has(slug) && !(section.variantOf && hiddenIds.has(section.variantOf))),\n ),\n } as T;\n}\n","/**\n * Generated by scripts/gen-dock-icon-names.mjs from the vendored icon tarball\n * (sha256 0691620e50bdf453c2fed06224d9dc52d521574ab254a149eba47664b92fb889)\n * and the vendored line-icon subset (sha256 06cd85d602d1104d962ed8ace64f6c4d64846ee50bd62bd328252c9d8f697b75).\n * Do not edit by hand: rerun the script (`--check` fails CI on drift).\n *\n * The closed vocabulary for `ui.icon` (field ui, fieldsets, prop ui.group). `as const` because a\n * z.enum needs the literal tuple; a `readonly string[]` would type every string as valid.\n */\nexport const DOCK_ICON_NAMES = [\n \"abc\",\n \"access-denied\",\n \"activity\",\n \"add\",\n \"add-circle\",\n \"add-comment\",\n \"add-document\",\n \"add-user\",\n \"address-book\",\n \"adjustments\",\n \"adjustments-horizontal\",\n \"alarm\",\n \"alert-triangle\",\n \"align-left\",\n \"api\",\n \"app-window\",\n \"apple\",\n \"apps\",\n \"archive\",\n \"arrow-back-up\",\n \"arrow-down\",\n \"arrow-guide\",\n \"arrow-left\",\n \"arrow-right\",\n \"arrow-top-right\",\n \"arrow-up\",\n \"arrows-diagonal\",\n \"arrows-down\",\n \"arrows-exchange\",\n \"arrows-horizontal\",\n \"arrows-left-right\",\n \"arrows-shuffle\",\n \"arrows-sort\",\n \"article\",\n \"aspect-ratio\",\n \"asterisk\",\n \"award\",\n \"axis-x\",\n \"backpack\",\n \"badge\",\n \"badge-cc\",\n \"badges\",\n \"bar-chart\",\n \"basket\",\n \"bell\",\n \"bill\",\n \"binary-document\",\n \"block-content\",\n \"block-element\",\n \"blockquote\",\n \"bold\",\n \"bolt\",\n \"book\",\n \"book-2\",\n \"bookmark\",\n \"bookmark-filled\",\n \"books\",\n \"bottle\",\n \"box\",\n \"brand-dribbble\",\n \"brand-facebook\",\n \"brand-instagram\",\n \"brand-linkedin\",\n \"brand-pinterest\",\n \"brand-tiktok\",\n \"brand-x\",\n \"brand-youtube\",\n \"briefcase\",\n \"broadcast\",\n \"browser\",\n \"bug\",\n \"building\",\n \"building-skyscraper\",\n \"building-store\",\n \"bulb-filled\",\n \"bulb-outline\",\n \"calculator\",\n \"calendar\",\n \"calendar-dollar\",\n \"calendar-event\",\n \"calendar-exclamation\",\n \"calendar-off\",\n \"calendar-plus\",\n \"calendar-star\",\n \"calendar-time\",\n \"camera\",\n \"campfire\",\n \"carousel-horizontal\",\n \"case\",\n \"cash\",\n \"category\",\n \"category-2\",\n \"chart-area\",\n \"chart-arrows\",\n \"chart-bar\",\n \"chart-bar-popular\",\n \"chart-donut\",\n \"chart-dots\",\n \"chart-line\",\n \"chart-upward\",\n \"check\",\n \"checkbox\",\n \"checklist\",\n \"checkmark\",\n \"checkmark-circle\",\n \"chef-hat\",\n \"chevron-down\",\n \"chevron-left\",\n \"chevron-right\",\n \"chevron-up\",\n \"chevrons-right\",\n \"circle\",\n \"circle-check\",\n \"circle-dot\",\n \"circle-number-1\",\n \"circle-plus\",\n \"click\",\n \"clipboard\",\n \"clipboard-image\",\n \"clipboard-text\",\n \"clock\",\n \"clock-check\",\n \"clock-hour-4\",\n \"close\",\n \"close-circle\",\n \"code\",\n \"code-block\",\n \"cog\",\n \"collapse\",\n \"color-wheel\",\n \"columns\",\n \"columns-2\",\n \"columns-3\",\n \"comment\",\n \"component\",\n \"compose\",\n \"compose-sparkles\",\n \"confetti\",\n \"controls\",\n \"cookie\",\n \"copy\",\n \"credit-card\",\n \"crop\",\n \"cube\",\n \"currency-dollar\",\n \"dashboard\",\n \"database\",\n \"database-search\",\n \"desktop\",\n \"device-desktop\",\n \"device-mobile\",\n \"device-tablet\",\n \"devices\",\n \"diamond\",\n \"discount\",\n \"document\",\n \"document-pdf\",\n \"document-remove\",\n \"document-sheet\",\n \"document-text\",\n \"document-video\",\n \"document-word\",\n \"document-zip\",\n \"documents\",\n \"door-exit\",\n \"dot\",\n \"double-chevron-down\",\n \"double-chevron-left\",\n \"double-chevron-right\",\n \"double-chevron-up\",\n \"double-quote\",\n \"download\",\n \"drag-handle\",\n \"drop\",\n \"droplet\",\n \"droplet-half\",\n \"earth-americas\",\n \"earth-globe\",\n \"edit\",\n \"egg\",\n \"ellipsis-horizontal\",\n \"ellipsis-vertical\",\n \"empty\",\n \"enter\",\n \"enter-right\",\n \"envelope\",\n \"equal\",\n \"error-filled\",\n \"error-outline\",\n \"error-screen\",\n \"expand\",\n \"eye-closed\",\n \"eye-off\",\n \"eye-open\",\n \"face-happy\",\n \"face-indifferent\",\n \"face-sad\",\n \"feather\",\n \"feedback\",\n \"file\",\n \"file-certificate\",\n \"file-code\",\n \"file-download\",\n \"file-text\",\n \"filter\",\n \"flag\",\n \"flame\",\n \"flask\",\n \"focus-2\",\n \"folder\",\n \"folders\",\n \"forms\",\n \"frame\",\n \"generate\",\n \"gift\",\n \"git-branch\",\n \"github\",\n \"grid-dots\",\n \"groq\",\n \"hammer\",\n \"hand-finger\",\n \"hanger\",\n \"hash\",\n \"headphones\",\n \"headset\",\n \"heart\",\n \"heart-filled\",\n \"heart-handshake\",\n \"help-circle\",\n \"highlight\",\n \"history\",\n \"home\",\n \"hourglass\",\n \"ice-cream\",\n \"id-badge\",\n \"id-badge-2\",\n \"image\",\n \"image-remove\",\n \"images\",\n \"inbox\",\n \"infinity\",\n \"info-circle\",\n \"info-filled\",\n \"info-outline\",\n \"info-square-rounded\",\n \"inline\",\n \"inline-element\",\n \"input-search\",\n \"insert-above\",\n \"insert-below\",\n \"italic\",\n \"joystick\",\n \"json\",\n \"language\",\n \"launch\",\n \"layout\",\n \"layout-align-center\",\n \"layout-board\",\n \"layout-board-split\",\n \"layout-bottombar\",\n \"layout-bottombar-expand\",\n \"layout-cards\",\n \"layout-columns\",\n \"layout-dashboard\",\n \"layout-grid\",\n \"layout-list\",\n \"layout-navbar\",\n \"layout-rows\",\n \"layout-sidebar\",\n \"layout-sidebar-right\",\n \"leaf\",\n \"leave\",\n \"lemon\",\n \"library-photo\",\n \"lifebuoy\",\n \"link\",\n \"link-removed\",\n \"linkedin\",\n \"list\",\n \"list-check\",\n \"list-details\",\n \"list-numbers\",\n \"list-tree\",\n \"lock\",\n \"logo-js\",\n \"logo-ts\",\n \"mail\",\n \"map-2\",\n \"map-pin\",\n \"map-pins\",\n \"marker\",\n \"marker-removed\",\n \"master-detail\",\n \"math-function\",\n \"meat\",\n \"menu\",\n \"message\",\n \"message-2\",\n \"message-check\",\n \"message-circle\",\n \"message-circle-2\",\n \"message-plus\",\n \"message-star\",\n \"microphone\",\n \"microphone-slash\",\n \"mobile-device\",\n \"mood-empty\",\n \"moon\",\n \"movie\",\n \"news\",\n \"notes\",\n \"number\",\n \"ok-hand\",\n \"olist\",\n \"overage\",\n \"package\",\n \"packages\",\n \"palette\",\n \"panel-left\",\n \"panel-right\",\n \"paperclip\",\n \"pause\",\n \"pencil\",\n \"phone\",\n \"photo\",\n \"photo-scan\",\n \"photo-search\",\n \"pig-money\",\n \"pin\",\n \"pin-filled\",\n \"pin-removed\",\n \"play\",\n \"player-play\",\n \"player-track-next\",\n \"playlist-add\",\n \"plug\",\n \"plug-connected\",\n \"plus-minus\",\n \"point\",\n \"presentation\",\n \"printer\",\n \"progress-50\",\n \"progress-75\",\n \"projects\",\n \"publish\",\n \"qrcode\",\n \"quote\",\n \"read-only\",\n \"receipt\",\n \"recycle\",\n \"redo\",\n \"refresh\",\n \"remove\",\n \"remove-circle\",\n \"repeat\",\n \"reset\",\n \"restore\",\n \"retrieve\",\n \"retry\",\n \"revert\",\n \"robot\",\n \"rocket\",\n \"rosette\",\n \"route\",\n \"ruler\",\n \"ruler-measure\",\n \"salad\",\n \"scale\",\n \"schema\",\n \"school\",\n \"search\",\n \"section\",\n \"select\",\n \"send\",\n \"server\",\n \"settings\",\n \"share\",\n \"shield-check\",\n \"shield-lock\",\n \"shopping-bag\",\n \"shopping-cart\",\n \"shopping-cart-plus\",\n \"signature\",\n \"sitemap\",\n \"slideshow\",\n \"sort\",\n \"sort-descending\",\n \"spacing-vertical\",\n \"sparkle\",\n \"sparkles\",\n \"speakerphone\",\n \"spinner\",\n \"split-horizontal\",\n \"split-vertical\",\n \"square\",\n \"stack\",\n \"stack-2\",\n \"stack-compact\",\n \"stairs\",\n \"stairs-up\",\n \"star\",\n \"star-filled\",\n \"stars\",\n \"stop\",\n \"strikethrough\",\n \"string\",\n \"subtask\",\n \"sun\",\n \"superscript\",\n \"sync\",\n \"table\",\n \"table-options\",\n \"tablet-device\",\n \"tag\",\n \"tags\",\n \"target\",\n \"task\",\n \"template\",\n \"tent\",\n \"terminal\",\n \"terminal-2\",\n \"text\",\n \"th-large\",\n \"th-list\",\n \"thumb-up\",\n \"thumbs-down\",\n \"thumbs-up\",\n \"ticket\",\n \"tiers\",\n \"timeline\",\n \"toggle-arrow-right\",\n \"toggle-right\",\n \"token\",\n \"tool\",\n \"tools-kitchen-2\",\n \"transfer\",\n \"translate\",\n \"trash\",\n \"trend-upward\",\n \"triangle-outline\",\n \"trolley\",\n \"truck\",\n \"truck-delivery\",\n \"truncate\",\n \"twitter\",\n \"typography\",\n \"ulist\",\n \"unarchive\",\n \"underline\",\n \"undo\",\n \"unknown\",\n \"unlink\",\n \"unlock\",\n \"unpublish\",\n \"upload\",\n \"user\",\n \"user-circle\",\n \"user-plus\",\n \"user-search\",\n \"user-star\",\n \"users\",\n \"users-group\",\n \"versions\",\n \"video\",\n \"vocabulary\",\n \"vs\",\n \"warning-filled\",\n \"warning-outline\",\n \"weight\",\n \"world\",\n \"wrench\",\n \"zoom-question\",\n] as const;\n\nexport type DockIconName = (typeof DOCK_ICON_NAMES)[number];\n\nexport const DOCK_ICON_NAME_SET: ReadonlySet<string> = new Set<string>(DOCK_ICON_NAMES);\n","/**\n * The dock's click budget, as ONE pure function both ends read (V9): the backend's next-steps\n * rules call it on live data, and the dashboard's reach test measures its RENDERED dock against the\n * golden this module emits (src/__tests__/fixtures/dock-budget.golden.json). No dependencies.\n *\n * A SCREEN is one navigation level of the dock, modelled on what the dock renders:\n * - `root` the lane's first screen: the page fields, a page section, or a component's props;\n * - `list` a repeatable's items, one branch hop below the row that opens it (a repeater, an\n * `array` with a repeatable zone, a `table` prop, `modular`);\n * - `item` one item of that list, a second hop. `modular` has no item screen: its items are\n * other models.\n * A non-repeatable zone (`group`, `array` + zones.nonRepeatable, a `group` prop) is NOT a screen.\n * It renders inline as a group, collapsed only when its own `ui.collapsed` is true. An array with\n * BOTH zones is that group with one more row, the branch that opens its list.\n *\n * On a screen:\n * - fieldsets with no `kind` are FLAT (V2): members render ungrouped, in document order;\n * - `kind:\"group\"` is a disclosure placed at its first member; `collapsed` costs 1 activation;\n * - `kind:\"row\"` is ONE leaf, however many members it holds;\n * - `kind:\"tab\"`, root screens only: a strip renders only with ≥2 non-empty tabs. Tab 1 is the\n * first panel, each later tab costs 1 activation, untabbed fields are PINNED above the strip,\n * and a group/row with `tab: <id>` sits in that tab. Below the root a tab reference is flat.\n * - component props join a group through `ui.group`; the first prop naming an id defines it.\n *\n * Budget, per screen (DOCK_BUDGET holds the limits):\n * - ungroupedLeaves: rows outside any group (a leaf, a row fieldset, a branch), as the max over\n * panels of pinned + panel. No picker term: tabs are capped at 3, so the strip never overflows.\n * - maxGroupLeaves: the largest group's own rows (a nested group counts in its own entry).\n * - depth: branch hops from the lane's root screen.\n * - maxActivations: the dearest value on the screen counted from the lane's root: +1 per branch\n * hop, +1 per collapsed group, +1 for a non-first tab. A screen with no values costs its entry.\n */\n\nexport const DOCK_BUDGET = { ungrouped: 8, group: 12, depth: 3, activations: 2 } as const;\n\nexport type DockLane = \"page-fields\" | \"page-section\" | \"component\";\n\nexport interface DockBudget {\n ungroupedLeaves: number;\n maxGroupLeaves: number;\n depth: number;\n maxActivations: number;\n}\n\n/** One row on a screen. Keys are paths from the screen's own fields (`hero.title`). */\nexport type DockNode =\n | { kind: \"leaf\"; key: string }\n | { kind: \"row\"; id: string; keys: string[] }\n | { kind: \"branch\"; key: string }\n | { kind: \"group\"; id: string; collapsed: boolean; nodes: DockNode[] };\n\nexport interface DockScreen {\n /** `<lane>`, then `/<branch key>` per list and `/item` per item: `page-fields/quotes/item`. */\n id: string;\n lane: DockLane;\n kind: \"root\" | \"list\" | \"item\";\n title: string;\n depth: number;\n /** Activations spent reaching this screen from the lane's root. */\n entry: number;\n pinned: DockNode[];\n /** One panel per tab, in fieldset order. Empty when no strip renders. */\n tabs: DockNode[][];\n}\n\n/** The structural subset of a model field or component prop that this module reads. */\nexport interface DockFieldLike {\n key: string;\n label?: string;\n type: string;\n fieldsetId?: string;\n ui?: { collapsed?: boolean; group?: DockPropGroupLike } | null;\n config?: unknown;\n /** Legacy `group`/`repeater` children, and a component sub-field's own children. */\n fields?: DockFieldLike[];\n}\n\nexport interface DockFieldsetLike {\n id: string;\n name?: string;\n kind?: \"group\" | \"row\" | \"tab\";\n collapsed?: boolean;\n tab?: string;\n}\n\nexport interface DockPropGroupLike {\n id: string;\n label?: string;\n kind?: \"group\" | \"row\";\n collapsed?: boolean;\n}\n\ntype Config = {\n fields?: DockFieldLike[];\n zones?: { nonRepeatable?: DockFieldLike[]; repeatable?: { fields?: DockFieldLike[] } };\n};\n\n/** A repeatable's item fields (null: no item screen), or undefined when the field is no list. */\nfunction listItems(f: DockFieldLike): DockFieldLike[] | null | undefined {\n const c = (f.config ?? {}) as Config;\n if (f.type === \"repeater\") return f.fields ?? [];\n if (f.type === \"table\") return c.fields ?? f.fields ?? [];\n if (f.type === \"array\" && c.zones?.repeatable) return c.zones.repeatable.fields ?? [];\n if (f.type === \"modular\" || f.type === \"slot\") return null;\n return undefined;\n}\n\n/** An inline zone's fields, or undefined when the field is not one. */\nfunction zoneFields(f: DockFieldLike): DockFieldLike[] | undefined {\n const c = (f.config ?? {}) as Config;\n // A V2 `object` (a prop or a model field) is one nested object, laid out inline as a group is.\n if (f.type === \"group\" || f.type === \"object\") return c.fields ?? f.fields ?? [];\n if (f.type === \"array\" && c.zones?.nonRepeatable) return c.zones.nonRepeatable;\n return undefined;\n}\n\ninterface Branch {\n key: string;\n field: DockFieldLike;\n items: DockFieldLike[] | null;\n}\n\n/**\n * Lay one sibling level out into pinned rows and tab panels. `branches` collects every branch row\n * with the in-screen cost of reaching it, so the caller can open its screens.\n */\nfunction layout(\n fields: DockFieldLike[],\n fieldsets: DockFieldsetLike[],\n root: boolean,\n): { pinned: DockNode[]; tabs: DockNode[][]; branches: Map<string, Branch> } {\n const byId = new Map(fieldsets.map((s) => [s.id, s]));\n const tabIds = root ? fieldsets.filter((s) => s.kind === \"tab\").map((s) => s.id) : [];\n const tabOf = (s: DockFieldsetLike | undefined): string | undefined =>\n s?.kind === \"tab\" ? s.id : s?.tab !== undefined && byId.get(s.tab)?.kind === \"tab\" ? s.tab : undefined;\n const nonEmpty = new Set(\n fields.map((f) => tabOf(byId.get(f.fieldsetId ?? \"\"))).filter((t) => t && tabIds.includes(t)),\n );\n const strip = nonEmpty.size >= 2;\n\n const branches = new Map<string, Branch>();\n const nodeFor = (f: DockFieldLike, path: string): DockNode => {\n const key = `${path}${f.key}`;\n const zone = zoneFields(f);\n const items = listItems(f);\n if (zone) {\n const nodes = zone.map((z) => nodeFor(z, `${key}.`));\n // An array with BOTH zones: its list opens from a row inside its group, so it is measured too.\n if (zone.length > 0 && items?.length) {\n branches.set(key, { key, field: f, items });\n nodes.push({ kind: \"branch\", key });\n }\n return { kind: \"group\", id: key, collapsed: f.ui?.collapsed === true, nodes };\n }\n if (items !== undefined) {\n branches.set(key, { key, field: f, items });\n return { kind: \"branch\", key };\n }\n return { kind: \"leaf\", key };\n };\n\n const pinned: DockNode[] = [];\n const panels = new Map<string, DockNode[]>(strip ? tabIds.filter((t) => nonEmpty.has(t)).map((t) => [t, []]) : []);\n const containers = new Map<string, DockNode>();\n for (const f of fields) {\n const node = nodeFor(f, \"\");\n const set = byId.get(f.fieldsetId ?? \"\");\n const target = (strip && panels.get(tabOf(set) ?? \"\")) || pinned;\n if (set?.kind !== \"group\" && set?.kind !== \"row\") {\n target.push(node);\n continue;\n }\n let box = containers.get(set.id);\n if (!box) {\n box =\n set.kind === \"row\"\n ? { kind: \"row\", id: set.id, keys: [] }\n : { kind: \"group\", id: set.id, collapsed: set.collapsed === true, nodes: [] };\n containers.set(set.id, box);\n target.push(box);\n }\n if (box.kind === \"row\") box.keys.push(f.key);\n else if (box.kind === \"group\") box.nodes.push(node);\n }\n return { pinned, tabs: [...panels.values()], branches };\n}\n\n/** Cheapest in-screen cost of each value and branch row, keyed by node key. */\nfunction walkCosts(screen: DockScreen): { values: number[]; branchCost: Map<string, number> } {\n const values: number[] = [];\n const branchCost = new Map<string, number>();\n const walk = (nodes: DockNode[], cost: number): void => {\n for (const n of nodes) {\n if (n.kind === \"group\") walk(n.nodes, cost + (n.collapsed ? 1 : 0));\n else if (n.kind === \"branch\") branchCost.set(n.key, cost);\n else values.push(cost);\n }\n };\n walk(screen.pinned, 0);\n screen.tabs.forEach((panel, i) => walk(panel, i === 0 ? 0 : 1));\n return { values, branchCost };\n}\n\n/**\n * Every screen of one lane, root first. Pass `props` for a component lane (its `fields` and\n * `fieldsets` are then ignored): a prop's `ui.group` becomes the fieldset it joins.\n */\nexport function dockScreens(\n source: { fields?: DockFieldLike[] | null; fieldsets?: DockFieldsetLike[] | null },\n lane: DockLane,\n props?: DockFieldLike[] | null,\n): DockScreen[] {\n let fields = source.fields ?? [];\n let fieldsets = source.fieldsets ?? [];\n if (props) {\n fieldsets = [];\n fields = props.map((p) => {\n const g = p.ui?.group;\n if (!g) return p;\n if (!fieldsets.some((s) => s.id === g.id)) {\n fieldsets.push({ id: g.id, name: g.label, kind: g.kind ?? \"group\", collapsed: g.collapsed });\n }\n return { ...p, fieldsetId: g.id };\n });\n }\n\n const screens: DockScreen[] = [];\n const open = (\n id: string,\n kind: DockScreen[\"kind\"],\n title: string,\n depth: number,\n entry: number,\n level: DockFieldLike[] | null,\n ): void => {\n const laid = level ? layout(level, fieldsets, kind === \"root\") : null;\n const screen: DockScreen = {\n id,\n lane,\n kind,\n title,\n depth,\n entry,\n pinned: laid?.pinned ?? [],\n tabs: laid?.tabs ?? [],\n };\n screens.push(screen);\n if (!laid) return;\n const { branchCost } = walkCosts(screen);\n for (const b of laid.branches.values()) {\n const listId = `${id}/${b.key}`;\n const listEntry = entry + (branchCost.get(b.key) ?? 0) + 1;\n const label = b.field.label ?? b.field.key;\n open(listId, \"list\", label, depth + 1, listEntry, null);\n if (b.items) open(`${listId}/item`, \"item\", `${label} item`, depth + 2, listEntry + 1, b.items);\n }\n };\n open(lane, \"root\", lane === \"component\" ? \"Component\" : lane === \"page-fields\" ? \"Page fields\" : \"Section\", 0, 0, fields);\n return screens;\n}\n\nexport function dockBudget(screen: DockScreen): DockBudget {\n const rows = (nodes: DockNode[]): number => nodes.filter((n) => n.kind !== \"group\").length;\n let maxGroupLeaves = 0;\n const groups = (nodes: DockNode[]): void => {\n for (const n of nodes) {\n if (n.kind !== \"group\") continue;\n maxGroupLeaves = Math.max(maxGroupLeaves, rows(n.nodes));\n groups(n.nodes);\n }\n };\n groups(screen.pinned);\n screen.tabs.forEach(groups);\n const pinned = rows(screen.pinned);\n const { values } = walkCosts(screen);\n return {\n ungroupedLeaves: screen.tabs.length ? Math.max(...screen.tabs.map((p) => pinned + rows(p))) : pinned,\n maxGroupLeaves,\n depth: screen.depth,\n maxActivations: screen.entry + (values.length ? Math.max(...values) : 0),\n };\n}\n","/**\n * THE button-link pairing rule, pure: which two sibling fields render as ONE button unit (the words\n * on the button + where it goes). The dashboard folds them together; the backend refuses a write\n * that splits such a pair across fieldsets (`pair_split`). One copy, so both ends agree.\n *\n * Presentation only: a pair keeps its own keys, values and writers.\n *\n * 1. A key is split into words whatever its spelling (`hero_cta_label`, `ctaText`, `button-link`);\n * a dotted path counts only its last segment.\n * 2. The LAST word is the role: `label text title cta button btn name` are TEXT roles, `href link\n * url to` LINK roles. Everything before it is the STEM.\n * 3. A text candidate is a text-typed field (`text`, `string`) with a text role. A key that is a\n * button noun (`cta`, `primaryButton`) also offers its full key as a stem.\n * 4. A link candidate is a link-typed field (`link`, `url`), or a text-typed field with a link role\n * that is not a media address (`image_url`). A link-typed field whose last word is not a link\n * role offers both its stem and its full key.\n * 5. Two fields pair when their stem holds EXACTLY one text and one link candidate. Three or more\n * candidates on a stem: none pair. A field that would pair two ways pairs neither way.\n *\n * 0. Before all of that, an importer's spelling pairs outright (@see derivedPairs):\n * `<stem>-href` (link-typed) with the one text keyed `<stem>`, or `<stem>` with its tag swapped.\n *\n * When the key's words say nothing, the visible LABEL is read the same way, its stems namespaced\n * (`label:`) so a label reading only ever meets another label reading.\n */\n\nconst TEXT_ROLES: ReadonlySet<string> = new Set([\"label\", \"text\", \"title\", \"cta\", \"button\", \"btn\", \"name\"]);\nconst LINK_ROLES: ReadonlySet<string> = new Set([\"href\", \"link\", \"url\", \"to\"]);\nconst BUTTON_NOUNS: ReadonlySet<string> = new Set([\"cta\", \"button\", \"btn\"]);\nconst TEXT_TYPES: ReadonlySet<string> = new Set([\"text\", \"string\"]);\nconst LINK_TYPES: ReadonlySet<string> = new Set([\"link\", \"url\"]);\nconst MEDIA = /image|img|photo|video|avatar|logo|icon|thumb|poster|embed|src|og|favicon/i;\n\n/** What the rule needs to know about one field. */\nexport interface ButtonLinkCandidate {\n key: string;\n type?: string;\n label?: string;\n /** The current value, when known: a structured value never pairs as text. */\n value?: unknown;\n}\n\n/** `hero_cta_primary_label` / `ctaText` / `primaryButton-link` → lowercase words. */\nexport function keyWords(key: string): string[] {\n const leaf = key.split(\".\").pop() ?? \"\";\n return leaf\n .replace(/([a-z\\d])([A-Z])/g, \"$1 $2\")\n .replace(/([A-Z]+)([A-Z][a-z])/g, \"$1 $2\")\n .split(/[\\s_-]+/)\n .filter(Boolean)\n .map((word) => word.toLowerCase());\n}\n\ntype Role = { role: \"text\" | \"link\"; stems: string[] };\n\nfunction roleFromWords(candidate: ButtonLinkCandidate, words: string[]): Role | null {\n const type = (candidate.type ?? \"\").toLowerCase();\n const value = candidate.value;\n if (!(value === undefined || value === null || typeof value === \"string\")) return null;\n if (!words.length) return null;\n const last = words[words.length - 1]!;\n const stem = words.slice(0, -1).join(\"_\");\n const full = words.join(\"_\");\n if (LINK_TYPES.has(type)) return { role: \"link\", stems: LINK_ROLES.has(last) ? [stem] : [stem, full] };\n if (!TEXT_TYPES.has(type)) return null;\n if (LINK_ROLES.has(last)) {\n if (MEDIA.test(candidate.key) || MEDIA.test(candidate.label ?? \"\")) return null;\n return { role: \"link\", stems: [stem] };\n }\n if (TEXT_ROLES.has(last)) return { role: \"text\", stems: BUTTON_NOUNS.has(last) ? [stem, full] : [stem] };\n return null;\n}\n\n/** The role one field plays, with every stem it offers, or null. */\nexport function candidateRole(candidate: ButtonLinkCandidate): Role | null {\n const fromKey = roleFromWords(candidate, keyWords(candidate.key));\n if (fromKey) return fromKey;\n const label = candidate.label?.trim();\n if (!label) return null;\n const fromLabel = roleFromWords(candidate, keyWords(label.replace(/\\s+/g, \"_\")));\n return fromLabel ? { role: fromLabel.role, stems: fromLabel.stems.map((stem) => `label:${stem}`) } : null;\n}\n\n/** Element words an importer writes into a key: the tag the copy sat in, never part of its name. */\nconst TAG_SEGMENTS: ReadonlySet<string> = new Set([\"a\", \"span\", \"button\", \"div\", \"strong\"]);\n\nconst isScalarText = (value: unknown): boolean => value === undefined || value === null || typeof value === \"string\";\n\n/**\n * The pairs an IMPORTER's spelling names outright, before any role is read.\n *\n * Derive keys a call to action by the element it found it in: `equip-a-start-exploring-href` (link)\n * beside `equip-span-start-exploring` (text). Neither key ends in a role word, so the role pass\n * cannot pair them. Here a link-typed `<stem>-href` / `<stem>_href` pairs with the ONE text field\n * keyed `<stem>`, or `<stem>` with exactly one tag segment (a/span/button/div/strong) swapped for\n * another. Two candidate texts: none pairs.\n */\nexport function derivedPairs(candidates: readonly ButtonLinkCandidate[]): Map<number, { pair: string; role: \"text\" | \"link\" }> {\n const out = new Map<number, { pair: string; role: \"text\" | \"link\" }>();\n const leaf = (key: string) => key.split(\".\").pop() ?? \"\";\n const isText = (c: ButtonLinkCandidate) =>\n TEXT_TYPES.has((c.type ?? \"\").toLowerCase()) && isScalarText(c.value) && !/[-_]href$/i.test(leaf(c.key));\n const sameButTag = (a: string, b: string) => {\n if (a === b) return true;\n const x = a.split(/[-_]/);\n const y = b.split(/[-_]/);\n if (x.length !== y.length) return false;\n let swapped = 0;\n for (let i = 0; i < x.length; i++) {\n if (x[i] === y[i]) continue;\n if (!TAG_SEGMENTS.has(x[i]!) || !TAG_SEGMENTS.has(y[i]!)) return false;\n swapped++;\n }\n return swapped === 1;\n };\n candidates.forEach((link, linkIndex) => {\n if (out.has(linkIndex) || !LINK_TYPES.has((link.type ?? \"\").toLowerCase()) || !isScalarText(link.value)) return;\n const key = leaf(link.key);\n const suffix = /[-_]href$/i.exec(key);\n if (!suffix) return;\n const stem = key.slice(0, suffix.index);\n const parent = link.key.slice(0, link.key.length - key.length);\n const texts = candidates\n .map((text, textIndex) => ({ text, textIndex }))\n .filter(\n ({ text, textIndex }) =>\n textIndex !== linkIndex &&\n !out.has(textIndex) &&\n isText(text) &&\n text.key.startsWith(parent) &&\n sameButTag(leaf(text.key), stem),\n );\n if (texts.length !== 1) return;\n const pair = `${texts[0]!.textIndex}:${linkIndex}`;\n out.set(texts[0]!.textIndex, { pair, role: \"text\" });\n out.set(linkIndex, { pair, role: \"link\" });\n });\n return out;\n}\n\n/** Every unambiguous pair in one sibling list, as `[textIndex, linkIndex]`, in list order. */\nexport function buttonLinkPairs(candidates: readonly ButtonLinkCandidate[]): Array<[number, number]> {\n const derived = derivedPairs(candidates);\n const roles = candidates.map((candidate, index) => {\n const half = derived.get(index);\n return half ? { role: half.role, stems: [`derived:${half.pair}`] } : candidateRole(candidate);\n });\n const byStem = new Map<string, { text: Set<number>; link: Set<number> }>();\n roles.forEach((role, index) => {\n if (!role) return;\n for (const stem of new Set(role.stems)) {\n const bucket = byStem.get(stem) ?? { text: new Set<number>(), link: new Set<number>() };\n bucket[role.role].add(index);\n byStem.set(stem, bucket);\n }\n });\n\n const ambiguous = new Set<number>();\n const proposals = new Map<string, [number, number]>();\n for (const bucket of byStem.values()) {\n if (bucket.text.size + bucket.link.size >= 3) {\n for (const index of [...bucket.text, ...bucket.link]) ambiguous.add(index);\n continue;\n }\n if (bucket.text.size === 1 && bucket.link.size === 1) {\n const pair: [number, number] = [[...bucket.text][0]!, [...bucket.link][0]!];\n proposals.set(pair.join(\":\"), pair);\n }\n }\n\n const uses = new Map<number, number>();\n for (const [text, link] of proposals.values()) {\n uses.set(text, (uses.get(text) ?? 0) + 1);\n uses.set(link, (uses.get(link) ?? 0) + 1);\n }\n return [...proposals.values()]\n .filter(([t, l]) => !ambiguous.has(t) && !ambiguous.has(l) && uses.get(t) === 1 && uses.get(l) === 1)\n .sort((a, b) => Math.min(...a) - Math.min(...b));\n}\n","/**\n * A button block's LOOK beyond size: its variant, an optional leading icon and an optional\n * trailing arrow. The ONE source of the names: the renderer draws from it, the validation schema\n * allow-lists from it, and the dashboard's copy is pinned to it by a parity test.\n *\n * <a class=\"bcms-btn bcms-btn-{variant}\">[<svg class=\"bcms-btn-icon\">]Text[<svg class=\"bcms-btn-arrow\">]</a>\n *\n * Icons are the BetterCMS icon set (`@bettercms-ai/icons`, 472 icons): the same names a field's\n * `ui.icon` takes (`DOCK_ICON_NAMES`), drawn from its plain-SVG `markup` export, so the hosted\n * renderer, the SDKs and the dashboard's picker all draw the same artwork.\n */\nimport { ICON_MARKUP, iconSvg } from \"@bettercms-ai/icons/markup\";\nimport { DOCK_ICON_NAMES, DOCK_ICON_NAME_SET, type DockIconName } from \"./dock-icon-names.js\";\nimport { LINK_RELS, isLinkObject, isScriptHref, linkAnchorOf, linkHref, linkValueProblem, type LinkRel, type LinkValue } from \"./link-value.js\";\n\nexport { LINK_RELS, type LinkRel };\n\nexport const BUTTON_VARIANTS = [\"primary\", \"secondary\", \"tertiary\", \"brand\", \"dark\", \"light\", \"outline\", \"link\"] as const;\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number];\n\n/** Each icon's inner SVG markup (viewBox `0 0 25 25`), by name. */\nexport const BUTTON_ICONS: Readonly<Record<DockIconName, string>> = ICON_MARKUP;\nexport type ButtonIcon = DockIconName;\nexport const BUTTON_ICON_NAMES = DOCK_ICON_NAMES;\n\n/** A stored variant as it renders: anything off the list is Primary. */\nexport function buttonVariantOf(value: unknown): ButtonVariant {\n return BUTTON_VARIANTS.includes(value as ButtonVariant) ? (value as ButtonVariant) : \"primary\";\n}\n\n/**\n * How an IMPORTED site draws one look of its Button family: the classes its own stylesheet PAINTS\n * the look by, the `data-variant` it keys the look on when it uses one, and the paint classes of\n * every other spelling of the same look (`also`), which a publish takes off the anchor with the rest.\n * A look comes in sizes: `size` are the classes that size its most-used spelling and `sizeAlso`\n * those of the others. A publish leaves a button's size classes on it and adds `size` only to a\n * button that has none. Measured from the built site and stored on the look's button block as\n * `props.siteLook`.\n */\nexport interface ButtonSiteLook {\n classes: string[];\n attrs?: { \"data-variant\"?: string };\n also?: string[];\n size?: string[];\n sizeAlso?: string[];\n}\n\n/** A class token as a publish may write it onto an anchor. */\nconst SITE_CLASS = /^[^\\s\"'<>`=]{1,64}$/;\nconst LOOK_VALUE = /^[a-z0-9][a-z0-9-]{0,63}$/;\n\n/** A button block's `props.siteLook`, read defensively: null when it names nothing to paint with. */\nexport function buttonSiteLookOf(value: unknown): ButtonSiteLook | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const v = value as { classes?: unknown; attrs?: Record<string, unknown>; also?: unknown; size?: unknown; sizeAlso?: unknown };\n const tokens = (list: unknown): string[] => (Array.isArray(list) ? list.filter((c): c is string => typeof c === \"string\" && SITE_CLASS.test(c)) : []);\n const variant = v.attrs?.[\"data-variant\"];\n const classes = tokens(v.classes);\n const also = tokens(v.also);\n const size = tokens(v.size);\n const sizeAlso = tokens(v.sizeAlso);\n const attrs = typeof variant === \"string\" && LOOK_VALUE.test(variant) ? { \"data-variant\": variant } : undefined;\n if (classes.length === 0 && !attrs) return null;\n return {\n classes,\n ...(attrs ? { attrs } : {}),\n ...(also.length ? { also } : {}),\n ...(size.length ? { size } : {}),\n ...(sizeAlso.length ? { sizeAlso } : {}),\n };\n}\n\n/**\n * The value a `button` stores to pick one look of the project's Button family: what the site's own\n * `data-variant` calls the look when it keys on one, the look's component slug otherwise. A\n * publish writes it back as the anchor's `data-variant`.\n */\nexport function buttonLookValue(slug: string, siteLook: ButtonSiteLook | null): string {\n return siteLook?.attrs?.[\"data-variant\"] ?? slug;\n}\n\n/** Is this a value that could name a family look (or one of the fixed names)? */\nexport function isButtonLookValue(value: unknown): value is string {\n return typeof value === \"string\" && LOOK_VALUE.test(value);\n}\n\n/** A stored icon as it renders: anything off the list is no icon. */\nexport function buttonIconOf(value: unknown): ButtonIcon | null {\n return typeof value === \"string\" && DOCK_ICON_NAME_SET.has(value) ? (value as ButtonIcon) : null;\n}\n\n/** One icon as inline SVG sized to the button's text, hidden from assistive tech (the label names the button). */\nexport function buttonIconSvg(name: ButtonIcon, cls: \"bcms-btn-icon\" | \"bcms-btn-arrow\"): string {\n return iconSvg(name, cls);\n}\n\n// ── The `button` field type: one button as one value ─────────────────────────────────────────\n\nexport const BUTTON_SIZES = [\"sm\", \"md\", \"lg\"] as const;\nexport type ButtonSizeName = (typeof BUTTON_SIZES)[number];\n\n/**\n * The value a `button` field stores: the words, the link and the look, as Sanity stores a button\n * object. Only `label` and `href` are required; every look key is optional and absent reads as\n * today's default (Primary, medium, no arrow, no icon, same tab).\n */\n/**\n * The target and rel attributes of an anchor, as one string. A new tab keeps the `noopener\n * noreferrer` pair; a link relation joins it in the SAME rel attribute, so an anchor never\n * carries two.\n */\nexport function anchorTargetRel(newTab: boolean, rel?: unknown): string {\n const tokens = [...(newTab ? [\"noopener\", \"noreferrer\"] : []), ...(LINK_RELS.includes(rel as LinkRel) ? [rel as string] : [])];\n return `${newTab ? ' target=\"_blank\"' : \"\"}${tokens.length ? ` rel=\"${tokens.join(\" \")}\"` : \"\"}`;\n}\n\n/**\n * What a button does when the site's own code decides it: `<button type=\"button\">` opening a\n * dialog, accepting cookies, starting a tour. Such a button has no destination to store, so the\n * value says so outright instead of carrying an empty href nobody can tell from a forgotten one.\n */\nexport const BUTTON_ACTIONS = [\"code\"] as const;\nexport type ButtonAction = (typeof BUTTON_ACTIONS)[number];\n\n/** Is this stored value a button whose action is the site's code (no href, never an anchor)? */\nexport function isCodeButton(value: unknown): boolean {\n return !!value && typeof value === \"object\" && (value as { action?: unknown }).action === \"code\";\n}\n\nexport interface ButtonValue {\n label: string;\n /**\n * A plain href, or a link object (@see LinkValue) whose newTab / rel apply when the button sets\n * none. Absent (or empty) only beside `action: \"code\"`.\n */\n href?: string | LinkValue;\n /** `\"code\"`: the click is the site's own script. The label and the look are edited; no href, no new tab, no rel. */\n action?: ButtonAction;\n variant?: ButtonVariant;\n size?: ButtonSizeName;\n arrow?: boolean;\n icon?: ButtonIcon | null;\n newTab?: boolean;\n /** Sponsored, untrusted or user-generated destination. Absent ⇒ no rel beyond a new tab's own. */\n rel?: LinkRel;\n /** Stretch across its column, label centred. Absent ⇒ the button's own width. */\n fullWidth?: boolean;\n}\n\n/**\n * A stored button value as it renders: `rel`, `action` and `fullWidth` stay optional (present only\n * when set, so a value that never named them reads byte-for-byte as before), every other key is filled.\n */\nexport type ReadButtonValue = Required<Omit<ButtonValue, \"rel\" | \"href\" | \"action\" | \"fullWidth\">> & Pick<ButtonValue, \"rel\" | \"action\"> & { href: string; fullWidth?: true };\n\n/**\n * A button's destination as a string. `href` is a string, or — on a value written by an editor\n * that stores links as objects — a link object `{ type, href, ref?, … }`, whose `href` is read.\n */\nconst hrefOf = linkHref;\n\n/** A stored button value as it renders: every key read through the same allow-lists as a block. */\nexport function readButtonValue(value: unknown): ReadButtonValue {\n const v = (value && typeof value === \"object\" ? value : {}) as Record<string, unknown>;\n // A link object's own newTab / rel count when the button sets none of its own.\n const link = isLinkObject(v.href) ? linkAnchorOf(v.href) : null;\n const rel = v.rel ?? link?.rel;\n // A code-action button goes nowhere: whatever href, new tab or rel rode along is not read.\n const code = v.action === \"code\";\n return {\n label: typeof v.label === \"string\" ? v.label : \"\",\n href: code ? \"\" : (hrefOf(v.href) ?? \"\"),\n variant: buttonVariantOf(v.variant),\n size: BUTTON_SIZES.includes(v.size as ButtonSizeName) ? (v.size as ButtonSizeName) : \"md\",\n arrow: v.arrow === true,\n icon: buttonIconOf(v.icon),\n newTab: code ? false : v.newTab === undefined ? link?.newTab === true : v.newTab === true,\n ...(!code && LINK_RELS.includes(rel as LinkRel) ? { rel: rel as LinkRel } : {}),\n ...(code ? { action: \"code\" as const } : {}),\n ...(v.fullWidth === true ? { fullWidth: true as const } : {}),\n };\n}\n\n/** The named refusal of a `button` value whose `fullWidth` is not true or false. */\nexport const BUTTON_FULL_WIDTH_INVALID = \"button_full_width_invalid\";\n\n/**\n * Why a button value's `fullWidth` is refused, or null. Introduced-only: a value whose `fullWidth`\n * is the one `previous` already stored saves (values written before the key was checked keep\n * saving), so only a write that BRINGS a non-boolean is refused. Kept out of `buttonValueProblem`,\n * which also runs baseline-free at readiness and publish.\n */\nexport function buttonFullWidthProblem(value: unknown, previous?: unknown): string | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const fullWidth = (value as Record<string, unknown>).fullWidth;\n if (fullWidth === undefined || typeof fullWidth === \"boolean\") return null;\n const before = previous && typeof previous === \"object\" ? (previous as Record<string, unknown>).fullWidth : undefined;\n if (before !== undefined && JSON.stringify(before) === JSON.stringify(fullWidth)) return null;\n return `${BUTTON_FULL_WIDTH_INVALID}: fullWidth must be true or false`;\n}\n\n/**\n * Why a value is not a button, or null when it is. Look keys are checked only when present.\n * `looks` are the values that pick a look of the project's own Button family (@see\n * buttonLookValue): a variant is one of those or one of the fixed names.\n */\nexport function buttonValueProblem(value: unknown, looks?: ReadonlySet<string>): string | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return \"must be a { label, href } button\";\n const v = value as Record<string, unknown>;\n if (typeof v.label !== \"string\") return \"needs a label\";\n if (v.action !== undefined && !BUTTON_ACTIONS.includes(v.action as ButtonAction)) return `has an unknown action \"${String(v.action)}\" (code, or none for a link)`;\n if (v.action === \"code\") {\n // The site's script owns the click: a destination here would be a second, silent answer.\n if (v.href !== undefined && v.href !== null && v.href !== \"\") return 'takes no href with action \"code\"';\n if (v.newTab === true || v.rel !== undefined) return 'takes no newTab or rel with action \"code\"';\n } else if (hrefOf(v.href) === null) return 'needs an href (or action \"code\" for a button the site\\'s script handles)';\n if (isLinkObject(v.href)) {\n const problem = linkValueProblem(v.href);\n if (problem) return `href ${problem}`;\n }\n if (v.variant !== undefined && !BUTTON_VARIANTS.includes(v.variant as ButtonVariant) && !(typeof v.variant === \"string\" && looks?.has(v.variant))) {\n return `has an unknown variant \"${String(v.variant)}\"${looks?.size ? ` (this project's looks: ${[...looks].join(\", \")})` : \"\"}`;\n }\n if (v.size !== undefined && !BUTTON_SIZES.includes(v.size as ButtonSizeName)) return `has an unknown size \"${String(v.size)}\"`;\n if (v.arrow !== undefined && typeof v.arrow !== \"boolean\") return \"arrow must be true or false\";\n if (v.newTab !== undefined && typeof v.newTab !== \"boolean\") return \"newTab must be true or false\";\n if (v.rel !== undefined && !LINK_RELS.includes(v.rel as LinkRel)) return `has an unknown rel \"${String(v.rel)}\" (nofollow, sponsored or ugc)`;\n if (v.icon !== undefined && v.icon !== null && buttonIconOf(v.icon) === null) return `has an unknown icon \"${String(v.icon)}\"`;\n return null;\n}\n\n// ── A Button component instance's look ───────────────────────────────────────────────────────\n\n/** The look keys an instance of a Button component may override, beside its label and link. */\nexport const BUTTON_LOOK_KEYS = [\"variant\", \"size\", \"arrow\", \"icon\", \"newTab\", \"fullWidth\"] as const;\nexport type ButtonLookKey = (typeof BUTTON_LOOK_KEYS)[number];\n\n/**\n * A `button` PROP's value as the `button` BLOCK props it writes, for every lane that applies an\n * instance's overrides. `label` lands on `text`, and only the keys the value names come back, so\n * an override carrying a label alone keeps the definition's href and look.\n */\nexport function buttonBlockProps(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return {};\n const v = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n if (typeof v.label === \"string\") out.text = v.label;\n if (v.action === \"code\") {\n // Drawn as `<button type=\"button\">`: no destination, and none of a link's new tab or rel.\n out.action = \"code\";\n out.href = \"\";\n for (const key of BUTTON_LOOK_KEYS) if (key in v && key !== \"newTab\") out[key] = v[key];\n return out;\n }\n const href = hrefOf(v.href);\n // An instance's overrides are an open record nobody validated: a script href renders as \"#\",\n // with none of the link's new tab or rel.\n const script = href !== null && isScriptHref(href);\n if (href !== null) out.href = script ? \"#\" : href;\n // A block's href is a string: a link object's newTab / rel move onto the block beside it. The\n // object describes the WHOLE anchor (linkAnchorOf), so its same tab or \"follow\" (no rel) clears\n // the block's own, unless the button value sets its own newTab or rel.\n if (isLinkObject(v.href) && !script) {\n const link = linkAnchorOf(v.href)!;\n out.newTab = link.newTab;\n out.rel = link.rel;\n }\n if (v.rel !== undefined) out.rel = v.rel;\n for (const key of BUTTON_LOOK_KEYS) if (key in v) out[key] = v[key];\n return out;\n}\n\ninterface PropDefLike {\n key: string;\n label?: string;\n type?: string;\n target: { blockId: string; path: string };\n}\ninterface ComponentLike<P extends PropDefLike> {\n category?: string | null;\n blockJson?: unknown;\n props?: readonly P[] | null;\n}\n\n/** The id of a tree's ONLY `button` block, at any depth; null for none or several. */\nfunction soleButtonId(blockJson: unknown): string | null {\n const ids: string[] = [];\n const walk = (list: unknown): void => {\n if (!Array.isArray(list)) return;\n for (const b of list as Array<{ id?: unknown; type?: unknown; props?: { children?: unknown; columns?: unknown } }>) {\n if (b?.type === \"button\" && typeof b.id === \"string\") ids.push(b.id);\n walk(b?.props?.children);\n if (Array.isArray(b?.props?.columns)) for (const column of b.props.columns) walk(column);\n }\n };\n walk(blockJson);\n return ids.length === 1 ? ids[0]! : null;\n}\n\nconst LOOK_PROP_TYPE: Record<ButtonLookKey, string> = { variant: \"text\", size: \"text\", arrow: \"boolean\", icon: \"text\", newTab: \"boolean\", fullWidth: \"boolean\" };\nconst LOOK_PROP_LABEL: Record<ButtonLookKey, string> = { variant: \"Style\", size: \"Size\", arrow: \"Show arrow\", icon: \"Leading icon\", newTab: \"Open in new tab\", fullWidth: \"Full width\" };\n\n/**\n * A component's prop declarations, plus — on a Button component (category `button`, one button\n * block) — a look prop for every `BUTTON_LOOK_KEYS` key it does not declare itself, each driving\n * that block's `props.<key>`. So an INSTANCE of any Button carries its own look in its overrides\n * (`{ text, href, variant, arrow, … }`) with nothing to backfill: every renderer that applies\n * overrides passes this instead of `props`. Any other component is returned as declared, so a\n * section with one CTA never has a stray `variant` override land on its button.\n */\nexport function withButtonLookProps<P extends PropDefLike>(def: ComponentLike<P>): P[] {\n const props = [...(def.props ?? [])];\n if (def.category !== \"button\") return props;\n const blockId = soleButtonId(def.blockJson);\n if (!blockId) return props;\n for (const key of BUTTON_LOOK_KEYS) {\n if (props.some((p) => p.key === key)) continue;\n props.push({ key, label: LOOK_PROP_LABEL[key], type: LOOK_PROP_TYPE[key], target: { blockId, path: `props.${key}` } } as P);\n }\n return props;\n}\n\n/**\n * One instance of a Button component as a `ButtonValue` — the definition's button with the\n * instance's overrides written onto it — for a site rendering the instance with `BcmsButton`.\n * Null when the component is not a Button (not category `button`, or not exactly one button).\n */\nexport function buttonValueOfInstance<P extends PropDefLike>(def: ComponentLike<P>, overrides: Record<string, unknown> | null | undefined): ReadButtonValue | null {\n if (def.category !== \"button\") return null;\n const blockId = soleButtonId(def.blockJson);\n if (!blockId) return null;\n const found: { props?: Record<string, unknown> }[] = [];\n const walk = (list: unknown): void => {\n if (!Array.isArray(list)) return;\n for (const b of list as Array<{ id?: unknown; props?: { children?: unknown; columns?: unknown } }>) {\n if (b?.id === blockId) found.push(b as { props?: Record<string, unknown> });\n walk(b?.props?.children);\n if (Array.isArray(b?.props?.columns)) for (const column of b.props.columns) walk(column);\n }\n };\n walk(def.blockJson);\n const props: Record<string, unknown> = { ...(found[0]?.props ?? {}) };\n for (const p of withButtonLookProps(def)) {\n if (p.target.blockId !== blockId || !overrides || !(p.key in overrides)) continue;\n if (p.type === \"button\") Object.assign(props, buttonBlockProps(overrides[p.key]));\n else if (p.target.path.startsWith(\"props.\")) props[p.target.path.slice(\"props.\".length)] = overrides[p.key];\n }\n return readButtonValue({ ...props, label: props.text });\n}\n\n","/**\n * A LINK VALUE: what a `link` field, a `link` prop and a button's `href` store.\n *\n * Two shapes, both valid forever:\n * - a plain href string (\"/about\", \"https://example.com\"), which is what every value stored\n * before the V2 link element holds;\n * - the V2 link object (dashboard kit `controls/link.tsx`, `LinkValue` after `finalizeLink`):\n * `{ type, href, title?, newTab?, target?, rel?, section?, ref? }`.\n *\n * `href` is always the final href the site renders (`mailto:`, `tel:`, `#anchor` included), so a\n * reader that only wants a destination reads `href` and nothing else. `ref` is the id of the page\n * or CMS item a `page` / `entry` link points at: the write path checks it exists and delivery\n * resolves it like a reference. Keys the kit writes beside these (`pageId`, `entryId`, `assetId`,\n * `anchor`, `email`, `subject`, `phone`, `label`) are kept as sent.\n */\n\n/** A link's relation beyond a new tab's own `noopener noreferrer`. */\nexport const LINK_RELS = [\"nofollow\", \"sponsored\", \"ugc\"] as const;\nexport type LinkRel = (typeof LINK_RELS)[number];\n\n/**\n * What a link points at. `section` is the kit's spelling of `anchor` (a `#fragment` on the page);\n * both are accepted and stored as sent.\n */\nexport const LINK_VALUE_TYPES = [\"url\", \"page\", \"entry\", \"email\", \"phone\", \"anchor\", \"section\", \"file\"] as const;\nexport type LinkValueType = (typeof LINK_VALUE_TYPES)[number];\n\nexport interface LinkValue {\n type?: LinkValueType;\n href: string;\n title?: string;\n newTab?: boolean;\n /** Legacy mirror of `newTab`; must agree with it. */\n target?: \"_self\" | \"_blank\";\n /** Absent = a normal link (the kit's \"follow\" is dropped on write). */\n rel?: LinkRel;\n /** The `#anchor` on the target page. */\n section?: string;\n /** The page id (`type: \"page\"`) or entry id (`type: \"entry\"`) this link points at. */\n ref?: string;\n}\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> => !!v && typeof v === \"object\" && !Array.isArray(v);\n\n/** A link object (`{ href: string, … }`), as opposed to a plain href string. */\nexport function isLinkObject(value: unknown): value is LinkValue & Record<string, unknown> {\n return isPlainObject(value) && typeof value.href === \"string\";\n}\n\n/** A link value's destination: the string itself, or the object's `href`. Null for anything else. */\nexport function linkHref(value: unknown): string | null {\n if (typeof value === \"string\") return value;\n return isLinkObject(value) ? value.href : null;\n}\n\n/** The page or entry a `page` / `entry` link points at, or null. Reads `ref`, then the kit's `pageId` / `entryId`. */\nexport function linkRefOf(value: unknown): { kind: \"page\" | \"entry\"; id: string } | null {\n if (!isLinkObject(value) || (value.type !== \"page\" && value.type !== \"entry\")) return null;\n const id = value.ref ?? (value.type === \"page\" ? value.pageId : value.entryId);\n return typeof id === \"string\" && id.length > 0 ? { kind: value.type, id } : null;\n}\n\n/** `javascript:`, `data:` and `vbscript:`, also behind the control characters a URL parser strips. */\nexport const isScriptHref = (href: string): boolean =>\n /^(javascript|data|vbscript):/i.test(href.replace(/[\\u0000- \\u007F]/g, \"\"));\n\nconst newTabOf = (v: Record<string, unknown>): boolean => v.newTab === true || (v.newTab === undefined && v.target === \"_blank\");\n\n/**\n * Why a link OBJECT is not a link value, or null when it is. The href's own grammar (which schemes,\n * which relative forms) is the caller's rule; this refuses only what no link may be.\n * Messages start with `link_value_invalid:` so every surface can name the refusal.\n */\nexport function linkValueProblem(value: unknown): string | null {\n if (!isPlainObject(value)) return \"link_value_invalid: must be an href string or a link object { type, href, … }\";\n const v = value;\n if (typeof v.href !== \"string\") return \"link_value_invalid: needs an href string\";\n if (isScriptHref(v.href)) return \"link_value_invalid: script links (javascript:, data:, vbscript:) aren't allowed\";\n if (v.type !== undefined && !LINK_VALUE_TYPES.includes(v.type as LinkValueType)) {\n return `link_value_invalid: unknown type \"${String(v.type)}\" (${LINK_VALUE_TYPES.join(\", \")})`;\n }\n for (const key of [\"title\", \"section\", \"ref\"] as const) {\n if (v[key] !== undefined && typeof v[key] !== \"string\") return `link_value_invalid: ${key} must be a string`;\n }\n if (v.ref !== undefined && v.type !== \"page\" && v.type !== \"entry\") return \"link_value_invalid: ref is the target of a page or entry link\";\n if (v.newTab !== undefined && typeof v.newTab !== \"boolean\") return \"link_value_invalid: newTab must be true or false\";\n if (v.target !== undefined && v.target !== \"_self\" && v.target !== \"_blank\") return 'link_value_invalid: target must be \"_self\" or \"_blank\"';\n if (typeof v.newTab === \"boolean\" && v.target !== undefined && v.newTab !== (v.target === \"_blank\")) {\n return \"link_value_invalid: newTab and target disagree\";\n }\n // The kit's \"follow\" (a normal link) is not a rel: the write normalizer drops it before this runs.\n if (v.rel !== undefined && !LINK_RELS.includes(v.rel as LinkRel)) {\n return `link_value_invalid: unknown rel \"${String(v.rel)}\" (nofollow, sponsored or ugc)`;\n }\n return null;\n}\n\n/**\n * A link value as it is stored: a string as sent; an object with the kit's `rel: \"follow\"` dropped\n * (no rel IS a normal link), `newTab` filled from a lone `target`, a page/entry link's\n * `pageId` / `entryId` copied to `ref`, and the read-only `resolved` dropped. Never invents a destination.\n */\nexport function normalizeLinkValue<T>(value: T): T {\n if (!isLinkObject(value)) return value;\n const out: Record<string, unknown> = { ...value };\n // `resolved` is what a delivery read adds (the target page or entry); a client that writes a\n // read value back must not store a stale copy of its target.\n delete out.resolved;\n if (out.rel === \"follow\") delete out.rel;\n if (out.newTab === undefined && out.target !== undefined) out.newTab = out.target === \"_blank\";\n const ref = linkRefOf(out);\n if (ref && out.ref === undefined) out.ref = ref.id;\n return out as T;\n}\n\n/** What an anchor for this link value carries: its href, whether it opens a new tab, and its rel. */\nexport function linkAnchorOf(value: unknown): { href: string; newTab: boolean; rel?: LinkRel } | null {\n if (typeof value === \"string\") return { href: value, newTab: false };\n if (!isLinkObject(value)) return null;\n return {\n href: value.href,\n newTab: newTabOf(value),\n ...(LINK_RELS.includes(value.rel as LinkRel) ? { rel: value.rel as LinkRel } : {}),\n };\n}\n","/**\n * The V2 video value (DESIGN.md §6.2, §8.15): a pasted provider link or a file URL, as a bare\n * string or as `{ url, poster?, autoplay?, loop?, transcript? }`.\n *\n * The object's keys are the `video` block's own props (`VideoProps`, block.ts), so a video prop\n * aimed at a video block lands as that block's props unchanged, and a video field renders the way\n * the block does. Any other key is refused by name (`video_value_invalid`), never dropped.\n */\n\n/** The keys a video object may carry: exactly the `video` block's props. */\nexport const VIDEO_VALUE_KEYS = [\"url\", \"poster\", \"autoplay\", \"loop\", \"transcript\"] as const;\n\n/** A video value's object form. A bare string is the same value with only `url`. */\nexport interface VideoValue {\n url: string;\n poster?: string;\n autoplay?: boolean;\n loop?: boolean;\n transcript?: string;\n}\n\n/** Same cap as the video block's transcript (CPO-093). */\nexport const VIDEO_TRANSCRIPT_MAX = 100_000;\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> => typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/** A URL a video or poster may hold: an http(s) URL or a site path. \"\" is an unset one. */\nconst isVideoUrl = (s: string): boolean => s === \"\" || /^https?:\\/\\/[^\\s]+$/i.test(s.trim()) || /^\\/(?!\\/)\\S*$/.test(s.trim());\n\n/** The url a video value plays, or null when it holds none (a bare string is its url). */\nexport function videoUrlOf(value: unknown): string | null {\n const url = typeof value === \"string\" ? value : isPlainObject(value) ? value.url : undefined;\n return typeof url === \"string\" && url.trim() !== \"\" ? url.trim() : null;\n}\n\n/** Why `value` is not a video value, or null when it is. Every message starts `video_value_invalid:`. */\nexport function videoValueProblem(value: unknown): string | null {\n if (typeof value === \"string\") return isVideoUrl(value) ? null : \"video_value_invalid: url must be an http(s) URL or a site path\";\n if (!isPlainObject(value)) return \"video_value_invalid: must be a URL string or { url, poster?, autoplay?, loop?, transcript? }\";\n const unknown = Object.keys(value).find((k) => !(VIDEO_VALUE_KEYS as readonly string[]).includes(k));\n if (unknown !== undefined) return `video_value_invalid: unknown key \"${unknown}\" (${VIDEO_VALUE_KEYS.join(\", \")})`;\n if (typeof value.url !== \"string\") return \"video_value_invalid: needs a url string\";\n if (!isVideoUrl(value.url)) return \"video_value_invalid: url must be an http(s) URL or a site path\";\n if (value.poster !== undefined && (typeof value.poster !== \"string\" || !isVideoUrl(value.poster))) {\n return \"video_value_invalid: poster must be an http(s) URL or a site path\";\n }\n for (const key of [\"autoplay\", \"loop\"] as const) {\n if (value[key] !== undefined && typeof value[key] !== \"boolean\") return `video_value_invalid: ${key} must be true or false`;\n }\n if (value.transcript !== undefined && (typeof value.transcript !== \"string\" || value.transcript.length > VIDEO_TRANSCRIPT_MAX)) {\n return `video_value_invalid: transcript must be a string of ${VIDEO_TRANSCRIPT_MAX} characters or fewer`;\n }\n return null;\n}\n","/**\n * The V2 TABLE value (CPO D42; V2 `src/schema/table.ts`): typed, keyed columns × keyed rows.\n *\n * What a `table` FIELD stores, and what a `table` PROP stores when its `config.mode` is `\"data\"`.\n * A `table` prop with no mode (or `mode: \"rows\"`) is the older shape, an array of row objects\n * keyed by `config.fields`, and is not this value.\n *\n * { id?, caption, notes?, headerRow, headerColumn, columns: [{ _key, label, type, … }],\n * columnGroups?, rowGroups?, rows: [{ _key, cells: { [columnKey]: cell }, group?, footer?, type?, highlight? }],\n * footnotes?, filterable?, design?, jsonLd? }\n *\n * A cell is a bare value (string, number, boolean, null, a link `{ label, href, newTab?, rel? }`, a\n * reference `{ ref, label?, href? }`) or `{ value, type?, note? }` when it needs its own type or a\n * footnote. Body cells never merge: only group headers span.\n *\n * One renderer for every read lane: {@link renderTableHtml} (hosted pages), {@link tableToMarkdown}\n * (the `.md` twin), {@link tableSearchText} (site search). A reference cell renders what a read\n * resolved onto it (`resolved`), then its stored `label` / `href`, then its id.\n *\n * Every refusal is named (`table_value_invalid`, `table_caption_required`, `table_limit_exceeded`,\n * `table_column_type_not_allowed`, `table_columns_locked`, `link_value_invalid`) at the value's own\n * path, and no key is dropped: an unknown one is refused by name.\n */\nimport { isScriptHref, LINK_RELS } from \"./link-value.js\";\n\nexport const TABLE_COLUMN_TYPES = [\"text\", \"number\", \"money\", \"boolean\", \"rating\", \"link\", \"richtext-inline\", \"reference\"] as const;\nexport type TableColumnType = (typeof TABLE_COLUMN_TYPES)[number];\nexport const TABLE_RESPONSIVE = [\"scroll\", \"stack\", \"cards\"] as const;\nexport type TableResponsive = (typeof TABLE_RESPONSIVE)[number];\nexport const TABLE_JSONLD_TYPES = [\"none\", \"ItemList\", \"Dataset\", \"Offers\"] as const;\nexport type TableJsonLdType = (typeof TABLE_JSONLD_TYPES)[number];\n\n/** Hard limits, whatever a field allows: past these a table is a dataset, not page content. */\nexport const TABLE_LIMITS = { columns: 50, rows: 1000, cellChars: 5000, captionChars: 300, notesChars: 2000, keyChars: 64, labelChars: 300 } as const;\n\nexport interface TableColumn {\n _key: string;\n label: string;\n type: TableColumnType;\n description?: string;\n unit?: string;\n currency?: string;\n decimals?: number;\n align?: \"start\" | \"center\" | \"end\";\n sortable?: boolean;\n group?: string;\n trueLabel?: string;\n falseLabel?: string;\n max?: number;\n refTo?: string[];\n highlight?: boolean;\n}\nexport interface TableGroup { _key: string; label: string }\nexport interface TableLink { label: string; href: string; newTab?: boolean; rel?: \"follow\" | \"nofollow\" | \"ugc\" | \"sponsored\" }\n/** What a read that resolves references writes onto a reference cell (never stored). */\nexport interface TableRefResolved { kind: \"page\" | \"entry\"; id: string; title: string; slug: string | null; url: string | null }\nexport interface TableRef { ref: string; label?: string; href?: string; resolved?: TableRefResolved }\nexport type TableCellValue = string | number | boolean | null | TableLink | TableRef;\nexport interface TableCellObject { value: TableCellValue; type?: TableColumnType; note?: string }\nexport type TableCell = TableCellValue | TableCellObject;\nexport interface TableRow {\n _key: string;\n cells: Record<string, TableCell | undefined>;\n group?: string;\n footer?: boolean;\n type?: TableColumnType;\n highlight?: boolean;\n}\nexport interface TableFootnote { _key: string; text: string }\nexport interface TableValue {\n id?: string;\n caption: string;\n notes?: string;\n headerRow: boolean;\n headerColumn: boolean;\n columns: TableColumn[];\n columnGroups?: TableGroup[];\n rowGroups?: TableGroup[];\n rows: TableRow[];\n footnotes?: TableFootnote[];\n filterable?: boolean;\n design?: { responsive?: TableResponsive; sticky?: boolean; striped?: boolean; density?: \"compact\" | \"comfortable\"; hideCaption?: boolean };\n jsonLd?: { type: TableJsonLdType; axis?: \"rows\" | \"columns\"; priceRow?: string };\n}\n\n/** The field-level options (`config` of a `table` field, or of a `table` prop in `mode: \"data\"`). */\nexport interface TableFieldOptions {\n columnTypes?: TableColumnType[];\n lockColumns?: boolean;\n minRows?: number;\n maxRows?: number;\n maxColumns?: number;\n requireCaption?: boolean;\n allowGroups?: boolean;\n allowFootnotes?: boolean;\n allowNote?: boolean;\n settings?: { headers?: boolean; totals?: boolean; phones?: TableResponsive[]; highlight?: boolean; sticky?: boolean; sort?: boolean; search?: boolean };\n jsonLd?: Exclude<TableJsonLdType, \"none\">[];\n}\n\nconst isObj = (v: unknown): v is Record<string, unknown> => !!v && typeof v === \"object\" && !Array.isArray(v);\n\n/** A value shaped like a table (`columns` and `rows` arrays): what a walker hands to the table lane. */\nexport const isTableValue = (v: unknown): v is TableValue => isObj(v) && Array.isArray(v.columns) && Array.isArray(v.rows);\nexport const isTableCellObject = (c: unknown): c is TableCellObject => isObj(c) && \"value\" in c;\nexport const isTableRef = (v: unknown): v is TableRef => isObj(v) && \"ref\" in v;\nexport const isTableLink = (v: unknown): v is TableLink => isObj(v) && !(\"ref\" in v) && \"href\" in v;\n\n/** A cell's value, unwrapped from `{ value, … }`. */\nexport const tableCellValue = (c: unknown): TableCellValue => (c === undefined ? null : isTableCellObject(c) ? c.value : (c as TableCellValue));\n/** The type that judges a cell: its own, then its row's, then its column's. */\nexport const tableCellType = (col: TableColumn, row?: TableRow, c?: unknown): TableColumnType => (isTableCellObject(c) && c.type) || row?.type || col.type;\n\n// ── validation ─────────────────────────────────────────────────────────────────────────────────\n\nexport type TableProblem = { path: Array<string | number>; code: string; message: string };\n\nconst TOP_KEYS = new Set([\"id\", \"caption\", \"notes\", \"headerRow\", \"headerColumn\", \"columns\", \"columnGroups\", \"rowGroups\", \"rows\", \"footnotes\", \"filterable\", \"design\", \"jsonLd\"]);\nconst COLUMN_KEYS = new Set([\"_key\", \"label\", \"type\", \"description\", \"unit\", \"currency\", \"decimals\", \"align\", \"sortable\", \"group\", \"trueLabel\", \"falseLabel\", \"max\", \"refTo\", \"highlight\"]);\nconst ROW_KEYS = new Set([\"_key\", \"cells\", \"group\", \"footer\", \"type\", \"highlight\"]);\nconst GROUP_KEYS = new Set([\"_key\", \"label\"]);\nconst FOOTNOTE_KEYS = new Set([\"_key\", \"text\"]);\nconst DESIGN_KEYS = new Set([\"responsive\", \"sticky\", \"striped\", \"density\", \"hideCaption\"]);\nconst JSONLD_KEYS = new Set([\"type\", \"axis\", \"priceRow\"]);\nconst CELL_KEYS = new Set([\"value\", \"type\", \"note\"]);\nconst LINK_KEYS = new Set([\"label\", \"href\", \"newTab\", \"rel\"]);\n// `resolved` is what a read writes; a client that echoes a read back is not refused for it (normalize drops it).\nconst REF_KEYS = new Set([\"ref\", \"label\", \"href\", \"resolved\"]);\nconst TABLE_LINK_RELS: readonly string[] = [\"follow\", ...LINK_RELS];\n\nexport type TableCheckOptions = TableFieldOptions & {\n /** The columns a `lockColumns` table must keep (the field's default table): same keys, types and order. */\n lockedColumns?: ReadonlyArray<{ _key: string; type: string }>;\n /** The caller's href grammar (which relative forms a site may hold); script hrefs are always refused. */\n hrefProblem?: (href: string) => string | null;\n};\n\n/**\n * Every reason `value` is not a table this field takes, each at its own path inside the value\n * (`rows[2].cells.price`). Empty when it is one. Cells whose words do not match their column's type\n * (text in a number column) are accepted, as V2 accepts them: the type decides formatting, and the\n * editor warns. A cell OBJECT must match its type (a link in a link cell, a reference in a reference\n * cell), so nothing is stored that the renderer would drop.\n */\nexport function tableValueProblems(value: unknown, opts: TableCheckOptions = {}): TableProblem[] {\n const out: TableProblem[] = [];\n const bad = (path: Array<string | number>, message: string, code = \"table_value_invalid\") => out.push({ path, code, message: `${code}: ${message}` });\n if (!isTableValue(value)) {\n bad([], \"a table is { caption, headerRow, headerColumn, columns: [{ _key, label, type }], rows: [{ _key, cells }] }\");\n return out;\n }\n const t = value as unknown as Record<string, unknown>;\n const unknownKeys = (o: Record<string, unknown>, allowed: Set<string>, at: Array<string | number>) => {\n for (const k of Object.keys(o)) if (!allowed.has(k)) bad([...at, k], `unknown key \"${k}\" (${[...allowed].join(\", \")})`);\n };\n const str = (v: unknown, at: Array<string | number>, what: string, max: number, required = false) => {\n if (v === undefined && !required) return;\n if (typeof v !== \"string\") bad(at, `${what} must be a string`);\n else if (v.length > max) bad(at, `${what} is ${v.length} characters; at most ${max}`, \"table_limit_exceeded\");\n };\n const bool = (v: unknown, at: Array<string | number>, what: string) => {\n if (v !== undefined && typeof v !== \"boolean\") bad(at, `${what} must be true or false`);\n };\n const oneOf = (v: unknown, at: Array<string | number>, what: string, allowed: readonly string[]) => {\n if (v !== undefined && !allowed.includes(v as string)) bad(at, `${what} must be one of ${allowed.join(\", \")}`);\n };\n unknownKeys(t, TOP_KEYS, []);\n str(t.id, [\"id\"], \"id\", TABLE_LIMITS.keyChars);\n str(t.caption, [\"caption\"], \"caption\", TABLE_LIMITS.captionChars, true);\n if (typeof t.caption === \"string\" && t.caption.trim() === \"\" && opts.requireCaption !== false) {\n bad([\"caption\"], \"give the table a caption that says what it compares (it names the table for screen readers and search)\", \"table_caption_required\");\n }\n str(t.notes, [\"notes\"], \"notes\", TABLE_LIMITS.notesChars);\n if (t.notes !== undefined && opts.allowNote === false && typeof t.notes === \"string\" && t.notes.trim() !== \"\") bad([\"notes\"], \"this table takes no note (config.allowNote is false)\");\n bool(t.headerRow, [\"headerRow\"], \"headerRow\");\n bool(t.headerColumn, [\"headerColumn\"], \"headerColumn\");\n bool(t.filterable, [\"filterable\"], \"filterable\");\n if (t.design !== undefined) {\n if (!isObj(t.design)) bad([\"design\"], \"design must be an object\");\n else {\n const d = t.design;\n unknownKeys(d, DESIGN_KEYS, [\"design\"]);\n oneOf(d.responsive, [\"design\", \"responsive\"], \"design.responsive\", TABLE_RESPONSIVE);\n oneOf(d.density, [\"design\", \"density\"], \"design.density\", [\"compact\", \"comfortable\"]);\n for (const k of [\"sticky\", \"striped\", \"hideCaption\"]) bool(d[k], [\"design\", k], `design.${k}`);\n }\n }\n\n // Groups and footnotes first: columns, rows and cells name them.\n const keyed = (list: unknown, at: string, keys: Set<string>, textKey: \"label\" | \"text\", allowed: boolean): Set<string> => {\n const seen = new Set<string>();\n if (list === undefined) return seen;\n if (!Array.isArray(list)) {\n bad([at], `${at} must be an array`);\n return seen;\n }\n if (!allowed && list.length > 0) bad([at], `this table takes no ${at === \"footnotes\" ? \"footnotes (config.allowFootnotes is false)\" : \"row groups (config.allowGroups is false)\"}`);\n list.forEach((g, i) => {\n if (!isObj(g)) return bad([at, i], `${at}[${i}] must be an object`);\n unknownKeys(g, keys, [at, i]);\n if (typeof g._key !== \"string\" || g._key === \"\" || g._key.length > TABLE_LIMITS.keyChars) bad([at, i, \"_key\"], `needs a _key string of 1 to ${TABLE_LIMITS.keyChars} characters`);\n else if (seen.has(g._key)) bad([at, i, \"_key\"], `_key \"${g._key}\" is used twice`);\n else seen.add(g._key);\n str(g[textKey], [at, i, textKey], textKey, textKey === \"text\" ? TABLE_LIMITS.notesChars : TABLE_LIMITS.labelChars, true);\n });\n return seen;\n };\n const colGroups = keyed(t.columnGroups, \"columnGroups\", GROUP_KEYS, \"label\", true);\n const rowGroups = keyed(t.rowGroups, \"rowGroups\", GROUP_KEYS, \"label\", opts.allowGroups !== false);\n const notes = keyed(t.footnotes, \"footnotes\", FOOTNOTE_KEYS, \"text\", opts.allowFootnotes !== false);\n\n const columns = t.columns as unknown[];\n const maxColumns = Math.min(opts.maxColumns ?? TABLE_LIMITS.columns, TABLE_LIMITS.columns);\n if (columns.length > maxColumns) bad([\"columns\"], `${columns.length} columns; at most ${maxColumns}`, \"table_limit_exceeded\");\n const cols = new Map<string, TableColumn>();\n columns.forEach((c, i) => {\n const at = [\"columns\", i];\n if (!isObj(c)) return bad(at, `columns[${i}] must be an object`);\n unknownKeys(c, COLUMN_KEYS, at);\n if (typeof c._key !== \"string\" || c._key === \"\" || c._key.length > TABLE_LIMITS.keyChars) bad([...at, \"_key\"], `needs a _key string of 1 to ${TABLE_LIMITS.keyChars} characters`);\n else if (cols.has(c._key)) bad([...at, \"_key\"], `_key \"${c._key}\" is used twice`);\n str(c.label, [...at, \"label\"], \"label\", TABLE_LIMITS.labelChars, true);\n if (!TABLE_COLUMN_TYPES.includes(c.type as TableColumnType)) bad([...at, \"type\"], `type must be one of ${TABLE_COLUMN_TYPES.join(\", \")}`);\n else if (opts.columnTypes && !opts.columnTypes.includes(c.type as TableColumnType)) {\n bad([...at, \"type\"], `a ${String(c.type)} column is not offered here (config.columnTypes: ${opts.columnTypes.join(\", \")})`, \"table_column_type_not_allowed\");\n }\n str(c.description, [...at, \"description\"], \"description\", TABLE_LIMITS.notesChars);\n str(c.unit, [...at, \"unit\"], \"unit\", 16);\n if (c.currency !== undefined && (typeof c.currency !== \"string\" || !/^[A-Z]{3}$/.test(c.currency))) bad([...at, \"currency\"], \"currency must be an ISO 4217 code such as USD\");\n if (c.decimals !== undefined && (!Number.isInteger(c.decimals) || (c.decimals as number) < 0 || (c.decimals as number) > 10)) bad([...at, \"decimals\"], \"decimals must be a whole number from 0 to 10\");\n if (c.max !== undefined && (!Number.isInteger(c.max) || (c.max as number) < 1 || (c.max as number) > 10)) bad([...at, \"max\"], \"max must be a whole number from 1 to 10\");\n oneOf(c.align, [...at, \"align\"], \"align\", [\"start\", \"center\", \"end\"]);\n for (const k of [\"sortable\", \"highlight\"]) bool(c[k], [...at, k], k);\n str(c.trueLabel, [...at, \"trueLabel\"], \"trueLabel\", TABLE_LIMITS.labelChars);\n str(c.falseLabel, [...at, \"falseLabel\"], \"falseLabel\", TABLE_LIMITS.labelChars);\n if (c.group !== undefined && (typeof c.group !== \"string\" || !colGroups.has(c.group))) bad([...at, \"group\"], `group \"${String(c.group)}\" is not a key of columnGroups`);\n if (c.refTo !== undefined && (!Array.isArray(c.refTo) || c.refTo.some((r) => typeof r !== \"string\" || r === \"\"))) bad([...at, \"refTo\"], 'refTo must be a list of collection ids or \"page\"');\n if (typeof c._key === \"string\" && c._key !== \"\" && !cols.has(c._key)) cols.set(c._key, c as unknown as TableColumn);\n });\n if (opts.lockColumns && opts.lockedColumns) {\n const want = opts.lockedColumns.map((c) => `${c._key}:${c.type}`).join(\",\");\n const got = columns.map((c) => (isObj(c) ? `${String(c._key)}:${String(c.type)}` : \"?\")).join(\",\");\n if (want !== got) bad([\"columns\"], `this table's columns are set by its developer (config.lockColumns): keep ${opts.lockedColumns.map((c) => c._key).join(\", \")}, in that order, with their types`, \"table_columns_locked\");\n }\n\n const rows = t.rows as unknown[];\n const maxRows = Math.min(opts.maxRows ?? TABLE_LIMITS.rows, TABLE_LIMITS.rows);\n const body = rows.filter((r) => !(isObj(r) && r.footer === true)).length;\n if (rows.length > TABLE_LIMITS.rows || body > maxRows) bad([\"rows\"], `${body} rows; at most ${maxRows}`, \"table_limit_exceeded\");\n if (opts.minRows !== undefined && body < opts.minRows) bad([\"rows\"], `${body} rows; at least ${opts.minRows}`, \"table_rows_min\");\n const rowKeys = new Set<string>();\n rows.forEach((r, i) => {\n const at = [\"rows\", i];\n if (!isObj(r)) return bad(at, `rows[${i}] must be an object`);\n unknownKeys(r, ROW_KEYS, at);\n if (typeof r._key !== \"string\" || r._key === \"\" || r._key.length > TABLE_LIMITS.keyChars) bad([...at, \"_key\"], `needs a _key string of 1 to ${TABLE_LIMITS.keyChars} characters`);\n else if (rowKeys.has(r._key)) bad([...at, \"_key\"], `_key \"${r._key}\" is used twice`);\n else rowKeys.add(r._key);\n if (r.group !== undefined && (typeof r.group !== \"string\" || !rowGroups.has(r.group))) bad([...at, \"group\"], `group \"${String(r.group)}\" is not a key of rowGroups`);\n bool(r.footer, [...at, \"footer\"], \"footer\");\n bool(r.highlight, [...at, \"highlight\"], \"highlight\");\n oneOf(r.type, [...at, \"type\"], \"type\", TABLE_COLUMN_TYPES);\n if (!isObj(r.cells)) return bad([...at, \"cells\"], \"cells must be an object keyed by column _key\");\n for (const [k, cell] of Object.entries(r.cells)) {\n const cAt = [...at, \"cells\", k];\n const col = cols.get(k);\n if (!col) {\n bad(cAt, `no column has _key \"${k}\"`);\n continue;\n }\n cellProblems(cell, col, r as unknown as TableRow, cAt, notes, opts, bad);\n }\n });\n return out;\n}\n\nfunction cellProblems(\n cell: unknown,\n col: TableColumn,\n row: TableRow,\n at: Array<string | number>,\n notes: Set<string>,\n opts: TableCheckOptions,\n bad: (path: Array<string | number>, message: string, code?: string) => void,\n): void {\n if (cell === undefined || cell === null) return;\n let v: unknown = cell;\n let vAt = at;\n if (isTableCellObject(cell)) {\n for (const k of Object.keys(cell)) if (!CELL_KEYS.has(k)) bad([...at, k], `unknown key \"${k}\" (value, type, note)`);\n if (cell.type !== undefined && !TABLE_COLUMN_TYPES.includes(cell.type)) bad([...at, \"type\"], `type must be one of ${TABLE_COLUMN_TYPES.join(\", \")}`);\n if (cell.note !== undefined && (typeof cell.note !== \"string\" || !notes.has(cell.note))) bad([...at, \"note\"], `note \"${String(cell.note)}\" is not a key of footnotes`);\n v = cell.value;\n vAt = [...at, \"value\"];\n if (v === null) return;\n }\n const type = tableCellType(col, row, cell);\n if (typeof v === \"string\") {\n if (v.length > TABLE_LIMITS.cellChars) bad(vAt, `a cell holds at most ${TABLE_LIMITS.cellChars} characters`, \"table_limit_exceeded\");\n return;\n }\n if (typeof v === \"number\") {\n if (!Number.isFinite(v)) bad(vAt, \"a number cell must be finite\");\n return;\n }\n if (typeof v === \"boolean\") return;\n if (!isObj(v)) return bad(vAt, \"a cell holds text, a number, true / false, a link { label, href } or a reference { ref }\");\n if (\"ref\" in v) {\n if (type !== \"reference\") return bad(vAt, `a reference { ref } belongs in a reference cell; this cell is ${type}`);\n for (const k of Object.keys(v)) if (!REF_KEYS.has(k)) bad([...vAt, k], `unknown key \"${k}\" (ref, label, href)`);\n if (typeof v.ref !== \"string\" || v.ref === \"\") bad([...vAt, \"ref\"], \"ref must be the id of a page or an entry\");\n if (v.label !== undefined && typeof v.label !== \"string\") bad([...vAt, \"label\"], \"label must be a string\");\n if (v.href !== undefined && (typeof v.href !== \"string\" || isScriptHref(v.href))) bad([...vAt, \"href\"], \"href must be a link the site can hold (no script links)\", \"link_value_invalid\");\n return;\n }\n if (type !== \"link\") return bad(vAt, `a link { label, href } belongs in a link cell; this cell is ${type}`);\n for (const k of Object.keys(v)) if (!LINK_KEYS.has(k)) bad([...vAt, k], `unknown key \"${k}\" (label, href, newTab, rel)`);\n if (typeof v.label !== \"string\" && v.label !== undefined) bad([...vAt, \"label\"], \"label must be a string\");\n if (typeof v.href !== \"string\") return bad([...vAt, \"href\"], \"needs an href string\", \"link_value_invalid\");\n if (isScriptHref(v.href)) return bad([...vAt, \"href\"], \"script links (javascript:, data:, vbscript:) aren't allowed\", \"link_value_invalid\");\n const grammar = v.href !== \"\" ? opts.hrefProblem?.(v.href) : null;\n if (grammar) bad([...vAt, \"href\"], grammar, \"link_value_invalid\");\n if (v.newTab !== undefined && typeof v.newTab !== \"boolean\") bad([...vAt, \"newTab\"], \"newTab must be true or false\", \"link_value_invalid\");\n if (v.rel !== undefined && !TABLE_LINK_RELS.includes(v.rel as string)) bad([...vAt, \"rel\"], `rel must be one of ${TABLE_LINK_RELS.join(\", \")}`, \"link_value_invalid\");\n}\n\n/** A {@link TableProblem}'s path as the dotted / indexed string error maps use: `rows[2].cells.price`. */\nexport function tablePathString(path: ReadonlyArray<string | number>): string {\n return path.map((s, i) => (typeof s === \"number\" ? `[${s}]` : i === 0 ? s : `.${s}`)).join(\"\");\n}\n\n/**\n * The stored form of a table value: explicit `headerRow` / `headerColumn`, and no `resolved` on a\n * reference cell (a read writes it; a client echoing a read back must not store it). Everything\n * else is kept as sent. A value that is not table-shaped is returned as is, for the validator.\n */\nexport function normalizeTableValue<T>(value: T): T {\n if (!isTableValue(value)) return value;\n const t = structuredClone(value) as unknown as TableValue;\n t.headerRow = t.headerRow !== false;\n t.headerColumn = t.headerColumn === true;\n for (const r of t.rows) {\n if (!isObj(r) || !isObj(r.cells)) continue;\n for (const c of Object.values(r.cells)) {\n const v = isTableCellObject(c) ? c.value : c;\n if (isTableRef(v)) delete (v as TableRef).resolved;\n }\n }\n return t as unknown as T;\n}\n\n/** The value as the renderers read it: the header flags' defaults, nothing removed (a read's `resolved` is what they print). */\nconst readTable = (v: TableValue): TableValue => ({ ...v, headerRow: v.headerRow !== false, headerColumn: v.headerColumn === true });\n\n/** Every reference cell a table holds: the object (resolved in place by a read), its id, path and column's `refTo`. */\nexport function tableRefCells(value: unknown): Array<{ cell: TableRef; id: string; path: Array<string | number>; refTo: string[] | null }> {\n if (!isTableValue(value)) return [];\n const cols = new Map(value.columns.filter(isObj).map((c) => [c._key, c]));\n const out: Array<{ cell: TableRef; id: string; path: Array<string | number>; refTo: string[] | null }> = [];\n value.rows.forEach((r, i) => {\n if (!isObj(r) || !isObj(r.cells)) return;\n for (const [k, c] of Object.entries(r.cells)) {\n const col = cols.get(k);\n if (!col) continue;\n const v = isTableCellObject(c) ? c.value : c;\n if (!isTableRef(v) || typeof v.ref !== \"string\" || v.ref === \"\" || tableCellType(col, r, c) !== \"reference\") continue;\n out.push({ cell: v, id: v.ref, path: [\"rows\", i, \"cells\", k, ...(isTableCellObject(c) ? [\"value\"] : [])], refTo: Array.isArray(col.refTo) && col.refTo.length ? col.refTo : null });\n }\n });\n return out;\n}\n\n// ── text, HTML, Markdown ───────────────────────────────────────────────────────────────────────\n\nconst strip = (s: string) => s.replace(/<[^>]*>/g, \"\").replace(/ /g, \" \").replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/"/g, '\"').replace(/'/g, \"'\");\nconst TRUE_WORDS = new Set([\"✓\", \"✔\", \"✔️\", \"☑\", \"✅\", \"yes\", \"y\", \"true\", \"included\", \"available\", \"supported\", \"check\", \"●\"]);\nconst FALSE_WORDS = new Set([\"✗\", \"✕\", \"✖\", \"❌\", \"×\", \"x\", \"no\", \"n\", \"false\", \"not included\", \"unavailable\", \"not available\", \"unsupported\", \"—\", \"–\", \"-\", \"○\"]);\nfunction toBool(v: unknown): boolean | null {\n if (typeof v === \"boolean\") return v;\n if (typeof v !== \"string\") return null;\n const s = strip(v).trim().toLowerCase();\n return TRUE_WORDS.has(s) ? true : FALSE_WORDS.has(s) ? false : null;\n}\nfunction toNumber(v: unknown): number | null {\n if (typeof v === \"number\") return Number.isFinite(v) ? v : null;\n if (typeof v !== \"string\") return null;\n const s = v.replace(/[,\\s]/g, \"\").replace(/[^\\d.+-]/g, \"\");\n return s && /^[+-]?\\d*\\.?\\d+$/.test(s) ? Number(s) : null;\n}\nconst formatNumber = (n: number, decimals?: number) =>\n new Intl.NumberFormat(\"en-US\", decimals != null ? { minimumFractionDigits: decimals, maximumFractionDigits: decimals } : { maximumFractionDigits: 6 }).format(n);\nfunction formatMoney(n: number, currency = \"USD\", decimals?: number) {\n try {\n const whole = Number.isInteger(n) && decimals == null;\n return new Intl.NumberFormat(\"en-US\", { style: \"currency\", currency, minimumFractionDigits: whole ? 0 : (decimals ?? 2), maximumFractionDigits: whole ? 0 : (decimals ?? 2) }).format(n);\n } catch {\n return `${formatNumber(n, decimals)} ${currency}`;\n }\n}\nconst isEmptyCell = (v: TableCellValue) => v == null || v === \"\" || (isObj(v) && !(isTableRef(v) ? v.ref : (v as TableLink).label || (v as TableLink).href));\nconst refLabel = (r: TableRef) => r.resolved?.title || r.label || r.ref;\nconst refHref = (r: TableRef) => r.resolved?.url ?? r.href;\n\n/** The words a cell says (Markdown, search, screen readers). Booleans say their words, never a tick. */\nexport function tableCellText(col: TableColumn, row: TableRow | undefined, c: unknown): string {\n const v = tableCellValue(c);\n if (isEmptyCell(v)) return \"\";\n switch (tableCellType(col, row, c)) {\n case \"boolean\": {\n const b = toBool(v);\n return b == null ? strip(String(v)) : b ? col.trueLabel || \"Included\" : col.falseLabel || \"Not included\";\n }\n case \"number\": {\n const n = toNumber(v);\n return n == null ? strip(String(v)) : `${formatNumber(n, col.decimals)}${col.unit ? (/^[%°]/.test(col.unit) ? col.unit : ` ${col.unit}`) : \"\"}`;\n }\n case \"money\": {\n const n = toNumber(v);\n return n == null ? strip(String(v)) : formatMoney(n, col.currency || \"USD\", col.decimals);\n }\n case \"rating\": {\n const n = toNumber(v);\n return n == null ? strip(String(v)) : `${formatNumber(n, 1).replace(/\\.0$/, \"\")} out of ${col.max ?? 5}`;\n }\n case \"link\":\n return isObj(v) ? String((v as TableLink).label || (v as TableLink).href || \"\") : strip(String(v));\n case \"reference\":\n return isTableRef(v) ? refLabel(v) : strip(String(v));\n default:\n return isObj(v) ? String((v as TableLink).label ?? \"\") : strip(String(v)).replace(/\\s+/g, \" \").trim();\n }\n}\n\nconst esc = (s: string) => s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\nconst escAttr = (s: string) => esc(s).replace(/\"/g, \""\");\nconst safeHref = (h: string) => (isScriptHref(h) ? \"#\" : h);\nconst INLINE_TAGS = new Set([\"strong\", \"b\", \"em\", \"i\", \"u\", \"s\", \"del\", \"code\", \"a\", \"br\", \"sup\", \"sub\", \"mark\", \"small\", \"abbr\"]);\n/** Inline rich text in a cell: only inline marks and safe links survive. */\nfunction sanitizeInline(html: string): string {\n return html\n .replace(/<(script|style|iframe|object|embed|template)\\b[\\s\\S]*?<\\/\\1>/gi, \"\")\n .replace(/<\\/?([a-z][a-z0-9]*)\\b([^>]*)>/gi, (m, tag: string, attrs: string) => {\n const t = tag.toLowerCase();\n if (!INLINE_TAGS.has(t)) return \"\";\n const name = t === \"b\" ? \"strong\" : t === \"i\" ? \"em\" : t;\n if (m.startsWith(\"</\")) return `</${name}>`;\n if (t === \"a\") {\n const href = attrs.match(/href\\s*=\\s*(\"([^\"]*)\"|'([^']*)')/i);\n return `<a href=\"${escAttr(safeHref(href ? (href[2] ?? href[3] ?? \"\") : \"\"))}\">`;\n }\n if (t === \"abbr\") {\n const title = attrs.match(/title\\s*=\\s*\"([^\"]*)\"/i);\n return title ? `<abbr title=\"${escAttr(title[1]!)}\">` : \"<abbr>\";\n }\n return `<${name}>`;\n });\n}\nconst alignOf = (col: TableColumn, t: TableColumnType) => col.align ?? (t === \"number\" || t === \"money\" || t === \"rating\" ? \"end\" : \"start\");\n\n/** Rows in display order: ungrouped body rows, then each row group in order, then footer rows. */\nfunction orderedRows(t: TableValue) {\n const groups = (t.rowGroups ?? []).filter(isObj);\n const known = new Set(groups.map((g) => g._key));\n const body = t.rows.filter((r) => isObj(r) && !r.footer);\n const loose = body.filter((r) => !r.group || !known.has(r.group));\n const bodies: { group?: TableGroup; rows: TableRow[] }[] = [];\n if (loose.length || !groups.length) bodies.push({ rows: loose });\n for (const g of groups) {\n const rows = body.filter((r) => r.group === g._key);\n if (rows.length) bodies.push({ group: g, rows });\n }\n return { bodies, foot: t.rows.filter((r) => isObj(r) && r.footer) };\n}\n\nfunction cellHtml(t: TableValue, col: TableColumn, row: TableRow, c: unknown, fn: Map<string, number>, asHeader: boolean): { inner: string; align: string } {\n const v = tableCellValue(c);\n const type = tableCellType(col, row, c);\n const note = isTableCellObject(c) ? c.note : undefined;\n const n = note ? fn.get(note) : undefined;\n const sup = n ? `<sup><a href=\"#${escAttr(t.id ?? \"tbl\")}-fn-${n}\" aria-label=\"Note ${n}\">${n}</a></sup>` : \"\";\n let inner: string;\n if (isEmptyCell(v)) inner = asHeader ? \"\" : `<span aria-hidden=\"true\" class=\"bt-dash\">—</span><span class=\"bt-sr\">No value</span>`;\n else\n switch (type) {\n case \"boolean\": {\n const b = toBool(v);\n inner = b == null ? esc(strip(String(v))) : `<span aria-hidden=\"true\" class=\"bt-bool\" data-bool=\"${b}\">${b ? \"✓\" : \"–\"}</span><span class=\"bt-sr\">${esc(b ? col.trueLabel || \"Included\" : col.falseLabel || \"Not included\")}</span>`;\n break;\n }\n case \"rating\": {\n const num = toNumber(v);\n inner = num == null ? esc(strip(String(v))) : `<span aria-hidden=\"true\" class=\"bt-star\">★</span> ${esc(formatNumber(num, 1).replace(/\\.0$/, \"\"))}<span class=\"bt-dim\"> / ${col.max ?? 5}</span>`;\n break;\n }\n case \"link\": {\n const l = isObj(v) ? (v as TableLink) : { label: String(v), href: \"\" };\n const rel = [l.newTab ? \"noopener noreferrer\" : \"\", l.rel && l.rel !== \"follow\" ? l.rel : \"\"].filter(Boolean).join(\" \");\n inner = l.href ? `<a href=\"${escAttr(safeHref(l.href))}\"${l.newTab ? ' target=\"_blank\"' : \"\"}${rel ? ` rel=\"${rel}\"` : \"\"}>${esc(l.label || l.href)}</a>` : esc(l.label ?? \"\");\n break;\n }\n case \"reference\": {\n if (!isTableRef(v)) {\n inner = esc(strip(String(v)));\n break;\n }\n const href = refHref(v);\n inner = href ? `<a href=\"${escAttr(safeHref(href))}\">${esc(refLabel(v))}</a>` : esc(refLabel(v));\n break;\n }\n case \"richtext-inline\":\n inner = sanitizeInline(String(isObj(v) ? ((v as TableLink).label ?? \"\") : v));\n break;\n default:\n inner = esc(type === \"number\" || type === \"money\" ? tableCellText(col, row, c) : isObj(v) ? String((v as TableLink).label ?? \"\") : strip(String(v)));\n }\n return { inner: inner + sup, align: alignOf(col, type) };\n}\n\n/**\n * The few rules every rendered table needs wherever it lands (a hosted page, a prop's `props.html`,\n * a code site): screen-reader-only words, the scroll region, cell padding. Scoped to `.bt-table`\n * and carried in the figure, so a page without a table ships none of it.\n */\nexport const TABLE_CSS =\n \".bt-table .bt-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\" +\n \".bt-table .bt-scroll{overflow-x:auto}.bt-table table{border-collapse:collapse;width:100%}\" +\n \".bt-table th,.bt-table td{padding:8px 12px;border-bottom:1px solid #e5e5e5;text-align:start;vertical-align:top}\" +\n '.bt-table [data-align=\"end\"]{text-align:end}.bt-table [data-align=\"center\"]{text-align:center}' +\n \".bt-table caption{text-align:start;font-weight:600;padding-bottom:8px}.bt-table .bt-notes{font-size:.9em;margin-top:8px}\";\n\n/**\n * The table as semantic HTML (published form: no editing marks): `<figure class=\"bt-table\">` ›\n * `<table>` with caption, column-group headers, `<thead>`, one `<tbody>` per row group, `<tfoot>`,\n * then notes and footnotes. Stack / cards layouts restate the table roles (CSS display drops them).\n */\nexport function renderTableHtml(input: TableValue): string {\n const t = readTable(input);\n const id = (t.id ?? \"tbl\").replace(/[^\\w-]/g, \"\") || \"tbl\";\n const cols = t.columns.filter(isObj);\n const n = cols.length;\n if (!n) return \"\";\n const fn = new Map((t.footnotes ?? []).filter(isObj).map((f, i) => [f._key, i + 1]));\n const groups = (t.columnGroups ?? []).filter((g) => isObj(g) && cols.some((c) => c.group === g._key));\n const hasNotes = !!t.notes || fn.size > 0;\n const responsive = t.design?.responsive ?? \"scroll\";\n const fig: string[] = [];\n const attrs = [\n `class=\"bt-table\"`,\n `data-responsive=\"${escAttr(responsive)}\"`,\n t.design?.sticky ? `data-sticky=\"true\"` : \"\",\n t.design?.striped ? `data-striped=\"true\"` : \"\",\n t.design?.density === \"compact\" ? `data-density=\"compact\"` : \"\",\n ].filter(Boolean);\n fig.push(`<figure ${attrs.join(\" \")}><style>${TABLE_CSS}</style>`);\n fig.push(`<div class=\"bt-scroll\" role=\"region\" tabindex=\"0\" aria-labelledby=\"${id}-caption\">`);\n fig.push(`<table${hasNotes ? ` aria-describedby=\"${id}-notes\"` : \"\"}>`);\n fig.push(`<caption id=\"${id}-caption\"${t.design?.hideCaption ? ` class=\"bt-sr\"` : \"\"}>${esc(t.caption || \"Table\")}</caption>`);\n if (t.headerRow) {\n fig.push(\"<thead>\");\n if (groups.length) {\n const cells: string[] = [];\n for (let i = 0; i < n; ) {\n const g = cols[i]!.group ? groups.find((x) => x._key === cols[i]!.group) : undefined;\n if (!g) {\n cells.push(\"<td></td>\");\n i++;\n continue;\n }\n let span = 1;\n while (i + span < n && cols[i + span]!.group === g._key) span++;\n cells.push(`<th scope=\"colgroup\"${span > 1 ? ` colspan=\"${span}\"` : \"\"}>${esc(g.label)}</th>`);\n i += span;\n }\n fig.push(`<tr>${cells.join(\"\")}</tr>`);\n }\n fig.push(\n `<tr>${cols\n .map((c, i) => {\n if (i === 0 && t.headerColumn && !String(c.label ?? \"\").trim()) return \"<td></td>\";\n const align = alignOf(c, c.type);\n return `<th scope=\"col\"${align !== \"start\" ? ` data-align=\"${align}\"` : \"\"}${c.highlight ? ` data-highlight=\"true\"` : \"\"}${c.description ? ` title=\"${escAttr(c.description)}\"` : \"\"}>${esc(c.label || `Column ${i + 1}`)}</th>`;\n })\n .join(\"\")}</tr>`,\n );\n fig.push(\"</thead>\");\n }\n const rowHtml = (r: TableRow) => {\n const cells = cols.map((c, i) => {\n const asTh = t.headerColumn && i === 0;\n const { inner, align } = cellHtml(t, c, r, isObj(r.cells) ? r.cells[c._key] : undefined, fn, asTh);\n const a = `${align !== \"start\" ? ` data-align=\"${align}\"` : \"\"}${c.highlight ? ` data-highlight=\"true\"` : \"\"}`;\n return asTh ? `<th scope=\"row\"${a}>${inner}</th>` : `<td data-label=\"${escAttr(c.label || `Column ${i + 1}`)}\"${a}>${inner}</td>`;\n });\n return `<tr${r.highlight ? ` data-highlight=\"true\"` : \"\"}>${cells.join(\"\")}</tr>`;\n };\n const { bodies, foot } = orderedRows(t);\n for (const b of bodies) {\n fig.push(\"<tbody>\");\n if (b.group) fig.push(`<tr class=\"bt-group\"><th scope=\"rowgroup\" colspan=\"${n}\">${esc(b.group.label)}</th></tr>`);\n fig.push(b.rows.map(rowHtml).join(\"\"));\n fig.push(\"</tbody>\");\n }\n if (foot.length) fig.push(`<tfoot>${foot.map(rowHtml).join(\"\")}</tfoot>`);\n fig.push(\"</table></div>\");\n if (hasNotes) {\n fig.push(`<div class=\"bt-notes\" id=\"${id}-notes\">`);\n if (t.notes) fig.push(`<p>${esc(t.notes)}</p>`);\n if (fn.size) fig.push(`<ol>${(t.footnotes ?? []).filter(isObj).map((f, i) => `<li id=\"${id}-fn-${i + 1}\">${esc(f.text)}</li>`).join(\"\")}</ol>`);\n fig.push(\"</div>\");\n }\n fig.push(\"</figure>\");\n const html = fig.join(\"\");\n return responsive === \"stack\" || responsive === \"cards\"\n ? html\n .replace(/<table(?=[\\s>])/, '<table role=\"table\"')\n .replace(/<(thead|tbody|tfoot)(?=[\\s>])/g, '<$1 role=\"rowgroup\"')\n .replace(/<tr(?=[\\s>])/g, '<tr role=\"row\"')\n .replace(/<th scope=\"(col|colgroup)\"/g, '<th role=\"columnheader\" scope=\"$1\"')\n .replace(/<th scope=\"(row|rowgroup)\"/g, '<th role=\"rowheader\" scope=\"$1\"')\n .replace(/<td(?=[\\s>])/g, '<td role=\"cell\"')\n : html;\n}\n\n/**\n * Text a Markdown reader must not parse as HTML: `<` and `>` as entities (they render as the\n * characters), as the HTML table escapes them. A link target `](…)` is left as written.\n */\nconst mdSafe = (s: string) => s.replace(/(\\]\\([^)]*\\))|[<>]/g, (m: string, link?: string) => link ?? (m === \"<\" ? \"<\" : \">\"));\nconst mdCell = (s: string) => mdSafe(s).replace(/\\\\/g, \"\\\\\\\\\").replace(/\\|/g, \"\\\\|\").replace(/\\s*\\n\\s*/g, \" \").trim();\nconst inlineMd = (html: string): string =>\n strip(\n sanitizeInline(html)\n .replace(/<(strong)>([\\s\\S]*?)<\\/\\1>/g, \"**$2**\")\n .replace(/<(em)>([\\s\\S]*?)<\\/\\1>/g, \"_$2_\")\n .replace(/<code>([\\s\\S]*?)<\\/code>/g, \"`$1`\")\n .replace(/<a href=\"([^\"]*)\">([\\s\\S]*?)<\\/a>/g, (_m, h: string, l: string) => `[${l}](${h.replace(/&/g, \"&\")})`)\n .replace(/<br>/g, \" \"),\n );\n\n/**\n * The table as GFM: the caption in bold above, one header row (a column group prefixes its\n * columns: \"Sizes · Chest\"), a row group as a bold label row, then notes, column descriptions and\n * footnotes. Booleans say their words. Links and resolved references are Markdown links.\n */\nexport function tableToMarkdown(input: TableValue): string {\n const t = readTable(input);\n const cols = t.columns.filter(isObj);\n if (!cols.length) return \"\";\n const groups = new Map((t.columnGroups ?? []).filter(isObj).map((g) => [g._key, g.label]));\n const fn = new Map((t.footnotes ?? []).filter(isObj).map((f, i) => [f._key, i + 1]));\n const pfx = (t.id ?? \"t\").replace(/[^\\w-]/g, \"\") || \"t\";\n const line = (cells: string[]) => `| ${cells.join(\" | \")} |`;\n const head = cols.map((c, i) => mdCell([c.group && groups.get(c.group), c.label || (i === 0 && t.headerColumn ? \"\" : `Column ${i + 1}`)].filter(Boolean).join(\" · \")) || \" \");\n const sep = cols.map((c) => (alignOf(c, c.type) === \"end\" ? \"---:\" : alignOf(c, c.type) === \"center\" ? \":---:\" : \"---\"));\n const row = (r: TableRow) =>\n line(\n cols.map((c, i) => {\n const cell = isObj(r.cells) ? r.cells[c._key] : undefined;\n const v = tableCellValue(cell);\n const ty = tableCellType(c, r, cell);\n let s = ty === \"richtext-inline\" && typeof v === \"string\" ? inlineMd(v) : tableCellText(c, r, cell);\n if (ty === \"link\" && isTableLink(v) && v.href && !isScriptHref(v.href)) s = `[${s}](${v.href})`;\n if (ty === \"reference\" && isTableRef(v)) {\n const href = refHref(v);\n if (href && !isScriptHref(href)) s = `[${s}](${href})`;\n }\n if (!s && !(t.headerColumn && i === 0)) s = \"—\";\n if (t.headerColumn && i === 0 && s) s = `**${s}**`;\n const note = isTableCellObject(cell) ? cell.note : undefined;\n if (note && fn.get(note)) s += `[^${pfx}-${fn.get(note)}]`;\n return mdCell(s) || \" \";\n }),\n );\n const out: string[] = [`**${mdCell(t.caption || \"Table\")}**`, \"\", line(head), line(sep)];\n const { bodies, foot } = orderedRows(t);\n for (const b of bodies) {\n if (b.group) out.push(line([`**${mdCell(b.group.label)}**`, ...cols.slice(1).map(() => \" \")]));\n b.rows.forEach((r) => out.push(row(r)));\n }\n foot.forEach((r) => out.push(row(r)));\n const after: string[] = [];\n if (t.notes) after.push(mdSafe(t.notes));\n const described = cols.filter((c) => c.description);\n if (described.length) after.push(mdSafe(described.map((c) => `${c.label}: ${c.description}`).join(\". \") + \".\"));\n if (fn.size) after.push((t.footnotes ?? []).filter(isObj).map((f, i) => `[^${pfx}-${i + 1}]: ${mdSafe(f.text)}`).join(\"\\n\"));\n return [out.join(\"\\n\"), ...after].join(\"\\n\\n\");\n}\n\n/** The words a table holds, for site search: caption, notes, headers, group labels, every cell's text, footnotes. */\nexport function tableSearchText(input: unknown): string {\n if (!isTableValue(input)) return \"\";\n const t = input;\n const cols = t.columns.filter(isObj);\n const parts: string[] = [t.caption, t.notes ?? \"\"];\n for (const c of cols) parts.push(c.label, c.description ?? \"\");\n for (const g of [...(t.columnGroups ?? []), ...(t.rowGroups ?? [])]) if (isObj(g)) parts.push(g.label);\n for (const r of t.rows) {\n if (!isObj(r) || !isObj(r.cells)) continue;\n for (const c of cols) {\n const cell = r.cells[c._key];\n parts.push(tableCellType(c, r, cell) === \"richtext-inline\" ? strip(String(tableCellValue(cell) ?? \"\")) : tableCellText(c, r, cell));\n }\n }\n for (const f of t.footnotes ?? []) if (isObj(f)) parts.push(f.text);\n return parts.filter((p) => typeof p === \"string\" && p.trim() !== \"\").map((p) => p.trim()).join(\" \");\n}\n","import type { DockIconName } from \"./dock-icon-names.js\";\nimport type { NumberFieldFormat } from \"./number-format.js\";\n\n/** Longest `description` a choice option may carry: one line under its label (V2's longest is 71). */\nexport const OPTION_DESCRIPTION_MAX = 140;\n\n/**\n * One choice of a select / multiselect / tags field or prop. Values are judged by `value` alone;\n * `icon` (a dock icon name, bettercms://icons/dock) and `description` (one line under the label)\n * are editor chrome. A bare string is a choice whose label is its value.\n */\nexport interface ChoiceOption {\n label: string;\n value: string;\n /** A `DockIconName`, typed as a string so a stored row (db `ComponentPropDef`) stays assignable. */\n icon?: string;\n description?: string;\n}\n\n/**\n * ContentModel — the structured content model (schema) for a workspace.\n * Defines which content fields are available for authors to fill in.\n */\nexport interface ContentModel {\n id: string;\n workspaceId: string;\n name: string;\n description?: string;\n /** 'block' models hold no entries — they are instantiable only inside a `modular` field. */\n kind?: ContentModelKind;\n fields: ContentModelField[];\n /** Authoring-only field grouping for the schema builder. Never affects the API shape. */\n fieldsets?: Fieldset[];\n createdAt: string; // ISO 8601\n updatedAt: string; // ISO 8601\n}\n\n/**\n * Canonical field types. Nesting lives on `array` via `config.zones`\n * (see {@link ArrayZoneConfig}): `group`/`repeater` are accepted as legacy input\n * by the API but normalized to `array` + zones on write, so stored/delivered\n * content never contains them.\n */\nexport type ContentModelFieldType =\n | \"text\"\n | \"richtext\"\n // THE article body — a document canvas, at most one per collection. Stored exactly like\n // `richtext` (same {format, value, html} envelope, same toRichTextEnvelope funnel), so it\n // needed no migration; the editor and the placement are what differ. Named `document`, not\n // `body`, because `placement` already has a \"body\" member: that is the SLOT, this is the\n // TYPE. Authors still see it labelled \"Body\".\n // Declared in FOUR places — keep in lockstep with packages/db/src/schema/content_models.ts,\n // ContentModelFieldOutput and the discriminated union in\n // src/lib/validation/schemas/content.ts. Only tsc catches a miss here, and only because\n // that union is cast `as unknown as` — it will NOT flag the type omission on its own.\n | \"document\"\n | \"image\"\n | \"boolean\"\n | \"number\"\n | \"select\"\n | \"reference\"\n | \"multi-reference\"\n // Same field type, camelCase. NOT a typo and NOT dead: the template seeder and the\n // Webflow migrator write this spelling (they insert via jsonb_populate_recordset,\n // bypassing Zod), and the dashboard's FieldRenderer only switches on camelCase. Real\n // rows carry it — both starter templates ship one — so every consumer of this union\n // must handle BOTH spellings.\n | \"multiReference\"\n | \"array\" // the canonical nesting type — see config.zones\n | \"date\"\n | \"datetime\"\n // ── Builder scalars ────────────────────────────────────────────────────────\n // Offered by the schema builder's field picker. Each one is VALUE-validated in\n // src/lib/content/reference-validation.ts — accepting the type without checking\n // the value would make the picker's promise (\"Validated email address\") a lie.\n | \"longtext\"\n | \"slug\"\n | \"email\"\n | \"phone\"\n | \"link\"\n | \"color\"\n | \"json\"\n | \"file\"\n // ── Component reference ────────────────────────────────────────────────────\n // A slot in the schema that holds ONE component instance. Deliberately NOT\n // named \"component\": that name already belongs to a BLOCK type\n // (componentBlockSchema, src/lib/validation/schemas/content.ts), and this\n // codebase has seven field-type lists that already disagree with each other —\n // reusing the name is how a field type ends up in a block union.\n //\n // The value is a REFERENCE, not an embedded tree:\n // draft (data) { componentId, overrides }\n // published (published_data) + resolved: the frozen block tree\n // Publishing snapshots the resolved component, so editing a component does not\n // silently rewrite entries that were already published.\n | \"component-ref\"\n // ── Modular content ────────────────────────────────────────────────────────\n // An ordered array of POLYMORPHIC block instances, each one an instance of a\n // kind='block' content model. This is the thing `array` + zones cannot express:\n // a repeatable zone has ONE fixed field set, so every item has the same shape,\n // whereas each item here may be any one of the block types the field allows.\n //\n // The stored shape IS the delivered shape — ModularBlock[], verbatim, with no\n // publish-time resolution step (unlike component-ref above). That is deliberate:\n // the one field-shape incident this codebase has had came from a type whose\n // delivered payload differed from its authored one, and `modular` is new enough\n // that no row exists to migrate.\n | \"modular\"\n // ── Section zone ───────────────────────────────────────────────────────────\n // A composable page region. The value is a BLOCK TREE — `ContentBlock[]`, the exact\n // shape `pages.block_json` already holds — NOT the flat ModularBlock[] that `modular`\n // above uses. `config.allowedSections` names which section slugs may be inserted.\n //\n // Why not just reuse `modular`, which is otherwise the same idea: page content is\n // RECURSIVE. `columns` holds ContentBlock[][], and `section`/`slider`/`tabs` each hold\n // `children: ContentBlock[]`. A flat {__id,__type,data} item cannot carry those subtrees\n // without inventing a nesting encoding, and any encoding changes what renderBlocks emits\n // — which would make migrating an existing page into one of these fields lossy. 10 live\n // pages carry container blocks today, so this is not hypothetical.\n //\n // Sharing the block tree is what makes the rest free: renderBlocks, the page builder's\n // tree ops, and the content-lock walker (which duck-types a block as {id,type,props})\n // all work on this value unchanged.\n | \"sections\"\n // ── Location ───────────────────────────────────────────────────────────────\n // { lat, lng, label? }. No existing type can stand in for it: `json` accepts\n // anything and two `number` fields cannot be validated as a coordinate pair.\n | \"location\"\n // One button as one value: { label, href, variant?, size?, arrow?, icon?, newTab? }\n // (`ButtonValue`, button-look.ts). A leaf with no config, like `location`.\n | \"button\"\n // A string[] of `config.options` values (tags when `config.allowCustom`), and a BetterCMS icon\n // name (DOCK_ICON_NAMES) or an uploaded icon as an image value. Leaves, like `location`.\n | \"multiselect\"\n | \"icon\"\n // V2 schema language: ONE nested object of named `fields`, stored as `{ [childKey]: value }`.\n // Unlike legacy `group` it is kept as `object` on write (not normalized into array zones).\n | \"object\"\n // V2 leaves (DESIGN.md §6.6 D47, §8.4, §8.21): a taxonomy string[] (`config.options` suggestions,\n // `max`, `allowCustom`), a 0..`config.max` rating number, and `{ language?, code }` or a string.\n | \"tags\"\n | \"rating\"\n | \"code\"\n // V2 video (DESIGN.md §6.2, §8.15): a URL string, or `{ url, poster?, autoplay?, loop?, transcript? }`\n // (the video block's own props). @see VideoValue\n | \"video\"\n // V2 table (CPO D42): typed, keyed columns × keyed rows, `TableValue` (table-value.ts). The\n // field's `config` holds its options (columnTypes, lockColumns, minRows, maxRows, …).\n | \"table\"\n // V2 slot: blocks inside a block, INLINE: `{ _key, _type, _variant?, _settings?, ...values }[]`\n // (slot-child.ts), `_type` a kind='block' model's slug from `config.blockSlugs`. Unlike `modular`\n // ({ __id, __type, data }) a child's values sit at its root, as V2 stores them.\n | \"slot\";\n\n/** One block instance inside a `modular` field's value. */\nexport interface ModularBlock {\n /** Stable across reorders — the React key AND the diff identity. Never the array index. */\n __id: string;\n /** The block model's SLUG. Reserved keys are `__`-prefixed so an authored field\n * named `type` cannot collide with the discriminator. */\n __type: string;\n /** The block's own field values, in the same envelopes top-level fields use\n * (image `{url, altText}`, richtext `{format, value, html}`). */\n data: Record<string, unknown>;\n}\n\nexport interface LocationValue {\n lat: number;\n lng: number;\n label?: string;\n}\n\nexport type ContentModelKind = \"model\" | \"block\";\n\n/**\n * How a fieldset renders in the dock. ABSENT ≡ today's flat list (V2): a legacy `{id, name}`\n * fieldset never regroups anything.\n * - `group` a disclosure; `row` ≤3 pairable scalars on one line; `tab` one of ≤3 top-level tabs.\n */\nexport type FieldsetKind = \"group\" | \"row\" | \"tab\";\n\n/** Who last shaped a path's authoring chrome. Server-owned: a client echo is discarded. */\nexport type UiOrigin = \"human\" | \"agent\" | \"derived\";\n\n/**\n * The chrome a field had before the first agent write over a non-agent state, kept so a human\n * can revert it. Server-owned, like {@link UiOrigin}.\n */\nexport interface UiBefore {\n ui?: ContentModelFieldUi;\n fieldsetId?: string;\n /** Index among the field's siblings at the time. */\n position: number;\n label?: string;\n helpText?: string;\n /** The V2 editor keys, snapshotted with the rest so a Revert restores them. */\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n openMode?: OpenMode;\n}\n\n/**\n * A fieldset's chrome before the first agent change over a human/derived (or unstamped) state,\n * kept so a person can revert it. `label` is the set's `name`. Server-owned, like {@link UiOrigin}:\n * frozen while the origin stays `agent`, cleared by a human or derived change, carried by id.\n */\nexport interface FieldsetUiBefore {\n label: string;\n ui: {\n kind?: FieldsetKind;\n tab?: string;\n icon?: DockIconName;\n collapsed?: boolean;\n collapsible?: boolean;\n columns?: 1 | 2;\n layout?: \"stack\" | \"breakpoints\";\n };\n /** Its index among the model's fieldsets before the agent's change; absent on older snapshots. */\n position?: number;\n}\n\n/** A named, UI-only grouping of a model's fields. Order is the array index. */\nexport interface Fieldset {\n id: string;\n name: string;\n /** One line shown under the card title in the editor. Editor-only. */\n description?: string;\n kind?: FieldsetKind;\n icon?: DockIconName;\n /** A `group` that starts closed. */\n collapsed?: boolean;\n /** A group/row that sits inside this `kind:\"tab\"` fieldset. */\n tab?: string;\n /** `false`: a static heading with no toggle. */\n collapsible?: boolean;\n /** `2`: short fields side by side. */\n columns?: 1 | 2;\n /** `breakpoints`: its per-screen-size `object` fields (desktop, tablet, phone; joined by `fieldsetId`) shown as ONE group with a switcher. */\n layout?: \"stack\" | \"breakpoints\";\n uiOrigin?: UiOrigin;\n uiBefore?: FieldsetUiBefore;\n}\n\n/**\n * Nested-content config for an `array` field. A zone holds ordinary fields, and a\n * zone field may itself be an `array` with its own zones, so nesting is recursive\n * to any depth.\n * - `nonRepeatable` — a single fixed block of fields (former `group`).\n * - `repeatable` — a repeating list of field-objects (former `repeater`).\n * Mutually exclusive with the primitive form (`config.itemType`).\n */\nexport interface ArrayZoneConfig {\n nonRepeatable?: ContentModelField[];\n repeatable?: {\n fields: ContentModelField[];\n minItems?: number;\n maxItems?: number;\n };\n}\n\n/** Per-type config for a field (the typed shape behind the loose `config` bag). */\nexport interface FieldConfig {\n /**\n * primitive array: list of scalars, or of images, links or rich text (V2 `array` of one\n * primitive), each item judged by its own type's validator.\n */\n itemType?: \"text\" | \"number\" | \"date\" | \"image\" | \"link\" | \"richtext\";\n /** nested array: zoned fields (recursive) */\n zones?: ArrayZoneConfig;\n /** reference / multi-reference */\n contentModelId?: string;\n min?: number;\n max?: number;\n /** number: how the value is shown on the site (`$1,299.00`, `38%`). @see NumberFieldFormat */\n format?: NumberFieldFormat;\n /** A derived field whose value lives in an ATTRIBUTE and is written there: `aria-label`, or the `data-target` a count-up script reads. */\n attr?: string;\n /** date / datetime */\n includeTime?: boolean;\n /**\n * date / datetime with a time: \"site\" (the project's own zone), an IANA zone name, or V2 `true`\n * (the editor picks a zone) / `false` (no zone, ≡ absent). When set (not false), a stored value\n * must carry `Z` or a numeric offset, so it names one instant in every region.\n */\n timezone?: string | boolean;\n /** modular / slot: SLUGS of the kind='block' models this field accepts. Non-empty. */\n blockSlugs?: string[];\n /** slot: per-child layout settings, what each child's `_settings` holds (leaf fields). */\n slotSettings?: ContentModelField[];\n /** modular: bounds on how many block instances the field may hold; a primitive array (itemType): how many items. */\n minItems?: number;\n maxItems?: number;\n /**\n * sections: SLUGS of the sections an author may insert into this zone.\n *\n * Deliberately NOT named `blockSlugs`. That key means \"kind='block' content models\" and is\n * read by ModularField; these are section-registry slugs resolved from a different place.\n * One key meaning two things is how `blockModels`/`blockSlugs` already drifted apart in the\n * dashboard — a distinct name costs nothing and cannot be confused at a call site.\n *\n * ⚠ ABSENT ≠ EMPTY:\n * absent → UNRESTRICTED, every registry section may be inserted\n * [] → DENY ALL, a deliberate empty restriction\n * [a, b] → only those\n * `[]` means DENY here to match `components.allowed_on` (migration 0190), so two adjacent\n * allow-lists never disagree about what empty means.\n *\n * Absent rather than \"all current slugs\" because the registry GROWS — it is fed by repo\n * pushes and project components, so materializing today's slugs at field-creation time would\n * silently exclude every section shipped afterwards.\n *\n * NOT READ DIRECTLY. Insertability is this list INTERSECTED with the component's `allowedOn`\n * (where that section may be placed), computed by one resolver so the two cannot drift.\n *\n * Enforced on NEW picks only. Narrowing the list later must never invalidate sections an\n * author already placed, the same rule modular's blockSlugs and component-ref's allowlist\n * follow.\n */\n allowedSections?: string[];\n /** Durable project-local authored Zone mode. Legacy zones omit this key. */\n mode?: \"authored-v2\";\n /** Durable Zone id. Present when `mode` is `authored-v2`. */\n zoneId?: string;\n /** Explicit migration acknowledgement while the legacy allowlist remains readable. */\n legacyResolved?: boolean;\n /** number: a V2 scale (stepped range, numeric or token steps, units, presets, custom escape hatch). */\n scale?: NumberScale;\n /** number: V2 `numeric.unit`, what it counts (\"%\", \"USD\", \"days\"), shown beside the input. 1–24 chars. */\n unit?: string;\n /** number: V2 `validation.min / max`, the error bounds; they win over `min` / `max` (the input's range). */\n validation?: { min?: number; max?: number };\n /** text / longtext / richtext: length in characters (richtext: its plain text). */\n minLength?: number;\n maxLength?: number;\n /** text / longtext: a regex (≤ 200 characters) and the message shown when a value does not match it. */\n pattern?: string;\n patternMessage?: string;\n legacyMappings?: Record<string, string>;\n /**\n * image: `\"icon\"` marks an inline SVG icon the import derived (its value a `data:image/svg+xml`\n * url or an `image/svg+xml` asset). The editor offers an icon picker for it, and the dock budget\n * and the field-pruning guards leave it alone: an icon is editable content, never markup to tidy.\n */\n media?: \"icon\";\n /** multiselect / tags: the choices (tags: suggestions unless allowCustom is false). */\n options?: Array<string | ChoiceOption>;\n [key: string]: unknown;\n}\n\nexport type ScaleUnit = \"px\" | \"%\" | \"rem\" | \"em\" | \"vw\" | \"vh\";\n\n/** A V2 scale's custom value: a number in one of the scale's units. */\nexport interface ScaleCustomValue {\n value: number;\n unit: ScaleUnit;\n}\n\n/**\n * A number field's `config.scale` (V2 scale.ts, CPO D41). The value a field with a scale stores is\n * a bare number (range or numeric steps), a token step's string value, or a {@link ScaleCustomValue}\n * when `allowCustom` is set (within its bounds).\n */\nexport interface NumberScale {\n steps:\n | { min: number; max: number; step?: number }\n | Array<{ value: number; label?: string }>\n | Array<{ value: string; label: string; title?: string; px?: number; css?: string }>;\n units?: ScaleUnit[];\n defaultUnit?: ScaleUnit;\n /** Fixed values only (false, absent) or fixed + custom: `true`, or the custom value's bounds. */\n allowCustom?:\n | boolean\n | { min?: number | Partial<Record<ScaleUnit, number>>; max?: number | Partial<Record<ScaleUnit, number>>; units?: ScaleUnit[]; step?: number };\n presets?: Array<{ label?: string; value: number | string | ScaleCustomValue }>;\n}\n\n/** V2: how a compound field (an `object`, or an array's rows) opens when edited. Editor-only. */\nexport type OpenMode = \"inline\" | \"drill\" | \"popover\" | \"dialog\";\n\n/**\n * Where a field renders in the entry editor.\n *\n * AUTHORING ONLY — this has no delivery or storage effect. It does not change the\n * shape of `data`, is not read by any renderer in @bettercms-ai/next or /astro, and\n * cannot move a value onto or off a published page. It decides one thing: where the\n * control sits while somebody is writing.\n *\n * Granularity is REGION-level, never interleaved between body blocks: the canvas is\n * `[hero slots] → [free block flow] → [inline fields] → [panel fields in the drawer]`.\n * A field cannot be positioned \"between two paragraphs\" — there is no coordinate space\n * for that, and inventing one would mean mounting form controls inside the Lexical tree.\n *\n * - `cover` / `title` / `excerpt` / `body` — the four hero slots, rendered unlabelled\n * and typographically native. SCHEMA-LEVEL ONLY: a per-entry override may never\n * claim one, or one author's click renders anonymous 40px text over anonymous text\n * on that entry alone.\n * - `inline` — in the canvas, below the block flow, labelled.\n * - `panel` — in the drawer.\n *\n * ABSENT is meaningful and is the default for every model that predates this: the\n * editor falls back to its title-gated heuristic. Only an explicit value promotes a\n * field past that gate.\n */\nexport type ContentModelFieldPlacement = \"cover\" | \"title\" | \"excerpt\" | \"body\" | \"inline\" | \"panel\";\n\n/**\n * Editor-only conditional visibility: the field (or component prop) shows only while the\n * sibling keys its rules name hold these values. `isSet` reads no `value`: it passes once the\n * source holds anything (`false` and `0` count; \"\", null and an empty list do not).\n */\nexport interface ShowIfRule {\n field: string;\n /**\n * `notEmpty` ≡ `isSet`; `empty` passes while the source holds nothing. Neither reads `value`.\n * `notIn` is `in` negated. `gt` / `lt` compare numbers: `value` is one number as a string, and a\n * source that holds no number fails the rule.\n */\n op: \"eq\" | \"neq\" | \"in\" | \"notIn\" | \"gt\" | \"lt\" | \"isSet\" | \"notEmpty\" | \"empty\";\n value?: string | string[];\n}\nexport interface ShowIf {\n match: \"all\" | \"any\";\n rules: ShowIfRule[];\n}\n\nexport interface ContentModelField {\n key: string;\n label: string;\n type: ContentModelFieldType;\n /** Shown to editors under the field: what it is for, where it shows, any constraint. Never its value. */\n helpText?: string;\n required?: boolean;\n /**\n * No two entries of the model may hold the same value (trimmed, case-insensitive). On a\n * repeater child, every row of every entry at that path. Scalar types only.\n */\n unique?: boolean;\n defaultValue?: unknown;\n /** select: the choices (multiselect / tags keep theirs on `config.options`). */\n options?: Array<string | ChoiceOption>;\n /** Per-type config. For `array`: either `itemType` (primitive) or `zones` (nested). */\n config?: FieldConfig | null;\n /** `object`: its child fields. */\n fields?: ContentModelField[];\n /** `object` / `array`: how the value (or each row) opens when edited. */\n openMode?: OpenMode;\n /** Longer help behind the ⓘ next to the label. Editor-only. */\n helpMore?: string;\n /** Tuck into the closed \"Advanced\" section. Editor-only. */\n advanced?: boolean;\n /** A soft limit the editor warns at, never a refusal. */\n recommendedMax?: number;\n /**\n * Which fieldset this field renders under in the schema builder. Authoring-only: it is\n * never delivered and cannot move a value — see {@link Fieldset}.\n */\n fieldsetId?: string;\n /**\n * Authoring-only editor placement. See {@link ContentModelFieldPlacement}.\n * Field ORDER is the array index — there is deliberately no `order` property.\n */\n placement?: ContentModelFieldPlacement;\n /** Editor-only conditional visibility; a hidden required field is not required. @see ShowIf */\n showIf?: ShowIf;\n /**\n * A value another system owns (a store, job board or feed id).\n * - `\"developer\"`: only a caller with schema authority (a key with `schema:manage`, a person\n * with schema access) may change the value on an entry, or add or remove this lock. Anyone\n * else is refused with 403 `FIELD_LOCKED`. Needs {@link lockReason}.\n * - `true`: a marker the editor renders read-only. The API does not enforce it.\n */\n readOnly?: true | \"developer\";\n /** Which system owns the value; shown on the refusal. At most 200 characters. */\n lockReason?: string;\n /**\n * V2 per-field localization (the locale chip). Once any field of a schema is marked, a\n * translation row owns only its localized values; the rest are inherited from its source, and a\n * translation write that changes one is 409 `FIELD_NOT_LOCALIZED`. None marked: rows copy as before.\n */\n localized?: boolean;\n /**\n * Authoring chrome — how the field PRESENTS in the editor. Never delivered, never read by a\n * renderer, and never able to move a value; the same contract as {@link placement}.\n *\n * A SIBLING of `config`, not a member of it: `config` is per-type and strict on several\n * types, and the normalizer rebuilds it wholesale for every nesting field — so a `config.ui`\n * survives on leaves and vanishes on exactly the fields `preview` is for.\n *\n * `preview.title` / `preview.media` name a CHILD FIELD KEY of this field (validated on\n * write). Still no `order`: order is the array index, per the note on {@link placement}.\n */\n ui?: ContentModelFieldUi;\n /** Server-owned: who named this field (label, help text). Only an `auto` name may be renamed by a derive. */\n nameSource?: \"auto\" | \"human\";\n /** Server-owned: who wrote `helpText`. @see HelpSource */\n helpSource?: HelpSource;\n /** Server-owned provenance of this field's chrome. @see UiOrigin */\n uiOrigin?: UiOrigin;\n /** Server-owned revert point. @see UiBefore */\n uiBefore?: UiBefore;\n /** `true`: the last release's build renders this field on no route of its page — hidden, never deleted. `false`: a person keeps it shown. */\n stale?: boolean;\n}\n\n/** @see ContentModelField.ui */\nexport interface ContentModelFieldUi {\n /** Start this nesting field's panel collapsed. Absent ≡ the editor's own default. */\n collapsed?: boolean;\n /** How one item of a nesting field summarises itself when collapsed. Keys, not values. */\n preview?: {\n /** Child field key whose value titles the row. */\n title?: string;\n /** Child field key whose value is the row's second line. */\n subtitle?: string;\n /** Child field key whose value is the row's thumbnail. Type is not constrained. */\n media?: string;\n /** A literal row label while the title child is empty (\"Untitled question\"). Not a key. */\n fallback?: string;\n /** The row's icon while it has no media (V2 `preview.icon`). */\n icon?: DockIconName;\n };\n /**\n * How the ITEMS of a nesting field are arranged. ABSENT ≡ `\"list\"` — every field stored\n * before this key existed means `\"list\"`, so a reader must treat undefined as list and never\n * as \"unset, pick something\".\n *\n * Same placement rule as {@link ContentModelFieldUi.preview}: nesting fields only.\n */\n layout?: \"list\" | \"grid\" | \"table\" | \"rows\" | \"chips\" | \"gallery\";\n /**\n * Whether the items of a list may be dragged. ABSENT ≡ `true`, for the same reason — nothing\n * stored today carries it, and everything stored today is reorderable.\n *\n * `false` LOCKS the order: a \"three steps\" band, a semantic nav, a timeline. Valid only where\n * there is a list (a repeatable zone, a `repeater`, or `modular`), so a reader that honours it\n * must disable the sortable behaviour, not just hide the grip — a hidden grip still reorders\n * from the keyboard.\n */\n reorderable?: boolean;\n /**\n * Which editor control a LEAF renders with. ABSENT ≡ the type's default (a dropdown for a\n * `select`, a plain input for a `number`). `segmented` is valid on a single-choice `select`;\n * `slider` on a `number` whose config.min < config.max; `rating` on a `number` with numeric\n * config.min, max and step (stars).\n */\n control?: \"segmented\" | \"slider\" | \"rating\" | \"dropdown\" | \"radio\" | \"cards\" | \"grid\" | \"switch\" | \"checkbox\";\n /** The branch row's icon. Nesting fields only. */\n icon?: DockIconName;\n /** What one item is called (\"Slide\", \"Member\"), 1–24 chars (V2 itemNoun). Nesting fields and lists. */\n itemLabel?: string;\n /** V2 `rows`: the lines a text box opens with (1–40). text / longtext only. */\n rows?: number;\n /** V2 `placeholder` on a field of any type. A prop keeps its own `placeholder`. */\n placeholder?: string;\n /** V2 item identity on a list: the item type's own name (an identifier) and title. */\n itemName?: string;\n itemTitle?: string;\n /** V2 `synced`: the value comes from a global, so an edit applies everywhere. A marker. */\n synced?: { from: string };\n /** V2 `valueShape`: a link / image / button writes a plain string or the object. */\n valueShape?: \"string\" | \"object\";\n /** V2 field access (D58): who sees and who changes it. The editor gates; the backend stores. */\n access?: { view?: \"schema.view\"; edit?: \"schema.manage\" };\n /** V2 `hidden`: true = never shown in the form; false ≡ absent. A conditional hide is `showIf`. */\n hidden?: boolean;\n /**\n * V2 per-item chrome of a `modular` field (`of[i].icon` / `preview`), by block slug: how a row\n * of that block type reads in this field. Each slug is one of `config.blockSlugs`.\n */\n blocks?: Record<string, { icon?: DockIconName; preview?: ContentModelFieldUi[\"preview\"] }>;\n /**\n * A custom dock input, by NAME: the project's own input (built with its site, served on its\n * own inputs origin, never the dashboard's) draws this field instead of the stock control.\n * Data, never code. An unknown name, a disabled input or one that fails to load falls back to\n * the stock control. @see DockInputRef\n */\n input?: DockInputRef;\n}\n\n/**\n * Which custom input draws a field, and which OTHER fields of the same document it may write.\n * `writes` is an allowlist of sibling field keys: the dock refuses any patch outside it, checks\n * each against the target field's own schema, commits all of them at once (If-Match) to the\n * draft only, and undoes them as one step. Absent `writes` ≡ the input writes its own field only.\n */\nexport interface DockInputRef {\n /** The input's name in the project's inputs manifest: lowercase, digits and dashes. */\n name: string;\n /** Sibling field keys this input may also write. */\n writes?: string[];\n}\n\n/**\n * A field inside an array zone — identical to a top-level {@link ContentModelField}.\n * Kept as a named alias so consumers can express \"zone field\" intent; recursion\n * (an array zone field with its own `config.zones`) is supported.\n */\nexport type ZoneField = ContentModelField;\n\n/**\n * Who wrote a help text or a description: the platform's generator (`auto`, rewritten whenever its\n * wording improves), a person in the dashboard (`human`) or an agent over the API (`agent`). Only\n * `auto` text is ever replaced. Server-owned: a client's copy is ignored.\n */\nexport type HelpSource = \"auto\" | \"human\" | \"agent\";\n","/**\n * WHERE an element was on a built page, so a later pass can find it again.\n *\n * This lives in the shared package because BOTH ends of the comparison have to spell an address\n * the same way: the backend derives it from a JSDOM tree at import time, the dashboard computes\n * it from a live iframe tree when a person clicks an unbound element. Two implementations of\n * \"the ancestor chain down from the nearest landmark\" is one implementation too many — the first\n * time they disagree by one tag, a click binds the wrong element.\n *\n * The DOM is typed STRUCTURALLY (`ElementLike`, `LandmarkHost`) so this package needs no DOM lib\n * and stays importable from a node-only build.\n */\n\n/** The landmark tags an address is anchored at, as one CSS selector and as one tag set. */\nexport const LANDMARK_SELECTOR = \"header,nav,footer\";\nconst LANDMARK_TAGS = new Set([\"HEADER\", \"NAV\", \"FOOTER\"]);\n\n/**\n * The THIRD region — a modal, a cookie banner, a pop-up — behind a per-project gate.\n *\n * A `<dialog>` or a `[role=\"dialog\"]` sits at BODY level, outside every landmark, so a banner\n * byte-identical on twelve routes derived twelve copies of itself. It is NOT a stop for\n * `locatorFor`: `region` already names which dialog an element is in, and a second gated rule\n * about where the ancestor chain ends would make the same element's locator differ between a\n * project that derived it as chrome and one that did not.\n */\nexport const DIALOG_SELECTOR = 'dialog,[role=\"dialog\"]';\n\n/**\n * The page's own content. A landmark INSIDE it is the page's, not the site's — under the v2\n * grammar only. @see isChromeLandmark\n */\nexport const MAIN_SELECTOR = 'main,[role=\"main\"]';\n\n/**\n * Which address grammar a page was derived in — the two per-project gates that change what a\n * REGION is. Both off is the original grammar, and `{}` must keep meaning exactly that: every\n * locator stored before a gate existed was spelled in it.\n *\n * `dialogs` — a `<dialog>`/`[role=\"dialog\"]` is a region of its own (the chrome grammar).\n * `landmarks` — landmark grammar v2. @see isChromeLandmark, and `landmarkRegions` for rule (ii).\n */\nexport interface LocatorGrammar {\n dialogs?: boolean;\n landmarks?: boolean;\n}\n\n/**\n * Is this element a landmark that holds SITE chrome — a header, nav or footer that earns a region\n * and a `nav-`/`footer-` key?\n *\n * 🔴 A LANDMARK INSIDE `<main>` IS PAGE COPY. HTML allows a `<nav>` anywhere, and a built page\n * uses one for whatever it likes: a features band's `<nav role=\"tablist\">`, a docs page's\n * prev/next pager in a `<footer>` inside the article. Counted as chrome, the home page's tab list\n * minted nine `nav-` keys that are really the section's copy — keys the Layout's Header section\n * claims by prefix the moment two routes render that band alike, and that componentize reads as\n * chrome everywhere else. The `<main>` is the page saying \"everything in here is mine\", and v2\n * believes it.\n *\n * Gated (`landmarks`), because it moves keys AND regions: a project whose pages were derived\n * with that tab list as `nav#0` holds values under `nav-…` keys, and re-reading them as section\n * copy would strand every one of them.\n *\n * EXCEPT A `<main>` THAT IS THE PAGE SHELL. Plenty of layouts wrap the whole page in it —\n * `<main><Navbar/>{children}<Footer/></main>`, or `role=\"main\"` on the app root — and there the\n * fence would take the site's real masthead and footer away: no region, no `nav-`/`footer-` keys,\n * nothing for the Layout to claim, and a copy of the nav minted into every route. A `<main>` that\n * OPENS with a header/nav and CLOSES with a footer is framing the site, not holding page copy, so\n * its own direct-child landmarks stay chrome. A landmark deeper inside it (a section's tab list)\n * is still page copy, and a `<main>` that only opens with a header (a changelog's title) still\n * fences it.\n */\nexport function isChromeLandmark(\n el: { tagName: string; parentElement: { closest(selectors: string): unknown } | null },\n landmarks: boolean,\n): boolean {\n if (!LANDMARK_TAGS.has(el.tagName)) return false;\n if (!landmarks) return true;\n const fence = el.parentElement?.closest(MAIN_SELECTOR) as ShellCandidate | null | undefined;\n return !fence || ((fence as unknown) === el.parentElement && isPageShell(fence));\n}\n\n/** Tags a framework appends around content that say nothing about the page's shape. */\nconst INERT_TAGS = new Set([\"SCRIPT\", \"STYLE\", \"TEMPLATE\", \"NOSCRIPT\", \"LINK\"]);\ntype ShellCandidate = { children: ArrayLike<{ tagName: string }> };\n\n/** Opens with the masthead (header/nav) and closes with the footer, ignoring inert tags. */\nfunction isPageShell(main: ShellCandidate): boolean {\n const kids = Array.from(main.children).filter((k) => !INERT_TAGS.has(k.tagName));\n const first = kids[0]?.tagName;\n return (first === \"HEADER\" || first === \"NAV\") && kids.length > 1 && kids[kids.length - 1]!.tagName === \"FOOTER\";\n}\n\n/**\n * Best-effort by construction — built-DOM positions do not survive component expansion or\n * conditional rendering — so a consumer that finds no exact match, or finds several, falls back\n * to ambiguity rather than to a guess. The ancestor chain is compared EXACTLY (`atLocator`,\n * annotate-static.ts): a chain that merely contains the stored one is a different element.\n */\nexport interface DerivedLocator {\n /** The landmark it lives in — `header#0`, `nav#1`, `footer#0` — or null for the page body. */\n region: string | null;\n /** Tag names from the nearest landmark (or `<body>`) down to the element's parent. */\n ancestors: string[];\n /** Its index among its parent's element children. */\n siblingIndex: number;\n /**\n * The element's own lower-cased tag name.\n *\n * The cheapest fact that separates two elements a chain-and-index pair calls identical — a\n * `<h2>` and the `<a>` beside it in a rebuilt layout — and the only one a resolver can use to\n * NARROW its candidate list before comparing anything. Absent on locators stored before it\n * existed; a comparer must treat a missing tag as \"matches\".\n */\n tag: string;\n /**\n * The repeater row this value belongs to.\n *\n * On a leaf's field DEFINITION the index is 0 — one definition serves every row — and the\n * brief overrides it with the row it is actually describing (`cards[2].title` → index 2).\n */\n repeat?: { groupKey: string; index: number };\n}\n\n/** The DOM surface `locatorFor` reads. `Element` satisfies it; so does a plain object. */\nexport interface ElementLike {\n tagName: string;\n parentElement: ElementLike | null;\n children: ArrayLike<ElementLike>;\n}\n\n/**\n * `ElementLike` plus the one DOM call the v2 chain needs — whether a landmark sits inside\n * `<main>` (@see isChromeLandmark). `Element` satisfies it. Only the backend derives in v2, so\n * the plain-object surface above stays all the original grammar asks for.\n */\nexport interface LandmarkChainElement extends ElementLike {\n parentElement: LandmarkChainElement | null;\n closest(selectors: string): unknown;\n}\n\n/**\n * The structural address of one element: its ancestor tags and its position among its siblings.\n *\n * Stops at the nearest LANDMARK because that is where a page's structure stops being comparable\n * — a header's internals are the same on every route while the body's are not — and `region`\n * already names which landmark it was.\n *\n * 🔴 UNDER v2 (`landmarks`) THE CHAIN STOPS ONLY AT A CHROME LANDMARK. The stop is only sound\n * because `region` names the landmark it stopped at, and a `<nav>` inside `<main>` names no\n * region under v2. Stopping there anyway threw away the only structure that told two of them\n * apart: two sections' `<nav><a>` both addressed as `{region: null, ancestors: [], 0, a}` — the\n * address of a link sitting directly in `<body>` — where the original grammar said `nav#0` and\n * `nav#1`. So the chain runs on to `<body>` like every other element of the page's copy. An\n * element outside every in-`<main>` landmark stops exactly where it always did, which is what\n * keeps every locator whose region v2 did not move byte-identical. Two landmarks of one shape in\n * two sections of one shape still collide, as two cards always have; every reader refuses an\n * address that names several elements (`atLocator`, the pin replay, `bindElement`).\n */\nexport function locatorFor(el: ElementLike, region: string | null): DerivedLocator;\nexport function locatorFor(el: LandmarkChainElement, region: string | null, landmarks: boolean): DerivedLocator;\nexport function locatorFor(el: ElementLike, region: string | null, landmarks = false): DerivedLocator {\n const ancestors: string[] = [];\n for (\n let parent = el.parentElement;\n // The cast is the overloads' promise: `landmarks` is only ever true for a `LandmarkChainElement`,\n // and `isChromeLandmark` never reads past the tag with it false.\n parent && parent.tagName !== \"BODY\" && !isChromeLandmark(parent as LandmarkChainElement, landmarks);\n parent = parent.parentElement\n ) {\n ancestors.unshift(parent.tagName.toLowerCase());\n }\n const siblings = el.parentElement ? Array.from(el.parentElement.children) : [];\n return {\n region,\n ancestors,\n siblingIndex: Math.max(siblings.indexOf(el), 0),\n tag: el.tagName.toLowerCase(),\n };\n}\n\n/** The DOM surface `landmarkRegions` reads of each element it considers. */\nexport interface LandmarkElement {\n tagName: string;\n parentElement: { closest(selectors: string): unknown } | null;\n matches(selectors: string): boolean;\n}\n\n/**\n * A page's landmark regions: the OUTERMOST `header`/`nav`/`footer` elements, in document order.\n *\n * Outermost, because a `<nav>` inside a `<header>` is one region a visitor sees as one thing —\n * and promoting the two separately would let a site's masthead be half layout, half page.\n *\n * Under the v2 grammar (`landmarks`) regions may NEST, in exactly one way — a dialog inside a\n * landmark is its own region — so a consumer must ask {@link regionOf} which one an element is\n * in, never take the first region that contains it.\n */\nexport function landmarkRegions<E extends LandmarkElement>(\n doc: { querySelectorAll(selectors: string): Iterable<E> },\n /**\n * Count a dialog as a region too — the per-project chrome grammar.\n *\n * OFF by default, and not merely for symmetry: a region name is part of every field's LOCATOR,\n * and a project whose stored locators say `region: null` for a modal's copy must keep being\n * read the same way.\n */\n dialogs = false,\n /**\n * Landmark grammar v2 — the per-project `landmarks` gate. Two rules change, both OFF by default\n * for the reason `dialogs` is:\n *\n * (i) a landmark inside `<main>`/`[role=\"main\"]` is no region. @see isChromeLandmark\n * (ii) a dialog inside a landmark is its OWN region. The auth modals a masthead carries are\n * the commonest dialogs on the web, and outermost-only folded all three into `header#0`:\n * their copy promoted as the header's, and the header could only promote when every\n * route's modals did too. A dialog still folds into an enclosing DIALOG, and a landmark\n * into anything enclosing it — nothing else nests.\n */\n landmarks = false,\n): { slot: string; el: E }[] {\n const counts = new Map<string, number>();\n const out: { slot: string; el: E }[] = [];\n const selector = dialogs ? `${LANDMARK_SELECTOR},${DIALOG_SELECTOR}` : LANDMARK_SELECTOR;\n for (const el of doc.querySelectorAll(selector)) {\n if (!landmarks) {\n if (el.parentElement?.closest(selector)) continue;\n } else if (LANDMARK_TAGS.has(el.tagName)) {\n // A landmark outside `<main>` has no ancestor inside it either, so anything enclosing it is\n // a region — the outermost rule, unchanged.\n if (!isChromeLandmark(el, true) || el.parentElement?.closest(selector)) continue;\n } else if (el.parentElement?.closest(DIALOG_SELECTOR)) {\n continue;\n }\n // The NAME, not the tag: a `[role=\"dialog\"]` is usually a `<div>`, and slotting it as\n // `div#0` would make one site's modal and another's wrapper the same kind of region.\n const name = !LANDMARK_TAGS.has(el.tagName) && el.matches(DIALOG_SELECTOR)\n ? \"dialog\"\n : el.tagName.toLowerCase();\n const n = counts.get(name) ?? 0;\n counts.set(name, n + 1);\n out.push({ slot: `${name}#${n}`, el });\n }\n return out;\n}\n\n/**\n * The region an element is in: the INNERMOST region that contains it, or null for the page body.\n *\n * The last match rather than the first, because regions are in document order and an enclosing\n * region opens before the one nested inside it (v2's dialog in a header). Under every other\n * grammar regions are disjoint and first and last are the same region — which is what keeps a\n * resolver built on this byte-identical for every locator stored before v2.\n */\nexport function regionOf<E extends { contains(other: unknown): boolean }>(\n regions: readonly { slot: string; el: E }[],\n el: unknown,\n): string | null {\n let slot: string | null = null;\n for (const r of regions) if (r.el.contains(el)) slot = r.slot;\n return slot;\n}\n","/**\n * `<BcmsSections>`: which of a page's sections render, in what order, and which block each one is.\n *\n * A code-built page passes every section it can draw as a named SLOT; the CMS page's block list\n * says the order. This is the one place that joins the two, shared by @bettercms-ai/astro and\n * @bettercms-ai/next so a site renders the same list on either. The backend reads a placement's\n * group through the same `placementBindOf`, so a slot's name is the id the platform measured.\n *\n * Pure: no DOM, no framework, no I/O.\n */\n\n/**\n * The tag-shaped heads the derive lane mints keys from (`h1-welcome`, `p-we-build-things`,\n * `img-logo`, `list-benefits`, `a-contact`). A key whose head is one of these names an ELEMENT,\n * not a section family, so it has no group root.\n *\n * 🔴 NOT ONLY TEXT TAGS. Derive also keys a text leaf found by SHAPE by its own tag (`span-dismiss`,\n * `div-samantha-ruiz`, `time-…`) and a media leaf by its kind (`icon-icon`, `bg-…`). Missing here,\n * each of those heads read as a FAMILY: an unmarked announcement bar became components called\n * \"Span\" and \"Icon\".\n */\nexport const TAG_HEADS: ReadonlySet<string> = new Set([\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\",\n \"p\", \"a\", \"img\", \"li\", \"list\", \"blockquote\", \"figcaption\", \"button\", \"summary\", \"dt\", \"dd\", \"th\", \"td\",\n \"pre\", \"label\", \"span\", \"div\", \"time\", \"strong\", \"em\", \"small\", \"b\", \"i\", \"code\",\n \"icon\", \"bg\",\n]);\n\n/** The top-level field key a path belongs to: `hero.title` → `hero`, `faq[0].q` → `faq`. */\nexport const topFieldKeyOf = (path: string): string => path.split(/[.[]/, 1)[0] ?? path;\n\n/**\n * The GROUP a top-level field key belongs to, and whether that group has a real root.\n *\n * Two shapes are groups: a repeater the derive lane already folded (`group-*`), and a family prefix\n * on an authored or renamed key (`hero-title`, `hero.title` → `hero`). Everything else is a bare\n * element key with no family, and grouping those by their tag would mint one section per heading.\n */\nexport function fieldGroupOf(topKey: string, flat = false): { groupKey: string; rooted: boolean } {\n if (topKey.startsWith(\"group-\")) return { groupKey: topKey, rooted: true };\n // A FLAT camelCase key names its family by its first word (`heroTitle`, `heroSubtitle` → `hero`),\n // the way hand-authored starter schemas spell them. Flat only: a nested `featureGrid.items` was\n // always its own group, and re-keying it would move that section's slug and identity.\n const camel = flat ? /^([a-z][a-z0-9]*)[A-Z]/.exec(topKey)?.[1] : undefined;\n if (camel) return TAG_HEADS.has(camel) ? { groupKey: topKey, rooted: false } : { groupKey: camel, rooted: true };\n // 🔴 `-` OR `_`. The importer mints `hero-title`, and every tool text teaches an agent to write\n // `hero_title`: both form a family. `||`, not `??`: a key that STARTS with a separator has an\n // empty head, and an empty group key would fold every such key into one section.\n const head = topKey.split(/[-_]/, 1)[0] || topKey;\n if (TAG_HEADS.has(head)) return { groupKey: topKey, rooted: false };\n return { groupKey: head, rooted: true };\n}\n\n/**\n * The GROUP a placement renders, or null if this block is not a placement of the site's own code.\n *\n * Two spellings: `props.bind` says the group outright; `props.source` (`{ propKey: \"<page path>\" }`)\n * is what is left once the copy moved onto the instance, and the group is derived from it. A\n * section added from the library carries neither, which is how it is told apart: the site's code\n * has nothing to draw it with.\n */\nexport function placementBindOf(block: unknown): string | null {\n if (!block || typeof block !== \"object\" || (block as { type?: unknown }).type !== \"component\") return null;\n const props = (block as { props?: { bind?: unknown; source?: unknown } }).props;\n const bind = props?.bind;\n if (typeof bind === \"string\" && bind) return bind;\n const source = props?.source;\n if (!source || typeof source !== \"object\") return null;\n // The first path that names a FAMILY: a lone `eyebrow` placed in `hero` is not the placement's group.\n const groups = Object.values(source as Record<string, unknown>)\n .filter((path): path is string => typeof path === \"string\" && path.length > 0)\n .map((path) => ({ top: topFieldKeyOf(path), group: fieldGroupOf(topFieldKeyOf(path), path === topFieldKeyOf(path)).groupKey }));\n return (groups.find((g) => g.group !== g.top) ?? groups[0])?.group ?? null;\n}\n\n/**\n * A slot the CMS was not known to hold when the page was wrapped is spelled `code:<bind>`.\n * It matches a block bound to `<bind>` like the bare spelling does; it differs only when no block\n * names it: a `code:` slot then renders where the source has it, a bare one is a removed section.\n */\nexport const CODE_SLOT_PREFIX = \"code:\";\n\n/** The bind a slot answers to: `code:hero` and `hero` → `hero`. */\nexport const slotBindOf = (slot: string): string => (slot.startsWith(CODE_SLOT_PREFIX) ? slot.slice(CODE_SLOT_PREFIX.length) : slot);\n\n/** One thing `<BcmsSections>` renders: the page's own slot (with its block, when one names it), or a CMS block. */\nexport type SectionPlanItem<B> = { slot: string; block: B | null } | { slot: null; block: B };\n\n/**\n * The render order of a page: its slots (in source order) joined with its block list (in CMS order).\n *\n * - No block list (a build with no snapshot, the API down): every slot, in source order, no block.\n * - A block bound to a slot renders that slot at the block's position. Each slot renders once: a\n * second block of the same bind is skipped, as is a bound block the page passed no slot for\n * (the site draws that one somewhere this list cannot reach, so drawing it again would double it).\n * - A block with no bind (a section added from the library) is the CMS's own to draw.\n * - A slot no block names: a `code:` slot always renders, after the source slot before it. A bare\n * slot renders the same way while the list names none of this page's slots (another project's\n * snapshot, a page never placed); once it names one, an unnamed bare slot is a removed section.\n */\nexport function planSections<B>(slots: readonly string[], blocks: readonly B[] | null | undefined): SectionPlanItem<B>[] {\n if (!Array.isArray(blocks)) return slots.map((slot) => ({ slot, block: null }));\n const byBind = new Map<string, string>();\n for (const slot of slots) if (!byBind.has(slotBindOf(slot))) byBind.set(slotBindOf(slot), slot);\n\n const out: SectionPlanItem<B>[] = [];\n const named = new Set<string>();\n for (const block of blocks as readonly B[]) {\n const bind = placementBindOf(block);\n if (bind === null) {\n out.push({ slot: null, block });\n continue;\n }\n const slot = byBind.get(bind);\n if (slot === undefined || named.has(slot)) continue;\n named.add(slot);\n out.push({ slot, block });\n }\n\n const held = named.size > 0;\n slots.forEach((slot, n) => {\n if (named.has(slot) || out.some((item) => item.slot === slot)) return;\n if (held && !slot.startsWith(CODE_SLOT_PREFIX)) return;\n // After the nearest source slot before it that renders; first when none does.\n let at = 0;\n for (let before = n - 1; before >= 0; before--) {\n const found = out.findIndex((item) => item.slot === slots[before]);\n if (found >= 0) {\n at = found + 1;\n break;\n }\n }\n out.splice(at, 0, { slot, block: null });\n });\n return out;\n}\n"],"mappings":"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tGjF,IAAM,uBAA0C,OAAO,OAAO;AAAA,EACnE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AA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A;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAC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","names":["isRecord","layout","strip","isPlainObject","formatNumber"]}
|