@cancia/toolbar 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"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 */\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 // 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\" }\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\" {\n if (el.dataset.cmsType === \"image\") return \"image\";\n return el.tagName === \"IMG\" ? \"image\" : \"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 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 : 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\nexport function attachHighlight(selectCallback: SelectCallback) {\n injectStyles();\n onSelect = selectCallback;\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 and image upload.\n// =============================================================================\n\nimport { state, getValue, setPending, applyOverlay } from \"./state\";\nimport { uploadImage } from \"./api\";\nimport { onPendingChange } from \"./events\";\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\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\",\n anchorEl: HTMLElement,\n onClose: () => void\n) {\n closePopup();\n\n const popup =\n fieldType === \"image\"\n ? buildImagePopup(key, anchorEl, () => { onClose(); closePopup(); })\n : buildTextPopup(key, anchorEl, () => { onClose(); closePopup(); });\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, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\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, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\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/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.\n if (el.dataset.cmsType === \"link\" || el.tagName === \"A\") {\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 const labelEl = el.querySelector<HTMLElement>(\"[data-cms-label]\");\n if (labelEl) labelEl.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 // An annotated anchor is a link (label + href), not plain text: editing only\n // its text would leave the href stale and the CTA broken.\n if (el.tagName === \"A\") return \"link\";\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]. Fall back to the element itself when there\n // is no marker (a plain <a> with no icon).\n const labelNode = anchorEl.querySelector<HTMLElement>(\"[data-cms-label]\") ?? anchorEl;\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 node,\n // NOT the anchor — setting textContent on the anchor would delete its icon.\n const paint = () => {\n labelNode.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, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\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, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\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"]}