@cancia/toolbar 0.5.2 → 0.12.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/cancia.d.ts +10 -0
- package/dist/cancia.iife.js +696 -512
- package/dist/cancia.js +1642 -693
- package/dist/cancia.js.map +1 -1
- package/package.json +7 -4
package/dist/cancia.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/state.ts","../src/api.ts","../src/highlight.ts","../src/events.ts","../src/popup.ts","../src/list-panel.ts","../src/entry-modal.ts","../src/toolbar.ts","../src/index.ts"],"sourcesContent":["// =============================================================================\n// Cancia Toolbar — Shared State\n// =============================================================================\n\nimport type { CanciaConfig, CMSData, PendingChange } from \"./types\";\nimport type { ListSchemaDescription } from \"./api\";\n\nexport const state = {\n config: null as CanciaConfig | null,\n cmsData: {} as CMSData,\n pending: new Map<string, PendingChange>(),\n activeLang: \"\",\n editMode: false,\n /** Auth token from sessionStorage — set by toolbar/index.ts after session validation */\n sessionToken: \"\" as string,\n /** Called by toolbar logout button — wired up by index.ts to avoid circular deps */\n onLogout: null as (() => void) | null,\n /** List schemas, keyed by name. Loaded once on toolbar init. */\n schemas: {} as Record<string, ListSchemaDescription>,\n /** Currently-selected locale for list-panel + modal. Defaults to activeLang on open. */\n activeListLocale: \"\" as string,\n};\n\nexport function pendingKey(key: string, lang: string) {\n return `${key}.${lang}`;\n}\n\nexport function getValue(key: string, lang: string): string {\n const full = `${key}.${lang}`;\n // Pending changes win\n const p = state.pending.get(full);\n if (p) return p.value;\n // Then CMS overrides\n if (state.cmsData[full] !== undefined) return state.cmsData[full];\n return \"\";\n}\n\nexport function setPending(key: string, lang: string, value: string) {\n const full = pendingKey(key, lang);\n state.pending.set(full, { key, lang, value });\n}\n\nexport function clearPending() {\n state.pending.clear();\n}\n\n/**\n * Overlay saved (draft) CMS values onto the prerendered page.\n *\n * On a `static` build the page HTML is baked at build time, so an editor's\n * saved-but-unpublished changes (which live in `state.cmsData`) never show up\n * on reload. This walks every `[data-cms]` element and, when there is a saved\n * value for the active language, applies it client-side — so editors see their\n * drafts while normal visitors (no session, no toolbar) keep the baked build.\n *\n * Only runs from `init`, which is gated behind a valid session or `public`\n * mode, so it never affects normal visitors.\n */\n/**\n * Read a stored link value for overlay. Mirrors parseLinkValue in\n * @cancia/astro/schema — the toolbar is a standalone browser bundle and does\n * not import the astro package, so the shape contract is duplicated here on\n * purpose. Never throws; an unparseable value degrades to a bare label.\n */\nfunction parseLinkOverlay(raw: string): { label: string; href: string } {\n if (!raw) return { label: \"\", href: \"\" };\n const trimmed = raw.trim();\n if (trimmed.startsWith(\"{\")) {\n try {\n const p = JSON.parse(trimmed) as { label?: string; href?: string };\n if (p && typeof p === \"object\") {\n return { label: String(p.label ?? \"\"), href: String(p.href ?? \"\") };\n }\n } catch {\n // fall through\n }\n }\n return { label: raw, href: \"\" };\n}\n\nexport function applyOverlay() {\n document.querySelectorAll<HTMLElement>(\"[data-cms]\").forEach((el) => {\n // Skip list-region containers — they mark list areas, not text nodes.\n if (el.dataset.cmsList !== undefined) return;\n\n const key = el.dataset.cms;\n if (!key) return;\n\n const savedValue = state.cmsData[`${key}.${state.activeLang}`];\n // No saved override → leave the baked value in place.\n if (savedValue === undefined) return;\n\n if (el.tagName === \"IMG\") {\n (el as HTMLImageElement).src = savedValue;\n return;\n }\n\n // A link stores JSON ({label, href}) — without this branch the raw JSON\n // string would be written onto the page as visible text. Gated on the\n // EXPLICIT data-cms-type (matching fieldType in highlight.ts): a plain\n // text field is allowed to live on an <a> (footer email, nav item) and\n // must keep behaving like text.\n if (el.dataset.cmsType === \"link\") {\n const link = parseLinkOverlay(savedValue);\n if (link.href && el.tagName === \"A\") el.setAttribute(\"href\", link.href);\n // A button usually holds an icon next to its text (<a>Book<svg/></a>), so\n // writing textContent would delete the icon. `[data-cms-label]` marks the\n // text node to replace; without it we only touch a childless element.\n // ALL marked nodes update, not just the first: a responsive button often\n // carries two labels that swap by breakpoint (one `hidden sm:inline`,\n // one `sm:hidden`), and updating only one leaves the other stale.\n const labelEls = el.querySelectorAll<HTMLElement>(\"[data-cms-label]\");\n if (labelEls.length > 0) labelEls.forEach((n) => (n.textContent = link.label));\n else if (el.childElementCount === 0) el.textContent = link.label;\n return;\n }\n\n // Safety: setting textContent on an element with child ELEMENT nodes would\n // destroy them. Only overlay elements whose children are all text/comments.\n if (el.childElementCount > 0) {\n console.warn(\n `Cancia: skipping overlay for \"${key}\" — element has child elements ` +\n `(textContent would destroy them).`\n );\n return;\n }\n\n el.textContent = savedValue;\n });\n}\n\n/** Revert all pending changes — restores DOM elements to their last saved CMS value */\nexport function revertPending() {\n for (const [fullKey, { key, lang }] of state.pending) {\n const savedValue = state.cmsData[fullKey] ?? \"\";\n // Update any matching data-cms elements in the DOM\n document.querySelectorAll<HTMLElement>(`[data-cms=\"${key}\"]`).forEach((el) => {\n if (el.tagName === \"IMG\") {\n (el as HTMLImageElement).src = savedValue;\n } else {\n el.textContent = savedValue;\n }\n });\n }\n state.pending.clear();\n}\n","// =============================================================================\n// Cancia Toolbar — API Client\n// =============================================================================\n\nimport { state } from \"./state\";\nimport type { CMSData } from \"./types\";\n\nfunction headers(): HeadersInit {\n const h: HeadersInit = { \"Content-Type\": \"application/json\" };\n if (state.sessionToken) h[\"Authorization\"] = `Bearer ${state.sessionToken}`;\n return h;\n}\n\n/**\n * The current page's route (034). The client is the source of truth for \"which\n * page am I editing\" — the server uses it to invalidate the right cache tag in\n * `invalidate` publish mode. Empty string when not in a browser (SSR/tests).\n */\nfunction currentRoute(): string {\n return typeof location !== \"undefined\" ? location.pathname : \"\";\n}\n\n/** Append `&route=<pathname>` to a lists URL so the server can invalidate it. */\nfunction routeParam(): string {\n const r = currentRoute();\n return r ? `&route=${encodeURIComponent(r)}` : \"\";\n}\n\nexport async function fetchContent(): Promise<CMSData> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(`${apiUrl}/api/cancia/content?site=${encodeURIComponent(site)}`, {\n headers: headers(),\n });\n if (!res.ok) throw new Error(`Cancia: failed to fetch content (${res.status})`);\n return res.json();\n}\n\nexport async function saveEntry(key: string, lang: string, value: string): Promise<void> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(`${apiUrl}/api/cancia/save`, {\n method: \"POST\",\n headers: headers(),\n // `route` lets the server invalidate this page's cache tag (034, invalidate mode).\n body: JSON.stringify({ key, lang, value, site, route: currentRoute() }),\n });\n if (!res.ok) throw new Error(`Cancia: failed to save (${res.status})`);\n}\n\nexport function isAuthError(err: unknown): boolean {\n return err instanceof Error && err.message.includes(\"(401)\");\n}\n\nexport function uploadImage(\n file: File,\n onProgress?: (percent: number) => void\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const { apiUrl, site } = state.config!;\n const form = new FormData();\n form.append(\"file\", file);\n form.append(\"site\", site);\n\n const xhr = new XMLHttpRequest();\n xhr.open(\"POST\", `${apiUrl}/api/cancia/upload`);\n if (state.sessionToken) xhr.setRequestHeader(\"Authorization\", `Bearer ${state.sessionToken}`);\n\n xhr.upload.addEventListener(\"progress\", (e) => {\n if (e.lengthComputable) onProgress?.(Math.round((e.loaded / e.total) * 100));\n });\n xhr.addEventListener(\"load\", () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n resolve(JSON.parse(xhr.responseText).url as string);\n } catch {\n reject(new Error(\"Cancia: invalid upload response\"));\n }\n } else {\n reject(new Error(`Cancia: failed to upload image (${xhr.status})`));\n }\n });\n xhr.addEventListener(\"error\", () => reject(new Error(\"Cancia: upload network error\")));\n xhr.send(form);\n });\n}\n\nexport async function triggerPublish(): Promise<void> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(`${apiUrl}/api/cancia/publish`, {\n method: \"POST\",\n headers: headers(),\n body: JSON.stringify({ site }),\n });\n if (!res.ok) throw new Error(`Cancia: publish failed (${res.status})`);\n}\n\n// ---------------------------------------------------------------------------\n// Lists + schemas (v2)\n// ---------------------------------------------------------------------------\n\nexport interface ListSchemaField {\n name: string;\n label: string;\n description?: string;\n widget:\n | \"text\"\n | \"textarea\"\n | \"url\"\n | \"email\"\n | \"datetime\"\n | \"number\"\n | \"checkbox\"\n | \"select\"\n | \"image\"\n | \"slug\"\n | \"array\"\n | \"object\"\n | \"reference\"\n | \"richtext\";\n required: boolean;\n placeholder?: string;\n options?: string[];\n minLength?: number;\n maxLength?: number;\n min?: number;\n max?: number;\n /** Regex source (no delimiters) the value must match. */\n pattern?: string;\n /** For slug widgets: the field name to derive the slug from. */\n source?: string;\n /** For array widgets: the schema of a single item (name is \"\"). */\n of?: ListSchemaField;\n /** For object widgets: the sub-field schemas, in declared order. */\n fields?: ListSchemaField[];\n /** For reference widgets: the name of the list whose entry id this stores. */\n referenceList?: string;\n}\n\nexport interface ListSchemaDescription {\n name: string;\n label: string;\n labelSingular: string;\n titleField: string;\n bodyField?: string;\n slugField?: string;\n fields: ListSchemaField[];\n}\n\nexport interface ListEntry {\n id: string;\n data: Record<string, unknown>;\n locale: string;\n createdAt: string;\n updatedAt: string;\n _rev: string;\n}\n\nexport interface TranslationStatus {\n id: string;\n locales: string[];\n}\n\nexport async function fetchSchemas(): Promise<Record<string, ListSchemaDescription>> {\n const { apiUrl } = state.config!;\n const res = await fetch(`${apiUrl}/api/cancia/schemas`, { headers: headers() });\n if (!res.ok) throw new Error(`Cancia: failed to fetch schemas (${res.status})`);\n const body = (await res.json()) as { schemas: Record<string, ListSchemaDescription> };\n return body.schemas;\n}\n\nfunction localeParam(locale?: string): string {\n return locale ? `&locale=${encodeURIComponent(locale)}` : \"\";\n}\n\nexport async function fetchList(listName: string, locale?: string): Promise<ListEntry[]> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}?site=${encodeURIComponent(site)}${localeParam(locale)}`,\n { headers: headers() },\n );\n if (!res.ok) throw new Error(`Cancia: failed to fetch list \"${listName}\" (${res.status})`);\n const body = (await res.json()) as { entries: ListEntry[] };\n return body.entries;\n}\n\nexport async function fetchTranslations(listName: string): Promise<TranslationStatus[]> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}/_translations?site=${encodeURIComponent(site)}`,\n { headers: headers() },\n );\n if (!res.ok) throw new Error(`Cancia: failed to fetch translations (${res.status})`);\n const body = (await res.json()) as { translations: TranslationStatus[] };\n return body.translations;\n}\n\nexport async function createListEntry(\n listName: string,\n data: Record<string, unknown>,\n locale: string,\n id?: string,\n): Promise<ListEntry> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}?site=${encodeURIComponent(site)}${localeParam(locale)}${routeParam()}`,\n { method: \"POST\", headers: headers(), body: JSON.stringify({ data, id }) },\n );\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string };\n throw new Error(err.error ?? `Cancia: failed to create entry (${res.status})`);\n }\n const body = (await res.json()) as { entry: ListEntry };\n return body.entry;\n}\n\nexport async function updateListEntry(\n listName: string,\n id: string,\n data: Record<string, unknown>,\n rev: string,\n locale: string,\n): Promise<ListEntry> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}/${encodeURIComponent(id)}?site=${encodeURIComponent(site)}${localeParam(locale)}${routeParam()}`,\n { method: \"PATCH\", headers: headers(), body: JSON.stringify({ data, _rev: rev }) },\n );\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string; code?: string };\n const message = err.error ?? `Cancia: failed to update entry (${res.status})`;\n throw Object.assign(new Error(message), { code: err.code });\n }\n const body = (await res.json()) as { entry: ListEntry };\n return body.entry;\n}\n\nexport async function deleteListEntry(listName: string, id: string, locale: string): Promise<void> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}/${encodeURIComponent(id)}?site=${encodeURIComponent(site)}${localeParam(locale)}${routeParam()}`,\n { method: \"DELETE\", headers: headers() },\n );\n if (!res.ok) throw new Error(`Cancia: failed to delete entry (${res.status})`);\n}\n\nexport async function reorderList(listName: string, ids: string[]): Promise<void> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}/reorder?site=${encodeURIComponent(site)}${routeParam()}`,\n { method: \"POST\", headers: headers(), body: JSON.stringify({ ids }) },\n );\n if (!res.ok) throw new Error(`Cancia: failed to reorder list (${res.status})`);\n}\n\n/** Save all pending changes in one batch. Removes successfully saved entries from pending. */\nexport async function flushPending(): Promise<void> {\n const entries = Array.from(state.pending.values());\n const results = await Promise.allSettled(\n entries.map(({ key, lang, value }) => saveEntry(key, lang, value))\n );\n results.forEach((result, i) => {\n if (result.status === \"fulfilled\") {\n const { key, lang } = entries[i];\n state.pending.delete(`${key}.${lang}`);\n }\n });\n const failed = results.filter((r) => r.status === \"rejected\").length;\n if (failed > 0) throw new Error(`Cancia: ${failed} save(s) failed`);\n}\n","// =============================================================================\n// Cancia Toolbar — Hover Highlight\n// =============================================================================\n// Scans [data-cms] elements. While edit mode is active, hovering shows a\n// coloured outline overlay + tooltip with field key. Clicking fires onSelect.\n// =============================================================================\n\nimport { state } from \"./state\";\n\nexport type CanciaSelection =\n | { kind: \"field\"; el: HTMLElement; key: string; fieldType: \"text\" | \"image\" | \"link\" }\n | { kind: \"list\"; el: HTMLElement; listName: string };\n\ntype SelectCallback = (selection: CanciaSelection) => void;\n\nconst CMS_SELECTOR = \"[data-cms], [data-cms-list]\";\n\nlet onSelect: SelectCallback | null = null;\nlet currentHighlighted: HTMLElement | null = null;\nlet cleanupFns: (() => void)[] = [];\nlet scrollRAF: number | null = null;\n\n// Overlay + tooltip elements (reused, not re-created per hover)\nlet overlayEl: HTMLElement | null = null;\nlet tooltipEl: HTMLElement | null = null;\nlet styleInjected = false;\n\nfunction accent() {\n return state.config?.accentColor ?? \"#6366f1\";\n}\n\nfunction fieldType(el: HTMLElement): \"text\" | \"image\" | \"link\" {\n // An explicit data-cms-type always wins — it is how a consumer overrides the\n // tag-based guess (e.g. a framework <Image> that renders an <img>).\n if (el.dataset.cmsType === \"image\") return \"image\";\n if (el.dataset.cmsType === \"link\") return \"link\";\n if (el.tagName === \"IMG\") return \"image\";\n // NOTE: an <a> is deliberately NOT inferred as a link. Link editing must be\n // opted into with data-cms-type=\"link\", because plenty of legitimate text\n // fields live on an anchor — a footer email/phone, a nav item — where the\n // href is derived from the value or fixed in code. Inferring from the tag\n // silently converted those into link fields and showed the editor a URL\n // input that had nowhere to write. Opt-in keeps a text field a text field.\n return \"text\";\n}\n\n/**\n * The two CMS modes. data-cms-list takes precedence when both are set on\n * the same element (rare but possible if a list is nested inside a KV\n * region — the inner list wins on the closest() lookup anyway).\n */\nfunction elementMode(el: HTMLElement): \"list\" | \"field\" {\n return el.dataset.cmsList ? \"list\" : \"field\";\n}\n\n// ---------------------------------------------------------------------------\n// Inject keyframes once\n// ---------------------------------------------------------------------------\n\nfunction injectStyles() {\n if (styleInjected) return;\n styleInjected = true;\n const s = document.createElement(\"style\");\n s.textContent = `\n @keyframes cancia-highlight-in {\n from { opacity: 0; transform: scale(0.98); }\n to { opacity: 1; transform: scale(1); }\n }\n @keyframes cancia-tooltip-in {\n from { opacity: 0; transform: scale(0.95) translateY(3px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n }\n `;\n document.head.appendChild(s);\n}\n\n// ---------------------------------------------------------------------------\n// Overlay: fixed border box that tracks the hovered element\n// ---------------------------------------------------------------------------\n\nfunction getOrCreateOverlay(): HTMLElement {\n if (!overlayEl) {\n overlayEl = document.createElement(\"div\");\n overlayEl.dataset.canciaOverlay = \"1\";\n overlayEl.style.cssText = `\n position: fixed;\n pointer-events: none !important;\n box-sizing: border-box;\n border-radius: 5px;\n z-index: 2147483644;\n will-change: top, left, width, height, opacity;\n transition: top 0.08s cubic-bezier(0.16,1,0.3,1), left 0.08s cubic-bezier(0.16,1,0.3,1),\n width 0.08s cubic-bezier(0.16,1,0.3,1), height 0.08s cubic-bezier(0.16,1,0.3,1);\n `;\n document.body.appendChild(overlayEl);\n }\n return overlayEl;\n}\n\nfunction getOrCreateTooltip(): HTMLElement {\n if (!tooltipEl) {\n tooltipEl = document.createElement(\"div\");\n tooltipEl.dataset.canciaTooltip = \"1\";\n tooltipEl.style.cssText = `\n position: fixed;\n pointer-events: none !important;\n z-index: 2147483645;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n font-size: 11px;\n font-weight: 500;\n letter-spacing: 0.02em;\n color: #fff;\n background: rgba(10,10,12,0.92);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n border: 1px solid rgba(255,255,255,0.1);\n padding: 4px 8px;\n border-radius: 6px;\n white-space: nowrap;\n max-width: 260px;\n overflow: hidden;\n text-overflow: ellipsis;\n box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n `;\n document.body.appendChild(tooltipEl);\n }\n return tooltipEl;\n}\n\nlet lastOverlayEl: HTMLElement | null = null; // track which el we last styled the badge for\n\n/** Shift a hex color's hue/saturation slightly so lists read as related-but-distinct from fields. */\nfunction listAccent(hex: string): string {\n // Cheap visual differentiation: deepen by 18% via a fixed shade rather than\n // recompute HSL. Falls back to a strong emerald if the accent isn't a hex.\n if (!/^#[0-9a-f]{6}$/i.test(hex)) return \"#059669\";\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n // Swap RGB channels deterministically to land on a related-but-distinct hue.\n // Boring trick that keeps tone consistent with the user's accent choice.\n const shifted = [g, b, r].map((c) => c.toString(16).padStart(2, \"0\")).join(\"\");\n return `#${shifted}`;\n}\n\nconst FIELD_ICON = `<svg width=\"10\" height=\"10\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\">\n <path d=\"M2 4h10M2 7h7M2 10h5\"/>\n</svg>`;\n\nconst IMAGE_ICON = `<svg width=\"10\" height=\"10\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"1\" y=\"1\" width=\"12\" height=\"12\" rx=\"2\"/>\n <circle cx=\"4.5\" cy=\"4.5\" r=\"1.2\"/>\n <path d=\"M1 9.5l3.5-3 2.5 2.5 2-1.5 3 3.5\"/>\n</svg>`;\n\nconst LINK_ICON = `<svg width=\"10\" height=\"10\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M6 8a2.5 2.5 0 003.6.3l2.2-2.2a2.5 2.5 0 00-3.5-3.5L7.2 3.6\"/>\n <path d=\"M8 6a2.5 2.5 0 00-3.6-.3L2.2 7.9a2.5 2.5 0 003.5 3.5l1.1-1.1\"/>\n</svg>`;\n\nconst LIST_ICON = `<svg width=\"10\" height=\"10\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"1\" y=\"2\" width=\"3\" height=\"3\" rx=\"0.5\"/>\n <rect x=\"1\" y=\"7.5\" width=\"3\" height=\"3\" rx=\"0.5\"/>\n <path d=\"M6 3.5h7M6 9h7\"/>\n</svg>`;\n\nfunction positionOverlay(el: HTMLElement, animate = false) {\n const rect = el.getBoundingClientRect();\n const mode = elementMode(el);\n const a = mode === \"list\" ? listAccent(accent()) : accent();\n const overlay = getOrCreateOverlay();\n const tooltip = getOrCreateTooltip();\n\n const padding = 3;\n overlay.style.top = `${rect.top - padding}px`;\n overlay.style.left = `${rect.left - padding}px`;\n overlay.style.width = `${rect.width + padding * 2}px`;\n overlay.style.height = `${rect.height + padding * 2}px`;\n\n // Rebuild badge only when switching to a new element\n if (lastOverlayEl !== el) {\n lastOverlayEl = el;\n overlay.style.border = `2px ${mode === \"list\" ? \"dashed\" : \"solid\"} ${a}`;\n overlay.style.background = `${a}12`;\n\n let badgeIcon: string;\n let badgeLabel: string;\n let tooltipText: string;\n if (mode === \"list\") {\n badgeIcon = LIST_ICON;\n badgeLabel = \"list\";\n tooltipText = `list: ${el.dataset.cmsList}`;\n } else {\n const type = fieldType(el);\n badgeIcon = type === \"image\" ? IMAGE_ICON : type === \"link\" ? LINK_ICON : FIELD_ICON;\n badgeLabel = type;\n tooltipText = el.dataset.cms ?? \"\";\n }\n\n overlay.innerHTML = `\n <div style=\"\n position: absolute; top: -1px; left: -1px;\n background: ${a}; color: #fff;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 10px; font-weight: 600; letter-spacing: 0.04em;\n padding: 2px 6px; border-radius: 3px 0 4px 0;\n display: flex; align-items: center; gap: 4px;\n line-height: 1;\n \">\n ${badgeIcon}\n ${badgeLabel}\n </div>\n `;\n tooltip.textContent = tooltipText;\n }\n\n overlay.style.display = \"block\";\n if (animate) overlay.style.animation = \"cancia-highlight-in 0.12s ease-out forwards\";\n\n // Position tooltip above the element (flip below if not enough space)\n tooltip.style.display = \"block\";\n if (animate) tooltip.style.animation = \"cancia-tooltip-in 0.1s ease-out forwards\";\n\n const tooltipMargin = 8;\n const tooltipH = 26;\n if (rect.top - tooltipH - tooltipMargin > 0) {\n tooltip.style.top = `${rect.top - tooltipH - tooltipMargin + padding}px`;\n tooltip.style.left = `${rect.left - padding}px`;\n } else {\n tooltip.style.top = `${rect.bottom + tooltipMargin - padding}px`;\n tooltip.style.left = `${rect.left - padding}px`;\n }\n}\n\nfunction hideOverlay() {\n lastOverlayEl = null;\n if (overlayEl) {\n overlayEl.style.display = \"none\";\n overlayEl.style.animation = \"none\";\n }\n if (tooltipEl) {\n tooltipEl.style.display = \"none\";\n tooltipEl.style.animation = \"none\";\n }\n}\n\nfunction handleScroll() {\n // Throttle with rAF to avoid layout thrash on every scroll tick\n if (scrollRAF !== null) return;\n scrollRAF = requestAnimationFrame(() => {\n scrollRAF = null;\n if (currentHighlighted) {\n positionOverlay(currentHighlighted);\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Event handlers\n// ---------------------------------------------------------------------------\n\nfunction handleMouseOver(e: MouseEvent) {\n const target = (e.target as HTMLElement).closest(CMS_SELECTOR) as HTMLElement | null;\n if (!target) return;\n currentHighlighted = target;\n target.style.cursor = \"pointer\";\n positionOverlay(target, true);\n}\n\nfunction handleMouseOut(e: MouseEvent) {\n const target = (e.target as HTMLElement).closest(CMS_SELECTOR) as HTMLElement | null;\n if (!target) return;\n // Only hide if we're actually leaving this element (not moving to a child)\n const related = e.relatedTarget as HTMLElement | null;\n if (related && target.contains(related)) return;\n target.style.cursor = \"\";\n if (currentHighlighted === target) {\n currentHighlighted = null;\n hideOverlay();\n }\n}\n\nfunction handleClick(e: MouseEvent) {\n const target = (e.target as HTMLElement).closest(CMS_SELECTOR) as HTMLElement | null;\n if (!target) return;\n e.preventDefault();\n e.stopPropagation();\n hideOverlay();\n if (elementMode(target) === \"list\") {\n const listName = target.dataset.cmsList!;\n onSelect?.({ kind: \"list\", el: target, listName });\n } else {\n const key = target.dataset.cms!;\n onSelect?.({ kind: \"field\", el: target, key, fieldType: fieldType(target) });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Warn about CMS regions that can never be hovered or clicked.\n *\n * The highlight positions itself from getBoundingClientRect(), so an element\n * with no layout box is invisible to the editor even though the markup looks\n * correct. Two ways to hit this, both of which look perfectly reasonable in\n * source: `class=\"sr-only\"` (collapses to 1px + clip) and\n * `display:contents` (no box at all). This cost real debugging time on the\n * first site that used a list, so make the failure loud instead of silent.\n *\n * Runs once per attach and only reports; it never mutates the page.\n */\nfunction warnUnhoverableRegions() {\n const els = document.querySelectorAll<HTMLElement>(CMS_SELECTOR);\n els.forEach((el) => {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) return;\n // An element inside a collapsed/hidden ancestor (a closed accordion, the\n // inactive half of a responsive pair) is legitimately 0×0 right now — only\n // warn when the element itself is styled out of the layout.\n const cs = getComputedStyle(el);\n const selfInflicted =\n cs.display === \"contents\" || cs.position === \"absolute\" || cs.clipPath !== \"none\";\n if (!selfInflicted) return;\n\n const name = el.dataset.cmsList\n ? `list \"${el.dataset.cmsList}\"`\n : `field \"${el.dataset.cms}\"`;\n console.warn(\n `[cancia] ${name} is annotated but has no layout box (${Math.round(rect.width)}×${Math.round(\n rect.height,\n )}) — it cannot be hovered or clicked in the editor. ` +\n `Avoid sr-only / display:contents on CMS regions; give the container a real box.`,\n el,\n );\n });\n}\n\nexport function attachHighlight(selectCallback: SelectCallback) {\n injectStyles();\n onSelect = selectCallback;\n\n warnUnhoverableRegions();\n\n document.addEventListener(\"mouseover\", handleMouseOver, true);\n document.addEventListener(\"mouseout\", handleMouseOut, true);\n document.addEventListener(\"click\", handleClick, true);\n window.addEventListener(\"scroll\", handleScroll, { passive: true, capture: true });\n\n cleanupFns = [\n () => document.removeEventListener(\"mouseover\", handleMouseOver, true),\n () => document.removeEventListener(\"mouseout\", handleMouseOut, true),\n () => document.removeEventListener(\"click\", handleClick, true),\n () => window.removeEventListener(\"scroll\", handleScroll, true),\n ];\n}\n\nexport function detachHighlight() {\n if (currentHighlighted) {\n currentHighlighted.style.cursor = \"\";\n currentHighlighted = null;\n }\n if (scrollRAF !== null) {\n cancelAnimationFrame(scrollRAF);\n scrollRAF = null;\n }\n hideOverlay();\n // Remove overlay + tooltip from DOM entirely when edit mode is off\n overlayEl?.remove();\n overlayEl = null;\n tooltipEl?.remove();\n tooltipEl = null;\n cleanupFns.forEach((fn) => fn());\n cleanupFns = [];\n onSelect = null;\n}\n","// =============================================================================\n// Cancia Toolbar — Internal Events\n// =============================================================================\n// Simple pub/sub so toolbar.ts can react to changes from popup.ts without\n// circular imports.\n// =============================================================================\n\ntype Listener = () => void;\nconst listeners = new Set<Listener>();\n\nexport function onPendingChange(cb?: Listener) {\n if (cb) {\n listeners.add(cb);\n return () => listeners.delete(cb);\n }\n // Called with no args to emit\n listeners.forEach((fn) => fn());\n}\n","// =============================================================================\n// Cancia Toolbar — Edit Popup\n// =============================================================================\n// Anchors near the clicked element. Handles text editing, image upload, and\n// link (label + href) editing.\n// =============================================================================\n\nimport { state, getValue, setPending, applyOverlay } from \"./state\";\nimport { uploadImage } from \"./api\";\nimport { onPendingChange } from \"./events\";\nimport type { CanciaLinkValue } from \"./types\";\n\nlet popupEl: HTMLElement | null = null;\nlet outsideListener: ((e: MouseEvent) => void) | null = null;\nlet keyListener: ((e: KeyboardEvent) => void) | null = null;\nlet dragover = false;\n\n// WeakMap replaces the unsafe _canciaInput monkey-patch on textarea elements\nconst inputHandlers = new WeakMap<HTMLTextAreaElement, () => void>();\n\nfunction accent() {\n return state.config?.accentColor ?? \"#6366f1\";\n}\n\n// ---------------------------------------------------------------------------\n// Position helpers\n// ---------------------------------------------------------------------------\n\nfunction getPopupPosition(anchor: HTMLElement): { top: number; left: number; origin: string } {\n const rect = anchor.getBoundingClientRect();\n const scrollY = window.scrollY;\n const scrollX = window.scrollX;\n const popupW = 320;\n const popupH = 260;\n const margin = 10;\n\n let left = rect.left + scrollX;\n let top = rect.bottom + scrollY + margin;\n let origin = \"top left\";\n\n // Flip up if not enough space below\n if (rect.bottom + popupH + margin > window.innerHeight) {\n top = rect.top + scrollY - popupH - margin;\n origin = \"bottom left\";\n }\n\n // Keep within viewport horizontally\n if (left + popupW > window.innerWidth + scrollX) {\n left = window.innerWidth + scrollX - popupW - margin;\n origin = origin.replace(\"left\", \"right\");\n }\n if (left < scrollX + margin) left = scrollX + margin;\n\n return { top, left, origin };\n}\n\n// ---------------------------------------------------------------------------\n// Build popup DOM\n// ---------------------------------------------------------------------------\n\nfunction buildHeader(key: string, onClose: () => void): HTMLElement {\n const header = document.createElement(\"div\");\n header.style.cssText = `\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 14px;\n `;\n\n const titleWrap = document.createElement(\"div\");\n titleWrap.style.cssText = `display: flex; flex-direction: column; gap: 1px; min-width: 0;`;\n\n const titleEl = document.createElement(\"span\");\n const keyParts = key.split(\".\");\n titleEl.textContent = keyParts[keyParts.length - 1].replace(/[-_]/g, \" \").replace(/\\b\\w/g, c => c.toUpperCase());\n titleEl.style.cssText = `\n font-size: 13px; font-weight: 600;\n color: rgba(255,255,255,0.9);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n `;\n\n const keyEl = document.createElement(\"span\");\n keyEl.textContent = key;\n keyEl.style.cssText = `\n font-size: 10px; font-family: \"SF Mono\", \"Fira Code\", ui-monospace, monospace;\n color: rgba(255,255,255,0.22); letter-spacing: 0.03em;\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n `;\n\n titleWrap.appendChild(titleEl);\n titleWrap.appendChild(keyEl);\n header.appendChild(titleWrap);\n header.appendChild(makeCloseButton(onClose));\n return header;\n}\n\nfunction buildTextPopup(\n key: string,\n anchorEl: HTMLElement,\n onClose: () => void\n): HTMLElement {\n const langs = state.config?.languages ?? [\"en\"];\n let activeLang = state.activeLang || langs[0];\n\n const wrap = document.createElement(\"div\");\n wrap.dataset.canciaPopup = \"1\";\n applyPopupStyles(wrap);\n wrap.appendChild(buildHeader(key, onClose));\n\n // Language tabs — minimal underline style, only if multiple langs\n if (langs.length > 1) {\n const tabs = document.createElement(\"div\");\n tabs.style.cssText = `display: flex; gap: 0; margin-bottom: 12px; border-bottom: 1px solid rgba(255,255,255,0.06);`;\n\n const renderTabs = () => {\n tabs.innerHTML = \"\";\n langs.forEach((lang) => {\n const tab = document.createElement(\"button\");\n tab.textContent = lang.toUpperCase();\n const isActive = lang === activeLang;\n tab.style.cssText = `\n padding: 5px 10px 6px; border: none; border-bottom: 2px solid;\n margin-bottom: -1px;\n font-size: 11px; font-weight: 600; cursor: pointer; letter-spacing: 0.06em;\n background: transparent;\n border-bottom-color: ${isActive ? accent() : \"transparent\"};\n color: ${isActive ? \"#fff\" : \"rgba(255,255,255,0.3)\"};\n transition: color 0.15s, border-color 0.15s;\n `;\n tab.addEventListener(\"mouseenter\", () => { if (!isActive) tab.style.color = \"rgba(255,255,255,0.6)\"; });\n tab.addEventListener(\"mouseleave\", () => { if (!isActive) tab.style.color = \"rgba(255,255,255,0.3)\"; });\n tab.addEventListener(\"click\", () => {\n const current = wrap.querySelector(\"textarea\") as HTMLTextAreaElement | null;\n if (current) {\n const existing = getValue(key, activeLang);\n const fallback = anchorEl.textContent?.trim() || \"\";\n if (current.value !== (existing || fallback)) {\n setPending(key, activeLang, current.value);\n }\n }\n activeLang = lang;\n state.activeLang = lang;\n // Active language changed globally — re-overlay the page's drafts so\n // other [data-cms] elements match the newly-selected language.\n applyOverlay();\n renderTabs();\n renderTextarea();\n });\n tabs.appendChild(tab);\n });\n };\n renderTabs();\n wrap.appendChild(tabs);\n }\n\n // Textarea\n let textarea: HTMLTextAreaElement;\n\n const attachInputHandler = () => {\n const prev = inputHandlers.get(textarea);\n if (prev) textarea.removeEventListener(\"input\", prev);\n const handler = () => {\n setPending(key, activeLang, textarea.value);\n onPendingChange();\n anchorEl.textContent = textarea.value;\n };\n inputHandlers.set(textarea, handler);\n textarea.addEventListener(\"input\", handler);\n };\n\n const renderTextarea = (isInit = false) => {\n if (!isInit && textarea) {\n // Swap value in-place — no DOM removal so no focus event, no blink\n textarea.value = getValue(key, activeLang) || anchorEl.textContent?.trim() || \"\";\n // Re-apply focused border since element stays focused\n textarea.style.borderColor = `${accent()}66`;\n textarea.style.background = \"rgba(255,255,255,0.05)\";\n attachInputHandler();\n return;\n }\n\n const footerEl = wrap.querySelector(\"[data-cancia-footer]\");\n\n textarea = document.createElement(\"textarea\");\n textarea.value = getValue(key, activeLang) || anchorEl.textContent?.trim() || \"\";\n textarea.rows = 4;\n textarea.placeholder = \"Enter text…\";\n textarea.style.cssText = `\n width: 100%; box-sizing: border-box;\n background: rgba(255,255,255,0.03); color: rgba(255,255,255,0.9);\n border: 1px solid rgba(255,255,255,0.07); border-radius: 10px;\n padding: 10px 12px;\n font-size: 13px; font-family: inherit; resize: none; outline: none;\n transition: border-color 0.18s, background 0.18s;\n line-height: 1.55;\n caret-color: ${accent()};\n `;\n textarea.addEventListener(\"focus\", () => {\n textarea.style.borderColor = `${accent()}66`;\n textarea.style.background = \"rgba(255,255,255,0.05)\";\n });\n textarea.addEventListener(\"blur\", () => {\n textarea.style.borderColor = \"rgba(255,255,255,0.07)\";\n textarea.style.background = \"rgba(255,255,255,0.03)\";\n });\n attachInputHandler();\n\n if (footerEl) {\n wrap.insertBefore(textarea, footerEl);\n } else {\n wrap.appendChild(textarea);\n }\n setTimeout(() => textarea.focus(), 80);\n };\n\n renderTextarea(true);\n\n // Footer\n const footer = document.createElement(\"div\");\n footer.dataset.canciaFooter = \"1\";\n footer.style.cssText = `display: flex; justify-content: flex-end; margin-top: 10px;`;\n\n const saveBtn = makePrimaryButton(\"Save\", accent());\n saveBtn.dataset.canciaSave = \"1\";\n saveBtn.title = \"Save (⌘S)\";\n saveBtn.addEventListener(\"click\", () => {\n const existing = getValue(key, activeLang);\n const fallback = anchorEl.textContent?.trim() || \"\";\n if (textarea.value !== (existing || fallback)) {\n setPending(key, activeLang, textarea.value);\n }\n onPendingChange();\n onClose();\n });\n\n footer.appendChild(saveBtn);\n wrap.appendChild(footer);\n\n return wrap;\n}\n\n// ---------------------------------------------------------------------------\n// Link popup — label + href as one unit\n// ---------------------------------------------------------------------------\n\n/** Same allow-list the schema enforces (isSafeHref). Kept in sync deliberately. */\nfunction isSafeHrefValue(href: string): boolean {\n const trimmed = href.trim();\n if (trimmed === \"\") return true; // empty is \"not set yet\", not unsafe\n if (/^(https?:|mailto:|tel:)/i.test(trimmed)) return true;\n const schemeMatch = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);\n if (schemeMatch) {\n const firstSep = trimmed.search(/[/?#]/);\n if (firstSep === -1 || schemeMatch[1].length < firstSep) return false;\n }\n return true;\n}\n\nfunction parseLink(raw: string): CanciaLinkValue {\n if (!raw) return { label: \"\", href: \"\" };\n const trimmed = raw.trim();\n if (trimmed.startsWith(\"{\")) {\n try {\n const p = JSON.parse(trimmed) as Partial<CanciaLinkValue>;\n if (p && typeof p === \"object\") {\n return { label: String(p.label ?? \"\"), href: String(p.href ?? \"\") };\n }\n } catch {\n // fall through — treat as a plain label\n }\n }\n // A legacy plain string is the label (a `text` field promoted to `link`).\n return { label: raw, href: \"\" };\n}\n\nfunction buildLinkPopup(\n key: string,\n anchorEl: HTMLElement,\n onClose: () => void\n): HTMLElement {\n const langs = state.config?.languages ?? [\"en\"];\n let activeLang = state.activeLang || langs[0];\n\n const wrap = document.createElement(\"div\");\n wrap.dataset.canciaPopup = \"1\";\n applyPopupStyles(wrap);\n wrap.appendChild(buildHeader(key, onClose));\n\n // A button usually holds an icon beside its text, so the editable label is\n // marked with [data-cms-label]. A responsive button may carry SEVERAL marked\n // labels that swap by breakpoint — paint them all. Fall back to the element\n // itself when there is no marker (a plain <a> with no icon).\n const marked = anchorEl.querySelectorAll<HTMLElement>(\"[data-cms-label]\");\n const labelNodes: HTMLElement[] = marked.length > 0 ? Array.from(marked) : [anchorEl];\n const labelNode = labelNodes[0];\n\n // Fall back to what is actually rendered so a first edit starts from the\n // page's own values rather than empty inputs.\n const domLabel = labelNode.textContent?.trim() ?? \"\";\n const domHref = anchorEl.getAttribute(\"href\") ?? \"\";\n\n const readCurrent = (lang: string): CanciaLinkValue => {\n const stored = parseLink(getValue(key, lang));\n return {\n label: stored.label || domLabel,\n // The href is shared across languages (see the note below), so fall back\n // to the default language's stored value before the DOM.\n href: stored.href || parseLink(getValue(key, langs[0])).href || domHref,\n };\n };\n\n const inputStyle = `\n width: 100%; box-sizing: border-box;\n background: rgba(255,255,255,0.03); color: rgba(255,255,255,0.9);\n border: 1px solid rgba(255,255,255,0.07); border-radius: 10px;\n padding: 9px 12px;\n font-size: 13px; font-family: inherit; outline: none;\n transition: border-color 0.18s, background 0.18s;\n caret-color: ${accent()};\n `;\n\n const makeLabelled = (text: string, input: HTMLInputElement) => {\n const field = document.createElement(\"div\");\n field.style.cssText = `display: flex; flex-direction: column; gap: 5px; margin-bottom: 10px;`;\n const lab = document.createElement(\"div\");\n lab.textContent = text;\n lab.style.cssText = `font-size:10px;letter-spacing:0.08em;text-transform:uppercase;color:rgba(255,255,255,0.35);`;\n input.style.cssText = inputStyle;\n input.addEventListener(\"focus\", () => {\n input.style.borderColor = `${accent()}66`;\n input.style.background = \"rgba(255,255,255,0.05)\";\n });\n input.addEventListener(\"blur\", () => {\n input.style.borderColor = \"rgba(255,255,255,0.07)\";\n input.style.background = \"rgba(255,255,255,0.03)\";\n });\n field.appendChild(lab);\n field.appendChild(input);\n return field;\n };\n\n const labelInput = document.createElement(\"input\");\n labelInput.type = \"text\";\n labelInput.placeholder = \"Book a call\";\n\n const hrefInput = document.createElement(\"input\");\n hrefInput.type = \"text\";\n hrefInput.inputMode = \"url\";\n hrefInput.placeholder = \"/start or https://…\";\n\n const current = readCurrent(activeLang);\n labelInput.value = current.label;\n hrefInput.value = current.href;\n\n // Language tabs — the LABEL is per-language, the href is not (a CTA points\n // at the same place whatever language it is written in). Only the label\n // input swaps; the note under the URL says so, since it is surprising.\n if (langs.length > 1) {\n const tabs = document.createElement(\"div\");\n tabs.style.cssText = `display: flex; gap: 0; margin-bottom: 12px; border-bottom: 1px solid rgba(255,255,255,0.06);`;\n const renderTabs = () => {\n tabs.innerHTML = \"\";\n langs.forEach((lang) => {\n const tab = document.createElement(\"button\");\n tab.textContent = lang.toUpperCase();\n const isActive = lang === activeLang;\n tab.style.cssText = `\n padding: 5px 10px 6px; border: none; border-bottom: 2px solid;\n margin-bottom: -1px;\n font-size: 11px; font-weight: 600; cursor: pointer; letter-spacing: 0.06em;\n background: transparent;\n border-bottom-color: ${isActive ? accent() : \"transparent\"};\n color: ${isActive ? \"#fff\" : \"rgba(255,255,255,0.3)\"};\n transition: color 0.15s, border-color 0.15s;\n `;\n tab.addEventListener(\"click\", () => {\n // Persist the label being edited before switching away from it.\n stage(activeLang);\n activeLang = lang;\n state.activeLang = lang;\n applyOverlay();\n labelInput.value = readCurrent(lang).label;\n renderTabs();\n });\n tabs.appendChild(tab);\n });\n };\n renderTabs();\n wrap.appendChild(tabs);\n }\n\n wrap.appendChild(makeLabelled(\"Label\", labelInput));\n wrap.appendChild(makeLabelled(\"URL\", hrefInput));\n\n const hint = document.createElement(\"div\");\n hint.style.cssText = `font-size:11px;color:rgba(255,255,255,0.28);margin:-4px 0 10px;line-height:1.45;`;\n hint.textContent =\n langs.length > 1\n ? \"Relative (/start), #anchor, mailto: and tel: all work. The URL is shared across languages.\"\n : \"Relative (/start), #anchor, mailto: and tel: all work.\";\n wrap.appendChild(hint);\n\n const warn = document.createElement(\"div\");\n warn.style.cssText = `font-size:11px;color:#f0a; margin:-4px 0 10px; display:none;`;\n wrap.appendChild(warn);\n\n // Live preview on the page as the editor types. Writes to the label nodes,\n // NOT the anchor — setting textContent on the anchor would delete its icon.\n const paint = () => {\n labelNodes.forEach((n) => (n.textContent = labelInput.value));\n if (isSafeHrefValue(hrefInput.value)) anchorEl.setAttribute(\"href\", hrefInput.value);\n };\n\n /** Stage the current inputs as a pending change for `lang`. */\n const stage = (lang: string) => {\n const value: CanciaLinkValue = {\n label: labelInput.value,\n href: hrefInput.value.trim(),\n };\n const existing = parseLink(getValue(key, lang));\n if (existing.label !== value.label || existing.href !== value.href) {\n setPending(key, lang, JSON.stringify(value));\n }\n };\n\n const validate = (): boolean => {\n const ok = isSafeHrefValue(hrefInput.value);\n warn.style.display = ok ? \"none\" : \"block\";\n warn.textContent = ok ? \"\" : \"That URL scheme isn’t allowed and won’t be saved.\";\n return ok;\n };\n\n labelInput.addEventListener(\"input\", () => {\n paint();\n onPendingChange();\n });\n hrefInput.addEventListener(\"input\", () => {\n validate();\n paint();\n onPendingChange();\n });\n\n setTimeout(() => labelInput.focus(), 80);\n\n // Footer\n const footer = document.createElement(\"div\");\n footer.dataset.canciaFooter = \"1\";\n footer.style.cssText = `display: flex; justify-content: flex-end; margin-top: 10px;`;\n\n const saveBtn = makePrimaryButton(\"Save\", accent());\n saveBtn.dataset.canciaSave = \"1\";\n saveBtn.title = \"Save (⌘S)\";\n saveBtn.addEventListener(\"click\", () => {\n // Refuse to persist an unsafe scheme — the schema rejects it server-side\n // too, but failing here tells the editor why instead of silently dropping.\n if (!validate()) return;\n stage(activeLang);\n onPendingChange();\n onClose();\n });\n\n footer.appendChild(saveBtn);\n wrap.appendChild(footer);\n\n return wrap;\n}\n\nfunction buildImagePopup(\n key: string,\n anchorEl: HTMLElement,\n onClose: () => void\n): HTMLElement {\n const wrap = document.createElement(\"div\");\n wrap.dataset.canciaPopup = \"1\";\n applyPopupStyles(wrap);\n wrap.appendChild(buildHeader(key, onClose));\n\n // Current image preview\n const currentSrc = anchorEl.tagName === \"IMG\"\n ? (anchorEl as HTMLImageElement).src\n : anchorEl.querySelector(\"img\")?.src ?? \"\";\n\n if (currentSrc && !currentSrc.startsWith(\"data:\")) {\n const previewWrap = document.createElement(\"div\");\n previewWrap.style.cssText = `\n border-radius: 10px; overflow: hidden; margin-bottom: 10px;\n border: 1px solid rgba(255,255,255,0.06);\n position: relative; height: 100px;\n `;\n const previewImg = document.createElement(\"img\");\n previewImg.src = currentSrc;\n previewImg.style.cssText = `width: 100%; height: 100%; object-fit: cover; display: block;`;\n const previewLabel = document.createElement(\"div\");\n previewLabel.textContent = \"Current\";\n previewLabel.style.cssText = `\n position: absolute; bottom: 0; left: 0; right: 0;\n font-size: 10px; color: rgba(255,255,255,0.45); letter-spacing: 0.04em;\n padding: 16px 8px 6px;\n background: linear-gradient(transparent, rgba(0,0,0,0.55));\n `;\n previewWrap.appendChild(previewImg);\n previewWrap.appendChild(previewLabel);\n wrap.appendChild(previewWrap);\n }\n\n // Drop zone — clean, minimal\n const dropZone = document.createElement(\"label\");\n dropZone.style.cssText = `\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n gap: 8px;\n border: 1.5px dashed rgba(255,255,255,0.1); border-radius: 10px;\n padding: 24px 20px;\n cursor: pointer;\n transition: border-color 0.18s, background 0.18s;\n background: rgba(255,255,255,0.015);\n `;\n\n // Simple arrow-up icon, no container box\n const uploadIcon = document.createElement(\"div\");\n uploadIcon.style.cssText = `color: rgba(255,255,255,0.35); transition: color 0.18s;`;\n uploadIcon.innerHTML = `<svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12 15V3m0 0L8 7m4-4l4 4M2 17l.621 2.485A2 2 0 004.561 21h14.878a2 2 0 001.94-1.515L22 17\"/>\n </svg>`;\n\n const dropText = document.createElement(\"div\");\n dropText.style.cssText = `text-align: center;`;\n dropText.innerHTML = `\n <div style=\"font-size:12px;font-weight:500;color:rgba(255,255,255,0.5);\">Drop an image</div>\n <div style=\"font-size:11px;color:rgba(255,255,255,0.25);margin-top:2px;\">or click to browse</div>\n `;\n\n dropZone.appendChild(uploadIcon);\n dropZone.appendChild(dropText);\n\n const fileInput = document.createElement(\"input\");\n fileInput.type = \"file\";\n fileInput.accept = \"image/*\";\n fileInput.style.display = \"none\";\n dropZone.appendChild(fileInput);\n\n // Status area\n const statusWrap = document.createElement(\"div\");\n statusWrap.style.cssText = `margin-top: 8px; min-height: 18px;`;\n\n const statusMsg = document.createElement(\"p\");\n statusMsg.style.cssText = `font-size: 11px; color: rgba(255,255,255,0.35); margin: 0; text-align: center; transition: color 0.2s;`;\n\n const progressBar = document.createElement(\"div\");\n progressBar.style.cssText = `\n height: 2px; border-radius: 2px; background: rgba(255,255,255,0.05);\n overflow: hidden; margin-top: 6px; display: none;\n `;\n const progressFill = document.createElement(\"div\");\n progressFill.style.cssText = `\n height: 100%; border-radius: 2px; background: ${accent()};\n width: 0%; transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1);\n `;\n progressBar.appendChild(progressFill);\n statusWrap.appendChild(statusMsg);\n statusWrap.appendChild(progressBar);\n\n const handleFile = async (file: File) => {\n if (!file.type.startsWith(\"image/\")) {\n statusMsg.textContent = \"Only image files are supported\";\n statusMsg.style.color = \"#f87171\";\n return;\n }\n const maxMb = 10;\n if (file.size > maxMb * 1024 * 1024) {\n statusMsg.textContent = `File too large (max ${maxMb}MB)`;\n statusMsg.style.color = \"#f87171\";\n return;\n }\n dropZone.style.borderColor = `${accent()}55`;\n dropZone.style.background = `${accent()}0a`;\n uploadIcon.style.color = accent();\n statusMsg.textContent = \"Uploading…\";\n statusMsg.style.color = \"rgba(255,255,255,0.45)\";\n progressBar.style.display = \"block\";\n progressFill.style.width = \"0%\";\n\n try {\n const url = await uploadImage(file, (percent) => {\n progressFill.style.width = `${percent}%`;\n });\n progressFill.style.width = \"100%\";\n setPending(key, state.activeLang, url);\n onPendingChange();\n\n if (anchorEl.tagName === \"IMG\") {\n const img = anchorEl as HTMLImageElement;\n img.srcset = \"\";\n img.src = url;\n } else {\n const img = document.createElement(\"img\");\n img.src = url;\n img.alt = \"\";\n img.style.cssText = \"width:100%;height:100%;object-fit:cover;display:block;\";\n img.dataset.cms = key;\n anchorEl.replaceWith(img);\n }\n\n setTimeout(() => {\n statusMsg.textContent = \"Done\";\n statusMsg.style.color = \"#4ade80\";\n setTimeout(onClose, 600);\n }, 200);\n } catch {\n progressBar.style.display = \"none\";\n statusMsg.textContent = \"Upload failed — try again\";\n statusMsg.style.color = \"#f87171\";\n dropZone.style.borderColor = \"rgba(255,255,255,0.1)\";\n dropZone.style.background = \"rgba(255,255,255,0.015)\";\n uploadIcon.style.color = \"rgba(255,255,255,0.35)\";\n }\n };\n\n fileInput.addEventListener(\"change\", () => {\n if (fileInput.files?.[0]) handleFile(fileInput.files[0]);\n });\n\n dropZone.addEventListener(\"dragover\", (e) => {\n e.preventDefault();\n if (!dragover) {\n dragover = true;\n dropZone.style.borderColor = `${accent()}88`;\n dropZone.style.background = `${accent()}0d`;\n uploadIcon.style.color = accent();\n }\n });\n dropZone.addEventListener(\"dragleave\", () => {\n dragover = false;\n dropZone.style.borderColor = \"rgba(255,255,255,0.1)\";\n dropZone.style.background = \"rgba(255,255,255,0.015)\";\n uploadIcon.style.color = \"rgba(255,255,255,0.35)\";\n });\n dropZone.addEventListener(\"drop\", (e) => {\n e.preventDefault();\n dragover = false;\n dropZone.style.borderColor = \"rgba(255,255,255,0.1)\";\n dropZone.style.background = \"rgba(255,255,255,0.015)\";\n const file = e.dataTransfer?.files[0];\n if (file) handleFile(file);\n });\n\n dropZone.addEventListener(\"mouseenter\", () => {\n if (!dragover) {\n dropZone.style.borderColor = \"rgba(255,255,255,0.18)\";\n dropZone.style.background = \"rgba(255,255,255,0.03)\";\n }\n });\n dropZone.addEventListener(\"mouseleave\", () => {\n if (!dragover) {\n dropZone.style.borderColor = \"rgba(255,255,255,0.1)\";\n dropZone.style.background = \"rgba(255,255,255,0.015)\";\n }\n });\n\n wrap.appendChild(dropZone);\n wrap.appendChild(statusWrap);\n\n return wrap;\n}\n\n// ---------------------------------------------------------------------------\n// Shared UI helpers\n// ---------------------------------------------------------------------------\n\nexport function makeCloseButton(onClose: () => void): HTMLButtonElement {\n const btn = document.createElement(\"button\");\n btn.style.cssText = `\n display: flex; align-items: center; justify-content: center;\n width: 24px; height: 24px; border-radius: 6px; flex-shrink: 0;\n background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.06);\n cursor: pointer; color: rgba(255,255,255,0.35); padding: 0;\n transition: background 0.15s, color 0.15s;\n `;\n btn.innerHTML = `<svg width=\"9\" height=\"9\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M1 1l8 8M9 1L1 9\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>`;\n btn.addEventListener(\"mouseenter\", () => {\n btn.style.background = \"rgba(255,255,255,0.08)\";\n btn.style.color = \"rgba(255,255,255,0.75)\";\n });\n btn.addEventListener(\"mouseleave\", () => {\n btn.style.background = \"rgba(255,255,255,0.04)\";\n btn.style.color = \"rgba(255,255,255,0.35)\";\n });\n btn.addEventListener(\"click\", onClose);\n return btn;\n}\n\nexport function makePrimaryButton(label: string, color: string): HTMLButtonElement {\n const btn = document.createElement(\"button\");\n btn.textContent = label;\n btn.style.cssText = `\n padding: 7px 16px; border-radius: 8px; border: none; cursor: pointer;\n background: #fff; color: #0c0c0e;\n font-size: 12px; font-weight: 600; letter-spacing: 0.01em;\n transition: opacity 0.15s, transform 0.1s cubic-bezier(0.2, 0, 0, 1);\n `;\n btn.addEventListener(\"mouseenter\", () => (btn.style.opacity = \"0.88\"));\n btn.addEventListener(\"mouseleave\", () => (btn.style.opacity = \"1\"));\n return btn;\n}\n\n// ---------------------------------------------------------------------------\n// Styles\n// ---------------------------------------------------------------------------\n\nfunction applyPopupStyles(el: HTMLElement) {\n el.style.cssText = `\n position: absolute;\n z-index: 2147483646;\n width: 320px;\n background: rgba(14, 14, 16, 0.97);\n backdrop-filter: blur(24px) saturate(180%);\n -webkit-backdrop-filter: blur(24px) saturate(180%);\n border: 1px solid rgba(255,255,255,0.07);\n border-radius: 14px;\n padding: 14px;\n box-shadow: 0 0 0 1px rgba(0,0,0,0.4), 0 8px 24px rgba(0,0,0,0.5), 0 24px 64px rgba(0,0,0,0.4);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n animation: cancia-popup-in 0.25s cubic-bezier(0.16, 1, 0.3, 1) both;\n `;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport function openPopup(\n key: string,\n fieldType: \"text\" | \"image\" | \"link\",\n anchorEl: HTMLElement,\n onClose: () => void\n) {\n closePopup();\n\n const done = () => { onClose(); closePopup(); };\n const popup =\n fieldType === \"image\"\n ? buildImagePopup(key, anchorEl, done)\n : fieldType === \"link\"\n ? buildLinkPopup(key, anchorEl, done)\n : buildTextPopup(key, anchorEl, done);\n\n document.body.appendChild(popup);\n popupEl = popup;\n\n const { top, left, origin } = getPopupPosition(anchorEl);\n popup.style.top = `${top}px`;\n popup.style.left = `${left}px`;\n popup.style.transformOrigin = origin;\n\n // Click outside to close\n outsideListener = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node)) {\n closePopup();\n onClose();\n }\n };\n setTimeout(() => {\n if (outsideListener) document.addEventListener(\"click\", outsideListener, true);\n }, 100);\n\n // Keyboard shortcuts\n keyListener = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n closePopup();\n onClose();\n }\n if ((e.metaKey || e.ctrlKey) && e.key === \"s\") {\n e.preventDefault();\n popup.querySelector<HTMLButtonElement>(\"[data-cancia-save]\")?.click();\n }\n };\n document.addEventListener(\"keydown\", keyListener, true);\n}\n\nexport function closePopup() {\n if (outsideListener) {\n document.removeEventListener(\"click\", outsideListener, true);\n outsideListener = null;\n }\n if (keyListener) {\n document.removeEventListener(\"keydown\", keyListener, true);\n keyListener = null;\n }\n if (popupEl) {\n const el = popupEl;\n popupEl = null;\n el.style.animation = \"none\";\n el.style.transition = \"opacity 0.18s cubic-bezier(0.4, 0, 1, 1), transform 0.18s cubic-bezier(0.4, 0, 1, 1)\";\n el.style.opacity = \"0\";\n el.style.transform = \"scale(0.96) translateY(3px)\";\n setTimeout(() => el.remove(), 200);\n }\n}\n","// =============================================================================\n// Cancia Toolbar — List Panel\n// =============================================================================\n// Right-side slide-in panel that opens when the user clicks a [data-cms-list]\n// element. Per-locale: tabs at the top switch which locale's entries are\n// rendered. Entries that exist in other locales but not the active one are\n// shown as a \"not translated\" stub so the user can fill them in.\n// =============================================================================\n\nimport {\n fetchList,\n fetchTranslations,\n reorderList,\n type ListEntry,\n type ListSchemaDescription,\n type TranslationStatus,\n} from \"./api\";\nimport { state } from \"./state\";\n\nconst PANEL_Z = 2147483646;\nconst BACKDROP_Z = 2147483646;\n\nlet panelEl: HTMLElement | null = null;\nlet backdropEl: HTMLElement | null = null;\nlet styleInjected = false;\n// Captured per-open so refreshListPanel() can re-fetch and re-render in place.\nlet currentSchema: ListSchemaDescription | null = null;\nlet currentBody: HTMLElement | null = null;\nlet currentTabsRow: HTMLElement | null = null;\nlet currentOnEditEntry: ((entry: ListEntry, locale: string) => void) | null = null;\nlet currentOnAddEntry: ((locale: string) => void) | null = null;\nlet currentOnTranslateEntry:\n | ((id: string, sourceEntry: ListEntry | null, targetLocale: string) => void)\n | null = null;\n\nfunction injectStyles() {\n if (styleInjected) return;\n styleInjected = true;\n const s = document.createElement(\"style\");\n s.textContent = `\n @keyframes cancia-panel-in {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n }\n @keyframes cancia-panel-out {\n from { transform: translateX(0); }\n to { transform: translateX(100%); }\n }\n @keyframes cancia-backdrop-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n `;\n document.head.appendChild(s);\n}\n\nfunction accent(): string {\n return state.config?.accentColor ?? \"#6366f1\";\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction formatExcerpt(value: unknown, maxLength = 120): string {\n const text = toPlainText(value);\n if (!text) return \"\";\n const trimmed = text.trim();\n if (trimmed.length <= maxLength) return trimmed;\n return trimmed.slice(0, maxLength).trimEnd() + \"…\";\n}\n\n/**\n * Flatten a stored field value to a plain-text preview string. Handles plain\n * strings and Portable-Text SUBSET arrays (richtext) — for the latter, joins\n * the span texts across blocks. Anything else yields \"\".\n */\nfunction toPlainText(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (Array.isArray(value)) {\n // Portable-Text SUBSET blocks: { children: [{ text }] }.\n const parts: string[] = [];\n for (const block of value) {\n if (block && typeof block === \"object\" && Array.isArray((block as { children?: unknown }).children)) {\n for (const span of (block as { children: unknown[] }).children) {\n const t = (span as { text?: unknown })?.text;\n if (typeof t === \"string\") parts.push(t);\n }\n parts.push(\" \");\n }\n }\n return parts.join(\"\").replace(/\\s+/g, \" \").trim();\n }\n return \"\";\n}\n\n/**\n * Auto-derive a scannable preview for a list row (plan 025), NO schema config:\n * subtitle — the bodyField (richtext flattened / text stripped), else the\n * first text-ish scalar field after the title that has a value.\n * thumbnail — the value of the first image-widget field that holds a URL.\n * Both are best-effort and independently optional (a title-only row is fine).\n */\nfunction derivePreview(\n schema: ListSchemaDescription,\n data: Record<string, unknown>,\n): { subtitle: string; thumbnail: string } {\n // --- Subtitle ---\n let subtitle = \"\";\n if (schema.bodyField) subtitle = formatExcerpt(data[schema.bodyField]);\n if (!subtitle) {\n const TEXTISH = new Set([\"text\", \"textarea\", \"richtext\"]);\n for (const f of schema.fields) {\n if (f.name === schema.titleField) continue;\n if (!TEXTISH.has(f.widget)) continue;\n const s = formatExcerpt(data[f.name]);\n if (s) { subtitle = s; break; }\n }\n }\n\n // --- Thumbnail ---\n let thumbnail = \"\";\n for (const f of schema.fields) {\n if (f.widget !== \"image\") continue;\n const v = data[f.name];\n if (typeof v === \"string\" && v.trim()) { thumbnail = v.trim(); break; }\n }\n\n return { subtitle, thumbnail };\n}\n\nfunction locales(): string[] {\n return state.config?.languages ?? [];\n}\n\nfunction buildShell(schema: ListSchemaDescription): {\n panel: HTMLElement;\n body: HTMLElement;\n tabsRow: HTMLElement;\n} {\n const panel = document.createElement(\"div\");\n panel.dataset.canciaListPanel = \"1\";\n panel.style.cssText = `\n position: fixed;\n top: 0; right: 0; bottom: 0;\n width: min(420px, 100vw);\n background: #fff;\n color: #1a1a1d;\n z-index: ${PANEL_Z};\n box-shadow: -8px 0 32px rgba(0,0,0,0.18);\n display: flex;\n flex-direction: column;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n animation: cancia-panel-in 0.22s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n `;\n\n panel.innerHTML = `\n <header style=\"\n display: flex; align-items: center; justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid #eaeaea;\n \">\n <div>\n <div style=\"font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: #777;\">List</div>\n <div style=\"font-size: 17px; font-weight: 600; margin-top: 2px;\">${escapeHtml(schema.label)}</div>\n </div>\n <button data-cancia-close style=\"\n appearance: none; border: 0; background: transparent;\n cursor: pointer; padding: 6px; border-radius: 6px;\n color: #555; transition: background 0.12s, color 0.12s;\n \" aria-label=\"Close panel\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\">\n <path d=\"M4 4l10 10M14 4L4 14\"/>\n </svg>\n </button>\n </header>\n <div data-cancia-tabs style=\"\n display: flex; gap: 4px;\n padding: 8px 16px 0;\n border-bottom: 1px solid #f3f3f3;\n overflow-x: auto;\n \"></div>\n <div style=\"padding: 12px 20px; border-bottom: 1px solid #f3f3f3;\">\n <button data-cancia-add style=\"\n appearance: none; border: 1px dashed ${accent()}; background: ${accent()}10;\n color: ${accent()}; font-weight: 600; font-size: 13px;\n padding: 10px 14px; border-radius: 8px; width: 100%; cursor: pointer;\n display: flex; align-items: center; justify-content: center; gap: 6px;\n transition: background 0.12s;\n \">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\">\n <path d=\"M7 2v10M2 7h10\"/>\n </svg>\n Add ${escapeHtml(schema.labelSingular.toLowerCase())}\n </button>\n </div>\n <div data-cancia-entries style=\"\n flex: 1; overflow-y: auto;\n padding: 8px 12px 16px;\n \">\n <div data-cancia-loading style=\"text-align: center; padding: 32px 12px; color: #888; font-size: 13px;\">Loading…</div>\n </div>\n `;\n\n const body = panel.querySelector(\"[data-cancia-entries]\") as HTMLElement;\n const tabsRow = panel.querySelector(\"[data-cancia-tabs]\") as HTMLElement;\n return { panel, body, tabsRow };\n}\n\nfunction renderTabs(tabsRow: HTMLElement, activeLocale: string, onSwitch: (loc: string) => void) {\n tabsRow.innerHTML = \"\";\n const langs = locales();\n if (langs.length <= 1) {\n tabsRow.style.display = \"none\";\n return;\n }\n tabsRow.style.display = \"flex\";\n\n for (const loc of langs) {\n const tab = document.createElement(\"button\");\n const isActive = loc === activeLocale;\n tab.style.cssText = `\n appearance: none; border: 0; background: transparent;\n font-family: inherit; font-size: 12px; font-weight: 600;\n letter-spacing: 0.04em; text-transform: uppercase;\n padding: 8px 10px 9px;\n cursor: ${isActive ? \"default\" : \"pointer\"};\n color: ${isActive ? accent() : \"#777\"};\n border-bottom: 2px solid ${isActive ? accent() : \"transparent\"};\n margin-bottom: -1px;\n transition: color 0.12s, border-color 0.12s;\n `;\n tab.textContent = loc;\n if (!isActive) {\n tab.addEventListener(\"mouseenter\", () => { tab.style.color = \"#333\"; });\n tab.addEventListener(\"mouseleave\", () => { tab.style.color = \"#777\"; });\n tab.addEventListener(\"click\", () => onSwitch(loc));\n }\n tabsRow.appendChild(tab);\n }\n}\n\ninterface RenderRow {\n id: string;\n locale: string;\n entry: ListEntry | null;\n translatedFrom: string | null;\n}\n\nfunction renderEntries(\n body: HTMLElement,\n schema: ListSchemaDescription,\n activeLocale: string,\n entriesInLocale: ListEntry[],\n translations: TranslationStatus[],\n allEntries: Map<string, ListEntry[]>,\n) {\n const entryById = new Map<string, ListEntry>();\n for (const e of entriesInLocale) entryById.set(e.id, e);\n\n const orderedIds: string[] = entriesInLocale.map((e) => e.id);\n const seen = new Set(orderedIds);\n for (const t of translations) {\n if (!seen.has(t.id)) {\n orderedIds.push(t.id);\n seen.add(t.id);\n }\n }\n\n const rows: RenderRow[] = orderedIds.map((id) => {\n const entry = entryById.get(id) ?? null;\n let translatedFrom: string | null = null;\n if (!entry) {\n const t = translations.find((x) => x.id === id);\n if (t && t.locales.length > 0) translatedFrom = t.locales[0];\n }\n return { id, locale: activeLocale, entry, translatedFrom };\n });\n\n if (rows.length === 0) {\n body.innerHTML = `\n <div style=\"text-align: center; padding: 40px 12px; color: #888; font-size: 13px;\">\n No entries yet. Click \"Add ${escapeHtml(schema.labelSingular.toLowerCase())}\" above to create one.\n </div>\n `;\n return;\n }\n\n body.innerHTML = \"\";\n\n // Drag-reorder state. Each rendered row gets a record so add/remove/reorder\n // stay in sync with the DOM. Reuses the same HTML5 drag mechanism as the\n // entry-modal array rows (plan 022): drag handle → dragover splice → drop.\n interface DragRec { wrap: HTMLElement; id: string }\n const dragRecs: DragRec[] = [];\n let dragging: DragRec | null = null;\n // Order snapshot captured at dragstart so a failed reorder can roll back to\n // exactly where it was before this drag.\n let orderBeforeDrag: string[] = [];\n\n // The FULL ordered id list — spans BOTH translated rows and \"not translated\"\n // stubs, because order is shared across locales and the store's reorder\n // DELETES any id NOT in the supplied list. We must always send every id.\n const currentOrder = (): string[] => dragRecs.map((r) => r.id);\n\n async function commitOrder(prevOrder: string[]): Promise<void> {\n try {\n await reorderList(schema.name, currentOrder());\n } catch {\n // Restore the previous DOM order on failure so nothing appears lost.\n const byId = new Map(dragRecs.map((r) => [r.id, r]));\n dragRecs.length = 0;\n for (const id of prevOrder) {\n const rec = byId.get(id);\n if (rec) { dragRecs.push(rec); body.appendChild(rec.wrap); }\n }\n // Surface a transient failure hint without nuking the list.\n const err = document.createElement(\"div\");\n err.textContent = \"Couldn't save the new order. Reverted.\";\n err.style.cssText = `text-align:center; padding:8px; color:#c0392b; font-size:12px;`;\n body.insertBefore(err, body.firstChild);\n setTimeout(() => err.remove(), 3000);\n }\n }\n\n rows.forEach((row) => {\n const isStub = row.entry === null;\n\n // Row wrapper holds the drag handle + the clickable item side by side.\n const wrap = document.createElement(\"div\");\n wrap.style.cssText = `display: flex; align-items: stretch; gap: 4px; margin-bottom: 6px;`;\n\n const handle = document.createElement(\"div\");\n handle.textContent = \"⋮⋮\";\n handle.title = \"Drag to reorder\";\n handle.draggable = true;\n handle.style.cssText = `\n cursor: grab; user-select: none;\n display: flex; align-items: center; justify-content: center;\n color: #bbb; font-size: 13px; letter-spacing: -2px;\n padding: 0 2px; flex-shrink: 0;\n `;\n\n const item = document.createElement(\"button\");\n item.style.cssText = `\n appearance: none; border: 1px solid transparent; background: ${isStub ? \"#fff8ee\" : \"#fafafa\"};\n text-align: left; flex: 1; min-width: 0;\n padding: 12px 14px; border-radius: 8px; cursor: pointer;\n transition: background 0.12s, border-color 0.12s, transform 0.12s;\n display: block;\n `;\n\n const rec: DragRec = { wrap, id: row.id };\n\n handle.addEventListener(\"dragstart\", (e) => {\n dragging = rec;\n orderBeforeDrag = currentOrder();\n handle.style.cursor = \"grabbing\";\n wrap.style.opacity = \"0.5\";\n e.dataTransfer?.setData(\"text/plain\", \"\");\n if (e.dataTransfer) e.dataTransfer.effectAllowed = \"move\";\n });\n handle.addEventListener(\"dragend\", () => {\n handle.style.cursor = \"grab\";\n wrap.style.opacity = \"1\";\n dragging = null;\n });\n wrap.addEventListener(\"dragover\", (e) => {\n if (!dragging || dragging === rec) return;\n e.preventDefault();\n const rect = wrap.getBoundingClientRect();\n const after = e.clientY > rect.top + rect.height / 2;\n const from = dragRecs.indexOf(dragging);\n let to = dragRecs.indexOf(rec);\n if (from < 0 || to < 0) return;\n if (after) to += 1;\n if (from < to) to -= 1;\n if (from === to) return;\n dragRecs.splice(from, 1);\n dragRecs.splice(to, 0, dragging);\n body.insertBefore(dragging.wrap, after ? wrap.nextSibling : wrap);\n });\n wrap.addEventListener(\"drop\", (e) => {\n if (!dragging) return;\n e.preventDefault();\n // Only persist if the order actually changed.\n const next = currentOrder();\n const changed = next.length !== orderBeforeDrag.length\n || next.some((id, i) => id !== orderBeforeDrag[i]);\n if (changed) void commitOrder(orderBeforeDrag);\n });\n\n if (row.entry) {\n const titleValue = row.entry.data[schema.titleField];\n const title =\n typeof titleValue === \"string\" && titleValue.trim().length > 0\n ? titleValue\n : `(untitled ${schema.labelSingular.toLowerCase()})`;\n const { subtitle, thumbnail } = derivePreview(schema, row.entry.data);\n // NEVER innerHTML user text: title/subtitle are escapeHtml'd, and the\n // thumbnail URL goes through an escaped src attribute (escapeHtml escapes\n // the quote), so a crafted URL can't break out of the attribute.\n const textCol = `\n <div style=\"min-width: 0; flex: 1;\">\n <div style=\"font-weight: 600; font-size: 14px; color: #1a1a1d; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\">${escapeHtml(title)}</div>\n ${subtitle ? `<div style=\"font-size: 12px; color: #666; margin-top: 4px; line-height: 1.4;\">${escapeHtml(subtitle)}</div>` : \"\"}\n </div>\n `;\n const thumb = thumbnail\n ? `<img src=\"${escapeHtml(thumbnail)}\" alt=\"\" loading=\"lazy\" style=\"\n width: 44px; height: 44px; flex-shrink: 0; object-fit: cover;\n border-radius: 6px; background: #eee; border: 1px solid #eaeaea;\n \" onerror=\"this.style.display='none'\" />`\n : \"\";\n item.innerHTML = `\n <div style=\"display: flex; align-items: center; gap: 12px;\">\n ${thumb}${textCol}\n </div>\n `;\n item.addEventListener(\"mouseenter\", () => {\n item.style.background = \"#f3f3f3\";\n item.style.borderColor = \"#e3e3e3\";\n });\n item.addEventListener(\"mouseleave\", () => {\n item.style.background = \"#fafafa\";\n item.style.borderColor = \"transparent\";\n });\n item.addEventListener(\"click\", () => currentOnEditEntry?.(row.entry!, activeLocale));\n } else {\n const sourceLocale = row.translatedFrom!;\n const sourceEntry =\n allEntries.get(sourceLocale)?.find((e) => e.id === row.id) ?? null;\n const sourceTitleValue = sourceEntry?.data[schema.titleField];\n const sourceTitle =\n typeof sourceTitleValue === \"string\" && sourceTitleValue.trim().length > 0\n ? sourceTitleValue\n : row.id;\n item.innerHTML = `\n <div style=\"display: flex; align-items: center; gap: 8px;\">\n <span style=\"\n font-size: 9px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;\n background: #f5b400; color: #fff;\n padding: 2px 6px; border-radius: 4px;\n \">Not translated</span>\n <span style=\"font-size: 11px; color: #888;\">from ${escapeHtml(sourceLocale)}</span>\n </div>\n <div style=\"font-weight: 600; font-size: 14px; color: #6b5616; margin-top: 6px;\">${escapeHtml(sourceTitle)}</div>\n <div style=\"font-size: 11px; color: #b08800; margin-top: 4px;\">Click to translate into ${escapeHtml(activeLocale)}</div>\n `;\n item.addEventListener(\"mouseenter\", () => {\n item.style.background = \"#fff2d5\";\n item.style.borderColor = \"#f5d27a\";\n });\n item.addEventListener(\"mouseleave\", () => {\n item.style.background = \"#fff8ee\";\n item.style.borderColor = \"transparent\";\n });\n item.addEventListener(\"click\", () =>\n currentOnTranslateEntry?.(row.id, sourceEntry, activeLocale),\n );\n }\n\n wrap.appendChild(handle);\n wrap.appendChild(item);\n dragRecs.push(rec);\n body.appendChild(wrap);\n });\n}\n\nexport interface OpenListPanelOptions {\n schema: ListSchemaDescription;\n /** Locale to start on. Defaults to state.activeLang. */\n initialLocale?: string;\n onAddEntry: (locale: string) => void;\n onEditEntry: (entry: ListEntry, locale: string) => void;\n /** Called when user clicks a \"not translated\" row. */\n onTranslateEntry: (id: string, sourceEntry: ListEntry | null, targetLocale: string) => void;\n}\n\nexport async function openListPanel(opts: OpenListPanelOptions): Promise<void> {\n closeListPanel();\n injectStyles();\n\n const backdrop = document.createElement(\"div\");\n backdrop.dataset.canciaPanelBackdrop = \"1\";\n backdrop.style.cssText = `\n position: fixed; inset: 0;\n background: rgba(10,10,12,0.32);\n z-index: ${BACKDROP_Z};\n animation: cancia-backdrop-in 0.18s ease-out forwards;\n `;\n backdrop.addEventListener(\"click\", () => closeListPanel());\n document.body.appendChild(backdrop);\n backdropEl = backdrop;\n\n const { panel, body, tabsRow } = buildShell(opts.schema);\n document.body.appendChild(panel);\n panelEl = panel;\n currentSchema = opts.schema;\n currentBody = body;\n currentTabsRow = tabsRow;\n currentOnEditEntry = opts.onEditEntry;\n currentOnAddEntry = opts.onAddEntry;\n currentOnTranslateEntry = opts.onTranslateEntry;\n\n const langs = locales();\n const initial = opts.initialLocale ?? state.activeLang ?? langs[0] ?? \"\";\n state.activeListLocale = langs.includes(initial) ? initial : (langs[0] ?? initial);\n\n panel.querySelector<HTMLButtonElement>(\"[data-cancia-close]\")?.addEventListener(\n \"click\",\n () => closeListPanel(),\n );\n panel.querySelector<HTMLButtonElement>(\"[data-cancia-add]\")?.addEventListener(\n \"click\",\n () => currentOnAddEntry?.(state.activeListLocale),\n );\n\n await refreshListPanel();\n}\n\n/**\n * Re-fetch the current list and re-render the entries. No-op if the panel\n * isn't open. Called by the entry modal after a successful save/delete, and\n * by tab switches.\n */\nexport async function refreshListPanel(): Promise<void> {\n if (!panelEl || !currentSchema || !currentBody || !currentTabsRow) return;\n const schema = currentSchema;\n const body = currentBody;\n const tabsRow = currentTabsRow;\n\n renderTabs(tabsRow, state.activeListLocale, async (newLocale) => {\n state.activeListLocale = newLocale;\n await refreshListPanel();\n });\n\n try {\n const langs = locales();\n const [translations, ...perLocale] = await Promise.all([\n fetchTranslations(schema.name),\n ...langs.map((l) => fetchList(schema.name, l)),\n ]);\n if (!panelEl) return;\n const allEntries = new Map<string, ListEntry[]>();\n langs.forEach((l, i) => allEntries.set(l, perLocale[i] ?? []));\n const activeEntries = allEntries.get(state.activeListLocale) ?? [];\n renderEntries(body, schema, state.activeListLocale, activeEntries, translations, allEntries);\n } catch (err) {\n if (!panelEl) return;\n body.innerHTML = `\n <div style=\"text-align: center; padding: 32px 12px; color: #c0392b; font-size: 13px;\">\n Failed to load entries: ${escapeHtml(err instanceof Error ? err.message : String(err))}\n </div>\n `;\n }\n}\n\nexport function closeListPanel(): void {\n if (panelEl) {\n panelEl.style.animation = \"cancia-panel-out 0.18s cubic-bezier(0.7, 0, 0.84, 0) forwards\";\n const el = panelEl;\n setTimeout(() => el.remove(), 180);\n panelEl = null;\n }\n if (backdropEl) {\n const el = backdropEl;\n el.style.opacity = \"0\";\n el.style.transition = \"opacity 0.18s ease-out\";\n setTimeout(() => el.remove(), 180);\n backdropEl = null;\n }\n currentSchema = null;\n currentBody = null;\n currentTabsRow = null;\n currentOnEditEntry = null;\n currentOnAddEntry = null;\n currentOnTranslateEntry = null;\n}\n\nexport function isListPanelOpen(): boolean {\n return panelEl !== null;\n}\n","// =============================================================================\n// Cancia Toolbar — Entry Modal\n// =============================================================================\n// Same visual family as popup.ts (dark frosted shell, same close + primary\n// button helpers) but laid out as a centered, viewport-bounded modal so it\n// can host a longer form than the anchored popup.\n//\n// Layout:\n// ┌─ header (fixed) ─────────────────────────┐\n// │ eyebrow + title close │\n// ├─ body (scrolls) ─────────────────────────┤\n// │ form fields… │\n// ├─ footer (fixed) ─────────────────────────┤\n// │ [Delete] [Cancel] [Save] │\n// └───────────────────────────────────────────┘\n//\n// Only the body scrolls. Header + footer are always visible, so Save and\n// Delete are always reachable regardless of how many fields the schema has.\n// =============================================================================\n\nimport {\n createListEntry,\n updateListEntry,\n deleteListEntry,\n uploadImage,\n fetchList,\n type ListEntry,\n type ListSchemaDescription,\n type ListSchemaField,\n} from \"./api\";\nimport { state } from \"./state\";\nimport { makeCloseButton, makePrimaryButton } from \"./popup\";\nimport {\n rowsToPortableText,\n portableTextToRows,\n portableTextSubsetSchema,\n PT_STYLES,\n type RichTextRow,\n type PtStyle,\n type PtListItem,\n} from \"@cancia/astro/richtext\";\nimport { slugify } from \"@cancia/astro/schema\";\n\nconst MODAL_Z = 2147483647;\nconst BACKDROP_Z = 2147483646;\n\nlet modalEl: HTMLElement | null = null;\nlet backdropEl: HTMLElement | null = null;\nlet escListener: ((e: KeyboardEvent) => void) | null = null;\nlet styleInjected = false;\n\n// ---------------------------------------------------------------------------\n// Styles — shared keyframes + focus styles for inputs inside the modal\n// ---------------------------------------------------------------------------\n\nfunction injectStyles() {\n if (styleInjected) return;\n styleInjected = true;\n const s = document.createElement(\"style\");\n s.textContent = `\n @keyframes cancia-modal-in {\n from { opacity: 0; transform: translate(-50%, calc(-50% + 8px)) scale(0.985); }\n to { opacity: 1; transform: translate(-50%, -50%) scale(1); }\n }\n @keyframes cancia-modal-out {\n from { opacity: 1; transform: translate(-50%, -50%) scale(1); }\n to { opacity: 0; transform: translate(-50%, calc(-50% + 8px)) scale(0.985); }\n }\n .cancia-form-input:focus,\n .cancia-form-textarea:focus,\n .cancia-form-select:focus {\n border-color: var(--cancia-accent-border, rgba(99,102,241,0.6));\n background: rgba(255,255,255,0.05);\n outline: none;\n }\n .cancia-form-input::placeholder,\n .cancia-form-textarea::placeholder {\n color: rgba(255,255,255,0.25);\n }\n .cancia-form-select option {\n background: #15151a;\n color: rgba(255,255,255,0.9);\n }\n .cancia-field-error {\n color: #ff8786;\n font-size: 11px;\n margin-top: 5px;\n line-height: 1.35;\n }\n `;\n document.head.appendChild(s);\n}\n\nfunction accent(): string {\n return state.config?.accentColor ?? \"#6366f1\";\n}\n\nfunction accentBorder(): string {\n const a = accent();\n if (/^#[0-9a-f]{6}$/i.test(a)) return `${a}99`;\n return \"rgba(99,102,241,0.6)\";\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n// ---------------------------------------------------------------------------\n// Datetime helpers — ISO ⇄ datetime-local\n// ---------------------------------------------------------------------------\n\nfunction isoToLocalInput(iso: string): string {\n if (!iso) return \"\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return \"\";\n const pad = (n: number) => n.toString().padStart(2, \"0\");\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n}\n\nfunction localInputToIso(local: string): string {\n if (!local) return \"\";\n const d = new Date(local);\n if (Number.isNaN(d.getTime())) return \"\";\n return d.toISOString();\n}\n\n// ---------------------------------------------------------------------------\n// Field rendering — all inputs share the same dark style\n// ---------------------------------------------------------------------------\n\nconst INPUT_BASE = `\n width: 100%; box-sizing: border-box;\n background: rgba(255,255,255,0.03);\n color: rgba(255,255,255,0.9);\n border: 1px solid rgba(255,255,255,0.07);\n border-radius: 8px;\n padding: 8px 11px;\n font-size: 13px;\n font-family: inherit;\n line-height: 1.5;\n outline: none;\n transition: border-color 0.18s, background 0.18s;\n`;\n\ninterface FieldState {\n field: ListSchemaField;\n getValue: () => unknown;\n setError: (msg: string | null) => void;\n /**\n * Validate this field (recursively, for array/object) and return whether it\n * passed. Scalar fields fall back to the shared required + constraint checks;\n * array/object branches override this to validate their children and paint\n * nested error slots. Populates/clears the field's own error UI as a side\n * effect. Returns the effective value (may be undefined when empty).\n */\n validate: () => { value: unknown; ok: boolean };\n /**\n * Slug auto-fill wiring (plan 025). Only set on plain text-ish inputs.\n * `onInput` lets a slug field subscribe to a source field's keystrokes;\n * `setValue` lets the slug field push an auto-derived value into its input.\n * Left undefined for composite/non-input widgets.\n */\n onInput?: (cb: () => void) => void;\n setValue?: (v: string) => void;\n}\n\n/**\n * Depth guard for nested array/object rendering. Client sites don't need deep\n * nesting; this stops a pathological schema from blowing the stack.\n */\nconst MAX_FIELD_DEPTH = 6;\n\nfunction renderField(\n field: ListSchemaField,\n initial: unknown,\n depth = 0,\n): { wrapper: HTMLElement; fieldState: FieldState } {\n const wrapper = document.createElement(\"div\");\n wrapper.style.cssText = `margin-bottom: 14px;`;\n\n const labelRow = document.createElement(\"label\");\n labelRow.style.cssText = `\n display: flex; align-items: baseline; justify-content: space-between;\n gap: 8px;\n font-size: 11px; font-weight: 600;\n color: rgba(255,255,255,0.75);\n letter-spacing: 0.04em;\n margin-bottom: 5px;\n `;\n\n const labelText = document.createElement(\"span\");\n labelText.textContent = field.label;\n if (field.required) {\n const star = document.createElement(\"span\");\n star.textContent = \" *\";\n star.style.color = \"rgba(255,135,134,0.8)\";\n labelText.appendChild(star);\n }\n labelRow.appendChild(labelText);\n // Array/object rows for an unnamed item (\"\") shouldn't show an empty label bar.\n if (field.label) wrapper.appendChild(labelRow);\n\n if (field.description) {\n const help = document.createElement(\"div\");\n help.style.cssText = `font-size: 11px; color: rgba(255,255,255,0.35); margin-bottom: 6px; line-height: 1.4;`;\n help.textContent = field.description;\n wrapper.appendChild(help);\n }\n\n const errorEl = document.createElement(\"div\");\n errorEl.className = \"cancia-field-error\";\n errorEl.style.display = \"none\";\n\n const setError = (msg: string | null) => {\n if (msg) {\n errorEl.textContent = msg;\n errorEl.style.display = \"block\";\n } else {\n errorEl.textContent = \"\";\n errorEl.style.display = \"none\";\n }\n };\n\n let getValue: () => unknown;\n // Array/object branches assign their own recursive validator. Anything that\n // leaves this null uses the shared scalar validator (required + constraints).\n let validate: (() => { value: unknown; ok: boolean }) | null = null;\n // Slug auto-fill hooks; assigned by the plain-input branches only.\n let onInput: ((cb: () => void) => void) | undefined;\n let setValue: ((v: string) => void) | undefined;\n\n switch (field.widget) {\n case \"array\": {\n const built = renderArrayField(field, initial, setError, depth);\n wrapper.appendChild(built.control);\n getValue = built.getValue;\n validate = built.validate;\n break;\n }\n\n case \"object\": {\n const built = renderObjectField(field, initial, setError, depth);\n wrapper.appendChild(built.control);\n getValue = built.getValue;\n validate = built.validate;\n break;\n }\n\n case \"reference\": {\n const built = renderReferenceField(field, initial);\n wrapper.appendChild(built.control);\n getValue = built.getValue;\n break;\n }\n\n case \"richtext\": {\n const built = renderRichTextField(field, initial, setError);\n wrapper.appendChild(built.control);\n getValue = built.getValue;\n validate = built.validate;\n break;\n }\n\n case \"textarea\": {\n const ta = document.createElement(\"textarea\");\n ta.className = \"cancia-form-textarea\";\n ta.style.cssText = `${INPUT_BASE} resize: vertical; min-height: 110px; max-height: 320px; caret-color: ${accent()};`;\n ta.rows = 5;\n if (field.placeholder) ta.placeholder = field.placeholder;\n if (typeof initial === \"string\") ta.value = initial;\n wrapper.appendChild(ta);\n getValue = () => ta.value;\n break;\n }\n\n case \"checkbox\": {\n const row = document.createElement(\"label\");\n row.style.cssText = `display: flex; align-items: center; gap: 9px; cursor: pointer; user-select: none; padding: 6px 0;`;\n const cb = document.createElement(\"input\");\n cb.type = \"checkbox\";\n cb.style.cssText = `width: 16px; height: 16px; accent-color: ${accent()};`;\n if (initial === true) cb.checked = true;\n const txt = document.createElement(\"span\");\n txt.style.cssText = `font-size: 13px; color: rgba(255,255,255,0.7);`;\n txt.textContent = field.placeholder ?? `Enable ${field.label.toLowerCase()}`;\n row.appendChild(cb);\n row.appendChild(txt);\n wrapper.appendChild(row);\n getValue = () => cb.checked;\n break;\n }\n\n case \"select\": {\n const sel = document.createElement(\"select\");\n sel.className = \"cancia-form-select\";\n sel.style.cssText = `${INPUT_BASE} appearance: none; padding-right: 30px; background-image: url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'><path d='M2.5 3.75l2.5 2.5 2.5-2.5' stroke='rgba(255,255,255,0.4)' stroke-width='1.3' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>\"); background-repeat: no-repeat; background-position: right 10px center; cursor: pointer;`;\n if (!field.required) {\n const empty = document.createElement(\"option\");\n empty.value = \"\";\n empty.textContent = \"—\";\n sel.appendChild(empty);\n }\n for (const opt of field.options ?? []) {\n const o = document.createElement(\"option\");\n o.value = opt;\n o.textContent = opt;\n if (initial === opt) o.selected = true;\n sel.appendChild(o);\n }\n wrapper.appendChild(sel);\n getValue = () => (sel.value === \"\" ? undefined : sel.value);\n break;\n }\n\n case \"image\": {\n const initialUrl = typeof initial === \"string\" ? initial : \"\";\n let currentUrl = initialUrl;\n\n const container = document.createElement(\"div\");\n container.style.cssText = `\n display: flex; gap: 10px; align-items: stretch;\n background: rgba(255,255,255,0.02);\n border: 1px dashed rgba(255,255,255,0.1);\n border-radius: 10px;\n padding: 10px;\n `;\n\n const preview = document.createElement(\"div\");\n preview.style.cssText = `\n width: 72px; height: 72px; flex-shrink: 0;\n background: rgba(255,255,255,0.04) no-repeat center / cover;\n border: 1px solid rgba(255,255,255,0.06);\n border-radius: 6px;\n display: flex; align-items: center; justify-content: center;\n color: rgba(255,255,255,0.25);\n `;\n const updatePreview = (url: string) => {\n if (url) {\n preview.style.backgroundImage = `url(\"${url.replace(/\"/g, '\\\\\"')}\")`;\n preview.innerHTML = \"\";\n } else {\n preview.style.backgroundImage = \"\";\n preview.innerHTML = `<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><path d=\"M21 15l-5-5L5 21\"/></svg>`;\n }\n };\n updatePreview(initialUrl);\n\n const right = document.createElement(\"div\");\n right.style.cssText = `flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px;`;\n\n const fileInput = document.createElement(\"input\");\n fileInput.type = \"file\";\n fileInput.accept = \"image/*\";\n fileInput.style.display = \"none\";\n\n const btnRow = document.createElement(\"div\");\n btnRow.style.cssText = `display: flex; gap: 6px;`;\n\n const uploadBtn = document.createElement(\"button\");\n uploadBtn.type = \"button\";\n uploadBtn.style.cssText = `\n appearance: none; cursor: pointer;\n background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.85);\n border: 1px solid rgba(255,255,255,0.07);\n font-size: 11px; font-weight: 500; letter-spacing: 0.02em;\n padding: 5px 10px; border-radius: 6px;\n transition: background 0.15s;\n `;\n uploadBtn.textContent = \"Upload…\";\n uploadBtn.addEventListener(\"mouseenter\", () => { uploadBtn.style.background = \"rgba(255,255,255,0.1)\"; });\n uploadBtn.addEventListener(\"mouseleave\", () => { uploadBtn.style.background = \"rgba(255,255,255,0.06)\"; });\n uploadBtn.addEventListener(\"click\", () => fileInput.click());\n\n const clearBtn = document.createElement(\"button\");\n clearBtn.type = \"button\";\n clearBtn.style.cssText = `\n appearance: none; cursor: pointer;\n background: transparent; color: rgba(255,255,255,0.4);\n border: 1px solid transparent;\n font-size: 11px;\n padding: 5px 8px; border-radius: 6px;\n `;\n clearBtn.textContent = \"Clear\";\n clearBtn.addEventListener(\"click\", () => {\n currentUrl = \"\";\n urlField.value = \"\";\n updatePreview(\"\");\n });\n\n btnRow.appendChild(uploadBtn);\n btnRow.appendChild(clearBtn);\n\n const urlField = document.createElement(\"input\");\n urlField.type = \"url\";\n urlField.className = \"cancia-form-input\";\n urlField.style.cssText = `${INPUT_BASE} font-size: 11px; padding: 6px 9px;`;\n urlField.placeholder = \"https://… or upload\";\n urlField.value = initialUrl;\n urlField.addEventListener(\"input\", () => {\n currentUrl = urlField.value.trim();\n updatePreview(currentUrl);\n });\n\n const progressEl = document.createElement(\"div\");\n progressEl.style.cssText = `font-size: 10px; color: rgba(255,255,255,0.5); height: 12px;`;\n\n right.appendChild(btnRow);\n right.appendChild(urlField);\n right.appendChild(progressEl);\n\n container.appendChild(preview);\n container.appendChild(right);\n container.appendChild(fileInput);\n wrapper.appendChild(container);\n\n fileInput.addEventListener(\"change\", async () => {\n const file = fileInput.files?.[0];\n if (!file) return;\n uploadBtn.disabled = true;\n progressEl.style.color = \"rgba(255,255,255,0.5)\";\n try {\n const url = await uploadImage(file, (pct) => {\n progressEl.textContent = `Uploading… ${pct}%`;\n });\n currentUrl = url;\n urlField.value = url;\n updatePreview(url);\n progressEl.textContent = \"Uploaded\";\n setTimeout(() => { progressEl.textContent = \"\"; }, 1500);\n } catch (err) {\n progressEl.textContent = `Upload failed: ${err instanceof Error ? err.message : String(err)}`;\n progressEl.style.color = \"#ff8786\";\n } finally {\n uploadBtn.disabled = false;\n fileInput.value = \"\";\n }\n });\n\n getValue = () => (currentUrl === \"\" ? undefined : currentUrl);\n break;\n }\n\n case \"datetime\": {\n const input = document.createElement(\"input\");\n input.type = \"datetime-local\";\n input.className = \"cancia-form-input\";\n // datetime-local on dark backgrounds needs a colour-scheme nudge so the\n // calendar/clock icon renders white instead of black.\n input.style.cssText = `${INPUT_BASE} color-scheme: dark; caret-color: ${accent()};`;\n if (typeof initial === \"string\") input.value = isoToLocalInput(initial);\n wrapper.appendChild(input);\n getValue = () => {\n const v = input.value.trim();\n if (!v) return undefined;\n return localInputToIso(v);\n };\n break;\n }\n\n case \"number\": {\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.className = \"cancia-form-input\";\n input.style.cssText = `${INPUT_BASE} caret-color: ${accent()};`;\n if (field.min !== undefined) input.min = String(field.min);\n if (field.max !== undefined) input.max = String(field.max);\n if (typeof initial === \"number\") input.value = String(initial);\n else if (typeof initial === \"string\" && initial !== \"\") input.value = initial;\n wrapper.appendChild(input);\n getValue = () => {\n const v = input.value.trim();\n if (v === \"\") return undefined;\n const n = Number(v);\n return Number.isNaN(n) ? undefined : n;\n };\n break;\n }\n\n default: {\n // text | url | email | slug\n const input = document.createElement(\"input\");\n input.type = field.widget === \"url\" ? \"url\" : field.widget === \"email\" ? \"email\" : \"text\";\n input.className = \"cancia-form-input\";\n input.style.cssText = `${INPUT_BASE} caret-color: ${accent()};`;\n if (field.placeholder) input.placeholder = field.placeholder;\n if (field.minLength !== undefined) input.minLength = field.minLength;\n if (field.maxLength !== undefined) input.maxLength = field.maxLength;\n if (typeof initial === \"string\") input.value = initial;\n wrapper.appendChild(input);\n getValue = () => input.value;\n // Expose keystroke subscription + value setter so slug auto-fill (below)\n // can react to a source field and push a derived slug into a slug input.\n onInput = (cb) => input.addEventListener(\"input\", cb);\n setValue = (v) => { input.value = v; };\n break;\n }\n }\n\n wrapper.appendChild(errorEl);\n\n // Scalar fields share the required + constraint validator; array/object\n // supplied their own recursive one above.\n const scalarValidate = (): { value: unknown; ok: boolean } => {\n const value = getValue();\n setError(null);\n if (field.required && (value === undefined || value === \"\" || value === null)) {\n setError(`${field.label || \"This field\"} is required`);\n return { value, ok: false };\n }\n const err = validateValue(field, value);\n if (err) {\n setError(err);\n return { value, ok: false };\n }\n return { value, ok: true };\n };\n\n return {\n wrapper,\n fieldState: { field, getValue, setError, validate: validate ?? scalarValidate, onInput, setValue },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Array + object branches (recursive)\n// ---------------------------------------------------------------------------\n\ninterface BuiltComposite {\n control: HTMLElement;\n getValue: () => unknown;\n validate: () => { value: unknown; ok: boolean };\n}\n\n/**\n * A repeatable list of `field.of` items. Each row is a full renderField of the\n * item schema plus a drag handle and a remove (×) button. Rows are tracked by a\n * live array of per-row records (not DOM index), so add/remove/reorder never\n * desync from their FieldState. Order is taken from live DOM order on collect.\n */\nfunction renderArrayField(\n field: ListSchemaField,\n initial: unknown,\n setOwnError: (msg: string | null) => void,\n depth: number,\n): BuiltComposite {\n const itemSchema = field.of;\n\n const container = document.createElement(\"div\");\n container.style.cssText = `\n display: flex; flex-direction: column; gap: 8px;\n background: rgba(255,255,255,0.02);\n border: 1px solid rgba(255,255,255,0.07);\n border-radius: 10px;\n padding: 10px;\n `;\n\n const rowsWrap = document.createElement(\"div\");\n rowsWrap.style.cssText = `display: flex; flex-direction: column; gap: 8px;`;\n container.appendChild(rowsWrap);\n\n if (!itemSchema || depth >= MAX_FIELD_DEPTH) {\n const note = document.createElement(\"div\");\n note.style.cssText = `font-size: 11px; color: rgba(255,255,255,0.4);`;\n note.textContent = itemSchema\n ? \"Nesting too deep to edit here.\"\n : \"This array has no item schema.\";\n container.appendChild(note);\n return { control: container, getValue: () => [], validate: () => ({ value: [], ok: true }) };\n }\n\n interface Row {\n el: HTMLElement;\n state: FieldState;\n }\n const rows: Row[] = [];\n\n // Drag-reorder: track the row being dragged; on dragover of another row,\n // splice it in before/after based on pointer position.\n let dragging: Row | null = null;\n\n function makeRow(itemValue: unknown): Row {\n const row = document.createElement(\"div\");\n row.style.cssText = `\n display: flex; align-items: flex-start; gap: 8px;\n background: rgba(255,255,255,0.02);\n border: 1px solid rgba(255,255,255,0.06);\n border-radius: 8px;\n padding: 8px;\n `;\n\n const handle = document.createElement(\"div\");\n handle.textContent = \"⋮⋮\";\n handle.title = \"Drag to reorder\";\n handle.draggable = true;\n handle.style.cssText = `\n cursor: grab; user-select: none;\n color: rgba(255,255,255,0.35);\n font-size: 13px; line-height: 1.2;\n padding: 4px 2px; flex-shrink: 0;\n letter-spacing: -2px;\n `;\n\n const { wrapper, fieldState } = renderField(itemSchema!, itemValue, depth + 1);\n wrapper.style.marginBottom = \"0\";\n wrapper.style.flex = \"1\";\n wrapper.style.minWidth = \"0\";\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.type = \"button\";\n removeBtn.textContent = \"×\";\n removeBtn.title = \"Remove\";\n removeBtn.style.cssText = `\n appearance: none; cursor: pointer; flex-shrink: 0;\n background: transparent; border: 1px solid transparent;\n color: rgba(255,135,134,0.7);\n font-size: 16px; line-height: 1;\n padding: 2px 7px; border-radius: 6px;\n transition: background 0.15s;\n `;\n removeBtn.addEventListener(\"mouseenter\", () => { removeBtn.style.background = \"rgba(255,135,134,0.1)\"; });\n removeBtn.addEventListener(\"mouseleave\", () => { removeBtn.style.background = \"transparent\"; });\n\n row.appendChild(handle);\n row.appendChild(wrapper);\n row.appendChild(removeBtn);\n\n const rec: Row = { el: row, state: fieldState };\n\n removeBtn.addEventListener(\"click\", () => {\n const i = rows.indexOf(rec);\n if (i >= 0) rows.splice(i, 1);\n row.remove();\n setOwnError(null);\n });\n\n handle.addEventListener(\"dragstart\", (e) => {\n dragging = rec;\n handle.style.cursor = \"grabbing\";\n row.style.opacity = \"0.5\";\n e.dataTransfer?.setData(\"text/plain\", \"\");\n if (e.dataTransfer) e.dataTransfer.effectAllowed = \"move\";\n });\n handle.addEventListener(\"dragend\", () => {\n handle.style.cursor = \"grab\";\n row.style.opacity = \"1\";\n dragging = null;\n });\n row.addEventListener(\"dragover\", (e) => {\n if (!dragging || dragging === rec) return;\n e.preventDefault();\n const rect = row.getBoundingClientRect();\n const after = e.clientY > rect.top + rect.height / 2;\n const from = rows.indexOf(dragging);\n let to = rows.indexOf(rec);\n if (from < 0 || to < 0) return;\n if (after) to += 1;\n if (from < to) to -= 1;\n if (from === to) return;\n rows.splice(from, 1);\n rows.splice(to, 0, dragging);\n // Reflect the new order in the DOM.\n rowsWrap.insertBefore(dragging.el, after ? row.nextSibling : row);\n });\n\n return rec;\n }\n\n function addRow(itemValue: unknown): void {\n const rec = makeRow(itemValue);\n rows.push(rec);\n rowsWrap.appendChild(rec.el);\n }\n\n const initialItems = Array.isArray(initial) ? initial : [];\n for (const it of initialItems) addRow(it);\n\n const addBtn = document.createElement(\"button\");\n addBtn.type = \"button\";\n const itemLabel = itemSchema.label || \"item\";\n addBtn.textContent = `+ Add ${itemLabel.toLowerCase()}`;\n addBtn.style.cssText = `\n appearance: none; cursor: pointer; align-self: flex-start;\n background: rgba(255,255,255,0.05); color: rgba(255,255,255,0.8);\n border: 1px solid rgba(255,255,255,0.08);\n font-size: 11px; font-weight: 500;\n padding: 6px 11px; border-radius: 7px;\n transition: background 0.15s;\n `;\n addBtn.addEventListener(\"mouseenter\", () => { addBtn.style.background = \"rgba(255,255,255,0.1)\"; });\n addBtn.addEventListener(\"mouseleave\", () => { addBtn.style.background = \"rgba(255,255,255,0.05)\"; });\n addBtn.addEventListener(\"click\", () => addRow(defaultForField(itemSchema)));\n container.appendChild(addBtn);\n\n const collect = (): unknown[] => rows.map((r) => r.state.getValue());\n\n return {\n control: container,\n // Deleting the last item serialises to [] (not undefined) so a cleared\n // array persists as an empty array.\n getValue: () => collect(),\n validate: () => {\n setOwnError(null);\n let ok = true;\n for (const r of rows) {\n const res = r.state.validate();\n if (!res.ok) ok = false;\n }\n const value = collect();\n if (field.required && value.length === 0) {\n setOwnError(`${field.label || \"This list\"} needs at least one item`);\n ok = false;\n }\n return { value, ok };\n },\n };\n}\n\n/**\n * A nested group. Renders each sub-field with renderField and collects them\n * into a plain object keyed by sub-field name. Objects nest arrays and vice\n * versa because both go back through renderField.\n */\nfunction renderObjectField(\n field: ListSchemaField,\n initial: unknown,\n setOwnError: (msg: string | null) => void,\n depth: number,\n): BuiltComposite {\n const subFields = field.fields ?? [];\n const subInitial = (initial && typeof initial === \"object\" && !Array.isArray(initial))\n ? (initial as Record<string, unknown>)\n : {};\n\n const fieldset = document.createElement(\"div\");\n fieldset.style.cssText = `\n display: flex; flex-direction: column; gap: 2px;\n background: rgba(255,255,255,0.02);\n border: 1px solid rgba(255,255,255,0.07);\n border-radius: 10px;\n padding: 10px 10px 0;\n `;\n\n if (depth >= MAX_FIELD_DEPTH) {\n const note = document.createElement(\"div\");\n note.style.cssText = `font-size: 11px; color: rgba(255,255,255,0.4); padding-bottom: 10px;`;\n note.textContent = \"Nesting too deep to edit here.\";\n fieldset.appendChild(note);\n return { control: fieldset, getValue: () => ({}), validate: () => ({ value: {}, ok: true }) };\n }\n\n const childStates: FieldState[] = [];\n for (const sub of subFields) {\n const { wrapper, fieldState } = renderField(sub, subInitial[sub.name], depth + 1);\n fieldset.appendChild(wrapper);\n childStates.push(fieldState);\n }\n\n const collect = (): Record<string, unknown> => {\n const out: Record<string, unknown> = {};\n for (const c of childStates) {\n const v = c.getValue();\n // Keep empty strings out, mirroring the top-level collector, but always\n // serialise the object itself (never undefined) so a group persists.\n if (v !== undefined && v !== \"\") out[c.field.name] = v;\n }\n return out;\n };\n\n return {\n control: fieldset,\n getValue: () => collect(),\n validate: () => {\n setOwnError(null);\n let ok = true;\n for (const c of childStates) {\n const res = c.validate();\n if (!res.ok) ok = false;\n }\n return { value: collect(), ok };\n },\n };\n}\n\n/**\n * A reference field: a native <select> whose options are the target list's\n * entries (label = the target's titleField value, value = the entry id). Stores\n * the chosen id as a plain string.\n *\n * Loading is async — the select renders immediately with a disabled \"Loading…\"\n * option (and, when editing, the current id preserved as a placeholder so\n * getValue never drops it while the fetch is in flight). Once the fetch\n * resolves the options are populated and the current value re-selected.\n *\n * Per D5 there is NO integrity: a stored id that is no longer in the target\n * list (target deleted) is kept and surfaced as a distinct \"⚠ missing (<id>)\"\n * option so saving doesn't silently drop it.\n */\nfunction renderReferenceField(\n field: ListSchemaField,\n initial: unknown,\n): { control: HTMLElement; getValue: () => unknown } {\n const currentId = typeof initial === \"string\" ? initial : \"\";\n const targetList = field.referenceList;\n\n const sel = document.createElement(\"select\");\n sel.className = \"cancia-form-select\";\n sel.style.cssText = `${INPUT_BASE} appearance: none; padding-right: 30px; background-image: url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'><path d='M2.5 3.75l2.5 2.5 2.5-2.5' stroke='rgba(255,255,255,0.4)' stroke-width='1.3' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>\"); background-repeat: no-repeat; background-position: right 10px center; cursor: pointer;`;\n\n const opt = (value: string, text: string, selected = false): HTMLOptionElement => {\n const o = document.createElement(\"option\");\n o.value = value;\n o.textContent = text;\n if (selected) o.selected = true;\n return o;\n };\n\n // Placeholder state while loading (and the fallback if there's no target).\n const loadingOpt = opt(\"\", \"Loading…\");\n loadingOpt.disabled = true;\n sel.appendChild(loadingOpt);\n // Preserve the current id during load so getValue keeps it if saved early.\n if (currentId) sel.appendChild(opt(currentId, `Current (${currentId})`, true));\n\n const getValue = () => (sel.value === \"\" ? undefined : sel.value);\n\n if (!targetList) {\n sel.innerHTML = \"\";\n const note = opt(\"\", \"No target list configured\");\n note.disabled = true;\n sel.appendChild(note);\n return { control: sel, getValue };\n }\n\n const titleField = state.schemas[targetList]?.titleField;\n\n // Resolve an entry's display title (falls back to id when unavailable).\n const titleOf = (entry: ListEntry): string => {\n if (titleField) {\n const v = entry.data[titleField];\n if (typeof v === \"string\" && v.trim()) return v;\n }\n return `(untitled · ${entry.id})`;\n };\n\n void (async () => {\n let entries: ListEntry[] = [];\n let failed = false;\n try {\n entries = await fetchList(targetList, state.activeListLocale || state.activeLang || undefined);\n } catch {\n failed = true;\n }\n\n sel.innerHTML = \"\";\n\n if (failed) {\n const errOpt = opt(\"\", \"Failed to load options\");\n errOpt.disabled = true;\n sel.appendChild(errOpt);\n // Still preserve any current id so a load failure doesn't drop it.\n if (currentId) sel.appendChild(opt(currentId, `Current (${currentId})`, true));\n return;\n }\n\n // Optional / not-required → an explicit \"none\" choice.\n if (!field.required) sel.appendChild(opt(\"\", \"— none —\", currentId === \"\"));\n\n let matched = false;\n for (const entry of entries) {\n const isCurrent = entry.id === currentId;\n if (isCurrent) matched = true;\n sel.appendChild(opt(entry.id, titleOf(entry), isCurrent));\n }\n\n // Dangling id (target deleted): keep it, surface it, don't drop it (D5).\n if (currentId && !matched) {\n sel.appendChild(opt(currentId, `⚠ missing (${currentId})`, true));\n }\n })();\n\n return { control: sel, getValue };\n}\n\n/**\n * The rich-text editor — APPROACH B (structured blocks + markdown shorthand).\n *\n * A list of block rows. Each row is:\n * - a <textarea> holding the block's text, where inline emphasis/links are\n * authored with a tiny markdown shorthand (**bold**, *italic*, [t](url));\n * - a style <select> (normal / h2 / h3 / blockquote);\n * - a list toggle (none / bullet / number).\n * Rows can be added, removed, and drag-reordered (same handle mechanism as the\n * array field). There is NO contenteditable and NO raw HTML anywhere.\n *\n * On collect, rows are serialised to a PT-subset value with rowsToPortableText\n * (the whitelisted parser in @cancia/astro), then round-tripped through\n * portableTextSubsetSchema as the accept guard — if that ever fails, validate()\n * blocks the save. Deserialisation (portableTextToRows) turns a stored value\n * back into editable shorthand rows.\n */\nfunction renderRichTextField(\n field: ListSchemaField,\n initial: unknown,\n setOwnError: (msg: string | null) => void,\n): BuiltComposite {\n const STYLE_LABELS: Record<PtStyle, string> = {\n normal: \"Normal\",\n h2: \"Heading 2\",\n h3: \"Heading 3\",\n blockquote: \"Quote\",\n };\n const LIST_LABELS: Array<{ value: \"\" | PtListItem; label: string }> = [\n { value: \"\", label: \"No list\" },\n { value: \"bullet\", label: \"Bulleted\" },\n { value: \"number\", label: \"Numbered\" },\n ];\n\n const container = document.createElement(\"div\");\n container.style.cssText = `\n display: flex; flex-direction: column; gap: 8px;\n background: rgba(255,255,255,0.02);\n border: 1px solid rgba(255,255,255,0.07);\n border-radius: 10px;\n padding: 10px;\n `;\n\n const rowsWrap = document.createElement(\"div\");\n rowsWrap.style.cssText = `display: flex; flex-direction: column; gap: 8px;`;\n container.appendChild(rowsWrap);\n\n interface RtRow {\n el: HTMLElement;\n read: () => RichTextRow;\n }\n const rows: RtRow[] = [];\n let dragging: RtRow | null = null;\n\n function makeRow(initialRow: RichTextRow): RtRow {\n const row = document.createElement(\"div\");\n row.style.cssText = `\n display: flex; align-items: flex-start; gap: 8px;\n background: rgba(255,255,255,0.02);\n border: 1px solid rgba(255,255,255,0.06);\n border-radius: 8px;\n padding: 8px;\n `;\n\n const handle = document.createElement(\"div\");\n handle.textContent = \"⋮⋮\";\n handle.title = \"Drag to reorder\";\n handle.draggable = true;\n handle.style.cssText = `\n cursor: grab; user-select: none;\n color: rgba(255,255,255,0.35);\n font-size: 13px; line-height: 1.2;\n padding: 4px 2px; flex-shrink: 0;\n letter-spacing: -2px;\n `;\n\n const main = document.createElement(\"div\");\n main.style.cssText = `flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px;`;\n\n const ta = document.createElement(\"textarea\");\n ta.className = \"cancia-form-textarea\";\n ta.style.cssText = `${INPUT_BASE} resize: vertical; min-height: 54px; max-height: 240px; caret-color: ${accent()};`;\n ta.rows = 2;\n ta.placeholder = \"Text — use **bold**, *italic*, [label](https://…)\";\n ta.value = initialRow.text;\n\n const controls = document.createElement(\"div\");\n controls.style.cssText = `display: flex; gap: 6px;`;\n\n const styleSel = document.createElement(\"select\");\n styleSel.className = \"cancia-form-select\";\n styleSel.style.cssText = `${INPUT_BASE} width: auto; flex: 1; appearance: none; padding: 5px 26px 5px 9px; font-size: 11px; background-image: url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'><path d='M2.5 3.75l2.5 2.5 2.5-2.5' stroke='rgba(255,255,255,0.4)' stroke-width='1.3' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>\"); background-repeat: no-repeat; background-position: right 9px center; cursor: pointer;`;\n for (const s of PT_STYLES) {\n const o = document.createElement(\"option\");\n o.value = s;\n o.textContent = STYLE_LABELS[s];\n if (initialRow.style === s) o.selected = true;\n styleSel.appendChild(o);\n }\n\n const listSel = document.createElement(\"select\");\n listSel.className = \"cancia-form-select\";\n listSel.style.cssText = styleSel.style.cssText;\n for (const { value, label } of LIST_LABELS) {\n const o = document.createElement(\"option\");\n o.value = value;\n o.textContent = label;\n if ((initialRow.listItem ?? \"\") === value) o.selected = true;\n listSel.appendChild(o);\n }\n\n controls.appendChild(styleSel);\n controls.appendChild(listSel);\n main.appendChild(ta);\n main.appendChild(controls);\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.type = \"button\";\n removeBtn.textContent = \"×\";\n removeBtn.title = \"Remove block\";\n removeBtn.style.cssText = `\n appearance: none; cursor: pointer; flex-shrink: 0;\n background: transparent; border: 1px solid transparent;\n color: rgba(255,135,134,0.7);\n font-size: 16px; line-height: 1;\n padding: 2px 7px; border-radius: 6px;\n transition: background 0.15s;\n `;\n removeBtn.addEventListener(\"mouseenter\", () => { removeBtn.style.background = \"rgba(255,135,134,0.1)\"; });\n removeBtn.addEventListener(\"mouseleave\", () => { removeBtn.style.background = \"transparent\"; });\n\n row.appendChild(handle);\n row.appendChild(main);\n row.appendChild(removeBtn);\n\n const rec: RtRow = {\n el: row,\n read: () => {\n const style = (styleSel.value as PtStyle) ?? \"normal\";\n const listValue = listSel.value as \"\" | PtListItem;\n const out: RichTextRow = { text: ta.value, style };\n if (listValue) out.listItem = listValue;\n return out;\n },\n };\n\n removeBtn.addEventListener(\"click\", () => {\n const i = rows.indexOf(rec);\n if (i >= 0) rows.splice(i, 1);\n row.remove();\n setOwnError(null);\n });\n\n handle.addEventListener(\"dragstart\", (e) => {\n dragging = rec;\n handle.style.cursor = \"grabbing\";\n row.style.opacity = \"0.5\";\n e.dataTransfer?.setData(\"text/plain\", \"\");\n if (e.dataTransfer) e.dataTransfer.effectAllowed = \"move\";\n });\n handle.addEventListener(\"dragend\", () => {\n handle.style.cursor = \"grab\";\n row.style.opacity = \"1\";\n dragging = null;\n });\n row.addEventListener(\"dragover\", (e) => {\n if (!dragging || dragging === rec) return;\n e.preventDefault();\n const rect = row.getBoundingClientRect();\n const after = e.clientY > rect.top + rect.height / 2;\n const from = rows.indexOf(dragging);\n let to = rows.indexOf(rec);\n if (from < 0 || to < 0) return;\n if (after) to += 1;\n if (from < to) to -= 1;\n if (from === to) return;\n rows.splice(from, 1);\n rows.splice(to, 0, dragging);\n rowsWrap.insertBefore(dragging.el, after ? row.nextSibling : row);\n });\n\n return rec;\n }\n\n function addRow(initialRow: RichTextRow): void {\n const rec = makeRow(initialRow);\n rows.push(rec);\n rowsWrap.appendChild(rec.el);\n }\n\n // Deserialise the stored value into editable shorthand rows.\n const initialRows: RichTextRow[] = (() => {\n const parsed = portableTextSubsetSchema.safeParse(initial);\n if (parsed.success && parsed.data.length > 0) return portableTextToRows(parsed.data);\n return [{ text: \"\", style: \"normal\" }];\n })();\n for (const r of initialRows) addRow(r);\n\n const addBtn = document.createElement(\"button\");\n addBtn.type = \"button\";\n addBtn.textContent = \"+ Add block\";\n addBtn.style.cssText = `\n appearance: none; cursor: pointer; align-self: flex-start;\n background: rgba(255,255,255,0.05); color: rgba(255,255,255,0.8);\n border: 1px solid rgba(255,255,255,0.08);\n font-size: 11px; font-weight: 500;\n padding: 6px 11px; border-radius: 7px;\n transition: background 0.15s;\n `;\n addBtn.addEventListener(\"mouseenter\", () => { addBtn.style.background = \"rgba(255,255,255,0.1)\"; });\n addBtn.addEventListener(\"mouseleave\", () => { addBtn.style.background = \"rgba(255,255,255,0.05)\"; });\n addBtn.addEventListener(\"click\", () => addRow({ text: \"\", style: \"normal\" }));\n container.appendChild(addBtn);\n\n // Serialise rows → PT-subset. Blank trailing/empty rows are dropped so an\n // empty editor persists as [] rather than a block of empty text.\n const serialise = (): unknown[] => {\n const editorRows = rows.map((r) => r.read()).filter((r) => r.text.trim() !== \"\");\n return rowsToPortableText(editorRows);\n };\n\n return {\n control: container,\n getValue: () => serialise(),\n validate: () => {\n setOwnError(null);\n const value = serialise();\n // Accept guard: the serialised value MUST validate against the subset\n // schema. The parser is whitelisted, so this should always pass — but it\n // is the hard gate that keeps out-of-subset content from ever persisting.\n const parsed = portableTextSubsetSchema.safeParse(value);\n if (!parsed.success) {\n setOwnError(\"This rich-text content is not valid. Check links and formatting.\");\n return { value, ok: false };\n }\n if (field.required && value.length === 0) {\n setOwnError(`${field.label || \"This field\"} is required`);\n return { value, ok: false };\n }\n return { value: parsed.data, ok: true };\n },\n };\n}\n\n/**\n * A sensible empty value for a freshly-added array item / object, so the new\n * row starts blank instead of undefined.\n */\nfunction defaultForField(field: ListSchemaField): unknown {\n if (field.widget === \"array\" || field.widget === \"richtext\") return [];\n if (field.widget === \"object\") {\n const out: Record<string, unknown> = {};\n for (const sub of field.fields ?? []) {\n const d = defaultForField(sub);\n if (d !== undefined) out[sub.name] = d;\n }\n return out;\n }\n if (field.widget === \"checkbox\") return false;\n return \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\ninterface ValidationResult {\n data: Record<string, unknown>;\n ok: boolean;\n}\n\nfunction preValidate(fieldStates: FieldState[]): ValidationResult {\n const data: Record<string, unknown> = {};\n let ok = true;\n\n for (const f of fieldStates) {\n // validate() runs required + constraint checks (recursively for\n // array/object) and paints inline errors as a side effect.\n const { value, ok: fieldOk } = f.validate();\n if (!fieldOk) {\n ok = false;\n continue;\n }\n\n // Keep empty scalars out; but arrays/objects/richtext always serialise (an\n // empty array is [], an empty group is {}, empty richtext is []), never\n // dropped to undefined.\n if (f.field.widget === \"array\" || f.field.widget === \"object\" || f.field.widget === \"richtext\") {\n data[f.field.name] = value;\n } else if (value !== undefined && value !== \"\") {\n data[f.field.name] = value;\n }\n }\n\n return { data, ok };\n}\n\n/**\n * Client-side constraint checks mirrored from the Zod schema (threaded via\n * FieldDescription). The server stays the source of truth — this only saves a\n * round-trip on obvious errors and gives inline feedback. Empty/undefined\n * values are already handled by the required check upstream, so here we only\n * validate present values.\n */\nfunction validateValue(field: ListSchemaField, value: unknown): string | null {\n if (value === undefined || value === null || value === \"\") return null;\n\n if (typeof value === \"string\") {\n if (field.minLength !== undefined && value.length < field.minLength) {\n return `Must be at least ${field.minLength} character${field.minLength === 1 ? \"\" : \"s\"}`;\n }\n if (field.maxLength !== undefined && value.length > field.maxLength) {\n return `Must be at most ${field.maxLength} characters`;\n }\n if (field.pattern !== undefined) {\n let re: RegExp | null = null;\n try {\n re = new RegExp(field.pattern);\n } catch {\n re = null; // Malformed pattern — leave it to the server.\n }\n if (re && !re.test(value)) {\n return \"Invalid format\";\n }\n }\n if (field.options && field.options.length > 0 && !field.options.includes(value)) {\n return \"Choose one of the allowed options\";\n }\n if (field.widget === \"email\" && !isLikelyEmail(value)) {\n return \"Enter a valid email address\";\n }\n if ((field.widget === \"url\" || field.widget === \"image\") && !isLikelyUrl(value)) {\n return \"Enter a valid URL\";\n }\n }\n\n if (typeof value === \"number\") {\n if (field.min !== undefined && value < field.min) {\n return `Must be at least ${field.min}`;\n }\n if (field.max !== undefined && value > field.max) {\n return `Must be at most ${field.max}`;\n }\n }\n\n return null;\n}\n\n// Deliberately loose — the server's Zod schema is authoritative. These only\n// catch obvious typos before a round-trip.\nfunction isLikelyEmail(s: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(s);\n}\n\nfunction isLikelyUrl(s: string): boolean {\n try {\n // eslint-disable-next-line no-new\n new URL(s);\n return true;\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Slug auto-fill (plan 025)\n// ---------------------------------------------------------------------------\n\n/**\n * Wire slug fields to their source field so the slug tracks the source live.\n *\n * A slug field qualifies if it has `widget: \"slug\"` and a `source` naming\n * another top-level field, and both fields expose input hooks (they are plain\n * text inputs, not composites). The slug is auto-derived only while \"clean\":\n * - a NEW entry with an empty slug starts clean → fills as the source types;\n * - a hand-edit of the slug latches it dirty → auto-fill stops (stays editable);\n * - an EXISTING (or pre-populated) slug starts dirty → never clobbered.\n */\nfunction wireSlugAutoFill(\n schema: ListSchemaDescription,\n fieldStates: FieldState[],\n sourceEntry: ListEntry | null,\n): void {\n const byName = new Map(fieldStates.map((f) => [f.field.name, f]));\n\n for (const slug of fieldStates) {\n if (slug.field.widget !== \"slug\") continue;\n const sourceName = slug.field.source;\n if (!sourceName) continue;\n const src = byName.get(sourceName);\n if (!src || !src.onInput || !slug.setValue) continue;\n\n // Start dirty if the slug already has a value (existing entry, translation,\n // or a manually-seeded default) — we must not overwrite it.\n const existing = sourceEntry?.data[slug.field.name];\n let dirty = typeof existing === \"string\" && existing.trim().length > 0;\n\n // A hand-edit of the slug latches it dirty forever.\n slug.onInput?.(() => { dirty = true; });\n\n src.onInput(() => {\n if (dirty) return;\n const sv = src.getValue();\n slug.setValue?.(typeof sv === \"string\" ? slugify(sv) : \"\");\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Modal lifecycle\n// ---------------------------------------------------------------------------\n\nexport interface EntryModalOptions {\n schema: ListSchemaDescription;\n /** Locale being edited / created in. */\n locale: string;\n /** null = create; ListEntry = edit. */\n entry: ListEntry | null;\n /**\n * Translation mode: fill in the form pre-populated from `entry` (which is in\n * a different locale than `locale`) and save into `locale` with a fixed id.\n */\n translateFromEntry?: ListEntry | null;\n /** Fixed id when translating (so order matches across locales). */\n fixedId?: string;\n /** Called after successful save or delete. */\n onSaved: () => void;\n}\n\nexport function openEntryModal(opts: EntryModalOptions): void {\n closeEntryModal();\n injectStyles();\n\n const isEdit = opts.entry !== null;\n const isTranslate = !isEdit && (opts.translateFromEntry ?? null) !== null;\n\n // CSS var for input focus border so the focus rule above can pick it up.\n document.documentElement.style.setProperty(\"--cancia-accent-border\", accentBorder());\n\n // ---- Backdrop ----\n const backdrop = document.createElement(\"div\");\n backdrop.dataset.canciaModalBackdrop = \"1\";\n backdrop.style.cssText = `\n position: fixed; inset: 0;\n background: rgba(8,8,10,0.55);\n backdrop-filter: blur(3px);\n -webkit-backdrop-filter: blur(3px);\n z-index: ${BACKDROP_Z};\n opacity: 0;\n transition: opacity 0.2s ease-out;\n `;\n document.body.appendChild(backdrop);\n requestAnimationFrame(() => { backdrop.style.opacity = \"1\"; });\n backdropEl = backdrop;\n\n // ---- Modal shell — same family as popup.ts (dark, frosted, rounded) ----\n // Sized to fit within the viewport: max-height is clamped, and the body\n // is the only scrolling region so header + footer stay reachable.\n const modal = document.createElement(\"div\");\n modal.dataset.canciaModal = \"1\";\n modal.style.cssText = `\n position: fixed;\n top: 50%; left: 50%;\n transform: translate(-50%, -50%);\n width: min(480px, calc(100vw - 32px));\n max-height: min(680px, calc(100vh - 48px));\n display: flex; flex-direction: column;\n background: rgba(14, 14, 16, 0.97);\n backdrop-filter: blur(24px) saturate(180%);\n -webkit-backdrop-filter: blur(24px) saturate(180%);\n border: 1px solid rgba(255,255,255,0.07);\n border-radius: 14px;\n box-shadow: 0 0 0 1px rgba(0,0,0,0.4), 0 8px 24px rgba(0,0,0,0.5), 0 24px 64px rgba(0,0,0,0.4);\n z-index: ${MODAL_Z};\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n color: rgba(255,255,255,0.9);\n animation: cancia-modal-in 0.22s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n overflow: hidden;\n `;\n document.body.appendChild(modal);\n modalEl = modal;\n\n // ---- Header (fixed) ----\n const header = document.createElement(\"div\");\n header.style.cssText = `\n display: flex; align-items: center; justify-content: space-between;\n padding: 14px 16px 12px;\n border-bottom: 1px solid rgba(255,255,255,0.06);\n flex-shrink: 0;\n `;\n\n const titleWrap = document.createElement(\"div\");\n titleWrap.style.cssText = `display: flex; flex-direction: column; gap: 2px; min-width: 0;`;\n\n const eyebrow = document.createElement(\"span\");\n eyebrow.style.cssText = `\n font-size: 10px; font-weight: 600;\n color: rgba(255,255,255,0.32);\n letter-spacing: 0.08em; text-transform: uppercase;\n `;\n const action = isEdit ? \"Edit\" : isTranslate ? \"Translate\" : \"New\";\n eyebrow.textContent = `${action} ${opts.schema.labelSingular.toLowerCase()} · ${opts.locale}`;\n\n const titleEl = document.createElement(\"span\");\n titleEl.style.cssText = `\n font-size: 14px; font-weight: 600;\n color: rgba(255,255,255,0.92);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n `;\n titleEl.textContent = opts.schema.label;\n\n titleWrap.appendChild(eyebrow);\n titleWrap.appendChild(titleEl);\n\n header.appendChild(titleWrap);\n header.appendChild(makeCloseButton(() => closeEntryModal()));\n modal.appendChild(header);\n\n // ---- Body (scrolls) ----\n const body = document.createElement(\"div\");\n body.style.cssText = `\n padding: 14px 16px 4px;\n overflow-y: auto;\n flex: 1 1 auto;\n min-height: 0;\n `;\n modal.appendChild(body);\n\n // Form-level error banner (REV_CONFLICT, network errors)\n const formError = document.createElement(\"div\");\n formError.style.cssText = `\n display: none;\n background: rgba(255,135,134,0.08);\n color: #ff8786;\n border: 1px solid rgba(255,135,134,0.18);\n border-radius: 8px;\n padding: 9px 11px;\n font-size: 12px;\n line-height: 1.4;\n margin-bottom: 12px;\n `;\n body.appendChild(formError);\n\n function showFormError(msg: string): void {\n formError.textContent = msg;\n formError.style.display = \"block\";\n }\n function clearFormError(): void {\n formError.textContent = \"\";\n formError.style.display = \"none\";\n }\n\n if (isTranslate) {\n const banner = document.createElement(\"div\");\n banner.style.cssText = `\n background: rgba(245,180,0,0.1);\n color: #f5b400;\n border: 1px solid rgba(245,180,0,0.25);\n border-radius: 8px;\n padding: 9px 11px;\n font-size: 12px;\n line-height: 1.4;\n margin-bottom: 12px;\n `;\n const src = opts.translateFromEntry!;\n banner.textContent = `Translating from ${src.locale} into ${opts.locale}. Fields are pre-filled from the source.`;\n body.appendChild(banner);\n }\n\n const fieldStates: FieldState[] = [];\n const sourceForInitial = opts.entry ?? opts.translateFromEntry ?? null;\n for (const f of opts.schema.fields) {\n const initial = sourceForInitial?.data[f.name];\n const { wrapper, fieldState } = renderField(f, initial);\n body.appendChild(wrapper);\n fieldStates.push(fieldState);\n }\n\n // ---- Slug auto-fill from a source field (plan 025) ----\n // For each slug field that declares a `source`, mirror slugify(source) into\n // the slug as the source is typed — but only while the slug is \"clean\" (never\n // hand-edited AND not already populated). Editing the slug by hand latches it\n // dirty and stops the auto-overwrite; an existing entry that already has a\n // slug starts dirty so its value is never clobbered.\n wireSlugAutoFill(opts.schema, fieldStates, sourceForInitial);\n\n // ---- Footer (fixed) ----\n const footer = document.createElement(\"div\");\n footer.style.cssText = `\n display: flex; align-items: center; justify-content: space-between;\n gap: 10px;\n padding: 12px 16px;\n border-top: 1px solid rgba(255,255,255,0.06);\n background: rgba(0,0,0,0.18);\n flex-shrink: 0;\n `;\n\n const leftActions = document.createElement(\"div\");\n const rightActions = document.createElement(\"div\");\n rightActions.style.cssText = `display: flex; gap: 8px;`;\n\n if (isEdit) {\n const deleteBtn = document.createElement(\"button\");\n deleteBtn.type = \"button\";\n deleteBtn.style.cssText = `\n appearance: none; cursor: pointer;\n background: transparent; border: 1px solid transparent;\n color: #ff8786;\n font-size: 12px; font-weight: 500;\n padding: 6px 10px; border-radius: 7px;\n transition: background 0.15s;\n `;\n deleteBtn.textContent = \"Delete\";\n deleteBtn.addEventListener(\"mouseenter\", () => { deleteBtn.style.background = \"rgba(255,135,134,0.08)\"; });\n deleteBtn.addEventListener(\"mouseleave\", () => { deleteBtn.style.background = \"transparent\"; });\n deleteBtn.addEventListener(\"click\", async () => {\n if (!confirm(`Delete the ${opts.locale} version of this ${opts.schema.labelSingular.toLowerCase()}? This can't be undone.`)) return;\n deleteBtn.disabled = true;\n try {\n await deleteListEntry(opts.schema.name, opts.entry!.id, opts.locale);\n opts.onSaved();\n closeEntryModal();\n } catch (err) {\n showFormError(err instanceof Error ? err.message : String(err));\n deleteBtn.disabled = false;\n }\n });\n leftActions.appendChild(deleteBtn);\n }\n\n const cancelBtn = document.createElement(\"button\");\n cancelBtn.type = \"button\";\n cancelBtn.style.cssText = `\n appearance: none; cursor: pointer;\n background: rgba(255,255,255,0.04);\n border: 1px solid rgba(255,255,255,0.07);\n color: rgba(255,255,255,0.75);\n font-size: 12px; font-weight: 500;\n padding: 7px 14px; border-radius: 8px;\n transition: background 0.15s, color 0.15s;\n `;\n cancelBtn.textContent = \"Cancel\";\n cancelBtn.addEventListener(\"mouseenter\", () => {\n cancelBtn.style.background = \"rgba(255,255,255,0.08)\";\n cancelBtn.style.color = \"rgba(255,255,255,0.9)\";\n });\n cancelBtn.addEventListener(\"mouseleave\", () => {\n cancelBtn.style.background = \"rgba(255,255,255,0.04)\";\n cancelBtn.style.color = \"rgba(255,255,255,0.75)\";\n });\n cancelBtn.addEventListener(\"click\", () => closeEntryModal());\n\n const saveBtn = makePrimaryButton(isEdit ? \"Save\" : \"Create\", accent());\n\n saveBtn.addEventListener(\"click\", async () => {\n clearFormError();\n const { data, ok } = preValidate(fieldStates);\n if (!ok) return;\n\n saveBtn.disabled = true;\n saveBtn.style.opacity = \"0.6\";\n const original = saveBtn.textContent;\n saveBtn.textContent = isEdit ? \"Saving…\" : \"Creating…\";\n\n try {\n if (isEdit) {\n await updateListEntry(opts.schema.name, opts.entry!.id, data, opts.entry!._rev, opts.locale);\n } else {\n let id: string | undefined;\n if (opts.fixedId) {\n id = opts.fixedId;\n } else {\n const slugFieldName = opts.schema.slugField;\n id = slugFieldName && typeof data[slugFieldName] === \"string\"\n ? (data[slugFieldName] as string)\n : undefined;\n }\n await createListEntry(opts.schema.name, data, opts.locale, id);\n }\n opts.onSaved();\n closeEntryModal();\n } catch (err) {\n const error = err as Error & { code?: string };\n if (error.message.includes(\"Validation failed\")) {\n showFormError(\"Server-side validation failed. Check the fields above.\");\n } else if (error.code === \"REV_CONFLICT\") {\n showFormError(\"This entry was changed by someone else. Close and reopen to see the latest version.\");\n } else {\n showFormError(error.message);\n }\n saveBtn.disabled = false;\n saveBtn.style.opacity = \"1\";\n saveBtn.textContent = original ?? (isEdit ? \"Save\" : \"Create\");\n }\n });\n\n rightActions.appendChild(cancelBtn);\n rightActions.appendChild(saveBtn);\n footer.appendChild(leftActions);\n footer.appendChild(rightActions);\n modal.appendChild(footer);\n\n // ---- Close handlers ----\n backdrop.addEventListener(\"click\", () => closeEntryModal());\n\n escListener = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n closeEntryModal();\n }\n };\n document.addEventListener(\"keydown\", escListener, true);\n\n // Focus the first input — small delay so the focus ring doesn't fight\n // the open animation.\n setTimeout(() => {\n const firstInput = body.querySelector<HTMLElement>(\"input, textarea, select\");\n firstInput?.focus();\n }, 90);\n}\n\nexport function closeEntryModal(): void {\n if (modalEl) {\n modalEl.style.animation = \"cancia-modal-out 0.16s cubic-bezier(0.7, 0, 0.84, 0) forwards\";\n const el = modalEl;\n setTimeout(() => el.remove(), 160);\n modalEl = null;\n }\n if (backdropEl) {\n const el = backdropEl;\n el.style.opacity = \"0\";\n setTimeout(() => el.remove(), 180);\n backdropEl = null;\n }\n if (escListener) {\n document.removeEventListener(\"keydown\", escListener, true);\n escListener = null;\n }\n}\n\nexport function isEntryModalOpen(): boolean {\n return modalEl !== null;\n}\n","// =============================================================================\n// Cancia Toolbar — Floating Bar\n// =============================================================================\n// Starts as a 44px circle, morphs into a pill on load/click.\n// =============================================================================\n\nimport { state, clearPending, revertPending } from \"./state\";\nimport { attachHighlight, detachHighlight } from \"./highlight\";\nimport { openPopup, closePopup } from \"./popup\";\nimport { openListPanel, closeListPanel, isListPanelOpen, refreshListPanel } from \"./list-panel\";\nimport { openEntryModal, closeEntryModal, isEntryModalOpen } from \"./entry-modal\";\nimport { flushPending, triggerPublish, isAuthError } from \"./api\";\nimport { onPendingChange } from \"./events\";\n\nlet toolbarEl: HTMLElement | null = null;\nlet pendingPanelEl: HTMLElement | null = null;\nlet isExpanded = false;\nlet expandedEscListener: ((e: KeyboardEvent) => void) | null = null;\n\nfunction accent() {\n return state.config?.accentColor ?? \"#6366f1\";\n}\n\n// ---------------------------------------------------------------------------\n// Inject keyframe animations\n// ---------------------------------------------------------------------------\n\nlet styleInjected = false;\nfunction injectStyles() {\n if (styleInjected) return;\n styleInjected = true;\n const s = document.createElement(\"style\");\n s.textContent = `\n @keyframes cancia-enter {\n from { opacity: 0; transform: scale(0.5) rotate(90deg); }\n to { opacity: 1; transform: scale(1) rotate(0deg); }\n }\n @keyframes cancia-exit {\n from { opacity: 1; transform: scale(1); }\n to { opacity: 0; transform: scale(0.8); }\n }\n @keyframes cancia-controls-in {\n from { opacity: 0; filter: blur(8px); transform: scale(0.6); }\n to { opacity: 1; filter: blur(0px); transform: scale(1); }\n }\n @keyframes cancia-controls-out {\n from { opacity: 1; filter: blur(0px); transform: scale(1); }\n to { opacity: 0; filter: blur(6px); transform: scale(0.5); }\n }\n @keyframes cancia-fade-in {\n from { opacity: 0; transform: scale(0.94) translateY(5px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n }\n @keyframes cancia-popup-in {\n from { opacity: 0; transform: scale(0.93); }\n to { opacity: 1; transform: scale(1); }\n }\n @keyframes cancia-badge-pop {\n 0% { transform: scale(0); }\n 60% { transform: scale(1.25); }\n 100% { transform: scale(1); }\n }\n @keyframes cancia-icon-slide-in {\n from { transform: translateY(-150%); }\n to { transform: translateY(0); }\n }\n @keyframes cancia-tooltip-in {\n from { opacity: 0; transform: translateX(-50%) translateY(4px); }\n to { opacity: 1; transform: translateX(-50%) translateY(0); }\n }\n [data-cancia-toolbar] * { box-sizing: border-box; }\n [data-cancia-toolbar] button:active:not(:disabled) { transform: scale(0.92) !important; }\n [data-cancia-popup] * { box-sizing: border-box; }\n [data-cancia-popup] button:active:not(:disabled) { transform: scale(0.94) !important; }\n /* Protect stroke-based icons from host page \"svg { fill: currentColor }\" rules */\n [data-cancia-toolbar] svg[fill=\"none\"] { fill: none !important; }\n [data-cancia-toolbar] svg[fill=\"none\"] :not([fill]) { fill: none !important; }\n [data-cancia-popup] svg[fill=\"none\"] { fill: none !important; }\n [data-cancia-popup] svg[fill=\"none\"] :not([fill]) { fill: none !important; }\n /* Reset cosmetic host CSS leaking into toolbar buttons */\n [data-cancia-toolbar] :where(button) {\n background: unset; border: unset; border-radius: unset; padding: unset;\n margin: unset; color: unset; font-family: unset; font-weight: unset;\n font-size: unset; line-height: unset; letter-spacing: unset;\n box-shadow: unset; outline: unset; text-transform: unset;\n }\n `;\n document.head.appendChild(s);\n}\n\n// ---------------------------------------------------------------------------\n// Shared tooltip element (reused across buttons)\n// ---------------------------------------------------------------------------\n\nlet btnTooltipEl: HTMLElement | null = null;\nlet tooltipHideTimer: ReturnType<typeof setTimeout> | null = null;\nlet tooltipShowTimer: ReturnType<typeof setTimeout> | null = null;\nlet tooltipVisible = false;\n\nfunction getOrCreateBtnTooltip(): HTMLElement {\n if (!btnTooltipEl) {\n btnTooltipEl = document.createElement(\"div\");\n btnTooltipEl.style.cssText = `\n position: fixed;\n pointer-events: none;\n z-index: 2147483646;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n font-size: 11px; font-weight: 500; letter-spacing: 0.02em;\n color: #fff;\n background: rgba(10,10,12,0.92);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n border: 1px solid rgba(255,255,255,0.1);\n padding: 4px 8px; border-radius: 6px;\n white-space: nowrap;\n box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n display: none;\n `;\n document.body.appendChild(btnTooltipEl);\n }\n return btnTooltipEl;\n}\n\nfunction showBtnTooltip(btn: HTMLElement, label: string) {\n if (tooltipHideTimer) { clearTimeout(tooltipHideTimer); tooltipHideTimer = null; }\n if (tooltipShowTimer) { clearTimeout(tooltipShowTimer); tooltipShowTimer = null; }\n\n const doShow = () => {\n tooltipVisible = true;\n const tooltip = getOrCreateBtnTooltip();\n tooltip.textContent = label;\n tooltip.style.display = \"block\";\n tooltip.style.animation = \"cancia-tooltip-in 0.12s cubic-bezier(0.16,1,0.3,1) both\";\n\n const rect = btn.getBoundingClientRect();\n const tooltipH = 26;\n const gap = 8;\n tooltip.style.top = `${rect.top - tooltipH - gap}px`;\n tooltip.style.left = `${rect.left + rect.width / 2}px`;\n };\n\n // Skip delay if tooltip is already visible (moving between buttons)\n if (tooltipVisible) {\n doShow();\n } else {\n tooltipShowTimer = setTimeout(doShow, 400);\n }\n}\n\nfunction hideBtnTooltip() {\n if (tooltipShowTimer) { clearTimeout(tooltipShowTimer); tooltipShowTimer = null; }\n if (tooltipHideTimer) clearTimeout(tooltipHideTimer);\n tooltipHideTimer = setTimeout(() => {\n tooltipVisible = false;\n if (btnTooltipEl) btnTooltipEl.style.display = \"none\";\n }, 80);\n}\n\n// ---------------------------------------------------------------------------\n// Build the toolbar DOM\n// ---------------------------------------------------------------------------\n\nfunction buildToolbar(): HTMLElement {\n injectStyles();\n\n // Single morphing container — collapses to 44px circle, expands to pill\n const bar = document.createElement(\"div\");\n bar.dataset.canciaToolbar = \"1\";\n bar.style.cssText = `\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 2147483647;\n width: 44px;\n height: 44px;\n border-radius: 22px;\n background: rgba(12, 12, 14, 0.92);\n backdrop-filter: blur(16px) saturate(180%);\n -webkit-backdrop-filter: blur(16px) saturate(180%);\n border: 1px solid rgba(255,255,255,0.08);\n box-shadow: 0 2px 8px rgba(0,0,0,0.3), 0 8px 32px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.05);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n font-size: 13px;\n color: #f0f0f0;\n user-select: none;\n cursor: pointer;\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: width 0.45s cubic-bezier(0.19, 1, 0.22, 1), border-radius 0.45s cubic-bezier(0.19, 1, 0.22, 1);\n animation: cancia-enter 0.5s cubic-bezier(0.34, 1.2, 0.64, 1) both;\n `;\n\n // Icon shown when collapsed\n const collapseIcon = document.createElement(\"div\");\n collapseIcon.style.cssText = `\n position: absolute;\n display: flex; align-items: center; justify-content: center;\n color: rgba(255,255,255,0.7);\n transition: opacity 0.15s, transform 0.15s cubic-bezier(0.2,0,0,1);\n pointer-events: none;\n `;\n // Pencil-line icon (Lucide style)\n collapseIcon.innerHTML = `<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12 20h9\"/>\n <path d=\"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z\"/>\n </svg>`;\n\n\n // Controls row (shown when expanded)\n const controls = document.createElement(\"div\");\n controls.style.cssText = `\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 5px;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n transform-origin: right center;\n `;\n\n // Edit toggle — pencil icon, tooltip \"Edit\" / \"Editing\"\n let editActive = false;\n const editBtn = makeIconButton(\n `<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\"/>\n <path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\"/>\n </svg>`,\n \"Edit\",\n () => toggleEditMode()\n );\n\n controls.appendChild(editBtn);\n\n // Publish — disabled if no publish method (deploy hook OR dispatch repo) is\n // configured. Default enabled so older integrations (that don't inject the\n // flag) don't regress.\n const canPublish = state.config?.canPublish ?? true;\n const publishBtn = makeIconButton(\n `<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 2L11 13\"/>\n <path d=\"M22 2L15 22l-4-9-9-4 20-7z\"/>\n </svg>`,\n canPublish ? \"Publish\" : \"Publish (no publish method configured)\",\n () => handlePublish(publishBtn)\n );\n if (!canPublish) {\n publishBtn.disabled = true;\n publishBtn.style.opacity = \"0.3\";\n publishBtn.style.cursor = \"not-allowed\";\n }\n controls.appendChild(publishBtn);\n\n // Log out — door/exit icon\n const logoutBtn = makeIconButton(\n `<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"/>\n <path d=\"M16 17l5-5-5-5\"/>\n <path d=\"M21 12H9\"/>\n </svg>`,\n \"Log out\",\n () => state.onLogout?.()\n );\n controls.appendChild(logoutBtn);\n controls.appendChild(makeDivider());\n\n // Collapse — X icon\n const collapseBtn = makeIconButton(\n `<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\">\n <path d=\"M6 6l12 12M18 6L6 18\"/>\n </svg>`,\n \"Close\",\n () => collapse(bar, collapseIcon, controls)\n );\n controls.appendChild(collapseBtn);\n\n bar.appendChild(collapseIcon);\n bar.appendChild(controls);\n\n // Click on the collapsed bar to expand\n bar.addEventListener(\"click\", () => {\n if (!isExpanded) expand(bar, collapseIcon, controls);\n });\n\n // Hover effect when collapsed\n bar.addEventListener(\"mouseenter\", () => {\n if (!isExpanded) bar.style.background = \"rgba(24, 24, 28, 0.96)\";\n });\n bar.addEventListener(\"mouseleave\", () => {\n bar.style.background = \"rgba(12, 12, 14, 0.92)\";\n });\n\n // Pending changes listener — show/hide floating panel above toolbar\n onPendingChange(() => {\n const count = state.pending.size;\n if (count > 0) {\n showPendingPanel(count);\n } else {\n hidePendingPanel();\n }\n });\n\n let editModeEscListener: ((e: KeyboardEvent) => void) | null = null;\n\n // Edit toggle implementation (closes over controls)\n function toggleEditMode() {\n editActive = !editActive;\n state.editMode = editActive;\n\n const svgEl = editBtn.querySelector(\"svg\");\n if (editActive) {\n editBtn.style.background = `${accent()}22`;\n editBtn.style.color = accent();\n if (svgEl) svgEl.style.stroke = accent();\n editBtn.dataset.canciaTooltip = \"Stop editing (Esc)\";\n attachHighlight((selection) => {\n if (selection.kind === \"field\") {\n openPopup(selection.key, selection.fieldType, selection.el, () => {});\n return;\n }\n // selection.kind === \"list\"\n const schema = state.schemas[selection.listName];\n if (!schema) {\n console.warn(`[cancia] No schema found for list \"${selection.listName}\". Define it in src/cms/schemas.ts.`);\n return;\n }\n openListPanel({\n schema,\n onAddEntry: (locale) => {\n openEntryModal({\n schema,\n locale,\n entry: null,\n onSaved: () => { refreshListPanel(); },\n });\n },\n onEditEntry: (entry, locale) => {\n openEntryModal({\n schema,\n locale,\n entry,\n onSaved: () => { refreshListPanel(); },\n });\n },\n onTranslateEntry: (id, sourceEntry, targetLocale) => {\n openEntryModal({\n schema,\n locale: targetLocale,\n entry: null,\n translateFromEntry: sourceEntry,\n fixedId: id,\n onSaved: () => { refreshListPanel(); },\n });\n },\n });\n });\n // Esc cascade: modal → panel → exit edit mode\n editModeEscListener = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n if (isEntryModalOpen()) {\n // The modal owns its own Esc handler (capture: true) so this branch\n // only runs once the modal is gone. Guard anyway for safety.\n return;\n }\n if (isListPanelOpen()) {\n closeListPanel();\n return;\n }\n if (!document.querySelector(\"[data-cancia-popup]\")) {\n toggleEditMode();\n }\n };\n document.addEventListener(\"keydown\", editModeEscListener, true);\n } else {\n editBtn.style.background = \"transparent\";\n editBtn.style.color = \"rgba(255,255,255,0.85)\";\n if (svgEl) svgEl.style.stroke = \"\";\n editBtn.dataset.canciaTooltip = \"Edit\";\n detachHighlight();\n closePopup();\n closeEntryModal();\n closeListPanel();\n if (editModeEscListener) {\n document.removeEventListener(\"keydown\", editModeEscListener, true);\n editModeEscListener = null;\n }\n }\n }\n\n return bar;\n}\n\n// ---------------------------------------------------------------------------\n// Expand / collapse\n// ---------------------------------------------------------------------------\n\nfunction expand(bar: HTMLElement, icon: HTMLElement, controls: HTMLElement) {\n if (isExpanded) return;\n isExpanded = true;\n\n // Esc collapses toolbar when expanded but not in edit mode\n expandedEscListener = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && !document.querySelector(\"[data-cancia-popup]\") && !state.editMode) {\n collapse(bar, icon, controls);\n }\n };\n document.addEventListener(\"keydown\", expandedEscListener, true);\n\n // Measure natural content width, then animate to it\n controls.style.visibility = \"hidden\";\n controls.style.opacity = \"0\";\n controls.style.pointerEvents = \"none\";\n bar.style.width = \"max-content\";\n bar.style.borderRadius = \"100px\";\n\n requestAnimationFrame(() => {\n const naturalW = bar.scrollWidth;\n bar.style.width = \"44px\"; // reset for transition start\n controls.style.visibility = \"\";\n\n requestAnimationFrame(() => {\n bar.style.width = `${naturalW}px`;\n bar.style.borderRadius = \"100px\";\n bar.style.cursor = \"default\";\n icon.style.opacity = \"0\";\n icon.style.transform = \"scale(0.5) rotate(-90deg)\";\n\n setTimeout(() => {\n controls.style.pointerEvents = \"auto\";\n controls.style.animation = \"cancia-controls-in 0.4s cubic-bezier(0.19, 1, 0.22, 1) both\";\n controls.style.opacity = \"1\";\n }, 80);\n });\n });\n}\n\nfunction collapse(bar: HTMLElement, icon: HTMLElement, controls: HTMLElement) {\n if (!isExpanded) return;\n isExpanded = false;\n hideBtnTooltip();\n\n if (expandedEscListener) {\n document.removeEventListener(\"keydown\", expandedEscListener, true);\n expandedEscListener = null;\n }\n\n controls.style.pointerEvents = \"none\";\n controls.style.animation = \"cancia-controls-out 0.15s cubic-bezier(0.4, 0, 1, 1) both\";\n\n setTimeout(() => {\n controls.style.opacity = \"0\";\n bar.style.width = \"44px\";\n bar.style.borderRadius = \"22px\";\n bar.style.cursor = \"pointer\";\n icon.style.opacity = \"1\";\n icon.style.transform = \"scale(1) rotate(0deg)\";\n }, 100);\n}\n\n// ---------------------------------------------------------------------------\n// Save handler\n// ---------------------------------------------------------------------------\n\nasync function handleSave(btn?: HTMLButtonElement) {\n if (btn) { btn.disabled = true; btn.style.opacity = \"0.5\"; }\n\n try {\n await flushPending();\n flashPanelMessage(\"Saved\", \"success\");\n } catch (err) {\n console.error(err);\n if (isAuthError(err)) { unmountToolbar(); return; }\n if (btn) { btn.disabled = false; btn.style.opacity = \"1\"; }\n flashPanelMessage(\"Save failed\", \"error\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Publish handler\n// ---------------------------------------------------------------------------\n\nasync function handlePublish(btn: HTMLButtonElement) {\n btn.disabled = true;\n btn.style.opacity = \"0.5\";\n\n try {\n if (state.pending.size > 0) await flushPending();\n await triggerPublish();\n showToast(\"Published!\", \"success\");\n } catch (err) {\n console.error(err);\n showToast(\"Publish failed\", \"error\");\n } finally {\n btn.disabled = false;\n btn.style.opacity = \"1\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Toast\n// ---------------------------------------------------------------------------\n\nfunction showToast(message: string, type: \"success\" | \"error\") {\n const toast = document.createElement(\"div\");\n const color = type === \"success\" ? \"#4ade80\" : \"#f87171\";\n toast.style.cssText = `\n position: fixed; bottom: 80px; right: 24px; z-index: 2147483647;\n display: flex; align-items: center; gap: 8px;\n background: rgba(12, 12, 14, 0.95);\n backdrop-filter: blur(16px);\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 10px; padding: 10px 14px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n font-size: 13px; font-weight: 500; color: #f0f0f0;\n box-shadow: 0 4px 24px rgba(0,0,0,0.4);\n pointer-events: none;\n animation: cancia-fade-in 0.3s cubic-bezier(0.16, 1, 0.3, 1) both;\n `;\n const dot = document.createElement(\"span\");\n dot.style.cssText = `width: 7px; height: 7px; border-radius: 50%; background: ${color}; flex-shrink: 0;`;\n const label = document.createElement(\"span\");\n label.textContent = message;\n toast.appendChild(dot);\n toast.appendChild(label);\n document.body.appendChild(toast);\n\n setTimeout(() => {\n toast.style.transition = \"opacity 0.25s cubic-bezier(0.4,0,1,1), transform 0.25s cubic-bezier(0.4,0,1,1)\";\n toast.style.opacity = \"0\";\n toast.style.transform = \"translateY(4px)\";\n setTimeout(() => toast.remove(), 300);\n }, 2000);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction makeIconButton(\n svg: string,\n title: string,\n onClick: () => void,\n): HTMLButtonElement {\n const btn = document.createElement(\"button\");\n btn.style.cssText = `\n display: flex; align-items: center; justify-content: center;\n width: 34px; height: 34px; border-radius: 50%;\n border: none; background: transparent;\n cursor: pointer; color: rgba(255,255,255,0.85); flex-shrink: 0; padding: 0;\n transition: color 0.15s, background 0.15s, transform 0.1s cubic-bezier(0.2,0,0,1);\n `;\n btn.innerHTML = svg;\n // Force consistent stroke-width on all child SVGs to prevent host CSS override\n const svgEl = btn.querySelector(\"svg\");\n if (svgEl) {\n svgEl.style.cssText = \"display:block;flex-shrink:0;overflow:visible;margin:auto;\";\n svgEl.setAttribute(\"stroke-width\", \"1.5\");\n }\n btn.dataset.canciaTooltip = title;\n btn.addEventListener(\"mouseenter\", () => {\n if (!btn.disabled) {\n btn.style.background = \"rgba(255,255,255,0.1)\";\n showBtnTooltip(btn, btn.dataset.canciaTooltip ?? title);\n }\n });\n btn.addEventListener(\"mouseleave\", () => {\n // Only reset bg if not in active state (active state managed externally)\n const activeColor = state.config?.accentColor ?? \"#6366f1\";\n if (!btn.style.background.includes(activeColor.slice(1, 7))) {\n btn.style.background = \"transparent\";\n }\n hideBtnTooltip();\n });\n btn.addEventListener(\"click\", (e) => { e.stopPropagation(); hideBtnTooltip(); onClick(); });\n return btn;\n}\n\nfunction makeDivider(): HTMLElement {\n const d = document.createElement(\"span\");\n d.style.cssText = `width: 1px; height: 14px; background: rgba(255,255,255,0.08); flex-shrink: 0; margin: 0 1px;`;\n return d;\n}\n\n// ---------------------------------------------------------------------------\n// Pending panel — floats above the toolbar\n// ---------------------------------------------------------------------------\n\nfunction showPendingPanel(count: number) {\n if (!pendingPanelEl) {\n pendingPanelEl = document.createElement(\"div\");\n pendingPanelEl.style.cssText = `\n position: fixed;\n bottom: 80px;\n right: 24px;\n z-index: 2147483646;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n background: rgba(12, 12, 14, 0.92);\n backdrop-filter: blur(16px) saturate(180%);\n -webkit-backdrop-filter: blur(16px) saturate(180%);\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 12px;\n padding: 0;\n box-shadow: 0 2px 8px rgba(0,0,0,0.3), 0 8px 32px rgba(0,0,0,0.4);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n animation: cancia-fade-in 0.25s cubic-bezier(0.16,1,0.3,1) both;\n width: max-content;\n overflow: hidden;\n `;\n\n const label = document.createElement(\"span\");\n label.dataset.canciaPendingLabel = \"1\";\n label.style.cssText = `font-size: 12px; font-weight: 500; color: rgba(255,255,255,0.5); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;`;\n\n const saveBtn = document.createElement(\"button\");\n saveBtn.dataset.canciaSaveBtn = \"1\";\n saveBtn.title = \"Save changes\";\n saveBtn.style.cssText = `\n padding: 5px 10px; border-radius: 7px; border: none; cursor: pointer;\n background: #fff; color: #0c0c0e;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n font-size: 12px; font-weight: 600; letter-spacing: 0.01em;\n transition: opacity 0.15s, transform 0.1s cubic-bezier(0.2,0,0,1);\n flex-shrink: 0;\n `;\n saveBtn.textContent = \"Save\";\n saveBtn.addEventListener(\"mouseenter\", () => { saveBtn.style.opacity = \"0.85\"; });\n saveBtn.addEventListener(\"mouseleave\", () => { saveBtn.style.opacity = \"1\"; });\n saveBtn.addEventListener(\"click\", (e) => { e.stopPropagation(); handleSave(saveBtn); });\n\n const undoBtn = document.createElement(\"button\");\n undoBtn.title = \"Discard changes\";\n undoBtn.style.cssText = `\n padding: 5px 10px; border-radius: 7px; border: 1px solid rgba(255,255,255,0.1); cursor: pointer;\n background: transparent; color: rgba(255,255,255,0.5);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n font-size: 12px; font-weight: 500; letter-spacing: 0.01em;\n transition: color 0.15s, border-color 0.15s;\n flex-shrink: 0;\n `;\n undoBtn.textContent = \"Discard\";\n undoBtn.addEventListener(\"mouseenter\", () => { undoBtn.style.color = \"rgba(255,255,255,0.8)\"; undoBtn.style.borderColor = \"rgba(255,255,255,0.2)\"; });\n undoBtn.addEventListener(\"mouseleave\", () => { undoBtn.style.color = \"rgba(255,255,255,0.5)\"; undoBtn.style.borderColor = \"rgba(255,255,255,0.1)\"; });\n undoBtn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n revertPending();\n closePopup();\n hidePendingPanel();\n });\n\n // Inner slot: stacks current content + flash message via grid\n const slot = document.createElement(\"div\");\n slot.dataset.canciaPanelSlot = \"1\";\n slot.style.cssText = `display:grid;place-items:center;overflow:hidden;`;\n\n // Default row: label + undo + save button\n const row = document.createElement(\"div\");\n row.dataset.canciaPanelRow = \"1\";\n row.style.cssText = `\n grid-area: 1/1; display: flex; align-items: center; gap: 6px;\n padding: 7px 7px 7px 12px;\n transition: transform 200ms cubic-bezier(0.785,0.135,0.15,0.86);\n `;\n row.appendChild(label);\n row.appendChild(undoBtn);\n row.appendChild(saveBtn);\n\n // Flash row: success/error message (hidden above initially)\n const flash = document.createElement(\"div\");\n flash.dataset.canciaPanelFlash = \"1\";\n flash.style.cssText = `\n grid-area: 1/1; display: flex; align-items: center; gap: 7px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n font-size: 12px; font-weight: 500; color: rgba(255,255,255,0.8); white-space: nowrap;\n padding: 7px 12px;\n transform: translateY(-150%);\n transition: transform 200ms cubic-bezier(0.785,0.135,0.15,0.86);\n `;\n\n slot.appendChild(row);\n slot.appendChild(flash);\n pendingPanelEl.appendChild(slot);\n document.body.appendChild(pendingPanelEl);\n }\n\n const label = pendingPanelEl.querySelector<HTMLElement>(\"[data-cancia-pending-label]\");\n if (label) label.textContent = `${count} unsaved change${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction flashPanelMessage(message: string, type: \"success\" | \"error\") {\n if (!pendingPanelEl) return;\n const color = type === \"success\" ? \"#4ade80\" : \"#f87171\";\n\n const row = pendingPanelEl.querySelector<HTMLElement>(\"[data-cancia-panel-row]\");\n const flash = pendingPanelEl.querySelector<HTMLElement>(\"[data-cancia-panel-flash]\");\n if (!row || !flash) return;\n\n // Build flash content\n flash.innerHTML = `<span style=\"width:7px;height:7px;border-radius:50%;background:${color};flex-shrink:0;display:block;\"></span>${message}`;\n\n // Slide current content down, flash content in from above\n row.style.transform = \"translateY(150%)\";\n flash.style.transform = \"translateY(0)\";\n\n setTimeout(() => hidePendingPanel(), 1600);\n}\n\nfunction hidePendingPanel() {\n if (!pendingPanelEl) return;\n const panel = pendingPanelEl;\n pendingPanelEl = null;\n panel.style.transition = \"opacity 0.2s cubic-bezier(0.4,0,1,1), transform 0.2s cubic-bezier(0.4,0,1,1)\";\n panel.style.opacity = \"0\";\n panel.style.transform = \"translateY(4px)\";\n setTimeout(() => panel.remove(), 220);\n}\n\n// ---------------------------------------------------------------------------\n// Mount / unmount\n// ---------------------------------------------------------------------------\n\nexport function mountToolbar() {\n if (toolbarEl) return;\n isExpanded = false;\n toolbarEl = buildToolbar();\n document.body.appendChild(toolbarEl);\n}\n\nexport function unmountToolbar() {\n detachHighlight();\n closePopup();\n isExpanded = false;\n // Clean up shared tooltip\n btnTooltipEl?.remove();\n btnTooltipEl = null;\n // Clean up pending panel\n pendingPanelEl?.remove();\n pendingPanelEl = null;\n if (toolbarEl) {\n toolbarEl.style.animation = \"cancia-exit 0.25s cubic-bezier(0.4, 0, 1, 1) both\";\n setTimeout(() => {\n toolbarEl?.remove();\n toolbarEl = null;\n }, 260);\n }\n}\n","// =============================================================================\n// Cancia Toolbar — Entry Point\n// =============================================================================\n\nimport type { CanciaConfig } from \"./types\";\nimport { state, applyOverlay } from \"./state\";\nimport { fetchContent, fetchSchemas } from \"./api\";\nimport { mountToolbar, unmountToolbar } from \"./toolbar\";\nimport { onPendingChange } from \"./events\";\n\nexport type { CanciaConfig } from \"./types\";\nexport type { CMSData, CMSEntry, PendingChange } from \"./types\";\n\nconst SESSION_KEY = \"cancia_session\";\n\n// ---------------------------------------------------------------------------\n// Session helpers — token lives in sessionStorage only\n// ---------------------------------------------------------------------------\n\nfunction getSessionToken(): string | null {\n try {\n return sessionStorage.getItem(SESSION_KEY);\n } catch {\n return null;\n }\n}\n\nfunction setSessionToken(token: string): void {\n try {\n sessionStorage.setItem(SESSION_KEY, token);\n } catch {}\n}\n\nexport function clearSession(): void {\n try {\n sessionStorage.removeItem(SESSION_KEY);\n } catch {}\n}\n\n// ---------------------------------------------------------------------------\n// Magic URL: ?cancia=<token>\n// Validates against the API, stores in sessionStorage, strips from URL.\n// ---------------------------------------------------------------------------\n\nasync function handleMagicUrl(): Promise<string | null> {\n const params = new URLSearchParams(window.location.search);\n const token = params.get(\"cancia\");\n if (!token) return null;\n\n // Strip ?cancia=... from the URL immediately (before any validation)\n params.delete(\"cancia\");\n const newSearch = params.toString();\n const cleanUrl = window.location.pathname + (newSearch ? `?${newSearch}` : \"\") + window.location.hash;\n window.history.replaceState(null, \"\", cleanUrl);\n\n // Validate with the server\n try {\n const res = await fetch(\"/api/cancia/auth\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token }),\n });\n if (res.ok) {\n setSessionToken(token);\n return token;\n }\n } catch {}\n\n console.warn(\"Cancia: magic link token is invalid or expired.\");\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// init()\n// ---------------------------------------------------------------------------\n\nexport async function init(config: CanciaConfig): Promise<void> {\n state.config = config;\n state.activeLang = config.languages[0];\n\n // Preload CMS overrides from window if available (injected at build time)\n if (window.__CANCIA_DATA__) {\n state.cmsData = window.__CANCIA_DATA__;\n }\n\n try {\n const fresh = await fetchContent();\n state.cmsData = fresh;\n } catch (err: unknown) {\n if (!config.public && err instanceof Error && err.message.includes(\"401\")) {\n clearSession();\n console.warn(\"Cancia: session expired or invalid, toolbar not mounted.\");\n return;\n }\n console.warn(\"Cancia: could not fetch CMS content, using preloaded data.\");\n }\n\n // Overlay saved drafts onto the (prerendered) page so editors see their\n // unpublished changes. Uses whatever cmsData ended up loaded above — fresh\n // fetch, or the window.__CANCIA_DATA__ preload if the fetch failed.\n applyOverlay();\n\n // Schemas are best-effort: a v1 install with no schemas.ts returns {}.\n // Lists with no schema are simply unclickable from the toolbar.\n try {\n state.schemas = await fetchSchemas();\n } catch {\n state.schemas = {};\n }\n\n mountToolbar();\n}\n\n// ---------------------------------------------------------------------------\n// Auto-init from window.__CANCIA__\n// Checks magic URL first, then falls back to existing sessionStorage session.\n// Does nothing if no valid session exists — toolbar stays hidden from visitors.\n// ---------------------------------------------------------------------------\n\nasync function tryAutoInit() {\n if (!window.__CANCIA__) return;\n\n // Public mode — skip auth, always show toolbar (demo sites only)\n if (window.__CANCIA__.public) {\n init(window.__CANCIA__);\n return;\n }\n\n // Check magic URL first, then existing session\n const token = (await handleMagicUrl()) ?? getSessionToken();\n if (!token) return; // No session — normal visitor, nothing to do\n\n // Attach the session token to state so API calls can use it\n state.sessionToken = token;\n\n // Wire up logout handler — called by the toolbar button\n state.onLogout = () => {\n clearSession();\n unmountToolbar();\n };\n\n init(window.__CANCIA__);\n}\n\nif (typeof document !== \"undefined\") {\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", tryAutoInit);\n } else {\n tryAutoInit();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Re-exports for programmatic use\n// ---------------------------------------------------------------------------\n\nexport { unmountToolbar as destroy } from \"./toolbar\";\nexport { getValue } from \"./state\";\nexport { onPendingChange };\n"],"mappings":"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","names":["accent","renderTabs","fieldType","styleInjected","injectStyles","accent","BACKDROP_Z","backdropEl","styleInjected","injectStyles","accent","getValue","accent","injectStyles","BACKDROP_Z","backdropEl","accent","styleInjected","injectStyles","label"]}
|
|
1
|
+
{"version":3,"sources":["../src/richtext.ts","../src/state.ts","../src/api.ts","../src/tokens.ts","../src/styles.ts","../src/highlight.ts","../src/events.ts","../src/popup.ts","../src/list-panel.ts","../src/entry-modal.ts","../src/toolbar.ts","../src/index.ts"],"sourcesContent":["// =============================================================================\n// Cancia Toolbar — Rich text on the INLINE surface\n// =============================================================================\n// The pure half of rich-text handling: parsing a stored value, rendering a\n// Portable-Text document to DOM, and serialising back. No popup, no modal, no\n// styling — so both surfaces can share it and it can be tested without a\n// browser.\n//\n// The block-row EDITOR still lives in entry-modal.ts. Extracting it needs the\n// modal's private styling helpers (INPUT_BASE, SELECT_CHEVRON, group/button)\n// moved out with it, which is plan 048/049's job; a second copy of the pure\n// logic here would be the thing worth avoiding, and this file prevents that.\n// =============================================================================\n\nimport { PT_STYLES, portableTextSubsetSchema } from \"@cancia/astro/richtext\";\nimport type { PtBlock, PtSpan } from \"@cancia/astro/richtext\";\n\n/**\n * Parse a stored rich value.\n *\n * Mirrors parseRichValue (@cancia/astro) — the toolbar cannot import the Node\n * side of that module, and this must agree with what the server renders or the\n * editor shows something the page does not.\n *\n * undefined → null (no override: the page is showing its authored markup)\n * \"\" → [] (deliberately empty)\n * JSON → blocks, or [] when malformed / off-subset\n */\nexport function parseRichValue(raw: string | undefined): PtBlock[] | null {\n if (raw === undefined) return null;\n const trimmed = raw.trim();\n if (trimmed === \"\") return [];\n if (!trimmed.startsWith(\"[\")) {\n // A legacy plain string (a field promoted from `text`) becomes one block.\n return [\n {\n _type: \"block\",\n _key: \"legacy\",\n style: \"normal\",\n markDefs: [],\n children: [{ _type: \"span\", _key: \"legacy0\", text: raw, marks: [] }],\n } as PtBlock,\n ];\n }\n try {\n const parsed = portableTextSubsetSchema.safeParse(JSON.parse(trimmed));\n return parsed.success ? parsed.data : [];\n } catch {\n return [];\n }\n}\n\nexport function serializeRichValue(blocks: PtBlock[]): string {\n return blocks.length === 0 ? \"\" : JSON.stringify(blocks);\n}\n\n/** The tag each block style renders as — must match <CanciaRichText>'s output. */\nconst STYLE_TAG: Record<string, string> = {\n normal: \"p\",\n h2: \"h2\",\n h3: \"h3\",\n blockquote: \"blockquote\",\n};\n\n/**\n * Render a PT document into `target`, replacing its children.\n *\n * This is the LIVE PREVIEW and the draft overlay. It has to produce the same\n * shape astro-portabletext produces server-side, or the client sees one thing\n * while editing and another after publish.\n *\n * Everything is built with createElement + textContent — no innerHTML anywhere.\n * The stored value is validated against the subset, but \"validated\" is not\n * \"trusted with HTML parsing\", and the no-raw-HTML rule (D4) is the reason the\n * subset exists at all.\n */\nexport function renderRichToDom(target: HTMLElement, blocks: PtBlock[]): void {\n target.replaceChildren();\n\n let listWrap: HTMLElement | null = null;\n let listKind: string | null = null;\n\n for (const block of blocks) {\n if (block.listItem) {\n const wantTag = block.listItem === \"number\" ? \"ol\" : \"ul\";\n if (!listWrap || listKind !== block.listItem) {\n listWrap = document.createElement(wantTag);\n listKind = block.listItem;\n target.appendChild(listWrap);\n }\n const li = document.createElement(\"li\");\n appendSpans(li, block);\n listWrap.appendChild(li);\n continue;\n }\n\n // A non-list block closes any run of list items before it.\n listWrap = null;\n listKind = null;\n\n const el = document.createElement(STYLE_TAG[block.style] ?? \"p\");\n appendSpans(el, block);\n target.appendChild(el);\n }\n}\n\n/** Append a block's spans, applying decorators and link annotations. */\nfunction appendSpans(parent: HTMLElement, block: PtBlock): void {\n const markDefs = new Map(\n (block.markDefs ?? []).map((d) => [d._key, d] as const),\n );\n\n for (const span of block.children as PtSpan[]) {\n let node: HTMLElement | Text = document.createTextNode(span.text);\n\n // Marks apply innermost-first; a link wraps whatever the decorators made.\n for (const mark of span.marks ?? []) {\n if (mark === \"strong\" || mark === \"em\") {\n const wrap = document.createElement(mark === \"strong\" ? \"strong\" : \"em\");\n wrap.appendChild(node);\n node = wrap;\n continue;\n }\n const def = markDefs.get(mark);\n if (def) {\n const a = document.createElement(\"a\");\n // The href already passed isSafeHref on the way in (schema refine) and\n // again on read; setAttribute keeps it out of any HTML parse.\n a.setAttribute(\"href\", def.href);\n a.appendChild(node);\n node = a;\n }\n // An unresolved mark is dropped: the schema forbids it, and rendering\n // raw \"L1\" text would be worse than losing the emphasis.\n }\n\n parent.appendChild(node);\n }\n}\n\n/** Is this a style the subset permits? Used when validating an edited doc. */\nexport function isKnownStyle(style: string): boolean {\n return (PT_STYLES as readonly string[]).includes(style);\n}\n\n// ---------------------------------------------------------------------------\n// Reading the AUTHORED markup back out of the page\n// ---------------------------------------------------------------------------\n\nconst STYLE_OF_TAG: Record<string, string> = {\n P: \"normal\",\n H2: \"h2\",\n H3: \"h3\",\n BLOCKQUOTE: \"blockquote\",\n};\n\n/**\n * Turn the region's own DOM into editable rows.\n *\n * This is what a client sees the FIRST time they edit a region, because a\n * region with no override is rendering the markup authored in the .astro file.\n * Seeding from `textContent` instead — which is what this replaced — flattened\n * two paragraphs into one and dropped every bold, italic and link on the floor,\n * so the client's first save silently destroyed formatting the page was\n * displaying a second earlier. Exactly the failure the whole rich-text feature\n * exists to prevent.\n *\n * Emits the same markdown shorthand the editor authors in (**bold**, *italic*,\n * [label](href)), so a round-trip through rowsToPortableText is lossless.\n */\nexport function domToRows(region: HTMLElement): { text: string; style: string; listItem?: string }[] {\n const rows: { text: string; style: string; listItem?: string }[] = [];\n\n const pushBlock = (el: Element, style: string, listItem?: string) => {\n const text = inlineToShorthand(el);\n if (text.trim() === \"\") return;\n rows.push(listItem ? { text, style, listItem } : { text, style });\n };\n\n for (const child of region.children) {\n const tag = child.tagName;\n\n if (tag === \"UL\" || tag === \"OL\") {\n const kind = tag === \"OL\" ? \"number\" : \"bullet\";\n for (const li of child.children) {\n if (li.tagName === \"LI\") pushBlock(li, \"normal\", kind);\n }\n continue;\n }\n\n // astro-portabletext wraps its output in .cancia-richtext, so an already\n // overridden region nests one level deeper than an authored one.\n if (child.classList.contains(\"cancia-richtext\")) {\n rows.push(...domToRows(child as HTMLElement));\n continue;\n }\n\n pushBlock(child, STYLE_OF_TAG[tag] ?? \"normal\");\n }\n\n // A region whose children are bare text (no block elements at all) is still\n // one paragraph, not nothing.\n if (rows.length === 0) {\n const text = inlineToShorthand(region);\n if (text.trim() !== \"\") rows.push({ text, style: \"normal\" });\n }\n\n return rows;\n}\n\n/** Serialise inline markup to the editor's markdown shorthand. */\nfunction inlineToShorthand(el: Element): string {\n let out = \"\";\n\n for (const node of el.childNodes) {\n if (node.nodeType === Node.TEXT_NODE) {\n // Collapse source-formatting whitespace, exactly as the renderer does —\n // otherwise the .astro file's indentation becomes part of the value.\n out += (node.textContent ?? \"\").replace(/\\s+/g, \" \");\n continue;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) continue;\n\n const child = node as Element;\n const inner = inlineToShorthand(child);\n\n switch (child.tagName) {\n case \"STRONG\":\n case \"B\":\n out += `**${inner}**`;\n break;\n case \"EM\":\n case \"I\":\n out += `*${inner}*`;\n break;\n case \"A\": {\n const href = child.getAttribute(\"href\") ?? \"\";\n out += href ? `[${inner}](${href})` : inner;\n break;\n }\n default:\n // Anything outside the subset contributes its text and loses its tag —\n // the annotator refuses to make such regions editable in the first\n // place, so this is a fallback, not the normal path.\n out += inner;\n }\n }\n\n return out;\n}\n","// =============================================================================\n// Cancia Toolbar — Shared State\n// =============================================================================\n\nimport type { CanciaConfig, CMSData, PendingChange } from \"./types\";\nimport type { ListSchemaDescription } from \"./api\";\nimport { parseRichValue, renderRichToDom } from \"./richtext\";\n\nexport const state = {\n config: null as CanciaConfig | null,\n cmsData: {} as CMSData,\n pending: new Map<string, PendingChange>(),\n activeLang: \"\",\n editMode: false,\n /** Auth token from sessionStorage — set by toolbar/index.ts after session validation */\n sessionToken: \"\" as string,\n /** Called by toolbar logout button — wired up by index.ts to avoid circular deps */\n onLogout: null as (() => void) | null,\n /** List schemas, keyed by name. Loaded once on toolbar init. */\n schemas: {} as Record<string, ListSchemaDescription>,\n /** Currently-selected locale for list-panel + modal. Defaults to activeLang on open. */\n activeListLocale: \"\" as string,\n};\n\nexport function pendingKey(key: string, lang: string) {\n return `${key}.${lang}`;\n}\n\nexport function getValue(key: string, lang: string): string {\n const full = `${key}.${lang}`;\n // Pending changes win\n const p = state.pending.get(full);\n if (p) return p.value;\n // Then CMS overrides\n if (state.cmsData[full] !== undefined) return state.cmsData[full];\n return \"\";\n}\n\nexport function setPending(key: string, lang: string, value: string) {\n const full = pendingKey(key, lang);\n state.pending.set(full, { key, lang, value });\n}\n\nexport function clearPending() {\n state.pending.clear();\n}\n\n/**\n * Overlay saved (draft) CMS values onto the prerendered page.\n *\n * On a `static` build the page HTML is baked at build time, so an editor's\n * saved-but-unpublished changes (which live in `state.cmsData`) never show up\n * on reload. This walks every `[data-cms]` element and, when there is a saved\n * value for the active language, applies it client-side — so editors see their\n * drafts while normal visitors (no session, no toolbar) keep the baked build.\n *\n * Only runs from `init`, which is gated behind a valid session or `public`\n * mode, so it never affects normal visitors.\n */\n/**\n * Read a stored link value for overlay. Mirrors parseLinkValue in\n * @cancia/astro/schema — the toolbar is a standalone browser bundle and does\n * not import the astro package, so the shape contract is duplicated here on\n * purpose. Never throws; an unparseable value degrades to a bare label.\n */\nfunction parseLinkOverlay(raw: string): { label: string; href: string } {\n if (!raw) return { label: \"\", href: \"\" };\n const trimmed = raw.trim();\n if (trimmed.startsWith(\"{\")) {\n try {\n const p = JSON.parse(trimmed) as { label?: string; href?: string };\n if (p && typeof p === \"object\") {\n return { label: String(p.label ?? \"\"), href: String(p.href ?? \"\") };\n }\n } catch {\n // fall through\n }\n }\n return { label: raw, href: \"\" };\n}\n\nexport function applyOverlay() {\n document.querySelectorAll<HTMLElement>(\"[data-cms]\").forEach((el) => {\n // Skip list-region containers — they mark list areas, not text nodes.\n if (el.dataset.cmsList !== undefined) return;\n\n const key = el.dataset.cms;\n if (!key) return;\n\n const savedValue = state.cmsData[`${key}.${state.activeLang}`];\n // No saved override → leave the baked value in place.\n if (savedValue === undefined) return;\n\n if (el.tagName === \"IMG\") {\n (el as HTMLImageElement).src = savedValue;\n return;\n }\n\n // A rich region holds a DOCUMENT, and its children ARE the value — so the\n // childElementCount guard below (which exists to stop textContent\n // destroying markup) is exactly backwards here. Replace the subtree with\n // the rendered document instead.\n //\n // Gated on the explicit data-cms-type, matching fieldType() in\n // highlight.ts: opt-in only, so an ordinary text field that happens to sit\n // on an element with children keeps its safe refusal.\n if (el.dataset.cmsType === \"richtext\") {\n const blocks = parseRichValue(savedValue);\n // null cannot occur here (savedValue is defined), but [] can: a\n // deliberately-empty region renders nothing rather than falling back to\n // the authored markup, which would resurrect prose the client deleted.\n if (blocks) renderRichToDom(el, blocks);\n return;\n }\n\n // A link stores JSON ({label, href}) — without this branch the raw JSON\n // string would be written onto the page as visible text. Gated on the\n // EXPLICIT data-cms-type (matching fieldType in highlight.ts): a plain\n // text field is allowed to live on an <a> (footer email, nav item) and\n // must keep behaving like text.\n if (el.dataset.cmsType === \"link\") {\n const link = parseLinkOverlay(savedValue);\n if (link.href && el.tagName === \"A\") el.setAttribute(\"href\", link.href);\n // A button usually holds an icon next to its text (<a>Book<svg/></a>), so\n // writing textContent would delete the icon. `[data-cms-label]` marks the\n // text node to replace; without it we only touch a childless element.\n // ALL marked nodes update, not just the first: a responsive button often\n // carries two labels that swap by breakpoint (one `hidden sm:inline`,\n // one `sm:hidden`), and updating only one leaves the other stale.\n const labelEls = el.querySelectorAll<HTMLElement>(\"[data-cms-label]\");\n if (labelEls.length > 0) labelEls.forEach((n) => (n.textContent = link.label));\n else if (el.childElementCount === 0) el.textContent = link.label;\n return;\n }\n\n // Safety: setting textContent on an element with child ELEMENT nodes would\n // destroy them. Only overlay elements whose children are all text/comments.\n if (el.childElementCount > 0) {\n console.warn(\n `Cancia: skipping overlay for \"${key}\" — element has child elements ` +\n `(textContent would destroy them).`\n );\n return;\n }\n\n el.textContent = savedValue;\n });\n}\n\n/** Revert all pending changes — restores DOM elements to their last saved CMS value */\nexport function revertPending() {\n for (const [fullKey, { key }] of state.pending) {\n const savedValue = state.cmsData[fullKey] ?? \"\";\n // Update any matching data-cms elements in the DOM\n document.querySelectorAll<HTMLElement>(`[data-cms=\"${key}\"]`).forEach((el) => {\n if (el.tagName === \"IMG\") {\n (el as HTMLImageElement).src = savedValue;\n return;\n }\n // A rich region stores a JSON document. Writing that JSON as textContent\n // would print it on the page AND flatten every paragraph in the region —\n // discarding a client's work on a Discard they meant to be harmless.\n if (el.dataset.cmsType === \"richtext\") {\n const blocks = parseRichValue(savedValue);\n if (blocks) renderRichToDom(el, blocks);\n return;\n }\n el.textContent = savedValue;\n });\n }\n state.pending.clear();\n}\n","// =============================================================================\n// Cancia Toolbar — API Client\n// =============================================================================\n\nimport { state } from \"./state\";\nimport type { CMSData } from \"./types\";\n\nfunction headers(): HeadersInit {\n const h: HeadersInit = { \"Content-Type\": \"application/json\" };\n if (state.sessionToken) h[\"Authorization\"] = `Bearer ${state.sessionToken}`;\n return h;\n}\n\n/**\n * The current page's route (034). The client is the source of truth for \"which\n * page am I editing\" — the server uses it to invalidate the right cache tag in\n * `invalidate` publish mode. Empty string when not in a browser (SSR/tests).\n */\nfunction currentRoute(): string {\n return typeof location !== \"undefined\" ? location.pathname : \"\";\n}\n\n/** Append `&route=<pathname>` to a lists URL so the server can invalidate it. */\nfunction routeParam(): string {\n const r = currentRoute();\n return r ? `&route=${encodeURIComponent(r)}` : \"\";\n}\n\nexport async function fetchContent(): Promise<CMSData> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(`${apiUrl}/api/cancia/content?site=${encodeURIComponent(site)}`, {\n headers: headers(),\n });\n if (!res.ok) throw new Error(`Cancia: failed to fetch content (${res.status})`);\n return res.json();\n}\n\nexport async function saveEntry(key: string, lang: string, value: string): Promise<void> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(`${apiUrl}/api/cancia/save`, {\n method: \"POST\",\n headers: headers(),\n // `route` lets the server invalidate this page's cache tag (034, invalidate mode).\n body: JSON.stringify({ key, lang, value, site, route: currentRoute() }),\n });\n if (!res.ok) throw new Error(`Cancia: failed to save (${res.status})`);\n}\n\nexport function isAuthError(err: unknown): boolean {\n return err instanceof Error && err.message.includes(\"(401)\");\n}\n\nexport function uploadImage(\n file: File,\n onProgress?: (percent: number) => void\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const { apiUrl, site } = state.config!;\n const form = new FormData();\n form.append(\"file\", file);\n form.append(\"site\", site);\n\n const xhr = new XMLHttpRequest();\n xhr.open(\"POST\", `${apiUrl}/api/cancia/upload`);\n if (state.sessionToken) xhr.setRequestHeader(\"Authorization\", `Bearer ${state.sessionToken}`);\n\n xhr.upload.addEventListener(\"progress\", (e) => {\n if (e.lengthComputable) onProgress?.(Math.round((e.loaded / e.total) * 100));\n });\n xhr.addEventListener(\"load\", () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n resolve(JSON.parse(xhr.responseText).url as string);\n } catch {\n reject(new Error(\"Cancia: invalid upload response\"));\n }\n } else {\n reject(new Error(`Cancia: failed to upload image (${xhr.status})`));\n }\n });\n xhr.addEventListener(\"error\", () => reject(new Error(\"Cancia: upload network error\")));\n xhr.send(form);\n });\n}\n\nexport async function triggerPublish(): Promise<void> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(`${apiUrl}/api/cancia/publish`, {\n method: \"POST\",\n headers: headers(),\n body: JSON.stringify({ site }),\n });\n if (!res.ok) throw new Error(`Cancia: publish failed (${res.status})`);\n}\n\n// ---------------------------------------------------------------------------\n// Lists + schemas (v2)\n// ---------------------------------------------------------------------------\n\nexport interface ListSchemaField {\n name: string;\n label: string;\n description?: string;\n widget:\n | \"text\"\n | \"textarea\"\n | \"url\"\n | \"email\"\n | \"datetime\"\n | \"number\"\n | \"checkbox\"\n | \"select\"\n | \"image\"\n | \"slug\"\n | \"array\"\n | \"object\"\n | \"reference\"\n | \"richtext\";\n required: boolean;\n placeholder?: string;\n options?: string[];\n minLength?: number;\n maxLength?: number;\n min?: number;\n max?: number;\n /** Regex source (no delimiters) the value must match. */\n pattern?: string;\n /** For slug widgets: the field name to derive the slug from. */\n source?: string;\n /** For array widgets: the schema of a single item (name is \"\"). */\n of?: ListSchemaField;\n /** For object widgets: the sub-field schemas, in declared order. */\n fields?: ListSchemaField[];\n /** For reference widgets: the name of the list whose entry id this stores. */\n referenceList?: string;\n}\n\nexport interface ListSchemaDescription {\n name: string;\n label: string;\n labelSingular: string;\n titleField: string;\n bodyField?: string;\n slugField?: string;\n /**\n * Field holding the entry's draft flag, when the list opts in. Rows whose\n * value is true get a \"Draft\" badge — the editor's only signal that the\n * entry they can see in the panel is NOT on the live site.\n */\n draftField?: string;\n fields: ListSchemaField[];\n}\n\nexport interface ListEntry {\n id: string;\n data: Record<string, unknown>;\n locale: string;\n createdAt: string;\n updatedAt: string;\n _rev: string;\n}\n\nexport interface TranslationStatus {\n id: string;\n locales: string[];\n}\n\nexport async function fetchSchemas(): Promise<Record<string, ListSchemaDescription>> {\n const { apiUrl } = state.config!;\n const res = await fetch(`${apiUrl}/api/cancia/schemas`, { headers: headers() });\n if (!res.ok) throw new Error(`Cancia: failed to fetch schemas (${res.status})`);\n const body = (await res.json()) as { schemas: Record<string, ListSchemaDescription> };\n return body.schemas;\n}\n\nfunction localeParam(locale?: string): string {\n return locale ? `&locale=${encodeURIComponent(locale)}` : \"\";\n}\n\nexport async function fetchList(listName: string, locale?: string): Promise<ListEntry[]> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}?site=${encodeURIComponent(site)}${localeParam(locale)}`,\n { headers: headers() },\n );\n if (!res.ok) throw new Error(`Cancia: failed to fetch list \"${listName}\" (${res.status})`);\n const body = (await res.json()) as { entries: ListEntry[] };\n return body.entries;\n}\n\nexport async function fetchTranslations(listName: string): Promise<TranslationStatus[]> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}/_translations?site=${encodeURIComponent(site)}`,\n { headers: headers() },\n );\n if (!res.ok) throw new Error(`Cancia: failed to fetch translations (${res.status})`);\n const body = (await res.json()) as { translations: TranslationStatus[] };\n return body.translations;\n}\n\nexport async function createListEntry(\n listName: string,\n data: Record<string, unknown>,\n locale: string,\n id?: string,\n): Promise<ListEntry> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}?site=${encodeURIComponent(site)}${localeParam(locale)}${routeParam()}`,\n { method: \"POST\", headers: headers(), body: JSON.stringify({ data, id }) },\n );\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string };\n throw new Error(err.error ?? `Cancia: failed to create entry (${res.status})`);\n }\n const body = (await res.json()) as { entry: ListEntry };\n return body.entry;\n}\n\nexport async function updateListEntry(\n listName: string,\n id: string,\n data: Record<string, unknown>,\n rev: string,\n locale: string,\n): Promise<ListEntry> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}/${encodeURIComponent(id)}?site=${encodeURIComponent(site)}${localeParam(locale)}${routeParam()}`,\n { method: \"PATCH\", headers: headers(), body: JSON.stringify({ data, _rev: rev }) },\n );\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string; code?: string };\n const message = err.error ?? `Cancia: failed to update entry (${res.status})`;\n throw Object.assign(new Error(message), { code: err.code });\n }\n const body = (await res.json()) as { entry: ListEntry };\n return body.entry;\n}\n\nexport async function deleteListEntry(listName: string, id: string, locale: string): Promise<void> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}/${encodeURIComponent(id)}?site=${encodeURIComponent(site)}${localeParam(locale)}${routeParam()}`,\n { method: \"DELETE\", headers: headers() },\n );\n if (!res.ok) throw new Error(`Cancia: failed to delete entry (${res.status})`);\n}\n\nexport async function reorderList(listName: string, ids: string[]): Promise<void> {\n const { apiUrl, site } = state.config!;\n const res = await fetch(\n `${apiUrl}/api/cancia/lists/${encodeURIComponent(listName)}/reorder?site=${encodeURIComponent(site)}${routeParam()}`,\n { method: \"POST\", headers: headers(), body: JSON.stringify({ ids }) },\n );\n if (!res.ok) throw new Error(`Cancia: failed to reorder list (${res.status})`);\n}\n\n/** Save all pending changes in one batch. Removes successfully saved entries from pending. */\nexport async function flushPending(): Promise<void> {\n const entries = Array.from(state.pending.values());\n const results = await Promise.allSettled(\n entries.map(({ key, lang, value }) => saveEntry(key, lang, value))\n );\n results.forEach((result, i) => {\n if (result.status === \"fulfilled\") {\n const { key, lang } = entries[i];\n state.pending.delete(`${key}.${lang}`);\n }\n });\n const failed = results.filter((r) => r.status === \"rejected\").length;\n if (failed > 0) throw new Error(`Cancia: ${failed} save(s) failed`);\n}\n","// =============================================================================\n// Cancia Toolbar — Design tokens\n// =============================================================================\n// ONE source of truth for every colour, space, radius, shadow and motion value\n// in the editor UI.\n//\n// Why this exists: the toolbar grew to ~108 inline `cssText` blocks with values\n// written by hand at each call site — `rgba(255,255,255,0.1)` appeared 14\n// separate times, `0.07` twelve, `0.06` eleven. Nothing was reliably the same\n// as anything else, and changing \"the border colour\" meant finding every one.\n//\n// These are emitted as CSS custom properties on the injected root, so:\n// - a value is defined once and referenced by name,\n// - the accent follows the site's configured colour at runtime,\n// - a consumer can override any token without us shipping a release.\n//\n// Everything is namespaced `--cancia-*`. The toolbar is injected into somebody\n// else's page: an unprefixed custom property would collide with theirs, and a\n// bare `--accent` is exactly the kind of name a Tailwind theme already owns.\n// =============================================================================\n\n/**\n * The editor chrome is a LIGHT, neutral surface.\n *\n * It used to be near-black. The people using this are the site owner — a coach,\n * a school administrator — not developers, and a dark floating panel over their\n * own (usually light) site reads as a developer tool that has landed on top of\n * their page. A white surface with a real border reads as a document: part of\n * the same world as the page, just clearly OURS because of the border and the\n * shadow rather than because of a colour inversion.\n *\n * Neutral zinc greys throughout, no colour cast. The only hue in the set is in\n * the three status tokens, where the colour IS the meaning.\n */\nexport const tokens = {\n // ── Surfaces ──────────────────────────────────────────────────────────────\n // All three chrome levels are plain white. On a light theme, depth comes from\n // the BORDER and the shadow, not from a lightness ramp: three subtly\n // different off-whites just look like a rendering bug. The scale is still\n // three names so component code keeps its layering vocabulary.\n \"surface-1\": \"#ffffff\", // the floating bar itself\n \"surface-2\": \"#ffffff\", // popups, panels\n \"surface-3\": \"#ffffff\", // the drawer / form (the topmost layer)\n \"surface-raised\": \"#f4f4f5\", // an input or row ON a surface — recessed, not raised\n \"surface-hover\": \"#f4f4f5\",\n \"surface-active\": \"#e4e4e7\",\n\n // ── Text ──────────────────────────────────────────────────────────────────\n // Four steps only. More than four and nothing reads as deliberate.\n // Opaque hex, not white-alpha: these sit on white, and an alpha black over a\n // translucent surface picks up whatever the page beneath happens to be.\n \"fg-strong\": \"#18181b\", // headings, input text\n \"fg\": \"#3f3f46\", // body\n \"fg-muted\": \"#71717a\", // labels, help text\n \"fg-faint\": \"#a1a1aa\", // placeholders, disabled\n\n // ── Borders ───────────────────────────────────────────────────────────────\n // On a light surface a 1px border does more work than a large shadow — it is\n // the primary way a panel separates itself from the page behind it.\n \"border\": \"#e4e4e7\",\n \"border-strong\": \"#d4d4d8\",\n\n // ── Accent ────────────────────────────────────────────────────────────────\n // Near-black, NOT a brand colour. See the note on tokenCss(): the site's\n // configured accentColor is opt-in, because a client's brand colour is\n // frequently pale or neon and produces an unreadable button on light chrome.\n \"accent\": \"#18181b\",\n \"accent-fg\": \"#ffffff\",\n \"accent-soft\": \"rgba(24, 24, 27, 0.06)\", // recomputed when an accent is supplied\n \"accent-ring\": \"rgba(24, 24, 27, 0.28)\", // recomputed when an accent is supplied\n\n // ── Status ────────────────────────────────────────────────────────────────\n // Retuned for light: the dark theme used pastel-bright status colours that\n // glowed on near-black and wash out to illegible on white. These are the\n // mid-weight variants that hold contrast against a white surface.\n \"danger\": \"#dc2626\",\n \"danger-soft\": \"rgba(220, 38, 38, 0.08)\",\n \"success\": \"#16a34a\",\n // Amber. Marks an incomplete-but-not-broken state — chiefly a list entry that\n // exists in another locale but is NOT translated into the active one.\n \"warning\": \"#d97706\",\n \"warning-soft\": \"rgba(217, 119, 6, 0.10)\",\n\n // ── Radii ─────────────────────────────────────────────────────────────────\n \"radius-sm\": \"6px\",\n \"radius\": \"10px\",\n \"radius-lg\": \"14px\",\n \"radius-full\": \"999px\",\n\n // ── Spacing ───────────────────────────────────────────────────────────────\n // A 4px scale. Every gap/padding in the UI is one of these.\n \"space-1\": \"4px\",\n \"space-2\": \"8px\",\n \"space-3\": \"12px\",\n \"space-4\": \"16px\",\n \"space-5\": \"20px\",\n \"space-6\": \"24px\",\n\n // ── Typography ────────────────────────────────────────────────────────────\n // The system stack, so the editor never waits on a webfont or inherits a\n // display face from the page it is injected into.\n \"font\":\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n \"text-xs\": \"11px\",\n \"text-sm\": \"12px\",\n \"text-base\": \"13px\",\n \"text-lg\": \"15px\",\n\n // ── Elevation ─────────────────────────────────────────────────────────────\n // Retuned for light surfaces. The dark theme's shadows were 0.3–0.5 alpha\n // black, which on white reads as a grey smear rather than elevation. Light UI\n // wants soft, low-opacity shadows in two layers — a tight contact shadow plus\n // a wide ambient one — with the 1px `border` doing most of the separating.\n // The `inset` top highlight is gone: it simulated light catching the top edge\n // of a dark glass panel and is invisible (or dirty) on white.\n \"shadow-sm\": \"0 1px 2px rgba(0, 0, 0, 0.04), 0 1px 3px rgba(0, 0, 0, 0.06)\",\n \"shadow\": \"0 2px 4px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.08)\",\n \"shadow-lg\": \"0 4px 8px rgba(0, 0, 0, 0.05), 0 16px 48px rgba(0, 0, 0, 0.12)\",\n\n // ── Motion ────────────────────────────────────────────────────────────────\n // Two curves, and a rule for choosing between them.\n //\n // `ease` is critically damped — it settles without overshoot, which is what\n // almost all UI wants. Overshoot on a menu that simply appeared reads as\n // noise; overshoot is only earned when the user's own gesture carried\n // momentum into it (a flick, a drag release).\n //\n // `ease-spring` is the momentum curve: a slight overshoot that makes a\n // element feel thrown rather than placed. Reserve it for motion the user\n // initiated with a gesture, and for the toolbar's own entrance (which should\n // feel like it arrives, not like it blinks on).\n // Three curves, chosen by what the element is DOING — not by taste.\n //\n // entering or exiting the screen -> ease-out\n // already on screen, moving -> ease-in-out\n // hover / colour change -> ease\n //\n // `ease-in` is deliberately absent. Its slow start delays visual feedback,\n // which reads as a sluggish interface; this file previously carried a\n // cubic-bezier(0.7, 0, 0.84, 0) exit that did exactly that.\n //\n // These are named after the standard easing set so the intent is legible at\n // the call site: `ease-out-quart` is a strong ease-out, not a magic tuple.\n \"ease\": \"cubic-bezier(0.25, 0.1, 0.25, 1)\", // hover, colour — gentle, asymmetric\n \"ease-out\": \"cubic-bezier(0.165, 0.84, 0.44, 1)\", // quart: enter/exit, the default\n \"ease-out-soft\": \"cubic-bezier(0.25, 0.46, 0.45, 0.94)\", // quad: small/short moves\n \"ease-in-out\": \"cubic-bezier(0.645, 0.045, 0.355, 1)\", // cubic: on-screen movement\n \"ease-spring\": \"cubic-bezier(0.34, 1.35, 0.64, 1)\", // overshoot — momentum only\n\n // Durations. UI animation stays under 300ms; past that an interface starts\n // to feel like it is waiting on itself. Larger surfaces get the longer end,\n // and an exit runs ~20% faster than the matching entrance because nobody\n // wants to watch something leave.\n \"duration-fast\": \"0.12s\", // press feedback, hover — must feel instant\n \"duration\": \"0.2s\", // the default: popups, tooltips, panels\n \"duration-slow\": \"0.28s\", // the largest surfaces (drawer, list panel)\n \"duration-exit\": \"0.16s\", // exits: ~20% faster than the entrance\n\n // ── Effects ───────────────────────────────────────────────────────────────\n // Surfaces are opaque white now, so the blur is mostly inert — it is kept so\n // a consumer who overrides a surface to a translucent value still gets the\n // frosted treatment. The `saturate(180%)` boost is dropped: it existed to\n // give dark glass richness, and over a light surface it pushes whatever page\n // colour bleeds through toward the garish.\n \"blur\": \"blur(16px)\",\n\n // ── Layering ──────────────────────────────────────────────────────────────\n // The toolbar must sit above the host page's own stacking contexts, so these\n // live at the very top of the range.\n \"z-overlay\": \"2147483645\",\n \"z-panel\": \"2147483646\",\n \"z-bar\": \"2147483647\",\n} as const;\n\nexport type TokenName = keyof typeof tokens;\n\n/** Reference a token in a style string: `background: ${v(\"surface-1\")}`. */\nexport function v(name: TokenName): string {\n return `var(--cancia-${name})`;\n}\n\n/**\n * Parse `#rgb` / `#rrggbb` into components so the accent can be derived into\n * soft/ring variants. Returns null for anything else (a named colour, hsl(),\n * a CSS variable) — callers then keep the default, which is always valid.\n */\nfunction parseHex(hex: string): { r: number; g: number; b: number } | null {\n const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());\n if (!m) return null;\n let h = m[1];\n if (h.length === 3) h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];\n return {\n r: parseInt(h.slice(0, 2), 16),\n g: parseInt(h.slice(2, 4), 16),\n b: parseInt(h.slice(4, 6), 16),\n };\n}\n\n/**\n * Build the `:root`-level custom properties. Injected ONCE; every component\n * then references `var(--cancia-*)` instead of restating values.\n *\n * The site's `accentColor` is OPT-IN, not automatic.\n *\n * This used to unconditionally overwrite `accent` with whatever the site had\n * configured. That is wrong on a light chrome: `accent` is the fill of the\n * primary button (with `accent-fg` white text on it), and a client's brand\n * colour is very often pale (a soft sand, a pastel mint) or neon — either of\n * which produces white-on-near-white and an unreadable Save button. The brand\n * colour is chosen to work on THEIR page, and carries no guarantee about our\n * chrome.\n *\n * So the default is the neutral near-black, and a supplied accent is honoured\n * only when it PARSES AS A HEX — the same gate that lets us derive coherent\n * soft/ring variants from it. A named colour, an `hsl()`, or a `var()` cannot\n * be decomposed, so it would leave a brand `accent` paired with near-black\n * halos; those fall back wholesale rather than half-applying.\n *\n * (This still does not guarantee contrast for a pale hex. A luminance check\n * that rejects an accent too light for white text is the natural next step,\n * but it changes which colour a client sees, so it is left for a deliberate\n * decision rather than smuggled in with a theme flip.)\n */\nexport function tokenCss(accent?: string, useAccent = false): string {\n const resolved = { ...tokens } as Record<string, string>;\n\n // The editor's accent is NEUTRAL NEAR-BLACK by default, and a site's\n // configured `accentColor` does NOT override it unless a project explicitly\n // opts in (`toolbarAccent: true`).\n //\n // This is deliberate and it is not the same as \"accept it if it parses\".\n // Nearly every site sets some accentColor, so parse-gating alone means the\n // editor is tinted by whatever the brand happens to be — and a brand colour\n // is chosen to stand out on that site's own design, not to be legible as\n // chrome on white. A pale yellow gives an unreadable primary button; a neon\n // gives a UI that shouts louder than the content being edited. Neutral\n // chrome never fights the page it is sitting on.\n //\n // A hex is still required when opting in, because the soft/ring variants are\n // derived from the parsed channels — pairing a brand colour with neutral\n // halos looks like a mistake rather than a theme.\n const rgb = accent ? parseHex(accent) : null;\n if (useAccent && accent && rgb) {\n resolved[\"accent\"] = accent;\n resolved[\"accent-soft\"] = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.10)`;\n resolved[\"accent-ring\"] = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.35)`;\n }\n\n const decls = Object.entries(resolved)\n .map(([k, val]) => ` --cancia-${k}: ${val};`)\n .join(\"\\n\");\n\n return `:root {\\n${decls}\\n}`;\n}\n","// =============================================================================\n// Cancia Toolbar — Shared style primitives\n// =============================================================================\n// Small composable style strings built from tokens. Components call these\n// instead of writing `cssText` by hand, so a button in the popup and a button\n// in the list panel are the SAME button — which is what \"consistent\" means in\n// practice.\n//\n// These return CSS text (not classes) because the toolbar builds DOM nodes\n// directly and must not depend on a stylesheet the host page could override.\n// The one global sheet we do inject (see `injectBaseStyles`) carries only the\n// tokens, keyframes, and resets that cannot be expressed inline.\n// =============================================================================\n\nimport { tokenCss, v } from \"./tokens\";\n\nlet injected = false;\n\n/**\n * Inject the token sheet + keyframes once per page.\n *\n * Idempotent: repeated calls are no-ops, so any component can call it during\n * its own setup without coordinating with the others. Pass the site's accent\n * so every surface derives from the same colour.\n */\nexport function injectBaseStyles(accent?: string, useAccent = false): void {\n if (injected) return;\n injected = true;\n\n const style = document.createElement(\"style\");\n style.dataset.cancia = \"tokens\";\n style.textContent = `\n${tokenCss(accent, useAccent)}\n\n@keyframes cancia-in {\n from { opacity: 0; transform: translateY(4px) scale(0.98); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n}\n@keyframes cancia-fade {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n@keyframes cancia-spin {\n to { transform: rotate(360deg); }\n}\n\n/* Scoped reset. The toolbar is injected into somebody else's page, whose\n global styles WILL otherwise reach our elements — a site-wide\n \\`button { text-transform: uppercase }\\` would rewrite our labels. */\n[data-cancia-ui], [data-cancia-ui] * {\n box-sizing: border-box;\n font-family: ${v(\"font\")};\n text-transform: none;\n letter-spacing: normal;\n line-height: 1.45;\n margin: 0;\n}\n[data-cancia-ui] button {\n font: inherit;\n color: inherit;\n background: none;\n border: none;\n cursor: pointer;\n}\n[data-cancia-ui] input,\n[data-cancia-ui] textarea,\n[data-cancia-ui] select {\n font: inherit;\n color: inherit;\n}\n[data-cancia-ui] ::placeholder { color: ${v(\"fg-faint\")}; }\n\n/* Focus is shown with our own ring so it matches the accent and is consistent\n across browsers, rather than inheriting whatever the host page's UA default\n or global \\`:focus\\` rule happens to be. */\n[data-cancia-ui] :focus-visible {\n outline: 2px solid ${v(\"accent-ring\")};\n outline-offset: 2px;\n}\n\n/* Reduced motion: neutralise every animation and transition on our subtree.\n This is deliberately a blanket rule keyed on the [data-cancia-ui] marker —\n which is exactly why markUi() must be called on every top-level container we\n create. Any new motion added anywhere in the toolbar is covered by this\n automatically, as long as it lives inside a marked subtree and is expressed\n as a CSS animation or transition (both of the mechanisms we use).\n\n Note this zeroes DURATION, not the properties themselves: an element still\n lands on its final state instantly, so nothing is left mid-transition. */\n@media (prefers-reduced-motion: reduce) {\n [data-cancia-ui], [data-cancia-ui] * {\n animation-duration: 0.01ms !important;\n transition-duration: 0.01ms !important;\n }\n}\n`;\n document.head.appendChild(style);\n}\n\n/** Mark an element as ours, so the scoped reset above applies to its subtree. */\nexport function markUi<T extends HTMLElement>(el: T): T {\n el.dataset.canciaUi = \"\";\n return el;\n}\n\n// ---------------------------------------------------------------------------\n// Surfaces\n// ---------------------------------------------------------------------------\n\n/**\n * A floating panel: popup, dropdown, list panel.\n *\n * On the light theme the 1px border is what separates the surface from the\n * page; the shadow only supplies the sense of height. That is the inverse of\n * the old dark chrome, where a heavy shadow did the separating and the border\n * was a faint edge highlight — so do NOT drop the border here in favour of a\n * bigger shadow. A white panel on a white page with no border disappears.\n */\nexport const surface = (level: 1 | 2 | 3 = 2): string => `\n background: ${v(`surface-${level}` as \"surface-2\")};\n backdrop-filter: ${v(\"blur\")};\n -webkit-backdrop-filter: ${v(\"blur\")};\n border: 1px solid ${v(\"border\")};\n border-radius: ${v(\"radius-lg\")};\n box-shadow: ${v(\"shadow\")};\n color: ${v(\"fg\")};\n`;\n\n// ---------------------------------------------------------------------------\n// Controls\n// ---------------------------------------------------------------------------\n\nexport type ButtonVariant = \"primary\" | \"ghost\" | \"danger\";\n\n/** The one button in the system. Every clickable control routes through this. */\nexport const button = (variant: ButtonVariant = \"ghost\"): string => {\n const base = `\n display: inline-flex; align-items: center; justify-content: center;\n gap: ${v(\"space-2\")};\n height: 30px;\n padding: 0 ${v(\"space-3\")};\n border-radius: ${v(\"radius-sm\")};\n font-size: ${v(\"text-sm\")};\n font-weight: 500;\n white-space: nowrap;\n transition: background ${v(\"duration-fast\")} ${v(\"ease\")},\n color ${v(\"duration-fast\")} ${v(\"ease\")},\n opacity ${v(\"duration-fast\")} ${v(\"ease\")};\n `;\n if (variant === \"primary\") {\n return `${base}\n background: ${v(\"accent\")};\n color: ${v(\"accent-fg\")};\n `;\n }\n if (variant === \"danger\") {\n return `${base}\n background: transparent;\n color: ${v(\"danger\")};\n `;\n }\n return `${base}\n background: transparent;\n color: ${v(\"fg\")};\n `;\n};\n\n/** A square icon-only button (toolbar controls, close buttons). */\nexport const iconButton = (size = 30): string => `\n display: inline-flex; align-items: center; justify-content: center;\n width: ${size}px; height: ${size}px;\n border-radius: ${v(\"radius-sm\")};\n color: ${v(\"fg-muted\")};\n transition: background ${v(\"duration-fast\")} ${v(\"ease\")},\n color ${v(\"duration-fast\")} ${v(\"ease\")};\n`;\n\n/**\n * A labelled toolbar action: icon ABOVE-LEFT of a word.\n *\n * The toolbar previously showed four bare icons whose meaning depended on a\n * hover tooltip. The people using this are not developers — a paper-plane\n * glyph does not say \"Publish\", and on touch there is no hover at all. Every\n * primary action now carries its word. Bigger hit area, too: 38px minimum,\n * comfortably above the ~24px that trips people up on a trackpad.\n */\nexport const actionButton = (): string => `\n display: inline-flex; align-items: center; justify-content: center;\n gap: ${v(\"space-2\")};\n height: 38px;\n padding: 0 ${v(\"space-4\")};\n /* radius-pill so the button's curve echoes the pill-shaped bar containing\n it. A small square radius inside a fully-round container reads as two\n unrelated shapes. */\n border-radius: ${v(\"radius-full\")};\n font-size: ${v(\"text-base\")};\n font-weight: 500;\n color: ${v(\"fg\")};\n background: transparent;\n white-space: nowrap;\n transition: background ${v(\"duration-fast\")} ${v(\"ease\")},\n color ${v(\"duration-fast\")} ${v(\"ease\")},\n transform ${v(\"duration-fast\")} ${v(\"ease\")};\n`;\n\n/** Text input / textarea. */\nexport const input = (): string => `\n width: 100%;\n padding: ${v(\"space-2\")} ${v(\"space-3\")};\n background: ${v(\"surface-raised\")};\n color: ${v(\"fg-strong\")};\n border: 1px solid ${v(\"border\")};\n border-radius: ${v(\"radius-sm\")};\n font-size: ${v(\"text-base\")};\n outline: none;\n caret-color: ${v(\"accent\")};\n transition: border-color ${v(\"duration-fast\")} ${v(\"ease\")},\n background ${v(\"duration-fast\")} ${v(\"ease\")};\n`;\n\n// ---------------------------------------------------------------------------\n// Text\n// ---------------------------------------------------------------------------\n\n/**\n * A field label.\n *\n * Sentence case at readable size, NOT uppercase micro-tracking. Uppercase\n * labels read as a form-builder's chrome — they are harder to scan, they make\n * every field shout equally, and the tracking that makes them legible also\n * makes a long label wrap awkwardly in a 420px panel. The audience here is the\n * site owner, so a label should look like a question someone asked them.\n */\nexport const label = (): string => `\n display: block;\n font-size: ${v(\"text-sm\")};\n font-weight: 500;\n letter-spacing: normal;\n text-transform: none;\n color: ${v(\"fg-strong\")};\n`;\n\n/** Help text under a control. */\nexport const hint = (): string => `\n font-size: ${v(\"text-xs\")};\n color: ${v(\"fg-muted\")};\n line-height: 1.5;\n`;\n\n/**\n * A GROUP of related fields — an array's rows, an object's sub-fields.\n *\n * Structure comes from a heading and an indent under a thin left rule, the way\n * a document shows nesting. It does NOT come from a box.\n *\n * This is the fix for the form's worst problem: every composite field used to\n * draw its own bordered, filled card, so an array-of-objects nested SIX levels\n * of boxes — measured, not estimated. Card inside card inside card is\n * exhausting to look at and actively misleading, because when everything is a\n * card nothing has a hierarchy: a one-line text field looked exactly as\n * important as the whole entry.\n *\n * A left rule costs one 1px line per level instead of four borders plus a\n * fill, and indentation is the thing people already read as \"belongs to\".\n */\nexport const group = (): string => `\n display: flex;\n flex-direction: column;\n gap: ${v(\"space-2\")};\n padding-left: ${v(\"space-3\")};\n border-left: 1px solid ${v(\"border\")};\n margin-left: 1px;\n`;\n\n/** The heading above a group. Sits OUTSIDE the rule, so it reads as the parent. */\nexport const groupTitle = (): string => `\n font-size: ${v(\"text-sm\")};\n font-weight: 600;\n color: ${v(\"fg-strong\")};\n letter-spacing: -0.005em;\n`;\n\n/**\n * A row inside a group (one array item). Flat: no background, no border — the\n * group's rule already says these belong together, and a per-row box would put\n * the nesting straight back.\n */\nexport const groupRow = (): string => `\n display: flex;\n align-items: flex-start;\n gap: ${v(\"space-2\")};\n`;\n\n// ---------------------------------------------------------------------------\n// Interaction helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Wire hover/focus feedback for a control. Doing this centrally is what keeps\n * every control's hover identical — previously each site invented its own.\n */\nexport function attachHover(\n el: HTMLElement,\n opts: { bg?: string; color?: string } = {},\n): void {\n const bg = opts.bg ?? v(\"surface-hover\");\n const color = opts.color;\n const priorBg = el.style.background;\n const priorColor = el.style.color;\n\n el.addEventListener(\"mouseenter\", () => {\n el.style.background = bg;\n if (color) el.style.color = color;\n });\n el.addEventListener(\"mouseleave\", () => {\n el.style.background = priorBg;\n if (color) el.style.color = priorColor;\n });\n}\n\n/**\n * Instant press feedback on pointer-DOWN, not on click.\n *\n * \"The moment lag appears, the feeling of directness falls off a cliff.\"\n * Waiting for the click event to acknowledge a press feels dead; the response\n * has to happen the instant the finger lands. The scale is small (0.96) —\n * enough to read as a physical press, not enough to be distracting.\n *\n * Uses Pointer Events with capture so the press state is released correctly\n * even if the pointer slides off the button before lifting.\n */\nexport function attachPress(el: HTMLElement, scale = 0.96): void {\n const down = (e: PointerEvent) => {\n if ((el as HTMLButtonElement).disabled) return;\n el.setPointerCapture?.(e.pointerId);\n el.style.transform = `scale(${scale})`;\n };\n const up = () => {\n el.style.transform = \"\";\n };\n el.addEventListener(\"pointerdown\", down);\n el.addEventListener(\"pointerup\", up);\n el.addEventListener(\"pointercancel\", up);\n}\n\n/** Focus ring behaviour for inputs, matching the accent. */\nexport function attachInputFocus(el: HTMLElement): void {\n el.addEventListener(\"focus\", () => {\n el.style.borderColor = v(\"accent-ring\");\n el.style.background = v(\"surface-hover\");\n });\n el.addEventListener(\"blur\", () => {\n el.style.borderColor = v(\"border\");\n el.style.background = v(\"surface-raised\");\n });\n}\n","// =============================================================================\n// Cancia Toolbar — Hover Highlight\n// =============================================================================\n// Scans [data-cms] elements. While edit mode is active, hovering marks the\n// element with a translucent outline and a barely-there tint fill. Clicking\n// fires onSelect.\n//\n// This overlay is drawn on top of a CLIENT'S design, so the whole problem is\n// marking an element without appearing to belong to it. Two earlier attempts\n// failed in opposite directions:\n//\n// 1. A solid 2px outline read as a border the client had authored — it\n// collided with real borders and looked like an error state on a heading.\n// 2. An underline plus a filled label chip was worse: the underline sat\n// INSIDE the element's box, colliding with text descenders, and the solid\n// chip drew more attention than the thing it labelled (and disappeared\n// entirely over a dark section).\n//\n// What works — and what agentation arrived at independently — is not the shape\n// but the WEIGHT: an outline at ~50% alpha over a ~5% fill. At those opacities\n// the mark reads as a highlight laid OVER the page rather than a border\n// belonging TO it. Nothing is drawn at full strength.\n//\n// Two supporting decisions:\n// - The field kind lives in the cursor-following tooltip, not a chip welded\n// to the element. Same information, no visual weight, cannot be clipped.\n// - The marker HIDES during scroll and returns when scrolling stops. Tracking\n// an element mid-scroll makes the box chase the pointer down the page, and\n// no easing makes that read as anything but twitchy.\n//\n// LIST mode keeps the outline dashed: a list marks a REGION containing many\n// elements, and it should not look like just another single field.\n// =============================================================================\n\nimport { state } from \"./state\";\nimport { v } from \"./tokens\";\nimport { markUi } from \"./styles\";\nimport type { CanciaFieldType as FieldType } from \"./types\";\n\nexport type CanciaSelection =\n | { kind: \"field\"; el: HTMLElement; key: string; fieldType: FieldType }\n | { kind: \"list\"; el: HTMLElement; listName: string };\n\ntype SelectCallback = (selection: CanciaSelection) => void;\n\nconst CMS_SELECTOR = \"[data-cms], [data-cms-list]\";\n\nlet onSelect: SelectCallback | null = null;\nlet currentHighlighted: HTMLElement | null = null;\nlet cleanupFns: (() => void)[] = [];\nlet scrollRAF: number | null = null;\nlet scrollEndTimer: ReturnType<typeof setTimeout> | null = null;\n\n// Overlay + tooltip elements (reused, not re-created per hover)\nlet overlayEl: HTMLElement | null = null;\nlet tooltipEl: HTMLElement | null = null;\nlet styleInjected = false;\n\n/**\n * The colour the marker is drawn in.\n *\n * The fallback matches the `accent` token's default (near-black), NOT the old\n * indigo — this is drawn on the client's page, and a stray indigo here would\n * be the one place the editor still showed a brand colour we no longer use.\n *\n * Note this reads config.accentColor DIRECTLY rather than via the token, since\n * the marker is composed into an innerHTML string with derived alpha values.\n * Unlike tokenCss(), a non-hex value is harmless here (it is used as a plain\n * CSS colour, never decomposed), so it is passed through as-is.\n */\nfunction accent() {\n // Mirror tokenCss()'s rule exactly: the site's brand colour tints the editor\n // ONLY when a project opts in. Reading config.accentColor unconditionally\n // here meant the highlight stayed brand-coloured while every other surface\n // had gone neutral — the underline and tag showed the site's violet against\n // near-black chrome, which reads as a bug rather than a theme.\n const useAccent = state.config?.toolbarAccent === true;\n return (useAccent ? state.config?.accentColor : undefined) ?? \"#18181b\";\n}\n\n/**\n * The accent at a given alpha.\n *\n * `color-mix()` would be the clean way to do this and is what agentation uses,\n * but it is unsupported in older Safari, and this string is written onto the\n * CLIENT'S page — a colour that fails to parse there means no visible marker at\n * all, with nothing in the console to explain it. So: parse a hex when we have\n * one, and fall back to a neutral rgba otherwise. Never build a colour by\n * string concatenation (`${hex}80`), which silently produces invalid CSS for\n * any non-6-digit-hex input.\n */\nfunction withAlpha(color: string, alpha: number): string {\n const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color.trim());\n if (m) {\n let h = m[1];\n if (h.length === 3) h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];\n const r = parseInt(h.slice(0, 2), 16);\n const g = parseInt(h.slice(2, 4), 16);\n const b = parseInt(h.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n }\n // A named colour / hsl() / var() we cannot decompose: use the neutral so the\n // marker still renders, rather than emitting something the browser drops.\n return `rgba(24, 24, 27, ${alpha})`;\n}\n\nfunction fieldType(el: HTMLElement): FieldType {\n // An explicit data-cms-type always wins — it is how a consumer overrides the\n // tag-based guess (e.g. a framework <Image> that renders an <img>).\n if (el.dataset.cmsType === \"image\") return \"image\";\n if (el.dataset.cmsType === \"link\") return \"link\";\n // A rich region holds a document, not a string. This case MUST exist before\n // anything can emit data-cms-type=\"richtext\": without it the region falls\n // through to \"text\" below, gets a plain textarea, and saving writes\n // textContent over the whole subtree — destroying every paragraph, list and\n // link inside it. Opt-in only, never inferred: a footer phone number lives on\n // an element with children too, and giving a client a bold button on a tel:\n // link is worse than not.\n if (el.dataset.cmsType === \"richtext\") return \"richtext\";\n if (el.tagName === \"IMG\") return \"image\";\n // NOTE: an <a> is deliberately NOT inferred as a link. Link editing must be\n // opted into with data-cms-type=\"link\", because plenty of legitimate text\n // fields live on an anchor — a footer email/phone, a nav item — where the\n // href is derived from the value or fixed in code. Inferring from the tag\n // silently converted those into link fields and showed the editor a URL\n // input that had nowhere to write. Opt-in keeps a text field a text field.\n return \"text\";\n}\n\n/**\n * The two CMS modes. data-cms-list takes precedence when both are set on\n * the same element (rare but possible if a list is nested inside a KV\n * region — the inner list wins on the closest() lookup anyway).\n */\nfunction elementMode(el: HTMLElement): \"list\" | \"field\" {\n return el.dataset.cmsList ? \"list\" : \"field\";\n}\n\n// ---------------------------------------------------------------------------\n// Inject keyframes once\n// ---------------------------------------------------------------------------\n\nfunction injectStyles() {\n if (styleInjected) return;\n styleInjected = true;\n const s = document.createElement(\"style\");\n s.textContent = `\n /* A plain fade. The marker used to scale from 0.98, which was right for a\n box growing into place but wrong for an underline — a scaling underline\n reads as sliding sideways from its centre. Opacity only. */\n @keyframes cancia-highlight-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes cancia-tooltip-in {\n from { opacity: 0; transform: scale(0.95) translateY(3px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n }\n `;\n document.head.appendChild(s);\n}\n\n// ---------------------------------------------------------------------------\n// Overlay: fixed border box that tracks the hovered element\n// ---------------------------------------------------------------------------\n\nfunction getOrCreateOverlay(): HTMLElement {\n if (!overlayEl) {\n overlayEl = document.createElement(\"div\");\n overlayEl.dataset.canciaOverlay = \"1\";\n markUi(overlayEl);\n // The overlay itself is now an invisible HULL matching the element's box.\n // It paints nothing: the underline bar and the corner tag are children\n // positioned against it. Keeping the hull means the existing rect-tracking\n // (including the scroll handler) works unchanged — only what's drawn\n // inside it changed.\n //\n // Positioned with a TRANSFORM, not top/left/width/height.\n //\n // Those four are layout properties: animating them runs layout + paint on\n // every frame of a mousemove, on the CLIENT'S page, which is the one place\n // we must not cost frames. `transform` and `opacity` are the only two\n // properties that skip straight to the compositor. Width/height still have\n // to be set (a box has a size), but they are assigned without transition\n // so they never animate; only the transform moves.\n //\n // `contain` stops any of this from invalidating the host page's layout.\n //\n // z-index stays literal: it must sit exactly ONE below the tooltip's\n // z-overlay so the tooltip paints above the marker. No token for it.\n overlayEl.style.cssText = `\n position: fixed;\n top: 0; left: 0;\n pointer-events: none !important;\n box-sizing: border-box;\n background: transparent;\n border: 0;\n z-index: 2147483644;\n will-change: transform, opacity;\n contain: layout style;\n transition: transform ${v(\"duration-fast\")} ${v(\"ease-out-soft\")},\n opacity ${v(\"duration-fast\")} ${v(\"ease\")};\n `;\n document.body.appendChild(overlayEl);\n }\n return overlayEl;\n}\n\nfunction getOrCreateTooltip(): HTMLElement {\n if (!tooltipEl) {\n tooltipEl = document.createElement(\"div\");\n tooltipEl.dataset.canciaTooltip = \"1\";\n markUi(tooltipEl);\n tooltipEl.style.cssText = `\n position: fixed;\n pointer-events: none !important;\n z-index: ${v(\"z-overlay\")};\n font-family: ${v(\"font\")};\n font-size: ${v(\"text-xs\")};\n font-weight: 500;\n letter-spacing: 0.02em;\n color: ${v(\"fg-strong\")};\n background: ${v(\"surface-1\")};\n backdrop-filter: ${v(\"blur\")};\n -webkit-backdrop-filter: ${v(\"blur\")};\n border: 1px solid ${v(\"border-strong\")};\n padding: ${v(\"space-1\")} ${v(\"space-2\")};\n border-radius: ${v(\"radius-sm\")};\n white-space: nowrap;\n max-width: 260px;\n overflow: hidden;\n text-overflow: ellipsis;\n box-shadow: ${v(\"shadow-sm\")};\n `;\n document.body.appendChild(tooltipEl);\n }\n return tooltipEl;\n}\n\nlet lastOverlayEl: HTMLElement | null = null; // track which el we last styled the badge for\n\n/**\n * The colour lists are marked with — related to the field accent, but distinct.\n *\n * This used to swap RGB channels to derive a neighbouring hue from the accent.\n * That trick relied on the accent being a saturated colour (the old indigo\n * default): channel-swapping a NEUTRAL grey — which the default accent now is —\n * returns the same grey, so lists and fields became indistinguishable.\n *\n * So: a near-grey accent (all channels within a narrow spread) gets a fixed\n * emerald, which is the one hue in the editor that means \"a region you can add\n * things to\". A genuinely colourful accent still derives from itself.\n */\nconst LIST_FALLBACK = \"#059669\";\n\nfunction listAccent(hex: string): string {\n if (!/^#[0-9a-f]{6}$/i.test(hex)) return LIST_FALLBACK;\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n // Near-neutral (grey/black/white) → channel-swapping is a no-op, so use the\n // fixed hue instead of silently returning the field colour.\n const spread = Math.max(r, g, b) - Math.min(r, g, b);\n if (spread < 24) return LIST_FALLBACK;\n // Swap RGB channels deterministically to land on a related-but-distinct hue.\n // Boring trick that keeps tone consistent with the user's accent choice.\n const shifted = [g, b, r].map((c) => c.toString(16).padStart(2, \"0\")).join(\"\");\n return `#${shifted}`;\n}\n\nconst FIELD_ICON = `<svg width=\"10\" height=\"10\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\">\n <path d=\"M2 4h10M2 7h7M2 10h5\"/>\n</svg>`;\n\nconst IMAGE_ICON = `<svg width=\"10\" height=\"10\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"1\" y=\"1\" width=\"12\" height=\"12\" rx=\"2\"/>\n <circle cx=\"4.5\" cy=\"4.5\" r=\"1.2\"/>\n <path d=\"M1 9.5l3.5-3 2.5 2.5 2-1.5 3 3.5\"/>\n</svg>`;\n\nconst LINK_ICON = `<svg width=\"10\" height=\"10\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M6 8a2.5 2.5 0 003.6.3l2.2-2.2a2.5 2.5 0 00-3.5-3.5L7.2 3.6\"/>\n <path d=\"M8 6a2.5 2.5 0 00-3.6-.3L2.2 7.9a2.5 2.5 0 003.5 3.5l1.1-1.1\"/>\n</svg>`;\n\nconst LIST_ICON = `<svg width=\"10\" height=\"10\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"1\" y=\"2\" width=\"3\" height=\"3\" rx=\"0.5\"/>\n <rect x=\"1\" y=\"7.5\" width=\"3\" height=\"3\" rx=\"0.5\"/>\n <path d=\"M6 3.5h7M6 9h7\"/>\n</svg>`;\n\n/**\n * Human-facing names for the field kinds. The tag is read by a non-developer,\n * so it says \"Text\", not \"text\" or the widget name.\n */\nconst KIND_LABEL: Record<FieldType, string> = {\n text: \"Text\",\n image: \"Image\",\n link: \"Link\",\n richtext: \"Rich text\",\n};\n\nfunction positionOverlay(el: HTMLElement, animate = false) {\n const rect = el.getBoundingClientRect();\n const mode = elementMode(el);\n const isList = mode === \"list\";\n const a = isList ? listAccent(accent()) : accent();\n const overlay = getOrCreateOverlay();\n const tooltip = getOrCreateTooltip();\n\n const padding = 3;\n // Position via transform (compositor-only). Size is assigned directly and is\n // NOT transitioned — animating width/height would trigger layout per frame.\n overlay.style.transform = `translate(${rect.left - padding}px, ${rect.top - padding}px)`;\n overlay.style.width = `${rect.width + padding * 2}px`;\n overlay.style.height = `${rect.height + padding * 2}px`;\n\n // Rebuild the marker only when switching to a new element\n if (lastOverlayEl !== el) {\n lastOverlayEl = el;\n\n // A list marks a REGION, so it keeps a full (dashed, quiet) outline — see\n // the header note. A field gets no box at all.\n if (isList) {\n overlay.style.border = `1px dashed ${a}`;\n overlay.style.borderRadius = \"6px\";\n } else {\n overlay.style.border = \"0\";\n overlay.style.borderRadius = \"0\";\n }\n\n let tagIcon: string;\n let tagLabel: string;\n let tooltipText: string;\n if (isList) {\n tagIcon = LIST_ICON;\n tagLabel = \"List\";\n tooltipText = `list: ${el.dataset.cmsList}`;\n } else {\n const type = fieldType(el);\n tagIcon = type === \"image\" ? IMAGE_ICON : type === \"link\" ? LINK_ICON : FIELD_ICON;\n tagLabel = KIND_LABEL[type];\n tooltipText = el.dataset.cms ?? \"\";\n }\n\n // A translucent OUTLINE with a barely-there tint fill — no label chip.\n //\n // The previous underline-plus-solid-tag was worse on both counts. The\n // underline sat inside the element's box, so it collided with text\n // descenders and with any border the client already had; and the tag was a\n // filled near-black chip with white text welded to the element's edge,\n // which drew more attention than the thing it was labelling and vanished\n // outright over a dark section.\n //\n // This is the shape agentation uses, and the reason it works is the\n // opacities: the border is the accent at ~50%, the fill at ~5%. At those\n // weights the mark reads as a highlight laid OVER the design rather than a\n // border belonging TO it — which is exactly the distinction a solid 2px\n // box fails to make. Nothing is drawn at full strength.\n //\n // The field kind moves to the existing tooltip (which already follows the\n // cursor) instead of a chip stuck to the element. Same information, none of\n // the visual weight, and it cannot be clipped by the element's own bounds.\n //\n // `a` stays a live value, not a token: it is the per-mode accent (shifted\n // via listAccent for lists) computed at hover time.\n overlay.style.border = `2px solid ${withAlpha(a, isList ? 0.55 : 0.45)}`;\n overlay.style.background = withAlpha(a, 0.05);\n overlay.style.borderRadius = \"4px\";\n overlay.style.borderStyle = isList ? \"dashed\" : \"solid\";\n overlay.innerHTML = \"\";\n\n // The tooltip now carries the kind AND the key: \"Text · hero.title\".\n tooltip.textContent = tagLabel ? `${tagLabel} ${tooltipText}` : tooltipText;\n }\n\n overlay.style.display = \"block\";\n if (animate) overlay.style.animation = `cancia-highlight-in ${v(\"duration-fast\")} ${v(\"ease-out\")} forwards`;\n\n // Position tooltip above the element (flip below if not enough space)\n tooltip.style.display = \"block\";\n if (animate) tooltip.style.animation = \"cancia-tooltip-in 0.1s ease-out forwards\";\n\n const tooltipMargin = 8;\n const tooltipH = 26;\n if (rect.top - tooltipH - tooltipMargin > 0) {\n tooltip.style.top = `${rect.top - tooltipH - tooltipMargin + padding}px`;\n tooltip.style.left = `${rect.left - padding}px`;\n } else {\n tooltip.style.top = `${rect.bottom + tooltipMargin - padding}px`;\n tooltip.style.left = `${rect.left - padding}px`;\n }\n}\n\nfunction hideOverlay() {\n lastOverlayEl = null;\n if (overlayEl) {\n overlayEl.style.display = \"none\";\n overlayEl.style.animation = \"none\";\n }\n if (tooltipEl) {\n tooltipEl.style.display = \"none\";\n tooltipEl.style.animation = \"none\";\n }\n}\n\nfunction handleScroll() {\n // HIDE the marker while scrolling, and bring it back once scrolling stops.\n //\n // Tracking the element during a scroll means the box chases the pointer down\n // the page, and no amount of easing makes that read as anything but twitchy —\n // it is the single thing that made the old marker feel cheap. Agentation\n // gates its highlight on `!isScrolling` for the same reason. Hiding is also\n // strictly cheaper than repositioning on every tick.\n if (overlayEl && overlayEl.style.display !== \"none\") {\n overlayEl.style.opacity = \"0\";\n if (tooltipEl) tooltipEl.style.opacity = \"0\";\n }\n\n if (scrollEndTimer) clearTimeout(scrollEndTimer);\n scrollEndTimer = setTimeout(() => {\n scrollEndTimer = null;\n // Re-anchor to whatever is under the cursor now, not to the element that\n // was hovered before the scroll — after scrolling, that is usually no\n // longer where the pointer is pointing.\n if (currentHighlighted && document.contains(currentHighlighted)) {\n positionOverlay(currentHighlighted);\n if (overlayEl) overlayEl.style.opacity = \"1\";\n if (tooltipEl) tooltipEl.style.opacity = \"1\";\n }\n }, 140);\n}\n\n// ---------------------------------------------------------------------------\n// Event handlers\n// ---------------------------------------------------------------------------\n\nfunction handleMouseOver(e: MouseEvent) {\n const target = (e.target as HTMLElement).closest(CMS_SELECTOR) as HTMLElement | null;\n if (!target) return;\n currentHighlighted = target;\n target.style.cursor = \"pointer\";\n positionOverlay(target, true);\n}\n\nfunction handleMouseOut(e: MouseEvent) {\n const target = (e.target as HTMLElement).closest(CMS_SELECTOR) as HTMLElement | null;\n if (!target) return;\n // Only hide if we're actually leaving this element (not moving to a child)\n const related = e.relatedTarget as HTMLElement | null;\n if (related && target.contains(related)) return;\n target.style.cursor = \"\";\n if (currentHighlighted === target) {\n currentHighlighted = null;\n hideOverlay();\n }\n}\n\nfunction handleClick(e: MouseEvent) {\n const target = (e.target as HTMLElement).closest(CMS_SELECTOR) as HTMLElement | null;\n if (!target) return;\n e.preventDefault();\n e.stopPropagation();\n hideOverlay();\n if (elementMode(target) === \"list\") {\n const listName = target.dataset.cmsList!;\n onSelect?.({ kind: \"list\", el: target, listName });\n } else {\n const key = target.dataset.cms!;\n onSelect?.({ kind: \"field\", el: target, key, fieldType: fieldType(target) });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Warn about CMS regions that can never be hovered or clicked.\n *\n * The highlight positions itself from getBoundingClientRect(), so an element\n * with no layout box is invisible to the editor even though the markup looks\n * correct. Two ways to hit this, both of which look perfectly reasonable in\n * source: `class=\"sr-only\"` (collapses to 1px + clip) and\n * `display:contents` (no box at all). This cost real debugging time on the\n * first site that used a list, so make the failure loud instead of silent.\n *\n * Runs once per attach and only reports; it never mutates the page.\n */\nfunction warnUnhoverableRegions() {\n const els = document.querySelectorAll<HTMLElement>(CMS_SELECTOR);\n els.forEach((el) => {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) return;\n // An element inside a collapsed/hidden ancestor (a closed accordion, the\n // inactive half of a responsive pair) is legitimately 0×0 right now — only\n // warn when the element itself is styled out of the layout.\n const cs = getComputedStyle(el);\n const selfInflicted =\n cs.display === \"contents\" || cs.position === \"absolute\" || cs.clipPath !== \"none\";\n if (!selfInflicted) return;\n\n const name = el.dataset.cmsList\n ? `list \"${el.dataset.cmsList}\"`\n : `field \"${el.dataset.cms}\"`;\n console.warn(\n `[cancia] ${name} is annotated but has no layout box (${Math.round(rect.width)}×${Math.round(\n rect.height,\n )}) — it cannot be hovered or clicked in the editor. ` +\n `Avoid sr-only / display:contents on CMS regions; give the container a real box.`,\n el,\n );\n });\n}\n\nexport function attachHighlight(selectCallback: SelectCallback) {\n injectStyles();\n onSelect = selectCallback;\n\n warnUnhoverableRegions();\n\n document.addEventListener(\"mouseover\", handleMouseOver, true);\n document.addEventListener(\"mouseout\", handleMouseOut, true);\n document.addEventListener(\"click\", handleClick, true);\n window.addEventListener(\"scroll\", handleScroll, { passive: true, capture: true });\n\n cleanupFns = [\n () => document.removeEventListener(\"mouseover\", handleMouseOver, true),\n () => document.removeEventListener(\"mouseout\", handleMouseOut, true),\n () => document.removeEventListener(\"click\", handleClick, true),\n () => window.removeEventListener(\"scroll\", handleScroll, true),\n ];\n}\n\nexport function detachHighlight() {\n if (currentHighlighted) {\n currentHighlighted.style.cursor = \"\";\n currentHighlighted = null;\n }\n if (scrollRAF !== null) {\n cancelAnimationFrame(scrollRAF);\n scrollRAF = null;\n }\n hideOverlay();\n // Remove overlay + tooltip from DOM entirely when edit mode is off\n overlayEl?.remove();\n overlayEl = null;\n tooltipEl?.remove();\n tooltipEl = null;\n cleanupFns.forEach((fn) => fn());\n cleanupFns = [];\n onSelect = null;\n}\n","// =============================================================================\n// Cancia Toolbar — Internal Events\n// =============================================================================\n// Simple pub/sub so toolbar.ts can react to changes from popup.ts without\n// circular imports.\n// =============================================================================\n\ntype Listener = () => void;\nconst listeners = new Set<Listener>();\n\nexport function onPendingChange(cb?: Listener) {\n if (cb) {\n listeners.add(cb);\n return () => listeners.delete(cb);\n }\n // Called with no args to emit\n listeners.forEach((fn) => fn());\n}\n","// =============================================================================\n// Cancia Toolbar — Edit Popup\n// =============================================================================\n// Anchors near the clicked element. Handles text editing, image upload, and\n// link (label + href) editing.\n// =============================================================================\n\nimport { state, getValue, setPending, applyOverlay } from \"./state\";\nimport { uploadImage } from \"./api\";\nimport { onPendingChange } from \"./events\";\nimport type { CanciaFieldType, CanciaLinkValue } from \"./types\";\nimport { domToRows, parseRichValue, renderRichToDom, serializeRichValue } from \"./richtext\";\nimport {\n portableTextToRows,\n rowsToPortableText,\n type PtListItem,\n type PtStyle,\n type RichTextRow,\n} from \"@cancia/astro/richtext\";\nimport { v } from \"./tokens\";\nimport {\n surface,\n button,\n input as inputStyles,\n label as labelStyles,\n hint as hintStyles,\n markUi,\n attachHover,\n attachInputFocus,\n attachPress,\n} from \"./styles\";\n\nlet popupEl: HTMLElement | null = null;\nlet outsideListener: ((e: MouseEvent) => void) | null = null;\nlet keyListener: ((e: KeyboardEvent) => void) | null = null;\nlet dragover = false;\n\n// WeakMap replaces the unsafe _canciaInput monkey-patch on textarea elements\nconst inputHandlers = new WeakMap<HTMLTextAreaElement, () => void>();\n\nfunction accent() {\n // Matches the `accent` token default (near-black). See tokens.ts for why the\n // site's brand colour is no longer applied automatically.\n // Mirrors tokenCss()'s rule: the site's brand colour tints the editor\n // ONLY when a project opts in via `toolbarAccent`. Reading accentColor\n // unconditionally here would leave this surface brand-coloured while the\n // rest of the chrome is neutral.\n const useAccent = state.config?.toolbarAccent === true;\n return (useAccent ? state.config?.accentColor : undefined) ?? \"#18181b\";\n}\n\n// ---------------------------------------------------------------------------\n// Position helpers\n// ---------------------------------------------------------------------------\n\nfunction getPopupPosition(anchor: HTMLElement): { top: number; left: number; origin: string } {\n const rect = anchor.getBoundingClientRect();\n const scrollY = window.scrollY;\n const scrollX = window.scrollX;\n const popupW = 320;\n const popupH = 260;\n const margin = 10;\n\n let left = rect.left + scrollX;\n let top = rect.bottom + scrollY + margin;\n let origin = \"top left\";\n\n // Flip up if not enough space below\n if (rect.bottom + popupH + margin > window.innerHeight) {\n top = rect.top + scrollY - popupH - margin;\n origin = \"bottom left\";\n }\n\n // Keep within viewport horizontally\n if (left + popupW > window.innerWidth + scrollX) {\n left = window.innerWidth + scrollX - popupW - margin;\n origin = origin.replace(\"left\", \"right\");\n }\n if (left < scrollX + margin) left = scrollX + margin;\n\n return { top, left, origin };\n}\n\n// ---------------------------------------------------------------------------\n// Build popup DOM\n// ---------------------------------------------------------------------------\n\nfunction buildHeader(key: string, onClose: () => void): HTMLElement {\n const header = document.createElement(\"div\");\n header.style.cssText = `\n display: flex; align-items: center; justify-content: space-between;\n margin-bottom: 14px;\n `;\n\n const titleWrap = document.createElement(\"div\");\n titleWrap.style.cssText = `display: flex; flex-direction: column; gap: 1px; min-width: 0;`;\n\n const titleEl = document.createElement(\"span\");\n const keyParts = key.split(\".\");\n titleEl.textContent = keyParts[keyParts.length - 1].replace(/[-_]/g, \" \").replace(/\\b\\w/g, c => c.toUpperCase());\n titleEl.style.cssText = `\n font-size: ${v(\"text-base\")}; font-weight: 600;\n color: ${v(\"fg\")};\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n `;\n\n const keyEl = document.createElement(\"span\");\n keyEl.textContent = key;\n // 10px monospace: the raw key is deliberately below the type scale's floor —\n // it is a debug affordance, not body text. Colour tokenises to fg-faint.\n keyEl.style.cssText = `\n font-size: 10px; font-family: \"SF Mono\", \"Fira Code\", ui-monospace, monospace;\n color: ${v(\"fg-faint\")}; letter-spacing: 0.03em;\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n `;\n\n titleWrap.appendChild(titleEl);\n titleWrap.appendChild(keyEl);\n header.appendChild(titleWrap);\n header.appendChild(makeCloseButton(onClose));\n return header;\n}\n\nfunction buildTextPopup(\n key: string,\n anchorEl: HTMLElement,\n onClose: () => void\n): HTMLElement {\n const langs = state.config?.languages ?? [\"en\"];\n let activeLang = state.activeLang || langs[0];\n\n const wrap = document.createElement(\"div\");\n wrap.dataset.canciaPopup = \"1\";\n applyPopupStyles(wrap);\n wrap.appendChild(buildHeader(key, onClose));\n\n // Language tabs — minimal underline style, only if multiple langs\n if (langs.length > 1) {\n const tabs = document.createElement(\"div\");\n tabs.style.cssText = `display: flex; gap: 0; margin-bottom: ${v(\"space-3\")}; border-bottom: 1px solid ${v(\"border\")};`;\n\n const renderTabs = () => {\n tabs.innerHTML = \"\";\n langs.forEach((lang) => {\n const tab = document.createElement(\"button\");\n tab.textContent = lang.toUpperCase();\n const isActive = lang === activeLang;\n tab.style.cssText = `\n padding: 5px 10px 6px; border: none; border-bottom: 2px solid;\n margin-bottom: -1px;\n font-size: ${v(\"text-xs\")}; font-weight: 600; cursor: pointer; letter-spacing: 0.06em;\n background: transparent;\n border-bottom-color: ${isActive ? v(\"accent\") : \"transparent\"};\n color: ${isActive ? v(\"fg-strong\") : v(\"fg-faint\")};\n transition: color ${v(\"duration-fast\")} ${v(\"ease\")}, border-color ${v(\"duration-fast\")} ${v(\"ease\")};\n `;\n tab.addEventListener(\"mouseenter\", () => { if (!isActive) tab.style.color = v(\"fg\"); });\n tab.addEventListener(\"mouseleave\", () => { if (!isActive) tab.style.color = v(\"fg-faint\"); });\n tab.addEventListener(\"click\", () => {\n const current = wrap.querySelector(\"textarea\") as HTMLTextAreaElement | null;\n if (current) {\n const existing = getValue(key, activeLang);\n const fallback = anchorEl.textContent?.trim() || \"\";\n if (current.value !== (existing || fallback)) {\n setPending(key, activeLang, current.value);\n }\n }\n activeLang = lang;\n state.activeLang = lang;\n // Active language changed globally — re-overlay the page's drafts so\n // other [data-cms] elements match the newly-selected language.\n applyOverlay();\n renderTabs();\n renderTextarea();\n });\n tabs.appendChild(tab);\n });\n };\n renderTabs();\n wrap.appendChild(tabs);\n }\n\n // Textarea\n let textarea: HTMLTextAreaElement;\n\n const attachInputHandler = () => {\n const prev = inputHandlers.get(textarea);\n if (prev) textarea.removeEventListener(\"input\", prev);\n const handler = () => {\n setPending(key, activeLang, textarea.value);\n onPendingChange();\n anchorEl.textContent = textarea.value;\n };\n inputHandlers.set(textarea, handler);\n textarea.addEventListener(\"input\", handler);\n };\n\n const renderTextarea = (isInit = false) => {\n if (!isInit && textarea) {\n // Swap value in-place — no DOM removal so no focus event, no blink\n textarea.value = getValue(key, activeLang) || anchorEl.textContent?.trim() || \"\";\n // Re-apply focused border since element stays focused. accent-ring is the\n // derived focus colour (the old `${accent()}66` broke for non-hex accents).\n textarea.style.borderColor = v(\"accent-ring\");\n textarea.style.background = v(\"surface-hover\");\n attachInputHandler();\n return;\n }\n\n const footerEl = wrap.querySelector(\"[data-cancia-footer]\");\n\n textarea = document.createElement(\"textarea\");\n textarea.value = getValue(key, activeLang) || anchorEl.textContent?.trim() || \"\";\n textarea.rows = 4;\n textarea.placeholder = \"Enter text…\";\n textarea.style.cssText = `\n ${inputStyles()}\n border-radius: ${v(\"radius\")};\n padding: 10px ${v(\"space-3\")};\n font-family: inherit; resize: none;\n line-height: 1.55;\n `;\n attachInputFocus(textarea);\n attachInputHandler();\n\n if (footerEl) {\n wrap.insertBefore(textarea, footerEl);\n } else {\n wrap.appendChild(textarea);\n }\n setTimeout(() => textarea.focus(), 80);\n };\n\n renderTextarea(true);\n\n // Footer\n const footer = document.createElement(\"div\");\n footer.dataset.canciaFooter = \"1\";\n footer.style.cssText = `display: flex; justify-content: flex-end; margin-top: 10px;`;\n\n const saveBtn = makePrimaryButton(\"Save\", accent());\n saveBtn.dataset.canciaSave = \"1\";\n saveBtn.title = \"Save (⌘S)\";\n saveBtn.addEventListener(\"click\", () => {\n const existing = getValue(key, activeLang);\n const fallback = anchorEl.textContent?.trim() || \"\";\n if (textarea.value !== (existing || fallback)) {\n setPending(key, activeLang, textarea.value);\n }\n onPendingChange();\n onClose();\n });\n\n footer.appendChild(saveBtn);\n wrap.appendChild(footer);\n\n return wrap;\n}\n\n// ---------------------------------------------------------------------------\n// Link popup — label + href as one unit\n// ---------------------------------------------------------------------------\n\n/** Same allow-list the schema enforces (isSafeHref). Kept in sync deliberately. */\nfunction isSafeHrefValue(href: string): boolean {\n const trimmed = href.trim();\n if (trimmed === \"\") return true; // empty is \"not set yet\", not unsafe\n if (/^(https?:|mailto:|tel:)/i.test(trimmed)) return true;\n const schemeMatch = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);\n if (schemeMatch) {\n const firstSep = trimmed.search(/[/?#]/);\n if (firstSep === -1 || schemeMatch[1].length < firstSep) return false;\n }\n return true;\n}\n\nfunction parseLink(raw: string): CanciaLinkValue {\n if (!raw) return { label: \"\", href: \"\" };\n const trimmed = raw.trim();\n if (trimmed.startsWith(\"{\")) {\n try {\n const p = JSON.parse(trimmed) as Partial<CanciaLinkValue>;\n if (p && typeof p === \"object\") {\n return { label: String(p.label ?? \"\"), href: String(p.href ?? \"\") };\n }\n } catch {\n // fall through — treat as a plain label\n }\n }\n // A legacy plain string is the label (a `text` field promoted to `link`).\n return { label: raw, href: \"\" };\n}\n\nfunction buildLinkPopup(\n key: string,\n anchorEl: HTMLElement,\n onClose: () => void\n): HTMLElement {\n const langs = state.config?.languages ?? [\"en\"];\n let activeLang = state.activeLang || langs[0];\n\n const wrap = document.createElement(\"div\");\n wrap.dataset.canciaPopup = \"1\";\n applyPopupStyles(wrap);\n wrap.appendChild(buildHeader(key, onClose));\n\n // A button usually holds an icon beside its text, so the editable label is\n // marked with [data-cms-label]. A responsive button may carry SEVERAL marked\n // labels that swap by breakpoint — paint them all. Fall back to the element\n // itself when there is no marker (a plain <a> with no icon).\n const marked = anchorEl.querySelectorAll<HTMLElement>(\"[data-cms-label]\");\n const labelNodes: HTMLElement[] = marked.length > 0 ? Array.from(marked) : [anchorEl];\n const labelNode = labelNodes[0];\n\n // Fall back to what is actually rendered so a first edit starts from the\n // page's own values rather than empty inputs.\n const domLabel = labelNode.textContent?.trim() ?? \"\";\n const domHref = anchorEl.getAttribute(\"href\") ?? \"\";\n\n const readCurrent = (lang: string): CanciaLinkValue => {\n const stored = parseLink(getValue(key, lang));\n return {\n label: stored.label || domLabel,\n // The href is shared across languages (see the note below), so fall back\n // to the default language's stored value before the DOM.\n href: stored.href || parseLink(getValue(key, langs[0])).href || domHref,\n };\n };\n\n const inputStyle = `\n ${inputStyles()}\n border-radius: ${v(\"radius\")};\n padding: 9px ${v(\"space-3\")};\n font-family: inherit;\n `;\n\n const makeLabelled = (text: string, input: HTMLInputElement) => {\n const field = document.createElement(\"div\");\n field.style.cssText = `display: flex; flex-direction: column; gap: 5px; margin-bottom: 10px;`;\n const lab = document.createElement(\"div\");\n lab.textContent = text;\n lab.style.cssText = labelStyles();\n input.style.cssText = inputStyle;\n attachInputFocus(input);\n field.appendChild(lab);\n field.appendChild(input);\n return field;\n };\n\n const labelInput = document.createElement(\"input\");\n labelInput.type = \"text\";\n labelInput.placeholder = \"Book a call\";\n\n const hrefInput = document.createElement(\"input\");\n hrefInput.type = \"text\";\n hrefInput.inputMode = \"url\";\n hrefInput.placeholder = \"/start or https://…\";\n\n const current = readCurrent(activeLang);\n labelInput.value = current.label;\n hrefInput.value = current.href;\n\n // Language tabs — the LABEL is per-language, the href is not (a CTA points\n // at the same place whatever language it is written in). Only the label\n // input swaps; the note under the URL says so, since it is surprising.\n if (langs.length > 1) {\n const tabs = document.createElement(\"div\");\n tabs.style.cssText = `display: flex; gap: 0; margin-bottom: ${v(\"space-3\")}; border-bottom: 1px solid ${v(\"border\")};`;\n const renderTabs = () => {\n tabs.innerHTML = \"\";\n langs.forEach((lang) => {\n const tab = document.createElement(\"button\");\n tab.textContent = lang.toUpperCase();\n const isActive = lang === activeLang;\n tab.style.cssText = `\n padding: 5px 10px 6px; border: none; border-bottom: 2px solid;\n margin-bottom: -1px;\n font-size: ${v(\"text-xs\")}; font-weight: 600; cursor: pointer; letter-spacing: 0.06em;\n background: transparent;\n border-bottom-color: ${isActive ? v(\"accent\") : \"transparent\"};\n color: ${isActive ? v(\"fg-strong\") : v(\"fg-faint\")};\n transition: color ${v(\"duration-fast\")} ${v(\"ease\")}, border-color ${v(\"duration-fast\")} ${v(\"ease\")};\n `;\n tab.addEventListener(\"click\", () => {\n // Persist the label being edited before switching away from it.\n stage(activeLang);\n activeLang = lang;\n state.activeLang = lang;\n applyOverlay();\n labelInput.value = readCurrent(lang).label;\n renderTabs();\n });\n tabs.appendChild(tab);\n });\n };\n renderTabs();\n wrap.appendChild(tabs);\n }\n\n wrap.appendChild(makeLabelled(\"Label\", labelInput));\n wrap.appendChild(makeLabelled(\"URL\", hrefInput));\n\n const hint = document.createElement(\"div\");\n hint.style.cssText = `${hintStyles()} margin:-${v(\"space-1\")} 0 10px;`;\n hint.textContent =\n langs.length > 1\n ? \"Relative (/start), #anchor, mailto: and tel: all work. The URL is shared across languages.\"\n : \"Relative (/start), #anchor, mailto: and tel: all work.\";\n wrap.appendChild(hint);\n\n const warn = document.createElement(\"div\");\n // `danger` replaces a one-off `#f0a` magenta — this is the error colour used\n // everywhere else in the toolbar (failed upload, failed save).\n warn.style.cssText = `font-size:${v(\"text-xs\")};color:${v(\"danger\")}; margin:-${v(\"space-1\")} 0 10px; display:none;`;\n wrap.appendChild(warn);\n\n // Live preview on the page as the editor types. Writes to the label nodes,\n // NOT the anchor — setting textContent on the anchor would delete its icon.\n const paint = () => {\n labelNodes.forEach((n) => (n.textContent = labelInput.value));\n if (isSafeHrefValue(hrefInput.value)) anchorEl.setAttribute(\"href\", hrefInput.value);\n };\n\n /** Stage the current inputs as a pending change for `lang`. */\n const stage = (lang: string) => {\n const value: CanciaLinkValue = {\n label: labelInput.value,\n href: hrefInput.value.trim(),\n };\n const existing = parseLink(getValue(key, lang));\n if (existing.label !== value.label || existing.href !== value.href) {\n setPending(key, lang, JSON.stringify(value));\n }\n };\n\n const validate = (): boolean => {\n const ok = isSafeHrefValue(hrefInput.value);\n warn.style.display = ok ? \"none\" : \"block\";\n warn.textContent = ok ? \"\" : \"That URL scheme isn’t allowed and won’t be saved.\";\n return ok;\n };\n\n labelInput.addEventListener(\"input\", () => {\n paint();\n onPendingChange();\n });\n hrefInput.addEventListener(\"input\", () => {\n validate();\n paint();\n onPendingChange();\n });\n\n setTimeout(() => labelInput.focus(), 80);\n\n // Footer\n const footer = document.createElement(\"div\");\n footer.dataset.canciaFooter = \"1\";\n footer.style.cssText = `display: flex; justify-content: flex-end; margin-top: 10px;`;\n\n const saveBtn = makePrimaryButton(\"Save\", accent());\n saveBtn.dataset.canciaSave = \"1\";\n saveBtn.title = \"Save (⌘S)\";\n saveBtn.addEventListener(\"click\", () => {\n // Refuse to persist an unsafe scheme — the schema rejects it server-side\n // too, but failing here tells the editor why instead of silently dropping.\n if (!validate()) return;\n stage(activeLang);\n onPendingChange();\n onClose();\n });\n\n footer.appendChild(saveBtn);\n wrap.appendChild(footer);\n\n return wrap;\n}\n\nfunction buildImagePopup(\n key: string,\n anchorEl: HTMLElement,\n onClose: () => void\n): HTMLElement {\n const wrap = document.createElement(\"div\");\n wrap.dataset.canciaPopup = \"1\";\n applyPopupStyles(wrap);\n wrap.appendChild(buildHeader(key, onClose));\n\n // Current image preview\n const currentSrc = anchorEl.tagName === \"IMG\"\n ? (anchorEl as HTMLImageElement).src\n : anchorEl.querySelector(\"img\")?.src ?? \"\";\n\n if (currentSrc && !currentSrc.startsWith(\"data:\")) {\n const previewWrap = document.createElement(\"div\");\n previewWrap.style.cssText = `\n border-radius: ${v(\"radius\")}; overflow: hidden; margin-bottom: 10px;\n border: 1px solid ${v(\"border\")};\n position: relative; height: 100px;\n `;\n const previewImg = document.createElement(\"img\");\n previewImg.src = currentSrc;\n previewImg.style.cssText = `width: 100%; height: 100%; object-fit: cover; display: block;`;\n const previewLabel = document.createElement(\"div\");\n previewLabel.textContent = \"Current\";\n // The scrim gradient stays literal: a black-to-transparent overlay for\n // legibility over an arbitrary photo is not a surface token.\n //\n // Its TEXT stays literal white too, and deliberately does NOT follow the\n // theme flip. This label sits on the photo, not on our chrome — the\n // surface beneath it is whatever the client uploaded, so `fg-muted`\n // (now a mid grey for white backgrounds) would be illegible over a dark\n // image. White-on-scrim is correct in both themes.\n previewLabel.style.cssText = `\n position: absolute; bottom: 0; left: 0; right: 0;\n font-size: 10px; color: rgba(255,255,255,0.85); letter-spacing: 0.04em;\n padding: ${v(\"space-4\")} ${v(\"space-2\")} 6px;\n background: linear-gradient(transparent, rgba(0,0,0,0.55));\n `;\n previewWrap.appendChild(previewImg);\n previewWrap.appendChild(previewLabel);\n wrap.appendChild(previewWrap);\n }\n\n // Drop zone — clean, minimal\n const dropZone = document.createElement(\"label\");\n dropZone.style.cssText = `\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n gap: ${v(\"space-2\")};\n border: 1.5px dashed ${v(\"border-strong\")}; border-radius: ${v(\"radius\")};\n padding: ${v(\"space-6\")} ${v(\"space-5\")};\n cursor: pointer;\n transition: border-color ${v(\"duration-fast\")} ${v(\"ease\")}, background ${v(\"duration-fast\")} ${v(\"ease\")};\n background: ${v(\"surface-raised\")};\n `;\n\n // Simple arrow-up icon, no container box\n const uploadIcon = document.createElement(\"div\");\n uploadIcon.style.cssText = `color: ${v(\"fg-muted\")}; transition: color ${v(\"duration-fast\")} ${v(\"ease\")};`;\n uploadIcon.innerHTML = `<svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12 15V3m0 0L8 7m4-4l4 4M2 17l.621 2.485A2 2 0 004.561 21h14.878a2 2 0 001.94-1.515L22 17\"/>\n </svg>`;\n\n const dropText = document.createElement(\"div\");\n dropText.style.cssText = `text-align: center;`;\n dropText.innerHTML = `\n <div style=\"font-size:${v(\"text-sm\")};font-weight:500;color:${v(\"fg-muted\")};\">Drop an image</div>\n <div style=\"font-size:${v(\"text-xs\")};color:${v(\"fg-faint\")};margin-top:2px;\">or click to browse</div>\n `;\n\n dropZone.appendChild(uploadIcon);\n dropZone.appendChild(dropText);\n\n const fileInput = document.createElement(\"input\");\n fileInput.type = \"file\";\n fileInput.accept = \"image/*\";\n fileInput.style.display = \"none\";\n dropZone.appendChild(fileInput);\n\n // Status area\n const statusWrap = document.createElement(\"div\");\n statusWrap.style.cssText = `margin-top: ${v(\"space-2\")}; min-height: 18px;`;\n\n const statusMsg = document.createElement(\"p\");\n statusMsg.style.cssText = `font-size: ${v(\"text-xs\")}; color: ${v(\"fg-muted\")}; margin: 0; text-align: center; transition: color ${v(\"duration\")} ${v(\"ease\")};`;\n\n const progressBar = document.createElement(\"div\");\n progressBar.style.cssText = `\n height: 2px; border-radius: 2px; background: ${v(\"surface-raised\")};\n overflow: hidden; margin-top: 6px; display: none;\n `;\n const progressFill = document.createElement(\"div\");\n progressFill.style.cssText = `\n height: 100%; border-radius: 2px; background: ${v(\"accent\")};\n width: 0%; transition: width ${v(\"duration-slow\")} ${v(\"ease-out\")};\n `;\n progressBar.appendChild(progressFill);\n statusWrap.appendChild(statusMsg);\n statusWrap.appendChild(progressBar);\n\n const handleFile = async (file: File) => {\n if (!file.type.startsWith(\"image/\")) {\n statusMsg.textContent = \"Only image files are supported\";\n statusMsg.style.color = v(\"danger\");\n return;\n }\n const maxMb = 10;\n if (file.size > maxMb * 1024 * 1024) {\n statusMsg.textContent = `File too large (max ${maxMb}MB)`;\n statusMsg.style.color = v(\"danger\");\n return;\n }\n // accent-ring / accent-soft are the derived alpha variants; the old\n // `${accent()}55` + `${accent()}0a` concatenation broke for non-hex accents.\n dropZone.style.borderColor = v(\"accent-ring\");\n dropZone.style.background = v(\"accent-soft\");\n uploadIcon.style.color = v(\"accent\");\n statusMsg.textContent = \"Uploading…\";\n statusMsg.style.color = v(\"fg-muted\");\n progressBar.style.display = \"block\";\n progressFill.style.width = \"0%\";\n\n try {\n const url = await uploadImage(file, (percent) => {\n progressFill.style.width = `${percent}%`;\n });\n progressFill.style.width = \"100%\";\n setPending(key, state.activeLang, url);\n onPendingChange();\n\n if (anchorEl.tagName === \"IMG\") {\n const img = anchorEl as HTMLImageElement;\n img.srcset = \"\";\n img.src = url;\n } else {\n const img = document.createElement(\"img\");\n img.src = url;\n img.alt = \"\";\n img.style.cssText = \"width:100%;height:100%;object-fit:cover;display:block;\";\n img.dataset.cms = key;\n anchorEl.replaceWith(img);\n }\n\n setTimeout(() => {\n statusMsg.textContent = \"Done\";\n statusMsg.style.color = v(\"success\");\n setTimeout(onClose, 600);\n }, 200);\n } catch {\n progressBar.style.display = \"none\";\n statusMsg.textContent = \"Upload failed — try again\";\n statusMsg.style.color = v(\"danger\");\n dropZone.style.borderColor = v(\"border-strong\");\n dropZone.style.background = v(\"surface-raised\");\n uploadIcon.style.color = v(\"fg-muted\");\n }\n };\n\n fileInput.addEventListener(\"change\", () => {\n if (fileInput.files?.[0]) handleFile(fileInput.files[0]);\n });\n\n dropZone.addEventListener(\"dragover\", (e) => {\n e.preventDefault();\n if (!dragover) {\n dragover = true;\n dropZone.style.borderColor = v(\"accent-ring\");\n dropZone.style.background = v(\"accent-soft\");\n uploadIcon.style.color = v(\"accent\");\n }\n });\n dropZone.addEventListener(\"dragleave\", () => {\n dragover = false;\n dropZone.style.borderColor = v(\"border-strong\");\n dropZone.style.background = v(\"surface-raised\");\n uploadIcon.style.color = v(\"fg-muted\");\n });\n dropZone.addEventListener(\"drop\", (e) => {\n e.preventDefault();\n dragover = false;\n dropZone.style.borderColor = v(\"border-strong\");\n dropZone.style.background = v(\"surface-raised\");\n const file = e.dataTransfer?.files[0];\n if (file) handleFile(file);\n });\n\n dropZone.addEventListener(\"mouseenter\", () => {\n if (!dragover) {\n dropZone.style.borderColor = v(\"border-strong\");\n dropZone.style.background = v(\"surface-hover\");\n }\n });\n dropZone.addEventListener(\"mouseleave\", () => {\n if (!dragover) {\n dropZone.style.borderColor = v(\"border-strong\");\n dropZone.style.background = v(\"surface-raised\");\n }\n });\n\n wrap.appendChild(dropZone);\n wrap.appendChild(statusWrap);\n\n return wrap;\n}\n\n// ---------------------------------------------------------------------------\n// Shared UI helpers\n// ---------------------------------------------------------------------------\n\nexport function makeCloseButton(onClose: () => void): HTMLButtonElement {\n const btn = document.createElement(\"button\");\n btn.style.cssText = `\n display: flex; align-items: center; justify-content: center;\n width: 24px; height: 24px; border-radius: ${v(\"radius-sm\")}; flex-shrink: 0;\n background: ${v(\"surface-raised\")}; border: 1px solid ${v(\"border\")};\n cursor: pointer; color: ${v(\"fg-muted\")}; padding: 0;\n transition: background ${v(\"duration-fast\")} ${v(\"ease\")}, color ${v(\"duration-fast\")} ${v(\"ease\")};\n `;\n btn.innerHTML = `<svg width=\"9\" height=\"9\" viewBox=\"0 0 10 10\" fill=\"none\">\n <path d=\"M1 1l8 8M9 1L1 9\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>`;\n // attachHover captures the inline background/colour set above as the resting\n // state, so leave/enter restore exactly what was rendered.\n attachHover(btn, { color: v(\"fg\") });\n btn.addEventListener(\"click\", onClose);\n return btn;\n}\n\nexport function makePrimaryButton(label: string, color: string): HTMLButtonElement {\n const btn = document.createElement(\"button\");\n markUi(btn);\n btn.textContent = label;\n // The neutral primary fill: `accent` on `accent-fg`. On the light theme that\n // is near-black on white — the exact inverse of the white-on-near-black pill\n // this was before, and the same treatment the pending bar's Save uses, so\n // every \"commit\" button in the editor is one button.\n //\n // The `color` parameter remains unused (it predates the token system and is\n // kept only so the two call sites don't have to change); the fill comes from\n // the token, deliberately NOT from the site's brand colour.\n btn.style.cssText = `\n padding: 7px ${v(\"space-4\")}; border-radius: ${v(\"radius-sm\")}; border: none; cursor: pointer;\n background: ${v(\"accent\")}; color: ${v(\"accent-fg\")};\n font-size: ${v(\"text-sm\")}; font-weight: 600; letter-spacing: 0.01em;\n transition: opacity ${v(\"duration-fast\")} ${v(\"ease\")}, transform ${v(\"duration-fast\")} ${v(\"ease\")};\n `;\n btn.addEventListener(\"mouseenter\", () => (btn.style.opacity = \"0.88\"));\n btn.addEventListener(\"mouseleave\", () => (btn.style.opacity = \"1\"));\n // Respond on pointer-down rather than click — see attachPress().\n attachPress(btn);\n return btn;\n}\n\n// ---------------------------------------------------------------------------\n// Styles\n// ---------------------------------------------------------------------------\n\nfunction applyPopupStyles(el: HTMLElement) {\n markUi(el);\n // Opens with a TRANSITION, not the old `cancia-popup-in ... both` keyframe.\n //\n // A fill-mode animation keeps applying its end frame forever, and an inline\n // style cannot override it — so a rapid open/close/open race could strand the\n // popup at its FIRST frame (opacity 0, scale 0.93): present in the DOM,\n // taking clicks, and invisible. The same pattern caused a real bug in the\n // toolbar (see expand() in toolbar.ts). A transition has no fill mode,\n // nothing lingers, and it is interruptible mid-flight.\n //\n // The \"from\" state is set here; openPopup() commits it and flips to the\n // \"to\" state on the next frame, once transformOrigin is known.\n el.style.cssText = `\n ${surface(2)}\n position: absolute;\n z-index: ${v(\"z-panel\")};\n width: 320px;\n box-shadow: ${v(\"shadow-lg\")};\n padding: 14px;\n font-family: ${v(\"font\")};\n opacity: 0;\n transform: scale(0.93);\n transition: opacity ${v(\"duration\")} ${v(\"ease\")}, transform ${v(\"duration\")} ${v(\"ease\")};\n `;\n}\n\n// ---------------------------------------------------------------------------\n// Rich-text popup — a document, not a value\n// ---------------------------------------------------------------------------\n\n/**\n * The rich-text region editor.\n *\n * Structured block rows, deliberately the SAME model as the list surface's\n * richtext widget (entry-modal.ts): one textarea per block, a style select, a\n * list toggle, and inline emphasis via a small markdown shorthand. There is NO\n * contenteditable and NO raw HTML — that constraint is what makes the stored\n * value a validated Portable-Text subset rather than whatever a paste from Word\n * produced.\n *\n * Add / delete / reorder of ROWS is the point of this editor. It is where the\n * client's \"add a paragraph, remove this one\" freedom actually comes from —\n * every other inline field replaces one value in one slot.\n */\nfunction buildRichPopup(\n key: string,\n anchorEl: HTMLElement,\n onClose: () => void\n): HTMLElement {\n const langs = state.config?.languages ?? [\"en\"];\n let activeLang = state.activeLang || langs[0];\n\n const wrap = document.createElement(\"div\");\n wrap.dataset.canciaPopup = \"1\";\n applyPopupStyles(wrap);\n wrap.style.width = \"460px\";\n wrap.appendChild(buildHeader(key, onClose));\n\n const rowsWrap = document.createElement(\"div\");\n rowsWrap.style.cssText = `display: flex; flex-direction: column; gap: ${v(\"space-2\")}; max-height: 46vh; overflow-y: auto;`;\n wrap.appendChild(rowsWrap);\n\n interface Row {\n el: HTMLElement;\n read: () => RichTextRow;\n }\n let rows: Row[] = [];\n\n /**\n * The initial rows for a language.\n *\n * When there is no stored override we seed from the element's CURRENT text,\n * because the page is at that moment rendering its authored markup — that is\n * the fallback, and editing should start from what the client can see rather\n * than from an empty box.\n */\n function initialRows(): RichTextRow[] {\n const stored = getValue(key, activeLang);\n if (stored) {\n const blocks = parseRichValue(stored);\n if (blocks && blocks.length) return portableTextToRows(blocks);\n if (blocks && blocks.length === 0) return [{ text: \"\", style: \"normal\" }];\n }\n // No override: the page is rendering the markup authored in the .astro\n // file, so read THAT — paragraphs, headings, lists and inline emphasis all\n // survive into the editor. Seeding from textContent instead collapsed every\n // paragraph into one row and dropped every bold/italic/link, so the first\n // save destroyed formatting the client was looking at.\n const authored = domToRows(anchorEl) as RichTextRow[];\n return authored.length ? authored : [{ text: \"\", style: \"normal\" }];\n }\n\n function makeRow(initial: RichTextRow): Row {\n const row = document.createElement(\"div\");\n row.style.cssText = `display: flex; gap: 6px; align-items: flex-start;`;\n\n const main = document.createElement(\"div\");\n main.style.cssText = `flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px;`;\n\n const ta = document.createElement(\"textarea\");\n ta.value = initial.text;\n ta.rows = 2;\n ta.placeholder = \"Text — **bold**, *italic*, [label](https://…)\";\n ta.style.cssText = `\n ${inputStyles()}\n border-radius: ${v(\"radius\")};\n padding: 8px 10px;\n font-family: inherit; resize: vertical;\n min-height: 46px; line-height: 1.55;\n `;\n attachInputFocus(ta);\n ta.addEventListener(\"input\", commit);\n\n const controls = document.createElement(\"div\");\n controls.style.cssText = `display: flex; gap: 6px;`;\n\n const styleSel = document.createElement(\"select\");\n styleSel.style.cssText = `${inputStyles()} width: auto; flex: 1; padding: 4px 8px; font-size: ${v(\"text-xs\")}; cursor: pointer;`;\n for (const [value, labelText] of [\n [\"normal\", \"Normal\"],\n [\"h2\", \"Heading 2\"],\n [\"h3\", \"Heading 3\"],\n [\"blockquote\", \"Quote\"],\n ] as const) {\n const o = document.createElement(\"option\");\n o.value = value;\n o.textContent = labelText;\n if (initial.style === value) o.selected = true;\n styleSel.appendChild(o);\n }\n styleSel.addEventListener(\"change\", commit);\n\n const listSel = document.createElement(\"select\");\n listSel.style.cssText = styleSel.style.cssText;\n for (const [value, labelText] of [\n [\"\", \"No list\"],\n [\"bullet\", \"Bulleted\"],\n [\"number\", \"Numbered\"],\n ] as const) {\n const o = document.createElement(\"option\");\n o.value = value;\n o.textContent = labelText;\n if ((initial.listItem ?? \"\") === value) o.selected = true;\n listSel.appendChild(o);\n }\n listSel.addEventListener(\"change\", commit);\n\n controls.appendChild(styleSel);\n controls.appendChild(listSel);\n main.appendChild(ta);\n main.appendChild(controls);\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.type = \"button\";\n removeBtn.textContent = \"×\";\n removeBtn.title = \"Remove this block\";\n removeBtn.style.cssText = `\n ${button(\"ghost\")}\n flex-shrink: 0; height: auto; padding: 6px 9px;\n font-size: 15px; line-height: 1; color: ${v(\"fg-faint\")};\n `;\n attachHover(removeBtn);\n removeBtn.addEventListener(\"click\", () => {\n // Never leave zero rows: an empty editor gives the client nothing to type\n // into and no obvious way back. Clearing the last row is the same intent\n // and stays reversible.\n if (rows.length === 1) {\n ta.value = \"\";\n commit();\n return;\n }\n rows = rows.filter((r) => r.el !== row);\n row.remove();\n commit();\n });\n\n row.appendChild(main);\n row.appendChild(removeBtn);\n\n return {\n el: row,\n read: () => {\n const listItem = listSel.value as \"\" | PtListItem;\n return {\n text: ta.value,\n style: styleSel.value as PtStyle,\n ...(listItem ? { listItem } : {}),\n };\n },\n };\n }\n\n /** Serialise the rows, stage them as pending, and live-preview on the page. */\n function commit(): void {\n const docRows = rows.map((r) => r.read());\n // A document of nothing but empty text is a deliberately-empty region: it\n // stores \"\" and renders nothing, which is the client hiding this prose.\n const meaningful = docRows.filter((r) => r.text.trim() !== \"\");\n const blocks = meaningful.length ? rowsToPortableText(meaningful) : [];\n\n setPending(key, activeLang, serializeRichValue(blocks));\n onPendingChange();\n renderRichToDom(anchorEl, blocks);\n }\n\n function renderRows(): void {\n rowsWrap.replaceChildren();\n rows = initialRows().map(makeRow);\n for (const r of rows) rowsWrap.appendChild(r.el);\n }\n\n if (langs.length > 1) {\n const tabs = document.createElement(\"div\");\n tabs.style.cssText = `display: flex; gap: 0; margin-bottom: ${v(\"space-3\")}; border-bottom: 1px solid ${v(\"border\")};`;\n const renderTabs = () => {\n tabs.replaceChildren();\n for (const lang of langs) {\n const isActive = lang === activeLang;\n const tab = document.createElement(\"button\");\n tab.textContent = lang.toUpperCase();\n tab.style.cssText = `\n padding: 5px 10px 6px; border: none; border-bottom: 2px solid;\n margin-bottom: -1px;\n font-size: ${v(\"text-xs\")}; font-weight: 600; cursor: pointer; letter-spacing: 0.06em;\n background: transparent;\n border-bottom-color: ${isActive ? v(\"accent\") : \"transparent\"};\n color: ${isActive ? v(\"fg-strong\") : v(\"fg-faint\")};\n `;\n tab.addEventListener(\"click\", () => {\n commit();\n activeLang = lang;\n state.activeLang = lang;\n applyOverlay();\n renderTabs();\n renderRows();\n });\n tabs.appendChild(tab);\n }\n };\n renderTabs();\n wrap.insertBefore(tabs, rowsWrap);\n }\n\n renderRows();\n\n const footer = document.createElement(\"div\");\n footer.dataset.canciaFooter = \"1\";\n footer.style.cssText = `display: flex; justify-content: space-between; align-items: center; gap: ${v(\"space-2\")}; margin-top: 10px;`;\n\n const addBtn = document.createElement(\"button\");\n addBtn.type = \"button\";\n addBtn.textContent = \"+ Add block\";\n addBtn.style.cssText = `${button(\"ghost\")} font-size: ${v(\"text-xs\")};`;\n attachHover(addBtn);\n attachPress(addBtn);\n addBtn.addEventListener(\"click\", () => {\n const r = makeRow({ text: \"\", style: \"normal\" });\n rows.push(r);\n rowsWrap.appendChild(r.el);\n r.el.querySelector(\"textarea\")?.focus();\n });\n\n const saveBtn = makePrimaryButton(\"Save\", accent());\n saveBtn.dataset.canciaSave = \"1\";\n saveBtn.title = \"Save (⌘S)\";\n saveBtn.addEventListener(\"click\", () => {\n commit();\n onClose();\n });\n\n footer.appendChild(addBtn);\n footer.appendChild(saveBtn);\n wrap.appendChild(footer);\n\n return wrap;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport function openPopup(\n key: string,\n fieldType: CanciaFieldType,\n anchorEl: HTMLElement,\n onClose: () => void\n) {\n closePopup();\n\n const done = () => { onClose(); closePopup(); };\n const popup =\n fieldType === \"image\"\n ? buildImagePopup(key, anchorEl, done)\n : fieldType === \"link\"\n ? buildLinkPopup(key, anchorEl, done)\n : fieldType === \"richtext\"\n ? buildRichPopup(key, anchorEl, done)\n : buildTextPopup(key, anchorEl, done);\n\n document.body.appendChild(popup);\n popupEl = popup;\n\n const { top, left, origin } = getPopupPosition(anchorEl);\n popup.style.top = `${top}px`;\n popup.style.left = `${left}px`;\n // Scale from the TRIGGER, not the popup's own centre (apple-design §7): the\n // origin is the corner nearest the element that was clicked, so the popup\n // visibly grows out of the thing it belongs to. getPopupPosition already\n // computes which corner that is, flipping it when the popup is repositioned\n // to stay on screen.\n popup.style.transformOrigin = origin;\n\n // Commit the \"from\" state, then transition in on the next frame.\n requestAnimationFrame(() => {\n popup.style.opacity = \"1\";\n popup.style.transform = \"scale(1)\";\n });\n\n // Click outside to close\n outsideListener = (e: MouseEvent) => {\n if (!popup.contains(e.target as Node)) {\n closePopup();\n onClose();\n }\n };\n setTimeout(() => {\n if (outsideListener) document.addEventListener(\"click\", outsideListener, true);\n }, 100);\n\n // Keyboard shortcuts\n keyListener = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n closePopup();\n onClose();\n }\n if ((e.metaKey || e.ctrlKey) && e.key === \"s\") {\n e.preventDefault();\n popup.querySelector<HTMLButtonElement>(\"[data-cancia-save]\")?.click();\n }\n };\n document.addEventListener(\"keydown\", keyListener, true);\n}\n\nexport function closePopup() {\n if (outsideListener) {\n document.removeEventListener(\"click\", outsideListener, true);\n outsideListener = null;\n }\n if (keyListener) {\n document.removeEventListener(\"keydown\", keyListener, true);\n keyListener = null;\n }\n if (popupEl) {\n const el = popupEl;\n popupEl = null;\n // Exit along the SAME path it entered (apple-design §7): it scales back\n // down toward the same transformOrigin — the trigger — rather than sliding\n // off in an unrelated direction. `transformOrigin` is left as-is on\n // purpose. ease-out so the exit gets out of the way quickly.\n el.style.transition = `opacity ${v(\"duration-exit\")} ${v(\"ease-out\")}, transform ${v(\"duration-exit\")} ${v(\"ease-out\")}`;\n el.style.opacity = \"0\";\n el.style.transform = \"scale(0.93)\";\n setTimeout(() => el.remove(), 200);\n }\n}\n","// =============================================================================\n// Cancia Toolbar — List Panel\n// =============================================================================\n// Right-side slide-in panel that opens when the user clicks a [data-cms-list]\n// element. Per-locale: tabs at the top switch which locale's entries are\n// rendered. Entries that exist in other locales but not the active one are\n// shown as a \"not translated\" stub so the user can fill them in.\n// =============================================================================\n\nimport {\n fetchList,\n fetchTranslations,\n reorderList,\n type ListEntry,\n type ListSchemaDescription,\n type TranslationStatus,\n} from \"./api\";\nimport { state } from \"./state\";\nimport { v } from \"./tokens\";\nimport {\n injectBaseStyles,\n markUi,\n surface,\n button,\n iconButton,\n attachHover,\n} from \"./styles\";\n\n// NOTE: this panel is a LIGHT surface, the same family as the toolbar, the edit\n// popup and the entry drawer — the editor reads as one product. (It was dark\n// for one release; the whole chrome is now light. See the rationale on the\n// `tokens` export.) Every colour here comes from the token set; nothing is a\n// literal except where a value genuinely cannot resolve a `var()` — see the\n// scrim's own black rgba.\n//\n// This panel also HOSTS the entry form: \"Add entry\" slides the form in over the\n// list within this same surface rather than opening a second stacked modal.\n// See entry-modal.ts, which mounts into the [data-cancia-panel-stage] element\n// built below.\n//\n// The panel and its own scrim previously shared `z-panel`, which left their\n// stacking order to DOM insertion order. They are now explicitly separated.\nconst PANEL_Z = v(\"z-panel\");\n\n/**\n * Vertical space the panel keeps clear at its bottom edge for the floating\n * toolbar: the toolbar's 24px viewport inset, its ~52px height, and another\n * 24px of breathing room so a footer button never sits flush against it.\n */\nconst TOOLBAR_RESERVE = \"100px\";\nconst BACKDROP_Z = v(\"z-overlay\");\n\nlet panelEl: HTMLElement | null = null;\nlet backdropEl: HTMLElement | null = null;\nlet styleInjected = false;\n// Captured per-open so refreshListPanel() can re-fetch and re-render in place.\nlet currentSchema: ListSchemaDescription | null = null;\nlet currentBody: HTMLElement | null = null;\nlet currentTabsRow: HTMLElement | null = null;\nlet currentOnEditEntry: ((entry: ListEntry, locale: string) => void) | null = null;\nlet currentOnAddEntry: ((locale: string) => void) | null = null;\nlet currentOnTranslateEntry:\n | ((id: string, sourceEntry: ListEntry | null, targetLocale: string) => void)\n | null = null;\n\nfunction injectStyles() {\n if (styleInjected) return;\n styleInjected = true;\n // Tokens + scoped reset first, so this panel can reference var(--cancia-*).\n injectBaseStyles(state.config?.accentColor, state.config?.toolbarAccent === true);\n const s = document.createElement(\"style\");\n s.textContent = `\n @keyframes cancia-panel-in {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n }\n @keyframes cancia-panel-out {\n from { transform: translateX(0); }\n to { transform: translateX(100%); }\n }\n @keyframes cancia-backdrop-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n `;\n document.head.appendChild(s);\n}\n\n// The local accent() helper is gone: the accent now comes from the token sheet\n// (var(--cancia-accent)), which injectBaseStyles derives from config.accentColor.\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction formatExcerpt(value: unknown, maxLength = 120): string {\n const text = toPlainText(value);\n if (!text) return \"\";\n const trimmed = text.trim();\n if (trimmed.length <= maxLength) return trimmed;\n return trimmed.slice(0, maxLength).trimEnd() + \"…\";\n}\n\n/**\n * Flatten a stored field value to a plain-text preview string. Handles plain\n * strings and Portable-Text SUBSET arrays (richtext) — for the latter, joins\n * the span texts across blocks. Anything else yields \"\".\n */\nfunction toPlainText(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (Array.isArray(value)) {\n // Portable-Text SUBSET blocks: { children: [{ text }] }.\n const parts: string[] = [];\n for (const block of value) {\n if (block && typeof block === \"object\" && Array.isArray((block as { children?: unknown }).children)) {\n for (const span of (block as { children: unknown[] }).children) {\n const t = (span as { text?: unknown })?.text;\n if (typeof t === \"string\") parts.push(t);\n }\n parts.push(\" \");\n }\n }\n return parts.join(\"\").replace(/\\s+/g, \" \").trim();\n }\n return \"\";\n}\n\n/**\n * Auto-derive a scannable preview for a list row (plan 025), NO schema config:\n * subtitle — the bodyField (richtext flattened / text stripped), else the\n * first text-ish scalar field after the title that has a value.\n * thumbnail — the value of the first image-widget field that holds a URL.\n * Both are best-effort and independently optional (a title-only row is fine).\n */\nfunction derivePreview(\n schema: ListSchemaDescription,\n data: Record<string, unknown>,\n): { subtitle: string; thumbnail: string } {\n // --- Subtitle ---\n let subtitle = \"\";\n if (schema.bodyField) subtitle = formatExcerpt(data[schema.bodyField]);\n if (!subtitle) {\n const TEXTISH = new Set([\"text\", \"textarea\", \"richtext\"]);\n for (const f of schema.fields) {\n if (f.name === schema.titleField) continue;\n if (!TEXTISH.has(f.widget)) continue;\n const s = formatExcerpt(data[f.name]);\n if (s) { subtitle = s; break; }\n }\n }\n\n // --- Thumbnail ---\n let thumbnail = \"\";\n for (const f of schema.fields) {\n if (f.widget !== \"image\") continue;\n const v = data[f.name];\n if (typeof v === \"string\" && v.trim()) { thumbnail = v.trim(); break; }\n }\n\n return { subtitle, thumbnail };\n}\n\nfunction locales(): string[] {\n return state.config?.languages ?? [];\n}\n\nfunction buildShell(schema: ListSchemaDescription): {\n panel: HTMLElement;\n body: HTMLElement;\n tabsRow: HTMLElement;\n} {\n const panel = document.createElement(\"div\");\n panel.dataset.canciaListPanel = \"1\";\n markUi(panel);\n // surface(2) is the panel layer (same step as the popup). Its rounded corners\n // and all-round border are overridden: this panel is flush to the viewport\n // edge, so only the leading edge carries a border, and the shadow is cast\n // leftward rather than the surface's default all-round elevation.\n // The panel runs the full height, but everything inside it reserves room at\n // the bottom for the floating toolbar (fixed bottom-right, 24px inset, ~52px\n // tall). Without that reserve a full-height panel puts its own Save/Cancel\n // footer directly UNDERNEATH the toolbar and the form's primary action\n // becomes unclickable — a bug that only appears once the form has a footer,\n // which is exactly when it matters most.\n panel.style.cssText = `\n ${surface(2)}\n position: fixed;\n top: 0; right: 0; bottom: 0;\n padding-bottom: ${TOOLBAR_RESERVE};\n width: min(420px, 100vw);\n color: ${v(\"fg\")};\n z-index: ${PANEL_Z};\n border: 0;\n border-left: 1px solid ${v(\"border\")};\n border-radius: 0;\n box-shadow: ${v(\"shadow-lg\")};\n display: flex;\n flex-direction: column;\n font-family: ${v(\"font\")};\n /* The fixed positioning above also makes this the containing block for the\n absolutely-positioned list view and the form view that slides in over\n it; overflow:hidden clips both while they are off-stage. */\n overflow: hidden;\n animation: cancia-panel-in ${v(\"duration\")} ${v(\"ease\")} forwards;\n `;\n\n // Everything below lives inside a \"list view\" wrapper. The form view is a\n // SIBLING of this, added on demand by the entry drawer — the two slide\n // horizontally past each other inside the panel. Keeping the list markup\n // untouched inside a wrapper means none of the entry rendering below had to\n // change to gain the drawer.\n const listView = document.createElement(\"div\");\n listView.dataset.canciaListView = \"1\";\n listView.style.cssText = `\n position: absolute; inset: 0;\n display: flex; flex-direction: column;\n transition: transform ${v(\"duration\")} ${v(\"ease\")}, opacity ${v(\"duration\")} ${v(\"ease\")};\n `;\n\n listView.innerHTML = `\n <header style=\"\n display: flex; align-items: center; justify-content: space-between;\n padding: ${v(\"space-4\")} ${v(\"space-5\")};\n border-bottom: 1px solid ${v(\"border\")};\n \">\n <div>\n <div style=\"font-size: ${v(\"text-xs\")}; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: ${v(\"fg-muted\")};\">List</div>\n <div style=\"font-size: 17px; font-weight: 600; margin-top: 2px; color: ${v(\"fg-strong\")};\">${escapeHtml(schema.label)}</div>\n </div>\n <button data-cancia-close style=\"\n ${iconButton()}\n appearance: none; border: 0; background: transparent;\n cursor: pointer;\n \" aria-label=\"Close panel\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\">\n <path d=\"M4 4l10 10M14 4L4 14\"/>\n </svg>\n </button>\n </header>\n <!-- No overflow-x here. This row holds one short tab per configured\n locale — two or three at most — so a scroll container was solving a\n problem that does not occur, while permanently costing a scrollbar\n gutter and (on Windows, where scrollbars are not overlaid) a visible\n bar under the tabs. If a site ever ships enough locales to overflow,\n wrapping is the right answer, not scrolling. -->\n <div data-cancia-tabs style=\"\n display: flex; flex-wrap: wrap; gap: ${v(\"space-1\")};\n padding: ${v(\"space-2\")} ${v(\"space-4\")} 0;\n border-bottom: 1px solid ${v(\"border\")};\n \"></div>\n <div style=\"padding: ${v(\"space-3\")} ${v(\"space-5\")}; border-bottom: 1px solid ${v(\"border\")};\">\n <button data-cancia-add style=\"\n ${button(\"ghost\")}\n appearance: none; border: 1px dashed ${v(\"border-strong\")}; background: ${v(\"accent-soft\")};\n color: ${v(\"accent\")}; font-weight: 600; font-size: ${v(\"text-base\")};\n padding: 10px 14px; height: auto; width: 100%; cursor: pointer;\n display: flex; align-items: center; justify-content: center; gap: 6px;\n \">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\">\n <path d=\"M7 2v10M2 7h10\"/>\n </svg>\n Add ${escapeHtml(schema.labelSingular.toLowerCase())}\n </button>\n </div>\n <div data-cancia-entries style=\"\n flex: 1; overflow-y: auto;\n padding: ${v(\"space-2\")} ${v(\"space-3\")} ${v(\"space-4\")};\n \">\n <div data-cancia-loading style=\"text-align: center; padding: 32px ${v(\"space-3\")}; color: ${v(\"fg-muted\")}; font-size: ${v(\"text-base\")};\">Loading…</div>\n </div>\n `;\n\n panel.appendChild(listView);\n\n const body = listView.querySelector(\"[data-cancia-entries]\") as HTMLElement;\n const tabsRow = listView.querySelector(\"[data-cancia-tabs]\") as HTMLElement;\n\n // Hover feedback for the two shell buttons. These are built via innerHTML\n // above (so they can't take attachHover inline), but the behaviour is the\n // shared one — no bespoke handlers.\n const closeBtn = listView.querySelector<HTMLElement>(\"[data-cancia-close]\");\n if (closeBtn) attachHover(closeBtn, { bg: v(\"surface-hover\"), color: v(\"fg-strong\") });\n const addBtn = listView.querySelector<HTMLElement>(\"[data-cancia-add]\");\n // accent-soft (not accent-ring) on hover: the add button already sits on an\n // accent-soft fill, so it deepens by one step rather than jumping to the\n // much stronger ring colour, which on the light theme reads as pressed.\n if (addBtn) attachHover(addBtn, { bg: v(\"accent-soft\") });\n\n return { panel, body, tabsRow };\n}\n\nfunction renderTabs(tabsRow: HTMLElement, activeLocale: string, onSwitch: (loc: string) => void) {\n tabsRow.innerHTML = \"\";\n const langs = locales();\n if (langs.length <= 1) {\n tabsRow.style.display = \"none\";\n return;\n }\n tabsRow.style.display = \"flex\";\n\n for (const loc of langs) {\n const tab = document.createElement(\"button\");\n const isActive = loc === activeLocale;\n tab.style.cssText = `\n appearance: none; border: 0; background: transparent;\n font-family: inherit; font-size: ${v(\"text-sm\")}; font-weight: 600;\n letter-spacing: 0.04em; text-transform: uppercase;\n padding: ${v(\"space-2\")} 10px 9px;\n cursor: ${isActive ? \"default\" : \"pointer\"};\n color: ${isActive ? v(\"accent\") : v(\"fg-muted\")};\n border-bottom: 2px solid ${isActive ? v(\"accent\") : \"transparent\"};\n margin-bottom: -1px;\n transition: color 0.12s, border-color 0.12s;\n `;\n tab.textContent = loc;\n if (!isActive) {\n // Colour-only hover: a tab has no background of its own, so attachHover\n // (which always writes a background) would paint a block behind it.\n tab.addEventListener(\"mouseenter\", () => { tab.style.color = v(\"fg-strong\"); });\n tab.addEventListener(\"mouseleave\", () => { tab.style.color = v(\"fg-muted\"); });\n tab.addEventListener(\"click\", () => onSwitch(loc));\n }\n tabsRow.appendChild(tab);\n }\n}\n\ninterface RenderRow {\n id: string;\n locale: string;\n entry: ListEntry | null;\n translatedFrom: string | null;\n}\n\nfunction renderEntries(\n body: HTMLElement,\n schema: ListSchemaDescription,\n activeLocale: string,\n entriesInLocale: ListEntry[],\n translations: TranslationStatus[],\n allEntries: Map<string, ListEntry[]>,\n) {\n const entryById = new Map<string, ListEntry>();\n for (const e of entriesInLocale) entryById.set(e.id, e);\n\n const orderedIds: string[] = entriesInLocale.map((e) => e.id);\n const seen = new Set(orderedIds);\n for (const t of translations) {\n if (!seen.has(t.id)) {\n orderedIds.push(t.id);\n seen.add(t.id);\n }\n }\n\n const rows: RenderRow[] = orderedIds.map((id) => {\n const entry = entryById.get(id) ?? null;\n let translatedFrom: string | null = null;\n if (!entry) {\n const t = translations.find((x) => x.id === id);\n if (t && t.locales.length > 0) translatedFrom = t.locales[0];\n }\n return { id, locale: activeLocale, entry, translatedFrom };\n });\n\n if (rows.length === 0) {\n body.innerHTML = `\n <div style=\"text-align: center; padding: 40px ${v(\"space-3\")}; color: ${v(\"fg-muted\")}; font-size: ${v(\"text-base\")};\">\n No entries yet. Click \"Add ${escapeHtml(schema.labelSingular.toLowerCase())}\" above to create one.\n </div>\n `;\n return;\n }\n\n body.innerHTML = \"\";\n\n // Drag-reorder state. Each rendered row gets a record so add/remove/reorder\n // stay in sync with the DOM. Reuses the same HTML5 drag mechanism as the\n // entry-modal array rows (plan 022): drag handle → dragover splice → drop.\n interface DragRec { wrap: HTMLElement; id: string }\n const dragRecs: DragRec[] = [];\n let dragging: DragRec | null = null;\n // Order snapshot captured at dragstart so a failed reorder can roll back to\n // exactly where it was before this drag.\n let orderBeforeDrag: string[] = [];\n\n // The FULL ordered id list — spans BOTH translated rows and \"not translated\"\n // stubs, because order is shared across locales and the store's reorder\n // DELETES any id NOT in the supplied list. We must always send every id.\n const currentOrder = (): string[] => dragRecs.map((r) => r.id);\n\n async function commitOrder(prevOrder: string[]): Promise<void> {\n try {\n await reorderList(schema.name, currentOrder());\n } catch {\n // Restore the previous DOM order on failure so nothing appears lost.\n const byId = new Map(dragRecs.map((r) => [r.id, r]));\n dragRecs.length = 0;\n for (const id of prevOrder) {\n const rec = byId.get(id);\n if (rec) { dragRecs.push(rec); body.appendChild(rec.wrap); }\n }\n // Surface a transient failure hint without nuking the list.\n const err = document.createElement(\"div\");\n err.textContent = \"Couldn't save the new order. Reverted.\";\n err.style.cssText = `text-align:center; padding:${v(\"space-2\")}; color:${v(\"danger\")}; font-size:${v(\"text-sm\")};`;\n body.insertBefore(err, body.firstChild);\n setTimeout(() => err.remove(), 3000);\n }\n }\n\n rows.forEach((row) => {\n const isStub = row.entry === null;\n\n // Row wrapper holds the drag handle + the clickable item side by side.\n const wrap = document.createElement(\"div\");\n wrap.style.cssText = `display: flex; align-items: stretch; gap: ${v(\"space-1\")}; margin-bottom: 6px;`;\n\n const handle = document.createElement(\"div\");\n handle.textContent = \"⋮⋮\";\n handle.title = \"Drag to reorder\";\n handle.draggable = true;\n handle.style.cssText = `\n cursor: grab; user-select: none;\n display: flex; align-items: center; justify-content: center;\n color: ${v(\"fg-faint\")}; font-size: ${v(\"text-base\")}; letter-spacing: -2px;\n padding: 0 2px; flex-shrink: 0;\n transition: color 0.12s;\n `;\n // The handle is the reorder affordance — it picks up the accent on hover so\n // it reads as draggable. Colour-only, so no attachHover (it has no bg).\n handle.addEventListener(\"mouseenter\", () => { handle.style.color = v(\"accent\"); });\n handle.addEventListener(\"mouseleave\", () => { handle.style.color = v(\"fg-faint\"); });\n\n const item = document.createElement(\"button\");\n item.style.cssText = `\n appearance: none; border: 1px solid transparent;\n background: ${isStub ? v(\"warning-soft\") : v(\"surface-raised\")};\n text-align: left; flex: 1; min-width: 0;\n padding: ${v(\"space-3\")} 14px; border-radius: ${v(\"radius-sm\")}; cursor: pointer;\n transition: background 0.12s, border-color 0.12s, transform 0.12s;\n display: block;\n `;\n\n const rec: DragRec = { wrap, id: row.id };\n\n handle.addEventListener(\"dragstart\", (e) => {\n dragging = rec;\n orderBeforeDrag = currentOrder();\n handle.style.cursor = \"grabbing\";\n wrap.style.opacity = \"0.5\";\n e.dataTransfer?.setData(\"text/plain\", \"\");\n if (e.dataTransfer) e.dataTransfer.effectAllowed = \"move\";\n });\n handle.addEventListener(\"dragend\", () => {\n handle.style.cursor = \"grab\";\n wrap.style.opacity = \"1\";\n dragging = null;\n });\n wrap.addEventListener(\"dragover\", (e) => {\n if (!dragging || dragging === rec) return;\n e.preventDefault();\n const rect = wrap.getBoundingClientRect();\n const after = e.clientY > rect.top + rect.height / 2;\n const from = dragRecs.indexOf(dragging);\n let to = dragRecs.indexOf(rec);\n if (from < 0 || to < 0) return;\n if (after) to += 1;\n if (from < to) to -= 1;\n if (from === to) return;\n dragRecs.splice(from, 1);\n dragRecs.splice(to, 0, dragging);\n body.insertBefore(dragging.wrap, after ? wrap.nextSibling : wrap);\n });\n wrap.addEventListener(\"drop\", (e) => {\n if (!dragging) return;\n e.preventDefault();\n // Only persist if the order actually changed.\n const next = currentOrder();\n const changed = next.length !== orderBeforeDrag.length\n || next.some((id, i) => id !== orderBeforeDrag[i]);\n if (changed) void commitOrder(orderBeforeDrag);\n });\n\n if (row.entry) {\n const titleValue = row.entry.data[schema.titleField];\n const title =\n typeof titleValue === \"string\" && titleValue.trim().length > 0\n ? titleValue\n : `(untitled ${schema.labelSingular.toLowerCase()})`;\n const { subtitle, thumbnail } = derivePreview(schema, row.entry.data);\n // A draft is present in this panel but absent from the built site. Say\n // so on the row — otherwise the only feedback is the page not changing.\n const isDraftRow = !!schema.draftField && row.entry.data[schema.draftField] === true;\n const draftBadge = isDraftRow\n ? `<span style=\"\n flex-shrink: 0; margin-left: ${v(\"space-2\")}; padding: 1px 6px;\n font-size: 11px; font-weight: 600; line-height: 1.5;\n border-radius: ${v(\"radius-sm\")}; color: ${v(\"fg-muted\")};\n background: ${v(\"surface-raised\")}; border: 1px solid ${v(\"border\")};\n \">Draft</span>`\n : \"\";\n // NEVER innerHTML user text: title/subtitle are escapeHtml'd, and the\n // thumbnail URL goes through an escaped src attribute (escapeHtml escapes\n // the quote), so a crafted URL can't break out of the attribute.\n const textCol = `\n <div style=\"min-width: 0; flex: 1;\">\n <div style=\"display: flex; align-items: center;\">\n <span style=\"font-weight: 600; font-size: 14px; color: ${v(\"fg-strong\")}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\">${escapeHtml(title)}</span>${draftBadge}\n </div>\n ${subtitle ? `<div style=\"font-size: ${v(\"text-sm\")}; color: ${v(\"fg-muted\")}; margin-top: ${v(\"space-1\")}; line-height: 1.4;\">${escapeHtml(subtitle)}</div>` : \"\"}\n </div>\n `;\n const thumb = thumbnail\n ? `<img src=\"${escapeHtml(thumbnail)}\" alt=\"\" loading=\"lazy\" style=\"\n width: 44px; height: 44px; flex-shrink: 0; object-fit: cover;\n border-radius: ${v(\"radius-sm\")}; background: ${v(\"surface-raised\")}; border: 1px solid ${v(\"border\")};\n \" onerror=\"this.style.display='none'\" />`\n : \"\";\n item.innerHTML = `\n <div style=\"display: flex; align-items: center; gap: ${v(\"space-3\")};\">\n ${thumb}${textCol}\n </div>\n `;\n // Hover also lifts the border, which attachHover doesn't cover — so the\n // pair stays explicit rather than half-shared.\n item.addEventListener(\"mouseenter\", () => {\n item.style.background = v(\"surface-hover\");\n item.style.borderColor = v(\"border-strong\");\n });\n item.addEventListener(\"mouseleave\", () => {\n item.style.background = v(\"surface-raised\");\n item.style.borderColor = \"transparent\";\n });\n item.addEventListener(\"click\", () => currentOnEditEntry?.(row.entry!, activeLocale));\n } else {\n const sourceLocale = row.translatedFrom!;\n const sourceEntry =\n allEntries.get(sourceLocale)?.find((e) => e.id === row.id) ?? null;\n const sourceTitleValue = sourceEntry?.data[schema.titleField];\n const sourceTitle =\n typeof sourceTitleValue === \"string\" && sourceTitleValue.trim().length > 0\n ? sourceTitleValue\n : row.id;\n item.innerHTML = `\n <div style=\"display: flex; align-items: center; gap: ${v(\"space-2\")};\">\n <span style=\"\n font-size: 9px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;\n /* The light theme's warning token is a mid amber (#d97706), dark\n enough to carry WHITE text — so the chip now uses accent-fg and\n the near-black literal that used to live here is gone. */\n background: ${v(\"warning\")}; color: ${v(\"accent-fg\")};\n padding: 2px 6px; border-radius: 4px;\n \">Not translated</span>\n <span style=\"font-size: ${v(\"text-xs\")}; color: ${v(\"fg-muted\")};\">from ${escapeHtml(sourceLocale)}</span>\n </div>\n <div style=\"font-weight: 600; font-size: 14px; color: ${v(\"fg-strong\")}; margin-top: 6px;\">${escapeHtml(sourceTitle)}</div>\n <div style=\"font-size: ${v(\"text-xs\")}; color: ${v(\"warning\")}; margin-top: ${v(\"space-1\")};\">Click to translate into ${escapeHtml(activeLocale)}</div>\n `;\n // Hover stays in the amber family (a stub is a warning state, not an\n // accent one) — it just deepens and gains an amber edge. The literal\n // rgba is the warning hue at a hover alpha, deepened from warning-soft's\n // 0.10; no token expresses that intermediate step.\n item.addEventListener(\"mouseenter\", () => {\n item.style.background = \"rgba(217, 119, 6, 0.18)\";\n item.style.borderColor = v(\"warning\");\n });\n item.addEventListener(\"mouseleave\", () => {\n item.style.background = v(\"warning-soft\");\n item.style.borderColor = \"transparent\";\n });\n item.addEventListener(\"click\", () =>\n currentOnTranslateEntry?.(row.id, sourceEntry, activeLocale),\n );\n }\n\n wrap.appendChild(handle);\n wrap.appendChild(item);\n dragRecs.push(rec);\n body.appendChild(wrap);\n });\n}\n\nexport interface OpenListPanelOptions {\n schema: ListSchemaDescription;\n /** Locale to start on. Defaults to state.activeLang. */\n initialLocale?: string;\n onAddEntry: (locale: string) => void;\n onEditEntry: (entry: ListEntry, locale: string) => void;\n /** Called when user clicks a \"not translated\" row. */\n onTranslateEntry: (id: string, sourceEntry: ListEntry | null, targetLocale: string) => void;\n}\n\nexport async function openListPanel(opts: OpenListPanelOptions): Promise<void> {\n closeListPanel();\n injectStyles();\n\n const backdrop = document.createElement(\"div\");\n backdrop.dataset.canciaPanelBackdrop = \"1\";\n markUi(backdrop);\n // A dim layer keeps its own black rgba; only the layering is tokenised.\n // Lightened from 0.32 → 0.20: the panel is now a light surface, so it no\n // longer needs a heavy scrim to separate itself from the page, and a dark\n // wash over a light site reads as much heavier than it did behind dark\n // chrome. Enough to push the page back, not enough to feel like a modal.\n backdrop.style.cssText = `\n position: fixed; inset: 0;\n background: rgba(10,10,12,0.20);\n z-index: ${BACKDROP_Z};\n animation: cancia-backdrop-in ${v(\"duration\")} ${v(\"ease-out\")} forwards;\n `;\n backdrop.addEventListener(\"click\", () => closeListPanel());\n document.body.appendChild(backdrop);\n backdropEl = backdrop;\n\n const { panel, body, tabsRow } = buildShell(opts.schema);\n document.body.appendChild(panel);\n panelEl = panel;\n currentSchema = opts.schema;\n currentBody = body;\n currentTabsRow = tabsRow;\n currentOnEditEntry = opts.onEditEntry;\n currentOnAddEntry = opts.onAddEntry;\n currentOnTranslateEntry = opts.onTranslateEntry;\n\n const langs = locales();\n const initial = opts.initialLocale ?? state.activeLang ?? langs[0] ?? \"\";\n state.activeListLocale = langs.includes(initial) ? initial : (langs[0] ?? initial);\n\n panel.querySelector<HTMLButtonElement>(\"[data-cancia-close]\")?.addEventListener(\n \"click\",\n () => closeListPanel(),\n );\n panel.querySelector<HTMLButtonElement>(\"[data-cancia-add]\")?.addEventListener(\n \"click\",\n () => currentOnAddEntry?.(state.activeListLocale),\n );\n\n await refreshListPanel();\n}\n\n/**\n * Re-fetch the current list and re-render the entries. No-op if the panel\n * isn't open. Called by the entry modal after a successful save/delete, and\n * by tab switches.\n */\nexport async function refreshListPanel(): Promise<void> {\n if (!panelEl || !currentSchema || !currentBody || !currentTabsRow) return;\n const schema = currentSchema;\n const body = currentBody;\n const tabsRow = currentTabsRow;\n\n renderTabs(tabsRow, state.activeListLocale, async (newLocale) => {\n state.activeListLocale = newLocale;\n await refreshListPanel();\n });\n\n try {\n const langs = locales();\n const [translations, ...perLocale] = await Promise.all([\n fetchTranslations(schema.name),\n ...langs.map((l) => fetchList(schema.name, l)),\n ]);\n if (!panelEl) return;\n const allEntries = new Map<string, ListEntry[]>();\n langs.forEach((l, i) => allEntries.set(l, perLocale[i] ?? []));\n const activeEntries = allEntries.get(state.activeListLocale) ?? [];\n renderEntries(body, schema, state.activeListLocale, activeEntries, translations, allEntries);\n } catch (err) {\n if (!panelEl) return;\n body.innerHTML = `\n <div style=\"text-align: center; padding: 32px ${v(\"space-3\")}; color: ${v(\"danger\")}; font-size: ${v(\"text-base\")};\">\n Failed to load entries: ${escapeHtml(err instanceof Error ? err.message : String(err))}\n </div>\n `;\n }\n}\n\nexport function closeListPanel(): void {\n if (panelEl) {\n panelEl.style.animation = `cancia-panel-out ${v(\"duration-exit\")} ${v(\"ease-out\")} forwards`;\n const el = panelEl;\n setTimeout(() => el.remove(), 180);\n panelEl = null;\n }\n if (backdropEl) {\n const el = backdropEl;\n el.style.opacity = \"0\";\n el.style.transition = `opacity ${v(\"duration-exit\")} ${v(\"ease-out\")}`;\n setTimeout(() => el.remove(), 180);\n backdropEl = null;\n }\n currentSchema = null;\n currentBody = null;\n currentTabsRow = null;\n currentOnEditEntry = null;\n currentOnAddEntry = null;\n currentOnTranslateEntry = null;\n}\n\nexport function isListPanelOpen(): boolean {\n return panelEl !== null;\n}\n\n// ---------------------------------------------------------------------------\n// Drawer stage — the panel hosting the entry form in place\n// ---------------------------------------------------------------------------\n// The entry form used to be a centred modal on a dimmed page: a SECOND stacked\n// surface for what is really a continuation of the same task (\"I am working on\n// this list\"). Now the form slides into THIS panel, over the list, and a back\n// arrow returns. One surface, one place, no stacking.\n//\n// The mechanics live here rather than in entry-modal.ts because the panel owns\n// the geometry; the form only needs somewhere to mount. entry-modal.ts calls\n// pushPanelView() to slide its own element in and popPanelView() to reverse it.\n// If the panel ISN'T open (nothing currently does this, but the entry form is\n// callable independently), pushPanelView returns null and the form falls back\n// to its standalone centred presentation.\n\n/** The list view element, i.e. what the form slides in OVER. */\nfunction listViewEl(): HTMLElement | null {\n return panelEl?.querySelector<HTMLElement>(\"[data-cancia-list-view]\") ?? null;\n}\n\n/**\n * Slide `view` into the panel from the RIGHT, pushing the list out to the left.\n *\n * Both elements move along the same axis in the same direction, so the list\n * reads as being pushed aside rather than replaced — and popPanelView reverses\n * exactly this, which is what makes the pair feel like one surface scrolling\n * between two pages (apple-design §7: enter and exit along the same path).\n *\n * Returns false when there is no panel to mount into.\n */\nexport function pushPanelView(view: HTMLElement): boolean {\n const panel = panelEl;\n const list = listViewEl();\n if (!panel || !list) return false;\n\n view.style.position = \"absolute\";\n view.style.inset = \"0\";\n view.style.display = \"flex\";\n view.style.flexDirection = \"column\";\n view.style.background = v(\"surface-3\");\n // Start off-stage to the right. The transition is assigned in the same\n // statement as the start position, then committed with a forced reflow\n // before the \"to\" state — a transition (not a fill-mode animation) so a\n // rapid push/pop never strands the view mid-slide. See toolbar.ts expand().\n view.style.transform = \"translateX(100%)\";\n view.style.transition = `transform ${v(\"duration\")} ${v(\"ease\")}`;\n panel.appendChild(view);\n\n // Commit the \"from\" state before flipping to the \"to\" state.\n void view.offsetWidth;\n view.style.transform = \"translateX(0)\";\n\n // The list slides out the same way and dims slightly, so it reads as\n // receding behind the form rather than vanishing.\n //\n // It MUST carry the same transition as the incoming view. Without one the\n // list teleported to its off-stage position while the form slid in over it —\n // two halves of one movement running at different speeds, which is precisely\n // what made this transition feel broken. Elements that move as a unit have\n // to share easing and duration.\n //\n // Opacity is deliberately NOT animated to 0: fading the list out while it\n // translates makes it disappear before it has finished moving, which reads as\n // two separate effects. Dimming to 0.4 keeps it present but clearly behind.\n list.style.transition = `transform ${v(\"duration\")} ${v(\"ease\")}, opacity ${v(\"duration\")} ${v(\"ease\")}`;\n void list.offsetWidth;\n list.style.transform = \"translateX(-25%)\";\n list.style.opacity = \"0.4\";\n // It must not take clicks or keyboard focus while it is off-stage.\n list.setAttribute(\"aria-hidden\", \"true\");\n list.style.pointerEvents = \"none\";\n\n return true;\n}\n\n/**\n * Reverse pushPanelView: slide `view` back out to the right and bring the list\n * home. Removes `view` from the DOM once it is off-stage.\n */\nexport function popPanelView(view: HTMLElement): void {\n const list = listViewEl();\n\n // Exit runs on duration-exit — an exit should be faster than the entrance;\n // nobody wants to watch something leave. Both halves share it, for the same\n // reason they share it on the way in.\n view.style.transition = `transform ${v(\"duration-exit\")} ${v(\"ease-out\")}`;\n view.style.transform = \"translateX(100%)\";\n\n if (list) {\n list.style.transition = `transform ${v(\"duration-exit\")} ${v(\"ease-out\")}, opacity ${v(\"duration-exit\")} ${v(\"ease-out\")}`;\n list.style.transform = \"translateX(0)\";\n list.style.opacity = \"1\";\n list.removeAttribute(\"aria-hidden\");\n list.style.pointerEvents = \"\";\n }\n\n // Remove once the slide has finished. Prefer the real transitionend over a\n // fixed timeout — a hardcoded delay drifts out of sync the moment the\n // duration token changes, and under a throttled/background tab the timeout\n // can fire while the element is still visibly mid-slide. The timeout stays\n // only as a fallback for the case where no transition runs at all (reduced\n // motion zeroes the duration, so transitionend may never fire).\n let removed = false;\n const done = () => {\n if (removed) return;\n removed = true;\n view.remove();\n };\n view.addEventListener(\"transitionend\", done, { once: true });\n setTimeout(done, 400);\n}\n","// =============================================================================\n// Cancia Toolbar — Entry Form (in-panel drawer)\n// =============================================================================\n// The add/edit form for a list entry. It slides INTO the right-hand list panel,\n// over the list, rather than opening as a centred modal on a dimmed page.\n//\n// [ Blog posts ✕ ] [ ← New post ✕ ]\n// + Add blog post → Title [ ]\n// • Entry one Body [ ]\n// • Entry two [ Cancel ] [ Save ]\n//\n// Why: adding an entry is a CONTINUATION of \"I am working on this list\", not a\n// separate task. A stacked modal over a dimmed panel said otherwise — two\n// surfaces, two scrims, and the list you were working on greyed out behind the\n// thing you were doing to it. Sliding in place keeps one surface and one place,\n// and the back arrow makes \"how do I get out of here\" obvious (apple-design\n// §16: wayfinding). The panel owns the slide mechanics; see pushPanelView() /\n// popPanelView() in list-panel.ts.\n//\n// Layout (unchanged — only the shell it lives in moved):\n// ┌─ header (fixed) ─────────────────────────┐\n// │ ← back eyebrow + title close │\n// ├─ body (scrolls) ─────────────────────────┤\n// │ form fields… │\n// ├─ footer (fixed) ─────────────────────────┤\n// │ [Delete] [Cancel] [Save] │\n// └───────────────────────────────────────────┘\n//\n// Only the body scrolls. Header + footer are always visible, so Save and\n// Delete are always reachable regardless of how many fields the schema has.\n//\n// FALLBACK: when no list panel is open, the form still presents as a centred\n// modal with its own backdrop (the pre-drawer behaviour). Nothing in the app\n// currently opens it that way, but the entry points are public API.\n//\n// The exported names still say \"modal\" (openEntryModal / closeEntryModal /\n// isEntryModalOpen) — toolbar.ts imports them and this was a presentation\n// change, not an API change.\n// =============================================================================\n\nimport {\n createListEntry,\n updateListEntry,\n deleteListEntry,\n uploadImage,\n fetchList,\n type ListEntry,\n type ListSchemaDescription,\n type ListSchemaField,\n} from \"./api\";\nimport { state } from \"./state\";\nimport { makeCloseButton, makePrimaryButton } from \"./popup\";\nimport { pushPanelView, popPanelView, closeListPanel } from \"./list-panel\";\nimport { v } from \"./tokens\";\nimport {\n group,\n groupRow,\n injectBaseStyles,\n markUi,\n surface,\n button,\n iconButton as iconButtonStyle,\n input as inputStyle,\n label as labelStyle,\n hint,\n attachHover,\n attachPress,\n} from \"./styles\";\nimport {\n rowsToPortableText,\n portableTextToRows,\n portableTextSubsetSchema,\n PT_STYLES,\n type RichTextRow,\n type PtStyle,\n type PtListItem,\n} from \"@cancia/astro/richtext\";\nimport { slugify } from \"@cancia/astro/schema\";\n\nconst MODAL_Z = v(\"z-bar\");\nconst BACKDROP_Z = v(\"z-panel\");\n\nlet modalEl: HTMLElement | null = null;\nlet backdropEl: HTMLElement | null = null;\nlet escListener: ((e: KeyboardEvent) => void) | null = null;\nlet styleInjected = false;\n/**\n * True when the form is mounted INSIDE the list panel (the normal case), false\n * when it fell back to the standalone centred modal. Decides whether closing\n * slides back to the list or tears down a floating surface.\n */\nlet mountedInPanel = false;\n\n// ---------------------------------------------------------------------------\n// Styles — shared keyframes + focus styles for inputs inside the modal\n// ---------------------------------------------------------------------------\n\nfunction injectStyles() {\n if (styleInjected) return;\n styleInjected = true;\n // Tokens + scoped reset first, so the rules below can reference var(--cancia-*).\n injectBaseStyles(state.config?.accentColor, state.config?.toolbarAccent === true);\n const s = document.createElement(\"style\");\n // The `cancia-modal-in` / `cancia-modal-out` keyframes that used to live here\n // are gone: both the drawer and the fallback modal now animate with\n // TRANSITIONS. A fill-mode keyframe keeps applying its end frame forever and\n // can't be overridden inline, which strands an element at its first frame on\n // a fast open/close/open. See the note in toolbar.ts expand().\n s.textContent = `\n .cancia-form-input:focus,\n .cancia-form-textarea:focus,\n .cancia-form-select:focus {\n border-color: var(--cancia-accent-border, ${v(\"accent-ring\")});\n background: ${v(\"surface-hover\")};\n outline: none;\n }\n .cancia-form-input::placeholder,\n .cancia-form-textarea::placeholder {\n color: ${v(\"fg-faint\")};\n }\n .cancia-form-select option {\n /* An <option> is painted by the OS, so it cannot be translucent — this\n stays an opaque hex matching surface-3 (now white). */\n background: #ffffff;\n color: ${v(\"fg\")};\n }\n .cancia-field-error {\n color: ${v(\"danger\")};\n font-size: ${v(\"text-xs\")};\n margin-top: 5px;\n line-height: 1.35;\n }\n `;\n document.head.appendChild(s);\n}\n\nfunction accent(): string {\n // Matches the `accent` token default (near-black). See tokens.ts for why the\n // site's brand colour is no longer applied automatically.\n // Mirrors tokenCss()'s rule: the site's brand colour tints the editor\n // ONLY when a project opts in via `toolbarAccent`. Reading accentColor\n // unconditionally here would leave this surface brand-coloured while the\n // rest of the chrome is neutral.\n const useAccent = state.config?.toolbarAccent === true;\n return (useAccent ? state.config?.accentColor : undefined) ?? \"#18181b\";\n}\n\nfunction accentBorder(): string {\n const a = accent();\n if (/^#[0-9a-f]{6}$/i.test(a)) return `${a}99`;\n // Fallback matches accent-ring for the near-black default.\n return \"rgba(24,24,27,0.28)\";\n}\n\n/**\n * Turn a developer-written schema label into something a client can read.\n *\n * \"imageAlt\" -> \"Image alt\"\n * \"cta_primary\" -> \"Cta primary\"\n * \"URL slug\" -> \"URL slug\" (already prose: left alone)\n *\n * Deliberately conservative: it only reformats labels that look like\n * identifiers (single token, camelCase or snake_case). A label the developer\n * already wrote as a sentence is passed through untouched — second-guessing\n * real prose would do more harm than the identifiers do.\n */\n/**\n * Reveal a row's occasional affordances (drag handle, delete, block controls)\n * on hover or focus, and hide them otherwise.\n *\n * ONE function owns this per row. It previously lived in two places — one for\n * the handle/delete pair, one for the richtext selects — each with its own\n * hover and focus tracking, and the two disagreed: leaving a row could reveal\n * what entering it had not. A single flag on the row is the fix.\n *\n * Elements passed here keep their layout space (opacity/max-height, never\n * display) so nothing shifts as they appear. Focus always wins over pointer,\n * because losing the style dropdown mid-edit because the mouse drifted away\n * would be maddening — and because a keyboard user never hovers at all.\n */\nfunction attachRowReveal(row: HTMLElement, targets: HTMLElement[]): void {\n const apply = () => {\n const on =\n row.dataset.canciaHover === \"1\" || row.contains(document.activeElement);\n for (const t of targets) {\n t.style.opacity = on ? \"1\" : \"0\";\n if (t.dataset.canciaCollapsible === \"1\") {\n t.style.maxHeight = on ? \"40px\" : \"0\";\n }\n }\n };\n\n row.addEventListener(\"pointerenter\", () => {\n row.dataset.canciaHover = \"1\";\n apply();\n });\n row.addEventListener(\"pointerleave\", () => {\n row.dataset.canciaHover = \"0\";\n apply();\n });\n row.addEventListener(\"focusin\", apply);\n // focusout fires BEFORE the new element receives focus, so re-check on the\n // next tick rather than trusting activeElement in the handler itself.\n row.addEventListener(\"focusout\", () => requestAnimationFrame(apply));\n\n apply();\n}\n\nfunction humanise(label: string): string {\n if (!label) return label;\n // Contains a space already → treat as authored prose.\n if (/\\s/.test(label)) return label;\n\n // Known proper nouns that are camelCase by nature. Splitting \"linkedin\" into\n // \"Linked In\" is worse than leaving it: the point is to make labels readable,\n // and a mangled brand name reads as a typo. Matched case-insensitively on the\n // whole label only.\n const PROPER: Record<string, string> = {\n linkedin: \"LinkedIn\",\n github: \"GitHub\",\n youtube: \"YouTube\",\n tiktok: \"TikTok\",\n whatsapp: \"WhatsApp\",\n facebook: \"Facebook\",\n instagram: \"Instagram\",\n };\n const exact = PROPER[label.toLowerCase()];\n if (exact) return exact;\n\n const spaced = label\n .replace(/[_-]+/g, \" \")\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .trim();\n // Sentence case, but never lowercase an existing acronym (URL, SEO, ID).\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n// ---------------------------------------------------------------------------\n// Datetime helpers — ISO ⇄ datetime-local\n// ---------------------------------------------------------------------------\n\nfunction isoToLocalInput(iso: string): string {\n if (!iso) return \"\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return \"\";\n const pad = (n: number) => n.toString().padStart(2, \"0\");\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n}\n\nfunction localInputToIso(local: string): string {\n if (!local) return \"\";\n const d = new Date(local);\n if (Number.isNaN(d.getTime())) return \"\";\n return d.toISOString();\n}\n\n// ---------------------------------------------------------------------------\n// Field rendering — all inputs share the same dark style\n// ---------------------------------------------------------------------------\n\n// The `input()` primitive plus the bits this form's inputs genuinely add:\n// an explicit box-sizing/line-height (these render inside host pages that may\n// not inherit the scoped reset on every node) and a font-family of `inherit`.\nconst INPUT_BASE = `\n ${inputStyle()}\n box-sizing: border-box;\n font-family: inherit;\n line-height: 1.5;\n`;\n\n/**\n * The dropdown chevron, as a background image for our custom-styled <select>s.\n *\n * It lives in a data-URI, where `var()` cannot resolve — so the stroke is a\n * literal that must be kept in step with `fg-muted` by hand. It was white\n * (invisible on the light theme); it is now the same zinc grey as fg-muted.\n * Defined ONCE here because three selects previously repeated the whole URI\n * inline, which is how it came to be wrong in three places at once.\n */\nconst SELECT_CHEVRON =\n `url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'><path d='M2.5 3.75l2.5 2.5 2.5-2.5' stroke='%2371717a' stroke-width='1.3' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>\")`;\n\ninterface FieldState {\n field: ListSchemaField;\n getValue: () => unknown;\n setError: (msg: string | null) => void;\n /**\n * Validate this field (recursively, for array/object) and return whether it\n * passed. Scalar fields fall back to the shared required + constraint checks;\n * array/object branches override this to validate their children and paint\n * nested error slots. Populates/clears the field's own error UI as a side\n * effect. Returns the effective value (may be undefined when empty).\n */\n validate: () => { value: unknown; ok: boolean };\n /**\n * Slug auto-fill wiring (plan 025). Only set on plain text-ish inputs.\n * `onInput` lets a slug field subscribe to a source field's keystrokes;\n * `setValue` lets the slug field push an auto-derived value into its input.\n * Left undefined for composite/non-input widgets.\n */\n onInput?: (cb: () => void) => void;\n setValue?: (v: string) => void;\n}\n\n/**\n * Depth guard for nested array/object rendering. Client sites don't need deep\n * nesting; this stops a pathological schema from blowing the stack.\n */\nconst MAX_FIELD_DEPTH = 6;\n\nfunction renderField(\n field: ListSchemaField,\n initial: unknown,\n depth = 0,\n): { wrapper: HTMLElement; fieldState: FieldState } {\n const wrapper = document.createElement(\"div\");\n wrapper.style.cssText = `margin-bottom: ${v(\"space-4\")};`;\n\n // label() supplies the uppercase/tracking/colour; the row adds only its\n // flex layout, since a label here also hosts a trailing required marker.\n const labelRow = document.createElement(\"label\");\n labelRow.style.cssText = `\n ${labelStyle()}\n display: flex; align-items: baseline; justify-content: space-between;\n gap: ${v(\"space-2\")};\n margin-bottom: 5px;\n `;\n\n const labelText = document.createElement(\"span\");\n // Humanise: a schema label is written by a developer, and `imageAlt` or\n // `ctaPrimary` means nothing to the coach editing her own site. Split\n // camelCase, replace separators, sentence-case the result.\n labelText.textContent = humanise(field.label);\n // Mark the OPTIONAL fields, not the required ones.\n //\n // Most schemas make most fields required, so a \"Required\" tag on nearly every\n // row is noise: a marker that appears everywhere tells you nothing, and it\n // doubles the number of words on screen. Inverting it means a handful of\n // quiet \"Optional\" tags instead — and \"you may leave this blank\" is the more\n // useful thing to say, since required is what a form already implies.\n labelRow.appendChild(labelText);\n if (!field.required) {\n const opt = document.createElement(\"span\");\n opt.textContent = \"Optional\";\n opt.style.cssText = `\n font-size: ${v(\"text-xs\")}; font-weight: 400;\n color: ${v(\"fg-faint\")}; text-transform: none; letter-spacing: normal;\n `;\n labelRow.appendChild(opt);\n }\n // Array/object rows for an unnamed item (\"\") shouldn't show an empty label bar.\n if (field.label) wrapper.appendChild(labelRow);\n\n if (field.description) {\n const help = document.createElement(\"div\");\n help.style.cssText = `${hint()} margin-bottom: 6px;`;\n help.textContent = field.description;\n wrapper.appendChild(help);\n }\n\n const errorEl = document.createElement(\"div\");\n errorEl.className = \"cancia-field-error\";\n errorEl.style.display = \"none\";\n\n const setError = (msg: string | null) => {\n if (msg) {\n errorEl.textContent = msg;\n errorEl.style.display = \"block\";\n } else {\n errorEl.textContent = \"\";\n errorEl.style.display = \"none\";\n }\n };\n\n let getValue: () => unknown;\n // Array/object branches assign their own recursive validator. Anything that\n // leaves this null uses the shared scalar validator (required + constraints).\n let validate: (() => { value: unknown; ok: boolean }) | null = null;\n // Slug auto-fill hooks; assigned by the plain-input branches only.\n let onInput: ((cb: () => void) => void) | undefined;\n let setValue: ((v: string) => void) | undefined;\n\n switch (field.widget) {\n case \"array\": {\n const built = renderArrayField(field, initial, setError, depth);\n wrapper.appendChild(built.control);\n getValue = built.getValue;\n validate = built.validate;\n break;\n }\n\n case \"object\": {\n const built = renderObjectField(field, initial, setError, depth);\n wrapper.appendChild(built.control);\n getValue = built.getValue;\n validate = built.validate;\n break;\n }\n\n case \"reference\": {\n const built = renderReferenceField(field, initial);\n wrapper.appendChild(built.control);\n getValue = built.getValue;\n break;\n }\n\n case \"richtext\": {\n const built = renderRichTextField(field, initial, setError);\n wrapper.appendChild(built.control);\n getValue = built.getValue;\n validate = built.validate;\n break;\n }\n\n case \"textarea\": {\n const ta = document.createElement(\"textarea\");\n ta.className = \"cancia-form-textarea\";\n ta.style.cssText = `${INPUT_BASE} resize: vertical; min-height: 110px; max-height: 320px; caret-color: ${v(\"accent\")};`;\n ta.rows = 5;\n if (field.placeholder) ta.placeholder = field.placeholder;\n if (typeof initial === \"string\") ta.value = initial;\n wrapper.appendChild(ta);\n getValue = () => ta.value;\n break;\n }\n\n case \"checkbox\": {\n const row = document.createElement(\"label\");\n row.style.cssText = `display: flex; align-items: center; gap: 9px; cursor: pointer; user-select: none; padding: 6px 0;`;\n const cb = document.createElement(\"input\");\n cb.type = \"checkbox\";\n cb.style.cssText = `width: 16px; height: 16px; accent-color: ${v(\"accent\")};`;\n if (initial === true) cb.checked = true;\n const txt = document.createElement(\"span\");\n txt.style.cssText = `font-size: ${v(\"text-base\")}; color: ${v(\"fg\")};`;\n txt.textContent = field.placeholder ?? `Enable ${field.label.toLowerCase()}`;\n row.appendChild(cb);\n row.appendChild(txt);\n wrapper.appendChild(row);\n getValue = () => cb.checked;\n break;\n }\n\n case \"select\": {\n const sel = document.createElement(\"select\");\n sel.className = \"cancia-form-select\";\n sel.style.cssText = `${INPUT_BASE} appearance: none; padding-right: 30px; background-image: ${SELECT_CHEVRON}; background-repeat: no-repeat; background-position: right 10px center; cursor: pointer;`;\n if (!field.required) {\n const empty = document.createElement(\"option\");\n empty.value = \"\";\n empty.textContent = \"—\";\n sel.appendChild(empty);\n }\n for (const opt of field.options ?? []) {\n const o = document.createElement(\"option\");\n o.value = opt;\n o.textContent = opt;\n if (initial === opt) o.selected = true;\n sel.appendChild(o);\n }\n wrapper.appendChild(sel);\n getValue = () => (sel.value === \"\" ? undefined : sel.value);\n break;\n }\n\n case \"image\": {\n const initialUrl = typeof initial === \"string\" ? initial : \"\";\n let currentUrl = initialUrl;\n\n const container = document.createElement(\"div\");\n container.style.cssText = `\n display: flex; gap: 10px; align-items: stretch;\n background: ${v(\"surface-raised\")};\n border: 1px dashed ${v(\"border-strong\")};\n border-radius: ${v(\"radius\")};\n padding: 10px;\n `;\n\n const preview = document.createElement(\"div\");\n preview.style.cssText = `\n width: 72px; height: 72px; flex-shrink: 0;\n background: ${v(\"surface-raised\")} no-repeat center / cover;\n border: 1px solid ${v(\"border\")};\n border-radius: ${v(\"radius-sm\")};\n display: flex; align-items: center; justify-content: center;\n color: ${v(\"fg-faint\")};\n `;\n const updatePreview = (url: string) => {\n if (url) {\n preview.style.backgroundImage = `url(\"${url.replace(/\"/g, '\\\\\"')}\")`;\n preview.innerHTML = \"\";\n } else {\n preview.style.backgroundImage = \"\";\n preview.innerHTML = `<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><path d=\"M21 15l-5-5L5 21\"/></svg>`;\n }\n };\n updatePreview(initialUrl);\n\n const right = document.createElement(\"div\");\n right.style.cssText = `flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px;`;\n\n const fileInput = document.createElement(\"input\");\n fileInput.type = \"file\";\n fileInput.accept = \"image/*\";\n fileInput.style.display = \"none\";\n\n const btnRow = document.createElement(\"div\");\n btnRow.style.cssText = `display: flex; gap: 6px;`;\n\n const uploadBtn = document.createElement(\"button\");\n uploadBtn.type = \"button\";\n // A compact variant of the ghost button: shorter than the 30px default\n // because it sits inside the 72px-tall image row.\n uploadBtn.style.cssText = `\n ${button(\"ghost\")}\n background: ${v(\"surface-hover\")};\n color: ${v(\"fg\")};\n border: 1px solid ${v(\"border\")};\n height: auto;\n font-size: ${v(\"text-xs\")}; letter-spacing: 0.02em;\n padding: 5px 10px;\n cursor: pointer;\n `;\n uploadBtn.textContent = \"Upload…\";\n attachHover(uploadBtn, { bg: v(\"surface-active\") });\n uploadBtn.addEventListener(\"click\", () => fileInput.click());\n\n const clearBtn = document.createElement(\"button\");\n clearBtn.type = \"button\";\n clearBtn.style.cssText = `\n ${button(\"ghost\")}\n color: ${v(\"fg-muted\")};\n border: 1px solid transparent;\n height: auto;\n font-size: ${v(\"text-xs\")};\n padding: 5px 8px;\n cursor: pointer;\n `;\n clearBtn.textContent = \"Clear\";\n clearBtn.addEventListener(\"click\", () => {\n currentUrl = \"\";\n urlField.value = \"\";\n updatePreview(\"\");\n });\n\n btnRow.appendChild(uploadBtn);\n btnRow.appendChild(clearBtn);\n\n const urlField = document.createElement(\"input\");\n urlField.type = \"url\";\n urlField.className = \"cancia-form-input\";\n urlField.style.cssText = `${INPUT_BASE} font-size: ${v(\"text-xs\")}; padding: 6px 9px;`;\n urlField.placeholder = \"https://… or upload\";\n urlField.value = initialUrl;\n urlField.addEventListener(\"input\", () => {\n currentUrl = urlField.value.trim();\n updatePreview(currentUrl);\n });\n\n const progressEl = document.createElement(\"div\");\n // 10px is below the type scale (text-xs is 11px) — left literal.\n progressEl.style.cssText = `font-size: 10px; color: ${v(\"fg-muted\")}; height: 12px;`;\n\n right.appendChild(btnRow);\n right.appendChild(urlField);\n right.appendChild(progressEl);\n\n container.appendChild(preview);\n container.appendChild(right);\n container.appendChild(fileInput);\n wrapper.appendChild(container);\n\n fileInput.addEventListener(\"change\", async () => {\n const file = fileInput.files?.[0];\n if (!file) return;\n uploadBtn.disabled = true;\n progressEl.style.color = v(\"fg-muted\");\n try {\n const url = await uploadImage(file, (pct) => {\n progressEl.textContent = `Uploading… ${pct}%`;\n });\n currentUrl = url;\n urlField.value = url;\n updatePreview(url);\n progressEl.textContent = \"Uploaded\";\n setTimeout(() => { progressEl.textContent = \"\"; }, 1500);\n } catch (err) {\n progressEl.textContent = `Upload failed: ${err instanceof Error ? err.message : String(err)}`;\n progressEl.style.color = v(\"danger\");\n } finally {\n uploadBtn.disabled = false;\n fileInput.value = \"\";\n }\n });\n\n getValue = () => (currentUrl === \"\" ? undefined : currentUrl);\n break;\n }\n\n case \"datetime\": {\n const input = document.createElement(\"input\");\n input.type = \"datetime-local\";\n input.className = \"cancia-form-input\";\n // `color-scheme: light` pins the UA-painted calendar/clock icon to its\n // dark-on-light form. It is set EXPLICITLY rather than left to inherit,\n // because the host page may declare `color-scheme: dark` at the root —\n // which would give us a white icon on our white input.\n input.style.cssText = `${INPUT_BASE} color-scheme: light; caret-color: ${v(\"accent\")};`;\n if (typeof initial === \"string\") input.value = isoToLocalInput(initial);\n wrapper.appendChild(input);\n getValue = () => {\n const v = input.value.trim();\n if (!v) return undefined;\n return localInputToIso(v);\n };\n break;\n }\n\n case \"number\": {\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.className = \"cancia-form-input\";\n input.style.cssText = `${INPUT_BASE} caret-color: ${v(\"accent\")};`;\n if (field.min !== undefined) input.min = String(field.min);\n if (field.max !== undefined) input.max = String(field.max);\n if (typeof initial === \"number\") input.value = String(initial);\n else if (typeof initial === \"string\" && initial !== \"\") input.value = initial;\n wrapper.appendChild(input);\n getValue = () => {\n const v = input.value.trim();\n if (v === \"\") return undefined;\n const n = Number(v);\n return Number.isNaN(n) ? undefined : n;\n };\n break;\n }\n\n default: {\n // text | url | email | slug\n const input = document.createElement(\"input\");\n input.type = field.widget === \"url\" ? \"url\" : field.widget === \"email\" ? \"email\" : \"text\";\n input.className = \"cancia-form-input\";\n input.style.cssText = `${INPUT_BASE} caret-color: ${v(\"accent\")};`;\n if (field.placeholder) input.placeholder = field.placeholder;\n if (field.minLength !== undefined) input.minLength = field.minLength;\n if (field.maxLength !== undefined) input.maxLength = field.maxLength;\n if (typeof initial === \"string\") input.value = initial;\n wrapper.appendChild(input);\n getValue = () => input.value;\n // Expose keystroke subscription + value setter so slug auto-fill (below)\n // can react to a source field and push a derived slug into a slug input.\n onInput = (cb) => input.addEventListener(\"input\", cb);\n setValue = (v) => { input.value = v; };\n break;\n }\n }\n\n wrapper.appendChild(errorEl);\n\n // Scalar fields share the required + constraint validator; array/object\n // supplied their own recursive one above.\n const scalarValidate = (): { value: unknown; ok: boolean } => {\n const value = getValue();\n setError(null);\n if (field.required && (value === undefined || value === \"\" || value === null)) {\n setError(`${field.label || \"This field\"} is required`);\n return { value, ok: false };\n }\n const err = validateValue(field, value);\n if (err) {\n setError(err);\n return { value, ok: false };\n }\n return { value, ok: true };\n };\n\n return {\n wrapper,\n fieldState: { field, getValue, setError, validate: validate ?? scalarValidate, onInput, setValue },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Array + object branches (recursive)\n// ---------------------------------------------------------------------------\n\ninterface BuiltComposite {\n control: HTMLElement;\n getValue: () => unknown;\n validate: () => { value: unknown; ok: boolean };\n}\n\n/**\n * A repeatable list of `field.of` items. Each row is a full renderField of the\n * item schema plus a drag handle and a remove (×) button. Rows are tracked by a\n * live array of per-row records (not DOM index), so add/remove/reorder never\n * desync from their FieldState. Order is taken from live DOM order on collect.\n */\nfunction renderArrayField(\n field: ListSchemaField,\n initial: unknown,\n setOwnError: (msg: string | null) => void,\n depth: number,\n): BuiltComposite {\n const itemSchema = field.of;\n\n const container = document.createElement(\"div\");\n container.style.cssText = `\n ${group()}\n `;\n\n const rowsWrap = document.createElement(\"div\");\n rowsWrap.style.cssText = `display: flex; flex-direction: column; gap: ${v(\"space-2\")};`;\n container.appendChild(rowsWrap);\n\n if (!itemSchema || depth >= MAX_FIELD_DEPTH) {\n const note = document.createElement(\"div\");\n note.style.cssText = `font-size: ${v(\"text-xs\")}; color: ${v(\"fg-muted\")};`;\n note.textContent = itemSchema\n ? \"Nesting too deep to edit here.\"\n : \"This array has no item schema.\";\n container.appendChild(note);\n return { control: container, getValue: () => [], validate: () => ({ value: [], ok: true }) };\n }\n\n interface Row {\n el: HTMLElement;\n state: FieldState;\n }\n const rows: Row[] = [];\n\n // Drag-reorder: track the row being dragged; on dragover of another row,\n // splice it in before/after based on pointer position.\n let dragging: Row | null = null;\n\n function makeRow(itemValue: unknown): Row {\n const row = document.createElement(\"div\");\n row.style.cssText = `\n ${groupRow()}\n `;\n\n const handle = document.createElement(\"div\");\n handle.textContent = \"⋮⋮\";\n handle.title = \"Drag to reorder\";\n handle.draggable = true;\n // Faded until the row is hovered or focused, for the same reason as the\n // controls: reordering is occasional, writing is constant. It keeps its\n // space (opacity, not display) so nothing shifts when it appears.\n handle.style.cssText = `\n cursor: grab; user-select: none;\n color: ${v(\"fg-faint\")};\n font-size: ${v(\"text-base\")}; line-height: 1.2;\n padding: ${v(\"space-1\")} 2px; flex-shrink: 0;\n letter-spacing: -2px;\n opacity: 0;\n transition: opacity ${v(\"duration-fast\")} ${v(\"ease\")};\n `;\n\n const { wrapper, fieldState } = renderField(itemSchema!, itemValue, depth + 1);\n wrapper.style.marginBottom = \"0\";\n wrapper.style.flex = \"1\";\n wrapper.style.minWidth = \"0\";\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.type = \"button\";\n removeBtn.textContent = \"×\";\n removeBtn.title = \"Remove\";\n // 16px is a glyph size for the \"×\", not a type-scale step — left literal.\n removeBtn.style.cssText = `\n ${button(\"danger\")}\n flex-shrink: 0;\n border: 1px solid transparent;\n height: auto;\n font-size: 16px; line-height: 1;\n padding: 2px 7px;\n cursor: pointer;\n `;\n attachHover(removeBtn, { bg: v(\"danger-soft\") });\n\n // Reveal the row's affordances (drag handle, delete) on hover/focus. They\n // are occasional actions; the content is the constant one. Fading rather\n // than hiding keeps the layout stable — nothing shifts as they appear.\n attachRowReveal(row, [handle, removeBtn]);\n\n row.appendChild(handle);\n row.appendChild(wrapper);\n row.appendChild(removeBtn);\n\n const rec: Row = { el: row, state: fieldState };\n\n removeBtn.addEventListener(\"click\", () => {\n const i = rows.indexOf(rec);\n if (i >= 0) rows.splice(i, 1);\n row.remove();\n setOwnError(null);\n });\n\n handle.addEventListener(\"dragstart\", (e) => {\n dragging = rec;\n handle.style.cursor = \"grabbing\";\n row.style.opacity = \"0.5\";\n e.dataTransfer?.setData(\"text/plain\", \"\");\n if (e.dataTransfer) e.dataTransfer.effectAllowed = \"move\";\n });\n handle.addEventListener(\"dragend\", () => {\n handle.style.cursor = \"grab\";\n row.style.opacity = \"1\";\n dragging = null;\n });\n row.addEventListener(\"dragover\", (e) => {\n if (!dragging || dragging === rec) return;\n e.preventDefault();\n const rect = row.getBoundingClientRect();\n const after = e.clientY > rect.top + rect.height / 2;\n const from = rows.indexOf(dragging);\n let to = rows.indexOf(rec);\n if (from < 0 || to < 0) return;\n if (after) to += 1;\n if (from < to) to -= 1;\n if (from === to) return;\n rows.splice(from, 1);\n rows.splice(to, 0, dragging);\n // Reflect the new order in the DOM.\n rowsWrap.insertBefore(dragging.el, after ? row.nextSibling : row);\n });\n\n return rec;\n }\n\n function addRow(itemValue: unknown): void {\n const rec = makeRow(itemValue);\n rows.push(rec);\n rowsWrap.appendChild(rec.el);\n }\n\n const initialItems = Array.isArray(initial) ? initial : [];\n for (const it of initialItems) addRow(it);\n\n const addBtn = document.createElement(\"button\");\n addBtn.type = \"button\";\n const itemLabel = itemSchema.label || \"item\";\n addBtn.textContent = `+ Add ${itemLabel.toLowerCase()}`;\n addBtn.style.cssText = `\n ${button(\"ghost\")}\n align-self: flex-start;\n background: transparent;\n color: ${v(\"fg-muted\")};\n border: 0;\n height: auto;\n font-size: ${v(\"text-sm\")};\n font-weight: 500;\n padding: 4px 0;\n cursor: pointer;\n `;\n attachHover(addBtn, { bg: v(\"surface-active\") });\n addBtn.addEventListener(\"click\", () => addRow(defaultForField(itemSchema)));\n container.appendChild(addBtn);\n\n const collect = (): unknown[] => rows.map((r) => r.state.getValue());\n\n return {\n control: container,\n // Deleting the last item serialises to [] (not undefined) so a cleared\n // array persists as an empty array.\n getValue: () => collect(),\n validate: () => {\n setOwnError(null);\n let ok = true;\n for (const r of rows) {\n const res = r.state.validate();\n if (!res.ok) ok = false;\n }\n const value = collect();\n if (field.required && value.length === 0) {\n setOwnError(`${field.label || \"This list\"} needs at least one item`);\n ok = false;\n }\n return { value, ok };\n },\n };\n}\n\n/**\n * A nested group. Renders each sub-field with renderField and collects them\n * into a plain object keyed by sub-field name. Objects nest arrays and vice\n * versa because both go back through renderField.\n */\nfunction renderObjectField(\n field: ListSchemaField,\n initial: unknown,\n setOwnError: (msg: string | null) => void,\n depth: number,\n): BuiltComposite {\n const subFields = field.fields ?? [];\n const subInitial = (initial && typeof initial === \"object\" && !Array.isArray(initial))\n ? (initial as Record<string, unknown>)\n : {};\n\n const fieldset = document.createElement(\"div\");\n fieldset.style.cssText = `\n ${group()}\n gap: 2px;\n `;\n\n if (depth >= MAX_FIELD_DEPTH) {\n const note = document.createElement(\"div\");\n note.style.cssText = `font-size: ${v(\"text-xs\")}; color: ${v(\"fg-muted\")}; padding-bottom: 10px;`;\n note.textContent = \"Nesting too deep to edit here.\";\n fieldset.appendChild(note);\n return { control: fieldset, getValue: () => ({}), validate: () => ({ value: {}, ok: true }) };\n }\n\n const childStates: FieldState[] = [];\n for (const sub of subFields) {\n const { wrapper, fieldState } = renderField(sub, subInitial[sub.name], depth + 1);\n fieldset.appendChild(wrapper);\n childStates.push(fieldState);\n }\n\n const collect = (): Record<string, unknown> => {\n const out: Record<string, unknown> = {};\n for (const c of childStates) {\n const v = c.getValue();\n // Keep empty strings out, mirroring the top-level collector, but always\n // serialise the object itself (never undefined) so a group persists.\n if (v !== undefined && v !== \"\") out[c.field.name] = v;\n }\n return out;\n };\n\n return {\n control: fieldset,\n getValue: () => collect(),\n validate: () => {\n setOwnError(null);\n let ok = true;\n for (const c of childStates) {\n const res = c.validate();\n if (!res.ok) ok = false;\n }\n return { value: collect(), ok };\n },\n };\n}\n\n/**\n * A reference field: a native <select> whose options are the target list's\n * entries (label = the target's titleField value, value = the entry id). Stores\n * the chosen id as a plain string.\n *\n * Loading is async — the select renders immediately with a disabled \"Loading…\"\n * option (and, when editing, the current id preserved as a placeholder so\n * getValue never drops it while the fetch is in flight). Once the fetch\n * resolves the options are populated and the current value re-selected.\n *\n * Per D5 there is NO integrity: a stored id that is no longer in the target\n * list (target deleted) is kept and surfaced as a distinct \"⚠ missing (<id>)\"\n * option so saving doesn't silently drop it.\n */\nfunction renderReferenceField(\n field: ListSchemaField,\n initial: unknown,\n): { control: HTMLElement; getValue: () => unknown } {\n const currentId = typeof initial === \"string\" ? initial : \"\";\n const targetList = field.referenceList;\n\n const sel = document.createElement(\"select\");\n sel.className = \"cancia-form-select\";\n sel.style.cssText = `${INPUT_BASE} appearance: none; padding-right: 30px; background-image: ${SELECT_CHEVRON}; background-repeat: no-repeat; background-position: right 10px center; cursor: pointer;`;\n\n const opt = (value: string, text: string, selected = false): HTMLOptionElement => {\n const o = document.createElement(\"option\");\n o.value = value;\n o.textContent = text;\n if (selected) o.selected = true;\n return o;\n };\n\n // Placeholder state while loading (and the fallback if there's no target).\n const loadingOpt = opt(\"\", \"Loading…\");\n loadingOpt.disabled = true;\n sel.appendChild(loadingOpt);\n // Preserve the current id during load so getValue keeps it if saved early.\n if (currentId) sel.appendChild(opt(currentId, `Current (${currentId})`, true));\n\n const getValue = () => (sel.value === \"\" ? undefined : sel.value);\n\n if (!targetList) {\n sel.innerHTML = \"\";\n const note = opt(\"\", \"No target list configured\");\n note.disabled = true;\n sel.appendChild(note);\n return { control: sel, getValue };\n }\n\n const titleField = state.schemas[targetList]?.titleField;\n\n // Resolve an entry's display title (falls back to id when unavailable).\n const titleOf = (entry: ListEntry): string => {\n if (titleField) {\n const v = entry.data[titleField];\n if (typeof v === \"string\" && v.trim()) return v;\n }\n return `(untitled · ${entry.id})`;\n };\n\n void (async () => {\n let entries: ListEntry[] = [];\n let failed = false;\n try {\n entries = await fetchList(targetList, state.activeListLocale || state.activeLang || undefined);\n } catch {\n failed = true;\n }\n\n sel.innerHTML = \"\";\n\n if (failed) {\n const errOpt = opt(\"\", \"Failed to load options\");\n errOpt.disabled = true;\n sel.appendChild(errOpt);\n // Still preserve any current id so a load failure doesn't drop it.\n if (currentId) sel.appendChild(opt(currentId, `Current (${currentId})`, true));\n return;\n }\n\n // Optional / not-required → an explicit \"none\" choice.\n if (!field.required) sel.appendChild(opt(\"\", \"— none —\", currentId === \"\"));\n\n let matched = false;\n for (const entry of entries) {\n const isCurrent = entry.id === currentId;\n if (isCurrent) matched = true;\n sel.appendChild(opt(entry.id, titleOf(entry), isCurrent));\n }\n\n // Dangling id (target deleted): keep it, surface it, don't drop it (D5).\n if (currentId && !matched) {\n sel.appendChild(opt(currentId, `⚠ missing (${currentId})`, true));\n }\n })();\n\n return { control: sel, getValue };\n}\n\n/**\n * The rich-text editor — APPROACH B (structured blocks + markdown shorthand).\n *\n * A list of block rows. Each row is:\n * - a <textarea> holding the block's text, where inline emphasis/links are\n * authored with a tiny markdown shorthand (**bold**, *italic*, [t](url));\n * - a style <select> (normal / h2 / h3 / blockquote);\n * - a list toggle (none / bullet / number).\n * Rows can be added, removed, and drag-reordered (same handle mechanism as the\n * array field). There is NO contenteditable and NO raw HTML anywhere.\n *\n * On collect, rows are serialised to a PT-subset value with rowsToPortableText\n * (the whitelisted parser in @cancia/astro), then round-tripped through\n * portableTextSubsetSchema as the accept guard — if that ever fails, validate()\n * blocks the save. Deserialisation (portableTextToRows) turns a stored value\n * back into editable shorthand rows.\n */\nfunction renderRichTextField(\n field: ListSchemaField,\n initial: unknown,\n setOwnError: (msg: string | null) => void,\n): BuiltComposite {\n const STYLE_LABELS: Record<PtStyle, string> = {\n normal: \"Normal\",\n h2: \"Heading 2\",\n h3: \"Heading 3\",\n blockquote: \"Quote\",\n };\n const LIST_LABELS: Array<{ value: \"\" | PtListItem; label: string }> = [\n { value: \"\", label: \"No list\" },\n { value: \"bullet\", label: \"Bulleted\" },\n { value: \"number\", label: \"Numbered\" },\n ];\n\n const container = document.createElement(\"div\");\n container.style.cssText = `\n ${group()}\n `;\n\n const rowsWrap = document.createElement(\"div\");\n rowsWrap.style.cssText = `display: flex; flex-direction: column; gap: ${v(\"space-2\")};`;\n container.appendChild(rowsWrap);\n\n interface RtRow {\n el: HTMLElement;\n read: () => RichTextRow;\n }\n const rows: RtRow[] = [];\n let dragging: RtRow | null = null;\n\n function makeRow(initialRow: RichTextRow): RtRow {\n const row = document.createElement(\"div\");\n row.style.cssText = `\n ${groupRow()}\n `;\n\n const handle = document.createElement(\"div\");\n handle.textContent = \"⋮⋮\";\n handle.title = \"Drag to reorder\";\n handle.draggable = true;\n // Faded until the row is hovered or focused, for the same reason as the\n // controls: reordering is occasional, writing is constant. It keeps its\n // space (opacity, not display) so nothing shifts when it appears.\n handle.style.cssText = `\n cursor: grab; user-select: none;\n color: ${v(\"fg-faint\")};\n font-size: ${v(\"text-base\")}; line-height: 1.2;\n padding: ${v(\"space-1\")} 2px; flex-shrink: 0;\n letter-spacing: -2px;\n opacity: 0;\n transition: opacity ${v(\"duration-fast\")} ${v(\"ease\")};\n `;\n\n const main = document.createElement(\"div\");\n main.style.cssText = `flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px;`;\n\n const ta = document.createElement(\"textarea\");\n ta.className = \"cancia-form-textarea\";\n ta.style.cssText = `${INPUT_BASE} resize: vertical; min-height: 54px; max-height: 240px; caret-color: ${v(\"accent\")};`;\n ta.rows = 2;\n ta.placeholder = \"Text — use **bold**, *italic*, [label](https://…)\";\n ta.value = initialRow.text;\n\n // The per-block controls (style + list dropdowns) are REVEALED on focus or\n // hover, not shown permanently.\n //\n // Every block previously carried five visible controls at once — drag\n // handle, textarea, two dropdowns, delete. For a body field with three\n // paragraphs that is fifteen controls competing with the text itself, and\n // the overwhelming majority of the time the answer to \"what style is this\n // paragraph?\" is \"a paragraph\". The dropdowns are the rare case; text is\n // the common one, so text gets the space and the controls step forward\n // when you are actually working on that block.\n //\n // max-height + opacity rather than display:none so the reveal can animate\n // and so the selects keep their layout width (a display toggle makes the\n // row jump as the browser re-measures them).\n const controls = document.createElement(\"div\");\n controls.style.cssText = `\n display: flex; gap: 6px;\n max-height: 0; opacity: 0; overflow: hidden;\n transition: max-height ${v(\"duration-fast\")} ${v(\"ease-out\")},\n opacity ${v(\"duration-fast\")} ${v(\"ease\")};\n `;\n controls.dataset.canciaCollapsible = \"1\";\n\n // The list <select> deliberately reuses the style <select>'s exact cssText\n // (assigned below), so both must stay tokenised identically.\n const styleSel = document.createElement(\"select\");\n styleSel.className = \"cancia-form-select\";\n styleSel.style.cssText = `${INPUT_BASE} width: auto; flex: 1; appearance: none; padding: 5px 26px 5px 9px; font-size: ${v(\"text-xs\")}; background-image: ${SELECT_CHEVRON}; background-repeat: no-repeat; background-position: right 9px center; cursor: pointer;`;\n for (const s of PT_STYLES) {\n const o = document.createElement(\"option\");\n o.value = s;\n o.textContent = STYLE_LABELS[s];\n if (initialRow.style === s) o.selected = true;\n styleSel.appendChild(o);\n }\n\n const listSel = document.createElement(\"select\");\n listSel.className = \"cancia-form-select\";\n listSel.style.cssText = styleSel.style.cssText;\n for (const { value, label } of LIST_LABELS) {\n const o = document.createElement(\"option\");\n o.value = value;\n o.textContent = label;\n if ((initialRow.listItem ?? \"\") === value) o.selected = true;\n listSel.appendChild(o);\n }\n\n controls.appendChild(styleSel);\n controls.appendChild(listSel);\n main.appendChild(ta);\n main.appendChild(controls);\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.type = \"button\";\n removeBtn.textContent = \"×\";\n removeBtn.title = \"Remove block\";\n // 16px is a glyph size for the \"×\", not a type-scale step — left literal.\n removeBtn.style.cssText = `\n ${button(\"danger\")}\n flex-shrink: 0;\n border: 1px solid transparent;\n height: auto;\n font-size: 16px; line-height: 1;\n padding: 2px 7px;\n cursor: pointer;\n `;\n attachHover(removeBtn, { bg: v(\"danger-soft\") });\n\n // Reveal the row's affordances (drag handle, delete) on hover/focus. They\n // are occasional actions; the content is the constant one. Fading rather\n // than hiding keeps the layout stable — nothing shifts as they appear.\n attachRowReveal(row, [handle, removeBtn, controls]);\n\n row.appendChild(handle);\n row.appendChild(main);\n row.appendChild(removeBtn);\n\n const rec: RtRow = {\n el: row,\n read: () => {\n const style = (styleSel.value as PtStyle) ?? \"normal\";\n const listValue = listSel.value as \"\" | PtListItem;\n const out: RichTextRow = { text: ta.value, style };\n if (listValue) out.listItem = listValue;\n return out;\n },\n };\n\n removeBtn.addEventListener(\"click\", () => {\n const i = rows.indexOf(rec);\n if (i >= 0) rows.splice(i, 1);\n row.remove();\n setOwnError(null);\n });\n\n handle.addEventListener(\"dragstart\", (e) => {\n dragging = rec;\n handle.style.cursor = \"grabbing\";\n row.style.opacity = \"0.5\";\n e.dataTransfer?.setData(\"text/plain\", \"\");\n if (e.dataTransfer) e.dataTransfer.effectAllowed = \"move\";\n });\n handle.addEventListener(\"dragend\", () => {\n handle.style.cursor = \"grab\";\n row.style.opacity = \"1\";\n dragging = null;\n });\n row.addEventListener(\"dragover\", (e) => {\n if (!dragging || dragging === rec) return;\n e.preventDefault();\n const rect = row.getBoundingClientRect();\n const after = e.clientY > rect.top + rect.height / 2;\n const from = rows.indexOf(dragging);\n let to = rows.indexOf(rec);\n if (from < 0 || to < 0) return;\n if (after) to += 1;\n if (from < to) to -= 1;\n if (from === to) return;\n rows.splice(from, 1);\n rows.splice(to, 0, dragging);\n rowsWrap.insertBefore(dragging.el, after ? row.nextSibling : row);\n });\n\n return rec;\n }\n\n function addRow(initialRow: RichTextRow): void {\n const rec = makeRow(initialRow);\n rows.push(rec);\n rowsWrap.appendChild(rec.el);\n }\n\n // Deserialise the stored value into editable shorthand rows.\n const initialRows: RichTextRow[] = (() => {\n const parsed = portableTextSubsetSchema.safeParse(initial);\n if (parsed.success && parsed.data.length > 0) return portableTextToRows(parsed.data);\n return [{ text: \"\", style: \"normal\" }];\n })();\n for (const r of initialRows) addRow(r);\n\n const addBtn = document.createElement(\"button\");\n addBtn.type = \"button\";\n addBtn.textContent = \"+ Add block\";\n addBtn.style.cssText = `\n ${button(\"ghost\")}\n align-self: flex-start;\n background: transparent;\n color: ${v(\"fg-muted\")};\n border: 0;\n height: auto;\n font-size: ${v(\"text-sm\")};\n font-weight: 500;\n padding: 4px 0;\n cursor: pointer;\n `;\n attachHover(addBtn, { bg: v(\"surface-active\") });\n addBtn.addEventListener(\"click\", () => addRow({ text: \"\", style: \"normal\" }));\n container.appendChild(addBtn);\n\n // Serialise rows → PT-subset. Blank trailing/empty rows are dropped so an\n // empty editor persists as [] rather than a block of empty text.\n const serialise = (): unknown[] => {\n const editorRows = rows.map((r) => r.read()).filter((r) => r.text.trim() !== \"\");\n return rowsToPortableText(editorRows);\n };\n\n return {\n control: container,\n getValue: () => serialise(),\n validate: () => {\n setOwnError(null);\n const value = serialise();\n // Accept guard: the serialised value MUST validate against the subset\n // schema. The parser is whitelisted, so this should always pass — but it\n // is the hard gate that keeps out-of-subset content from ever persisting.\n const parsed = portableTextSubsetSchema.safeParse(value);\n if (!parsed.success) {\n setOwnError(\"This rich-text content is not valid. Check links and formatting.\");\n return { value, ok: false };\n }\n if (field.required && value.length === 0) {\n setOwnError(`${field.label || \"This field\"} is required`);\n return { value, ok: false };\n }\n return { value: parsed.data, ok: true };\n },\n };\n}\n\n/**\n * A sensible empty value for a freshly-added array item / object, so the new\n * row starts blank instead of undefined.\n */\nfunction defaultForField(field: ListSchemaField): unknown {\n if (field.widget === \"array\" || field.widget === \"richtext\") return [];\n if (field.widget === \"object\") {\n const out: Record<string, unknown> = {};\n for (const sub of field.fields ?? []) {\n const d = defaultForField(sub);\n if (d !== undefined) out[sub.name] = d;\n }\n return out;\n }\n if (field.widget === \"checkbox\") return false;\n return \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\ninterface ValidationResult {\n data: Record<string, unknown>;\n ok: boolean;\n}\n\nfunction preValidate(fieldStates: FieldState[]): ValidationResult {\n const data: Record<string, unknown> = {};\n let ok = true;\n\n for (const f of fieldStates) {\n // validate() runs required + constraint checks (recursively for\n // array/object) and paints inline errors as a side effect.\n const { value, ok: fieldOk } = f.validate();\n if (!fieldOk) {\n ok = false;\n continue;\n }\n\n // Keep empty scalars out; but arrays/objects/richtext always serialise (an\n // empty array is [], an empty group is {}, empty richtext is []), never\n // dropped to undefined.\n if (f.field.widget === \"array\" || f.field.widget === \"object\" || f.field.widget === \"richtext\") {\n data[f.field.name] = value;\n } else if (value !== undefined && value !== \"\") {\n data[f.field.name] = value;\n }\n }\n\n return { data, ok };\n}\n\n/**\n * Client-side constraint checks mirrored from the Zod schema (threaded via\n * FieldDescription). The server stays the source of truth — this only saves a\n * round-trip on obvious errors and gives inline feedback. Empty/undefined\n * values are already handled by the required check upstream, so here we only\n * validate present values.\n */\nfunction validateValue(field: ListSchemaField, value: unknown): string | null {\n if (value === undefined || value === null || value === \"\") return null;\n\n if (typeof value === \"string\") {\n if (field.minLength !== undefined && value.length < field.minLength) {\n return `Must be at least ${field.minLength} character${field.minLength === 1 ? \"\" : \"s\"}`;\n }\n if (field.maxLength !== undefined && value.length > field.maxLength) {\n return `Must be at most ${field.maxLength} characters`;\n }\n if (field.pattern !== undefined) {\n let re: RegExp | null = null;\n try {\n re = new RegExp(field.pattern);\n } catch {\n re = null; // Malformed pattern — leave it to the server.\n }\n if (re && !re.test(value)) {\n return \"Invalid format\";\n }\n }\n if (field.options && field.options.length > 0 && !field.options.includes(value)) {\n return \"Choose one of the allowed options\";\n }\n if (field.widget === \"email\" && !isLikelyEmail(value)) {\n return \"Enter a valid email address\";\n }\n if ((field.widget === \"url\" || field.widget === \"image\") && !isLikelyUrl(value)) {\n return \"Enter a valid URL\";\n }\n }\n\n if (typeof value === \"number\") {\n if (field.min !== undefined && value < field.min) {\n return `Must be at least ${field.min}`;\n }\n if (field.max !== undefined && value > field.max) {\n return `Must be at most ${field.max}`;\n }\n }\n\n return null;\n}\n\n// Deliberately loose — the server's Zod schema is authoritative. These only\n// catch obvious typos before a round-trip.\nfunction isLikelyEmail(s: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(s);\n}\n\nfunction isLikelyUrl(s: string): boolean {\n try {\n // eslint-disable-next-line no-new\n new URL(s);\n return true;\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Slug auto-fill (plan 025)\n// ---------------------------------------------------------------------------\n\n/**\n * Wire slug fields to their source field so the slug tracks the source live.\n *\n * A slug field qualifies if it has `widget: \"slug\"` and a `source` naming\n * another top-level field, and both fields expose input hooks (they are plain\n * text inputs, not composites). The slug is auto-derived only while \"clean\":\n * - a NEW entry with an empty slug starts clean → fills as the source types;\n * - a hand-edit of the slug latches it dirty → auto-fill stops (stays editable);\n * - an EXISTING (or pre-populated) slug starts dirty → never clobbered.\n */\nfunction wireSlugAutoFill(\n schema: ListSchemaDescription,\n fieldStates: FieldState[],\n sourceEntry: ListEntry | null,\n): void {\n const byName = new Map(fieldStates.map((f) => [f.field.name, f]));\n\n for (const slug of fieldStates) {\n if (slug.field.widget !== \"slug\") continue;\n const sourceName = slug.field.source;\n if (!sourceName) continue;\n const src = byName.get(sourceName);\n if (!src || !src.onInput || !slug.setValue) continue;\n\n // Start dirty if the slug already has a value (existing entry, translation,\n // or a manually-seeded default) — we must not overwrite it.\n const existing = sourceEntry?.data[slug.field.name];\n let dirty = typeof existing === \"string\" && existing.trim().length > 0;\n\n // A hand-edit of the slug latches it dirty forever.\n slug.onInput?.(() => { dirty = true; });\n\n src.onInput(() => {\n if (dirty) return;\n const sv = src.getValue();\n slug.setValue?.(typeof sv === \"string\" ? slugify(sv) : \"\");\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Modal lifecycle\n// ---------------------------------------------------------------------------\n\nexport interface EntryModalOptions {\n schema: ListSchemaDescription;\n /** Locale being edited / created in. */\n locale: string;\n /** null = create; ListEntry = edit. */\n entry: ListEntry | null;\n /**\n * Translation mode: fill in the form pre-populated from `entry` (which is in\n * a different locale than `locale`) and save into `locale` with a fixed id.\n */\n translateFromEntry?: ListEntry | null;\n /** Fixed id when translating (so order matches across locales). */\n fixedId?: string;\n /** Called after successful save or delete. */\n onSaved: () => void;\n}\n\nexport function openEntryModal(opts: EntryModalOptions): void {\n closeEntryModal();\n injectStyles();\n\n const isEdit = opts.entry !== null;\n const isTranslate = !isEdit && (opts.translateFromEntry ?? null) !== null;\n\n // CSS var for input focus border so the focus rule above can pick it up.\n document.documentElement.style.setProperty(\"--cancia-accent-border\", accentBorder());\n\n // ---- Shell ----\n // Built the same either way; only how it is MOUNTED differs. The drawer path\n // (normal) hands this element to the panel, which positions and slides it.\n // The fallback path floats it as a centred modal with its own backdrop.\n const modal = document.createElement(\"div\");\n modal.dataset.canciaModal = \"1\";\n markUi(modal);\n document.documentElement.style.setProperty(\"--cancia-accent-border\", accentBorder());\n\n // Try the drawer first. pushPanelView() returns false when no list panel is\n // open, in which case we fall back to the standalone modal below.\n mountedInPanel = pushPanelView(modal);\n\n if (!mountedInPanel) {\n // ---- Fallback: standalone centred modal (no panel to slide into) ----\n const backdrop = document.createElement(\"div\");\n backdrop.dataset.canciaModalBackdrop = \"1\";\n markUi(backdrop);\n // A dim layer keeps its own black rgba (the surface tokens are chrome\n // colours, not scrims); only the layering and motion are tokenised.\n backdrop.style.cssText = `\n position: fixed; inset: 0;\n background: rgba(8,8,10,0.45);\n backdrop-filter: blur(3px);\n -webkit-backdrop-filter: blur(3px);\n z-index: ${BACKDROP_Z};\n opacity: 0;\n transition: opacity ${v(\"duration\")} ${v(\"ease-out\")};\n `;\n document.body.appendChild(backdrop);\n requestAnimationFrame(() => { backdrop.style.opacity = \"1\"; });\n backdropEl = backdrop;\n backdrop.addEventListener(\"click\", () => closeEntryModal());\n\n // surface(3) is the topmost layer; shadow-lg overrides the surface's\n // default shadow because a centred modal sits higher than a panel.\n modal.style.cssText = `\n ${surface(3)}\n position: fixed;\n top: 50%; left: 50%;\n width: min(480px, calc(100vw - 32px));\n max-height: min(680px, calc(100vh - 48px));\n display: flex; flex-direction: column;\n box-shadow: ${v(\"shadow-lg\")};\n z-index: ${MODAL_Z};\n overflow: hidden;\n opacity: 0;\n transform: translate(-50%, calc(-50% + 8px)) scale(0.985);\n transition: opacity ${v(\"duration\")} ${v(\"ease\")}, transform ${v(\"duration\")} ${v(\"ease\")};\n `;\n document.body.appendChild(modal);\n // Commit the \"from\" state, then transition in. A transition rather than\n // the old fill-mode `cancia-modal-in` keyframe — see the note in\n // toolbar.ts expand() for why a filled animation strands elements.\n requestAnimationFrame(() => {\n modal.style.opacity = \"1\";\n modal.style.transform = \"translate(-50%, -50%) scale(1)\";\n });\n }\n\n modalEl = modal;\n\n // ---- Header (fixed) ----\n const header = document.createElement(\"div\");\n header.style.cssText = `\n display: flex; align-items: center; gap: ${v(\"space-2\")};\n padding: 14px ${v(\"space-4\")} ${v(\"space-3\")};\n border-bottom: 1px solid ${v(\"border\")};\n flex-shrink: 0;\n `;\n\n // Back arrow — only in the drawer, where there is a list to go back TO.\n // It is the primary way out: \"←\" is understood without a label, and it says\n // where you'll land in a way an \"✕\" does not.\n if (mountedInPanel) {\n const backBtn = document.createElement(\"button\");\n backBtn.type = \"button\";\n backBtn.setAttribute(\"aria-label\", \"Back to list\");\n backBtn.title = \"Back to list\";\n backBtn.style.cssText = `\n ${iconButtonStyle(28)}\n flex-shrink: 0; padding: 0; cursor: pointer;\n background: transparent; border: 0;\n `;\n backBtn.innerHTML = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M19 12H5\"/><path d=\"M12 19l-7-7 7-7\"/>\n </svg>`;\n attachHover(backBtn, { bg: v(\"surface-hover\"), color: v(\"fg-strong\") });\n attachPress(backBtn);\n backBtn.addEventListener(\"click\", () => closeEntryModal());\n header.appendChild(backBtn);\n }\n\n const titleWrap = document.createElement(\"div\");\n titleWrap.style.cssText = `display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1;`;\n\n const eyebrow = document.createElement(\"span\");\n eyebrow.style.cssText = `${labelStyle()} display: inline;`;\n const action = isEdit ? \"Edit\" : isTranslate ? \"Translate\" : \"New\";\n eyebrow.textContent = `${action} ${opts.schema.labelSingular.toLowerCase()} · ${opts.locale}`;\n\n const titleEl = document.createElement(\"span\");\n // 14px sits between text-base (13) and text-lg (15) — kept literal.\n titleEl.style.cssText = `\n font-size: 14px; font-weight: 600;\n color: ${v(\"fg-strong\")};\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n `;\n titleEl.textContent = opts.schema.label;\n\n titleWrap.appendChild(eyebrow);\n titleWrap.appendChild(titleEl);\n\n header.appendChild(titleWrap);\n // The ✕ means \"I'm done with this list entirely\", so in the drawer it closes\n // the PANEL, not just the form — otherwise ✕ and ← would do the same thing\n // and the ✕ would be the long way round. In the fallback modal there is no\n // panel, so it just closes the form.\n header.appendChild(\n makeCloseButton(() => {\n if (mountedInPanel) {\n closeEntryModal();\n closeListPanel();\n } else {\n closeEntryModal();\n }\n }),\n );\n modal.appendChild(header);\n\n // ---- Body (scrolls) ----\n const body = document.createElement(\"div\");\n body.style.cssText = `\n padding: 14px ${v(\"space-4\")} ${v(\"space-1\")};\n overflow-y: auto;\n flex: 1 1 auto;\n min-height: 0;\n `;\n modal.appendChild(body);\n\n // Form-level error banner (REV_CONFLICT, network errors)\n const formError = document.createElement(\"div\");\n formError.style.cssText = `\n display: none;\n background: ${v(\"danger-soft\")};\n color: ${v(\"danger\")};\n border: 1px solid ${v(\"danger-soft\")};\n border-radius: ${v(\"radius-sm\")};\n padding: 9px 11px;\n font-size: ${v(\"text-sm\")};\n line-height: 1.4;\n margin-bottom: ${v(\"space-3\")};\n `;\n body.appendChild(formError);\n\n function showFormError(msg: string): void {\n formError.textContent = msg;\n formError.style.display = \"block\";\n }\n function clearFormError(): void {\n formError.textContent = \"\";\n formError.style.display = \"none\";\n }\n\n if (isTranslate) {\n const banner = document.createElement(\"div\");\n // The `warning` / `warning-soft` tokens now exist (they were added for the\n // list panel's \"not translated\" stub, which is the same state this banner\n // describes), so the amber literals that used to be here are gone.\n banner.style.cssText = `\n background: ${v(\"warning-soft\")};\n color: ${v(\"warning\")};\n border: 1px solid ${v(\"warning-soft\")};\n border-radius: ${v(\"radius-sm\")};\n padding: 9px 11px;\n font-size: ${v(\"text-sm\")};\n line-height: 1.4;\n margin-bottom: ${v(\"space-3\")};\n `;\n const src = opts.translateFromEntry!;\n banner.textContent = `Translating from ${src.locale} into ${opts.locale}. Fields are pre-filled from the source.`;\n body.appendChild(banner);\n }\n\n const fieldStates: FieldState[] = [];\n const sourceForInitial = opts.entry ?? opts.translateFromEntry ?? null;\n for (const f of opts.schema.fields) {\n const initial = sourceForInitial?.data[f.name];\n const { wrapper, fieldState } = renderField(f, initial);\n body.appendChild(wrapper);\n fieldStates.push(fieldState);\n }\n\n // ---- Slug auto-fill from a source field (plan 025) ----\n // For each slug field that declares a `source`, mirror slugify(source) into\n // the slug as the source is typed — but only while the slug is \"clean\" (never\n // hand-edited AND not already populated). Editing the slug by hand latches it\n // dirty and stops the auto-overwrite; an existing entry that already has a\n // slug starts dirty so its value is never clobbered.\n wireSlugAutoFill(opts.schema, fieldStates, sourceForInitial);\n\n // ---- Footer (fixed) ----\n const footer = document.createElement(\"div\");\n // The footer sits on `surface-raised` — a light recessed grey — rather than\n // the old black wash, which on a white surface would read as a dirty smear\n // instead of a deeper bar. Pinned: it never scrolls with the fields.\n footer.style.cssText = `\n display: flex; align-items: center; justify-content: space-between;\n gap: 10px;\n padding: ${v(\"space-3\")} ${v(\"space-4\")};\n border-top: 1px solid ${v(\"border\")};\n background: ${v(\"surface-raised\")};\n flex-shrink: 0;\n `;\n\n const leftActions = document.createElement(\"div\");\n const rightActions = document.createElement(\"div\");\n rightActions.style.cssText = `display: flex; gap: ${v(\"space-2\")};`;\n\n if (isEdit) {\n const deleteBtn = document.createElement(\"button\");\n deleteBtn.type = \"button\";\n deleteBtn.style.cssText = `\n ${button(\"danger\")}\n border: 1px solid transparent;\n height: auto;\n padding: 6px 10px;\n cursor: pointer;\n `;\n deleteBtn.textContent = \"Delete\";\n attachHover(deleteBtn, { bg: v(\"danger-soft\") });\n deleteBtn.addEventListener(\"click\", async () => {\n if (!confirm(`Delete the ${opts.locale} version of this ${opts.schema.labelSingular.toLowerCase()}? This can't be undone.`)) return;\n deleteBtn.disabled = true;\n try {\n await deleteListEntry(opts.schema.name, opts.entry!.id, opts.locale);\n opts.onSaved();\n closeEntryModal();\n } catch (err) {\n showFormError(err instanceof Error ? err.message : String(err));\n deleteBtn.disabled = false;\n }\n });\n leftActions.appendChild(deleteBtn);\n }\n\n const cancelBtn = document.createElement(\"button\");\n cancelBtn.type = \"button\";\n cancelBtn.style.cssText = `\n ${button(\"ghost\")}\n background: ${v(\"surface-raised\")};\n border: 1px solid ${v(\"border\")};\n height: auto;\n padding: 7px 14px;\n cursor: pointer;\n `;\n cancelBtn.textContent = \"Cancel\";\n attachHover(cancelBtn, { bg: v(\"surface-hover\"), color: v(\"fg-strong\") });\n cancelBtn.addEventListener(\"click\", () => closeEntryModal());\n\n const saveBtn = makePrimaryButton(isEdit ? \"Save\" : \"Create\", accent());\n\n saveBtn.addEventListener(\"click\", async () => {\n clearFormError();\n const { data, ok } = preValidate(fieldStates);\n if (!ok) return;\n\n saveBtn.disabled = true;\n saveBtn.style.opacity = \"0.6\";\n const original = saveBtn.textContent;\n saveBtn.textContent = isEdit ? \"Saving…\" : \"Creating…\";\n\n try {\n if (isEdit) {\n await updateListEntry(opts.schema.name, opts.entry!.id, data, opts.entry!._rev, opts.locale);\n } else {\n let id: string | undefined;\n if (opts.fixedId) {\n id = opts.fixedId;\n } else {\n const slugFieldName = opts.schema.slugField;\n id = slugFieldName && typeof data[slugFieldName] === \"string\"\n ? (data[slugFieldName] as string)\n : undefined;\n }\n await createListEntry(opts.schema.name, data, opts.locale, id);\n }\n opts.onSaved();\n closeEntryModal();\n } catch (err) {\n const error = err as Error & { code?: string };\n if (error.message.includes(\"Validation failed\")) {\n showFormError(\"Server-side validation failed. Check the fields above.\");\n } else if (error.code === \"REV_CONFLICT\") {\n showFormError(\"This entry was changed by someone else. Close and reopen to see the latest version.\");\n } else {\n showFormError(error.message);\n }\n saveBtn.disabled = false;\n saveBtn.style.opacity = \"1\";\n saveBtn.textContent = original ?? (isEdit ? \"Save\" : \"Create\");\n }\n });\n\n rightActions.appendChild(cancelBtn);\n rightActions.appendChild(saveBtn);\n footer.appendChild(leftActions);\n footer.appendChild(rightActions);\n modal.appendChild(footer);\n\n // ---- Close handlers ----\n // Esc backs out ONE level: from the form to the list, not all the way out of\n // edit mode. stopPropagation is what enforces that — the edit-mode Esc\n // cascade in toolbar.ts would otherwise also fire and close the panel behind\n // us. (The backdrop click handler is wired in the fallback branch above;\n // the drawer has no backdrop of its own.)\n escListener = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n closeEntryModal();\n }\n };\n document.addEventListener(\"keydown\", escListener, true);\n\n // Focus the first input — small delay so the focus ring doesn't fight\n // the open animation.\n setTimeout(() => {\n const firstInput = body.querySelector<HTMLElement>(\"input, textarea, select\");\n firstInput?.focus();\n }, 90);\n}\n\nexport function closeEntryModal(): void {\n if (modalEl) {\n const el = modalEl;\n modalEl = null;\n if (mountedInPanel) {\n // Slide back out to the right, exactly reversing the way it came in, and\n // bring the list back. The panel owns this half of the animation.\n popPanelView(el);\n } else {\n // Fallback modal: reverse its own entrance (down + shrink + fade), as a\n // transition so nothing lingers if it is reopened mid-exit.\n el.style.transition = `opacity 0.16s ${v(\"ease-out\")}, transform 0.16s ${v(\"ease-out\")}`;\n el.style.opacity = \"0\";\n el.style.transform = \"translate(-50%, calc(-50% + 8px)) scale(0.985)\";\n setTimeout(() => el.remove(), 180);\n }\n }\n mountedInPanel = false;\n if (backdropEl) {\n const el = backdropEl;\n el.style.opacity = \"0\";\n setTimeout(() => el.remove(), 180);\n backdropEl = null;\n }\n if (escListener) {\n document.removeEventListener(\"keydown\", escListener, true);\n escListener = null;\n }\n}\n\nexport function isEntryModalOpen(): boolean {\n return modalEl !== null;\n}\n","// =============================================================================\n// Cancia Toolbar — Floating Bar\n// =============================================================================\n// Starts as a 52px circle, morphs into a labelled pill on load/click.\n// =============================================================================\n\nimport { state, clearPending, revertPending } from \"./state\";\nimport { attachHighlight, detachHighlight } from \"./highlight\";\nimport { openPopup, closePopup } from \"./popup\";\nimport { openListPanel, closeListPanel, isListPanelOpen, refreshListPanel } from \"./list-panel\";\nimport { openEntryModal, closeEntryModal, isEntryModalOpen } from \"./entry-modal\";\nimport { flushPending, triggerPublish, isAuthError } from \"./api\";\nimport { onPendingChange } from \"./events\";\nimport { v } from \"./tokens\";\nimport { injectBaseStyles, markUi, iconButton, actionButton, attachPress } from \"./styles\";\n\nlet toolbarEl: HTMLElement | null = null;\nlet pendingPanelEl: HTMLElement | null = null;\nlet isExpanded = false;\nlet expandedEscListener: ((e: KeyboardEvent) => void) | null = null;\n/**\n * The pending \"reveal the controls\" timer from expand().\n *\n * expand() defers revealing the controls by 80ms (so the bar has started\n * widening first), but collapse() runs synchronously. A collapse landing\n * inside that 80ms window would be immediately undone by the queued timeout —\n * which re-showed the controls on a bar that was on its way closed, or, in the\n * reverse order, left the bar wide with the controls still at opacity 0: the\n * \"wide empty pill\". Tracking the handle lets collapse() cancel it.\n */\nlet revealTimer: ReturnType<typeof setTimeout> | null = null;\n\nfunction accent() {\n // Matches the `accent` token default (near-black). See tokens.ts for why the\n // site's brand colour is no longer applied automatically.\n // Mirrors tokenCss()'s rule: the site's brand colour tints the editor\n // ONLY when a project opts in via `toolbarAccent`. Reading accentColor\n // unconditionally here would leave this surface brand-coloured while the\n // rest of the chrome is neutral.\n const useAccent = state.config?.toolbarAccent === true;\n return (useAccent ? state.config?.accentColor : undefined) ?? \"#18181b\";\n}\n\n// ---------------------------------------------------------------------------\n// Inject keyframe animations\n// ---------------------------------------------------------------------------\n\nlet styleInjected = false;\nfunction injectStyles() {\n if (styleInjected) return;\n styleInjected = true;\n // Tokens + reset first, so every component below can reference var(--cancia-*).\n injectBaseStyles(state.config?.accentColor, state.config?.toolbarAccent === true);\n const s = document.createElement(\"style\");\n s.textContent = `\n @keyframes cancia-enter {\n from { opacity: 0; transform: scale(0.5) rotate(90deg); }\n to { opacity: 1; transform: scale(1) rotate(0deg); }\n }\n @keyframes cancia-exit {\n from { opacity: 1; transform: scale(1); }\n to { opacity: 0; transform: scale(0.8); }\n }\n @keyframes cancia-controls-in {\n from { opacity: 0; filter: blur(8px); transform: scale(0.6); }\n to { opacity: 1; filter: blur(0px); transform: scale(1); }\n }\n @keyframes cancia-controls-out {\n from { opacity: 1; filter: blur(0px); transform: scale(1); }\n to { opacity: 0; filter: blur(6px); transform: scale(0.5); }\n }\n @keyframes cancia-fade-in {\n from { opacity: 0; transform: scale(0.94) translateY(5px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n }\n @keyframes cancia-popup-in {\n from { opacity: 0; transform: scale(0.93); }\n to { opacity: 1; transform: scale(1); }\n }\n @keyframes cancia-badge-pop {\n 0% { transform: scale(0); }\n 60% { transform: scale(1.25); }\n 100% { transform: scale(1); }\n }\n @keyframes cancia-icon-slide-in {\n from { transform: translateY(-150%); }\n to { transform: translateY(0); }\n }\n @keyframes cancia-tooltip-in {\n from { opacity: 0; transform: translateX(-50%) translateY(4px); }\n to { opacity: 1; transform: translateX(-50%) translateY(0); }\n }\n [data-cancia-toolbar] * { box-sizing: border-box; }\n [data-cancia-popup] * { box-sizing: border-box; }\n /* Press feedback for popup buttons. The TOOLBAR's buttons deliberately do\n NOT use :active — they use attachPress() on pointerdown instead, because\n :active only lands after the browser's own hit-test and reads as lag.\n An !important here would also override that inline transform. */\n [data-cancia-popup] button:active:not(:disabled) { transform: scale(0.96); }\n /* Protect stroke-based icons from host page \"svg { fill: currentColor }\" rules */\n [data-cancia-toolbar] svg[fill=\"none\"] { fill: none !important; }\n [data-cancia-toolbar] svg[fill=\"none\"] :not([fill]) { fill: none !important; }\n [data-cancia-popup] svg[fill=\"none\"] { fill: none !important; }\n [data-cancia-popup] svg[fill=\"none\"] :not([fill]) { fill: none !important; }\n /* Reset cosmetic host CSS leaking into toolbar buttons.\n NOTE: font-* and color are deliberately NOT unset here — the buttons now\n carry visible text labels, and unsetting those would strip the label's\n typography back to the UA default. The scoped reset in styles.ts already\n neutralises host typography for [data-cancia-ui] subtrees. */\n [data-cancia-toolbar] :where(button) {\n background: unset; border: unset; border-radius: unset; padding: unset;\n margin: unset; box-shadow: unset; outline: unset;\n }\n /* Labels must never be transformed by a host \\`button { text-transform }\\`. */\n [data-cancia-toolbar] [data-cancia-label] {\n text-transform: none;\n letter-spacing: normal;\n }\n `;\n document.head.appendChild(s);\n}\n\n// ---------------------------------------------------------------------------\n// Shared tooltip element (reused across buttons)\n// ---------------------------------------------------------------------------\n\nlet btnTooltipEl: HTMLElement | null = null;\nlet tooltipHideTimer: ReturnType<typeof setTimeout> | null = null;\nlet tooltipShowTimer: ReturnType<typeof setTimeout> | null = null;\nlet tooltipVisible = false;\n\nfunction getOrCreateBtnTooltip(): HTMLElement {\n if (!btnTooltipEl) {\n btnTooltipEl = document.createElement(\"div\");\n markUi(btnTooltipEl);\n btnTooltipEl.style.cssText = `\n position: fixed;\n pointer-events: none;\n z-index: ${v(\"z-panel\")};\n font-size: ${v(\"text-xs\")}; font-weight: 500; letter-spacing: 0.02em;\n color: ${v(\"fg-strong\")};\n background: ${v(\"surface-1\")};\n backdrop-filter: ${v(\"blur\")};\n -webkit-backdrop-filter: ${v(\"blur\")};\n border: 1px solid ${v(\"border-strong\")};\n padding: ${v(\"space-1\")} ${v(\"space-2\")};\n border-radius: ${v(\"radius-sm\")};\n white-space: nowrap;\n box-shadow: ${v(\"shadow-sm\")};\n display: none;\n `;\n document.body.appendChild(btnTooltipEl);\n }\n return btnTooltipEl;\n}\n\nfunction showBtnTooltip(btn: HTMLElement, label: string) {\n if (tooltipHideTimer) { clearTimeout(tooltipHideTimer); tooltipHideTimer = null; }\n if (tooltipShowTimer) { clearTimeout(tooltipShowTimer); tooltipShowTimer = null; }\n\n const doShow = () => {\n tooltipVisible = true;\n const tooltip = getOrCreateBtnTooltip();\n tooltip.textContent = label;\n tooltip.style.display = \"block\";\n tooltip.style.animation = `cancia-tooltip-in ${v(\"duration-fast\")} ${v(\"ease-out\")} both`;\n\n const rect = btn.getBoundingClientRect();\n const tooltipH = 26;\n const gap = 8;\n tooltip.style.top = `${rect.top - tooltipH - gap}px`;\n tooltip.style.left = `${rect.left + rect.width / 2}px`;\n };\n\n // Skip delay if tooltip is already visible (moving between buttons)\n if (tooltipVisible) {\n doShow();\n } else {\n tooltipShowTimer = setTimeout(doShow, 400);\n }\n}\n\nfunction hideBtnTooltip() {\n if (tooltipShowTimer) { clearTimeout(tooltipShowTimer); tooltipShowTimer = null; }\n if (tooltipHideTimer) clearTimeout(tooltipHideTimer);\n tooltipHideTimer = setTimeout(() => {\n tooltipVisible = false;\n if (btnTooltipEl) btnTooltipEl.style.display = \"none\";\n }, 80);\n}\n\n// ---------------------------------------------------------------------------\n// Build the toolbar DOM\n// ---------------------------------------------------------------------------\n\nfunction buildToolbar(): HTMLElement {\n injectStyles();\n\n // Single morphing container — collapses to 44px circle, expands to pill\n const bar = document.createElement(\"div\");\n bar.dataset.canciaToolbar = \"1\";\n markUi(bar);\n bar.style.cssText = `\n position: fixed;\n bottom: ${v(\"space-6\")};\n right: ${v(\"space-6\")};\n z-index: ${v(\"z-bar\")};\n width: 52px;\n height: 52px;\n border-radius: ${v(\"radius-full\")};\n background: ${v(\"surface-1\")};\n backdrop-filter: ${v(\"blur\")};\n -webkit-backdrop-filter: ${v(\"blur\")};\n border: 1px solid ${v(\"border\")};\n box-shadow: ${v(\"shadow\")};\n font-size: ${v(\"text-base\")};\n color: ${v(\"fg\")};\n user-select: none;\n cursor: pointer;\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: width ${v(\"duration-slow\")} ${v(\"ease\")},\n border-radius ${v(\"duration-slow\")} ${v(\"ease\")};\n animation: cancia-enter ${v(\"duration-slow\")} ${v(\"ease-spring\")} both;\n `;\n\n // Icon shown when collapsed\n const collapseIcon = document.createElement(\"div\");\n collapseIcon.style.cssText = `\n position: absolute;\n display: flex; align-items: center; justify-content: center;\n color: ${v(\"fg\")};\n transition: opacity ${v(\"duration-fast\")} ${v(\"ease\")},\n transform ${v(\"duration-fast\")} ${v(\"ease\")};\n pointer-events: none;\n `;\n // Pencil-line icon (Lucide style)\n collapseIcon.innerHTML = `<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12 20h9\"/>\n <path d=\"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z\"/>\n </svg>`;\n\n\n // Controls row (shown when expanded)\n const controls = document.createElement(\"div\");\n controls.style.cssText = `\n display: flex;\n align-items: center;\n gap: ${v(\"space-1\")};\n padding: 5px;\n white-space: nowrap;\n opacity: 0;\n transform: scale(0.6);\n pointer-events: none;\n transform-origin: right center;\n `;\n\n // Edit toggle — labelled, because \"am I currently editing?\" is the single\n // most important piece of state and an icon alone cannot say it.\n let editActive = false;\n const editBtn = makeActionButton(\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\"/>\n <path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\"/>\n </svg>`,\n \"Edit\",\n () => toggleEditMode()\n );\n\n controls.appendChild(editBtn);\n\n // Publish — disabled if no publish method (deploy hook OR dispatch repo) is\n // configured. Default enabled so older integrations (that don't inject the\n // flag) don't regress.\n const canPublish = state.config?.canPublish ?? true;\n const publishBtn = makeActionButton(\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 2L11 13\"/>\n <path d=\"M22 2L15 22l-4-9-9-4 20-7z\"/>\n </svg>`,\n \"Publish\",\n () => handlePublish(publishBtn)\n );\n if (!canPublish) {\n publishBtn.title = \"No publish method is configured for this site.\";\n }\n if (!canPublish) {\n publishBtn.disabled = true;\n publishBtn.style.opacity = \"0.3\";\n publishBtn.style.cursor = \"not-allowed\";\n }\n controls.appendChild(publishBtn);\n\n // Log out — door/exit icon\n const logoutBtn = makeActionButton(\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"/>\n <path d=\"M16 17l5-5-5-5\"/>\n <path d=\"M21 12H9\"/>\n </svg>`,\n \"Sign out\",\n () => state.onLogout?.()\n );\n controls.appendChild(logoutBtn);\n controls.appendChild(makeDivider());\n\n // Collapse — the one action that stays icon-only: an × is universally read\n // as \"close\", and labelling it would compete with the real actions.\n const collapseBtn = makeIconButton(\n `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\">\n <path d=\"M6 6l12 12M18 6L6 18\"/>\n </svg>`,\n \"Close\",\n () => collapse(bar, collapseIcon, controls)\n );\n collapseBtn.style.width = \"38px\";\n collapseBtn.style.height = \"38px\";\n controls.appendChild(collapseBtn);\n\n bar.appendChild(collapseIcon);\n bar.appendChild(controls);\n\n // Click on the collapsed bar to expand\n bar.addEventListener(\"click\", () => {\n if (!isExpanded) expand(bar, collapseIcon, controls);\n });\n\n // Hover effect when collapsed\n bar.addEventListener(\"mouseenter\", () => {\n if (!isExpanded) bar.style.background = v(\"surface-2\");\n });\n bar.addEventListener(\"mouseleave\", () => {\n bar.style.background = v(\"surface-1\");\n });\n\n // Pending changes listener — show/hide floating panel above toolbar\n onPendingChange(() => {\n const count = state.pending.size;\n if (count > 0) {\n showPendingPanel(count);\n } else {\n hidePendingPanel();\n }\n });\n\n let editModeEscListener: ((e: KeyboardEvent) => void) | null = null;\n\n // Edit toggle implementation (closes over controls)\n function toggleEditMode() {\n editActive = !editActive;\n state.editMode = editActive;\n\n const svgEl = editBtn.querySelector(\"svg\");\n if (editActive) {\n // accent-soft is DERIVED from the accent (see tokens.ts) rather than\n // built by appending hex alpha — `${accent()}22` silently produced an\n // invalid colour for any accent that wasn't 6-digit hex.\n editBtn.dataset.canciaActive = \"1\";\n editBtn.style.background = v(\"accent-soft\");\n editBtn.style.color = v(\"accent\");\n if (svgEl) svgEl.style.stroke = v(\"accent\");\n editBtn.dataset.canciaTooltip = \"Stop editing (Esc)\";\n attachHighlight((selection) => {\n if (selection.kind === \"field\") {\n openPopup(selection.key, selection.fieldType, selection.el, () => {});\n return;\n }\n // selection.kind === \"list\"\n const schema = state.schemas[selection.listName];\n if (!schema) {\n console.warn(`[cancia] No schema found for list \"${selection.listName}\". Define it in src/cms/schemas.ts.`);\n return;\n }\n openListPanel({\n schema,\n onAddEntry: (locale) => {\n openEntryModal({\n schema,\n locale,\n entry: null,\n onSaved: () => { refreshListPanel(); },\n });\n },\n onEditEntry: (entry, locale) => {\n openEntryModal({\n schema,\n locale,\n entry,\n onSaved: () => { refreshListPanel(); },\n });\n },\n onTranslateEntry: (id, sourceEntry, targetLocale) => {\n openEntryModal({\n schema,\n locale: targetLocale,\n entry: null,\n translateFromEntry: sourceEntry,\n fixedId: id,\n onSaved: () => { refreshListPanel(); },\n });\n },\n });\n });\n // Esc cascade: modal → panel → exit edit mode\n editModeEscListener = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n if (isEntryModalOpen()) {\n // The modal owns its own Esc handler (capture: true) so this branch\n // only runs once the modal is gone. Guard anyway for safety.\n return;\n }\n if (isListPanelOpen()) {\n closeListPanel();\n return;\n }\n if (!document.querySelector(\"[data-cancia-popup]\")) {\n toggleEditMode();\n }\n };\n document.addEventListener(\"keydown\", editModeEscListener, true);\n } else {\n delete editBtn.dataset.canciaActive;\n editBtn.style.background = \"transparent\";\n editBtn.style.color = v(\"fg-strong\");\n if (svgEl) svgEl.style.stroke = \"\";\n editBtn.dataset.canciaTooltip = \"Edit\";\n detachHighlight();\n closePopup();\n closeEntryModal();\n closeListPanel();\n if (editModeEscListener) {\n document.removeEventListener(\"keydown\", editModeEscListener, true);\n editModeEscListener = null;\n }\n }\n }\n\n return bar;\n}\n\n// ---------------------------------------------------------------------------\n// Expand / collapse\n// ---------------------------------------------------------------------------\n\nfunction expand(bar: HTMLElement, icon: HTMLElement, controls: HTMLElement) {\n if (isExpanded) return;\n isExpanded = true;\n\n // Esc collapses toolbar when expanded but not in edit mode\n expandedEscListener = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && !document.querySelector(\"[data-cancia-popup]\") && !state.editMode) {\n collapse(bar, icon, controls);\n }\n };\n document.addEventListener(\"keydown\", expandedEscListener, true);\n\n // Measure the natural content width SYNCHRONOUSLY, then animate to it.\n //\n // This deliberately does NOT defer the measurement into requestAnimationFrame.\n // It used to, and the bar could be left permanently as a \"wide empty pill\":\n // `width: max-content` is only a MEASUREMENT state, and if the rAF chain that\n // was supposed to replace it with a real pixel width never ran — a background\n // or throttled tab starves rAF, and a collapse landing mid-chain cancelled it\n // — the bar stayed stretched to max-content with its controls still hidden.\n //\n // Measuring in the same synchronous block removes the failure entirely: the\n // transient `max-content` never survives past this function, so there is no\n // window in which an interruption can strand it. Forcing one layout here is\n // cheap and happens once per expand.\n controls.style.visibility = \"hidden\";\n controls.style.opacity = \"0\";\n controls.style.pointerEvents = \"none\";\n bar.style.borderRadius = \"100px\";\n\n // Measure, then immediately restore the collapsed width as the transition's\n // starting point. Both reads/writes are flushed by the offsetWidth reflows.\n bar.style.width = \"max-content\";\n const naturalW = bar.scrollWidth;\n bar.style.width = \"52px\";\n controls.style.visibility = \"\";\n void bar.offsetWidth; // commit the 52px \"from\" state before widening\n\n bar.style.width = `${naturalW}px`;\n bar.style.cursor = \"default\";\n icon.style.opacity = \"0\";\n icon.style.transform = \"scale(0.5) rotate(-90deg)\";\n\n revealTimer = setTimeout(() => {\n revealTimer = null;\n // A collapse may have landed inside this 80ms window. If so, this reveal is\n // stale — applying it would re-show the controls on a bar that is closing.\n // Bail out and let collapse win.\n if (!isExpanded) return;\n controls.style.pointerEvents = \"auto\";\n controls.style.visibility = \"\";\n // Animate with a TRANSITION, not a keyframe animation.\n //\n // Both expand and collapse previously ran fill-mode `both` keyframes\n // over the same element. A filled animation keeps applying its end\n // frame forever, and an inline `opacity` cannot override it — so a\n // collapse/expand race left the controls pinned at the *first* frame\n // (opacity 0, scale 0.6) while the bar had already widened to full\n // width. The result: a wide empty pill.\n //\n // A transition has no fill mode and no lingering state: whatever the\n // property is set to last, wins. Interrupting it mid-flight is fine.\n controls.style.animation = \"none\";\n controls.style.transition = `opacity ${v(\"duration\")} ${v(\"ease\")}, transform ${v(\"duration\")} ${v(\"ease\")}`;\n void controls.offsetWidth; // commit the \"from\" state before transitioning\n controls.style.opacity = \"1\";\n controls.style.transform = \"scale(1)\";\n }, 80);\n}\n\nfunction collapse(bar: HTMLElement, icon: HTMLElement, controls: HTMLElement) {\n if (!isExpanded) return;\n isExpanded = false;\n hideBtnTooltip();\n\n // Cancel any queued reveal from an expand that hasn't finished opening.\n // Without this, the timer fires ~80ms from now and re-shows the controls on\n // a bar that is closing — the interrupted-mid-open case.\n if (revealTimer !== null) {\n clearTimeout(revealTimer);\n revealTimer = null;\n }\n\n if (expandedEscListener) {\n document.removeEventListener(\"keydown\", expandedEscListener, true);\n expandedEscListener = null;\n }\n\n controls.style.pointerEvents = \"none\";\n // Transition out (see the note in expand): no fill mode, so nothing lingers\n // to fight the next expand.\n controls.style.animation = \"none\";\n controls.style.transition = `opacity ${v(\"duration-fast\")} ${v(\"ease-out\")}, transform ${v(\"duration-fast\")} ${v(\"ease-out\")}`;\n controls.style.opacity = \"0\";\n controls.style.transform = \"scale(0.6)\";\n\n setTimeout(() => {\n // Mirror image of the guard in expand(): an expand may have landed inside\n // this 100ms window, in which case shrinking the bar now would strand it\n // narrow with its controls already fading in.\n if (isExpanded) return;\n bar.style.width = \"52px\";\n bar.style.borderRadius = \"26px\"; // half of the 52px collapsed size\n bar.style.cursor = \"pointer\";\n icon.style.opacity = \"1\";\n icon.style.transform = \"scale(1) rotate(0deg)\";\n }, 100);\n}\n\n// ---------------------------------------------------------------------------\n// Save handler\n// ---------------------------------------------------------------------------\n\nasync function handleSave(btn?: HTMLButtonElement) {\n if (btn) { btn.disabled = true; btn.style.opacity = \"0.5\"; }\n\n try {\n await flushPending();\n flashPanelMessage(\"Saved\", \"success\");\n } catch (err) {\n console.error(err);\n if (isAuthError(err)) { unmountToolbar(); return; }\n if (btn) { btn.disabled = false; btn.style.opacity = \"1\"; }\n flashPanelMessage(\"Save failed\", \"error\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Publish handler\n// ---------------------------------------------------------------------------\n\nasync function handlePublish(btn: HTMLButtonElement) {\n btn.disabled = true;\n btn.style.opacity = \"0.5\";\n\n try {\n if (state.pending.size > 0) await flushPending();\n await triggerPublish();\n showToast(\"Published!\", \"success\");\n } catch (err) {\n console.error(err);\n showToast(\"Publish failed\", \"error\");\n } finally {\n btn.disabled = false;\n btn.style.opacity = \"1\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Toast\n// ---------------------------------------------------------------------------\n\nfunction showToast(message: string, type: \"success\" | \"error\") {\n const toast = document.createElement(\"div\");\n markUi(toast);\n const color = type === \"success\" ? v(\"success\") : v(\"danger\");\n // Enters with a TRANSITION rather than the old fill-mode `cancia-fade-in`\n // keyframe — see the note in expand(). A toast is short-lived and can be\n // replaced by the next one mid-flight, which is exactly the case a filled\n // animation strands at its first frame.\n toast.style.cssText = `\n position: fixed; bottom: 80px; right: ${v(\"space-6\")}; z-index: ${v(\"z-bar\")};\n display: flex; align-items: center; gap: ${v(\"space-2\")};\n background: ${v(\"surface-1\")};\n backdrop-filter: ${v(\"blur\")};\n -webkit-backdrop-filter: ${v(\"blur\")};\n border: 1px solid ${v(\"border\")};\n border-radius: ${v(\"radius\")}; padding: 10px 14px;\n font-size: ${v(\"text-base\")}; font-weight: 500; color: ${v(\"fg-strong\")};\n box-shadow: ${v(\"shadow\")};\n pointer-events: none;\n opacity: 0; transform: translateY(4px);\n transition: opacity ${v(\"duration\")} ${v(\"ease\")}, transform ${v(\"duration\")} ${v(\"ease\")};\n `;\n const dot = document.createElement(\"span\");\n dot.style.cssText = `width: 7px; height: 7px; border-radius: 50%; background: ${color}; flex-shrink: 0;`;\n const label = document.createElement(\"span\");\n label.textContent = message;\n toast.appendChild(dot);\n toast.appendChild(label);\n document.body.appendChild(toast);\n\n // Commit the \"from\" state, then transition in on the next frame.\n requestAnimationFrame(() => {\n toast.style.opacity = \"1\";\n toast.style.transform = \"translateY(0)\";\n });\n\n setTimeout(() => {\n // Exit along the same path it entered (apple-design §7), with ease-out so\n // it gets out of the way quickly.\n toast.style.transition = `opacity ${v(\"duration-fast\")} ${v(\"ease-out\")}, transform ${v(\"duration-fast\")} ${v(\"ease-out\")}`;\n toast.style.opacity = \"0\";\n toast.style.transform = \"translateY(4px)\";\n setTimeout(() => toast.remove(), 300);\n }, 2000);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * A toolbar action with a VISIBLE LABEL.\n *\n * The toolbar used to be four unlabelled icons explained only by a hover\n * tooltip. Its users are the client — a coach, a school administrator — not\n * developers. A paper-plane glyph does not read as \"Publish\" to them, and on\n * a touch device there is no hover to reveal the tooltip at all. Labels are\n * not decoration here; they are the difference between usable and guessable.\n */\nfunction makeActionButton(\n svg: string,\n labelText: string,\n onClick: () => void,\n): HTMLButtonElement {\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.style.cssText = actionButton();\n btn.setAttribute(\"aria-label\", labelText);\n\n const icon = document.createElement(\"span\");\n icon.style.cssText = `display: flex; flex-shrink: 0;`;\n icon.innerHTML = svg;\n const svgEl = icon.querySelector(\"svg\");\n if (svgEl) {\n svgEl.style.cssText = \"display:block;flex-shrink:0;overflow:visible;\";\n svgEl.setAttribute(\"stroke-width\", \"1.6\");\n }\n\n const label = document.createElement(\"span\");\n label.textContent = labelText;\n label.dataset.canciaLabel = \"1\";\n\n btn.appendChild(icon);\n btn.appendChild(label);\n\n btn.addEventListener(\"mouseenter\", () => {\n if (!btn.disabled && btn.dataset.canciaActive !== \"1\") {\n btn.style.background = v(\"surface-hover\");\n btn.style.color = v(\"fg-strong\");\n }\n });\n btn.addEventListener(\"mouseleave\", () => {\n if (btn.dataset.canciaActive !== \"1\") {\n btn.style.background = \"transparent\";\n btn.style.color = v(\"fg\");\n }\n });\n // Respond on pointer-DOWN: waiting for click to acknowledge a press reads\n // as lag, and lag is what kills the sense of directness.\n attachPress(btn);\n btn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n onClick();\n });\n return btn;\n}\n\nfunction makeIconButton(\n svg: string,\n title: string,\n onClick: () => void,\n): HTMLButtonElement {\n const btn = document.createElement(\"button\");\n btn.style.cssText = `\n ${iconButton(34)}\n border-radius: ${v(\"radius-full\")};\n color: ${v(\"fg-strong\")};\n flex-shrink: 0; padding: 0;\n transition: color ${v(\"duration-fast\")} ${v(\"ease\")},\n background ${v(\"duration-fast\")} ${v(\"ease\")},\n transform 0.1s ${v(\"ease\")};\n `;\n btn.innerHTML = svg;\n // Force consistent stroke-width on all child SVGs to prevent host CSS override\n const svgEl = btn.querySelector(\"svg\");\n if (svgEl) {\n svgEl.style.cssText = \"display:block;flex-shrink:0;overflow:visible;margin:auto;\";\n svgEl.setAttribute(\"stroke-width\", \"1.5\");\n }\n btn.dataset.canciaTooltip = title;\n btn.addEventListener(\"mouseenter\", () => {\n if (!btn.disabled) {\n btn.style.background = v(\"surface-active\");\n showBtnTooltip(btn, btn.dataset.canciaTooltip ?? title);\n }\n });\n btn.addEventListener(\"mouseleave\", () => {\n // An \"active\" button (edit mode on) keeps its accent fill. That state is\n // set externally via data-cancia-active — previously this sniffed the\n // inline background for a hex substring, which broke for any accent whose\n // rgb() form didn't literally contain those characters.\n if (btn.dataset.canciaActive !== \"1\") btn.style.background = \"transparent\";\n hideBtnTooltip();\n });\n btn.addEventListener(\"click\", (e) => { e.stopPropagation(); hideBtnTooltip(); onClick(); });\n return btn;\n}\n\nfunction makeDivider(): HTMLElement {\n const d = document.createElement(\"span\");\n d.style.cssText = `width: 1px; height: 14px; background: ${v(\"border\")}; flex-shrink: 0; margin: 0 1px;`;\n return d;\n}\n\n// ---------------------------------------------------------------------------\n// Pending panel — floats above the toolbar\n// ---------------------------------------------------------------------------\n\nfunction showPendingPanel(count: number) {\n if (!pendingPanelEl) {\n pendingPanelEl = document.createElement(\"div\");\n markUi(pendingPanelEl);\n // Enters with a transition, not the old fill-mode `cancia-fade-in` — the\n // panel is shown/hidden on every pending change, so it is a prime\n // candidate for the open/close race that strands a filled animation.\n pendingPanelEl.style.cssText = `\n position: fixed;\n bottom: 80px;\n right: ${v(\"space-6\")};\n z-index: ${v(\"z-panel\")};\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: ${v(\"space-3\")};\n background: ${v(\"surface-1\")};\n backdrop-filter: ${v(\"blur\")};\n -webkit-backdrop-filter: ${v(\"blur\")};\n border: 1px solid ${v(\"border\")};\n border-radius: ${v(\"radius\")};\n padding: 0;\n box-shadow: ${v(\"shadow\")};\n width: max-content;\n overflow: hidden;\n opacity: 0; transform: translateY(4px);\n transition: opacity ${v(\"duration\")} ${v(\"ease\")}, transform ${v(\"duration\")} ${v(\"ease\")};\n `;\n\n const label = document.createElement(\"span\");\n label.dataset.canciaPendingLabel = \"1\";\n label.style.cssText = `font-size: ${v(\"text-sm\")}; font-weight: 500; color: ${v(\"fg-muted\")}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;`;\n\n // The one filled button in the bar: `accent` on `accent-fg`. On the light\n // theme that is near-black on white — the inverse of the old white-on-dark\n // pill, and the same primary treatment the drawer's Save uses.\n const saveBtn = document.createElement(\"button\");\n saveBtn.dataset.canciaSaveBtn = \"1\";\n saveBtn.title = \"Save changes\";\n saveBtn.style.cssText = `\n padding: 5px 10px; border-radius: ${v(\"radius-sm\")}; border: none; cursor: pointer;\n background: ${v(\"accent\")}; color: ${v(\"accent-fg\")};\n font-size: ${v(\"text-sm\")}; font-weight: 600; letter-spacing: 0.01em;\n transition: opacity ${v(\"duration-fast\")} ${v(\"ease\")}, transform ${v(\"duration-fast\")} ${v(\"ease\")};\n flex-shrink: 0;\n `;\n saveBtn.textContent = \"Save\";\n saveBtn.addEventListener(\"mouseenter\", () => { saveBtn.style.opacity = \"0.85\"; });\n saveBtn.addEventListener(\"mouseleave\", () => { saveBtn.style.opacity = \"1\"; });\n attachPress(saveBtn);\n saveBtn.addEventListener(\"click\", (e) => { e.stopPropagation(); handleSave(saveBtn); });\n\n const undoBtn = document.createElement(\"button\");\n undoBtn.title = \"Discard changes\";\n undoBtn.style.cssText = `\n padding: 5px 10px; border-radius: ${v(\"radius-sm\")}; border: 1px solid ${v(\"border\")}; cursor: pointer;\n background: transparent; color: ${v(\"fg-muted\")};\n font-size: ${v(\"text-sm\")}; font-weight: 500; letter-spacing: 0.01em;\n transition: color ${v(\"duration-fast\")} ${v(\"ease\")}, border-color ${v(\"duration-fast\")} ${v(\"ease\")};\n flex-shrink: 0;\n `;\n undoBtn.textContent = \"Discard\";\n undoBtn.addEventListener(\"mouseenter\", () => { undoBtn.style.color = v(\"fg-strong\"); undoBtn.style.borderColor = v(\"border-strong\"); });\n undoBtn.addEventListener(\"mouseleave\", () => { undoBtn.style.color = v(\"fg-muted\"); undoBtn.style.borderColor = v(\"border\"); });\n attachPress(undoBtn);\n undoBtn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n revertPending();\n closePopup();\n hidePendingPanel();\n });\n\n // Inner slot: stacks current content + flash message via grid\n const slot = document.createElement(\"div\");\n slot.dataset.canciaPanelSlot = \"1\";\n slot.style.cssText = `display:grid;place-items:center;overflow:hidden;`;\n\n // Default row: label + undo + save button\n const row = document.createElement(\"div\");\n row.dataset.canciaPanelRow = \"1\";\n row.style.cssText = `\n grid-area: 1/1; display: flex; align-items: center; gap: 6px;\n padding: 7px 7px 7px 12px;\n transition: transform ${v(\"duration\")} ${v(\"ease-out\")};\n `;\n row.appendChild(label);\n row.appendChild(undoBtn);\n row.appendChild(saveBtn);\n\n // Flash row: success/error message (hidden above initially)\n const flash = document.createElement(\"div\");\n flash.dataset.canciaPanelFlash = \"1\";\n flash.style.cssText = `\n grid-area: 1/1; display: flex; align-items: center; gap: 7px;\n font-size: ${v(\"text-sm\")}; font-weight: 500; color: ${v(\"fg-strong\")}; white-space: nowrap;\n padding: 7px ${v(\"space-3\")};\n transform: translateY(-150%);\n transition: transform ${v(\"duration\")} ${v(\"ease-out\")};\n `;\n\n slot.appendChild(row);\n slot.appendChild(flash);\n pendingPanelEl.appendChild(slot);\n document.body.appendChild(pendingPanelEl);\n\n // Commit the \"from\" state, then transition in on the next frame.\n const panel = pendingPanelEl;\n requestAnimationFrame(() => {\n panel.style.opacity = \"1\";\n panel.style.transform = \"translateY(0)\";\n });\n }\n\n const label = pendingPanelEl.querySelector<HTMLElement>(\"[data-cancia-pending-label]\");\n if (label) label.textContent = `${count} unsaved change${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction flashPanelMessage(message: string, type: \"success\" | \"error\") {\n if (!pendingPanelEl) return;\n const color = type === \"success\" ? v(\"success\") : v(\"danger\");\n\n const row = pendingPanelEl.querySelector<HTMLElement>(\"[data-cancia-panel-row]\");\n const flash = pendingPanelEl.querySelector<HTMLElement>(\"[data-cancia-panel-flash]\");\n if (!row || !flash) return;\n\n // Build flash content\n flash.innerHTML = `<span style=\"width:7px;height:7px;border-radius:50%;background:${color};flex-shrink:0;display:block;\"></span>${message}`;\n\n // Slide current content down, flash content in from above\n row.style.transform = \"translateY(150%)\";\n flash.style.transform = \"translateY(0)\";\n\n setTimeout(() => hidePendingPanel(), 1600);\n}\n\nfunction hidePendingPanel() {\n if (!pendingPanelEl) return;\n const panel = pendingPanelEl;\n pendingPanelEl = null;\n // Exits along the same path it entered (down + fade), with ease-out.\n panel.style.transition = `opacity 0.2s ${v(\"ease-out\")}, transform 0.2s ${v(\"ease-out\")}`;\n panel.style.opacity = \"0\";\n panel.style.transform = \"translateY(4px)\";\n setTimeout(() => panel.remove(), 220);\n}\n\n// ---------------------------------------------------------------------------\n// Mount / unmount\n// ---------------------------------------------------------------------------\n\nexport function mountToolbar() {\n if (toolbarEl) return;\n isExpanded = false;\n toolbarEl = buildToolbar();\n document.body.appendChild(toolbarEl);\n}\n\nexport function unmountToolbar() {\n detachHighlight();\n closePopup();\n isExpanded = false;\n // Clean up shared tooltip\n btnTooltipEl?.remove();\n btnTooltipEl = null;\n // Clean up pending panel\n pendingPanelEl?.remove();\n pendingPanelEl = null;\n if (toolbarEl) {\n toolbarEl.style.animation = `cancia-exit ${v(\"duration-exit\")} ${v(\"ease-out\")} both`;\n setTimeout(() => {\n toolbarEl?.remove();\n toolbarEl = null;\n }, 260);\n }\n}\n","// =============================================================================\n// Cancia Toolbar — Entry Point\n// =============================================================================\n\nimport type { CanciaConfig } from \"./types\";\nimport { state, applyOverlay } from \"./state\";\nimport { fetchContent, fetchSchemas } from \"./api\";\nimport { mountToolbar, unmountToolbar } from \"./toolbar\";\nimport { onPendingChange } from \"./events\";\n\nexport type { CanciaConfig } from \"./types\";\nexport type { CMSData, CMSEntry, PendingChange } from \"./types\";\n\nconst SESSION_KEY = \"cancia_session\";\n\n// ---------------------------------------------------------------------------\n// Session helpers — token lives in sessionStorage only\n// ---------------------------------------------------------------------------\n\nfunction getSessionToken(): string | null {\n try {\n return sessionStorage.getItem(SESSION_KEY);\n } catch {\n return null;\n }\n}\n\nfunction setSessionToken(token: string): void {\n try {\n sessionStorage.setItem(SESSION_KEY, token);\n } catch {}\n}\n\nexport function clearSession(): void {\n try {\n sessionStorage.removeItem(SESSION_KEY);\n } catch {}\n}\n\n// ---------------------------------------------------------------------------\n// Magic URL: ?cancia=<token>\n// Validates against the API, stores in sessionStorage, strips from URL.\n// ---------------------------------------------------------------------------\n\nasync function handleMagicUrl(): Promise<string | null> {\n const params = new URLSearchParams(window.location.search);\n const token = params.get(\"cancia\");\n if (!token) return null;\n\n // Strip ?cancia=... from the URL immediately (before any validation)\n params.delete(\"cancia\");\n const newSearch = params.toString();\n const cleanUrl = window.location.pathname + (newSearch ? `?${newSearch}` : \"\") + window.location.hash;\n window.history.replaceState(null, \"\", cleanUrl);\n\n // Validate with the server\n try {\n const res = await fetch(\"/api/cancia/auth\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token }),\n });\n if (res.ok) {\n setSessionToken(token);\n return token;\n }\n } catch {}\n\n console.warn(\"Cancia: magic link token is invalid or expired.\");\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// init()\n// ---------------------------------------------------------------------------\n\nexport async function init(config: CanciaConfig): Promise<void> {\n state.config = config;\n state.activeLang = config.languages[0];\n\n // Preload CMS overrides from window if available (injected at build time)\n if (window.__CANCIA_DATA__) {\n state.cmsData = window.__CANCIA_DATA__;\n }\n\n try {\n const fresh = await fetchContent();\n state.cmsData = fresh;\n } catch (err: unknown) {\n if (!config.public && err instanceof Error && err.message.includes(\"401\")) {\n clearSession();\n console.warn(\"Cancia: session expired or invalid, toolbar not mounted.\");\n return;\n }\n console.warn(\"Cancia: could not fetch CMS content, using preloaded data.\");\n }\n\n // Overlay saved drafts onto the (prerendered) page so editors see their\n // unpublished changes. Uses whatever cmsData ended up loaded above — fresh\n // fetch, or the window.__CANCIA_DATA__ preload if the fetch failed.\n applyOverlay();\n\n // Schemas are best-effort: a v1 install with no schemas.ts returns {}.\n // Lists with no schema are simply unclickable from the toolbar.\n try {\n state.schemas = await fetchSchemas();\n } catch {\n state.schemas = {};\n }\n\n mountToolbar();\n}\n\n// ---------------------------------------------------------------------------\n// Auto-init from window.__CANCIA__\n// Checks magic URL first, then falls back to existing sessionStorage session.\n// Does nothing if no valid session exists — toolbar stays hidden from visitors.\n// ---------------------------------------------------------------------------\n\nasync function tryAutoInit() {\n if (!window.__CANCIA__) return;\n\n // Public mode — skip auth, always show toolbar (demo sites only)\n if (window.__CANCIA__.public) {\n init(window.__CANCIA__);\n return;\n }\n\n // Check magic URL first, then existing session\n const token = (await handleMagicUrl()) ?? getSessionToken();\n if (!token) return; // No session — normal visitor, nothing to do\n\n // Attach the session token to state so API calls can use it\n state.sessionToken = token;\n\n // Wire up logout handler — called by the toolbar button\n state.onLogout = () => {\n clearSession();\n unmountToolbar();\n };\n\n init(window.__CANCIA__);\n}\n\nif (typeof document !== \"undefined\") {\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", tryAutoInit);\n } else {\n tryAutoInit();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Re-exports for programmatic use\n// ---------------------------------------------------------------------------\n\nexport { unmountToolbar as destroy } from \"./toolbar\";\nexport { getValue } from \"./state\";\nexport { onPendingChange };\n"],"mappings":"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","names":["accent","accent","accent","renderTabs","input","hint","label","fieldType","styleInjected","injectStyles","v","rowsToPortableText","portableTextToRows","portableTextSubsetSchema","PT_STYLES","BACKDROP_Z","backdropEl","styleInjected","injectStyles","accent","label","getValue","input","v","PT_STYLES","label","portableTextSubsetSchema","portableTextToRows","rowsToPortableText","injectStyles","BACKDROP_Z","backdropEl","accent","styleInjected","injectStyles","label"]}
|