@deneb-ui/cli 2.0.23 → 2.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +18 -0
- package/package.json +6 -1
- package/src/arc/__tests__/arc.test.cjs +46 -6
- package/src/arc/ast.cjs +17 -1
- package/src/arc/font-plan.cjs +65 -0
- package/src/arc/index.cjs +5 -6
- package/src/arc/learning.cjs +26 -0
- package/src/arc/manifest.cjs +17 -0
- package/src/arc/planner.cjs +26 -1
- package/src/arc/printer.cjs +32 -2
- package/src/arc/style-candidates.cjs +72 -0
- package/src/arc/transformer.cjs +57 -1
- package/src/arc/version.cjs +1 -1
- package/src/common/style-validation.ts +30 -0
- package/src/tools/deneb-fonts.cjs +114 -0
- package/src/tools/template-preview-focus-bridge.cjs +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
|
-
// Generated from visual editor bridge (
|
|
4
|
-
module.exports = ";(function fivoraPreviewFocusBridge(resolveParentOrigin, buildUniversalThemeCss, replaceColorLiterals, universalThemeStyleId, enforceSelectedPages) {\n const PREVIOUS_PREVIEW_PREFIX = `${['MARKET', 'PLACE'].join('')}_PREVIEW_`;\n const previousPreviewMessage = (suffix) => `${PREVIOUS_PREVIEW_PREFIX}${suffix}`;\n const previousPreviewStorageKey = (suffix) => `__${PREVIOUS_PREVIEW_PREFIX}${suffix}__`;\n const FOCUS_MESSAGE = 'FIVORA_PREVIEW_FOCUS_PAGE';\n const LEGACY_FOCUS_MESSAGE = previousPreviewMessage('FOCUS_PAGE');\n const FOCUS_RESULT_MESSAGE = 'FIVORA_PREVIEW_FOCUS_RESULT';\n const LEGACY_FOCUS_RESULT_MESSAGE = previousPreviewMessage('FOCUS_RESULT');\n const READY_MESSAGE = 'FIVORA_PREVIEW_READY';\n const LEGACY_READY_MESSAGE = previousPreviewMessage('READY');\n const ACTIVE_ATTRIBUTE = 'data-fivora-preview-active-field';\n const RESOLVED_PATH_ATTRIBUTE = 'data-fivora-resolved-field-path';\n const EMPTY_EDITABLE_ATTRIBUTE = 'data-fivora-empty-editable';\n const EMPTY_COLLECTION_ATTRIBUTE = 'data-fivora-empty-collection';\n const LIST_PATH_ATTRIBUTE = 'data-preview-list-path';\n const ITEM_PATH_ATTRIBUTE = 'data-preview-item-path';\n const STATIC_ATTRIBUTE = 'data-preview-static';\n const PENDING_KEY = '__FIVORA_UNIVERSAL_PREVIEW_FOCUS__';\n const RESOLVED_TARGETS_KEY = '__FIVORA_VISUAL_EDITOR_TARGETS__';\n const PARENT_ORIGIN_KEY = '__FIVORA_PREVIEW_PARENT_ORIGIN__';\n const LEGACY_PARENT_ORIGIN_KEY = previousPreviewStorageKey('PARENT_ORIGIN');\n const SITE_DATA_CACHE_KEY = '__FIVORA_PREVIEW_SITE_DATA_CACHE__';\n const LEGACY_SITE_DATA_CACHE_KEY = previousPreviewStorageKey('SITE_DATA_CACHE');\n const SITE_DATA_GLOBAL_KEY = '__FIVORA_PREVIEW_SITE_DATA__';\n const LEGACY_SITE_DATA_GLOBAL_KEY = previousPreviewStorageKey('SITE_DATA');\n const DATA_MESSAGE = 'FIVORA_PREVIEW_SITE_DATA';\n const LEGACY_DATA_MESSAGE = previousPreviewMessage('SITE_DATA');\n const DATA_APPLIED_MESSAGE = 'FIVORA_PREVIEW_SITE_DATA_APPLIED';\n const LEGACY_DATA_APPLIED_MESSAGE = previousPreviewMessage('SITE_DATA_APPLIED');\n const CONTENT_PATCH_MESSAGE = 'FIVORA_PREVIEW_CONTENT_PATCH';\n const LEGACY_CONTENT_PATCH_MESSAGE = previousPreviewMessage('CONTENT_PATCH');\n const COLOR_REPLACEMENT_STYLE_ID = 'fivora-template-color-replacements';\n // One delayed relay is enough for late-mounting SiteDataProviders; more\n // relays re-merge large content payloads and freeze heavy templates.\n const SITE_DATA_RELAY_DELAYS_MS = [200];\n const SITE_DATA_PERSIST_DELAY_MS = 2500;\n // While typing, keep React/template relays rare. DOM patches carry live preview.\n const CONTENT_ONLY_RELAY_DELAY_MS = 1600;\n const CONTENT_ONLY_PERSIST_DELAY_MS = 12000;\n const TEXT_SELECTOR = 'h1, h2, h3, h4, h5, h6, p, span, a, button, address, li, dt, dd, label, strong, em, small';\n let activeHighlights = [];\n const originalStylesheetCss = new Map();\n let colorReplacementRequest = 0;\n let applyingSiteData = false;\n let pendingSiteData = null;\n let pendingSiteDataOptions;\n let siteDataRelayTimers = [];\n let siteDataPersistTimer = null;\n let latestPublishedSiteData = null;\n let lastAppliedThemeSignature = '';\n let lastColorReplacementSignature = '';\n let lastAppliedPagesSignature = '';\n function clearPendingFocus() {\n try {\n window.sessionStorage.removeItem(PENDING_KEY);\n }\n catch {\n // Storage may be disabled.\n }\n }\n function readRememberedParentOrigin() {\n try {\n return (window.sessionStorage.getItem(PARENT_ORIGIN_KEY) ||\n window.sessionStorage.getItem(LEGACY_PARENT_ORIGIN_KEY));\n }\n catch {\n return null;\n }\n }\n function rememberParentOrigin(origin) {\n if (!origin)\n return;\n try {\n window.sessionStorage.setItem(PARENT_ORIGIN_KEY, origin);\n }\n catch {\n // The direct parent/source checks still work without session storage.\n }\n }\n function clearSiteDataRelayTimers() {\n for (const timer of siteDataRelayTimers) {\n window.clearTimeout(timer);\n }\n siteDataRelayTimers = [];\n }\n function collectSiteDataRelayOrigins() {\n const origins = new Set();\n if (parentOrigin)\n origins.add(parentOrigin);\n origins.add(window.location.origin);\n const remembered = readRememberedParentOrigin();\n if (remembered)\n origins.add(remembered);\n try {\n if (document.referrer) {\n const referrerOrigin = new URL(document.referrer).origin;\n if (referrerOrigin && referrerOrigin !== 'null') {\n origins.add(referrerOrigin);\n }\n }\n }\n catch {\n // Referrer may be opaque or unparsable.\n }\n try {\n const ancestor = window.location.ancestorOrigins?.item(0);\n if (ancestor)\n origins.add(ancestor);\n }\n catch {\n // ancestorOrigins is not available in every browser.\n }\n return Array.from(origins);\n }\n function relaySiteDataToTemplateRuntime(siteData, options) {\n // Prefer a single-origin relay on the hydrate critical path. Full fan-out\n // is delayed so we avoid N structured clones before first paint.\n const allOrigins = collectSiteDataRelayOrigins();\n const origins = options?.fanOut ? allOrigins : allOrigins.slice(0, 1);\n for (const origin of origins) {\n // Approved packages can contain either the current Fivora runtime or\n // the legacy Fivora runtime. Relay both protocol names so updating\n // the injected bridge never strands an already-approved template on its\n // bundled demo data.\n for (const type of [DATA_MESSAGE, LEGACY_DATA_MESSAGE]) {\n try {\n window.dispatchEvent(new MessageEvent('message', {\n // Mark relays so this bridge never re-enters publishSiteData on\n // its own synthetic events (that caused recursive publishes).\n data: {\n type,\n siteData,\n __fivoraBridgeRelay: true,\n },\n origin,\n source: window.parent,\n }));\n }\n catch {\n // Some environments reject synthetic MessageEvent construction.\n }\n }\n }\n }\n function persistSiteData(siteData, options) {\n latestPublishedSiteData = siteData;\n try {\n window[SITE_DATA_GLOBAL_KEY] =\n siteData;\n window[LEGACY_SITE_DATA_GLOBAL_KEY] = siteData;\n }\n catch {\n // Window may be non-extensible in locked-down embeds.\n }\n const writeSessionCache = () => {\n siteDataPersistTimer = null;\n try {\n const serialized = JSON.stringify(latestPublishedSiteData);\n window.sessionStorage.setItem(SITE_DATA_CACHE_KEY, serialized);\n window.sessionStorage.setItem(LEGACY_SITE_DATA_CACHE_KEY, serialized);\n }\n catch {\n // Storage may be disabled or over quota for large templates.\n }\n };\n if (options?.immediate) {\n if (siteDataPersistTimer !== null) {\n window.clearTimeout(siteDataPersistTimer);\n siteDataPersistTimer = null;\n }\n writeSessionCache();\n return;\n }\n if (siteDataPersistTimer !== null) {\n window.clearTimeout(siteDataPersistTimer);\n }\n siteDataPersistTimer = window.setTimeout(writeSessionCache, SITE_DATA_PERSIST_DELAY_MS);\n }\n function pagesSignature(siteData) {\n const record = siteData && typeof siteData === 'object' && !Array.isArray(siteData)\n ? siteData\n : null;\n const requirements = record?.requirements &&\n typeof record.requirements === 'object' &&\n !Array.isArray(record.requirements)\n ? record.requirements\n : null;\n const template = record?.template &&\n typeof record.template === 'object' &&\n !Array.isArray(record.template)\n ? record.template\n : null;\n const structure = template?.structure &&\n typeof template.structure === 'object' &&\n !Array.isArray(template.structure)\n ? template.structure\n : null;\n try {\n return JSON.stringify({\n requiredPages: requirements?.requiredPages ?? null,\n pages: structure?.pages ?? null,\n pageDefinitions: template?.pageDefinitions ?? structure?.pageDefinitions ?? null,\n });\n }\n catch {\n return String(Date.now());\n }\n }\n let contentOnlyRelayTimer = null;\n let contentOnlyPersistTimer = null;\n function parseFieldPath(path) {\n const parts = [];\n for (const match of path.matchAll(/([^.[\\]]+)|\\[(\\d+)\\]/g)) {\n if (match[2] !== undefined) {\n parts.push(Number(match[2]));\n }\n else if (match[1]) {\n parts.push(match[1]);\n }\n }\n return parts;\n }\n function setValueAtPath(content, path, value) {\n if (path.length === 0)\n return content;\n const setAt = (node, depth) => {\n const part = path[depth];\n const isLast = depth === path.length - 1;\n const nextPart = isLast ? undefined : path[depth + 1];\n if (typeof part === 'number') {\n const source = Array.isArray(node) ? node : [];\n const copy = source.slice();\n if (isLast) {\n copy[part] = value;\n return copy;\n }\n const child = copy[part];\n copy[part] =\n child === undefined || child === null || typeof child !== 'object'\n ? setAt(typeof nextPart === 'number' ? [] : {}, depth + 1)\n : setAt(child, depth + 1);\n return copy;\n }\n const source = node && typeof node === 'object' && !Array.isArray(node)\n ? node\n : {};\n const copy = { ...source };\n if (isLast) {\n copy[part] = value;\n return copy;\n }\n const child = copy[part];\n copy[part] =\n child === undefined || child === null || typeof child !== 'object'\n ? setAt(typeof nextPart === 'number' ? [] : {}, depth + 1)\n : setAt(child, depth + 1);\n return copy;\n };\n return setAt(content, 0);\n }\n function readPublishedContent() {\n const previous = latestPublishedSiteData &&\n typeof latestPublishedSiteData === 'object' &&\n !Array.isArray(latestPublishedSiteData)\n ? latestPublishedSiteData\n : {};\n return previous.content ?? {};\n }\n function writePublishedContent(content) {\n const previous = latestPublishedSiteData &&\n typeof latestPublishedSiteData === 'object' &&\n !Array.isArray(latestPublishedSiteData)\n ? latestPublishedSiteData\n : {};\n const nextSiteData = { ...previous, content };\n latestPublishedSiteData = nextSiteData;\n try {\n window[SITE_DATA_GLOBAL_KEY] =\n nextSiteData;\n window[LEGACY_SITE_DATA_GLOBAL_KEY] = nextSiteData;\n }\n catch {\n // Window may be non-extensible in locked-down embeds.\n }\n return nextSiteData;\n }\n function scheduleContentOnlyRelay() {\n if (contentOnlyRelayTimer !== null) {\n window.clearTimeout(contentOnlyRelayTimer);\n }\n contentOnlyRelayTimer = window.setTimeout(() => {\n contentOnlyRelayTimer = null;\n if (latestPublishedSiteData == null)\n return;\n relaySiteDataToTemplateRuntime(latestPublishedSiteData, {\n fanOut: false,\n });\n }, CONTENT_ONLY_RELAY_DELAY_MS);\n }\n function scheduleContentOnlyPersist() {\n if (contentOnlyPersistTimer !== null) {\n window.clearTimeout(contentOnlyPersistTimer);\n }\n contentOnlyPersistTimer = window.setTimeout(() => {\n contentOnlyPersistTimer = null;\n if (latestPublishedSiteData == null)\n return;\n const idleWindow = window;\n if (typeof idleWindow.requestIdleCallback === 'function') {\n idleWindow.requestIdleCallback(() => {\n if (latestPublishedSiteData == null)\n return;\n persistSiteData(latestPublishedSiteData, { immediate: true });\n }, { timeout: 4000 });\n return;\n }\n persistSiteData(latestPublishedSiteData, { immediate: true });\n }, CONTENT_ONLY_PERSIST_DELAY_MS);\n }\n function applyDomFieldValue(fieldPath, value) {\n const targets = Array.from(document.querySelectorAll(`[data-preview-field-path=\"${CSS.escape(fieldPath)}\"], ` +\n `[${RESOLVED_PATH_ATTRIBUTE}=\"${CSS.escape(fieldPath)}\"]`));\n for (const target of targets) {\n if (activeInlineEdit?.target === target)\n continue;\n if (target.tagName === 'IMG') {\n if (typeof value === 'string' && value.trim()) {\n target.setAttribute('src', value);\n }\n continue;\n }\n if (typeof value !== 'string' &&\n typeof value !== 'number' &&\n typeof value !== 'boolean') {\n continue;\n }\n const text = (target.getAttribute('data-fivora-value-prefix') ?? '') +\n String(value) +\n (target.getAttribute('data-fivora-value-suffix') ?? '');\n if (target.childElementCount === 0) {\n target.textContent = text;\n }\n else {\n // Keep simple leaf updates cheap; full React relay reconciles structure later.\n const textNode = Array.from(target.childNodes).find((node) => node.nodeType === Node.TEXT_NODE && node.textContent?.trim());\n if (textNode) {\n textNode.textContent = text;\n }\n else {\n target.textContent = text;\n }\n }\n if (editModeActive) {\n const isEmpty = text.trim().length === 0;\n if (isEmpty) {\n target.setAttribute(EMPTY_EDITABLE_ATTRIBUTE, 'true');\n }\n else {\n target.removeAttribute(EMPTY_EDITABLE_ATTRIBUTE);\n }\n }\n }\n }\n function publishContentPatches(patches) {\n if (!Array.isArray(patches) || patches.length === 0)\n return;\n let content = readPublishedContent();\n for (const patch of patches) {\n if (!patch || typeof patch.path !== 'string' || !patch.path.trim()) {\n continue;\n }\n const pathParts = parseFieldPath(patch.path);\n if (pathParts.length === 0)\n continue;\n content = setValueAtPath(content, pathParts, patch.value);\n applyDomFieldValue(patch.path, patch.value);\n }\n writePublishedContent(content);\n // DOM already shows the edit. Coalesce the expensive template React sync.\n scheduleContentOnlyRelay();\n scheduleContentOnlyPersist();\n }\n function publishContentOnly(content) {\n writePublishedContent(content);\n // Do not relay on every keystroke — structured-clone + full SPA reconcile\n // freezes low-end phones and mid-range PCs. DOM patches + delayed relay.\n scheduleContentOnlyRelay();\n scheduleContentOnlyPersist();\n }\n function publishSiteData(siteData, options) {\n if (options?.contentOnly) {\n const record = siteData && typeof siteData === 'object' && !Array.isArray(siteData)\n ? siteData\n : null;\n publishContentOnly(record?.content ?? siteData);\n return;\n }\n if (contentOnlyRelayTimer !== null) {\n window.clearTimeout(contentOnlyRelayTimer);\n contentOnlyRelayTimer = null;\n }\n if (contentOnlyPersistTimer !== null) {\n window.clearTimeout(contentOnlyPersistTimer);\n contentOnlyPersistTimer = null;\n }\n // Coalesce to the latest payload instead of dropping concurrent applies.\n // Rapid READY + retries + live edits used to lose the newest site data.\n if (applyingSiteData) {\n pendingSiteData = siteData;\n pendingSiteDataOptions = options;\n return;\n }\n applyingSiteData = true;\n try {\n persistSiteData(siteData, { immediate: options?.persistImmediate });\n applySelectedPages(siteData);\n applyUniversalTheme(siteData, {\n colorReplacements: options?.colorReplacements === true,\n });\n relaySiteDataToTemplateRuntime(siteData, {\n fanOut: options?.fanOut === true,\n });\n if (options?.scheduleRelays !== false) {\n clearSiteDataRelayTimers();\n for (const delay of SITE_DATA_RELAY_DELAYS_MS) {\n siteDataRelayTimers.push(window.setTimeout(() => {\n if (latestPublishedSiteData == null)\n return;\n relaySiteDataToTemplateRuntime(latestPublishedSiteData, {\n fanOut: true,\n });\n }, delay));\n }\n }\n }\n finally {\n applyingSiteData = false;\n if (pendingSiteData != null) {\n const nextSiteData = pendingSiteData;\n const nextOptions = pendingSiteDataOptions;\n pendingSiteData = null;\n pendingSiteDataOptions = undefined;\n // Defer so a same-tick relay cannot recurse through finally forever.\n window.setTimeout(() => {\n publishSiteData(nextSiteData, nextOptions);\n }, 0);\n }\n }\n }\n function acknowledgeSiteDataApplied(options) {\n // Ack only after the next paint so React SiteDataProvider can commit\n // merchant content before the parent clears the hydrate lock.\n const full = options?.full !== false;\n const deferColorPolish = ('ontouchstart' in window ||\n navigator.maxTouchPoints > 0 ||\n (navigator.hardwareConcurrency != null &&\n navigator.hardwareConcurrency <= 4)) === true;\n window.requestAnimationFrame(() => {\n window.requestAnimationFrame(() => {\n try {\n postToParent({ type: DATA_APPLIED_MESSAGE, full });\n postToParent({ type: LEGACY_DATA_APPLIED_MESSAGE, full });\n }\n catch {\n // Parent overlay still clears on a timeout fallback.\n }\n // Literal stylesheet color rewrites are polish — run after unlock.\n const polished = latestPublishedSiteData;\n if (polished == null)\n return;\n const run = () => applyUniversalTheme(polished, { colorReplacements: true });\n if (!deferColorPolish) {\n window.setTimeout(run, 0);\n return;\n }\n const requestIdle = window.requestIdleCallback;\n if (typeof requestIdle === 'function') {\n requestIdle(run, { timeout: 4000 });\n }\n else {\n window.setTimeout(run, 1200);\n }\n });\n });\n }\n const ancestorOrigin = (() => {\n try {\n return window.location.ancestorOrigins?.item(0) ?? null;\n }\n catch {\n return null;\n }\n })();\n const accessibleParentOrigin = (() => {\n try {\n return window.parent !== window ? window.parent.location.origin : null;\n }\n catch {\n return null;\n }\n })();\n let parentOrigin = resolveParentOrigin({\n currentOrigin: window.location.origin,\n referrer: document.referrer,\n rememberedOrigin: readRememberedParentOrigin(),\n ancestorOrigin,\n accessibleParentOrigin,\n });\n rememberParentOrigin(parentOrigin);\n function isTrustedParentMessage(event) {\n if (event.source !== window.parent)\n return false;\n if (parentOrigin)\n return event.origin === parentOrigin;\n // Referrer information can be intentionally suppressed. In that case,\n // trust only the direct parent window, reject opaque origins, and pin the\n // first concrete parent origin for every later command.\n try {\n const candidateOrigin = new URL(event.origin).origin;\n if (candidateOrigin === 'null')\n return false;\n parentOrigin = candidateOrigin;\n rememberParentOrigin(candidateOrigin);\n return true;\n }\n catch {\n return false;\n }\n }\n function postToParent(message) {\n window.parent.postMessage(message, parentOrigin ?? '*');\n }\n function postFocusResult(payload, result, occurrences = 0) {\n if (!payload.requestId)\n return;\n postToParent({\n type: FOCUS_RESULT_MESSAGE,\n requestId: payload.requestId,\n result,\n fieldPath: payload.fieldPath ?? null,\n pageRoute: payload.pageRoute ?? null,\n occurrences,\n });\n postToParent({\n type: LEGACY_FOCUS_RESULT_MESSAGE,\n requestId: payload.requestId,\n result,\n fieldPath: payload.fieldPath ?? null,\n pageRoute: payload.pageRoute ?? null,\n occurrences,\n });\n }\n function announceReady() {\n try {\n postToParent({\n type: READY_MESSAGE,\n pathname: window.location.pathname,\n });\n postToParent({\n type: LEGACY_READY_MESSAGE,\n pathname: window.location.pathname,\n });\n }\n catch {\n // The preview still works when embedded messaging is unavailable.\n }\n }\n async function applyTemplateColorReplacements(theme) {\n const request = ++colorReplacementRequest;\n const record = theme && typeof theme === 'object' && !Array.isArray(theme)\n ? theme\n : null;\n const replacements = record?.colorReplacements;\n const existing = document.getElementById(COLOR_REPLACEMENT_STYLE_ID);\n if (!replacements ||\n typeof replacements !== 'object' ||\n Array.isArray(replacements) ||\n Object.keys(replacements).length === 0) {\n existing?.remove();\n return;\n }\n const stylesheets = Array.from(document.querySelectorAll('link[rel=\"stylesheet\"][href]'));\n const transformed = await Promise.all(stylesheets.map(async (link) => {\n const href = link.href;\n let source = originalStylesheetCss.get(href);\n if (source === undefined) {\n const response = await fetch(href, { credentials: 'same-origin' });\n if (!response.ok)\n return '';\n source = await response.text();\n originalStylesheetCss.set(href, source);\n }\n const replaced = replaceColorLiterals(source, replacements);\n return replaced === source ? '' : replaced;\n }));\n if (request !== colorReplacementRequest)\n return;\n const css = transformed.filter(Boolean).join('\\n');\n if (!css) {\n existing?.remove();\n return;\n }\n const style = existing instanceof HTMLStyleElement\n ? existing\n : document.createElement('style');\n style.id = COLOR_REPLACEMENT_STYLE_ID;\n style.textContent = css;\n if (!style.isConnected)\n document.head.appendChild(style);\n }\n function applyUniversalTheme(siteData, options) {\n const record = siteData && typeof siteData === 'object' && !Array.isArray(siteData)\n ? siteData\n : null;\n const template = record?.template &&\n typeof record.template === 'object' &&\n !Array.isArray(record.template)\n ? record.template\n : null;\n const structure = template?.structure &&\n typeof template.structure === 'object' &&\n !Array.isArray(template.structure)\n ? template.structure\n : null;\n const theme = structure?.theme;\n const themeSignature = (() => {\n try {\n return JSON.stringify(theme ?? null);\n }\n catch {\n return String(Date.now());\n }\n })();\n const themeChanged = themeSignature !== lastAppliedThemeSignature;\n if (themeChanged) {\n lastAppliedThemeSignature = themeSignature;\n const css = buildUniversalThemeCss(theme);\n const existing = document.getElementById(universalThemeStyleId);\n if (!css) {\n existing?.remove();\n }\n else {\n const style = existing instanceof HTMLStyleElement\n ? existing\n : document.createElement('style');\n style.id = universalThemeStyleId;\n style.textContent = css;\n if (!style.isConnected)\n document.head.appendChild(style);\n }\n }\n if (options?.colorReplacements) {\n if (themeSignature === lastColorReplacementSignature) {\n return;\n }\n lastColorReplacementSignature = themeSignature;\n void applyTemplateColorReplacements(theme).catch(() => {\n // Semantic token overrides still work if a stylesheet cannot be read.\n });\n }\n }\n function applySelectedPages(siteData) {\n const signature = pagesSignature(siteData);\n if (signature === lastAppliedPagesSignature) {\n return;\n }\n lastAppliedPagesSignature = signature;\n enforceSelectedPages(siteData, document);\n window.setTimeout(() => enforceSelectedPages(siteData, document), 300);\n }\n function normalizeText(value) {\n return String(value ?? '')\n .trim()\n .replace(/\\s+/g, ' ')\n .toLowerCase();\n }\n function valueFragments(value) {\n const original = String(value ?? '').trim();\n if (!original)\n return [];\n const fragments = original\n .split(/[,;|\\n\\r]+/)\n .map((part) => normalizeText(part))\n .filter((part) => part.length >= 3);\n return Array.from(new Set([normalizeText(original), ...fragments])).filter((part) => part.length >= 2);\n }\n function isImageValue(value, key) {\n const normalizedKey = normalizeText(key);\n const normalizedValue = normalizeText(value);\n return (/image|photo|logo|banner|thumbnail|cover/.test(normalizedKey) ||\n /^(https?:|data:|blob:|\\/)/.test(normalizedValue));\n }\n function extractImageCandidates(image) {\n const candidates = new Set();\n const raw = image.getAttribute('src') || '';\n if (raw)\n candidates.add(raw);\n if ('src' in image && image.src) {\n candidates.add(image.src);\n }\n if ('currentSrc' in image && image.currentSrc) {\n candidates.add(image.currentSrc);\n }\n const srcset = image.getAttribute('srcset');\n if (srcset) {\n srcset.split(',').forEach((part) => {\n const url = part.trim().split(/\\s+/)[0];\n if (url)\n candidates.add(url);\n });\n }\n for (const attr of [\n 'data-src',\n 'data-original',\n 'data-fallback',\n 'data-nimg',\n 'data-image',\n 'data-url',\n ]) {\n const val = image.getAttribute(attr);\n if (val && val !== '1')\n candidates.add(val);\n }\n if (image.style.backgroundImage) {\n const bgMatch = image.style.backgroundImage.match(/url\\([\"']?([^\"']+)[\"']?\\)/i);\n if (bgMatch?.[1])\n candidates.add(bgMatch[1]);\n }\n for (const urlStr of Array.from(candidates)) {\n try {\n const parsed = new URL(urlStr, window.location.href);\n const nextUrl = parsed.searchParams.get('url');\n if (nextUrl) {\n candidates.add(nextUrl);\n try {\n candidates.add(decodeURIComponent(nextUrl));\n }\n catch { }\n }\n }\n catch { }\n }\n return Array.from(candidates).filter(Boolean);\n }\n function imageMatchesValue(image, value) {\n const expected = String(value ?? '').trim();\n if (!expected)\n return false;\n const candidates = extractImageCandidates(image);\n if (candidates.length === 0)\n return false;\n const expectedClean = expected.split('?')[0].replace(/\\\\/g, '/');\n const expectedFile = expectedClean.split('/').pop()?.toLowerCase();\n for (const candidate of candidates) {\n if (candidate === expected)\n return true;\n try {\n if (new URL(candidate, window.location.href).href ===\n new URL(expected, window.location.href).href) {\n return true;\n }\n }\n catch { }\n if (candidate.includes(expected) || expected.includes(candidate)) {\n return true;\n }\n try {\n const decoded = decodeURIComponent(candidate);\n if (decoded.includes(expected) || expected.includes(decoded)) {\n return true;\n }\n }\n catch { }\n const candidateClean = candidate.split('?')[0].replace(/\\\\/g, '/');\n const candidateFile = candidateClean.split('/').pop()?.toLowerCase();\n if (candidateFile &&\n expectedFile &&\n candidateFile.length >= 3 &&\n candidateFile === expectedFile) {\n return true;\n }\n }\n return false;\n }\n function findImageMatches(root, value) {\n return Array.from(root.querySelectorAll('img')).filter((image) => imageMatchesValue(image, value));\n }\n function attributeMatchesValue(element, value) {\n const expected = String(value ?? '').trim();\n if (!expected)\n return false;\n const candidates = [\n element.getAttribute('href'),\n element.getAttribute('src'),\n element.getAttribute('poster'),\n element.getAttribute('srcset'),\n element.style.backgroundImage,\n ].filter((candidate) => Boolean(candidate));\n return candidates.some((candidate) => {\n if (candidate === expected || candidate.includes(expected))\n return true;\n try {\n return (new URL(candidate, window.location.href).href ===\n new URL(expected, window.location.href).href);\n }\n catch {\n return false;\n }\n });\n }\n function findAttributeMatches(root, value) {\n return Array.from(root.querySelectorAll('a[href], img[src], source[src], video[poster], [style*=\"background-image\"]')).filter((element) => attributeMatchesValue(element, value));\n }\n function findTextMatches(root, value) {\n const fragments = valueFragments(value);\n if (fragments.length === 0)\n return [];\n const elements = Array.from(root.querySelectorAll(TEXT_SELECTOR));\n const exact = elements.filter((element) => {\n const text = normalizeText(element.textContent);\n return fragments.some((fragment) => text === fragment);\n });\n if (exact.length > 0)\n return exact;\n return elements.filter((element) => {\n const text = normalizeText(element.textContent);\n return fragments.some((fragment) => text.includes(fragment) || fragment.includes(text));\n });\n }\n function findValueMatches(root, value, key) {\n if (isImageValue(value, key)) {\n const images = findImageMatches(root, value);\n if (images.length > 0)\n return images;\n }\n return findTextMatches(root, value);\n }\n function subtreeContainsValue(element, value, key) {\n if (isImageValue(value, key) &&\n findImageMatches(element, value).length > 0) {\n return true;\n }\n const text = normalizeText(element.textContent);\n return valueFragments(value).some((fragment) => text.includes(fragment));\n }\n function lowestCommonAncestor(elements, boundary) {\n const first = elements[0];\n if (!first)\n return null;\n let candidate = first;\n while (candidate) {\n if (elements.every((element) => candidate?.contains(element))) {\n return candidate;\n }\n if (candidate === boundary)\n break;\n candidate = candidate.parentElement;\n }\n return boundary ?? first;\n }\n function pathVariants(path) {\n const original = String(path ?? '').trim();\n if (!original)\n return [];\n const dotted = original.replace(/\\[(\\d+)\\]/g, '.$1');\n const bracketed = dotted.replace(/\\.(\\d+)(?=\\.|$)/g, '[$1]');\n return Array.from(new Set([original, dotted, bracketed]));\n }\n function focusPathCandidates(payload) {\n return Array.from(new Set([payload.fieldPath, ...(payload.fieldPaths ?? [])]\n .filter((path) => Boolean(path && path.trim()))\n .flatMap((path) => pathVariants(path))));\n }\n /**\n * Eye-preview must outline something the agent can actually see. Templates\n * often keep duplicate markers in closed mobile drawers, 1×1 contract\n * spans, or opacity-0 chrome — those exact matches must not win.\n */\n function isVisuallyHighlightable(element) {\n if (element.closest('[hidden]'))\n return false;\n let node = element;\n while (node && node !== document.documentElement) {\n const style = window.getComputedStyle(node);\n if (style.display === 'none' ||\n style.visibility === 'hidden' ||\n Number(style.opacity) === 0) {\n return false;\n }\n if (style.maxHeight === '0px' || style.maxHeight === '0') {\n return false;\n }\n const rect = node.getBoundingClientRect();\n if ((style.overflow === 'hidden' || style.overflow === 'clip') &&\n (rect.width < 2 || rect.height < 2)) {\n return false;\n }\n node = node.parentElement;\n }\n const selfRect = element.getBoundingClientRect();\n return selfRect.width >= 2 && selfRect.height >= 2;\n }\n function highlightTargetScore(element) {\n let score = 0;\n if (isVisuallyHighlightable(element))\n score += 100;\n const text = normalizeText(element.textContent);\n if (text.length >= 2)\n score += 40;\n if (element.tagName === 'IMG')\n score += 35;\n if (element.closest('main, footer, header, [data-preview-page-key]')) {\n score += 20;\n }\n // Icon-only floating CTAs are valid fallbacks but weaker than labeled copy.\n if (element.closest('.fixed, [class*=\"fixed\"]') &&\n text.length < 2 &&\n element.tagName !== 'IMG') {\n score -= 25;\n }\n const rect = element.getBoundingClientRect();\n score += Math.min(15, Math.floor((rect.width * rect.height) / 400));\n return score;\n }\n function rankHighlightTargets(targets) {\n return [...targets].sort((left, right) => highlightTargetScore(right) - highlightTargetScore(left));\n }\n function findExplicitTargets(path, extraPaths) {\n const targets = [];\n const paths = Array.from(new Set([path, ...(extraPaths ?? [])]\n .filter((candidate) => Boolean(candidate))\n .flatMap((candidate) => pathVariants(candidate))));\n for (const variant of paths) {\n const escaped = CSS.escape(variant);\n document\n .querySelectorAll('[data-preview-field-path=\"' +\n escaped +\n '\"], [data-preview-list-path=\"' +\n escaped +\n '\"], [data-content-path=\"' +\n escaped +\n '\"]')\n .forEach((target) => {\n if (!targets.includes(target))\n targets.push(target);\n });\n }\n const visible = rankHighlightTargets(targets.filter((target) => isVisuallyHighlightable(target)));\n // Prefer leaf markers when both a parent and child share the same path.\n const leaves = visible.filter((target) => !visible.some((other) => other !== target && target.contains(other)));\n return leaves.length > 0 ? leaves : visible;\n }\n function findItemContainer(context) {\n const values = (context?.itemValues ?? []).filter((entry) => normalizeText(entry.value).length >= 2 && entry.key !== 'id');\n if (values.length === 0)\n return null;\n const anchors = [];\n for (const entry of values) {\n for (const match of findValueMatches(document, entry.value, entry.key).slice(0, 8)) {\n if (!anchors.includes(match))\n anchors.push(match);\n }\n }\n let best = null;\n for (const anchor of anchors) {\n let candidate = anchor;\n let levels = 0;\n while (candidate && candidate !== document.body && levels < 12) {\n const score = values.reduce((total, entry) => total +\n (subtreeContainsValue(candidate, entry.value, entry.key)\n ? 1\n : 0), 0);\n const rect = candidate.getBoundingClientRect();\n const area = Math.max(1, rect.width * rect.height);\n if (!best ||\n score > best.score ||\n (score === best.score && area < best.area)) {\n best = { target: candidate, score, area };\n }\n candidate = candidate.parentElement;\n levels += 1;\n }\n }\n const requiredScore = Math.min(2, values.length);\n return best && best.score >= requiredScore ? best.target : null;\n }\n function findFieldTarget(root, value, key) {\n const matches = findValueMatches(root, value, key);\n if (matches.length === 0)\n return null;\n const fragments = valueFragments(value);\n if (fragments.length > 1 && !isImageValue(value, key)) {\n const fragmentMatches = matches.filter((element) => {\n const text = normalizeText(element.textContent);\n return fragments.slice(1).some((fragment) => text === fragment);\n });\n if (fragmentMatches.length > 1) {\n return lowestCommonAncestor(fragmentMatches, root instanceof HTMLElement ? root : null);\n }\n }\n return matches.sort((left, right) => normalizeText(left.textContent).length -\n normalizeText(right.textContent).length)[0];\n }\n function normalizePageKey(pageKey, pageLabel) {\n const normalized = String(pageKey ?? pageLabel ?? '')\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '_');\n if (!normalized || normalized === 'common')\n return 'home';\n return normalized === 'about' ? 'about_us' : normalized;\n }\n function findPageTarget(pageKey) {\n const baseKey = pageKey.replace(/_us$/, '');\n const selectors = [\n '[data-preview-page-key=\"' + CSS.escape(pageKey) + '\"]',\n '[data-preview-page-key=\"' + CSS.escape(baseKey) + '\"]',\n '#' + CSS.escape(pageKey) + '_view',\n '#' + CSS.escape(baseKey) + '_view',\n '#' + CSS.escape(pageKey),\n '#' + CSS.escape(baseKey),\n 'main',\n 'body',\n ];\n for (const selector of selectors) {\n const element = document.querySelector(selector);\n if (element instanceof HTMLElement)\n return element;\n }\n return null;\n }\n function resolvePath(pageKey, pageRoute) {\n const match = window.location.pathname.match(/^(\\/uploads\\/generated-sites\\/(?:template-preview|preview|live)\\/[^/]+)/);\n const requestedRoute = String(pageRoute ?? '').trim();\n const normalizedRoute = requestedRoute\n ? '/' + requestedRoute.replace(/^\\/+|\\/+$/g, '')\n : null;\n const suffix = normalizedRoute !== null\n ? normalizedRoute === '/'\n ? ''\n : normalizedRoute\n : pageKey === 'home'\n ? ''\n : '/' + pageKey.replace(/^\\/+/, '');\n return match ? match[1] + suffix : suffix || '/';\n }\n function clearHighlight() {\n for (const snapshot of activeHighlights) {\n snapshot.target.style.outline = snapshot.outline;\n snapshot.target.style.outlineOffset = snapshot.outlineOffset;\n snapshot.target.style.boxShadow = snapshot.boxShadow;\n snapshot.target.style.transition = snapshot.transition;\n snapshot.target.style.scrollMarginTop = snapshot.scrollMarginTop;\n snapshot.target.style.borderRadius = snapshot.borderRadius;\n snapshot.target.removeAttribute(ACTIVE_ATTRIBUTE);\n }\n activeHighlights = [];\n }\n function highlightTargets(targets, isPageTarget) {\n clearHighlight();\n activeHighlights = targets.map((target) => ({\n target,\n outline: target.style.outline,\n outlineOffset: target.style.outlineOffset,\n boxShadow: target.style.boxShadow,\n transition: target.style.transition,\n scrollMarginTop: target.style.scrollMarginTop,\n borderRadius: target.style.borderRadius,\n }));\n for (const target of targets) {\n target.setAttribute(ACTIVE_ATTRIBUTE, 'true');\n target.style.scrollMarginTop = '72px';\n target.style.transition = 'outline-color 0.2s ease, box-shadow 0.2s ease';\n target.style.outline = '2px solid rgba(34, 197, 94, 0.98)';\n target.style.outlineOffset = '4px';\n target.style.boxShadow = '0 0 0 7px rgba(34, 197, 94, 0.2)';\n if (!target.style.borderRadius)\n target.style.borderRadius = '4px';\n }\n targets[0]?.scrollIntoView({\n behavior: 'smooth',\n block: isPageTarget ? 'start' : 'center',\n inline: 'nearest',\n });\n }\n function highlight(target, isPageTarget) {\n highlightTargets([target], isPageTarget);\n }\n function focusMatchValues(payload) {\n return Array.from(new Set([payload.fieldValue, ...(payload.fieldMatchValues ?? [])]\n .filter((value) => typeof value === 'boolean' ||\n typeof value === 'number' ||\n (typeof value === 'string' && value.trim().length > 0))\n .map((value) => String(value))));\n }\n function findRememberedFocusTarget(payload) {\n const pathCandidates = focusPathCandidates(payload);\n if (pathCandidates.length === 0)\n return null;\n try {\n const selectors = JSON.parse(window.sessionStorage.getItem(RESOLVED_TARGETS_KEY) ?? '{}');\n for (const fieldPath of pathCandidates) {\n const selector = selectors[`${window.location.pathname}|${fieldPath}`];\n if (!selector)\n continue;\n const target = document.querySelector(selector);\n if (!target)\n continue;\n const expectedValues = focusMatchValues(payload).map(normalizeText);\n const targetText = normalizeText(target.textContent);\n if (expectedValues.length > 0 &&\n targetText &&\n !expectedValues.some((value) => targetText === value ||\n targetText.includes(value) ||\n attributeMatchesValue(target, value))) {\n continue;\n }\n return target;\n }\n return null;\n }\n catch {\n return null;\n }\n }\n function pickVisibleHeuristicTarget(target) {\n if (!target)\n return null;\n if (isVisuallyHighlightable(target))\n return target;\n let node = target.parentElement;\n while (node && node !== document.body) {\n if (isVisuallyHighlightable(node))\n return node;\n node = node.parentElement;\n }\n return null;\n }\n function resolveFieldTarget(payload) {\n const pathCandidates = focusPathCandidates(payload);\n const explicit = findExplicitTargets(payload.fieldPath, pathCandidates.filter((path) => path !== payload.fieldPath));\n if (explicit.length > 0)\n return { targets: explicit, result: 'exact' };\n const remembered = pickVisibleHeuristicTarget(findRememberedFocusTarget(payload));\n if (remembered)\n return { targets: [remembered], result: 'heuristic' };\n const itemContainer = findItemContainer(payload.fieldContext);\n const fieldKey = payload.fieldContext?.fieldKey;\n if (itemContainer) {\n for (const value of focusMatchValues(payload)) {\n const insideItem = pickVisibleHeuristicTarget(findAttributeMatches(itemContainer, value)[0] ??\n findFieldTarget(itemContainer, value, fieldKey));\n if (insideItem) {\n return { targets: [insideItem], result: 'heuristic' };\n }\n }\n const visibleContainer = pickVisibleHeuristicTarget(itemContainer);\n if (visibleContainer) {\n return { targets: [visibleContainer], result: 'heuristic' };\n }\n }\n for (const value of focusMatchValues(payload)) {\n const attributeMatches = findAttributeMatches(document, value);\n const textMatch = findFieldTarget(document, value, fieldKey);\n const matches = textMatch\n ? [...attributeMatches, textMatch]\n : attributeMatches;\n const visibleMatches = rankHighlightTargets(matches\n .map((match) => pickVisibleHeuristicTarget(match))\n .filter((match) => Boolean(match)));\n if (visibleMatches.length > 0) {\n return { targets: [visibleMatches[0]], result: 'heuristic' };\n }\n }\n return null;\n }\n function activateRevealNodes() {\n // Templates often register IntersectionObserver once on mount. Live\n // preview data updates (especially image URL changes that remount cards)\n // leave new .reveal-on-scroll nodes at opacity:0. Eye-preview focus and\n // edit mode both need those nodes visible.\n document.documentElement.dataset.fivoraPreview = 'true';\n document\n .querySelectorAll('.reveal-on-scroll:not(.reveal-active)')\n .forEach((element) => element.classList.add('reveal-active'));\n }\n function applyFocus(payload, attempt = 0) {\n activateRevealNodes();\n const hasField = Boolean(payload.fieldPath);\n if (payload.focusOnly && hasField) {\n const resolution = resolveFieldTarget(payload);\n if (resolution) {\n highlightTargets(resolution.targets, false);\n postFocusResult(payload, resolution.result, resolution.targets.length);\n return;\n }\n if (attempt < 12) {\n window.setTimeout(() => applyFocus(payload, attempt + 1), 120);\n return;\n }\n postFocusResult(payload, 'missing');\n return;\n }\n const pageKey = normalizePageKey(payload.pageKey, payload.pageLabel);\n const pageTarget = findPageTarget(pageKey);\n if (!pageTarget) {\n if (attempt < 12) {\n window.setTimeout(() => applyFocus(payload, attempt + 1), 120);\n }\n else {\n postFocusResult(payload, 'missing');\n }\n return;\n }\n const resolution = hasField ? resolveFieldTarget(payload) : null;\n if (hasField && !resolution && attempt < 12) {\n window.setTimeout(() => applyFocus(payload, attempt + 1), 120);\n return;\n }\n if (resolution) {\n highlightTargets(resolution.targets, false);\n postFocusResult(payload, resolution.result, resolution.targets.length);\n }\n else {\n highlight(pageTarget, true);\n postFocusResult(payload, 'page', 1);\n }\n }\n function handleFocus(payload) {\n if (payload.focusOnly) {\n clearPendingFocus();\n window.setTimeout(() => applyFocus(payload), 80);\n return;\n }\n const pageKey = normalizePageKey(payload.pageKey, payload.pageLabel);\n const targetPath = resolvePath(pageKey, payload.pageRoute);\n const currentPath = window.location.pathname.replace(/\\/+$/, '') || '/';\n if (currentPath !== targetPath) {\n try {\n window.sessionStorage.setItem(PENDING_KEY, JSON.stringify({ ...payload, awaitingNavigation: true }));\n }\n catch {\n // Storage may be disabled; navigation recovery falls back to parent.\n }\n window.location.assign(targetPath);\n return;\n }\n clearPendingFocus();\n window.setTimeout(() => applyFocus(payload), 80);\n }\n function normalizeRouteToken(value) {\n return normalizeText(value)\n .replace(/\\.html$/i, '')\n .replace(/[^a-z0-9]+/g, '-');\n }\n /**\n * Older strict packages sometimes marked server-rendered collection-detail\n * values as static even though the same object is editable on its listing\n * page. Promote only leaves belonging to the item identified by the current\n * route; genuinely decorative/static content remains untouched.\n */\n function promoteActiveRouteDetailFields() {\n const segments = window.location.pathname\n .split('/')\n .map((part) => decodeURIComponent(part).trim())\n .filter(Boolean);\n if (segments.length < 2 || editableFields.length === 0)\n return;\n const activeFields = editableFields.filter((field) => {\n const context = field.context;\n if (!context?.collectionPath || !context.fieldKey)\n return false;\n const collectionKey = context.collectionPath.split('.').at(-1) ?? '';\n const collectionPosition = segments.lastIndexOf(collectionKey);\n if (collectionPosition < 0 || collectionPosition >= segments.length - 1) {\n return false;\n }\n const activeToken = normalizeRouteToken(segments.at(-1) ?? '');\n return context.itemValues.some(({ key, value }) => {\n const normalizedKey = normalizeText(key).replace(/[^a-z0-9]/g, '');\n if (normalizedKey !== 'id' &&\n !normalizedKey.endsWith('id') &&\n normalizedKey !== 'slug' &&\n normalizedKey !== 'name' &&\n normalizedKey !== 'title') {\n return false;\n }\n return normalizeRouteToken(value) === activeToken;\n });\n });\n if (activeFields.length === 0)\n return;\n const staticElements = Array.from(document.querySelectorAll(`[${STATIC_ATTRIBUTE}]`));\n const pairs = [];\n for (const field of activeFields) {\n const context = field.context;\n const fieldKey = context.fieldKey;\n const normalizedFieldKey = normalizeText(fieldKey).replace(/[^a-z0-9]/g, '');\n if (normalizedFieldKey === 'slug' ||\n normalizedFieldKey === 'identifier' ||\n normalizedFieldKey.endsWith('id')) {\n continue;\n }\n const collectionKey = context.collectionPath.split('.').at(-1) ?? '';\n const collectionToken = normalizeText(collectionKey).replace(/s$/, '');\n const fieldTokens = fieldKey\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .split(/[^a-z0-9]+/i)\n .map(normalizeText)\n .filter((token) => token && !['url', 'text', 'value'].includes(token));\n const normalizedValue = normalizeText(field.value);\n for (const element of staticElements) {\n const reason = normalizeText(element.getAttribute(STATIC_ATTRIBUTE));\n if (!reason || !reason.includes(collectionToken))\n continue;\n let score = 0;\n const reasonHits = fieldTokens.filter((token) => reason.includes(token));\n if (reasonHits.length > 0)\n score += 40 + reasonHits.length * 5;\n const visibleValue = element.tagName === 'IMG'\n ? normalizeText(element.getAttribute('src') ?? element.getAttribute('alt'))\n : normalizeText(element.textContent);\n if (normalizedValue && visibleValue === normalizedValue)\n score += 120;\n else if (normalizedValue.length >= 3 &&\n visibleValue.includes(normalizedValue)) {\n score += 80;\n }\n const imageField = /image|photo|logo|banner|thumbnail|cover/i.test(fieldKey);\n if (imageField &&\n element.tagName === 'IMG' &&\n reason.includes('image')) {\n score += 120;\n }\n if (score >= 40)\n pairs.push({ element, field, score });\n }\n }\n pairs.sort((left, right) => right.score - left.score);\n const claimed = new Set();\n for (const { element, field } of pairs) {\n if (claimed.has(element))\n continue;\n claimed.add(element);\n if (element.tagName !== 'IMG') {\n const currentText = element.textContent ?? '';\n const fieldText = String(field.value ?? '');\n const valuePosition = currentText\n .toLowerCase()\n .indexOf(fieldText.toLowerCase());\n if (fieldText &&\n valuePosition >= 0 &&\n currentText !== fieldText) {\n element.setAttribute('data-fivora-value-prefix', currentText.slice(0, valuePosition));\n element.setAttribute('data-fivora-value-suffix', currentText.slice(valuePosition + fieldText.length));\n }\n }\n element.removeAttribute(STATIC_ATTRIBUTE);\n element.setAttribute('data-preview-field-path', field.path);\n applyDomFieldValue(field.path, field.value);\n }\n }\n const CLICK_MESSAGE = 'FIVORA_PREVIEW_ELEMENT_CLICKED';\n const LEGACY_CLICK_MESSAGE = previousPreviewMessage('ELEMENT_CLICKED');\n const CHANGE_MESSAGE = 'FIVORA_PREVIEW_FIELD_CHANGED';\n const LEGACY_CHANGE_MESSAGE = previousPreviewMessage('FIELD_CHANGED');\n const EDIT_MODE_MESSAGE = 'FIVORA_PREVIEW_EDIT_MODE';\n const LEGACY_EDIT_MODE_MESSAGE = previousPreviewMessage('EDIT_MODE');\n const FLUSH_EDIT_MESSAGE = 'FIVORA_PREVIEW_FLUSH_EDIT';\n const LEGACY_FLUSH_EDIT_MESSAGE = previousPreviewMessage('FLUSH_EDIT');\n const EDIT_FLUSHED_MESSAGE = 'FIVORA_PREVIEW_EDIT_FLUSHED';\n const LEGACY_EDIT_FLUSHED_MESSAGE = previousPreviewMessage('EDIT_FLUSHED');\n const EDITABLE_SELECTOR = 'h1, h2, h3, h4, h5, h6, p, span, a, button, address, li, dt, dd, label, strong, em, small, img';\n const isTouchDevice = 'ontouchstart' in window ||\n navigator.maxTouchPoints > 0 ||\n (window.matchMedia && window.matchMedia('(pointer: coarse)').matches);\n // WebKit/Safari and many iOS browsers reject or ignore\n // contenteditable=\"plaintext-only\". Prefer the parent popover there.\n const isSafariLike = (() => {\n const ua = navigator.userAgent || '';\n const vendor = navigator.vendor || '';\n if (/iP(ad|hone|od)/i.test(ua))\n return true;\n if (/Safari/i.test(ua) &&\n /Apple Computer/i.test(vendor) &&\n !/Chrom(e|ium)/i.test(ua)) {\n return true;\n }\n try {\n return Boolean(window.safari);\n }\n catch {\n return false;\n }\n })();\n const supportsPlaintextOnlyContentEditable = (() => {\n try {\n const probe = document.createElement('div');\n probe.setAttribute('contenteditable', 'plaintext-only');\n return probe.contentEditable === 'plaintext-only';\n }\n catch {\n return false;\n }\n })();\n const isLowPowerPreview = isTouchDevice ||\n (navigator.hardwareConcurrency != null &&\n navigator.hardwareConcurrency <= 4) ||\n (typeof navigator\n .deviceMemory === 'number' &&\n (navigator.deviceMemory ??\n 8) <= 4);\n // Prefer the parent portal popover on every device — inline contenteditable\n // is unreliable on WebKit and still expensive on desktop while typing.\n const preferParentPopover = true;\n let editableFields = [];\n window.addEventListener('message', (event) => {\n if (!isTrustedParentMessage(event)) {\n return;\n }\n // Relays are synthetic MessageEvents for the template SiteDataProvider.\n // Never re-enter publishSiteData from them — that recurses until stack overflow.\n if (event.data &&\n typeof event.data === 'object' &&\n event.data\n .__fivoraBridgeRelay === true) {\n return;\n }\n const isFocusMsg = event.data?.type === FOCUS_MESSAGE ||\n event.data?.type === LEGACY_FOCUS_MESSAGE;\n if (isFocusMsg) {\n event.stopImmediatePropagation();\n handleFocus(event.data);\n return;\n }\n const isDataMsg = event.data?.type === DATA_MESSAGE ||\n event.data?.type === LEGACY_DATA_MESSAGE;\n if (isDataMsg && event.data.siteData) {\n const isFullPayload = event.data.full !== false;\n const contentOnly = event.data.contentOnly === true;\n if (contentOnly) {\n publishSiteData(event.data.siteData, { contentOnly: true });\n return;\n }\n publishSiteData(event.data.siteData, {\n fanOut: false,\n colorReplacements: false,\n });\n acknowledgeSiteDataApplied({ full: isFullPayload });\n return;\n }\n const isPatchMsg = event.data?.type === CONTENT_PATCH_MESSAGE ||\n event.data?.type === LEGACY_CONTENT_PATCH_MESSAGE;\n if (isPatchMsg) {\n const patches = event.data.patches;\n if (Array.isArray(patches)) {\n publishContentPatches(patches);\n }\n return;\n }\n const isEditModeMsg = event.data?.type === EDIT_MODE_MESSAGE ||\n event.data?.type === LEGACY_EDIT_MODE_MESSAGE;\n if (isEditModeMsg) {\n editableFields = Array.isArray(event.data.fields)\n ? event.data.fields\n : [];\n promoteActiveRouteDetailFields();\n if (event.data.editMode) {\n enterEditMode();\n // Defer heavy indexing so the saved content can paint first.\n window.setTimeout(() => scheduleEditableTargetIndex(), 50);\n }\n else {\n exitEditMode();\n }\n return;\n }\n const isFlushMsg = event.data?.type === FLUSH_EDIT_MESSAGE ||\n event.data?.type === LEGACY_FLUSH_EDIT_MESSAGE;\n if (isFlushMsg) {\n finishInlineEdit(true);\n postToParent({\n type: EDIT_FLUSHED_MESSAGE,\n requestId: event.data.requestId,\n });\n postToParent({\n type: LEGACY_EDIT_FLUSHED_MESSAGE,\n requestId: event.data.requestId,\n });\n }\n }, true);\n try {\n const pending = JSON.parse(window.sessionStorage.getItem(PENDING_KEY) ?? 'null');\n if (pending?.awaitingNavigation) {\n const pageKey = normalizePageKey(pending.pageKey, pending.pageLabel);\n const targetPath = resolvePath(pageKey, pending.pageRoute);\n const currentPath = window.location.pathname.replace(/\\/+$/, '') || '/';\n clearPendingFocus();\n if (currentPath === targetPath) {\n window.setTimeout(() => applyFocus(pending), 220);\n }\n }\n else if (pending) {\n // Drop stale focus from a previous preview session. Replaying it after a\n // fresh iframe load overwrote the newly requested field highlight.\n clearPendingFocus();\n }\n }\n catch {\n clearPendingFocus();\n }\n try {\n // Soft restore can flash stale demo content and block the parent payload on\n // low-power WebKit. Only restore the global/session pointers there.\n const cachedSiteData = JSON.parse(window.sessionStorage.getItem(SITE_DATA_CACHE_KEY) ??\n window.sessionStorage.getItem(LEGACY_SITE_DATA_CACHE_KEY) ??\n 'null');\n if (cachedSiteData) {\n latestPublishedSiteData = cachedSiteData;\n try {\n window[SITE_DATA_GLOBAL_KEY] =\n cachedSiteData;\n window[LEGACY_SITE_DATA_GLOBAL_KEY] = cachedSiteData;\n }\n catch {\n // Ignore non-extensible window environments.\n }\n if (!isLowPowerPreview) {\n applySelectedPages(cachedSiteData);\n applyUniversalTheme(cachedSiteData, { colorReplacements: false });\n }\n }\n }\n catch {\n // The next live-data message will restore the universal design layer.\n }\n // ── Edit mode: hover overlay + pencil badge + click-to-edit ────────────\n let editModeActive = false;\n let hoverBadge = null;\n let hoveredElement = null;\n let hoverOutlineCleanup = null;\n let activeInlineEdit = null;\n let indexTimeouts = [];\n let indexIdleHandle = null;\n function ensureEmptyEditableStyles() {\n if (document.querySelector('[data-fivora-empty-editable-styles]')) {\n return;\n }\n const style = document.createElement('style');\n style.setAttribute('data-fivora-empty-editable-styles', 'true');\n style.textContent = `\n [${EMPTY_EDITABLE_ATTRIBUTE}=\"true\"] {\n min-width: 7rem !important;\n min-height: 1.25em !important;\n outline: 1px dashed rgba(37, 99, 235, 0.28) !important;\n outline-offset: 3px !important;\n }\n span[${EMPTY_EDITABLE_ATTRIBUTE}=\"true\"],\n a[${EMPTY_EDITABLE_ATTRIBUTE}=\"true\"],\n strong[${EMPTY_EDITABLE_ATTRIBUTE}=\"true\"],\n em[${EMPTY_EDITABLE_ATTRIBUTE}=\"true\"],\n small[${EMPTY_EDITABLE_ATTRIBUTE}=\"true\"],\n label[${EMPTY_EDITABLE_ATTRIBUTE}=\"true\"] {\n display: inline-block !important;\n }\n [${EMPTY_EDITABLE_ATTRIBUTE}=\"true\"]:empty::before {\n content: \"\";\n color: rgba(37, 99, 235, 0.78);\n font: 500 12px/1.4 system-ui, sans-serif;\n letter-spacing: normal;\n text-transform: none;\n white-space: nowrap;\n }\n [${EMPTY_EDITABLE_ATTRIBUTE}=\"true\"]:empty:hover::before {\n content: \"Click to add text\";\n }\n [${EMPTY_COLLECTION_ATTRIBUTE}=\"true\"] {\n min-width: 10rem !important;\n min-height: 3.5rem !important;\n outline: 1px dashed rgba(37, 99, 235, 0.28) !important;\n outline-offset: 3px !important;\n }\n [${EMPTY_COLLECTION_ATTRIBUTE}=\"true\"]:empty::before {\n content: \"\";\n display: inline-flex;\n align-items: center;\n min-height: 3.5rem;\n color: rgba(37, 99, 235, 0.78);\n font: 500 12px/1.4 system-ui, sans-serif;\n letter-spacing: normal;\n text-transform: none;\n white-space: nowrap;\n }\n [${EMPTY_COLLECTION_ATTRIBUTE}=\"true\"]:empty:hover::before {\n content: \"Click to add the first item\";\n }\n `;\n document.head.appendChild(style);\n }\n function buildStructuralSelector(element) {\n if (element.id) {\n return '#' + CSS.escape(element.id);\n }\n const parts = [];\n let current = element;\n while (current && current !== document.body) {\n const tag = current.tagName.toLowerCase();\n const siblings = current.parentElement\n ? Array.from(current.parentElement.children).filter((sibling) => sibling.tagName === current?.tagName)\n : [];\n const position = siblings.indexOf(current) + 1;\n parts.unshift(siblings.length > 1 ? `${tag}:nth-of-type(${position})` : tag);\n current = current.parentElement;\n }\n return parts.length > 0 ? `body > ${parts.join(' > ')}` : '';\n }\n function readResolvedTargetSelectors() {\n try {\n const parsed = JSON.parse(window.sessionStorage.getItem(RESOLVED_TARGETS_KEY) ?? '{}');\n return parsed && typeof parsed === 'object' ? parsed : {};\n }\n catch {\n return {};\n }\n }\n function rememberResolvedTarget(element, fieldPath) {\n const selector = buildStructuralSelector(element);\n if (!selector)\n return;\n const selectors = readResolvedTargetSelectors();\n selectors[`${window.location.pathname}|${fieldPath}`] = selector;\n try {\n window.sessionStorage.setItem(RESOLVED_TARGETS_KEY, JSON.stringify(selectors));\n }\n catch {\n // The live DOM annotation still works when storage is unavailable.\n }\n }\n function forgetResolvedTargetsForCurrentPage() {\n const selectors = readResolvedTargetSelectors();\n const prefix = `${window.location.pathname}|`;\n let changed = false;\n for (const key of Object.keys(selectors)) {\n if (key.startsWith(prefix)) {\n delete selectors[key];\n changed = true;\n }\n }\n if (!changed)\n return;\n try {\n window.sessionStorage.setItem(RESOLVED_TARGETS_KEY, JSON.stringify(selectors));\n }\n catch {\n // Fresh DOM inference still works when storage is unavailable.\n }\n }\n function clearResolvedEditableTargets() {\n document\n .querySelectorAll(`[${RESOLVED_PATH_ATTRIBUTE}]`)\n .forEach((element) => {\n if (activeInlineEdit?.target === element)\n return;\n element.removeAttribute(RESOLVED_PATH_ATTRIBUTE);\n element.removeAttribute(EMPTY_EDITABLE_ATTRIBUTE);\n element.removeAttribute(EMPTY_COLLECTION_ATTRIBUTE);\n });\n }\n function annotateEditableTarget(element, field, remember = true) {\n const existingPath = element.getAttribute(RESOLVED_PATH_ATTRIBUTE);\n const authoredPath = element.getAttribute('data-preview-field-path') ??\n element.getAttribute(LIST_PATH_ATTRIBUTE) ??\n element.getAttribute('data-content-path') ??\n element.getAttribute('data-field-path');\n if (existingPath &&\n existingPath !== field.path &&\n authoredPath !== field.path) {\n return false;\n }\n element.setAttribute(RESOLVED_PATH_ATTRIBUTE, field.path);\n const isEmpty = String(field.value ?? '').trim().length === 0 &&\n normalizeText(element.textContent).length === 0;\n if (editModeActive && isEmpty && element.tagName !== 'IMG') {\n element.setAttribute(EMPTY_EDITABLE_ATTRIBUTE, 'true');\n }\n else {\n element.removeAttribute(EMPTY_EDITABLE_ATTRIBUTE);\n }\n const isCollection = field.kind === 'collection' || field.type === 'list';\n const collectionLength = field.collection?.length;\n if (editModeActive &&\n isCollection &&\n (collectionLength === 0 || element.childElementCount === 0)) {\n element.setAttribute(EMPTY_COLLECTION_ATTRIBUTE, 'true');\n element.removeAttribute(EMPTY_EDITABLE_ATTRIBUTE);\n }\n else {\n element.removeAttribute(EMPTY_COLLECTION_ATTRIBUTE);\n }\n if (remember && !isCollection) {\n rememberResolvedTarget(element, field.path);\n }\n return true;\n }\n function editableFieldMatchValues(field) {\n const values = [field.value, ...(field.matchValues ?? [])].filter((value) => typeof value === 'number' ||\n (typeof value === 'string' && value.trim().length > 0));\n return Array.from(new Set(values.map((value) => String(value))));\n }\n function findExplicitEditableTarget(fieldPath) {\n for (const variant of pathVariants(fieldPath)) {\n const escaped = CSS.escape(variant);\n const target = document.querySelector(`[data-preview-field-path=\"${escaped}\"], ` +\n `[${LIST_PATH_ATTRIBUTE}=\"${escaped}\"], ` +\n `[data-content-path=\"${escaped}\"], ` +\n `[data-field-path=\"${escaped}\"], ` +\n `[${RESOLVED_PATH_ATTRIBUTE}=\"${escaped}\"]`);\n if (target)\n return target;\n }\n return null;\n }\n function restoreRememberedTarget(field) {\n // A collection container must be explicitly authored. Remembering an\n // inferred ancestor can make an unrelated section (or the whole page)\n // reopen the collection after a reorder.\n if (field.kind === 'collection' || field.type === 'list') {\n return null;\n }\n const selectors = readResolvedTargetSelectors();\n const selector = selectors[`${window.location.pathname}|${field.path}`];\n if (!selector)\n return null;\n try {\n const target = document.querySelector(selector);\n if (!target)\n return null;\n const expectedValues = editableFieldMatchValues(field).map(normalizeText);\n const actual = normalizeText(target.textContent);\n if (expectedValues.length > 0 &&\n actual &&\n !expectedValues.includes(actual)) {\n return null;\n }\n annotateEditableTarget(target, field, false);\n return target;\n }\n catch {\n return null;\n }\n }\n function inferEditableTarget(field) {\n if (field.kind === 'collection' || field.type === 'list') {\n // Exact list and item markers are resolved before inference. Legacy\n // member leaves still expose collection CRUD through their context, but\n // no common ancestor is annotated: that ancestor can include headings,\n // navigation, or even the whole page in an unfamiliar template.\n return null;\n }\n const itemContainer = field.context\n ? findItemContainer({\n collectionPath: field.context.collectionPath,\n itemIndex: field.context.itemIndex,\n fieldKey: field.context.fieldKey,\n itemValues: field.context.itemValues,\n })\n : null;\n const root = itemContainer ?? document;\n for (const matchValue of editableFieldMatchValues(field)) {\n const preferred = findFieldTarget(root, matchValue, field.context?.fieldKey);\n const candidates = [\n ...findAttributeMatches(root, matchValue),\n ...(preferred ? [preferred] : []),\n ...findValueMatches(root, matchValue, field.context?.fieldKey),\n ];\n for (const target of candidates) {\n if (target.closest(`[${STATIC_ATTRIBUTE}]`)) {\n continue;\n }\n const resolvedPath = target.getAttribute(RESOLVED_PATH_ATTRIBUTE);\n if (!resolvedPath || resolvedPath === field.path) {\n return target;\n }\n }\n }\n return null;\n }\n function indexEditableTargets(options) {\n if (!editModeActive)\n return;\n ensureEmptyEditableStyles();\n activateRevealNodes();\n for (const field of editableFields) {\n const target = findExplicitEditableTarget(field.path) ??\n restoreRememberedTarget(field) ??\n (options?.explicitOnly ? null : inferEditableTarget(field));\n if (target) {\n annotateEditableTarget(target, field);\n }\n }\n }\n let indexScheduled = false;\n function scheduleEditableTargetIndex() {\n for (const timeout of indexTimeouts) {\n window.clearTimeout(timeout);\n }\n indexTimeouts = [];\n if (indexIdleHandle !== null) {\n const cancelIdle = window.cancelIdleCallback;\n if (typeof cancelIdle === 'function') {\n cancelIdle(indexIdleHandle);\n }\n else {\n window.clearTimeout(indexIdleHandle);\n }\n indexIdleHandle = null;\n }\n if (indexScheduled)\n return;\n indexScheduled = true;\n // Markers-only on every device. Full-text inference freezes the editor SPA\n // on large templates (phones and typical PCs alike).\n const runPass = (explicitOnly, isLast) => {\n if (isLast)\n indexScheduled = false;\n if (explicitOnly) {\n clearResolvedEditableTargets();\n }\n indexEditableTargets({ explicitOnly });\n };\n indexTimeouts = [\n window.setTimeout(() => {\n runPass(true, true);\n }, 0),\n ];\n }\n function createHoverBadge() {\n const badge = document.createElement('div');\n badge.setAttribute('data-fivora-edit-badge', 'true');\n badge.innerHTML = '✏️';\n Object.assign(badge.style, {\n position: 'fixed',\n zIndex: '2147483647',\n width: '28px',\n height: '28px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '14px',\n borderRadius: '8px',\n background: 'rgba(37, 99, 235, 0.92)',\n color: '#fff',\n cursor: 'pointer',\n pointerEvents: 'auto',\n boxShadow: '0 2px 8px rgba(0,0,0,0.18)',\n opacity: '0',\n transition: 'opacity 0.15s ease',\n userSelect: 'none',\n });\n badge.setAttribute('title', 'Edit this content');\n badge.setAttribute('aria-label', 'Edit this content');\n document.body.appendChild(badge);\n return badge;\n }\n function positionBadge(target) {\n if (!hoverBadge)\n return;\n const rect = target.getBoundingClientRect();\n const isImage = target.tagName === \'IMG\' || target.querySelector(\'img\') !== null || target.classList.contains(\'animated-shoe\') || target.closest(\'.animated-shoe\') !== null || /image/i.test(target.getAttribute(\'data-preview-field-path\') ?? \'\') || /image/i.test(target.getAttribute(\'data-content-path\') ?? \'\') || /image/i.test(target.getAttribute(\'data-field-path\') ?? \'\') || /image/i.test(target.getAttribute(RESOLVED_PATH_ATTRIBUTE) ?? \'\');\n if (isImage) {\n hoverBadge.style.top = `${Math.max(4, Math.min(window.innerHeight - 36, rect.bottom - 40))}px`;\n hoverBadge.style.left = `${Math.max(4, rect.left + 16)}px`;\n } else {\n hoverBadge.style.top = `${Math.max(4, rect.top - 4)}px`;\n hoverBadge.style.left = `${Math.min(window.innerWidth - 36, rect.right - 32)}px`;\n }\n hoverBadge.style.opacity = \'1\';\n }\n function clearHoverOverlay() {\n if (hoverOutlineCleanup) {\n hoverOutlineCleanup();\n hoverOutlineCleanup = null;\n }\n if (hoverBadge) {\n hoverBadge.style.opacity = '0';\n }\n hoveredElement = null;\n }\n function applyHoverOverlay(target) {\n if (target === hoveredElement)\n return;\n clearHoverOverlay();\n hoveredElement = target;\n const prevOutline = target.style.outline;\n const prevOutlineOffset = target.style.outlineOffset;\n const prevCursor = target.style.cursor;\n target.style.outline = '2px dashed rgba(37, 99, 235, 0.6)';\n target.style.outlineOffset = '2px';\n target.style.cursor = 'pointer';\n hoverOutlineCleanup = () => {\n target.style.outline = prevOutline;\n target.style.outlineOffset = prevOutlineOffset;\n target.style.cursor = prevCursor;\n };\n positionBadge(target);\n }\n function findEditableTarget(target) {\n let currentElement = target instanceof Element ? target : null;\n while (currentElement && !(currentElement instanceof HTMLElement)) {\n currentElement = currentElement.parentElement;\n }\n let current = currentElement;\n while (current && current !== document.body) {\n if (current.hasAttribute(STATIC_ATTRIBUTE)) {\n // A template can place a full-card static navigation link above an\n // editable collection row. Skip the fixed control itself and keep\n // walking so the exact authored item/list marker can open its editor.\n current = current.parentElement;\n continue;\n }\n const isCandidate = current.hasAttribute('data-preview-field-path') ||\n current.hasAttribute(LIST_PATH_ATTRIBUTE) ||\n current.hasAttribute(ITEM_PATH_ATTRIBUTE) ||\n current.hasAttribute('data-content-path') ||\n current.hasAttribute('data-field-path') ||\n current.hasAttribute(RESOLVED_PATH_ATTRIBUTE) ||\n current.matches(EDITABLE_SELECTOR);\n if (isCandidate) {\n const field = resolveEditableField(current);\n if (field) {\n return { element: current, field };\n }\n }\n current = current.parentElement;\n }\n return null;\n }\n function resolveEditableField(element) {\n if (element.closest(`[${STATIC_ATTRIBUTE}]`)) {\n return null;\n }\n // A primitive-list leaf commonly owns both an item marker and a field\n // marker. Resolve the concrete field first so the value remains editable;\n // its descriptor context still exposes collection CRUD in the popover.\n const explicitPath = element.getAttribute('data-preview-field-path') ??\n element.getAttribute('data-content-path') ??\n element.getAttribute('data-field-path') ??\n element.getAttribute(RESOLVED_PATH_ATTRIBUTE);\n if (explicitPath) {\n const explicitField = editableFields.find((field) => pathVariants(field.path).includes(explicitPath));\n return (explicitField ?? {\n path: explicitPath,\n label: explicitPath.split('.').pop() ?? 'Content',\n type: element.tagName === 'IMG' ? 'image' : 'text',\n value: element.tagName === 'IMG'\n ? element.src\n : (element.textContent?.trim() ?? ''),\n });\n }\n const itemPath = element.getAttribute(ITEM_PATH_ATTRIBUTE);\n if (itemPath) {\n const itemMatch = itemPath.match(/^(.+)\\[(\\d+)\\]$/);\n if (itemMatch) {\n const collectionPath = itemMatch[1];\n const itemIndex = Number(itemMatch[2]);\n const collectionField = editableFields.find((field) => (field.kind === 'collection' || field.type === 'list') &&\n pathVariants(field.path).includes(collectionPath));\n if (collectionField) {\n return {\n ...collectionField,\n collection: {\n listPath: collectionPath,\n itemIndex,\n length: collectionField.collection?.length ?? 0,\n minItems: collectionField.collection?.minItems,\n maxItems: collectionField.collection?.maxItems,\n itemLabel: collectionField.collection?.itemLabel,\n },\n };\n }\n }\n }\n const listPath = element.getAttribute(LIST_PATH_ATTRIBUTE);\n if (listPath) {\n const collectionField = editableFields.find((field) => (field.kind === 'collection' || field.type === 'list') &&\n pathVariants(field.path).includes(listPath));\n return (collectionField ?? {\n kind: 'collection',\n path: listPath,\n label: listPath.split('.').pop() ?? 'Collection',\n type: 'list',\n value: 0,\n collection: {\n listPath,\n length: element.children.length,\n },\n });\n }\n const imgElement = element.tagName === 'IMG'\n ? element\n : element.querySelector('img');\n if (imgElement) {\n const directImageField = editableFields.find((field) => field.type === 'image' &&\n editableFieldMatchValues(field).some((value) => imageMatchesValue(imgElement, value)));\n if (directImageField)\n return directImageField;\n const extractedCtx = extractCollectionContext(imgElement);\n if (extractedCtx.collectionPath &&\n typeof extractedCtx.itemIndex === 'number') {\n const itemImage = editableFields.find((field) => field.type === 'image' &&\n field.context?.collectionPath === extractedCtx.collectionPath &&\n field.context?.itemIndex === extractedCtx.itemIndex);\n if (itemImage)\n return itemImage;\n }\n const container = imgElement.closest('section, article, [data-preview-page-key], main, header, footer, .card, [class*=\"section\"]');\n if (container) {\n const containerHint = container.getAttribute('data-preview-field-path') ||\n container.getAttribute('data-content-path') ||\n container.getAttribute('data-field-path') ||\n container.getAttribute(RESOLVED_PATH_ATTRIBUTE);\n if (containerHint) {\n const prefix = containerHint.split('.')[0];\n const sectionImage = editableFields.find((field) => field.type === 'image' &&\n (field.path.startsWith(`${prefix}.`) ||\n field.path.startsWith(`${containerHint}.`)));\n if (sectionImage)\n return sectionImage;\n }\n }\n if (element.tagName === 'IMG') {\n const imageFields = editableFields.filter((f) => f.type === 'image');\n if (imageFields.length === 1)\n return imageFields[0];\n const rawSrc = imgElement.getAttribute('src') || imgElement.src || '';\n return {\n path: explicitPath || 'image',\n label: (explicitPath || '').split('.').pop() || 'Image',\n type: 'image',\n value: rawSrc,\n };\n }\n }\n const attributeFields = editableFields.filter((field) => editableFieldMatchValues(field).some((value) => attributeMatchesValue(element, value)));\n if (attributeFields.length === 1)\n return attributeFields[0];\n const elementText = normalizeText(element.textContent);\n if (!elementText)\n return null;\n const exact = editableFields.filter((field) => typeof field.value !== 'boolean' &&\n editableFieldMatchValues(field).some((value) => normalizeText(value) === elementText));\n if (exact.length === 1)\n return exact[0];\n const contained = editableFields\n .filter((field) => {\n if (typeof field.value === 'boolean')\n return false;\n return editableFieldMatchValues(field).some((matchValue) => {\n const value = normalizeText(matchValue);\n return value.length >= 3 && elementText.includes(value);\n });\n })\n .sort((left, right) => Math.max(...editableFieldMatchValues(right).map((value) => normalizeText(value).length), 0) -\n Math.max(...editableFieldMatchValues(left).map((value) => normalizeText(value).length), 0));\n return contained.length === 1 ? contained[0] : null;\n }\n function canEditInline(element, field) {\n return (element.tagName !== 'IMG' &&\n element.childElementCount === 0 &&\n ![\n 'INPUT',\n 'TEXTAREA',\n 'SELECT',\n 'OPTION',\n 'VIDEO',\n 'AUDIO',\n 'IFRAME',\n ].includes(element.tagName) &&\n !field.context &&\n !['image', 'color', 'boolean', 'select', 'list'].includes(field.type ?? 'text'));\n }\n function extractFieldPath(element) {\n let current = element;\n while (current && current !== document.body) {\n const path = current.getAttribute('data-preview-field-path') ??\n current.getAttribute(LIST_PATH_ATTRIBUTE) ??\n current.getAttribute('data-content-path') ??\n current.getAttribute('data-field-path') ??\n current.getAttribute(RESOLVED_PATH_ATTRIBUTE);\n if (path)\n return path;\n current = current.parentElement;\n }\n return null;\n }\n function extractCollectionContext(element) {\n let current = element;\n while (current && current !== document.body) {\n const itemPath = current.getAttribute(ITEM_PATH_ATTRIBUTE);\n if (itemPath) {\n const itemMatch = itemPath.match(/^(.+)\\[(\\d+)\\]$/);\n if (itemMatch) {\n return {\n collectionPath: itemMatch[1],\n itemIndex: Number(itemMatch[2]),\n };\n }\n }\n const path = current.getAttribute('data-preview-field-path') ??\n current.getAttribute('data-content-path') ??\n current.getAttribute('data-field-path') ??\n current.getAttribute(RESOLVED_PATH_ATTRIBUTE);\n if (path) {\n const match = path.match(/^(.+)\\[(\\d+)\\]/);\n if (match) {\n return { collectionPath: match[1], itemIndex: Number(match[2]) };\n }\n }\n const listPath = current.getAttribute(LIST_PATH_ATTRIBUTE);\n if (listPath) {\n return { collectionPath: listPath, itemIndex: null };\n }\n current = current.parentElement;\n }\n return { collectionPath: null, itemIndex: null };\n }\n function findRelatedAncestorFields(element, activeField) {\n const related = [];\n const seenPaths = new Set(activeField?.path ? [activeField.path] : []);\n let current = element;\n let depth = 0;\n while (current && current !== document.body && depth < 3) {\n if (current.hasAttribute(STATIC_ATTRIBUTE)) {\n break;\n }\n if (depth > 0 &&\n (current.hasAttribute(ITEM_PATH_ATTRIBUTE) ||\n current.hasAttribute(LIST_PATH_ATTRIBUTE) ||\n current.tagName === 'SECTION')) {\n break;\n }\n if (current.hasAttribute('data-preview-field-path') ||\n current.hasAttribute('data-content-path') ||\n current.hasAttribute('data-field-path') ||\n current.hasAttribute(RESOLVED_PATH_ATTRIBUTE)) {\n const candidate = resolveEditableField(current);\n if (candidate?.path &&\n candidate.kind !== 'collection' &&\n candidate.type !== 'list' &&\n !seenPaths.has(candidate.path)) {\n seenPaths.add(candidate.path);\n related.push({\n path: candidate.path,\n label: candidate.label ?? candidate.path.split('.').pop() ?? 'Content',\n type: candidate.type ?? 'text',\n });\n }\n }\n current = current.parentElement;\n depth += 1;\n }\n return related;\n }\n function emitClickEvent(element, field, relatedFields = findRelatedAncestorFields(element, field)) {\n const rect = element.getBoundingClientRect();\n const isImage = element.tagName === 'IMG';\n const fieldPath = field?.path ?? extractFieldPath(element);\n const fieldValue = isImage\n ? element.src\n : (element.textContent?.trim() ?? '');\n const extractedContext = extractCollectionContext(element);\n let collectionPath = field?.collection?.listPath ??\n field?.collection?.path ??\n field?.context?.collectionPath ??\n extractedContext.collectionPath;\n let itemIndex = field?.collection?.itemIndex ??\n field?.context?.itemIndex ??\n extractedContext.itemIndex;\n if (collectionPath &&\n fieldPath &&\n field?.kind !== 'collection' &&\n !fieldPath.startsWith(`${collectionPath}[`) &&\n !fieldPath.startsWith(`${collectionPath}.`) &&\n fieldPath !== collectionPath) {\n collectionPath = null;\n itemIndex = null;\n }\n const itemPath = field?.context?.itemPath ??\n (collectionPath && typeof itemIndex === 'number'\n ? `${collectionPath}[${itemIndex}]`\n : null);\n const clickPayload = {\n type: CLICK_MESSAGE,\n fieldPath,\n descriptorKind: field?.kind ?? 'field',\n fieldValue,\n elementTag: element.tagName.toLowerCase(),\n isImage,\n boundingRect: {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n },\n listPath: collectionPath,\n itemPath,\n collectionPath,\n itemIndex,\n relatedFields,\n };\n postToParent(clickPayload);\n postToParent({ ...clickPayload, type: LEGACY_CLICK_MESSAGE });\n }\n function emitFieldChange(fieldPath, value) {\n postToParent({\n type: CHANGE_MESSAGE,\n fieldPath,\n value,\n });\n postToParent({\n type: LEGACY_CHANGE_MESSAGE,\n fieldPath,\n value,\n });\n }\n function finishInlineEdit(commit) {\n const edit = activeInlineEdit;\n if (!edit)\n return;\n activeInlineEdit = null;\n edit.target.removeEventListener('keydown', edit.keydown);\n edit.target.removeEventListener('blur', edit.blur);\n const nextValue = commit\n ? (edit.target.innerText ?? edit.target.textContent ?? '')\n .replace(/\\u00a0/g, ' ')\n .trim()\n : '';\n if (edit.contentEditable === null) {\n edit.target.removeAttribute('contenteditable');\n }\n else {\n edit.target.setAttribute('contenteditable', edit.contentEditable);\n }\n if (edit.spellcheck === null) {\n edit.target.removeAttribute('spellcheck');\n }\n else {\n edit.target.setAttribute('spellcheck', edit.spellcheck);\n }\n edit.target.style.outline = edit.outline;\n edit.target.style.outlineOffset = edit.outlineOffset;\n edit.target.style.cursor = edit.cursor;\n edit.target.style.userSelect = edit.userSelect;\n edit.target.style.textTransform = edit.textTransform;\n // Restore the framework-authored DOM before notifying the host. React (or\n // another renderer) can then apply the value update without reconciling\n // against text nodes that the bridge created.\n edit.target.innerHTML = edit.originalHtml;\n if (!commit) {\n return;\n }\n if (nextValue !== edit.originalText.trim()) {\n edit.field.value = nextValue;\n annotateEditableTarget(edit.target, edit.field);\n emitFieldChange(edit.field.path, nextValue);\n }\n else if (!nextValue) {\n annotateEditableTarget(edit.target, edit.field);\n }\n }\n function beginInlineEdit(target, field, pointer) {\n if (activeInlineEdit?.target === target)\n return;\n finishInlineEdit(true);\n clearHoverOverlay();\n annotateEditableTarget(target, field);\n target.removeAttribute(EMPTY_EDITABLE_ATTRIBUTE);\n const originalText = typeof field.value === 'string' || typeof field.value === 'number'\n ? String(field.value)\n : (target.textContent ?? '');\n const originalHtml = target.innerHTML;\n const keydown = (event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n finishInlineEdit(false);\n return;\n }\n if (event.key === 'Enter' &&\n field.type !== 'textarea' &&\n !event.shiftKey) {\n event.preventDefault();\n finishInlineEdit(true);\n }\n };\n const blur = () => finishInlineEdit(true);\n activeInlineEdit = {\n target,\n field,\n originalText,\n originalHtml,\n contentEditable: target.getAttribute('contenteditable'),\n spellcheck: target.getAttribute('spellcheck'),\n outline: target.style.outline,\n outlineOffset: target.style.outlineOffset,\n cursor: target.style.cursor,\n userSelect: target.style.userSelect,\n textTransform: target.style.textTransform,\n keydown,\n blur,\n };\n target.setAttribute('contenteditable', supportsPlaintextOnlyContentEditable ? 'plaintext-only' : 'true');\n target.setAttribute('spellcheck', 'true');\n // Inline editing is limited to leaf elements, and finishInlineEdit restores\n // this authored markup before emitting the changed value.\n target.textContent = originalText;\n target.style.outline = '2px solid rgba(37, 99, 235, 0.95)';\n target.style.outlineOffset = '3px';\n target.style.cursor = 'text';\n target.style.userSelect = 'text';\n target.style.textTransform = 'none';\n target.addEventListener('keydown', keydown);\n target.addEventListener('blur', blur);\n target.focus();\n if (pointer) {\n const documentWithCaret = document;\n const caretPosition = documentWithCaret.caretPositionFromPoint?.(pointer.x, pointer.y);\n const range = caretPosition\n ? (() => {\n const nextRange = document.createRange();\n nextRange.setStart(caretPosition.offsetNode, caretPosition.offset);\n nextRange.collapse(true);\n return nextRange;\n })()\n : documentWithCaret.caretRangeFromPoint?.(pointer.x, pointer.y);\n if (range) {\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n }\n }\n else {\n const range = document.createRange();\n range.selectNodeContents(target);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n }\n }\n let hoverRafId = null;\n function onEditMouseOver(event) {\n if (!editModeActive)\n return;\n if (activeInlineEdit)\n return;\n if (isTouchDevice)\n return;\n if (hoverRafId !== null)\n return;\n const target = event.target;\n hoverRafId = requestAnimationFrame(() => {\n hoverRafId = null;\n if (!editModeActive || activeInlineEdit)\n return;\n const editableTarget = findEditableTarget(target);\n if (editableTarget &&\n !editableTarget.element.hasAttribute('data-fivora-edit-badge')) {\n applyHoverOverlay(editableTarget.element);\n }\n });\n }\n function onEditMouseOut(event) {\n if (!editModeActive)\n return;\n const related = event.relatedTarget instanceof HTMLElement ? event.relatedTarget : null;\n if (related &&\n (related === hoverBadge ||\n related === hoveredElement ||\n hoveredElement?.contains(related))) {\n return;\n }\n clearHoverOverlay();\n }\n function onEditClick(event) {\n if (!editModeActive)\n return;\n if (activeInlineEdit &&\n event.target instanceof Node &&\n activeInlineEdit.target.contains(event.target)) {\n return;\n }\n const badge = event.target instanceof HTMLElement &&\n event.target.hasAttribute('data-fivora-edit-badge')\n ? event.target\n : null;\n const editableTarget = badge\n ? hoveredElement\n ? {\n element: hoveredElement,\n field: resolveEditableField(hoveredElement),\n }\n : null\n : findEditableTarget(event.target);\n const target = editableTarget?.element;\n const field = editableTarget?.field;\n // Let real CTAs / nav / non-editable controls work. Only intercept\n // clicks that hit an editable field (or its hover badge).\n if (!target || !field) {\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n const relatedFields = findRelatedAncestorFields(target, field);\n if (!preferParentPopover &&\n canEditInline(target, field) &&\n relatedFields.length === 0) {\n beginInlineEdit(target, field, badge ? undefined : { x: event.clientX, y: event.clientY });\n }\n else {\n emitClickEvent(target, field, relatedFields);\n }\n }\n function enterEditMode() {\n if (editModeActive)\n return;\n editModeActive = true;\n clearHighlight();\n ensureEmptyEditableStyles();\n if (!isTouchDevice && !hoverBadge) {\n hoverBadge = createHoverBadge();\n }\n if (!isTouchDevice) {\n document.addEventListener('mouseover', onEditMouseOver, true);\n document.addEventListener('mouseout', onEditMouseOut, true);\n }\n document.addEventListener('click', onEditClick, true);\n document.addEventListener('submit', preventEditModeSubmit, true);\n scheduleEditableTargetIndex();\n }\n function preventEditModeSubmit(event) {\n if (!editModeActive)\n return;\n event.preventDefault();\n event.stopPropagation();\n }\n function exitEditMode() {\n if (!editModeActive)\n return;\n editModeActive = false;\n indexScheduled = false;\n finishInlineEdit(true);\n clearHoverOverlay();\n if (hoverRafId !== null) {\n cancelAnimationFrame(hoverRafId);\n hoverRafId = null;\n }\n for (const timeout of indexTimeouts) {\n window.clearTimeout(timeout);\n }\n indexTimeouts = [];\n if (indexIdleHandle !== null) {\n const cancelIdle = window.cancelIdleCallback;\n if (typeof cancelIdle === 'function') {\n cancelIdle(indexIdleHandle);\n }\n else {\n window.clearTimeout(indexIdleHandle);\n }\n indexIdleHandle = null;\n }\n clearResolvedEditableTargets();\n document\n .querySelectorAll(`[${EMPTY_EDITABLE_ATTRIBUTE}], [${EMPTY_COLLECTION_ATTRIBUTE}]`)\n .forEach((element) => {\n element.removeAttribute(EMPTY_EDITABLE_ATTRIBUTE);\n element.removeAttribute(EMPTY_COLLECTION_ATTRIBUTE);\n });\n document.removeEventListener('mouseover', onEditMouseOver, true);\n document.removeEventListener('mouseout', onEditMouseOut, true);\n document.removeEventListener('click', onEditClick, true);\n document.removeEventListener('submit', preventEditModeSubmit, true);\n }\n // Restore live data/edit mode and tell the host which page is open after\n // both full document loads and client-side router navigation.\n const originalPushState = window.history.pushState.bind(window.history);\n const originalReplaceState = window.history.replaceState.bind(window.history);\n window.history.pushState = (...args) => {\n originalPushState(...args);\n window.setTimeout(announceReady, 0);\n };\n window.history.replaceState = (...args) => {\n originalReplaceState(...args);\n window.setTimeout(announceReady, 0);\n };\n window.addEventListener('popstate', announceReady);\n // Static template previews are HTML exports — Next.js soft navigation tries\n // to fetch missing RSC `.txt` payloads (404 spam) and glitches the preview.\n // Force same-site internal links to full document loads; cached site data\n // prevents demo-content flash on remount.\n function resolvePreviewRootPrefix() {\n const match = window.location.pathname.match(/^(\\/uploads\\/generated-sites\\/(?:template-preview|[^/]+)\\/[^/]+)/);\n return match?.[1] ?? '';\n }\n function isInternalPreviewNavigation(anchor) {\n if (anchor.target && anchor.target !== '_self')\n return false;\n if (anchor.hasAttribute('download'))\n return false;\n const rawHref = anchor.getAttribute('href');\n if (!rawHref || rawHref.startsWith('#'))\n return false;\n if (/^(mailto:|tel:|sms:|whatsapp:|javascript:)/i.test(rawHref)) {\n return false;\n }\n let url;\n try {\n url = new URL(rawHref, window.location.href);\n }\n catch {\n return false;\n }\n if (url.origin !== window.location.origin)\n return false;\n const root = resolvePreviewRootPrefix();\n if (root && !url.pathname.startsWith(root))\n return false;\n const current = window.location.pathname.replace(/\\/+$/, '') || '/';\n const next = url.pathname.replace(/\\/+$/, '') || '/';\n return current !== next || url.search !== window.location.search;\n }\n document.addEventListener('click', (event) => {\n if (event.defaultPrevented)\n return;\n if (event.button !== 0)\n return;\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return;\n }\n const anchor = event.target?.closest?.('a[href]');\n if (!anchor || !isInternalPreviewNavigation(anchor))\n return;\n event.preventDefault();\n event.stopPropagation();\n window.location.assign(anchor.href);\n }, true);\n announceReady();\n})(function resolveTemplatePreviewParentOrigin(input) {\n const normalizeOrigin = (value, baseOrigin) => {\n if (!value || value.trim() === 'null')\n return null;\n try {\n const origin = new URL(value, baseOrigin ?? undefined).origin;\n return origin === 'null' ? null : origin;\n }\n catch {\n return null;\n }\n };\n const currentOrigin = normalizeOrigin(input.currentOrigin);\n const ancestorOrigin = normalizeOrigin(input.ancestorOrigin, currentOrigin);\n const accessibleParentOrigin = normalizeOrigin(input.accessibleParentOrigin, currentOrigin);\n const referrerOrigin = normalizeOrigin(input.referrer, currentOrigin);\n const rememberedOrigin = normalizeOrigin(input.rememberedOrigin);\n // ancestorOrigins and an accessible parent window describe the current\n // embedder directly. A cross-origin referrer does too on the first document\n // load. During a full in-frame navigation the referrer becomes the previous\n // preview page, so retain the parent origin captured by the first page.\n return (ancestorOrigin ??\n accessibleParentOrigin ??\n (referrerOrigin && referrerOrigin !== currentOrigin\n ? referrerOrigin\n : null) ??\n rememberedOrigin ??\n referrerOrigin);\n},function buildUniversalTemplateThemeCss(themeValue) {\n const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n if (!isRecord(themeValue) || themeValue.designCustomizationVersion !== 1) {\n return '';\n }\n const theme = themeValue;\n const safeValue = (value) => {\n if (typeof value !== 'string')\n return '';\n const trimmed = value.trim();\n if (!trimmed ||\n trimmed.length > 160 ||\n /[;{}<>\\r\\n]/.test(trimmed) ||\n /(?:url\\s*\\(|expression\\s*\\(|@import|javascript:)/i.test(trimmed)) {\n return '';\n }\n return trimmed;\n };\n const read = (key) => safeValue(theme[key]);\n const declaration = (property, value) => value ? `${property}:${value} !important;` : '';\n const rule = (selector, declarations) => {\n const body = declarations.filter(Boolean).join('');\n return body ? `${selector}{${body}}` : '';\n };\n const backgroundDeclarations = (value) => value\n ? [\n declaration('background', value),\n declaration('background-color', value),\n 'background-image:none !important;',\n ]\n : [];\n const alignItems = (value) => {\n if (value === 'start')\n return 'flex-start';\n if (value === 'end')\n return 'flex-end';\n if (value === 'center' || value === 'stretch')\n return value;\n return '';\n };\n const gridColumns = (value) => {\n const count = Number(value);\n return Number.isInteger(count) && count >= 1 && count <= 6\n ? `repeat(${count},minmax(0,1fr))`\n : '';\n };\n const scale = (() => {\n const value = Number(read('headingScale'));\n return Number.isFinite(value) && value >= 0.75 && value <= 2\n ? String(value)\n : '';\n })();\n const shadow = (value) => {\n const shadows = {\n none: 'none',\n subtle: '0 4px 14px rgba(15,23,42,.08)',\n medium: '0 12px 30px rgba(15,23,42,.14)',\n strong: '0 22px 55px rgba(15,23,42,.22)',\n };\n return shadows[value] ?? '';\n };\n const colorVariables = [\n ['--brand-color', read('primaryColor')],\n ['--brand-primary', read('primaryColor')],\n ['--primary-color', read('primaryColor')],\n ['--color-primary', read('primaryColor')],\n ['--brand-secondary', read('secondaryColor')],\n ['--secondary-color', read('secondaryColor')],\n ['--brand-accent', read('accentColor')],\n ['--accent-color', read('accentColor')],\n ['--page-background', read('backgroundColor')],\n ['--page-text', read('textColor')],\n ['--surface-color', read('surfaceColor')],\n ['--surface-alt-color', read('surfaceAltColor')],\n ['--heading-color', read('headingColor')],\n ['--muted-text-color', read('mutedTextColor')],\n ['--border-color', read('borderColor')],\n ['--card-background', read('cardBackgroundColor')],\n ['--hero-min-height', read('heroMinHeight')],\n ['--section-padding', read('sectionPadding')],\n ['--content-max-width', read('contentMaxWidth')],\n ['--container-padding', read('containerPadding')],\n ['--section-gap', read('sectionGap')],\n ['--element-gap', read('elementGap')],\n ['--grid-gap', read('gridGap')],\n ['--card-radius', read('cardRadius')],\n ['--button-radius', read('buttonRadius')],\n ['--image-radius', read('imageRadius')],\n ];\n const css = [\n rule(':root,body', colorVariables.map(([name, value]) => declaration(name, value))),\n rule('html', [declaration('font-size', read('baseSize'))]),\n rule('body', [\n declaration('font-family', read('bodyFont') ? `${read('bodyFont')},sans-serif` : ''),\n declaration('font-weight', read('bodyWeight')),\n declaration('line-height', read('bodyLineHeight')),\n declaration('letter-spacing', read('letterSpacing')),\n ...backgroundDeclarations(read('backgroundColor')),\n declaration('color', read('textColor')),\n ]),\n rule('body :where(h1,h2,h3,h4,h5,h6)', [\n declaration('font-family', read('headingFont') ? `${read('headingFont')},sans-serif` : ''),\n declaration('font-weight', read('headingWeight')),\n declaration('line-height', read('headingLineHeight')),\n declaration('color', read('headingColor')),\n ]),\n rule('body :where(p,small,.muted,[class*=\"muted\"])', [\n declaration('color', read('mutedTextColor')),\n ]),\n scale\n ? `body h1{font-size:calc(2.5rem * ${scale}) !important}` +\n `body h2{font-size:calc(2rem * ${scale}) !important}` +\n `body h3{font-size:calc(1.5rem * ${scale}) !important}` +\n `body h4{font-size:calc(1.25rem * ${scale}) !important}`\n : '',\n rule('body header', [\n ...backgroundDeclarations(read('headerBackgroundColor')),\n declaration('min-height', read('headerHeight')),\n ]),\n rule('body footer', [\n ...backgroundDeclarations(read('footerBackgroundColor')),\n ]),\n rule('body main', [\n ...backgroundDeclarations(read('backgroundColor')),\n declaration('color', read('textColor')),\n ]),\n rule('body main > section,body main [data-preview-page-key] > section', [\n declaration('padding-block', read('sectionPadding')),\n declaration('text-align', read('textAlign')),\n ]),\n rule('body main :where(section,[data-design-section]) :where(h1,h2,h3,h4,h5,h6,p,[data-design-text])', [declaration('text-align', read('textAlign'))]),\n rule('body main > section + section,body main [data-preview-page-key] > section + section', [declaration('margin-top', read('sectionGap'))]),\n rule('body main :where([class*=\"flex\"],[class*=\"grid\"],[data-design-stack])', [declaration('gap', read('elementGap'))]),\n rule('body main > section:nth-of-type(even),body main [data-preview-page-key] > section:nth-of-type(even)', backgroundDeclarations(read('surfaceAltColor'))),\n rule('body main > section:nth-of-type(odd),body main [data-preview-page-key] > section:nth-of-type(odd)', backgroundDeclarations(read('surfaceColor'))),\n rule('body main > section:first-of-type,body main [data-preview-page-key] > section:first-of-type', [\n declaration('min-height', read('heroMinHeight')),\n declaration('text-align', read('heroTextAlign')),\n ]),\n rule('body main > section:first-of-type :where(h1,h2,h3,h4,h5,h6,p,[class*=\"container\"],[data-design-text]),body main [data-preview-page-key] > section:first-of-type :where(h1,h2,h3,h4,h5,h6,p,[class*=\"container\"],[data-design-text])', [declaration('text-align', read('heroTextAlign'))]),\n rule('body main :where([class*=\"container\"],[class~=\"container\"],[data-design-container])', [\n declaration('max-width', read('contentMaxWidth')),\n declaration('padding-inline', read('containerPadding')),\n read('contentMaxWidth') ? 'margin-inline:auto !important;' : '',\n ]),\n rule('body main :where(section,[data-design-section]) > :where([class*=\"flex\"],[data-design-content])', [\n declaration('align-items', alignItems(read('contentAlign'))),\n declaration('justify-items', read('contentAlign')),\n ]),\n rule('body main :where([data-preview-list-path],[data-design-grid])', [\n gridColumns(read('gridColumns')) ? 'display:grid !important;' : '',\n declaration('grid-template-columns', gridColumns(read('gridColumns'))),\n declaration('gap', read('gridGap')),\n ]),\n rule('body main :where([data-preview-item-path],[data-design-card],.card,[class*=\"card-\"])', [\n declaration('width', read('cardWidth')),\n read('cardWidth') ? 'max-width:100% !important;' : '',\n declaration('min-height', read('cardMinHeight')),\n declaration('padding', read('cardPadding')),\n declaration('border-radius', read('cardRadius')),\n declaration('border-width', read('cardBorderWidth')),\n read('cardBorderWidth') ? 'border-style:solid !important;' : '',\n declaration('border-color', read('borderColor')),\n ...backgroundDeclarations(read('cardBackgroundColor')),\n declaration('box-shadow', shadow(read('cardShadow'))),\n declaration('text-align', read('cardTextAlign')),\n ]),\n rule('body main :where([data-preview-item-path],[data-design-card],.card,[class*=\"card-\"]) :where(h1,h2,h3,h4,h5,h6,p,span,[data-design-text])', [declaration('text-align', read('cardTextAlign'))]),\n rule('body main :where(button,a[class*=\"btn\"],a[class*=\"button\"],[data-design-button])', [\n declaration('padding', read('buttonPadding')),\n declaration('border-radius', read('buttonRadius')),\n ...backgroundDeclarations(read('buttonBackgroundColor')),\n declaration('color', read('buttonTextColor')),\n declaration('box-shadow', shadow(read('buttonShadow'))),\n ]),\n rule('body main img', [declaration('border-radius', read('imageRadius'))]),\n ];\n const sections = isRecord(theme.sections) ? theme.sections : {};\n for (const [key, rawSection] of Object.entries(sections)) {\n if (!/^[a-zA-Z0-9_-]{1,64}$/.test(key) || !isRecord(rawSection))\n continue;\n const sectionRead = (property) => safeValue(rawSection[property]);\n const sectionBackground = sectionRead('backgroundColor');\n const fullBleedLayerSelector = [\n '[class*=\"absolute\"][class*=\"inset-0\"]',\n '[class*=\"fixed\"][class*=\"inset-0\"]',\n '[class*=\"absolute\"][class*=\"inset-x-0\"][class*=\"inset-y-0\"]',\n '[class*=\"absolute\"][class*=\"top-0\"][class*=\"right-0\"][class*=\"bottom-0\"][class*=\"left-0\"]',\n ].join(',');\n const specialSelectors = {\n all: 'body main section',\n hero: 'body main > section:first-of-type,body main [data-preview-page-key] > section:first-of-type',\n header: 'body header',\n footer: 'body footer',\n cards: 'body main :where([data-preview-item-path],[data-design-card],.card,[class*=\"card-\"])',\n };\n const selector = specialSelectors[key] ??\n `body :where([data-preview-page-key=\"${key}\"] > section,[data-design-section=\"${key}\"],[data-section-id=\"${key}\"],section#${key},section.${key})`;\n css.push(rule(selector, [\n rawSection.visible === false ? 'display:none !important;' : '',\n ...backgroundDeclarations(sectionBackground),\n declaration('color', sectionRead('textColor')),\n declaration('min-height', sectionRead('minHeight')),\n declaration('padding-block', sectionRead('padding')),\n declaration('max-width', sectionRead('contentMaxWidth')),\n declaration('gap', sectionRead('gap')),\n declaration('text-align', sectionRead('textAlign')),\n declaration('align-items', alignItems(sectionRead('contentAlign'))),\n ]), rule(`${selector} :where(h1,h2,h3,h4,h5,h6)`, [\n declaration('color', sectionRead('headingColor')),\n declaration('text-align', sectionRead('textAlign')),\n ]), rule(`${selector} :where(p,span,[data-design-text])`, [\n declaration('text-align', sectionRead('textAlign')),\n ]), rule(`${selector} :where([data-preview-item-path],[data-design-card],.card,[class*=\"card-\"])`, [\n ...backgroundDeclarations(sectionRead('cardBackgroundColor')),\n declaration('width', sectionRead('cardWidth')),\n sectionRead('cardWidth') ? 'max-width:100% !important;' : '',\n declaration('min-height', sectionRead('cardMinHeight')),\n declaration('border-radius', sectionRead('cardRadius')),\n ]), rule(`${selector} :where([data-preview-list-path],[data-design-grid])`, [\n gridColumns(sectionRead('gridColumns'))\n ? 'display:grid !important;'\n : '',\n declaration('grid-template-columns', gridColumns(sectionRead('gridColumns'))),\n ]), rule(`${selector}::before,${selector}::after`, sectionBackground\n ? [\n 'background:none !important;',\n 'background-image:none !important;',\n 'opacity:0 !important;',\n ]\n : []), rule(`${selector} > :where(${fullBleedLayerSelector})`, sectionBackground\n ? [\n 'background:none !important;',\n 'background-image:none !important;',\n 'box-shadow:none !important;',\n 'mask-image:none !important;',\n '-webkit-mask-image:none !important;',\n ]\n : []), rule(`${selector} > :where(${fullBleedLayerSelector})::before,${selector} > :where(${fullBleedLayerSelector})::after`, sectionBackground\n ? [\n 'background:none !important;',\n 'background-image:none !important;',\n 'opacity:0 !important;',\n ]\n : []), rule(`${selector} > :where(${fullBleedLayerSelector}) :where(img,video,canvas,picture)`, sectionBackground ? ['opacity:0.2 !important;'] : []));\n }\n return css.filter(Boolean).join('\\n');\n},function replaceTemplateColorLiterals(sourceText, replacementsValue) {\n if (!replacementsValue ||\n typeof replacementsValue !== 'object' ||\n Array.isArray(replacementsValue)) {\n return sourceText;\n }\n const normalize = (value) => {\n const color = value.trim().toLowerCase();\n const short = color.match(/^#([0-9a-f]{3})$/);\n if (short) {\n return `#${[...short[1]].map((digit) => digit.repeat(2)).join('')}`;\n }\n return /^#[0-9a-f]{6}$/.test(color) ? color : null;\n };\n const variants = new Map();\n const rgbVariants = new Map();\n for (const [rawSource, rawReplacement] of Object.entries(replacementsValue).slice(0, 64)) {\n if (typeof rawReplacement !== 'string')\n continue;\n const source = normalize(rawSource);\n const replacement = normalize(rawReplacement);\n if (!source || !replacement || source === replacement)\n continue;\n variants.set(source, replacement);\n const channels = (color) => [\n Number.parseInt(color.slice(1, 3), 16),\n Number.parseInt(color.slice(3, 5), 16),\n Number.parseInt(color.slice(5, 7), 16),\n ];\n rgbVariants.set(channels(source).join(','), channels(replacement));\n if (source[1] === source[2] &&\n source[3] === source[4] &&\n source[5] === source[6]) {\n variants.set(`#${source[1]}${source[3]}${source[5]}`, replacement);\n }\n }\n if (variants.size === 0)\n return sourceText;\n const alternatives = [...variants.keys()]\n .sort((left, right) => right.length - left.length)\n .map((value) => value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n const pattern = new RegExp(`(?<!\\\\\\\\)(?:${alternatives.join('|')})(?![0-9a-f])`, 'gi');\n const replacedHex = sourceText.replace(pattern, (match) => {\n const normalized = normalize(match);\n return normalized ? (variants.get(normalized) ?? match) : match;\n });\n const rgbPattern = /(rgba?\\(\\s*)(\\d{1,3})(\\s+|,\\s*)(\\d{1,3})(\\s+|,\\s*)(\\d{1,3})/gi;\n return replacedHex.replace(rgbPattern, (match, prefix, red, firstSeparator, green, secondSeparator, blue) => {\n const replacement = rgbVariants.get(`${red},${green},${blue}`);\n if (!replacement)\n return match;\n return `${prefix}${replacement[0]}${firstSeparator}${replacement[1]}${secondSeparator}${replacement[2]}`;\n });\n},\"fivora-universal-design-overrides\",function enforceSelectedTemplatePages(siteDataValue, documentValue) {\n const doc = documentValue ?? document;\n const record = siteDataValue &&\n typeof siteDataValue === 'object' &&\n !Array.isArray(siteDataValue)\n ? siteDataValue\n : null;\n const requirements = record?.requirements &&\n typeof record.requirements === 'object' &&\n !Array.isArray(record.requirements)\n ? record.requirements\n : null;\n const template = record?.template &&\n typeof record.template === 'object' &&\n !Array.isArray(record.template)\n ? record.template\n : null;\n const structure = template?.structure &&\n typeof template.structure === 'object' &&\n !Array.isArray(template.structure)\n ? template.structure\n : null;\n const hasRequiredPages = Array.isArray(requirements?.requiredPages);\n const hasStructurePages = Array.isArray(structure?.pages);\n if (!hasRequiredPages && !hasStructurePages)\n return;\n const selectedSource = hasRequiredPages\n ? requirements?.requiredPages\n : structure?.pages;\n const selected = new Set(selectedSource\n .filter((value) => typeof value === 'string')\n .map((value) => value.trim())\n .filter(Boolean));\n const templateDefinitions = Array.isArray(template?.pageDefinitions)\n ? template.pageDefinitions\n : [];\n const structureDefinitions = Array.isArray(structure?.pageDefinitions)\n ? structure.pageDefinitions\n : [];\n const providedDefinitions = templateDefinitions.length > 0 ? templateDefinitions : structureDefinitions;\n const definitions = providedDefinitions.flatMap((page) => {\n if (!page || typeof page !== 'object' || Array.isArray(page))\n return [];\n const value = page;\n if (typeof value.id !== 'string' || !value.id.trim())\n return [];\n const id = value.id.trim();\n const label = typeof value.label === 'string' && value.label.trim()\n ? value.label.trim()\n : id.replace(/_/g, ' ');\n const rawRoute = typeof value.route === 'string' ? value.route.trim() : '';\n const route = rawRoute === '/' ? '/' : `/${(rawRoute || id).replace(/^\\/+|\\/+$/g, '')}`;\n return [{ id, label, route }];\n });\n const fallbackPageSource = hasStructurePages\n ? structure?.pages\n : selectedSource;\n const fallbackDefinitions = fallbackPageSource\n .filter((value) => typeof value === 'string')\n .map((value) => value.trim())\n .filter(Boolean)\n .map((id, index) => ({\n id,\n label: id.replace(/_/g, ' '),\n route: index === 0 ? '/' : `/${id}`,\n }));\n const pages = definitions.length > 0 ? definitions : fallbackDefinitions;\n if (pages.length === 0)\n return;\n const disabledPages = pages.filter((page) => !selected.has(page.id));\n if (disabledPages.length === 0) {\n doc\n .querySelectorAll('[data-fivora-page-disabled]')\n .forEach((element) => element.removeAttribute('data-fivora-page-disabled'));\n return;\n }\n let style = doc.getElementById('fivora-page-selection-style');\n if (!style || style.tagName !== 'STYLE') {\n style = doc.createElement('style');\n style.id = 'fivora-page-selection-style';\n style.textContent =\n '[data-fivora-page-disabled=\"true\"]{display:none!important}';\n doc.head.appendChild(style);\n }\n doc\n .querySelectorAll('[data-fivora-page-disabled]')\n .forEach((element) => element.removeAttribute('data-fivora-page-disabled'));\n const normalizePath = (value) => {\n let pathname = value;\n try {\n const url = new URL(value, doc.baseURI);\n if (url.origin !== doc.location?.origin)\n return '';\n pathname = url.pathname;\n }\n catch {\n return '';\n }\n const previewRoot = pathname.match(/^(\\/uploads\\/generated-sites\\/(?:template-preview|preview|live)\\/[^/]+)/)?.[1];\n if (previewRoot && pathname.startsWith(previewRoot)) {\n pathname = pathname.slice(previewRoot.length) || '/';\n }\n pathname = pathname.replace(/\\/index\\.html$/i, '/').replace(/\\.html$/i, '');\n const clean = pathname.replace(/\\/+$/g, '') || '/';\n return clean.startsWith('/') ? clean : `/${clean}`;\n };\n const pageForPath = (path) => pages.find((page) => {\n const route = normalizePath(page.route);\n if (!route)\n return false;\n if (route === '/')\n return path === '/';\n return path === route || path.startsWith(`${route}/`);\n });\n const pageForControl = (element) => {\n for (const attribute of [\n 'href',\n 'formaction',\n 'data-href',\n 'data-route',\n 'data-url',\n ]) {\n const destination = element.getAttribute(attribute);\n if (!destination)\n continue;\n const page = pageForPath(normalizePath(destination));\n if (page)\n return page;\n }\n return undefined;\n };\n const disable = (element) => {\n if (element)\n element.setAttribute('data-fivora-page-disabled', 'true');\n };\n for (const page of disabledPages) {\n for (const attribute of [\n 'data-page-key',\n 'data-required-page',\n 'data-target-page',\n ]) {\n doc.querySelectorAll(`[${attribute}]`).forEach((element) => {\n if (element.getAttribute(attribute) === page.id)\n disable(element);\n });\n }\n }\n const anchors = Array.from(doc.querySelectorAll('a[href]'));\n for (const anchor of anchors) {\n const targetPage = pageForControl(anchor);\n if (!targetPage || selected.has(targetPage.id))\n continue;\n const fullCardLink = anchor.classList.contains('absolute') &&\n (anchor.classList.contains('inset-0') ||\n (anchor.classList.contains('inset-x-0') &&\n anchor.classList.contains('inset-y-0')));\n if (fullCardLink) {\n disable(anchor.closest('[data-preview-item-path],[data-design-card],article,li'));\n }\n else {\n const listItem = anchor.closest('li');\n disable(listItem && listItem.querySelectorAll('a[href]').length === 1\n ? listItem\n : anchor);\n }\n }\n const buttons = Array.from(doc.querySelectorAll('button,[role=\"button\"],[data-href],[data-route],[data-url]')).filter((element) => element.tagName !== 'A');\n for (const button of buttons) {\n const targetPage = pageForControl(button);\n if (!targetPage || selected.has(targetPage.id))\n continue;\n const listItem = button.closest('li');\n disable(listItem &&\n listItem.querySelectorAll('a[href],button,[role=\"button\"],[data-href],[data-route],[data-url]').length === 1\n ? listItem\n : button);\n }\n const firstMainSection = doc.querySelector('main section');\n for (const section of doc.querySelectorAll('main section')) {\n const allActions = Array.from(section.querySelectorAll('a[href],button,[role=\"button\"],[data-href],[data-route],[data-url]'));\n const routeLinks = allActions\n .map(pageForControl)\n .filter((page) => Boolean(page));\n const isPageRoot = section.hasAttribute('data-preview-page-key');\n const isLikelyHero = section === firstMainSection ||\n section.hasAttribute('data-design-hero') ||\n /(?:^|\\s)(?:hero|banner|masthead)(?:\\s|$)/i.test(section.className) ||\n Boolean(section.querySelector('h1'));\n if (!isPageRoot &&\n !isLikelyHero &&\n routeLinks.length > 0 &&\n routeLinks.length === allActions.length &&\n routeLinks.every((page) => !selected.has(page.id))) {\n disable(section);\n }\n }\n});";
|
|
3
|
+
// Generated from visual editor bridge (v45).
|
|
4
|
+
module.exports = "(function(M,L,x,R,s){const l=`${[\"MARKET\",\"PLACE\"].join(\"\")}_PREVIEW_`,p=__name(t=>`${l}${t}`,\"previousPreviewMessage\"),P=__name(t=>`__${l}${t}__`,\"previousPreviewStorageKey\"),U=\"FIVORA_PREVIEW_FOCUS_PAGE\",T=p(\"FOCUS_PAGE\"),C=\"FIVORA_PREVIEW_FOCUS_RESULT\",v=p(\"FOCUS_RESULT\"),V=\"FIVORA_PREVIEW_READY\",j=p(\"READY\"),G=\"data-fivora-preview-active-field\",m=\"data-fivora-resolved-field-path\",h=\"data-fivora-empty-editable\",A=\"data-fivora-empty-collection\",N=\"data-preview-list-path\",$=\"data-preview-item-path\",W=\"data-preview-static\",k=\"__FIVORA_UNIVERSAL_PREVIEW_FOCUS__\",z=\"__FIVORA_VISUAL_EDITOR_TARGETS__\",Q=\"__FIVORA_PREVIEW_PARENT_ORIGIN__\",qt=P(\"PARENT_ORIGIN\"),wt=\"__FIVORA_PREVIEW_SITE_DATA_CACHE__\",At=P(\"SITE_DATA_CACHE\"),f=\"__FIVORA_PREVIEW_SITE_DATA__\",_=P(\"SITE_DATA\"),S=\"FIVORA_PREVIEW_SITE_DATA\",F=p(\"SITE_DATA\"),X=\"FIVORA_PREVIEW_SITE_DATA_APPLIED\",nt=p(\"SITE_DATA_APPLIED\"),An=\"FIVORA_PREVIEW_CONTENT_PATCH\",En=p(\"CONTENT_PATCH\"),Sn=\"FIVORA_PREVIEW_STYLE_PATCH\",xn=\"DENEB_PREVIEW_STYLE_PATCH\",Tn=p(\"STYLE_PATCH\"),Cn=\"data-preview-style-target\",Ae=\"data-preview-style-type\",Ee=\"__FIVORA_STYLE_LIVE_CACHE__\",Se=\"fivora-template-color-replacements\",vn=[200],In=2500,Pn=1600,Rn=12e3,On=\"h1, h2, h3, h4, h5, h6, p, span, a, button, address, li, dt, dd, label, strong, em, small\";let Bt=[];const xe=new Map;let Te=0,Ut=!1,Et=null,Wt,Yt=[],rt=null,O=null,Ce=\"\",ve=\"\",Ie=\"\";function ut(){try{window.sessionStorage.removeItem(k)}catch{}}__name(ut,\"clearPendingFocus\");function jt(){try{return window.sessionStorage.getItem(Q)||window.sessionStorage.getItem(qt)}catch{return null}}__name(jt,\"readRememberedParentOrigin\");function zt(t){if(t)try{window.sessionStorage.setItem(Q,t)}catch{}}__name(zt,\"rememberParentOrigin\");function Pe(){for(const t of Yt)window.clearTimeout(t);Yt=[]}__name(Pe,\"clearSiteDataRelayTimers\");function Re(){const t=new Set;at&&t.add(at),t.add(window.location.origin);const e=jt();e&&t.add(e);try{if(document.referrer){const n=new URL(document.referrer).origin;n&&n!==\"null\"&&t.add(n)}}catch{}try{const n=window.location.ancestorOrigins?.item(0);n&&t.add(n)}catch{}return Array.from(t)}__name(Re,\"collectSiteDataRelayOrigins\");function St(t,e){const n=Re(),r=e?.fanOut?n:n.slice(0,1);for(const i of r)for(const o of[S,F])try{window.dispatchEvent(new MessageEvent(\"message\",{data:{type:o,siteData:t,__fivoraBridgeRelay:!0},origin:i,source:window.parent}))}catch{}}__name(St,\"relaySiteDataToTemplateRuntime\");function xt(t,e){O=t;try{window[f]=t,window[_]=t}catch{}const n=__name(()=>{rt=null;try{const r=JSON.stringify(O);window.sessionStorage.setItem(wt,r),window.sessionStorage.setItem(At,r)}catch{}},\"writeSessionCache\");if(e?.immediate){rt!==null&&(window.clearTimeout(rt),rt=null),n();return}rt!==null&&window.clearTimeout(rt),rt=window.setTimeout(n,In)}__name(xt,\"persistSiteData\");function Oe(t){const e=t&&typeof t==\"object\"&&!Array.isArray(t)?t:null,n=e?.requirements&&typeof e.requirements==\"object\"&&!Array.isArray(e.requirements)?e.requirements:null,r=e?.template&&typeof e.template==\"object\"&&!Array.isArray(e.template)?e.template:null,i=r?.structure&&typeof r.structure==\"object\"&&!Array.isArray(r.structure)?r.structure:null;try{return JSON.stringify({requiredPages:n?.requiredPages??null,pages:i?.pages??null,pageDefinitions:r?.pageDefinitions??i?.pageDefinitions??null})}catch{return String(Date.now())}}__name(Oe,\"pagesSignature\");let it=null,ot=null;function Me(t){const e=[];for(const n of t.matchAll(/([^.[\\]]+)|\\[(\\d+)\\]/g))n[2]!==void 0?e.push(Number(n[2])):n[1]&&e.push(n[1]);return e}__name(Me,\"parseFieldPath\");function Le(t,e,n){if(e.length===0)return t;const r=__name((i,o)=>{const a=e[o],c=o===e.length-1,u=c?void 0:e[o+1];if(typeof a==\"number\"){const w=(Array.isArray(i)?i:[]).slice();if(c)return w[a]=n,w;const D=w[a];return w[a]=D==null||typeof D!=\"object\"?r(typeof u==\"number\"?[]:{},o+1):r(D,o+1),w}const d={...i&&typeof i==\"object\"&&!Array.isArray(i)?i:{}};if(c)return d[a]=n,d;const b=d[a];return d[a]=b==null||typeof b!=\"object\"?r(typeof u==\"number\"?[]:{},o+1):r(b,o+1),d},\"setAt\");return r(t,0)}__name(Le,\"setValueAtPath\");function $e(){return(O&&typeof O==\"object\"&&!Array.isArray(O)?O:{}).content??{}}__name($e,\"readPublishedContent\");function Kt(t){const n={...O&&typeof O==\"object\"&&!Array.isArray(O)?O:{},content:t};O=n;try{window[f]=n,window[_]=n}catch{}return n}__name(Kt,\"writePublishedContent\");function Jt(){it!==null&&window.clearTimeout(it),it=window.setTimeout(()=>{it=null,O!=null&&St(O,{fanOut:!1})},Pn)}__name(Jt,\"scheduleContentOnlyRelay\");function Xt(){ot!==null&&window.clearTimeout(ot),ot=window.setTimeout(()=>{if(ot=null,O==null)return;const t=window;if(typeof t.requestIdleCallback==\"function\"){t.requestIdleCallback(()=>{O!=null&&xt(O,{immediate:!0})},{timeout:4e3});return}xt(O,{immediate:!0})},Rn)}__name(Xt,\"scheduleContentOnlyPersist\");function Zt(t,e){const n=Array.from(document.querySelectorAll(`[data-preview-field-path=\"${CSS.escape(t)}\"], [${m}=\"${CSS.escape(t)}\"]`));for(const r of n){if(K?.target===r)continue;if(r.tagName===\"IMG\"){typeof e==\"string\"&&e.trim()&&r.setAttribute(\"src\",e);continue}if(typeof e!=\"string\"&&typeof e!=\"number\"&&typeof e!=\"boolean\")continue;const i=(r.getAttribute(\"data-fivora-value-prefix\")??\"\")+String(e)+(r.getAttribute(\"data-fivora-value-suffix\")??\"\");if(r.childElementCount===0)r.textContent=i;else{const o=Array.from(r.childNodes).find(a=>a.nodeType===Node.TEXT_NODE&&a.textContent?.trim());o?o.textContent=i:r.textContent=i}B&&(i.trim().length===0?r.setAttribute(h,\"true\"):r.removeAttribute(h))}}__name(Zt,\"applyDomFieldValue\");function ke(t){if(!Array.isArray(t)||t.length===0)return;let e=$e();for(const n of t){if(!n||typeof n.path!=\"string\"||!n.path.trim())continue;const r=Me(n.path);r.length!==0&&(e=Le(e,r,n.value),Zt(n.path,n.value))}Kt(e),Jt(),Xt()}__name(ke,\"publishContentPatches\");const Mn={none:\"none\",sm:\"0 1px 2px 0 rgba(0, 0, 0, 0.05)\",md:\"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)\",lg:\"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)\",xl:\"0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)\",\"2xl\":\"0 25px 50px -12px rgba(0, 0, 0, 0.25)\"};function I(t){if(t==null||t===\"\")return;if(typeof t==\"number\")return`${t}px`;const e=String(t);return/^\\d+$/.test(e)?`${e}px`:e}__name(I,\"formatStyleUnit\");function Tt(t,e){const n={},r=t.marginTop??t.spacingTop,i=t.marginBottom??t.spacingBottom,o=t.marginLeft??t.spacingLeft,a=t.marginRight??t.spacingRight,c=I(r),u=I(i),g=I(o),d=I(a);return c&&(n[`${e}-margin-top`]=c),u&&(n[`${e}-margin-bottom`]=u),g&&(n[`${e}-margin-left`]=g),d&&(n[`${e}-margin-right`]=d),n}__name(Tt,\"styleMarginVars\");function Fe(t,e){const n={};if(t===\"text\"){Object.assign(n,Tt(e,\"--deneb\")),e.fontFamily&&(n[\"--deneb-font-family\"]=String(e.fontFamily));const r=I(e.fontSize);return r&&(n[\"--deneb-font-size\"]=r),e.fontWeight!==void 0&&(n[\"--deneb-font-weight\"]=String(e.fontWeight)),e.lineHeight!==void 0&&(n[\"--deneb-line-height\"]=String(e.lineHeight)),e.letterSpacing&&(n[\"--deneb-letter-spacing\"]=String(e.letterSpacing)),e.color&&(n[\"--deneb-color\"]=String(e.color)),e.textAlign&&(n[\"--deneb-text-align\"]=String(e.textAlign)),e.textTransform&&(n[\"--deneb-text-transform\"]=String(e.textTransform)),n}if(t===\"card\"){Object.assign(n,Tt(e,\"--deneb-card\"));const r=I(e.width);r&&(n[\"--deneb-card-width\"]=r);const i=I(e.minWidth);i&&(n[\"--deneb-card-min-width\"]=i);const o=I(e.maxWidth);o&&(n[\"--deneb-card-max-width\"]=o);const a=I(e.height);a&&(n[\"--deneb-card-height\"]=a),e.aspectRatio&&(n[\"--deneb-card-aspect-ratio\"]=String(e.aspectRatio));const c=I(e.paddingTop);c&&(n[\"--deneb-card-pt\"]=c);const u=I(e.paddingBottom);u&&(n[\"--deneb-card-pb\"]=u);const g=I(e.paddingLeft);g&&(n[\"--deneb-card-pl\"]=g);const d=I(e.paddingRight);d&&(n[\"--deneb-card-pr\"]=d);const b=I(e.borderRadius);b&&(n[\"--deneb-card-radius\"]=b);const y=I(e.borderWidth);if(y&&(n[\"--deneb-card-border-w\"]=y),e.borderStyle&&(n[\"--deneb-card-border-s\"]=String(e.borderStyle)),e.borderColor&&(n[\"--deneb-card-border-c\"]=String(e.borderColor)),e.backgroundColor&&(n[\"--deneb-card-bg\"]=String(e.backgroundColor)),e.boxShadow){const D=String(e.boxShadow);n[\"--deneb-card-shadow\"]=Mn[D]??D}const w=I(e.backdropBlur);return w&&(n[\"--deneb-card-blur\"]=w),n}if(t===\"button\"){Object.assign(n,Tt(e,\"--deneb-btn\"));const r=I(e.borderRadius);r&&(n[\"--deneb-btn-radius\"]=r);const i=I(e.paddingX);i&&(n[\"--deneb-btn-px\"]=i);const o=I(e.paddingY);return o&&(n[\"--deneb-btn-py\"]=o),e.backgroundColor&&(n[\"--deneb-btn-bg\"]=String(e.backgroundColor)),e.textColor&&(n[\"--deneb-btn-color\"]=String(e.textColor)),e.borderColor&&(n[\"--deneb-btn-border-c\"]=String(e.borderColor)),e.hoverBackgroundColor&&(n[\"--deneb-btn-hover-bg\"]=String(e.hoverBackgroundColor)),e.hoverTextColor&&(n[\"--deneb-btn-hover-color\"]=String(e.hoverTextColor)),n}if(t===\"grid\"){e.columns!==void 0&&(n[\"--deneb-grid-cols\"]=String(e.columns)),e.minCardWidth&&(n[\"--deneb-grid-min-card\"]=String(e.minCardWidth));const r=I(e.gapX);r&&(n[\"--deneb-grid-gap-x\"]=r);const i=I(e.gapY);return i&&(n[\"--deneb-grid-gap-y\"]=i),e.equalHeight!==void 0&&(n[\"--deneb-grid-equal-height\"]=e.equalHeight?\"stretch\":\"start\"),n}if(t===\"section\"){const r=I(e.paddingTop);r&&(n[\"--deneb-section-pt\"]=r);const i=I(e.paddingBottom);i&&(n[\"--deneb-section-pb\"]=i);const o=I(e.paddingX);return o&&(n[\"--deneb-section-px\"]=o),e.maxWidth&&(n[\"--deneb-section-max-w\"]=String(e.maxWidth)),e.backgroundColor&&(n[\"--deneb-section-bg\"]=String(e.backgroundColor)),e.backgroundImage&&(n[\"--deneb-section-bg-image\"]=String(e.backgroundImage)),n}return n}__name(Fe,\"styleToCssVariables\");function De(){const t=window,e=t[Ee];if(e&&typeof e==\"object\"&&!Array.isArray(e))return e;const n={};return t[Ee]=n,n}__name(De,\"readStyleLiveCache\");function Ne(t,e){const n=[`[${Cn}=\"${CSS.escape(t)}\"]`,`[data-preview-field-path=\"${CSS.escape(t)}\"]`,`[${$}=\"${CSS.escape(t)}\"]`];if(e===\"card\"&&t.endsWith(\".card\")){const r=t.slice(0,-5);n.push(`[${$}=\"${CSS.escape(r)}\"]`)}for(const r of n){const i=document.querySelector(r);if(i)return i}return null}__name(Ne,\"findStyleTargetElement\");function Ve(t){const e=typeof t.targetPath==\"string\"?t.targetPath.trim():\"\";if(!e)return;const n=typeof t.styleType==\"string\"?t.styleType:\"text\",r=t.properties&&typeof t.properties==\"object\"?t.properties:{},i=Ne(e,n);if(!i)return;const o=De(),c={...o[e]??{},...r};o[e]=c;const u=Fe(n,c);for(const[g,d]of Object.entries(u))d?i.style.setProperty(g,d):i.style.removeProperty(g);i.getAttribute(Ae)||i.setAttribute(Ae,n)}__name(Ve,\"applyStylePatch\");function He(t){Kt(t),Jt(),Xt()}__name(He,\"publishContentOnly\");function Ct(t,e){if(e?.contentOnly){const n=t&&typeof t==\"object\"&&!Array.isArray(t)?t:null;He(n?.content??t);return}if(it!==null&&(window.clearTimeout(it),it=null),ot!==null&&(window.clearTimeout(ot),ot=null),Ut){Et=t,Wt=e;return}Ut=!0;try{if(xt(t,{immediate:e?.persistImmediate}),Qt(t),vt(t,{colorReplacements:e?.colorReplacements===!0}),St(t,{fanOut:e?.fanOut===!0}),e?.scheduleRelays!==!1){Pe();for(const n of vn)Yt.push(window.setTimeout(()=>{O!=null&&St(O,{fanOut:!0})},n))}}finally{if(Ut=!1,Et!=null){const n=Et,r=Wt;Et=null,Wt=void 0,window.setTimeout(()=>{Ct(n,r)},0)}}}__name(Ct,\"publishSiteData\");function Ge(t){const e=t?.full!==!1,n=\"ontouchstart\"in window||navigator.maxTouchPoints>0||navigator.hardwareConcurrency!=null&&navigator.hardwareConcurrency<=4;window.requestAnimationFrame(()=>{window.requestAnimationFrame(()=>{try{q({type:X,full:e}),q({type:nt,full:e})}catch{}const r=O;if(r==null)return;const i=__name(()=>vt(r,{colorReplacements:!0}),\"run\");if(!n){window.setTimeout(i,0);return}const o=window.requestIdleCallback;typeof o==\"function\"?o(i,{timeout:4e3}):window.setTimeout(i,1200)})})}__name(Ge,\"acknowledgeSiteDataApplied\");const Ln=(()=>{try{return window.location.ancestorOrigins?.item(0)??null}catch{return null}})(),$n=(()=>{try{return window.parent!==window?window.parent.location.origin:null}catch{return null}})();let at=M({currentOrigin:window.location.origin,referrer:document.referrer,rememberedOrigin:jt(),ancestorOrigin:Ln,accessibleParentOrigin:$n});zt(at);function qe(t){if(t.source!==window.parent)return!1;if(at)return t.origin===at;try{const e=new URL(t.origin).origin;return e===\"null\"?!1:(at=e,zt(e),!0)}catch{return!1}}__name(qe,\"isTrustedParentMessage\");function q(t){window.parent.postMessage(t,at??\"*\")}__name(q,\"postToParent\");function dt(t,e,n=0){t.requestId&&(q({type:C,requestId:t.requestId,result:e,fieldPath:t.fieldPath??null,pageRoute:t.pageRoute??null,occurrences:n}),q({type:v,requestId:t.requestId,result:e,fieldPath:t.fieldPath??null,pageRoute:t.pageRoute??null,occurrences:n}))}__name(dt,\"postFocusResult\");function gt(){try{q({type:V,pathname:window.location.pathname}),q({type:j,pathname:window.location.pathname})}catch{}}__name(gt,\"announceReady\");async function Be(t){const e=++Te,r=(t&&typeof t==\"object\"&&!Array.isArray(t)?t:null)?.colorReplacements,i=document.getElementById(Se);if(!r||typeof r!=\"object\"||Array.isArray(r)||Object.keys(r).length===0){i?.remove();return}const o=Array.from(document.querySelectorAll('link[rel=\"stylesheet\"][href]')),a=await Promise.all(o.map(async g=>{const d=g.href;let b=xe.get(d);if(b===void 0){const w=await fetch(d,{credentials:\"same-origin\"});if(!w.ok)return\"\";b=await w.text(),xe.set(d,b)}const y=x(b,r);return y===b?\"\":y}));if(e!==Te)return;const c=a.filter(Boolean).join(`\n`);if(!c){i?.remove();return}const u=i instanceof HTMLStyleElement?i:document.createElement(\"style\");u.id=Se,u.textContent=c,u.isConnected||document.head.appendChild(u)}__name(Be,\"applyTemplateColorReplacements\");function vt(t,e){const n=t&&typeof t==\"object\"&&!Array.isArray(t)?t:null,r=n?.template&&typeof n.template==\"object\"&&!Array.isArray(n.template)?n.template:null,o=(r?.structure&&typeof r.structure==\"object\"&&!Array.isArray(r.structure)?r.structure:null)?.theme,a=(()=>{try{return JSON.stringify(o??null)}catch{return String(Date.now())}})();if(a!==Ce){Ce=a;const u=L(o),g=document.getElementById(R);if(!u)g?.remove();else{const d=g instanceof HTMLStyleElement?g:document.createElement(\"style\");d.id=R,d.textContent=u,d.isConnected||document.head.appendChild(d)}}if(e?.colorReplacements){if(a===ve)return;ve=a,Be(o).catch(()=>{})}}__name(vt,\"applyUniversalTheme\");function Qt(t){const e=Oe(t);e!==Ie&&(Ie=e,s(t,document),window.setTimeout(()=>s(t,document),300))}__name(Qt,\"applySelectedPages\");function E(t){return String(t??\"\").trim().replace(/\\s+/g,\" \").toLowerCase()}__name(E,\"normalizeText\");function It(t){const e=String(t??\"\").trim();if(!e)return[];const n=e.split(/[,;|\\n\\r]+/).map(r=>E(r)).filter(r=>r.length>=3);return Array.from(new Set([E(e),...n])).filter(r=>r.length>=2)}__name(It,\"valueFragments\");function Pt(t,e){const n=E(e),r=E(t);return/image|photo|logo|banner|thumbnail|cover/.test(n)||/^(https?:|data:|blob:|\\/)/.test(r)}__name(Pt,\"isImageValue\");function Ue(t){const e=new Set,n=t.getAttribute(\"src\")||\"\";n&&e.add(n),\"src\"in t&&t.src&&e.add(t.src),\"currentSrc\"in t&&t.currentSrc&&e.add(t.currentSrc);const r=t.getAttribute(\"srcset\");r&&r.split(\",\").forEach(i=>{const o=i.trim().split(/\\s+/)[0];o&&e.add(o)});for(const i of[\"data-src\",\"data-original\",\"data-fallback\",\"data-nimg\",\"data-image\",\"data-url\"]){const o=t.getAttribute(i);o&&o!==\"1\"&&e.add(o)}if(t.style.backgroundImage){const i=t.style.backgroundImage.match(/url\\([\"']?([^\"']+)[\"']?\\)/i);i?.[1]&&e.add(i[1])}for(const i of Array.from(e))try{const a=new URL(i,window.location.href).searchParams.get(\"url\");if(a){e.add(a);try{e.add(decodeURIComponent(a))}catch{}}}catch{}return Array.from(e).filter(Boolean)}__name(Ue,\"extractImageCandidates\");function te(t,e){const n=String(e??\"\").trim();if(!n)return!1;const r=Ue(t);if(r.length===0)return!1;const o=n.split(\"?\")[0].replace(/\\\\/g,\"/\").split(\"/\").pop()?.toLowerCase();for(const a of r){if(a===n)return!0;try{if(new URL(a,window.location.href).href===new URL(n,window.location.href).href)return!0}catch{}if(a.includes(n)||n.includes(a))return!0;try{const g=decodeURIComponent(a);if(g.includes(n)||n.includes(g))return!0}catch{}const u=a.split(\"?\")[0].replace(/\\\\/g,\"/\").split(\"/\").pop()?.toLowerCase();if(u&&o&&u.length>=3&&u===o)return!0}return!1}__name(te,\"imageMatchesValue\");function ee(t,e){return Array.from(t.querySelectorAll(\"img\")).filter(n=>te(n,e))}__name(ee,\"findImageMatches\");function Rt(t,e){const n=String(e??\"\").trim();return n?[t.getAttribute(\"href\"),t.getAttribute(\"src\"),t.getAttribute(\"poster\"),t.getAttribute(\"srcset\"),t.style.backgroundImage].filter(i=>!!i).some(i=>{if(i===n||i.includes(n))return!0;try{return new URL(i,window.location.href).href===new URL(n,window.location.href).href}catch{return!1}}):!1}__name(Rt,\"attributeMatchesValue\");function Ot(t,e){return Array.from(t.querySelectorAll('a[href], img[src], source[src], video[poster], [style*=\"background-image\"]')).filter(n=>Rt(n,e))}__name(Ot,\"findAttributeMatches\");function We(t,e){const n=It(e);if(n.length===0)return[];const r=Array.from(t.querySelectorAll(On)),i=r.filter(o=>{const a=E(o.textContent);return n.some(c=>a===c)});return i.length>0?i:r.filter(o=>{const a=E(o.textContent);return n.some(c=>a.includes(c)||c.includes(a))})}__name(We,\"findTextMatches\");function Mt(t,e,n){if(Pt(e,n)){const r=ee(t,e);if(r.length>0)return r}return We(t,e)}__name(Mt,\"findValueMatches\");function Ye(t,e,n){if(Pt(e,n)&&ee(t,e).length>0)return!0;const r=E(t.textContent);return It(e).some(i=>r.includes(i))}__name(Ye,\"subtreeContainsValue\");function je(t,e){const n=t[0];if(!n)return null;let r=n;for(;r;){if(t.every(i=>r?.contains(i)))return r;if(r===e)break;r=r.parentElement}return e??n}__name(je,\"lowestCommonAncestor\");function st(t){const e=String(t??\"\").trim();if(!e)return[];const n=e.replace(/\\[(\\d+)\\]/g,\".$1\"),r=n.replace(/\\.(\\d+)(?=\\.|$)/g,\"[$1]\");return Array.from(new Set([e,n,r]))}__name(st,\"pathVariants\");function ne(t){return Array.from(new Set([t.fieldPath,...t.fieldPaths??[]].filter(e=>!!(e&&e.trim())).flatMap(e=>st(e))))}__name(ne,\"focusPathCandidates\");function pt(t){if(t.closest(\"[hidden]\"))return!1;let e=t;for(;e&&e!==document.documentElement;){const r=window.getComputedStyle(e);if(r.display===\"none\"||r.visibility===\"hidden\"||Number(r.opacity)===0||r.maxHeight===\"0px\"||r.maxHeight===\"0\")return!1;const i=e.getBoundingClientRect();if((r.overflow===\"hidden\"||r.overflow===\"clip\")&&(i.width<2||i.height<2))return!1;e=e.parentElement}const n=t.getBoundingClientRect();return n.width>=2&&n.height>=2}__name(pt,\"isVisuallyHighlightable\");function re(t){let e=0;pt(t)&&(e+=100);const n=E(t.textContent);n.length>=2&&(e+=40),t.tagName===\"IMG\"&&(e+=35),t.closest(\"main, footer, header, [data-preview-page-key]\")&&(e+=20),t.closest('.fixed, [class*=\"fixed\"]')&&n.length<2&&t.tagName!==\"IMG\"&&(e-=25);const r=t.getBoundingClientRect();return e+=Math.min(15,Math.floor(r.width*r.height/400)),e}__name(re,\"highlightTargetScore\");function ie(t){return[...t].sort((e,n)=>re(n)-re(e))}__name(ie,\"rankHighlightTargets\");function ze(t,e){const n=[],r=Array.from(new Set([t,...e??[]].filter(a=>!!a).flatMap(a=>st(a))));for(const a of r){const c=CSS.escape(a);document.querySelectorAll('[data-preview-field-path=\"'+c+'\"], [data-preview-list-path=\"'+c+'\"], [data-content-path=\"'+c+'\"]').forEach(u=>{n.includes(u)||n.push(u)})}const i=ie(n.filter(a=>pt(a))),o=i.filter(a=>!i.some(c=>c!==a&&a.contains(c)));return o.length>0?o:i}__name(ze,\"findExplicitTargets\");function oe(t){const e=(t?.itemValues??[]).filter(o=>E(o.value).length>=2&&o.key!==\"id\");if(e.length===0)return null;const n=[];for(const o of e)for(const a of Mt(document,o.value,o.key).slice(0,8))n.includes(a)||n.push(a);let r=null;for(const o of n){let a=o,c=0;for(;a&&a!==document.body&&c<12;){const u=e.reduce((b,y)=>b+(Ye(a,y.value,y.key)?1:0),0),g=a.getBoundingClientRect(),d=Math.max(1,g.width*g.height);(!r||u>r.score||u===r.score&&d<r.area)&&(r={target:a,score:u,area:d}),a=a.parentElement,c+=1}}const i=Math.min(2,e.length);return r&&r.score>=i?r.target:null}__name(oe,\"findItemContainer\");function Lt(t,e,n){const r=Mt(t,e,n);if(r.length===0)return null;const i=It(e);if(i.length>1&&!Pt(e,n)){const o=r.filter(a=>{const c=E(a.textContent);return i.slice(1).some(u=>c===u)});if(o.length>1)return je(o,t instanceof HTMLElement?t:null)}return r.sort((o,a)=>E(o.textContent).length-E(a.textContent).length)[0]}__name(Lt,\"findFieldTarget\");function $t(t,e){const n=String(t??e??\"\").trim().toLowerCase().replace(/\\s+/g,\"_\");return!n||n===\"common\"?\"home\":n===\"about\"?\"about_us\":n}__name($t,\"normalizePageKey\");function Ke(t){const e=t.replace(/_us$/,\"\"),n=['[data-preview-page-key=\"'+CSS.escape(t)+'\"]','[data-preview-page-key=\"'+CSS.escape(e)+'\"]',\"#\"+CSS.escape(t)+\"_view\",\"#\"+CSS.escape(e)+\"_view\",\"#\"+CSS.escape(t),\"#\"+CSS.escape(e),\"main\",\"body\"];for(const r of n){const i=document.querySelector(r);if(i instanceof HTMLElement)return i}return null}__name(Ke,\"findPageTarget\");function ae(t,e){const n=window.location.pathname.match(/^(\\/uploads\\/generated-sites\\/(?:template-preview|preview|live)\\/[^/]+)/),r=String(e??\"\").trim(),i=r?\"/\"+r.replace(/^\\/+|\\/+$/g,\"\"):null,o=i!==null?i===\"/\"?\"\":i:t===\"home\"?\"\":\"/\"+t.replace(/^\\/+/,\"\");return n?n[1]+o:o||\"/\"}__name(ae,\"resolvePath\");function se(){for(const t of Bt)t.target.style.outline=t.outline,t.target.style.outlineOffset=t.outlineOffset,t.target.style.boxShadow=t.boxShadow,t.target.style.transition=t.transition,t.target.style.scrollMarginTop=t.scrollMarginTop,t.target.style.borderRadius=t.borderRadius,t.target.removeAttribute(G);Bt=[]}__name(se,\"clearHighlight\");function kt(t,e){se(),Bt=t.map(n=>({target:n,outline:n.style.outline,outlineOffset:n.style.outlineOffset,boxShadow:n.style.boxShadow,transition:n.style.transition,scrollMarginTop:n.style.scrollMarginTop,borderRadius:n.style.borderRadius}));for(const n of t)n.setAttribute(G,\"true\"),n.style.scrollMarginTop=\"72px\",n.style.transition=\"outline-color 0.2s ease, box-shadow 0.2s ease\",n.style.outline=\"2px solid rgba(34, 197, 94, 0.98)\",n.style.outlineOffset=\"4px\",n.style.boxShadow=\"0 0 0 7px rgba(34, 197, 94, 0.2)\",n.style.borderRadius||(n.style.borderRadius=\"4px\");t[0]?.scrollIntoView({behavior:\"smooth\",block:e?\"start\":\"center\",inline:\"nearest\"})}__name(kt,\"highlightTargets\");function Je(t,e){kt([t],e)}__name(Je,\"highlight\");function Ft(t){return Array.from(new Set([t.fieldValue,...t.fieldMatchValues??[]].filter(e=>typeof e==\"boolean\"||typeof e==\"number\"||typeof e==\"string\"&&e.trim().length>0).map(e=>String(e))))}__name(Ft,\"focusMatchValues\");function Xe(t){const e=ne(t);if(e.length===0)return null;try{const n=JSON.parse(window.sessionStorage.getItem(z)??\"{}\");for(const r of e){const i=n[`${window.location.pathname}|${r}`];if(!i)continue;const o=document.querySelector(i);if(!o)continue;const a=Ft(t).map(E),c=E(o.textContent);if(!(a.length>0&&c&&!a.some(u=>c===u||c.includes(u)||Rt(o,u))))return o}return null}catch{return null}}__name(Xe,\"findRememberedFocusTarget\");function ht(t){if(!t)return null;if(pt(t))return t;let e=t.parentElement;for(;e&&e!==document.body;){if(pt(e))return e;e=e.parentElement}return null}__name(ht,\"pickVisibleHeuristicTarget\");function ce(t){const e=ne(t),n=ze(t.fieldPath,e.filter(a=>a!==t.fieldPath));if(n.length>0)return{targets:n,result:\"exact\"};const r=ht(Xe(t));if(r)return{targets:[r],result:\"heuristic\"};const i=oe(t.fieldContext),o=t.fieldContext?.fieldKey;if(i){for(const c of Ft(t)){const u=ht(Ot(i,c)[0]??Lt(i,c,o));if(u)return{targets:[u],result:\"heuristic\"}}const a=ht(i);if(a)return{targets:[a],result:\"heuristic\"}}for(const a of Ft(t)){const c=Ot(document,a),u=Lt(document,a,o),g=u?[...c,u]:c,d=ie(g.map(b=>ht(b)).filter(b=>!!b));if(d.length>0)return{targets:[d[0]],result:\"heuristic\"}}return null}__name(ce,\"resolveFieldTarget\");function le(){document.documentElement.dataset.fivoraPreview=\"true\",document.querySelectorAll(\".reveal-on-scroll:not(.reveal-active)\").forEach(t=>t.classList.add(\"reveal-active\"))}__name(le,\"activateRevealNodes\");function ct(t,e=0){le();const n=!!t.fieldPath;if(t.focusOnly&&n){const a=ce(t);if(a){kt(a.targets,!1),dt(t,a.result,a.targets.length);return}if(e<12){window.setTimeout(()=>ct(t,e+1),120);return}dt(t,\"missing\");return}const r=$t(t.pageKey,t.pageLabel),i=Ke(r);if(!i){e<12?window.setTimeout(()=>ct(t,e+1),120):dt(t,\"missing\");return}const o=n?ce(t):null;if(n&&!o&&e<12){window.setTimeout(()=>ct(t,e+1),120);return}o?(kt(o.targets,!1),dt(t,o.result,o.targets.length)):(Je(i,!0),dt(t,\"page\",1))}__name(ct,\"applyFocus\");function Ze(t){if(t.focusOnly){ut(),window.setTimeout(()=>ct(t),80);return}const e=$t(t.pageKey,t.pageLabel),n=ae(e,t.pageRoute);if((window.location.pathname.replace(/\\/+$/,\"\")||\"/\")!==n){try{window.sessionStorage.setItem(k,JSON.stringify({...t,awaitingNavigation:!0}))}catch{}window.location.assign(n);return}ut(),window.setTimeout(()=>ct(t),80)}__name(Ze,\"handleFocus\");function ue(t){return E(t).replace(/\\.html$/i,\"\").replace(/[^a-z0-9]+/g,\"-\")}__name(ue,\"normalizeRouteToken\");function Qe(){const t=window.location.pathname.split(\"/\").map(o=>decodeURIComponent(o).trim()).filter(Boolean);if(t.length<2||H.length===0)return;const e=H.filter(o=>{const a=o.context;if(!a?.collectionPath||!a.fieldKey)return!1;const c=a.collectionPath.split(\".\").at(-1)??\"\",u=t.lastIndexOf(c);if(u<0||u>=t.length-1)return!1;const g=ue(t.at(-1)??\"\");return a.itemValues.some(({key:d,value:b})=>{const y=E(d).replace(/[^a-z0-9]/g,\"\");return y!==\"id\"&&!y.endsWith(\"id\")&&y!==\"slug\"&&y!==\"name\"&&y!==\"title\"?!1:ue(b)===g})});if(e.length===0)return;const n=Array.from(document.querySelectorAll(`[${W}]`)),r=[];for(const o of e){const a=o.context,c=a.fieldKey,u=E(c).replace(/[^a-z0-9]/g,\"\");if(u===\"slug\"||u===\"identifier\"||u.endsWith(\"id\"))continue;const g=a.collectionPath.split(\".\").at(-1)??\"\",d=E(g).replace(/s$/,\"\"),b=c.replace(/([a-z0-9])([A-Z])/g,\"$1 $2\").split(/[^a-z0-9]+/i).map(E).filter(w=>w&&![\"url\",\"text\",\"value\"].includes(w)),y=E(o.value);for(const w of n){const D=E(w.getAttribute(W));if(!D||!D.includes(d))continue;let J=0;const _n=b.filter(Zn=>D.includes(Zn));_n.length>0&&(J+=40+_n.length*5);const wn=w.tagName===\"IMG\"?E(w.getAttribute(\"src\")??w.getAttribute(\"alt\")):E(w.textContent);y&&wn===y?J+=120:y.length>=3&&wn.includes(y)&&(J+=80),/image|photo|logo|banner|thumbnail|cover/i.test(c)&&w.tagName===\"IMG\"&&D.includes(\"image\")&&(J+=120),J>=40&&r.push({element:w,field:o,score:J})}}r.sort((o,a)=>a.score-o.score);const i=new Set;for(const{element:o,field:a}of r)if(!i.has(o)){if(i.add(o),o.tagName!==\"IMG\"){const c=o.textContent??\"\",u=String(a.value??\"\"),g=c.toLowerCase().indexOf(u.toLowerCase());u&&g>=0&&c!==u&&(o.setAttribute(\"data-fivora-value-prefix\",c.slice(0,g)),o.setAttribute(\"data-fivora-value-suffix\",c.slice(g+u.length)))}o.removeAttribute(W),o.setAttribute(\"data-preview-field-path\",a.path),Zt(a.path,a.value)}}__name(Qe,\"promoteActiveRouteDetailFields\");const kn=\"FIVORA_PREVIEW_ELEMENT_CLICKED\",Fn=p(\"ELEMENT_CLICKED\"),Dn=\"FIVORA_PREVIEW_FIELD_CHANGED\",Nn=p(\"FIELD_CHANGED\"),Vn=\"FIVORA_PREVIEW_EDIT_MODE\",Hn=p(\"EDIT_MODE\"),Gn=\"FIVORA_PREVIEW_FLUSH_EDIT\",qn=p(\"FLUSH_EDIT\"),Bn=\"FIVORA_PREVIEW_EDIT_FLUSHED\",Un=p(\"EDIT_FLUSHED\"),Wn=\"h1, h2, h3, h4, h5, h6, p, span, a, button, address, li, dt, dd, label, strong, em, small, img\",Dt=\"ontouchstart\"in window||navigator.maxTouchPoints>0||window.matchMedia&&window.matchMedia(\"(pointer: coarse)\").matches,Qn=(()=>{const t=navigator.userAgent||\"\",e=navigator.vendor||\"\";if(/iP(ad|hone|od)/i.test(t)||/Safari/i.test(t)&&/Apple Computer/i.test(e)&&!/Chrom(e|ium)/i.test(t))return!0;try{return!!window.safari}catch{return!1}})(),Yn=(()=>{try{const t=document.createElement(\"div\");return t.setAttribute(\"contenteditable\",\"plaintext-only\"),t.contentEditable===\"plaintext-only\"}catch{return!1}})(),jn=Dt||navigator.hardwareConcurrency!=null&&navigator.hardwareConcurrency<=4||typeof navigator.deviceMemory==\"number\"&&(navigator.deviceMemory??8)<=4,zn=!0;let H=[];window.addEventListener(\"message\",t=>{if(!qe(t)||t.data&&typeof t.data==\"object\"&&t.data.__fivoraBridgeRelay===!0)return;if(t.data?.type===U||t.data?.type===T){t.stopImmediatePropagation(),Ze(t.data);return}if((t.data?.type===S||t.data?.type===F)&&t.data.siteData){const c=t.data.full!==!1;if(t.data.contentOnly===!0){Ct(t.data.siteData,{contentOnly:!0});return}Ct(t.data.siteData,{fanOut:!1,colorReplacements:!1}),Ge({full:c});return}if(t.data?.type===An||t.data?.type===En){const c=t.data.patches;Array.isArray(c)&&ke(c);return}if(t.data?.type===Sn||t.data?.type===xn||t.data?.type===Tn){Ve(t.data);return}if(t.data?.type===Vn||t.data?.type===Hn){H=Array.isArray(t.data.fields)?t.data.fields:[],Qe(),t.data.editMode?(pn(),window.setTimeout(()=>me(),50)):hn();return}(t.data?.type===Gn||t.data?.type===qn)&&(lt(!0),q({type:Bn,requestId:t.data.requestId}),q({type:Un,requestId:t.data.requestId}))},!0);try{const t=JSON.parse(window.sessionStorage.getItem(k)??\"null\");if(t?.awaitingNavigation){const e=$t(t.pageKey,t.pageLabel),n=ae(e,t.pageRoute),r=window.location.pathname.replace(/\\/+$/,\"\")||\"/\";ut(),r===n&&window.setTimeout(()=>ct(t),220)}else t&&ut()}catch{ut()}try{const t=JSON.parse(window.sessionStorage.getItem(wt)??window.sessionStorage.getItem(At)??\"null\");if(t){O=t;try{window[f]=t,window[_]=t}catch{}jn||(Qt(t),vt(t,{colorReplacements:!1}))}}catch{}let B=!1,Y=null,tt=null,Nt=null,K=null,bt=[],et=null;function de(){if(document.querySelector(\"[data-fivora-empty-editable-styles]\"))return;const t=document.createElement(\"style\");t.setAttribute(\"data-fivora-empty-editable-styles\",\"true\"),t.textContent=`\n [${h}=\"true\"] {\n min-width: 7rem !important;\n min-height: 1.25em !important;\n outline: 1px dashed rgba(37, 99, 235, 0.28) !important;\n outline-offset: 3px !important;\n }\n span[${h}=\"true\"],\n a[${h}=\"true\"],\n strong[${h}=\"true\"],\n em[${h}=\"true\"],\n small[${h}=\"true\"],\n label[${h}=\"true\"] {\n display: inline-block !important;\n }\n [${h}=\"true\"]:empty::before {\n content: \"\";\n color: rgba(37, 99, 235, 0.78);\n font: 500 12px/1.4 system-ui, sans-serif;\n letter-spacing: normal;\n text-transform: none;\n white-space: nowrap;\n }\n [${h}=\"true\"]:empty:hover::before {\n content: \"Click to add text\";\n }\n [${A}=\"true\"] {\n min-width: 10rem !important;\n min-height: 3.5rem !important;\n outline: 1px dashed rgba(37, 99, 235, 0.28) !important;\n outline-offset: 3px !important;\n }\n [${A}=\"true\"]:empty::before {\n content: \"\";\n display: inline-flex;\n align-items: center;\n min-height: 3.5rem;\n color: rgba(37, 99, 235, 0.78);\n font: 500 12px/1.4 system-ui, sans-serif;\n letter-spacing: normal;\n text-transform: none;\n white-space: nowrap;\n }\n [${A}=\"true\"]:empty:hover::before {\n content: \"Click to add the first item\";\n }\n `,document.head.appendChild(t)}__name(de,\"ensureEmptyEditableStyles\");function tn(t){if(t.id)return\"#\"+CSS.escape(t.id);const e=[];let n=t;for(;n&&n!==document.body;){const r=n.tagName.toLowerCase(),i=n.parentElement?Array.from(n.parentElement.children).filter(a=>a.tagName===n?.tagName):[],o=i.indexOf(n)+1;e.unshift(i.length>1?`${r}:nth-of-type(${o})`:r),n=n.parentElement}return e.length>0?`body > ${e.join(\" > \")}`:\"\"}__name(tn,\"buildStructuralSelector\");function Vt(){try{const t=JSON.parse(window.sessionStorage.getItem(z)??\"{}\");return t&&typeof t==\"object\"?t:{}}catch{return{}}}__name(Vt,\"readResolvedTargetSelectors\");function en(t,e){const n=tn(t);if(!n)return;const r=Vt();r[`${window.location.pathname}|${e}`]=n;try{window.sessionStorage.setItem(z,JSON.stringify(r))}catch{}}__name(en,\"rememberResolvedTarget\");function Kn(){const t=Vt(),e=`${window.location.pathname}|`;let n=!1;for(const r of Object.keys(t))r.startsWith(e)&&(delete t[r],n=!0);if(n)try{window.sessionStorage.setItem(z,JSON.stringify(t))}catch{}}__name(Kn,\"forgetResolvedTargetsForCurrentPage\");function fe(){document.querySelectorAll(`[${m}]`).forEach(t=>{K?.target!==t&&(t.removeAttribute(m),t.removeAttribute(h),t.removeAttribute(A))})}__name(fe,\"clearResolvedEditableTargets\");function ft(t,e,n=!0){const r=t.getAttribute(m),i=t.getAttribute(\"data-preview-field-path\")??t.getAttribute(N)??t.getAttribute(\"data-content-path\")??t.getAttribute(\"data-field-path\");if(r&&r!==e.path&&i!==e.path)return!1;t.setAttribute(m,e.path);const o=String(e.value??\"\").trim().length===0&&E(t.textContent).length===0;B&&o&&t.tagName!==\"IMG\"?t.setAttribute(h,\"true\"):t.removeAttribute(h);const a=e.kind===\"collection\"||e.type===\"list\",c=e.collection?.length;return B&&a&&(c===0||t.childElementCount===0)?(t.setAttribute(A,\"true\"),t.removeAttribute(h)):t.removeAttribute(A),n&&!a&&en(t,e.path),!0}__name(ft,\"annotateEditableTarget\");function Z(t){const e=[t.value,...t.matchValues??[]].filter(n=>typeof n==\"number\"||typeof n==\"string\"&&n.trim().length>0);return Array.from(new Set(e.map(n=>String(n))))}__name(Z,\"editableFieldMatchValues\");function nn(t){for(const e of st(t)){const n=CSS.escape(e),r=document.querySelector(`[data-preview-field-path=\"${n}\"], [${N}=\"${n}\"], [data-content-path=\"${n}\"], [data-field-path=\"${n}\"], [${m}=\"${n}\"]`);if(r)return r}return null}__name(nn,\"findExplicitEditableTarget\");function rn(t){if(t.kind===\"collection\"||t.type===\"list\")return null;const n=Vt()[`${window.location.pathname}|${t.path}`];if(!n)return null;try{const r=document.querySelector(n);if(!r)return null;const i=Z(t).map(E),o=E(r.textContent);return i.length>0&&o&&!i.includes(o)?null:(ft(r,t,!1),r)}catch{return null}}__name(rn,\"restoreRememberedTarget\");function on(t){if(t.kind===\"collection\"||t.type===\"list\")return null;const n=(t.context?oe({collectionPath:t.context.collectionPath,itemIndex:t.context.itemIndex,fieldKey:t.context.fieldKey,itemValues:t.context.itemValues}):null)??document;for(const r of Z(t)){const i=Lt(n,r,t.context?.fieldKey),o=[...Ot(n,r),...i?[i]:[],...Mt(n,r,t.context?.fieldKey)];for(const a of o){if(a.closest(`[${W}]`))continue;const c=a.getAttribute(m);if(!c||c===t.path)return a}}return null}__name(on,\"inferEditableTarget\");function an(t){if(B){de(),le();for(const e of H){const n=nn(e.path)??rn(e)??(t?.explicitOnly?null:on(e));n&&ft(n,e)}}}__name(an,\"indexEditableTargets\");let Ht=!1;function me(){for(const e of bt)window.clearTimeout(e);if(bt=[],et!==null){const e=window.cancelIdleCallback;typeof e==\"function\"?e(et):window.clearTimeout(et),et=null}if(Ht)return;Ht=!0;const t=__name((e,n)=>{n&&(Ht=!1),e&&fe(),an({explicitOnly:e})},\"runPass\");bt=[window.setTimeout(()=>{t(!0,!0)},0)]}__name(me,\"scheduleEditableTargetIndex\");function sn(){const t=document.createElement(\"div\");return t.setAttribute(\"data-fivora-edit-badge\",\"true\"),t.innerHTML=\"\\u270F\\uFE0F\",Object.assign(t.style,{position:\"fixed\",zIndex:\"2147483647\",width:\"28px\",height:\"28px\",display:\"flex\",alignItems:\"center\",justifyContent:\"center\",fontSize:\"14px\",borderRadius:\"8px\",background:\"rgba(37, 99, 235, 0.92)\",color:\"#fff\",cursor:\"pointer\",pointerEvents:\"auto\",boxShadow:\"0 2px 8px rgba(0,0,0,0.18)\",opacity:\"0\",transition:\"opacity 0.15s ease\",userSelect:\"none\"}),t.setAttribute(\"title\",\"Edit this content\"),t.setAttribute(\"aria-label\",\"Edit this content\"),document.body.appendChild(t),t}__name(sn,\"createHoverBadge\");function cn(t){if(!Y)return;const e=t.getBoundingClientRect();t.tagName===\"IMG\"||t.querySelector(\"img\")!==null||t.classList.contains(\"animated-shoe\")||t.closest(\".animated-shoe\")!==null||/image/i.test(t.getAttribute(\"data-preview-field-path\")??\"\")||/image/i.test(t.getAttribute(\"data-content-path\")??\"\")||/image/i.test(t.getAttribute(\"data-field-path\")??\"\")||/image/i.test(t.getAttribute(m)??\"\")?(Y.style.top=`${Math.max(4,Math.min(window.innerHeight-36,e.bottom-40))}px`,Y.style.left=`${Math.max(4,e.left+16)}px`):(Y.style.top=`${Math.max(4,e.top-4)}px`,Y.style.left=`${Math.min(window.innerWidth-36,e.right-32)}px`),Y.style.opacity=\"1\"}__name(cn,\"positionBadge\");function yt(){Nt&&(Nt(),Nt=null),Y&&(Y.style.opacity=\"0\"),tt=null}__name(yt,\"clearHoverOverlay\");function ln(t){if(t===tt)return;yt(),tt=t;const e=t.style.outline,n=t.style.outlineOffset,r=t.style.cursor;t.style.outline=\"2px dashed rgba(37, 99, 235, 0.6)\",t.style.outlineOffset=\"2px\",t.style.cursor=\"pointer\",Nt=__name(()=>{t.style.outline=e,t.style.outlineOffset=n,t.style.cursor=r},\"hoverOutlineCleanup\"),cn(t)}__name(ln,\"applyHoverOverlay\");function ge(t){let e=t instanceof Element?t:null;for(;e&&!(e instanceof HTMLElement);)e=e.parentElement;let n=e;for(;n&&n!==document.body;){if(n.hasAttribute(W)){n=n.parentElement;continue}if(n.hasAttribute(\"data-preview-field-path\")||n.hasAttribute(N)||n.hasAttribute($)||n.hasAttribute(\"data-content-path\")||n.hasAttribute(\"data-field-path\")||n.hasAttribute(m)||n.matches(Wn)){const i=Gt(n);if(i)return{element:n,field:i}}n=n.parentElement}return null}__name(ge,\"findEditableTarget\");function Gt(t){if(t.closest(`[${W}]`))return null;const e=t.getAttribute(\"data-preview-field-path\")??t.getAttribute(\"data-content-path\")??t.getAttribute(\"data-field-path\")??t.getAttribute(m);if(e)return H.find(d=>st(d.path).includes(e))??{path:e,label:e.split(\".\").pop()??\"Content\",type:t.tagName===\"IMG\"?\"image\":\"text\",value:t.tagName===\"IMG\"?t.src:t.textContent?.trim()??\"\"};const n=t.getAttribute($);if(n){const g=n.match(/^(.+)\\[(\\d+)\\]$/);if(g){const d=g[1],b=Number(g[2]),y=H.find(w=>(w.kind===\"collection\"||w.type===\"list\")&&st(w.path).includes(d));if(y)return{...y,collection:{listPath:d,itemIndex:b,length:y.collection?.length??0,minItems:y.collection?.minItems,maxItems:y.collection?.maxItems,itemLabel:y.collection?.itemLabel}}}}const r=t.getAttribute(N);if(r)return H.find(d=>(d.kind===\"collection\"||d.type===\"list\")&&st(d.path).includes(r))??{kind:\"collection\",path:r,label:r.split(\".\").pop()??\"Collection\",type:\"list\",value:0,collection:{listPath:r,length:t.children.length}};const i=t.tagName===\"IMG\"?t:t.querySelector(\"img\");if(i){const g=H.find(y=>y.type===\"image\"&&Z(y).some(w=>te(i,w)));if(g)return g;const d=pe(i);if(d.collectionPath&&typeof d.itemIndex==\"number\"){const y=H.find(w=>w.type===\"image\"&&w.context?.collectionPath===d.collectionPath&&w.context?.itemIndex===d.itemIndex);if(y)return y}const b=i.closest('section, article, [data-preview-page-key], main, header, footer, .card, [class*=\"section\"]');if(b){const y=b.getAttribute(\"data-preview-field-path\")||b.getAttribute(\"data-content-path\")||b.getAttribute(\"data-field-path\")||b.getAttribute(m);if(y){const w=y.split(\".\")[0],D=H.find(J=>J.type===\"image\"&&(J.path.startsWith(`${w}.`)||J.path.startsWith(`${y}.`)));if(D)return D}}if(t.tagName===\"IMG\"){const y=H.filter(D=>D.type===\"image\");if(y.length===1)return y[0];const w=i.getAttribute(\"src\")||i.src||\"\";return{path:e||\"image\",label:(e||\"\").split(\".\").pop()||\"Image\",type:\"image\",value:w}}}const o=H.filter(g=>Z(g).some(d=>Rt(t,d)));if(o.length===1)return o[0];const a=E(t.textContent);if(!a)return null;const c=H.filter(g=>typeof g.value!=\"boolean\"&&Z(g).some(d=>E(d)===a));if(c.length===1)return c[0];const u=H.filter(g=>typeof g.value==\"boolean\"?!1:Z(g).some(d=>{const b=E(d);return b.length>=3&&a.includes(b)})).sort((g,d)=>Math.max(...Z(d).map(b=>E(b).length),0)-Math.max(...Z(g).map(b=>E(b).length),0));return u.length===1?u[0]:null}__name(Gt,\"resolveEditableField\");function un(t,e){return t.tagName!==\"IMG\"&&t.childElementCount===0&&![\"INPUT\",\"TEXTAREA\",\"SELECT\",\"OPTION\",\"VIDEO\",\"AUDIO\",\"IFRAME\"].includes(t.tagName)&&!e.context&&![\"image\",\"color\",\"boolean\",\"select\",\"list\"].includes(e.type??\"text\")}__name(un,\"canEditInline\");function dn(t){let e=t;for(;e&&e!==document.body;){const n=e.getAttribute(\"data-preview-field-path\")??e.getAttribute(N)??e.getAttribute(\"data-content-path\")??e.getAttribute(\"data-field-path\")??e.getAttribute(m);if(n)return n;e=e.parentElement}return null}__name(dn,\"extractFieldPath\");function pe(t){let e=t;for(;e&&e!==document.body;){const n=e.getAttribute($);if(n){const o=n.match(/^(.+)\\[(\\d+)\\]$/);if(o)return{collectionPath:o[1],itemIndex:Number(o[2])}}const r=e.getAttribute(\"data-preview-field-path\")??e.getAttribute(\"data-content-path\")??e.getAttribute(\"data-field-path\")??e.getAttribute(m);if(r){const o=r.match(/^(.+)\\[(\\d+)\\]/);if(o)return{collectionPath:o[1],itemIndex:Number(o[2])}}const i=e.getAttribute(N);if(i)return{collectionPath:i,itemIndex:null};e=e.parentElement}return{collectionPath:null,itemIndex:null}}__name(pe,\"extractCollectionContext\");function he(t,e){const n=[],r=new Set(e?.path?[e.path]:[]);let i=t,o=0;for(;i&&i!==document.body&&o<3&&!(i.hasAttribute(W)||o>0&&(i.hasAttribute($)||i.hasAttribute(N)||i.tagName===\"SECTION\"));){if(i.hasAttribute(\"data-preview-field-path\")||i.hasAttribute(\"data-content-path\")||i.hasAttribute(\"data-field-path\")||i.hasAttribute(m)){const a=Gt(i);a?.path&&a.kind!==\"collection\"&&a.type!==\"list\"&&!r.has(a.path)&&(r.add(a.path),n.push({path:a.path,label:a.label??a.path.split(\".\").pop()??\"Content\",type:a.type??\"text\"}))}i=i.parentElement,o+=1}return n}__name(he,\"findRelatedAncestorFields\");function fn(t,e,n=he(t,e)){const r=t.getBoundingClientRect(),i=t.tagName===\"IMG\",o=e?.path??dn(t),a=i?t.src:t.textContent?.trim()??\"\",c=pe(t);let u=e?.collection?.listPath??e?.collection?.path??e?.context?.collectionPath??c.collectionPath,g=e?.collection?.itemIndex??e?.context?.itemIndex??c.itemIndex;u&&o&&e?.kind!==\"collection\"&&!o.startsWith(`${u}[`)&&!o.startsWith(`${u}.`)&&o!==u&&(u=null,g=null);const d=e?.context?.itemPath??(u&&typeof g==\"number\"?`${u}[${g}]`:null),b={type:kn,fieldPath:o,descriptorKind:e?.kind??\"field\",fieldValue:a,elementTag:t.tagName.toLowerCase(),isImage:i,boundingRect:{top:r.top,left:r.left,width:r.width,height:r.height},listPath:u,itemPath:d,collectionPath:u,itemIndex:g,relatedFields:n};q(b),q({...b,type:Fn})}__name(fn,\"emitClickEvent\");function mn(t,e){q({type:Dn,fieldPath:t,value:e}),q({type:Nn,fieldPath:t,value:e})}__name(mn,\"emitFieldChange\");function lt(t){const e=K;if(!e)return;K=null,e.target.removeEventListener(\"keydown\",e.keydown),e.target.removeEventListener(\"blur\",e.blur);const n=t?(e.target.innerText??e.target.textContent??\"\").replace(/\\u00a0/g,\" \").trim():\"\";e.contentEditable===null?e.target.removeAttribute(\"contenteditable\"):e.target.setAttribute(\"contenteditable\",e.contentEditable),e.spellcheck===null?e.target.removeAttribute(\"spellcheck\"):e.target.setAttribute(\"spellcheck\",e.spellcheck),e.target.style.outline=e.outline,e.target.style.outlineOffset=e.outlineOffset,e.target.style.cursor=e.cursor,e.target.style.userSelect=e.userSelect,e.target.style.textTransform=e.textTransform,e.target.innerHTML=e.originalHtml,t&&(n!==e.originalText.trim()?(e.field.value=n,ft(e.target,e.field),mn(e.field.path,n)):n||ft(e.target,e.field))}__name(lt,\"finishInlineEdit\");function gn(t,e,n){if(K?.target===t)return;lt(!0),yt(),ft(t,e),t.removeAttribute(h);const r=typeof e.value==\"string\"||typeof e.value==\"number\"?String(e.value):t.textContent??\"\",i=t.innerHTML,o=__name(c=>{if(c.key===\"Escape\"){c.preventDefault(),lt(!1);return}c.key===\"Enter\"&&e.type!==\"textarea\"&&!c.shiftKey&&(c.preventDefault(),lt(!0))},\"keydown\"),a=__name(()=>lt(!0),\"blur\");if(K={target:t,field:e,originalText:r,originalHtml:i,contentEditable:t.getAttribute(\"contenteditable\"),spellcheck:t.getAttribute(\"spellcheck\"),outline:t.style.outline,outlineOffset:t.style.outlineOffset,cursor:t.style.cursor,userSelect:t.style.userSelect,textTransform:t.style.textTransform,keydown:o,blur:a},t.setAttribute(\"contenteditable\",Yn?\"plaintext-only\":\"true\"),t.setAttribute(\"spellcheck\",\"true\"),t.textContent=r,t.style.outline=\"2px solid rgba(37, 99, 235, 0.95)\",t.style.outlineOffset=\"3px\",t.style.cursor=\"text\",t.style.userSelect=\"text\",t.style.textTransform=\"none\",t.addEventListener(\"keydown\",o),t.addEventListener(\"blur\",a),t.focus(),n){const c=document,u=c.caretPositionFromPoint?.(n.x,n.y),g=u?(()=>{const d=document.createRange();return d.setStart(u.offsetNode,u.offset),d.collapse(!0),d})():c.caretRangeFromPoint?.(n.x,n.y);if(g){const d=window.getSelection();d?.removeAllRanges(),d?.addRange(g)}}else{const c=document.createRange();c.selectNodeContents(t);const u=window.getSelection();u?.removeAllRanges(),u?.addRange(c)}}__name(gn,\"beginInlineEdit\");let mt=null;function be(t){if(!B||K||Dt||mt!==null)return;const e=t.target;mt=requestAnimationFrame(()=>{if(mt=null,!B||K)return;const n=ge(e);n&&!n.element.hasAttribute(\"data-fivora-edit-badge\")&&ln(n.element)})}__name(be,\"onEditMouseOver\");function ye(t){if(!B)return;const e=t.relatedTarget instanceof HTMLElement?t.relatedTarget:null;e&&(e===Y||e===tt||tt?.contains(e))||yt()}__name(ye,\"onEditMouseOut\");function _e(t){if(!B||K&&t.target instanceof Node&&K.target.contains(t.target))return;const e=t.target instanceof HTMLElement&&t.target.hasAttribute(\"data-fivora-edit-badge\")?t.target:null,n=e?tt?{element:tt,field:Gt(tt)}:null:ge(t.target),r=n?.element,i=n?.field;if(!r||!i)return;t.preventDefault(),t.stopPropagation();const o=he(r,i);!zn&&un(r,i)&&o.length===0?gn(r,i,e?void 0:{x:t.clientX,y:t.clientY}):fn(r,i,o)}__name(_e,\"onEditClick\");function pn(){B||(B=!0,se(),de(),!Dt&&!Y&&(Y=sn()),Dt||(document.addEventListener(\"mouseover\",be,!0),document.addEventListener(\"mouseout\",ye,!0)),document.addEventListener(\"click\",_e,!0),document.addEventListener(\"submit\",we,!0),me())}__name(pn,\"enterEditMode\");function we(t){B&&(t.preventDefault(),t.stopPropagation())}__name(we,\"preventEditModeSubmit\");function hn(){if(B){B=!1,Ht=!1,lt(!0),yt(),mt!==null&&(cancelAnimationFrame(mt),mt=null);for(const t of bt)window.clearTimeout(t);if(bt=[],et!==null){const t=window.cancelIdleCallback;typeof t==\"function\"?t(et):window.clearTimeout(et),et=null}fe(),document.querySelectorAll(`[${h}], [${A}]`).forEach(t=>{t.removeAttribute(h),t.removeAttribute(A)}),document.removeEventListener(\"mouseover\",be,!0),document.removeEventListener(\"mouseout\",ye,!0),document.removeEventListener(\"click\",_e,!0),document.removeEventListener(\"submit\",we,!0)}}__name(hn,\"exitEditMode\");const Jn=window.history.pushState.bind(window.history),Xn=window.history.replaceState.bind(window.history);window.history.pushState=(...t)=>{Jn(...t),window.setTimeout(gt,0)},window.history.replaceState=(...t)=>{Xn(...t),window.setTimeout(gt,0)},window.addEventListener(\"popstate\",gt);function bn(){return window.location.pathname.match(/^(\\/uploads\\/generated-sites\\/(?:template-preview|[^/]+)\\/[^/]+)/)?.[1]??\"\"}__name(bn,\"resolvePreviewRootPrefix\");function yn(t){if(t.target&&t.target!==\"_self\"||t.hasAttribute(\"download\"))return!1;const e=t.getAttribute(\"href\");if(!e||e.startsWith(\"#\")||/^(mailto:|tel:|sms:|whatsapp:|javascript:)/i.test(e))return!1;let n;try{n=new URL(e,window.location.href)}catch{return!1}if(n.origin!==window.location.origin)return!1;const r=bn();if(r&&!n.pathname.startsWith(r))return!1;const i=window.location.pathname.replace(/\\/+$/,\"\")||\"/\",o=n.pathname.replace(/\\/+$/,\"\")||\"/\";return i!==o||n.search!==window.location.search}__name(yn,\"isInternalPreviewNavigation\"),document.addEventListener(\"click\",t=>{if(t.defaultPrevented||t.button!==0||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey)return;const e=t.target?.closest?.(\"a[href]\");!e||!yn(e)||(t.preventDefault(),t.stopPropagation(),window.location.assign(e.href))},!0),gt()})(function(M){const L=__name((P,U)=>{if(!P||P.trim()===\"null\")return null;try{const T=new URL(P,U??void 0).origin;return T===\"null\"?null:T}catch{return null}},\"normalizeOrigin\"),x=L(M.currentOrigin),R=L(M.ancestorOrigin,x),s=L(M.accessibleParentOrigin,x),l=L(M.referrer,x),p=L(M.rememberedOrigin);return R??s??(l&&l!==x?l:null)??p??l},function(M){const L=__name(m=>!!m&&typeof m==\"object\"&&!Array.isArray(m),\"isRecord\");if(!L(M)||M.designCustomizationVersion!==1)return\"\";const x=M,R=__name(m=>{if(typeof m!=\"string\")return\"\";const h=m.trim();return!h||h.length>160||/[;{}<>\\r\\n]/.test(h)||/(?:url\\s*\\(|expression\\s*\\(|@import|javascript:)/i.test(h)?\"\":h},\"safeValue\"),s=__name(m=>R(x[m]),\"read\"),l=__name((m,h)=>h?`${m}:${h} !important;`:\"\",\"declaration\"),p=__name((m,h)=>{const A=h.filter(Boolean).join(\"\");return A?`${m}{${A}}`:\"\"},\"rule\"),P=__name(m=>m?[l(\"background\",m),l(\"background-color\",m),\"background-image:none !important;\"]:[],\"backgroundDeclarations\"),U=__name(m=>m===\"start\"?\"flex-start\":m===\"end\"?\"flex-end\":m===\"center\"||m===\"stretch\"?m:\"\",\"alignItems\"),T=__name(m=>{const h=Number(m);return Number.isInteger(h)&&h>=1&&h<=6?`repeat(${h},minmax(0,1fr))`:\"\"},\"gridColumns\"),C=(()=>{const m=Number(s(\"headingScale\"));return Number.isFinite(m)&&m>=.75&&m<=2?String(m):\"\"})(),v=__name(m=>({none:\"none\",subtle:\"0 4px 14px rgba(15,23,42,.08)\",medium:\"0 12px 30px rgba(15,23,42,.14)\",strong:\"0 22px 55px rgba(15,23,42,.22)\"})[m]??\"\",\"shadow\"),V=[[\"--brand-color\",s(\"primaryColor\")],[\"--brand-primary\",s(\"primaryColor\")],[\"--primary-color\",s(\"primaryColor\")],[\"--color-primary\",s(\"primaryColor\")],[\"--brand-secondary\",s(\"secondaryColor\")],[\"--secondary-color\",s(\"secondaryColor\")],[\"--brand-accent\",s(\"accentColor\")],[\"--accent-color\",s(\"accentColor\")],[\"--page-background\",s(\"backgroundColor\")],[\"--page-text\",s(\"textColor\")],[\"--surface-color\",s(\"surfaceColor\")],[\"--surface-alt-color\",s(\"surfaceAltColor\")],[\"--heading-color\",s(\"headingColor\")],[\"--muted-text-color\",s(\"mutedTextColor\")],[\"--border-color\",s(\"borderColor\")],[\"--card-background\",s(\"cardBackgroundColor\")],[\"--hero-min-height\",s(\"heroMinHeight\")],[\"--section-padding\",s(\"sectionPadding\")],[\"--content-max-width\",s(\"contentMaxWidth\")],[\"--container-padding\",s(\"containerPadding\")],[\"--section-gap\",s(\"sectionGap\")],[\"--element-gap\",s(\"elementGap\")],[\"--grid-gap\",s(\"gridGap\")],[\"--card-radius\",s(\"cardRadius\")],[\"--button-radius\",s(\"buttonRadius\")],[\"--image-radius\",s(\"imageRadius\")]],j=[p(\":root,body\",V.map(([m,h])=>l(m,h))),p(\"html\",[l(\"font-size\",s(\"baseSize\"))]),p(\"body\",[l(\"font-family\",s(\"bodyFont\")?`${s(\"bodyFont\")},sans-serif`:\"\"),l(\"font-weight\",s(\"bodyWeight\")),l(\"line-height\",s(\"bodyLineHeight\")),l(\"letter-spacing\",s(\"letterSpacing\")),...P(s(\"backgroundColor\")),l(\"color\",s(\"textColor\"))]),p(\"body :where(h1,h2,h3,h4,h5,h6)\",[l(\"font-family\",s(\"headingFont\")?`${s(\"headingFont\")},sans-serif`:\"\"),l(\"font-weight\",s(\"headingWeight\")),l(\"line-height\",s(\"headingLineHeight\")),l(\"color\",s(\"headingColor\"))]),p('body :where(p,small,.muted,[class*=\"muted\"])',[l(\"color\",s(\"mutedTextColor\"))]),C?`body h1{font-size:calc(2.5rem * ${C}) !important}body h2{font-size:calc(2rem * ${C}) !important}body h3{font-size:calc(1.5rem * ${C}) !important}body h4{font-size:calc(1.25rem * ${C}) !important}`:\"\",p(\"body header\",[...P(s(\"headerBackgroundColor\")),l(\"min-height\",s(\"headerHeight\"))]),p(\"body footer\",[...P(s(\"footerBackgroundColor\"))]),p(\"body main\",[...P(s(\"backgroundColor\")),l(\"color\",s(\"textColor\"))]),p(\"body main > section,body main [data-preview-page-key] > section\",[l(\"padding-block\",s(\"sectionPadding\")),l(\"text-align\",s(\"textAlign\"))]),p(\"body main :where(section,[data-design-section]) :where(h1,h2,h3,h4,h5,h6,p,[data-design-text])\",[l(\"text-align\",s(\"textAlign\"))]),p(\"body main > section + section,body main [data-preview-page-key] > section + section\",[l(\"margin-top\",s(\"sectionGap\"))]),p('body main :where([class*=\"flex\"],[class*=\"grid\"],[data-design-stack])',[l(\"gap\",s(\"elementGap\"))]),p(\"body main > section:nth-of-type(even),body main [data-preview-page-key] > section:nth-of-type(even)\",P(s(\"surfaceAltColor\"))),p(\"body main > section:nth-of-type(odd),body main [data-preview-page-key] > section:nth-of-type(odd)\",P(s(\"surfaceColor\"))),p(\"body main > section:first-of-type,body main [data-preview-page-key] > section:first-of-type\",[l(\"min-height\",s(\"heroMinHeight\")),l(\"text-align\",s(\"heroTextAlign\"))]),p('body main > section:first-of-type :where(h1,h2,h3,h4,h5,h6,p,[class*=\"container\"],[data-design-text]),body main [data-preview-page-key] > section:first-of-type :where(h1,h2,h3,h4,h5,h6,p,[class*=\"container\"],[data-design-text])',[l(\"text-align\",s(\"heroTextAlign\"))]),p('body main :where([class*=\"container\"],[class~=\"container\"],[data-design-container])',[l(\"max-width\",s(\"contentMaxWidth\")),l(\"padding-inline\",s(\"containerPadding\")),s(\"contentMaxWidth\")?\"margin-inline:auto !important;\":\"\"]),p('body main :where(section,[data-design-section]) > :where([class*=\"flex\"],[data-design-content])',[l(\"align-items\",U(s(\"contentAlign\"))),l(\"justify-items\",s(\"contentAlign\"))]),p(\"body main :where([data-preview-list-path],[data-design-grid])\",[T(s(\"gridColumns\"))?\"display:grid !important;\":\"\",l(\"grid-template-columns\",T(s(\"gridColumns\"))),l(\"gap\",s(\"gridGap\"))]),p('body main :where([data-preview-item-path],[data-design-card],.card,[class*=\"card-\"])',[l(\"width\",s(\"cardWidth\")),s(\"cardWidth\")?\"max-width:100% !important;\":\"\",l(\"min-height\",s(\"cardMinHeight\")),l(\"padding\",s(\"cardPadding\")),l(\"border-radius\",s(\"cardRadius\")),l(\"border-width\",s(\"cardBorderWidth\")),s(\"cardBorderWidth\")?\"border-style:solid !important;\":\"\",l(\"border-color\",s(\"borderColor\")),...P(s(\"cardBackgroundColor\")),l(\"box-shadow\",v(s(\"cardShadow\"))),l(\"text-align\",s(\"cardTextAlign\"))]),p('body main :where([data-preview-item-path],[data-design-card],.card,[class*=\"card-\"]) :where(h1,h2,h3,h4,h5,h6,p,span,[data-design-text])',[l(\"text-align\",s(\"cardTextAlign\"))]),p('body main :where(button,a[class*=\"btn\"],a[class*=\"button\"],[data-design-button])',[l(\"padding\",s(\"buttonPadding\")),l(\"border-radius\",s(\"buttonRadius\")),...P(s(\"buttonBackgroundColor\")),l(\"color\",s(\"buttonTextColor\")),l(\"box-shadow\",v(s(\"buttonShadow\")))]),p(\"body main img\",[l(\"border-radius\",s(\"imageRadius\"))])],G=L(x.sections)?x.sections:{};for(const[m,h]of Object.entries(G)){if(!/^[a-zA-Z0-9_-]{1,64}$/.test(m)||!L(h))continue;const A=__name(z=>R(h[z]),\"sectionRead\"),N=A(\"backgroundColor\"),$=['[class*=\"absolute\"][class*=\"inset-0\"]','[class*=\"fixed\"][class*=\"inset-0\"]','[class*=\"absolute\"][class*=\"inset-x-0\"][class*=\"inset-y-0\"]','[class*=\"absolute\"][class*=\"top-0\"][class*=\"right-0\"][class*=\"bottom-0\"][class*=\"left-0\"]'].join(\",\"),k={all:\"body main section\",hero:\"body main > section:first-of-type,body main [data-preview-page-key] > section:first-of-type\",header:\"body header\",footer:\"body footer\",cards:'body main :where([data-preview-item-path],[data-design-card],.card,[class*=\"card-\"])'}[m]??`body :where([data-preview-page-key=\"${m}\"] > section,[data-design-section=\"${m}\"],[data-section-id=\"${m}\"],section#${m},section.${m})`;j.push(p(k,[h.visible===!1?\"display:none !important;\":\"\",...P(N),l(\"color\",A(\"textColor\")),l(\"min-height\",A(\"minHeight\")),l(\"padding-block\",A(\"padding\")),l(\"max-width\",A(\"contentMaxWidth\")),l(\"gap\",A(\"gap\")),l(\"text-align\",A(\"textAlign\")),l(\"align-items\",U(A(\"contentAlign\")))]),p(`${k} :where(h1,h2,h3,h4,h5,h6)`,[l(\"color\",A(\"headingColor\")),l(\"text-align\",A(\"textAlign\"))]),p(`${k} :where(p,span,[data-design-text])`,[l(\"text-align\",A(\"textAlign\"))]),p(`${k} :where([data-preview-item-path],[data-design-card],.card,[class*=\"card-\"])`,[...P(A(\"cardBackgroundColor\")),l(\"width\",A(\"cardWidth\")),A(\"cardWidth\")?\"max-width:100% !important;\":\"\",l(\"min-height\",A(\"cardMinHeight\")),l(\"border-radius\",A(\"cardRadius\"))]),p(`${k} :where([data-preview-list-path],[data-design-grid])`,[T(A(\"gridColumns\"))?\"display:grid !important;\":\"\",l(\"grid-template-columns\",T(A(\"gridColumns\")))]),p(`${k}::before,${k}::after`,N?[\"background:none !important;\",\"background-image:none !important;\",\"opacity:0 !important;\"]:[]),p(`${k} > :where(${$})`,N?[\"background:none !important;\",\"background-image:none !important;\",\"box-shadow:none !important;\",\"mask-image:none !important;\",\"-webkit-mask-image:none !important;\"]:[]),p(`${k} > :where(${$})::before,${k} > :where(${$})::after`,N?[\"background:none !important;\",\"background-image:none !important;\",\"opacity:0 !important;\"]:[]),p(`${k} > :where(${$}) :where(img,video,canvas,picture)`,N?[\"opacity:0.2 !important;\"]:[]))}return j.filter(Boolean).join(`\n`)},function(M,L){if(!L||typeof L!=\"object\"||Array.isArray(L))return M;const x=__name(T=>{const C=T.trim().toLowerCase(),v=C.match(/^#([0-9a-f]{3})$/);return v?`#${[...v[1]].map(V=>V.repeat(2)).join(\"\")}`:/^#[0-9a-f]{6}$/.test(C)?C:null},\"normalize\"),R=new Map,s=new Map;for(const[T,C]of Object.entries(L).slice(0,64)){if(typeof C!=\"string\")continue;const v=x(T),V=x(C);if(!v||!V||v===V)continue;R.set(v,V);const j=__name(G=>[Number.parseInt(G.slice(1,3),16),Number.parseInt(G.slice(3,5),16),Number.parseInt(G.slice(5,7),16)],\"channels\");s.set(j(v).join(\",\"),j(V)),v[1]===v[2]&&v[3]===v[4]&&v[5]===v[6]&&R.set(`#${v[1]}${v[3]}${v[5]}`,V)}if(R.size===0)return M;const l=[...R.keys()].sort((T,C)=>C.length-T.length).map(T=>T.replace(/[.*+?^${}()|[\\]\\\\]/g,\"\\\\$&\")),p=new RegExp(`(?<!\\\\\\\\)(?:${l.join(\"|\")})(?![0-9a-f])`,\"gi\"),P=M.replace(p,T=>{const C=x(T);return C?R.get(C)??T:T}),U=/(rgba?\\(\\s*)(\\d{1,3})(\\s+|,\\s*)(\\d{1,3})(\\s+|,\\s*)(\\d{1,3})/gi;return P.replace(U,(T,C,v,V,j,G,m)=>{const h=s.get(`${v},${j},${m}`);return h?`${C}${h[0]}${V}${h[1]}${G}${h[2]}`:T})},\"fivora-universal-design-overrides\",function(M,L){const x=L??document,R=M&&typeof M==\"object\"&&!Array.isArray(M)?M:null,s=R?.requirements&&typeof R.requirements==\"object\"&&!Array.isArray(R.requirements)?R.requirements:null,l=R?.template&&typeof R.template==\"object\"&&!Array.isArray(R.template)?R.template:null,p=l?.structure&&typeof l.structure==\"object\"&&!Array.isArray(l.structure)?l.structure:null,P=Array.isArray(s?.requiredPages),U=Array.isArray(p?.pages);if(!P&&!U)return;const T=P?s?.requiredPages:p?.pages,C=new Set(T.filter(f=>typeof f==\"string\").map(f=>f.trim()).filter(Boolean)),v=Array.isArray(l?.pageDefinitions)?l.pageDefinitions:[],V=Array.isArray(p?.pageDefinitions)?p.pageDefinitions:[],G=(v.length>0?v:V).flatMap(f=>{if(!f||typeof f!=\"object\"||Array.isArray(f))return[];const _=f;if(typeof _.id!=\"string\"||!_.id.trim())return[];const S=_.id.trim(),F=typeof _.label==\"string\"&&_.label.trim()?_.label.trim():S.replace(/_/g,\" \"),X=typeof _.route==\"string\"?_.route.trim():\"\",nt=X===\"/\"?\"/\":`/${(X||S).replace(/^\\/+|\\/+$/g,\"\")}`;return[{id:S,label:F,route:nt}]}),h=(U?p?.pages:T).filter(f=>typeof f==\"string\").map(f=>f.trim()).filter(Boolean).map((f,_)=>({id:f,label:f.replace(/_/g,\" \"),route:_===0?\"/\":`/${f}`})),A=G.length>0?G:h;if(A.length===0)return;const N=A.filter(f=>!C.has(f.id));if(N.length===0){x.querySelectorAll(\"[data-fivora-page-disabled]\").forEach(f=>f.removeAttribute(\"data-fivora-page-disabled\"));return}let $=x.getElementById(\"fivora-page-selection-style\");(!$||$.tagName!==\"STYLE\")&&($=x.createElement(\"style\"),$.id=\"fivora-page-selection-style\",$.textContent='[data-fivora-page-disabled=\"true\"]{display:none!important}',x.head.appendChild($)),x.querySelectorAll(\"[data-fivora-page-disabled]\").forEach(f=>f.removeAttribute(\"data-fivora-page-disabled\"));const W=__name(f=>{let _=f;try{const X=new URL(f,x.baseURI);if(X.origin!==x.location?.origin)return\"\";_=X.pathname}catch{return\"\"}const S=_.match(/^(\\/uploads\\/generated-sites\\/(?:template-preview|preview|live)\\/[^/]+)/)?.[1];S&&_.startsWith(S)&&(_=_.slice(S.length)||\"/\"),_=_.replace(/\\/index\\.html$/i,\"/\").replace(/\\.html$/i,\"\");const F=_.replace(/\\/+$/g,\"\")||\"/\";return F.startsWith(\"/\")?F:`/${F}`},\"normalizePath\"),k=__name(f=>A.find(_=>{const S=W(_.route);return S?S===\"/\"?f===\"/\":f===S||f.startsWith(`${S}/`):!1}),\"pageForPath\"),z=__name(f=>{for(const _ of[\"href\",\"formaction\",\"data-href\",\"data-route\",\"data-url\"]){const S=f.getAttribute(_);if(!S)continue;const F=k(W(S));if(F)return F}},\"pageForControl\"),Q=__name(f=>{f&&f.setAttribute(\"data-fivora-page-disabled\",\"true\")},\"disable\");for(const f of N)for(const _ of[\"data-page-key\",\"data-required-page\",\"data-target-page\"])x.querySelectorAll(`[${_}]`).forEach(S=>{S.getAttribute(_)===f.id&&Q(S)});const qt=Array.from(x.querySelectorAll(\"a[href]\"));for(const f of qt){const _=z(f);if(!_||C.has(_.id))continue;if(f.classList.contains(\"absolute\")&&(f.classList.contains(\"inset-0\")||f.classList.contains(\"inset-x-0\")&&f.classList.contains(\"inset-y-0\")))Q(f.closest(\"[data-preview-item-path],[data-design-card],article,li\"));else{const F=f.closest(\"li\");Q(F&&F.querySelectorAll(\"a[href]\").length===1?F:f)}}const wt=Array.from(x.querySelectorAll('button,[role=\"button\"],[data-href],[data-route],[data-url]')).filter(f=>f.tagName!==\"A\");for(const f of wt){const _=z(f);if(!_||C.has(_.id))continue;const S=f.closest(\"li\");Q(S&&S.querySelectorAll('a[href],button,[role=\"button\"],[data-href],[data-route],[data-url]').length===1?S:f)}const At=x.querySelector(\"main section\");for(const f of x.querySelectorAll(\"main section\")){const _=Array.from(f.querySelectorAll('a[href],button,[role=\"button\"],[data-href],[data-route],[data-url]')),S=_.map(z).filter(nt=>!!nt),F=f.hasAttribute(\"data-preview-page-key\"),X=f===At||f.hasAttribute(\"data-design-hero\")||/(?:^|\\s)(?:hero|banner|masthead)(?:\\s|$)/i.test(f.className)||!!f.querySelector(\"h1\");!F&&!X&&S.length>0&&S.length===_.length&&S.every(nt=>!C.has(nt.id))&&Q(f)}});";
|