accessify-widget 0.3.74 → 0.3.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { d, i } from "./index-DCvvWewP.js";
1
+ import { d, i } from "./index-CJw0r5jG.js";
2
2
  export {
3
3
  d as destroy,
4
4
  i as init
@@ -1,4 +1,4 @@
1
- import { g as getCurrentWidgetLang } from "./index-DCvvWewP.js";
1
+ import { g as getCurrentWidgetLang } from "./index-CJw0r5jG.js";
2
2
  const IDB_NAME = "accessify-alt-text-cache";
3
3
  const IDB_STORE = "alt-texts";
4
4
  const IDB_VERSION = 2;
@@ -742,4 +742,4 @@ export {
742
742
  autoApplyCachedAltTexts,
743
743
  createAltTextModule as default
744
744
  };
745
- //# sourceMappingURL=alt-text-CoS2ISqs.js.map
745
+ //# sourceMappingURL=alt-text-BzVlRLRb.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"alt-text-CoS2ISqs.js","sources":["../src/features/alt-text.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Accessify – Bildbeschreibung (Image Description) Feature\n// ---------------------------------------------------------------------------\n//\n// A) AUTO-APPLY (runs on widget init, no feature activation needed):\n// Loads alt texts from server manifest + IndexedDB cache and silently\n// applies them to images (alt + title). Ensures all visitors get\n// alt texts immediately.\n//\n// B) GENERATE (when user activates the feature toggle):\n// Scans for images without alt text → generates via AI → injects\n// alt + title into DOM. Title attribute provides native hover tooltip\n// on every image, consistently.\n//\n// Framer compatibility:\n// - Uses currentSrc || src (srcset-aware)\n// - Treats empty alt=\"\" on large images as \"missing\" (Framer sets alt=\"\" on all)\n// - Delayed re-scans for lazy-loaded images\n// - MutationObserver for dynamically added images\n// ---------------------------------------------------------------------------\n\nimport type { FeatureModule, FeatureState, AIService } from '../types';\nimport { RateLimitError } from '../services/ai-service';\nimport { getCurrentWidgetLang } from '../i18n/index';\n\n// ---------------------------------------------------------------------------\n// IndexedDB cache\n// ---------------------------------------------------------------------------\n\nconst IDB_NAME = 'accessify-alt-text-cache';\nconst IDB_STORE = 'alt-texts';\nconst IDB_VERSION = 2;\n\ninterface CachedAltText {\n key: string; src: string; altText: string; lang: string; createdAt: number;\n}\n\nfunction hashSrc(src: string): string {\n let hash = 5381;\n const n = src.toLowerCase().trim();\n for (let i = 0; i < n.length; i++) { hash = ((hash << 5) + hash) + n.charCodeAt(i); hash |= 0; }\n return Math.abs(hash).toString(36);\n}\n\n/** Normalize image URL: strip query params for cache matching (Framer adds ?width=&height=) */\nfunction normalizeImageUrl(url: string): string {\n try {\n const u = new URL(url);\n u.searchParams.delete('width');\n u.searchParams.delete('height');\n u.searchParams.delete('scale-down-to');\n return u.href;\n } catch {\n return url;\n }\n}\n\n/** Get the best available src for an image (Framer srcset aware) */\nfunction getImageSrc(img: HTMLImageElement): string {\n return img.currentSrc || img.src;\n}\n\nfunction openCache(): Promise<IDBDatabase | null> {\n return new Promise((resolve) => {\n try {\n const req = indexedDB.open(IDB_NAME, IDB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(IDB_STORE)) db.createObjectStore(IDB_STORE, { keyPath: 'key' });\n if (!db.objectStoreNames.contains('alt-text-reports')) db.createObjectStore('alt-text-reports', { keyPath: 'key' });\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => resolve(null);\n } catch { resolve(null); }\n });\n}\n\nasync function getAllCachedAltTexts(): Promise<Map<string, string>> {\n const db = await openCache();\n const map = new Map<string, string>();\n if (!db) return map;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const req = tx.objectStore(IDB_STORE).getAll();\n req.onsuccess = () => {\n for (const r of req.result as CachedAltText[]) { map.set(r.src, r.altText); }\n resolve(map);\n };\n req.onerror = () => resolve(map);\n } catch { resolve(map); }\n });\n}\n\nasync function getCachedAltText(src: string): Promise<string | null> {\n const db = await openCache();\n if (!db) return null;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const store = tx.objectStore(IDB_STORE);\n const req1 = store.get(hashSrc(src));\n req1.onsuccess = () => {\n if ((req1.result as CachedAltText | undefined)?.altText) {\n resolve(req1.result.altText);\n return;\n }\n const norm = normalizeImageUrl(src);\n if (norm !== src) {\n const req2 = store.get(hashSrc(norm));\n req2.onsuccess = () => resolve((req2.result as CachedAltText | undefined)?.altText || null);\n req2.onerror = () => resolve(null);\n } else {\n resolve(null);\n }\n };\n req1.onerror = () => resolve(null);\n } catch { resolve(null); }\n });\n}\n\nasync function setCachedAltText(src: string, altText: string, langCode: string): Promise<void> {\n const db = await openCache();\n if (!db) return;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).put({ key: hashSrc(src), src, altText, lang: langCode, createdAt: Date.now() } as CachedAltText);\n tx.oncomplete = () => resolve();\n tx.onerror = () => resolve();\n } catch { resolve(); }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Server-side alt-text cache (cross-browser, cross-visitor)\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_API_BASE = 'https://accessify-api.accessify.workers.dev';\n\n// Module-wide mode tracking, set on every manifest fetch. 'manual' = default,\n// never run live AI for unknown images. 'auto' = live fallback + auto-persist OK.\ntype ResimplifyMode = 'manual' | 'auto';\nlet currentAltSiteMode: ResimplifyMode = 'manual';\n\nasync function fetchServerAltTexts(siteKey: string, proxyUrl: string, lang: string): Promise<Map<string, string>> {\n const map = new Map<string, string>();\n try {\n const base = proxyUrl || DEFAULT_API_BASE;\n const pageUrl = window.location.origin + window.location.pathname;\n const res = await fetch(`${base}/v1/manifest?siteKey=${encodeURIComponent(siteKey)}&url=${encodeURIComponent(pageUrl)}&feature=alt_text&variant=${encodeURIComponent(lang)}`, {\n headers: { 'Accept': 'application/json' },\n cache: 'no-cache',\n });\n if (!res.ok) return map;\n const data = await res.json() as { blocks?: Array<{ selector: string; result: string }>; siteMode?: ResimplifyMode };\n // Update authoritative mode from server on every fetch\n currentAltSiteMode = data.siteMode === 'auto' ? 'auto' : 'manual';\n if (data.blocks) {\n for (const block of data.blocks) {\n if (block.selector && block.result) map.set(block.selector, block.result);\n }\n }\n } catch { /* fall back to IndexedDB */ }\n return map;\n}\n\nfunction persistAltTextToServer(siteKey: string, proxyUrl: string, imageUrl: string, altText: string, lang: string): void {\n try {\n const base = proxyUrl || DEFAULT_API_BASE;\n const pageUrl = window.location.origin + window.location.pathname;\n fetch(`${base}/v1/cache/persist-alt-text`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ siteKey, pageUrl, imageUrl, altText, lang }),\n }).catch(() => {});\n } catch { /* fire-and-forget */ }\n}\n\n// ---------------------------------------------------------------------------\n// Auto-apply: runs on widget init, no feature activation needed\n// ---------------------------------------------------------------------------\n\nlet autoApplied = false;\n\n/** Silently apply cached/manifest alt texts to all images on the page */\nexport async function autoApplyCachedAltTexts(\n widgetConfig?: { siteKey?: string; proxyUrl?: string; lang?: string },\n): Promise<number> {\n if (autoApplied) return 0;\n autoApplied = true;\n\n const cache = new Map<string, string>();\n const siteKey = widgetConfig?.siteKey;\n const proxyUrl = widgetConfig?.proxyUrl || '';\n const pageLang = widgetConfig?.lang?.split('-')[0] || document.documentElement.lang?.split('-')[0] || 'en';\n\n // 1. Server manifest (freshest, cross-browser)\n if (siteKey) {\n const serverCache = await fetchServerAltTexts(siteKey, proxyUrl, pageLang);\n for (const [url, alt] of serverCache) {\n // Store BOTH original URL and normalized URL (without width/height params)\n // so lookups by currentSrc (any size) will match\n cache.set(url, alt);\n const norm = normalizeImageUrl(url);\n if (norm !== url) cache.set(norm, alt);\n setCachedAltText(url, alt, pageLang).catch(() => {});\n }\n }\n\n // 2. IndexedDB (fills gaps)\n const localCache = await getAllCachedAltTexts();\n for (const [url, alt] of localCache) {\n if (!cache.has(url)) cache.set(url, alt);\n }\n\n if (cache.size === 0) return 0;\n\n function applyToImg(img: HTMLImageElement): boolean {\n if (img.closest('#accessify-root') || img.closest('accessify-widget')) return false;\n const src = getImageSrc(img);\n const norm = normalizeImageUrl(src);\n const imgSrcNorm = normalizeImageUrl(img.src);\n const cached = cache.get(src) || cache.get(norm) || cache.get(img.src) || cache.get(imgSrcNorm);\n if (!cached) return false;\n\n const alt = img.getAttribute('alt');\n if (alt === null || alt.trim() === '') {\n img.setAttribute('alt', cached);\n img.setAttribute('data-accessify-alt', 'auto');\n }\n // Always set title for native hover tooltip\n img.setAttribute('title', cached);\n return true;\n }\n\n let applied = 0;\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (applyToImg(img)) applied++;\n });\n\n // Watch for late-loading images (Framer SPA, lazy load)\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (const node of m.addedNodes) {\n const imgs = node instanceof HTMLImageElement ? [node] :\n node instanceof HTMLElement ? Array.from(node.querySelectorAll<HTMLImageElement>('img')) : [];\n for (const img of imgs) applyToImg(img);\n }\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n setTimeout(() => observer.disconnect(), 30000);\n\n return applied;\n}\n\n// ---------------------------------------------------------------------------\n// Feature Module\n// ---------------------------------------------------------------------------\n\nexport default function createAltTextModule(\n aiService?: AIService,\n initialLang: string = 'de',\n serverConfig?: { siteKey?: string; proxyUrl?: string },\n): FeatureModule {\n const siteKey = serverConfig?.siteKey || '';\n const proxyUrl = serverConfig?.proxyUrl || '';\n let enabled = false;\n let domObserver: MutationObserver | null = null;\n let autoGenerating = false;\n\n // Tracked images\n let missingAltImages: HTMLImageElement[] = [];\n const processedImages = new Map<HTMLImageElement, { generatedAlt: string }>();\n\n function lang(): string { return getCurrentWidgetLang() || initialLang; }\n function isDE(): boolean { return lang().startsWith('de'); }\n\n // -------------------------------------------------------------------------\n // Helpers\n // -------------------------------------------------------------------------\n\n function isGenericAlt(alt: string): boolean {\n if (!alt.trim()) return true;\n if (/^(image|img|photo|bild|foto|untitled|placeholder)/i.test(alt)) return true;\n if (/^IMG_\\d+/i.test(alt)) return true;\n if (/\\.(jpg|jpeg|png|gif|webp|svg|avif)$/i.test(alt)) return true;\n return false;\n }\n\n function isDecorativeImage(img: HTMLImageElement): boolean {\n const role = img.getAttribute('role');\n if (role === 'presentation' || role === 'none') return true;\n if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return true;\n return false;\n }\n\n function isValidImage(img: HTMLImageElement): boolean {\n if (img.closest('#accessify-root') || img.closest('accessify-widget')) return false;\n // Skip tiny images (icons, tracking pixels, avatars)\n if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return false;\n // Skip images not rendered on-screen (display:none, visibility:hidden, etc.)\n const rect = img.getBoundingClientRect();\n if (rect.width < 40 || rect.height < 40) return false;\n // Skip images hidden via CSS (opacity:0, visibility:hidden)\n const style = getComputedStyle(img);\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') return false;\n // Skip images with role=\"presentation\" or aria-hidden\n if (img.getAttribute('role') === 'presentation' || img.getAttribute('aria-hidden') === 'true') return false;\n return true;\n }\n\n function needsAltText(img: HTMLImageElement): boolean {\n if (!isValidImage(img)) return false;\n const alt = img.getAttribute('alt');\n if (alt === null) return true;\n if (isGenericAlt(alt)) return true;\n if (alt === '' && !isDecorativeImage(img)) return true;\n return false;\n }\n\n function scanForMissingAlt(): HTMLImageElement[] {\n const missing: HTMLImageElement[] = [];\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (needsAltText(img)) missing.push(img);\n });\n document.querySelectorAll<HTMLElement>('picture').forEach((picture) => {\n if (picture.closest('#accessify-root') || picture.closest('accessify-widget')) return;\n const img = picture.querySelector('img');\n if (img && !missing.includes(img) && needsAltText(img)) {\n missing.push(img);\n }\n });\n return missing;\n }\n\n function gatherImageContext(img: HTMLImageElement): string {\n const parts: string[] = [];\n try {\n const url = new URL(getImageSrc(img), window.location.href);\n const filename = url.pathname.split('/').pop();\n if (filename) parts.push(`Filename: ${filename}`);\n } catch {}\n const figure = img.closest('figure');\n if (figure) {\n const caption = figure.querySelector('figcaption');\n if (caption?.textContent?.trim()) parts.push(`Caption: ${caption.textContent.trim()}`);\n }\n const container = img.parentElement?.parentElement || img.parentElement;\n if (container) {\n const heading = container.querySelector('h1, h2, h3, h4, h5, h6');\n if (heading?.textContent?.trim()) parts.push(`Nearby heading: ${heading.textContent.trim()}`);\n }\n return parts.join('. ');\n }\n\n // -------------------------------------------------------------------------\n // Apply + Generate (title = native hover tooltip on every image)\n // -------------------------------------------------------------------------\n\n function applyAltText(img: HTMLImageElement, altText: string) {\n img.setAttribute('alt', altText);\n img.setAttribute('title', altText);\n processedImages.set(img, { generatedAlt: altText });\n if (enabled) addInfoBadge(img, altText);\n }\n\n /** Set title on every visible image that has alt text but no title yet */\n function applyTitlesToAllImages() {\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!isValidImage(img)) return;\n // Skip if already has a title\n if (img.getAttribute('title')) return;\n const alt = img.getAttribute('alt');\n if (alt && alt.trim()) {\n img.setAttribute('title', alt);\n img.setAttribute('data-accessify-title', 'auto');\n }\n });\n }\n\n // -------------------------------------------------------------------------\n // Info badge — small \"i\" icon on each image with alt text\n // -------------------------------------------------------------------------\n // Badges live in a single overlay container on document.body (position:fixed\n // would need scroll tracking, so we use position:absolute on the body).\n // This keeps them completely outside any overflow:hidden zoom containers.\n // -------------------------------------------------------------------------\n\n const BADGE_ATTR = 'data-accessify-badge';\n const WRAPPER_ATTR = 'data-accessify-badge-wrap';\n const OVERLAY_ID = 'accessify-badge-overlay';\n const BADGE_STYLE_ID = 'accessify-badge-styles';\n let badgePositionRAF: number | null = null;\n let trackedBadges: Array<{ target: HTMLElement; badge: HTMLElement; tooltip: HTMLElement }> = [];\n let outsideClickHandler: ((e: Event) => void) | null = null;\n\n function getOrCreateOverlay(): HTMLElement {\n let overlay = document.getElementById(OVERLAY_ID);\n if (!overlay) {\n overlay = document.createElement('div');\n overlay.id = OVERLAY_ID;\n Object.assign(overlay.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '0',\n height: '0',\n overflow: 'visible',\n pointerEvents: 'none',\n zIndex: '10000',\n });\n document.body.appendChild(overlay);\n }\n // Inject badge hover + coarse pointer styles once\n if (!document.getElementById(BADGE_STYLE_ID)) {\n const style = document.createElement('style');\n style.id = BADGE_STYLE_ID;\n style.textContent = `\n [${BADGE_ATTR}=\"badge\"]:hover + [${BADGE_ATTR}=\"tooltip\"] { display: block !important; }\n [${BADGE_ATTR}=\"badge\"]:hover { background: rgba(0,0,0,0.85) !important; }\n @media (pointer: coarse) {\n [${BADGE_ATTR}=\"badge\"] { width: 36px !important; height: 36px !important; line-height: 36px !important; font-size: 16px !important; }\n }\n `;\n document.head.appendChild(style);\n }\n return overlay;\n }\n\n function positionBadge(target: HTMLElement, badge: HTMLElement, tooltip: HTMLElement) {\n const rect = target.getBoundingClientRect();\n // Skip if element is not visible / too small / off-screen\n if (rect.width < 40 || rect.height < 40 ||\n rect.bottom < 0 || rect.top > window.innerHeight + 200 ||\n rect.right < 0 || rect.left > window.innerWidth + 200) {\n badge.style.display = 'none';\n tooltip.style.display = 'none';\n return;\n }\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n const top = rect.top + scrollY + 6;\n const left = rect.left + scrollX + 6;\n badge.style.display = '';\n badge.style.top = `${top}px`;\n badge.style.left = `${left}px`;\n // Tooltip positioned below badge\n tooltip.style.top = `${top + 26}px`;\n tooltip.style.left = `${left}px`;\n }\n\n function updateAllBadgePositions() {\n for (const { target, badge, tooltip } of trackedBadges) {\n if (!document.body.contains(target)) continue;\n positionBadge(target, badge, tooltip);\n }\n }\n\n function startBadgeTracking() {\n if (badgePositionRAF !== null) return;\n const tick = () => {\n updateAllBadgePositions();\n badgePositionRAF = requestAnimationFrame(tick);\n };\n badgePositionRAF = requestAnimationFrame(tick);\n\n // Outside-click handler to close all open tooltips\n if (!outsideClickHandler) {\n outsideClickHandler = (e: Event) => {\n const target = e.target as HTMLElement;\n if (target.getAttribute(BADGE_ATTR) === 'badge') return;\n for (const entry of trackedBadges) {\n entry.tooltip.style.display = 'none';\n entry.badge.style.background = 'rgba(0,0,0,0.6)';\n }\n };\n document.addEventListener('click', outsideClickHandler, { passive: true });\n }\n }\n\n function stopBadgeTracking() {\n if (badgePositionRAF !== null) {\n cancelAnimationFrame(badgePositionRAF);\n badgePositionRAF = null;\n }\n if (outsideClickHandler) {\n document.removeEventListener('click', outsideClickHandler);\n outsideClickHandler = null;\n }\n }\n\n function addInfoBadge(target: HTMLElement, altText: string) {\n if (target.getAttribute(BADGE_ATTR)) return;\n target.setAttribute(BADGE_ATTR, '1');\n\n const overlay = getOrCreateOverlay();\n\n // Badge \"i\" circle\n const badge = document.createElement('span');\n Object.assign(badge.style, {\n position: 'absolute',\n width: '22px',\n height: '22px',\n borderRadius: '50%',\n background: 'rgba(0,0,0,0.6)',\n color: '#fff',\n fontFamily: 'sans-serif',\n fontWeight: 'bold',\n fontSize: '13px',\n lineHeight: '22px',\n textAlign: 'center',\n cursor: 'default',\n pointerEvents: 'auto',\n boxShadow: '0 1px 4px rgba(0,0,0,0.4)',\n transition: 'background 0.15s',\n });\n badge.textContent = 'i';\n badge.setAttribute('aria-hidden', 'true');\n badge.setAttribute('translate', 'no');\n badge.classList.add('notranslate');\n badge.setAttribute(BADGE_ATTR, 'badge');\n\n // Tooltip\n const tooltip = document.createElement('span');\n Object.assign(tooltip.style, {\n display: 'none',\n position: 'absolute',\n minWidth: '150px',\n maxWidth: '280px',\n padding: '6px 10px',\n background: 'rgba(0,0,0,0.88)',\n color: '#fff',\n fontFamily: 'sans-serif',\n fontSize: '12px',\n lineHeight: '1.4',\n borderRadius: '6px',\n pointerEvents: 'none',\n wordWrap: 'break-word',\n boxShadow: '0 2px 8px rgba(0,0,0,0.3)',\n zIndex: '1',\n });\n tooltip.textContent = altText;\n tooltip.setAttribute('translate', 'no');\n tooltip.classList.add('notranslate');\n tooltip.setAttribute(BADGE_ATTR, 'tooltip');\n\n badge.addEventListener('click', () => {\n const isOpen = tooltip.style.display === 'block';\n // Close all other open tooltips first\n for (const entry of trackedBadges) {\n entry.tooltip.style.display = 'none';\n entry.badge.style.background = 'rgba(0,0,0,0.6)';\n }\n if (!isOpen) {\n badge.style.background = 'rgba(0,0,0,0.85)';\n tooltip.style.display = 'block';\n }\n });\n\n overlay.appendChild(badge);\n overlay.appendChild(tooltip);\n\n // Initial position\n positionBadge(target, badge, tooltip);\n\n // Track for continuous position updates\n trackedBadges.push({ target, badge, tooltip });\n }\n\n function removeAllBadges() {\n stopBadgeTracking();\n trackedBadges = [];\n // Remove overlay and badge styles\n document.getElementById(OVERLAY_ID)?.remove();\n document.getElementById(BADGE_STYLE_ID)?.remove();\n // Clear badge markers\n document.querySelectorAll(`[${BADGE_ATTR}]`).forEach(el => el.removeAttribute(BADGE_ATTR));\n // Legacy: unwrap any leftover wrappers from old version\n document.querySelectorAll<HTMLElement>(`[${WRAPPER_ATTR}]`).forEach(wrapper => {\n const img = wrapper.querySelector('img');\n if (img && wrapper.parentElement) {\n wrapper.parentElement.insertBefore(img, wrapper);\n wrapper.remove();\n }\n });\n }\n\n /** Add info badges to ALL visible images */\n function addBadgesToAllImages() {\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!isValidImage(img)) return;\n const alt = img.getAttribute('alt') || img.getAttribute('title');\n if (alt && alt.trim()) {\n addInfoBadge(img, alt.trim());\n }\n });\n // Also for background images\n document.querySelectorAll<HTMLElement>('[data-accessify-bg-alt]').forEach((el) => {\n const alt = el.getAttribute('aria-label');\n if (alt && alt.trim()) {\n addInfoBadge(el, alt.trim());\n }\n });\n // Start tracking positions (handles scroll, resize, zoom)\n if (trackedBadges.length > 0) startBadgeTracking();\n }\n\n function removeTitles() {\n document.querySelectorAll<HTMLImageElement>('img[data-accessify-title=\"auto\"]').forEach((img) => {\n img.removeAttribute('title');\n img.removeAttribute('data-accessify-title');\n });\n // Clean up background image descriptions\n document.querySelectorAll<HTMLElement>('[data-accessify-bg-alt]').forEach((el) => {\n el.removeAttribute('role');\n el.removeAttribute('aria-label');\n el.removeAttribute('title');\n el.removeAttribute('data-accessify-bg-alt');\n });\n // Remove all info badges\n removeAllBadges();\n }\n\n // -------------------------------------------------------------------------\n // Background images (CSS background-image)\n // -------------------------------------------------------------------------\n\n /** Find significant elements with CSS background-image and no accessibility info */\n function scanForBackgroundImages(): HTMLElement[] {\n const found: HTMLElement[] = [];\n // Scan ALL elements — not just specific class patterns — for background-image\n const allElements = document.querySelectorAll<HTMLElement>('*');\n for (const el of allElements) {\n if (el.closest('#accessify-root') || el.closest('accessify-widget')) continue;\n if (el.getAttribute('data-accessify-bg-alt')) continue;\n // Skip tiny or invisible elements quickly via offsetHeight (avoids getComputedStyle)\n if (el.offsetWidth < 200 || el.offsetHeight < 150) continue;\n const style = getComputedStyle(el);\n const bg = style.backgroundImage;\n if (!bg || bg === 'none') continue;\n // Must have a url() reference (not just gradients)\n const urlMatch = bg.match(/url\\([\"']?([^\"')]+)[\"']?\\)/);\n if (!urlMatch) continue;\n // Skip SVG data URIs and tiny inline images\n if (urlMatch[1].startsWith('data:image/svg')) continue;\n // Skip if already has role=\"img\" with aria-label\n if (el.getAttribute('role') === 'img' && el.getAttribute('aria-label')) continue;\n found.push(el);\n }\n return found;\n }\n\n function getBackgroundImageUrl(el: HTMLElement): string | null {\n const bg = getComputedStyle(el).backgroundImage;\n const match = bg?.match(/url\\([\"']?([^\"')]+)[\"']?\\)/);\n return match ? match[1] : null;\n }\n\n function applyBgAlt(el: HTMLElement, altText: string) {\n el.setAttribute('role', 'img');\n el.setAttribute('aria-label', altText);\n el.setAttribute('title', altText);\n el.setAttribute('data-accessify-bg-alt', 'auto');\n if (enabled) addInfoBadge(el, altText);\n }\n\n async function generateBgAlts() {\n if (!aiService || !enabled) return;\n if (currentAltSiteMode !== 'auto') {\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.info('[Accessify] alt-text: siteMode=manual — skipping live generation for background images');\n }\n return;\n }\n const bgElements = scanForBackgroundImages();\n for (const el of bgElements) {\n if (!enabled) break;\n const src = getBackgroundImageUrl(el);\n if (!src) continue;\n // Check cache first\n const cached = await getCachedAltText(src);\n if (cached) {\n applyBgAlt(el, cached);\n continue;\n }\n // Generate via AI\n try {\n const ctx = gatherBgContext(el);\n const alt = await aiService.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyBgAlt(el, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Bg alt-text generation failed:', src, err);\n }\n }\n }\n\n function gatherBgContext(el: HTMLElement): string {\n const parts: string[] = [];\n // Tag and class hints\n parts.push(`Element: <${el.tagName.toLowerCase()}>`);\n if (el.className) parts.push(`Class: ${el.className}`);\n // Text inside\n const text = el.textContent?.trim().slice(0, 100);\n if (text) parts.push(`Overlay text: ${text}`);\n // Nearby heading\n const heading = el.querySelector('h1, h2, h3');\n if (heading?.textContent?.trim()) parts.push(`Heading: ${heading.textContent.trim()}`);\n return parts.join('. ');\n }\n\n async function generateAll() {\n if (autoGenerating || !enabled || !aiService) return;\n autoGenerating = true;\n const CONCURRENCY = 3;\n\n // Phase 1: apply from IndexedDB cache\n const uncached: HTMLImageElement[] = [];\n for (const img of missingAltImages) {\n if (!enabled) { autoGenerating = false; return; }\n if (processedImages.has(img)) continue;\n const src = getImageSrc(img);\n const cached = await getCachedAltText(src);\n if (cached) {\n applyAltText(img, cached);\n } else {\n uncached.push(img);\n }\n }\n\n if (!enabled) { autoGenerating = false; return; }\n if (!uncached.length) { autoGenerating = false; return; }\n\n // SAFETY GATE: only proceed with live AI if site is in 'auto' mode.\n // In 'manual' (default), leave images without generated alt text — the\n // owner must trigger a crawl or switch modes from the dashboard.\n if (currentAltSiteMode !== 'auto') {\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.info(\n `[Accessify] alt-text: siteMode=manual — ${uncached.length} image(s) left untouched. ` +\n `Trigger a crawl from the dashboard or enable auto mode.`,\n );\n }\n autoGenerating = false;\n return;\n }\n\n // Phase 2: AI generation in parallel batches\n for (let i = 0; i < uncached.length; i += CONCURRENCY) {\n if (!enabled) { autoGenerating = false; return; }\n const batch = uncached.slice(i, i + CONCURRENCY);\n await Promise.all(batch.map(async (img) => {\n if (!enabled) return;\n try {\n const src = getImageSrc(img);\n const ctx = gatherImageContext(img);\n const alt = await aiService!.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyAltText(img, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Alt-text generation failed:', getImageSrc(img), err);\n }\n }));\n }\n\n autoGenerating = false;\n }\n\n async function generateSingle(img: HTMLImageElement) {\n if (!aiService || !enabled) return;\n const src = getImageSrc(img);\n const cached = await getCachedAltText(src);\n if (cached) { applyAltText(img, cached); return; }\n\n // Mode gate — only live-generate when site is in 'auto' mode\n if (currentAltSiteMode !== 'auto') return;\n\n try {\n const ctx = gatherImageContext(img);\n const alt = await aiService.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyAltText(img, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Alt-text generation failed:', src, err);\n }\n }\n\n // -------------------------------------------------------------------------\n // Dynamic image registration\n // -------------------------------------------------------------------------\n\n function tryRegisterImage(img: HTMLImageElement) {\n if (!enabled) return;\n if (!isValidImage(img)) return;\n if (missingAltImages.includes(img)) return;\n\n function addIfValid() {\n if (!enabled || missingAltImages.includes(img)) return;\n if (img.naturalWidth < 20 || img.naturalHeight < 20) return;\n\n if (needsAltText(img)) {\n missingAltImages.push(img);\n generateSingle(img);\n } else {\n // Image has alt but maybe no title/badge yet — add both\n const alt = img.getAttribute('alt');\n if (alt && alt.trim()) {\n if (!img.getAttribute('title')) {\n img.setAttribute('title', alt);\n img.setAttribute('data-accessify-title', 'auto');\n }\n addInfoBadge(img, alt.trim());\n }\n }\n }\n\n if (img.complete && img.naturalWidth > 0) addIfValid();\n else img.addEventListener('load', addIfValid, { once: true });\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n function activate() {\n if (enabled) return;\n enabled = true;\n\n // Recognize images that were auto-applied from cache/manifest\n document.querySelectorAll<HTMLImageElement>('img[data-accessify-alt=\"auto\"]').forEach((img) => {\n if (img.closest('#accessify-root')) return;\n if (!processedImages.has(img)) {\n processedImages.set(img, { generatedAlt: img.getAttribute('alt') || '' });\n missingAltImages.push(img);\n }\n });\n\n // Scan for truly missing alt texts\n const missing = scanForMissingAlt();\n for (const img of missing) {\n if (!missingAltImages.includes(img)) {\n missingAltImages.push(img);\n }\n }\n\n // Start AI generation in background (img + background images)\n generateAll();\n generateBgAlts();\n\n // Set title on ALL images (consistent hover tooltip everywhere)\n applyTitlesToAllImages();\n\n // Add info badges to show alt text is available\n addBadgesToAllImages();\n\n // Register not-yet-loaded images\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!img.complete) tryRegisterImage(img);\n });\n\n // Delayed re-scans for late-loading images and AI-generated alt texts\n for (const delay of [2000, 5000, 10000]) {\n setTimeout(() => {\n if (enabled) {\n document.querySelectorAll<HTMLImageElement>('img').forEach(tryRegisterImage);\n applyTitlesToAllImages();\n addBadgesToAllImages();\n }\n }, delay);\n }\n\n // Watch for new images\n domObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (const node of m.addedNodes) {\n if (node instanceof HTMLImageElement) tryRegisterImage(node);\n else if (node instanceof HTMLElement) {\n node.querySelectorAll<HTMLImageElement>('img').forEach(tryRegisterImage);\n }\n }\n }\n });\n domObserver.observe(document.body, { childList: true, subtree: true });\n }\n\n function deactivate() {\n enabled = false;\n autoGenerating = false;\n domObserver?.disconnect();\n domObserver = null;\n\n // Remove auto-added titles (but keep alt texts — those are useful)\n removeTitles();\n missingAltImages = [];\n }\n\n // Run auto-apply immediately when the module is created\n autoApplyCachedAltTexts({ siteKey, proxyUrl, lang: initialLang }).catch(() => {});\n\n return {\n id: 'alt-text',\n name: () => (isDE() ? 'Bildbeschreibung' : 'Image Description'),\n description: isDE() ? 'Bildbeschreibungen per Hover anzeigen und fehlende automatisch erzeugen' : 'Show image descriptions on hover and auto-generate missing ones',\n icon: 'alt-text',\n category: 'ai',\n activate,\n deactivate,\n getState: (): FeatureState => ({\n id: 'alt-text',\n enabled,\n value: {\n missingCount: missingAltImages.filter((img) => !processedImages.has(img)).length,\n processedCount: processedImages.size,\n },\n }),\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"alt-text-BzVlRLRb.js","sources":["../src/features/alt-text.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Accessify – Bildbeschreibung (Image Description) Feature\n// ---------------------------------------------------------------------------\n//\n// A) AUTO-APPLY (runs on widget init, no feature activation needed):\n// Loads alt texts from server manifest + IndexedDB cache and silently\n// applies them to images (alt + title). Ensures all visitors get\n// alt texts immediately.\n//\n// B) GENERATE (when user activates the feature toggle):\n// Scans for images without alt text → generates via AI → injects\n// alt + title into DOM. Title attribute provides native hover tooltip\n// on every image, consistently.\n//\n// Framer compatibility:\n// - Uses currentSrc || src (srcset-aware)\n// - Treats empty alt=\"\" on large images as \"missing\" (Framer sets alt=\"\" on all)\n// - Delayed re-scans for lazy-loaded images\n// - MutationObserver for dynamically added images\n// ---------------------------------------------------------------------------\n\nimport type { FeatureModule, FeatureState, AIService } from '../types';\nimport { RateLimitError } from '../services/ai-service';\nimport { getCurrentWidgetLang } from '../i18n/index';\n\n// ---------------------------------------------------------------------------\n// IndexedDB cache\n// ---------------------------------------------------------------------------\n\nconst IDB_NAME = 'accessify-alt-text-cache';\nconst IDB_STORE = 'alt-texts';\nconst IDB_VERSION = 2;\n\ninterface CachedAltText {\n key: string; src: string; altText: string; lang: string; createdAt: number;\n}\n\nfunction hashSrc(src: string): string {\n let hash = 5381;\n const n = src.toLowerCase().trim();\n for (let i = 0; i < n.length; i++) { hash = ((hash << 5) + hash) + n.charCodeAt(i); hash |= 0; }\n return Math.abs(hash).toString(36);\n}\n\n/** Normalize image URL: strip query params for cache matching (Framer adds ?width=&height=) */\nfunction normalizeImageUrl(url: string): string {\n try {\n const u = new URL(url);\n u.searchParams.delete('width');\n u.searchParams.delete('height');\n u.searchParams.delete('scale-down-to');\n return u.href;\n } catch {\n return url;\n }\n}\n\n/** Get the best available src for an image (Framer srcset aware) */\nfunction getImageSrc(img: HTMLImageElement): string {\n return img.currentSrc || img.src;\n}\n\nfunction openCache(): Promise<IDBDatabase | null> {\n return new Promise((resolve) => {\n try {\n const req = indexedDB.open(IDB_NAME, IDB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(IDB_STORE)) db.createObjectStore(IDB_STORE, { keyPath: 'key' });\n if (!db.objectStoreNames.contains('alt-text-reports')) db.createObjectStore('alt-text-reports', { keyPath: 'key' });\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => resolve(null);\n } catch { resolve(null); }\n });\n}\n\nasync function getAllCachedAltTexts(): Promise<Map<string, string>> {\n const db = await openCache();\n const map = new Map<string, string>();\n if (!db) return map;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const req = tx.objectStore(IDB_STORE).getAll();\n req.onsuccess = () => {\n for (const r of req.result as CachedAltText[]) { map.set(r.src, r.altText); }\n resolve(map);\n };\n req.onerror = () => resolve(map);\n } catch { resolve(map); }\n });\n}\n\nasync function getCachedAltText(src: string): Promise<string | null> {\n const db = await openCache();\n if (!db) return null;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const store = tx.objectStore(IDB_STORE);\n const req1 = store.get(hashSrc(src));\n req1.onsuccess = () => {\n if ((req1.result as CachedAltText | undefined)?.altText) {\n resolve(req1.result.altText);\n return;\n }\n const norm = normalizeImageUrl(src);\n if (norm !== src) {\n const req2 = store.get(hashSrc(norm));\n req2.onsuccess = () => resolve((req2.result as CachedAltText | undefined)?.altText || null);\n req2.onerror = () => resolve(null);\n } else {\n resolve(null);\n }\n };\n req1.onerror = () => resolve(null);\n } catch { resolve(null); }\n });\n}\n\nasync function setCachedAltText(src: string, altText: string, langCode: string): Promise<void> {\n const db = await openCache();\n if (!db) return;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).put({ key: hashSrc(src), src, altText, lang: langCode, createdAt: Date.now() } as CachedAltText);\n tx.oncomplete = () => resolve();\n tx.onerror = () => resolve();\n } catch { resolve(); }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Server-side alt-text cache (cross-browser, cross-visitor)\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_API_BASE = 'https://accessify-api.accessify.workers.dev';\n\n// Module-wide mode tracking, set on every manifest fetch. 'manual' = default,\n// never run live AI for unknown images. 'auto' = live fallback + auto-persist OK.\ntype ResimplifyMode = 'manual' | 'auto';\nlet currentAltSiteMode: ResimplifyMode = 'manual';\n\nasync function fetchServerAltTexts(siteKey: string, proxyUrl: string, lang: string): Promise<Map<string, string>> {\n const map = new Map<string, string>();\n try {\n const base = proxyUrl || DEFAULT_API_BASE;\n const pageUrl = window.location.origin + window.location.pathname;\n const res = await fetch(`${base}/v1/manifest?siteKey=${encodeURIComponent(siteKey)}&url=${encodeURIComponent(pageUrl)}&feature=alt_text&variant=${encodeURIComponent(lang)}`, {\n headers: { 'Accept': 'application/json' },\n cache: 'no-cache',\n });\n if (!res.ok) return map;\n const data = await res.json() as { blocks?: Array<{ selector: string; result: string }>; siteMode?: ResimplifyMode };\n // Update authoritative mode from server on every fetch\n currentAltSiteMode = data.siteMode === 'auto' ? 'auto' : 'manual';\n if (data.blocks) {\n for (const block of data.blocks) {\n if (block.selector && block.result) map.set(block.selector, block.result);\n }\n }\n } catch { /* fall back to IndexedDB */ }\n return map;\n}\n\nfunction persistAltTextToServer(siteKey: string, proxyUrl: string, imageUrl: string, altText: string, lang: string): void {\n try {\n const base = proxyUrl || DEFAULT_API_BASE;\n const pageUrl = window.location.origin + window.location.pathname;\n fetch(`${base}/v1/cache/persist-alt-text`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ siteKey, pageUrl, imageUrl, altText, lang }),\n }).catch(() => {});\n } catch { /* fire-and-forget */ }\n}\n\n// ---------------------------------------------------------------------------\n// Auto-apply: runs on widget init, no feature activation needed\n// ---------------------------------------------------------------------------\n\nlet autoApplied = false;\n\n/** Silently apply cached/manifest alt texts to all images on the page */\nexport async function autoApplyCachedAltTexts(\n widgetConfig?: { siteKey?: string; proxyUrl?: string; lang?: string },\n): Promise<number> {\n if (autoApplied) return 0;\n autoApplied = true;\n\n const cache = new Map<string, string>();\n const siteKey = widgetConfig?.siteKey;\n const proxyUrl = widgetConfig?.proxyUrl || '';\n const pageLang = widgetConfig?.lang?.split('-')[0] || document.documentElement.lang?.split('-')[0] || 'en';\n\n // 1. Server manifest (freshest, cross-browser)\n if (siteKey) {\n const serverCache = await fetchServerAltTexts(siteKey, proxyUrl, pageLang);\n for (const [url, alt] of serverCache) {\n // Store BOTH original URL and normalized URL (without width/height params)\n // so lookups by currentSrc (any size) will match\n cache.set(url, alt);\n const norm = normalizeImageUrl(url);\n if (norm !== url) cache.set(norm, alt);\n setCachedAltText(url, alt, pageLang).catch(() => {});\n }\n }\n\n // 2. IndexedDB (fills gaps)\n const localCache = await getAllCachedAltTexts();\n for (const [url, alt] of localCache) {\n if (!cache.has(url)) cache.set(url, alt);\n }\n\n if (cache.size === 0) return 0;\n\n function applyToImg(img: HTMLImageElement): boolean {\n if (img.closest('#accessify-root') || img.closest('accessify-widget')) return false;\n const src = getImageSrc(img);\n const norm = normalizeImageUrl(src);\n const imgSrcNorm = normalizeImageUrl(img.src);\n const cached = cache.get(src) || cache.get(norm) || cache.get(img.src) || cache.get(imgSrcNorm);\n if (!cached) return false;\n\n const alt = img.getAttribute('alt');\n if (alt === null || alt.trim() === '') {\n img.setAttribute('alt', cached);\n img.setAttribute('data-accessify-alt', 'auto');\n }\n // Always set title for native hover tooltip\n img.setAttribute('title', cached);\n return true;\n }\n\n let applied = 0;\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (applyToImg(img)) applied++;\n });\n\n // Watch for late-loading images (Framer SPA, lazy load)\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (const node of m.addedNodes) {\n const imgs = node instanceof HTMLImageElement ? [node] :\n node instanceof HTMLElement ? Array.from(node.querySelectorAll<HTMLImageElement>('img')) : [];\n for (const img of imgs) applyToImg(img);\n }\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n setTimeout(() => observer.disconnect(), 30000);\n\n return applied;\n}\n\n// ---------------------------------------------------------------------------\n// Feature Module\n// ---------------------------------------------------------------------------\n\nexport default function createAltTextModule(\n aiService?: AIService,\n initialLang: string = 'de',\n serverConfig?: { siteKey?: string; proxyUrl?: string },\n): FeatureModule {\n const siteKey = serverConfig?.siteKey || '';\n const proxyUrl = serverConfig?.proxyUrl || '';\n let enabled = false;\n let domObserver: MutationObserver | null = null;\n let autoGenerating = false;\n\n // Tracked images\n let missingAltImages: HTMLImageElement[] = [];\n const processedImages = new Map<HTMLImageElement, { generatedAlt: string }>();\n\n function lang(): string { return getCurrentWidgetLang() || initialLang; }\n function isDE(): boolean { return lang().startsWith('de'); }\n\n // -------------------------------------------------------------------------\n // Helpers\n // -------------------------------------------------------------------------\n\n function isGenericAlt(alt: string): boolean {\n if (!alt.trim()) return true;\n if (/^(image|img|photo|bild|foto|untitled|placeholder)/i.test(alt)) return true;\n if (/^IMG_\\d+/i.test(alt)) return true;\n if (/\\.(jpg|jpeg|png|gif|webp|svg|avif)$/i.test(alt)) return true;\n return false;\n }\n\n function isDecorativeImage(img: HTMLImageElement): boolean {\n const role = img.getAttribute('role');\n if (role === 'presentation' || role === 'none') return true;\n if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return true;\n return false;\n }\n\n function isValidImage(img: HTMLImageElement): boolean {\n if (img.closest('#accessify-root') || img.closest('accessify-widget')) return false;\n // Skip tiny images (icons, tracking pixels, avatars)\n if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return false;\n // Skip images not rendered on-screen (display:none, visibility:hidden, etc.)\n const rect = img.getBoundingClientRect();\n if (rect.width < 40 || rect.height < 40) return false;\n // Skip images hidden via CSS (opacity:0, visibility:hidden)\n const style = getComputedStyle(img);\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') return false;\n // Skip images with role=\"presentation\" or aria-hidden\n if (img.getAttribute('role') === 'presentation' || img.getAttribute('aria-hidden') === 'true') return false;\n return true;\n }\n\n function needsAltText(img: HTMLImageElement): boolean {\n if (!isValidImage(img)) return false;\n const alt = img.getAttribute('alt');\n if (alt === null) return true;\n if (isGenericAlt(alt)) return true;\n if (alt === '' && !isDecorativeImage(img)) return true;\n return false;\n }\n\n function scanForMissingAlt(): HTMLImageElement[] {\n const missing: HTMLImageElement[] = [];\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (needsAltText(img)) missing.push(img);\n });\n document.querySelectorAll<HTMLElement>('picture').forEach((picture) => {\n if (picture.closest('#accessify-root') || picture.closest('accessify-widget')) return;\n const img = picture.querySelector('img');\n if (img && !missing.includes(img) && needsAltText(img)) {\n missing.push(img);\n }\n });\n return missing;\n }\n\n function gatherImageContext(img: HTMLImageElement): string {\n const parts: string[] = [];\n try {\n const url = new URL(getImageSrc(img), window.location.href);\n const filename = url.pathname.split('/').pop();\n if (filename) parts.push(`Filename: ${filename}`);\n } catch {}\n const figure = img.closest('figure');\n if (figure) {\n const caption = figure.querySelector('figcaption');\n if (caption?.textContent?.trim()) parts.push(`Caption: ${caption.textContent.trim()}`);\n }\n const container = img.parentElement?.parentElement || img.parentElement;\n if (container) {\n const heading = container.querySelector('h1, h2, h3, h4, h5, h6');\n if (heading?.textContent?.trim()) parts.push(`Nearby heading: ${heading.textContent.trim()}`);\n }\n return parts.join('. ');\n }\n\n // -------------------------------------------------------------------------\n // Apply + Generate (title = native hover tooltip on every image)\n // -------------------------------------------------------------------------\n\n function applyAltText(img: HTMLImageElement, altText: string) {\n img.setAttribute('alt', altText);\n img.setAttribute('title', altText);\n processedImages.set(img, { generatedAlt: altText });\n if (enabled) addInfoBadge(img, altText);\n }\n\n /** Set title on every visible image that has alt text but no title yet */\n function applyTitlesToAllImages() {\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!isValidImage(img)) return;\n // Skip if already has a title\n if (img.getAttribute('title')) return;\n const alt = img.getAttribute('alt');\n if (alt && alt.trim()) {\n img.setAttribute('title', alt);\n img.setAttribute('data-accessify-title', 'auto');\n }\n });\n }\n\n // -------------------------------------------------------------------------\n // Info badge — small \"i\" icon on each image with alt text\n // -------------------------------------------------------------------------\n // Badges live in a single overlay container on document.body (position:fixed\n // would need scroll tracking, so we use position:absolute on the body).\n // This keeps them completely outside any overflow:hidden zoom containers.\n // -------------------------------------------------------------------------\n\n const BADGE_ATTR = 'data-accessify-badge';\n const WRAPPER_ATTR = 'data-accessify-badge-wrap';\n const OVERLAY_ID = 'accessify-badge-overlay';\n const BADGE_STYLE_ID = 'accessify-badge-styles';\n let badgePositionRAF: number | null = null;\n let trackedBadges: Array<{ target: HTMLElement; badge: HTMLElement; tooltip: HTMLElement }> = [];\n let outsideClickHandler: ((e: Event) => void) | null = null;\n\n function getOrCreateOverlay(): HTMLElement {\n let overlay = document.getElementById(OVERLAY_ID);\n if (!overlay) {\n overlay = document.createElement('div');\n overlay.id = OVERLAY_ID;\n Object.assign(overlay.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '0',\n height: '0',\n overflow: 'visible',\n pointerEvents: 'none',\n zIndex: '10000',\n });\n document.body.appendChild(overlay);\n }\n // Inject badge hover + coarse pointer styles once\n if (!document.getElementById(BADGE_STYLE_ID)) {\n const style = document.createElement('style');\n style.id = BADGE_STYLE_ID;\n style.textContent = `\n [${BADGE_ATTR}=\"badge\"]:hover + [${BADGE_ATTR}=\"tooltip\"] { display: block !important; }\n [${BADGE_ATTR}=\"badge\"]:hover { background: rgba(0,0,0,0.85) !important; }\n @media (pointer: coarse) {\n [${BADGE_ATTR}=\"badge\"] { width: 36px !important; height: 36px !important; line-height: 36px !important; font-size: 16px !important; }\n }\n `;\n document.head.appendChild(style);\n }\n return overlay;\n }\n\n function positionBadge(target: HTMLElement, badge: HTMLElement, tooltip: HTMLElement) {\n const rect = target.getBoundingClientRect();\n // Skip if element is not visible / too small / off-screen\n if (rect.width < 40 || rect.height < 40 ||\n rect.bottom < 0 || rect.top > window.innerHeight + 200 ||\n rect.right < 0 || rect.left > window.innerWidth + 200) {\n badge.style.display = 'none';\n tooltip.style.display = 'none';\n return;\n }\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n const top = rect.top + scrollY + 6;\n const left = rect.left + scrollX + 6;\n badge.style.display = '';\n badge.style.top = `${top}px`;\n badge.style.left = `${left}px`;\n // Tooltip positioned below badge\n tooltip.style.top = `${top + 26}px`;\n tooltip.style.left = `${left}px`;\n }\n\n function updateAllBadgePositions() {\n for (const { target, badge, tooltip } of trackedBadges) {\n if (!document.body.contains(target)) continue;\n positionBadge(target, badge, tooltip);\n }\n }\n\n function startBadgeTracking() {\n if (badgePositionRAF !== null) return;\n const tick = () => {\n updateAllBadgePositions();\n badgePositionRAF = requestAnimationFrame(tick);\n };\n badgePositionRAF = requestAnimationFrame(tick);\n\n // Outside-click handler to close all open tooltips\n if (!outsideClickHandler) {\n outsideClickHandler = (e: Event) => {\n const target = e.target as HTMLElement;\n if (target.getAttribute(BADGE_ATTR) === 'badge') return;\n for (const entry of trackedBadges) {\n entry.tooltip.style.display = 'none';\n entry.badge.style.background = 'rgba(0,0,0,0.6)';\n }\n };\n document.addEventListener('click', outsideClickHandler, { passive: true });\n }\n }\n\n function stopBadgeTracking() {\n if (badgePositionRAF !== null) {\n cancelAnimationFrame(badgePositionRAF);\n badgePositionRAF = null;\n }\n if (outsideClickHandler) {\n document.removeEventListener('click', outsideClickHandler);\n outsideClickHandler = null;\n }\n }\n\n function addInfoBadge(target: HTMLElement, altText: string) {\n if (target.getAttribute(BADGE_ATTR)) return;\n target.setAttribute(BADGE_ATTR, '1');\n\n const overlay = getOrCreateOverlay();\n\n // Badge \"i\" circle\n const badge = document.createElement('span');\n Object.assign(badge.style, {\n position: 'absolute',\n width: '22px',\n height: '22px',\n borderRadius: '50%',\n background: 'rgba(0,0,0,0.6)',\n color: '#fff',\n fontFamily: 'sans-serif',\n fontWeight: 'bold',\n fontSize: '13px',\n lineHeight: '22px',\n textAlign: 'center',\n cursor: 'default',\n pointerEvents: 'auto',\n boxShadow: '0 1px 4px rgba(0,0,0,0.4)',\n transition: 'background 0.15s',\n });\n badge.textContent = 'i';\n badge.setAttribute('aria-hidden', 'true');\n badge.setAttribute('translate', 'no');\n badge.classList.add('notranslate');\n badge.setAttribute(BADGE_ATTR, 'badge');\n\n // Tooltip\n const tooltip = document.createElement('span');\n Object.assign(tooltip.style, {\n display: 'none',\n position: 'absolute',\n minWidth: '150px',\n maxWidth: '280px',\n padding: '6px 10px',\n background: 'rgba(0,0,0,0.88)',\n color: '#fff',\n fontFamily: 'sans-serif',\n fontSize: '12px',\n lineHeight: '1.4',\n borderRadius: '6px',\n pointerEvents: 'none',\n wordWrap: 'break-word',\n boxShadow: '0 2px 8px rgba(0,0,0,0.3)',\n zIndex: '1',\n });\n tooltip.textContent = altText;\n tooltip.setAttribute('translate', 'no');\n tooltip.classList.add('notranslate');\n tooltip.setAttribute(BADGE_ATTR, 'tooltip');\n\n badge.addEventListener('click', () => {\n const isOpen = tooltip.style.display === 'block';\n // Close all other open tooltips first\n for (const entry of trackedBadges) {\n entry.tooltip.style.display = 'none';\n entry.badge.style.background = 'rgba(0,0,0,0.6)';\n }\n if (!isOpen) {\n badge.style.background = 'rgba(0,0,0,0.85)';\n tooltip.style.display = 'block';\n }\n });\n\n overlay.appendChild(badge);\n overlay.appendChild(tooltip);\n\n // Initial position\n positionBadge(target, badge, tooltip);\n\n // Track for continuous position updates\n trackedBadges.push({ target, badge, tooltip });\n }\n\n function removeAllBadges() {\n stopBadgeTracking();\n trackedBadges = [];\n // Remove overlay and badge styles\n document.getElementById(OVERLAY_ID)?.remove();\n document.getElementById(BADGE_STYLE_ID)?.remove();\n // Clear badge markers\n document.querySelectorAll(`[${BADGE_ATTR}]`).forEach(el => el.removeAttribute(BADGE_ATTR));\n // Legacy: unwrap any leftover wrappers from old version\n document.querySelectorAll<HTMLElement>(`[${WRAPPER_ATTR}]`).forEach(wrapper => {\n const img = wrapper.querySelector('img');\n if (img && wrapper.parentElement) {\n wrapper.parentElement.insertBefore(img, wrapper);\n wrapper.remove();\n }\n });\n }\n\n /** Add info badges to ALL visible images */\n function addBadgesToAllImages() {\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!isValidImage(img)) return;\n const alt = img.getAttribute('alt') || img.getAttribute('title');\n if (alt && alt.trim()) {\n addInfoBadge(img, alt.trim());\n }\n });\n // Also for background images\n document.querySelectorAll<HTMLElement>('[data-accessify-bg-alt]').forEach((el) => {\n const alt = el.getAttribute('aria-label');\n if (alt && alt.trim()) {\n addInfoBadge(el, alt.trim());\n }\n });\n // Start tracking positions (handles scroll, resize, zoom)\n if (trackedBadges.length > 0) startBadgeTracking();\n }\n\n function removeTitles() {\n document.querySelectorAll<HTMLImageElement>('img[data-accessify-title=\"auto\"]').forEach((img) => {\n img.removeAttribute('title');\n img.removeAttribute('data-accessify-title');\n });\n // Clean up background image descriptions\n document.querySelectorAll<HTMLElement>('[data-accessify-bg-alt]').forEach((el) => {\n el.removeAttribute('role');\n el.removeAttribute('aria-label');\n el.removeAttribute('title');\n el.removeAttribute('data-accessify-bg-alt');\n });\n // Remove all info badges\n removeAllBadges();\n }\n\n // -------------------------------------------------------------------------\n // Background images (CSS background-image)\n // -------------------------------------------------------------------------\n\n /** Find significant elements with CSS background-image and no accessibility info */\n function scanForBackgroundImages(): HTMLElement[] {\n const found: HTMLElement[] = [];\n // Scan ALL elements — not just specific class patterns — for background-image\n const allElements = document.querySelectorAll<HTMLElement>('*');\n for (const el of allElements) {\n if (el.closest('#accessify-root') || el.closest('accessify-widget')) continue;\n if (el.getAttribute('data-accessify-bg-alt')) continue;\n // Skip tiny or invisible elements quickly via offsetHeight (avoids getComputedStyle)\n if (el.offsetWidth < 200 || el.offsetHeight < 150) continue;\n const style = getComputedStyle(el);\n const bg = style.backgroundImage;\n if (!bg || bg === 'none') continue;\n // Must have a url() reference (not just gradients)\n const urlMatch = bg.match(/url\\([\"']?([^\"')]+)[\"']?\\)/);\n if (!urlMatch) continue;\n // Skip SVG data URIs and tiny inline images\n if (urlMatch[1].startsWith('data:image/svg')) continue;\n // Skip if already has role=\"img\" with aria-label\n if (el.getAttribute('role') === 'img' && el.getAttribute('aria-label')) continue;\n found.push(el);\n }\n return found;\n }\n\n function getBackgroundImageUrl(el: HTMLElement): string | null {\n const bg = getComputedStyle(el).backgroundImage;\n const match = bg?.match(/url\\([\"']?([^\"')]+)[\"']?\\)/);\n return match ? match[1] : null;\n }\n\n function applyBgAlt(el: HTMLElement, altText: string) {\n el.setAttribute('role', 'img');\n el.setAttribute('aria-label', altText);\n el.setAttribute('title', altText);\n el.setAttribute('data-accessify-bg-alt', 'auto');\n if (enabled) addInfoBadge(el, altText);\n }\n\n async function generateBgAlts() {\n if (!aiService || !enabled) return;\n if (currentAltSiteMode !== 'auto') {\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.info('[Accessify] alt-text: siteMode=manual — skipping live generation for background images');\n }\n return;\n }\n const bgElements = scanForBackgroundImages();\n for (const el of bgElements) {\n if (!enabled) break;\n const src = getBackgroundImageUrl(el);\n if (!src) continue;\n // Check cache first\n const cached = await getCachedAltText(src);\n if (cached) {\n applyBgAlt(el, cached);\n continue;\n }\n // Generate via AI\n try {\n const ctx = gatherBgContext(el);\n const alt = await aiService.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyBgAlt(el, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Bg alt-text generation failed:', src, err);\n }\n }\n }\n\n function gatherBgContext(el: HTMLElement): string {\n const parts: string[] = [];\n // Tag and class hints\n parts.push(`Element: <${el.tagName.toLowerCase()}>`);\n if (el.className) parts.push(`Class: ${el.className}`);\n // Text inside\n const text = el.textContent?.trim().slice(0, 100);\n if (text) parts.push(`Overlay text: ${text}`);\n // Nearby heading\n const heading = el.querySelector('h1, h2, h3');\n if (heading?.textContent?.trim()) parts.push(`Heading: ${heading.textContent.trim()}`);\n return parts.join('. ');\n }\n\n async function generateAll() {\n if (autoGenerating || !enabled || !aiService) return;\n autoGenerating = true;\n const CONCURRENCY = 3;\n\n // Phase 1: apply from IndexedDB cache\n const uncached: HTMLImageElement[] = [];\n for (const img of missingAltImages) {\n if (!enabled) { autoGenerating = false; return; }\n if (processedImages.has(img)) continue;\n const src = getImageSrc(img);\n const cached = await getCachedAltText(src);\n if (cached) {\n applyAltText(img, cached);\n } else {\n uncached.push(img);\n }\n }\n\n if (!enabled) { autoGenerating = false; return; }\n if (!uncached.length) { autoGenerating = false; return; }\n\n // SAFETY GATE: only proceed with live AI if site is in 'auto' mode.\n // In 'manual' (default), leave images without generated alt text — the\n // owner must trigger a crawl or switch modes from the dashboard.\n if (currentAltSiteMode !== 'auto') {\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.info(\n `[Accessify] alt-text: siteMode=manual — ${uncached.length} image(s) left untouched. ` +\n `Trigger a crawl from the dashboard or enable auto mode.`,\n );\n }\n autoGenerating = false;\n return;\n }\n\n // Phase 2: AI generation in parallel batches\n for (let i = 0; i < uncached.length; i += CONCURRENCY) {\n if (!enabled) { autoGenerating = false; return; }\n const batch = uncached.slice(i, i + CONCURRENCY);\n await Promise.all(batch.map(async (img) => {\n if (!enabled) return;\n try {\n const src = getImageSrc(img);\n const ctx = gatherImageContext(img);\n const alt = await aiService!.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyAltText(img, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Alt-text generation failed:', getImageSrc(img), err);\n }\n }));\n }\n\n autoGenerating = false;\n }\n\n async function generateSingle(img: HTMLImageElement) {\n if (!aiService || !enabled) return;\n const src = getImageSrc(img);\n const cached = await getCachedAltText(src);\n if (cached) { applyAltText(img, cached); return; }\n\n // Mode gate — only live-generate when site is in 'auto' mode\n if (currentAltSiteMode !== 'auto') return;\n\n try {\n const ctx = gatherImageContext(img);\n const alt = await aiService.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyAltText(img, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Alt-text generation failed:', src, err);\n }\n }\n\n // -------------------------------------------------------------------------\n // Dynamic image registration\n // -------------------------------------------------------------------------\n\n function tryRegisterImage(img: HTMLImageElement) {\n if (!enabled) return;\n if (!isValidImage(img)) return;\n if (missingAltImages.includes(img)) return;\n\n function addIfValid() {\n if (!enabled || missingAltImages.includes(img)) return;\n if (img.naturalWidth < 20 || img.naturalHeight < 20) return;\n\n if (needsAltText(img)) {\n missingAltImages.push(img);\n generateSingle(img);\n } else {\n // Image has alt but maybe no title/badge yet — add both\n const alt = img.getAttribute('alt');\n if (alt && alt.trim()) {\n if (!img.getAttribute('title')) {\n img.setAttribute('title', alt);\n img.setAttribute('data-accessify-title', 'auto');\n }\n addInfoBadge(img, alt.trim());\n }\n }\n }\n\n if (img.complete && img.naturalWidth > 0) addIfValid();\n else img.addEventListener('load', addIfValid, { once: true });\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n function activate() {\n if (enabled) return;\n enabled = true;\n\n // Recognize images that were auto-applied from cache/manifest\n document.querySelectorAll<HTMLImageElement>('img[data-accessify-alt=\"auto\"]').forEach((img) => {\n if (img.closest('#accessify-root')) return;\n if (!processedImages.has(img)) {\n processedImages.set(img, { generatedAlt: img.getAttribute('alt') || '' });\n missingAltImages.push(img);\n }\n });\n\n // Scan for truly missing alt texts\n const missing = scanForMissingAlt();\n for (const img of missing) {\n if (!missingAltImages.includes(img)) {\n missingAltImages.push(img);\n }\n }\n\n // Start AI generation in background (img + background images)\n generateAll();\n generateBgAlts();\n\n // Set title on ALL images (consistent hover tooltip everywhere)\n applyTitlesToAllImages();\n\n // Add info badges to show alt text is available\n addBadgesToAllImages();\n\n // Register not-yet-loaded images\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!img.complete) tryRegisterImage(img);\n });\n\n // Delayed re-scans for late-loading images and AI-generated alt texts\n for (const delay of [2000, 5000, 10000]) {\n setTimeout(() => {\n if (enabled) {\n document.querySelectorAll<HTMLImageElement>('img').forEach(tryRegisterImage);\n applyTitlesToAllImages();\n addBadgesToAllImages();\n }\n }, delay);\n }\n\n // Watch for new images\n domObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (const node of m.addedNodes) {\n if (node instanceof HTMLImageElement) tryRegisterImage(node);\n else if (node instanceof HTMLElement) {\n node.querySelectorAll<HTMLImageElement>('img').forEach(tryRegisterImage);\n }\n }\n }\n });\n domObserver.observe(document.body, { childList: true, subtree: true });\n }\n\n function deactivate() {\n enabled = false;\n autoGenerating = false;\n domObserver?.disconnect();\n domObserver = null;\n\n // Remove auto-added titles (but keep alt texts — those are useful)\n removeTitles();\n missingAltImages = [];\n }\n\n // Run auto-apply immediately when the module is created\n autoApplyCachedAltTexts({ siteKey, proxyUrl, lang: initialLang }).catch(() => {});\n\n return {\n id: 'alt-text',\n name: () => (isDE() ? 'Bildbeschreibung' : 'Image Description'),\n description: isDE() ? 'Bildbeschreibungen per Hover anzeigen und fehlende automatisch erzeugen' : 'Show image descriptions on hover and auto-generate missing ones',\n icon: 'alt-text',\n category: 'ai',\n activate,\n deactivate,\n getState: (): FeatureState => ({\n id: 'alt-text',\n enabled,\n value: {\n missingCount: missingAltImages.filter((img) => !processedImages.has(img)).length,\n processedCount: processedImages.size,\n },\n }),\n };\n}\n"],"names":[],"mappings":";AA6BA,MAAM,WAAW;AACjB,MAAM,YAAY;AAClB,MAAM,cAAc;AAMpB,SAAS,QAAQ,KAAqB;AACpC,MAAI,OAAO;AACX,QAAM,IAAI,IAAI,YAAA,EAAc,KAAA;AAC5B,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AAAE,YAAS,QAAQ,KAAK,OAAQ,EAAE,WAAW,CAAC;AAAG,YAAQ;AAAA,EAAG;AAC/F,SAAO,KAAK,IAAI,IAAI,EAAE,SAAS,EAAE;AACnC;AAGA,SAAS,kBAAkB,KAAqB;AAC9C,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,MAAE,aAAa,OAAO,OAAO;AAC7B,MAAE,aAAa,OAAO,QAAQ;AAC9B,MAAE,aAAa,OAAO,eAAe;AACrC,WAAO,EAAE;AAAA,EACX,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,SAAS,YAAY,KAA+B;AAClD,SAAO,IAAI,cAAc,IAAI;AAC/B;AAEA,SAAS,YAAyC;AAChD,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI;AACF,YAAM,MAAM,UAAU,KAAK,UAAU,WAAW;AAChD,UAAI,kBAAkB,MAAM;AAC1B,cAAM,KAAK,IAAI;AACf,YAAI,CAAC,GAAG,iBAAiB,SAAS,SAAS,EAAG,IAAG,kBAAkB,WAAW,EAAE,SAAS,MAAA,CAAO;AAChG,YAAI,CAAC,GAAG,iBAAiB,SAAS,kBAAkB,EAAG,IAAG,kBAAkB,oBAAoB,EAAE,SAAS,MAAA,CAAO;AAAA,MACpH;AACA,UAAI,YAAY,MAAM,QAAQ,IAAI,MAAM;AACxC,UAAI,UAAU,MAAM,QAAQ,IAAI;AAAA,IAClC,QAAQ;AAAE,cAAQ,IAAI;AAAA,IAAG;AAAA,EAC3B,CAAC;AACH;AAEA,eAAe,uBAAqD;AAClE,QAAM,KAAK,MAAM,UAAA;AACjB,QAAM,0BAAU,IAAA;AAChB,MAAI,CAAC,GAAI,QAAO;AAChB,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI;AACF,YAAM,KAAK,GAAG,YAAY,WAAW,UAAU;AAC/C,YAAM,MAAM,GAAG,YAAY,SAAS,EAAE,OAAA;AACtC,UAAI,YAAY,MAAM;AACpB,mBAAW,KAAK,IAAI,QAA2B;AAAE,cAAI,IAAI,EAAE,KAAK,EAAE,OAAO;AAAA,QAAG;AAC5E,gBAAQ,GAAG;AAAA,MACb;AACA,UAAI,UAAU,MAAM,QAAQ,GAAG;AAAA,IACjC,QAAQ;AAAE,cAAQ,GAAG;AAAA,IAAG;AAAA,EAC1B,CAAC;AACH;AAEA,eAAe,iBAAiB,KAAqC;AACnE,QAAM,KAAK,MAAM,UAAA;AACjB,MAAI,CAAC,GAAI,QAAO;AAChB,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI;AACF,YAAM,KAAK,GAAG,YAAY,WAAW,UAAU;AAC/C,YAAM,QAAQ,GAAG,YAAY,SAAS;AACtC,YAAM,OAAO,MAAM,IAAI,QAAQ,GAAG,CAAC;AACnC,WAAK,YAAY,MAAM;AACrB,YAAK,KAAK,QAAsC,SAAS;AACvD,kBAAQ,KAAK,OAAO,OAAO;AAC3B;AAAA,QACF;AACA,cAAM,OAAO,kBAAkB,GAAG;AAClC,YAAI,SAAS,KAAK;AAChB,gBAAM,OAAO,MAAM,IAAI,QAAQ,IAAI,CAAC;AACpC,eAAK,YAAY,MAAM,QAAS,KAAK,QAAsC,WAAW,IAAI;AAC1F,eAAK,UAAU,MAAM,QAAQ,IAAI;AAAA,QACnC,OAAO;AACL,kBAAQ,IAAI;AAAA,QACd;AAAA,MACF;AACA,WAAK,UAAU,MAAM,QAAQ,IAAI;AAAA,IACnC,QAAQ;AAAE,cAAQ,IAAI;AAAA,IAAG;AAAA,EAC3B,CAAC;AACH;AAEA,eAAe,iBAAiB,KAAa,SAAiB,UAAiC;AAC7F,QAAM,KAAK,MAAM,UAAA;AACjB,MAAI,CAAC,GAAI;AACT,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI;AACF,YAAM,KAAK,GAAG,YAAY,WAAW,WAAW;AAChD,SAAG,YAAY,SAAS,EAAE,IAAI,EAAE,KAAK,QAAQ,GAAG,GAAG,KAAK,SAAS,MAAM,UAAU,WAAW,KAAK,IAAA,GAAwB;AACzH,SAAG,aAAa,MAAM,QAAA;AACtB,SAAG,UAAU,MAAM,QAAA;AAAA,IACrB,QAAQ;AAAE,cAAA;AAAA,IAAW;AAAA,EACvB,CAAC;AACH;AAMA,MAAM,mBAAmB;AAKzB,IAAI,qBAAqC;AAEzC,eAAe,oBAAoB,SAAiB,UAAkB,MAA4C;AAChH,QAAM,0BAAU,IAAA;AAChB,MAAI;AACF,UAAM,OAAO,YAAY;AACzB,UAAM,UAAU,OAAO,SAAS,SAAS,OAAO,SAAS;AACzD,UAAM,MAAM,MAAM,MAAM,GAAG,IAAI,wBAAwB,mBAAmB,OAAO,CAAC,QAAQ,mBAAmB,OAAO,CAAC,6BAA6B,mBAAmB,IAAI,CAAC,IAAI;AAAA,MAC5K,SAAS,EAAE,UAAU,mBAAA;AAAA,MACrB,OAAO;AAAA,IAAA,CACR;AACD,QAAI,CAAC,IAAI,GAAI,QAAO;AACpB,UAAM,OAAO,MAAM,IAAI,KAAA;AAEvB,yBAAqB,KAAK,aAAa,SAAS,SAAS;AACzD,QAAI,KAAK,QAAQ;AACf,iBAAW,SAAS,KAAK,QAAQ;AAC/B,YAAI,MAAM,YAAY,MAAM,YAAY,IAAI,MAAM,UAAU,MAAM,MAAM;AAAA,MAC1E;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAA+B;AACvC,SAAO;AACT;AAEA,SAAS,uBAAuB,SAAiB,UAAkB,UAAkB,SAAiB,MAAoB;AACxH,MAAI;AACF,UAAM,OAAO,YAAY;AACzB,UAAM,UAAU,OAAO,SAAS,SAAS,OAAO,SAAS;AACzD,UAAM,GAAG,IAAI,8BAA8B;AAAA,MACzC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAA;AAAA,MAC3B,MAAM,KAAK,UAAU,EAAE,SAAS,SAAS,UAAU,SAAS,KAAA,CAAM;AAAA,IAAA,CACnE,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACnB,QAAQ;AAAA,EAAwB;AAClC;AAMA,IAAI,cAAc;AAGlB,eAAsB,wBACpB,cACiB;AACjB,MAAI,YAAa,QAAO;AACxB,gBAAc;AAEd,QAAM,4BAAY,IAAA;AAClB,QAAM,UAAU,cAAc;AAC9B,QAAM,WAAW,cAAc,YAAY;AAC3C,QAAM,WAAW,cAAc,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,SAAS,gBAAgB,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK;AAGtG,MAAI,SAAS;AACX,UAAM,cAAc,MAAM,oBAAoB,SAAS,UAAU,QAAQ;AACzE,eAAW,CAAC,KAAK,GAAG,KAAK,aAAa;AAGpC,YAAM,IAAI,KAAK,GAAG;AAClB,YAAM,OAAO,kBAAkB,GAAG;AAClC,UAAI,SAAS,IAAK,OAAM,IAAI,MAAM,GAAG;AACrC,uBAAiB,KAAK,KAAK,QAAQ,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACrD;AAAA,EACF;AAGA,QAAM,aAAa,MAAM,qBAAA;AACzB,aAAW,CAAC,KAAK,GAAG,KAAK,YAAY;AACnC,QAAI,CAAC,MAAM,IAAI,GAAG,EAAG,OAAM,IAAI,KAAK,GAAG;AAAA,EACzC;AAEA,MAAI,MAAM,SAAS,EAAG,QAAO;AAE7B,WAAS,WAAW,KAAgC;AAClD,QAAI,IAAI,QAAQ,iBAAiB,KAAK,IAAI,QAAQ,kBAAkB,EAAG,QAAO;AAC9E,UAAM,MAAM,YAAY,GAAG;AAC3B,UAAM,OAAO,kBAAkB,GAAG;AAClC,UAAM,aAAa,kBAAkB,IAAI,GAAG;AAC5C,UAAM,SAAS,MAAM,IAAI,GAAG,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,GAAG,KAAK,MAAM,IAAI,UAAU;AAC9F,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,MAAM,IAAI,aAAa,KAAK;AAClC,QAAI,QAAQ,QAAQ,IAAI,KAAA,MAAW,IAAI;AACrC,UAAI,aAAa,OAAO,MAAM;AAC9B,UAAI,aAAa,sBAAsB,MAAM;AAAA,IAC/C;AAEA,QAAI,aAAa,SAAS,MAAM;AAChC,WAAO;AAAA,EACT;AAEA,MAAI,UAAU;AACd,WAAS,iBAAmC,KAAK,EAAE,QAAQ,CAAC,QAAQ;AAClE,QAAI,WAAW,GAAG,EAAG;AAAA,EACvB,CAAC;AAGD,QAAM,WAAW,IAAI,iBAAiB,CAAC,cAAc;AACnD,eAAW,KAAK,WAAW;AACzB,iBAAW,QAAQ,EAAE,YAAY;AAC/B,cAAM,OAAO,gBAAgB,mBAAmB,CAAC,IAAI,IACnD,gBAAgB,cAAc,MAAM,KAAK,KAAK,iBAAmC,KAAK,CAAC,IAAI,CAAA;AAC7F,mBAAW,OAAO,KAAM,YAAW,GAAG;AAAA,MACxC;AAAA,IACF;AAAA,EACF,CAAC;AACD,WAAS,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,MAAM;AAClE,aAAW,MAAM,SAAS,WAAA,GAAc,GAAK;AAE7C,SAAO;AACT;AAMA,SAAwB,oBACtB,WACA,cAAsB,MACtB,cACe;AACf,QAAM,UAAU,cAAc,WAAW;AACzC,QAAM,WAAW,cAAc,YAAY;AAC3C,MAAI,UAAU;AACd,MAAI,cAAuC;AAC3C,MAAI,iBAAiB;AAGrB,MAAI,mBAAuC,CAAA;AAC3C,QAAM,sCAAsB,IAAA;AAE5B,WAAS,OAAe;AAAE,WAAO,0BAA0B;AAAA,EAAa;AACxE,WAAS,OAAgB;AAAE,WAAO,KAAA,EAAO,WAAW,IAAI;AAAA,EAAG;AAM3D,WAAS,aAAa,KAAsB;AAC1C,QAAI,CAAC,IAAI,KAAA,EAAQ,QAAO;AACxB,QAAI,qDAAqD,KAAK,GAAG,EAAG,QAAO;AAC3E,QAAI,YAAY,KAAK,GAAG,EAAG,QAAO;AAClC,QAAI,uCAAuC,KAAK,GAAG,EAAG,QAAO;AAC7D,WAAO;AAAA,EACT;AAEA,WAAS,kBAAkB,KAAgC;AACzD,UAAM,OAAO,IAAI,aAAa,MAAM;AACpC,QAAI,SAAS,kBAAkB,SAAS,OAAQ,QAAO;AACvD,QAAI,IAAI,YAAY,IAAI,eAAe,MAAM,IAAI,eAAe,MAAM,IAAI,gBAAgB,IAAK,QAAO;AACtG,WAAO;AAAA,EACT;AAEA,WAAS,aAAa,KAAgC;AACpD,QAAI,IAAI,QAAQ,iBAAiB,KAAK,IAAI,QAAQ,kBAAkB,EAAG,QAAO;AAE9E,QAAI,IAAI,YAAY,IAAI,eAAe,MAAM,IAAI,eAAe,MAAM,IAAI,gBAAgB,IAAK,QAAO;AAEtG,UAAM,OAAO,IAAI,sBAAA;AACjB,QAAI,KAAK,QAAQ,MAAM,KAAK,SAAS,GAAI,QAAO;AAEhD,UAAM,QAAQ,iBAAiB,GAAG;AAClC,QAAI,MAAM,YAAY,UAAU,MAAM,eAAe,YAAY,MAAM,YAAY,IAAK,QAAO;AAE/F,QAAI,IAAI,aAAa,MAAM,MAAM,kBAAkB,IAAI,aAAa,aAAa,MAAM,OAAQ,QAAO;AACtG,WAAO;AAAA,EACT;AAEA,WAAS,aAAa,KAAgC;AACpD,QAAI,CAAC,aAAa,GAAG,EAAG,QAAO;AAC/B,UAAM,MAAM,IAAI,aAAa,KAAK;AAClC,QAAI,QAAQ,KAAM,QAAO;AACzB,QAAI,aAAa,GAAG,EAAG,QAAO;AAC9B,QAAI,QAAQ,MAAM,CAAC,kBAAkB,GAAG,EAAG,QAAO;AAClD,WAAO;AAAA,EACT;AAEA,WAAS,oBAAwC;AAC/C,UAAM,UAA8B,CAAA;AACpC,aAAS,iBAAmC,KAAK,EAAE,QAAQ,CAAC,QAAQ;AAClE,UAAI,aAAa,GAAG,EAAG,SAAQ,KAAK,GAAG;AAAA,IACzC,CAAC;AACD,aAAS,iBAA8B,SAAS,EAAE,QAAQ,CAAC,YAAY;AACrE,UAAI,QAAQ,QAAQ,iBAAiB,KAAK,QAAQ,QAAQ,kBAAkB,EAAG;AAC/E,YAAM,MAAM,QAAQ,cAAc,KAAK;AACvC,UAAI,OAAO,CAAC,QAAQ,SAAS,GAAG,KAAK,aAAa,GAAG,GAAG;AACtD,gBAAQ,KAAK,GAAG;AAAA,MAClB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAEA,WAAS,mBAAmB,KAA+B;AACzD,UAAM,QAAkB,CAAA;AACxB,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,YAAY,GAAG,GAAG,OAAO,SAAS,IAAI;AAC1D,YAAM,WAAW,IAAI,SAAS,MAAM,GAAG,EAAE,IAAA;AACzC,UAAI,SAAU,OAAM,KAAK,aAAa,QAAQ,EAAE;AAAA,IAClD,QAAQ;AAAA,IAAC;AACT,UAAM,SAAS,IAAI,QAAQ,QAAQ;AACnC,QAAI,QAAQ;AACV,YAAM,UAAU,OAAO,cAAc,YAAY;AACjD,UAAI,SAAS,aAAa,KAAA,EAAQ,OAAM,KAAK,YAAY,QAAQ,YAAY,KAAA,CAAM,EAAE;AAAA,IACvF;AACA,UAAM,YAAY,IAAI,eAAe,iBAAiB,IAAI;AAC1D,QAAI,WAAW;AACb,YAAM,UAAU,UAAU,cAAc,wBAAwB;AAChE,UAAI,SAAS,aAAa,KAAA,EAAQ,OAAM,KAAK,mBAAmB,QAAQ,YAAY,KAAA,CAAM,EAAE;AAAA,IAC9F;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAMA,WAAS,aAAa,KAAuB,SAAiB;AAC5D,QAAI,aAAa,OAAO,OAAO;AAC/B,QAAI,aAAa,SAAS,OAAO;AACjC,oBAAgB,IAAI,KAAK,EAAE,cAAc,SAAS;AAClD,QAAI,QAAS,cAAa,KAAK,OAAO;AAAA,EACxC;AAGA,WAAS,yBAAyB;AAChC,aAAS,iBAAmC,KAAK,EAAE,QAAQ,CAAC,QAAQ;AAClE,UAAI,CAAC,aAAa,GAAG,EAAG;AAExB,UAAI,IAAI,aAAa,OAAO,EAAG;AAC/B,YAAM,MAAM,IAAI,aAAa,KAAK;AAClC,UAAI,OAAO,IAAI,QAAQ;AACrB,YAAI,aAAa,SAAS,GAAG;AAC7B,YAAI,aAAa,wBAAwB,MAAM;AAAA,MACjD;AAAA,IACF,CAAC;AAAA,EACH;AAUA,QAAM,aAAa;AACnB,QAAM,eAAe;AACrB,QAAM,aAAa;AACnB,QAAM,iBAAiB;AACvB,MAAI,mBAAkC;AACtC,MAAI,gBAA0F,CAAA;AAC9F,MAAI,sBAAmD;AAEvD,WAAS,qBAAkC;AACzC,QAAI,UAAU,SAAS,eAAe,UAAU;AAChD,QAAI,CAAC,SAAS;AACZ,gBAAU,SAAS,cAAc,KAAK;AACtC,cAAQ,KAAK;AACb,aAAO,OAAO,QAAQ,OAAO;AAAA,QAC3B,UAAU;AAAA,QACV,KAAK;AAAA,QACL,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,eAAe;AAAA,QACf,QAAQ;AAAA,MAAA,CACT;AACD,eAAS,KAAK,YAAY,OAAO;AAAA,IACnC;AAEA,QAAI,CAAC,SAAS,eAAe,cAAc,GAAG;AAC5C,YAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,YAAM,KAAK;AACX,YAAM,cAAc;AAAA,WACf,UAAU,sBAAsB,UAAU;AAAA,WAC1C,UAAU;AAAA;AAAA,aAER,UAAU;AAAA;AAAA;AAGjB,eAAS,KAAK,YAAY,KAAK;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,QAAqB,OAAoB,SAAsB;AACpF,UAAM,OAAO,OAAO,sBAAA;AAEpB,QAAI,KAAK,QAAQ,MAAM,KAAK,SAAS,MACjC,KAAK,SAAS,KAAK,KAAK,MAAM,OAAO,cAAc,OACnD,KAAK,QAAQ,KAAK,KAAK,OAAO,OAAO,aAAa,KAAK;AACzD,YAAM,MAAM,UAAU;AACtB,cAAQ,MAAM,UAAU;AACxB;AAAA,IACF;AACA,UAAM,UAAU,OAAO;AACvB,UAAM,UAAU,OAAO;AACvB,UAAM,MAAM,KAAK,MAAM,UAAU;AACjC,UAAM,OAAO,KAAK,OAAO,UAAU;AACnC,UAAM,MAAM,UAAU;AACtB,UAAM,MAAM,MAAM,GAAG,GAAG;AACxB,UAAM,MAAM,OAAO,GAAG,IAAI;AAE1B,YAAQ,MAAM,MAAM,GAAG,MAAM,EAAE;AAC/B,YAAQ,MAAM,OAAO,GAAG,IAAI;AAAA,EAC9B;AAEA,WAAS,0BAA0B;AACjC,eAAW,EAAE,QAAQ,OAAO,QAAA,KAAa,eAAe;AACtD,UAAI,CAAC,SAAS,KAAK,SAAS,MAAM,EAAG;AACrC,oBAAc,QAAQ,OAAO,OAAO;AAAA,IACtC;AAAA,EACF;AAEA,WAAS,qBAAqB;AAC5B,QAAI,qBAAqB,KAAM;AAC/B,UAAM,OAAO,MAAM;AACjB,8BAAA;AACA,yBAAmB,sBAAsB,IAAI;AAAA,IAC/C;AACA,uBAAmB,sBAAsB,IAAI;AAG7C,QAAI,CAAC,qBAAqB;AACxB,4BAAsB,CAAC,MAAa;AAClC,cAAM,SAAS,EAAE;AACjB,YAAI,OAAO,aAAa,UAAU,MAAM,QAAS;AACjD,mBAAW,SAAS,eAAe;AACjC,gBAAM,QAAQ,MAAM,UAAU;AAC9B,gBAAM,MAAM,MAAM,aAAa;AAAA,QACjC;AAAA,MACF;AACA,eAAS,iBAAiB,SAAS,qBAAqB,EAAE,SAAS,MAAM;AAAA,IAC3E;AAAA,EACF;AAEA,WAAS,oBAAoB;AAC3B,QAAI,qBAAqB,MAAM;AAC7B,2BAAqB,gBAAgB;AACrC,yBAAmB;AAAA,IACrB;AACA,QAAI,qBAAqB;AACvB,eAAS,oBAAoB,SAAS,mBAAmB;AACzD,4BAAsB;AAAA,IACxB;AAAA,EACF;AAEA,WAAS,aAAa,QAAqB,SAAiB;AAC1D,QAAI,OAAO,aAAa,UAAU,EAAG;AACrC,WAAO,aAAa,YAAY,GAAG;AAEnC,UAAM,UAAU,mBAAA;AAGhB,UAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,WAAO,OAAO,MAAM,OAAO;AAAA,MACzB,UAAU;AAAA,MACV,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,WAAW;AAAA,MACX,YAAY;AAAA,IAAA,CACb;AACD,UAAM,cAAc;AACpB,UAAM,aAAa,eAAe,MAAM;AACxC,UAAM,aAAa,aAAa,IAAI;AACpC,UAAM,UAAU,IAAI,aAAa;AACjC,UAAM,aAAa,YAAY,OAAO;AAGtC,UAAM,UAAU,SAAS,cAAc,MAAM;AAC7C,WAAO,OAAO,QAAQ,OAAO;AAAA,MAC3B,SAAS;AAAA,MACT,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,eAAe;AAAA,MACf,UAAU;AAAA,MACV,WAAW;AAAA,MACX,QAAQ;AAAA,IAAA,CACT;AACD,YAAQ,cAAc;AACtB,YAAQ,aAAa,aAAa,IAAI;AACtC,YAAQ,UAAU,IAAI,aAAa;AACnC,YAAQ,aAAa,YAAY,SAAS;AAE1C,UAAM,iBAAiB,SAAS,MAAM;AACpC,YAAM,SAAS,QAAQ,MAAM,YAAY;AAEzC,iBAAW,SAAS,eAAe;AACjC,cAAM,QAAQ,MAAM,UAAU;AAC9B,cAAM,MAAM,MAAM,aAAa;AAAA,MACjC;AACA,UAAI,CAAC,QAAQ;AACX,cAAM,MAAM,aAAa;AACzB,gBAAQ,MAAM,UAAU;AAAA,MAC1B;AAAA,IACF,CAAC;AAED,YAAQ,YAAY,KAAK;AACzB,YAAQ,YAAY,OAAO;AAG3B,kBAAc,QAAQ,OAAO,OAAO;AAGpC,kBAAc,KAAK,EAAE,QAAQ,OAAO,SAAS;AAAA,EAC/C;AAEA,WAAS,kBAAkB;AACzB,sBAAA;AACA,oBAAgB,CAAA;AAEhB,aAAS,eAAe,UAAU,GAAG,OAAA;AACrC,aAAS,eAAe,cAAc,GAAG,OAAA;AAEzC,aAAS,iBAAiB,IAAI,UAAU,GAAG,EAAE,QAAQ,CAAA,OAAM,GAAG,gBAAgB,UAAU,CAAC;AAEzF,aAAS,iBAA8B,IAAI,YAAY,GAAG,EAAE,QAAQ,CAAA,YAAW;AAC7E,YAAM,MAAM,QAAQ,cAAc,KAAK;AACvC,UAAI,OAAO,QAAQ,eAAe;AAChC,gBAAQ,cAAc,aAAa,KAAK,OAAO;AAC/C,gBAAQ,OAAA;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AAGA,WAAS,uBAAuB;AAC9B,aAAS,iBAAmC,KAAK,EAAE,QAAQ,CAAC,QAAQ;AAClE,UAAI,CAAC,aAAa,GAAG,EAAG;AACxB,YAAM,MAAM,IAAI,aAAa,KAAK,KAAK,IAAI,aAAa,OAAO;AAC/D,UAAI,OAAO,IAAI,QAAQ;AACrB,qBAAa,KAAK,IAAI,MAAM;AAAA,MAC9B;AAAA,IACF,CAAC;AAED,aAAS,iBAA8B,yBAAyB,EAAE,QAAQ,CAAC,OAAO;AAChF,YAAM,MAAM,GAAG,aAAa,YAAY;AACxC,UAAI,OAAO,IAAI,QAAQ;AACrB,qBAAa,IAAI,IAAI,MAAM;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,QAAI,cAAc,SAAS,EAAG,oBAAA;AAAA,EAChC;AAEA,WAAS,eAAe;AACtB,aAAS,iBAAmC,kCAAkC,EAAE,QAAQ,CAAC,QAAQ;AAC/F,UAAI,gBAAgB,OAAO;AAC3B,UAAI,gBAAgB,sBAAsB;AAAA,IAC5C,CAAC;AAED,aAAS,iBAA8B,yBAAyB,EAAE,QAAQ,CAAC,OAAO;AAChF,SAAG,gBAAgB,MAAM;AACzB,SAAG,gBAAgB,YAAY;AAC/B,SAAG,gBAAgB,OAAO;AAC1B,SAAG,gBAAgB,uBAAuB;AAAA,IAC5C,CAAC;AAED,oBAAA;AAAA,EACF;AAOA,WAAS,0BAAyC;AAChD,UAAM,QAAuB,CAAA;AAE7B,UAAM,cAAc,SAAS,iBAA8B,GAAG;AAC9D,eAAW,MAAM,aAAa;AAC5B,UAAI,GAAG,QAAQ,iBAAiB,KAAK,GAAG,QAAQ,kBAAkB,EAAG;AACrE,UAAI,GAAG,aAAa,uBAAuB,EAAG;AAE9C,UAAI,GAAG,cAAc,OAAO,GAAG,eAAe,IAAK;AACnD,YAAM,QAAQ,iBAAiB,EAAE;AACjC,YAAM,KAAK,MAAM;AACjB,UAAI,CAAC,MAAM,OAAO,OAAQ;AAE1B,YAAM,WAAW,GAAG,MAAM,4BAA4B;AACtD,UAAI,CAAC,SAAU;AAEf,UAAI,SAAS,CAAC,EAAE,WAAW,gBAAgB,EAAG;AAE9C,UAAI,GAAG,aAAa,MAAM,MAAM,SAAS,GAAG,aAAa,YAAY,EAAG;AACxE,YAAM,KAAK,EAAE;AAAA,IACf;AACA,WAAO;AAAA,EACT;AAEA,WAAS,sBAAsB,IAAgC;AAC7D,UAAM,KAAK,iBAAiB,EAAE,EAAE;AAChC,UAAM,QAAQ,IAAI,MAAM,4BAA4B;AACpD,WAAO,QAAQ,MAAM,CAAC,IAAI;AAAA,EAC5B;AAEA,WAAS,WAAW,IAAiB,SAAiB;AACpD,OAAG,aAAa,QAAQ,KAAK;AAC7B,OAAG,aAAa,cAAc,OAAO;AACrC,OAAG,aAAa,SAAS,OAAO;AAChC,OAAG,aAAa,yBAAyB,MAAM;AAC/C,QAAI,QAAS,cAAa,IAAI,OAAO;AAAA,EACvC;AAEA,iBAAe,iBAAiB;AAC9B,QAAI,CAAC,aAAa,CAAC,QAAS;AAC5B,QAAI,uBAAuB,QAAQ;AACjC,UAAK,OAAe,mBAAmB;AACrC,gBAAQ,KAAK,wFAAwF;AAAA,MACvG;AACA;AAAA,IACF;AACA,UAAM,aAAa,wBAAA;AACnB,eAAW,MAAM,YAAY;AAC3B,UAAI,CAAC,QAAS;AACd,YAAM,MAAM,sBAAsB,EAAE;AACpC,UAAI,CAAC,IAAK;AAEV,YAAM,SAAS,MAAM,iBAAiB,GAAG;AACzC,UAAI,QAAQ;AACV,mBAAW,IAAI,MAAM;AACrB;AAAA,MACF;AAEA,UAAI;AACF,cAAM,MAAM,gBAAgB,EAAE;AAC9B,cAAM,MAAM,MAAM,UAAU,gBAAgB,KAAK,KAAK,MAAM;AAC5D,YAAI,OAAO,SAAS;AAClB,qBAAW,IAAI,GAAG;AAClB,2BAAiB,KAAK,KAAK,KAAA,CAAM,EAAE,MAAM,MAAM;AAAA,UAAC,CAAC;AACjD,cAAI,QAAS,wBAAuB,SAAS,UAAU,KAAK,KAAK,MAAM;AAAA,QACzE;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,KAAK,8CAA8C,KAAK,GAAG;AAAA,MACrE;AAAA,IACF;AAAA,EACF;AAEA,WAAS,gBAAgB,IAAyB;AAChD,UAAM,QAAkB,CAAA;AAExB,UAAM,KAAK,aAAa,GAAG,QAAQ,YAAA,CAAa,GAAG;AACnD,QAAI,GAAG,UAAW,OAAM,KAAK,UAAU,GAAG,SAAS,EAAE;AAErD,UAAM,OAAO,GAAG,aAAa,OAAO,MAAM,GAAG,GAAG;AAChD,QAAI,KAAM,OAAM,KAAK,iBAAiB,IAAI,EAAE;AAE5C,UAAM,UAAU,GAAG,cAAc,YAAY;AAC7C,QAAI,SAAS,aAAa,KAAA,EAAQ,OAAM,KAAK,YAAY,QAAQ,YAAY,KAAA,CAAM,EAAE;AACrF,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,iBAAe,cAAc;AAC3B,QAAI,kBAAkB,CAAC,WAAW,CAAC,UAAW;AAC9C,qBAAiB;AACjB,UAAM,cAAc;AAGpB,UAAM,WAA+B,CAAA;AACrC,eAAW,OAAO,kBAAkB;AAClC,UAAI,CAAC,SAAS;AAAE,yBAAiB;AAAO;AAAA,MAAQ;AAChD,UAAI,gBAAgB,IAAI,GAAG,EAAG;AAC9B,YAAM,MAAM,YAAY,GAAG;AAC3B,YAAM,SAAS,MAAM,iBAAiB,GAAG;AACzC,UAAI,QAAQ;AACV,qBAAa,KAAK,MAAM;AAAA,MAC1B,OAAO;AACL,iBAAS,KAAK,GAAG;AAAA,MACnB;AAAA,IACF;AAEA,QAAI,CAAC,SAAS;AAAE,uBAAiB;AAAO;AAAA,IAAQ;AAChD,QAAI,CAAC,SAAS,QAAQ;AAAE,uBAAiB;AAAO;AAAA,IAAQ;AAKxD,QAAI,uBAAuB,QAAQ;AACjC,UAAK,OAAe,mBAAmB;AACrC,gBAAQ;AAAA,UACN,2CAA2C,SAAS,MAAM;AAAA,QAAA;AAAA,MAG9D;AACA,uBAAiB;AACjB;AAAA,IACF;AAGA,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,aAAa;AACrD,UAAI,CAAC,SAAS;AAAE,yBAAiB;AAAO;AAAA,MAAQ;AAChD,YAAM,QAAQ,SAAS,MAAM,GAAG,IAAI,WAAW;AAC/C,YAAM,QAAQ,IAAI,MAAM,IAAI,OAAO,QAAQ;AACzC,YAAI,CAAC,QAAS;AACd,YAAI;AACF,gBAAM,MAAM,YAAY,GAAG;AAC3B,gBAAM,MAAM,mBAAmB,GAAG;AAClC,gBAAM,MAAM,MAAM,UAAW,gBAAgB,KAAK,KAAK,MAAM;AAC7D,cAAI,OAAO,SAAS;AAClB,yBAAa,KAAK,GAAG;AACrB,6BAAiB,KAAK,KAAK,KAAA,CAAM,EAAE,MAAM,MAAM;AAAA,YAAC,CAAC;AACjD,gBAAI,QAAS,wBAAuB,SAAS,UAAU,KAAK,KAAK,MAAM;AAAA,UACzE;AAAA,QACF,SAAS,KAAK;AACZ,kBAAQ,KAAK,2CAA2C,YAAY,GAAG,GAAG,GAAG;AAAA,QAC/E;AAAA,MACF,CAAC,CAAC;AAAA,IACJ;AAEA,qBAAiB;AAAA,EACnB;AAEA,iBAAe,eAAe,KAAuB;AACnD,QAAI,CAAC,aAAa,CAAC,QAAS;AAC5B,UAAM,MAAM,YAAY,GAAG;AAC3B,UAAM,SAAS,MAAM,iBAAiB,GAAG;AACzC,QAAI,QAAQ;AAAE,mBAAa,KAAK,MAAM;AAAG;AAAA,IAAQ;AAGjD,QAAI,uBAAuB,OAAQ;AAEnC,QAAI;AACF,YAAM,MAAM,mBAAmB,GAAG;AAClC,YAAM,MAAM,MAAM,UAAU,gBAAgB,KAAK,KAAK,MAAM;AAC5D,UAAI,OAAO,SAAS;AAClB,qBAAa,KAAK,GAAG;AACrB,yBAAiB,KAAK,KAAK,KAAA,CAAM,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AACjD,YAAI,QAAS,wBAAuB,SAAS,UAAU,KAAK,KAAK,MAAM;AAAA,MACzE;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,2CAA2C,KAAK,GAAG;AAAA,IAClE;AAAA,EACF;AAMA,WAAS,iBAAiB,KAAuB;AAC/C,QAAI,CAAC,QAAS;AACd,QAAI,CAAC,aAAa,GAAG,EAAG;AACxB,QAAI,iBAAiB,SAAS,GAAG,EAAG;AAEpC,aAAS,aAAa;AACpB,UAAI,CAAC,WAAW,iBAAiB,SAAS,GAAG,EAAG;AAChD,UAAI,IAAI,eAAe,MAAM,IAAI,gBAAgB,GAAI;AAErD,UAAI,aAAa,GAAG,GAAG;AACrB,yBAAiB,KAAK,GAAG;AACzB,uBAAe,GAAG;AAAA,MACpB,OAAO;AAEL,cAAM,MAAM,IAAI,aAAa,KAAK;AAClC,YAAI,OAAO,IAAI,QAAQ;AACrB,cAAI,CAAC,IAAI,aAAa,OAAO,GAAG;AAC9B,gBAAI,aAAa,SAAS,GAAG;AAC7B,gBAAI,aAAa,wBAAwB,MAAM;AAAA,UACjD;AACA,uBAAa,KAAK,IAAI,MAAM;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAEA,QAAI,IAAI,YAAY,IAAI,eAAe,EAAG,YAAA;AAAA,aACjC,iBAAiB,QAAQ,YAAY,EAAE,MAAM,MAAM;AAAA,EAC9D;AAMA,WAAS,WAAW;AAClB,QAAI,QAAS;AACb,cAAU;AAGV,aAAS,iBAAmC,gCAAgC,EAAE,QAAQ,CAAC,QAAQ;AAC7F,UAAI,IAAI,QAAQ,iBAAiB,EAAG;AACpC,UAAI,CAAC,gBAAgB,IAAI,GAAG,GAAG;AAC7B,wBAAgB,IAAI,KAAK,EAAE,cAAc,IAAI,aAAa,KAAK,KAAK,IAAI;AACxE,yBAAiB,KAAK,GAAG;AAAA,MAC3B;AAAA,IACF,CAAC;AAGD,UAAM,UAAU,kBAAA;AAChB,eAAW,OAAO,SAAS;AACzB,UAAI,CAAC,iBAAiB,SAAS,GAAG,GAAG;AACnC,yBAAiB,KAAK,GAAG;AAAA,MAC3B;AAAA,IACF;AAGA,gBAAA;AACA,mBAAA;AAGA,2BAAA;AAGA,yBAAA;AAGA,aAAS,iBAAmC,KAAK,EAAE,QAAQ,CAAC,QAAQ;AAClE,UAAI,CAAC,IAAI,SAAU,kBAAiB,GAAG;AAAA,IACzC,CAAC;AAGD,eAAW,SAAS,CAAC,KAAM,KAAM,GAAK,GAAG;AACvC,iBAAW,MAAM;AACf,YAAI,SAAS;AACX,mBAAS,iBAAmC,KAAK,EAAE,QAAQ,gBAAgB;AAC3E,iCAAA;AACA,+BAAA;AAAA,QACF;AAAA,MACF,GAAG,KAAK;AAAA,IACV;AAGA,kBAAc,IAAI,iBAAiB,CAAC,cAAc;AAChD,iBAAW,KAAK,WAAW;AACzB,mBAAW,QAAQ,EAAE,YAAY;AAC/B,cAAI,gBAAgB,iBAAkB,kBAAiB,IAAI;AAAA,mBAClD,gBAAgB,aAAa;AACpC,iBAAK,iBAAmC,KAAK,EAAE,QAAQ,gBAAgB;AAAA,UACzE;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AACD,gBAAY,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,MAAM;AAAA,EACvE;AAEA,WAAS,aAAa;AACpB,cAAU;AACV,qBAAiB;AACjB,iBAAa,WAAA;AACb,kBAAc;AAGd,iBAAA;AACA,uBAAmB,CAAA;AAAA,EACrB;AAGA,0BAAwB,EAAE,SAAS,UAAU,MAAM,aAAa,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AAEhF,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM,MAAO,SAAS,qBAAqB;AAAA,IAC3C,aAAa,SAAS,4EAA4E;AAAA,IAClG,MAAM;AAAA,IACN,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,UAAU,OAAqB;AAAA,MAC7B,IAAI;AAAA,MACJ;AAAA,MACA,OAAO;AAAA,QACL,cAAc,iBAAiB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,IAAI,GAAG,CAAC,EAAE;AAAA,QAC1E,gBAAgB,gBAAgB;AAAA,MAAA;AAAA,IAClC;AAAA,EACF;AAEJ;"}
@@ -9,6 +9,21 @@ function createAnimationStopModule() {
9
9
  let originalAnimate = null;
10
10
  let pausedVideos = [];
11
11
  let gifOriginals = /* @__PURE__ */ new Map();
12
+ let debounceTimer = null;
13
+ let delayedTimers = [];
14
+ function isWidgetElement(el) {
15
+ try {
16
+ let node = el;
17
+ while (node) {
18
+ if (node.id === "accessify-root") return true;
19
+ const parent = node.parentNode || node.host || null;
20
+ if (parent === node) break;
21
+ node = parent;
22
+ }
23
+ } catch {
24
+ }
25
+ return false;
26
+ }
12
27
  const VISUAL_ONLY_PROPS = /* @__PURE__ */ new Set([
13
28
  "transform",
14
29
  "scale",
@@ -52,17 +67,8 @@ function createAnimationStopModule() {
52
67
  if (!enabled) {
53
68
  return originalAnimate.call(this, keyframes, options);
54
69
  }
55
- try {
56
- let node = this;
57
- while (node) {
58
- if (node.id === "accessify-root") {
59
- return originalAnimate.call(this, keyframes, options);
60
- }
61
- const parent = node.parentNode || node.host;
62
- if (parent === node) break;
63
- node = parent;
64
- }
65
- } catch {
70
+ if (isWidgetElement(this)) {
71
+ return originalAnimate.call(this, keyframes, options);
66
72
  }
67
73
  const visualOnly = isVisualOnlyKeyframes(keyframes);
68
74
  let opts;
@@ -102,7 +108,9 @@ function createAnimationStopModule() {
102
108
  const style = document.createElement("style");
103
109
  style.id = STYLE_ID;
104
110
  style.textContent = `
105
- *, *::before, *::after {
111
+ *:not(#accessify-root):not(#accessify-root *),
112
+ *:not(#accessify-root):not(#accessify-root *)::before,
113
+ *:not(#accessify-root):not(#accessify-root *)::after {
106
114
  animation-duration: 0.001ms !important;
107
115
  animation-iteration-count: 1 !important;
108
116
  animation-delay: 0s !important;
@@ -115,8 +123,7 @@ function createAnimationStopModule() {
115
123
  }
116
124
  /* Neutralize interaction transforms (hover zoom, click scale, focus
117
125
  lift). Without this, CSS like \`.card:hover { transform: scale(1.05) }\`
118
- still visibly changes the element — just instantly. Users who
119
- disable animations expect NO motion including the end-state. */
126
+ still visibly changes the element — just instantly. */
120
127
  *:not(#accessify-root):not(#accessify-root *):hover,
121
128
  *:not(#accessify-root):not(#accessify-root *):focus,
122
129
  *:not(#accessify-root):not(#accessify-root *):focus-within,
@@ -139,13 +146,7 @@ function createAnimationStopModule() {
139
146
  try {
140
147
  const target = anim.effect?.target;
141
148
  if (!target) return false;
142
- let node = target;
143
- while (node) {
144
- if (node.id === "accessify-root") return true;
145
- const parent = node.parentNode || node.host;
146
- if (parent === node) break;
147
- node = parent;
148
- }
149
+ return isWidgetElement(target);
149
150
  } catch {
150
151
  }
151
152
  return false;
@@ -191,30 +192,26 @@ function createAnimationStopModule() {
191
192
  function forceHiddenElementsVisible() {
192
193
  const viewH = window.innerHeight;
193
194
  const margin = viewH * 1.5;
194
- const all = document.querySelectorAll("*");
195
- for (const el of all) {
196
- if (el.tagName === "SCRIPT" || el.tagName === "STYLE" || el.tagName === "NOSCRIPT" || el.tagName === "META" || el.tagName === "LINK") continue;
197
- if (el.closest("#accessify-root") || el.closest("accessify-widget")) continue;
195
+ const candidates = document.querySelectorAll(
196
+ '[style*="opacity"]:not(#accessify-root):not(#accessify-root *),[style*="transform"]:not(#accessify-root):not(#accessify-root *),[style*="visibility"]:not(#accessify-root):not(#accessify-root *),[style*="clip-path"]:not(#accessify-root):not(#accessify-root *),[data-framer-appear-id]:not(#accessify-root):not(#accessify-root *)'
197
+ );
198
+ for (const el of candidates) {
199
+ if (el.tagName === "SCRIPT" || el.tagName === "STYLE" || el.tagName === "NOSCRIPT") continue;
198
200
  if (el.dataset.a11yOrigStyle) continue;
201
+ const rect = el.getBoundingClientRect();
202
+ if (rect.top > viewH + margin || rect.bottom < -margin) continue;
199
203
  const computed = window.getComputedStyle(el);
200
204
  if (computed.display === "none") continue;
201
- const rect = el.getBoundingClientRect();
202
- if (rect.top > viewH + margin) continue;
203
- if (rect.bottom < -margin) continue;
204
205
  const inline = el.style;
205
206
  let needsFix = false;
206
207
  const originals = {};
207
208
  const opacityVal = parseFloat(computed.opacity);
208
- if (opacityVal < 0.1 && inline.opacity !== "") {
209
- originals.opacity = inline.opacity;
210
- el.style.opacity = "1";
211
- needsFix = true;
212
- } else if (opacityVal < 0.1 && el.hasAttribute("data-framer-appear-id")) {
209
+ if (opacityVal < 0.1 && (inline.opacity !== "" || el.hasAttribute("data-framer-appear-id"))) {
213
210
  originals.opacity = inline.opacity || "";
214
211
  el.style.opacity = "1";
215
212
  needsFix = true;
216
213
  }
217
- if (inline.transform && /translate[XY]\([^0]/.test(inline.transform)) {
214
+ if (inline.transform && /translate[XY3d]\([^0]/.test(inline.transform)) {
218
215
  originals.transform = inline.transform;
219
216
  el.style.transform = "none";
220
217
  needsFix = true;
@@ -251,8 +248,9 @@ function createAnimationStopModule() {
251
248
  });
252
249
  }
253
250
  function freezeScrollAnimations() {
254
- document.querySelectorAll("[style]").forEach((el) => {
255
- if (el.closest("#accessify-root") || el.closest("accessify-widget")) return;
251
+ document.querySelectorAll(
252
+ '[style*="transform"]:not(#accessify-root):not(#accessify-root *),[style*="opacity"]:not(#accessify-root):not(#accessify-root *)'
253
+ ).forEach((el) => {
256
254
  if (el.dataset.a11yFrozenStyle) return;
257
255
  const s = el.style;
258
256
  if (s.transform || s.opacity) {
@@ -388,6 +386,17 @@ function createAnimationStopModule() {
388
386
  }
389
387
  });
390
388
  }
389
+ function debouncedRescan() {
390
+ if (debounceTimer) clearTimeout(debounceTimer);
391
+ debounceTimer = setTimeout(() => {
392
+ if (!enabled) return;
393
+ finishAllAnimations();
394
+ forceHiddenElementsVisible();
395
+ pauseAllVideos();
396
+ freezeAllGifs();
397
+ pauseSVG();
398
+ }, 100);
399
+ }
391
400
  function setupObserver() {
392
401
  if (mutationObserver) return;
393
402
  mutationObserver = new MutationObserver((mutations) => {
@@ -400,11 +409,7 @@ function createAnimationStopModule() {
400
409
  }
401
410
  }
402
411
  if (hasNewContent) {
403
- finishAllAnimations();
404
- forceHiddenElementsVisible();
405
- pauseAllVideos();
406
- freezeAllGifs();
407
- pauseSVG();
412
+ debouncedRescan();
408
413
  }
409
414
  });
410
415
  mutationObserver.observe(document.body, { childList: true, subtree: true });
@@ -412,13 +417,17 @@ function createAnimationStopModule() {
412
417
  function teardownObserver() {
413
418
  mutationObserver?.disconnect();
414
419
  mutationObserver = null;
420
+ if (debounceTimer) {
421
+ clearTimeout(debounceTimer);
422
+ debounceTimer = null;
423
+ }
415
424
  }
416
425
  function startPeriodicScan() {
417
426
  if (scanInterval) return;
418
427
  scanInterval = setInterval(() => {
419
428
  if (!enabled) return;
420
429
  finishAllAnimations();
421
- }, 500);
430
+ }, 2e3);
422
431
  }
423
432
  function stopPeriodicScan() {
424
433
  if (scanInterval) {
@@ -442,20 +451,32 @@ function createAnimationStopModule() {
442
451
  stopMarquees();
443
452
  setupObserver();
444
453
  startPeriodicScan();
445
- for (const delay of [50, 200, 500, 1e3, 2e3, 4e3]) {
446
- setTimeout(() => {
447
- if (!enabled) return;
448
- finishAllAnimations();
449
- forceHiddenElementsVisible();
450
- freezeScrollAnimations();
451
- pauseAllVideos();
452
- freezeAllGifs();
453
- }, delay);
454
- }
454
+ const scheduleIdle = typeof requestIdleCallback === "function" ? (fn, timeout) => {
455
+ const id = setTimeout(() => {
456
+ }, timeout + 500);
457
+ requestIdleCallback(() => {
458
+ clearTimeout(id);
459
+ if (enabled) fn();
460
+ }, { timeout });
461
+ return id;
462
+ } : (fn, timeout) => setTimeout(() => {
463
+ if (enabled) fn();
464
+ }, timeout);
465
+ const rescan = () => {
466
+ finishAllAnimations();
467
+ forceHiddenElementsVisible();
468
+ freezeScrollAnimations();
469
+ pauseAllVideos();
470
+ freezeAllGifs();
471
+ };
472
+ delayedTimers.push(scheduleIdle(rescan, 300));
473
+ delayedTimers.push(scheduleIdle(rescan, 2e3));
455
474
  localStorage.setItem(STORAGE_KEY, "true");
456
475
  }
457
476
  function deactivate() {
458
477
  enabled = false;
478
+ for (const t of delayedTimers) clearTimeout(t);
479
+ delayedTimers = [];
459
480
  stopPeriodicScan();
460
481
  teardownObserver();
461
482
  restoreAnimate();
@@ -487,4 +508,4 @@ function createAnimationStopModule() {
487
508
  export {
488
509
  createAnimationStopModule as default
489
510
  };
490
- //# sourceMappingURL=animation-stop-DrDe9Q9n.js.map
511
+ //# sourceMappingURL=animation-stop-BU0qc2Qp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation-stop-BU0qc2Qp.js","sources":["../src/features/animation-stop.ts"],"sourcesContent":["import type { FeatureModule, FeatureState } from '../types';\n\n/**\n * Animation Stop – V5 (Performance-Safe Rewrite)\n *\n * Layer 1: CSS injection — kill all CSS animations/transitions via 0.001ms duration\n * Explicitly excludes the widget host element (#accessify-root).\n * Layer 2: Web Animations API — finish() all running WAAPI animations (Framer Motion etc.)\n * Layer 3: JS library detection — GSAP globalTimeline, inline-style freeze for rAF-based libs\n * Layer 4: Media — pause videos, freeze GIFs, stop SVG SMIL, stop marquees\n *\n * + MutationObserver for dynamic content (debounced to avoid feedback loops)\n * + Periodic re-scan (every 2s) for frameworks that create new animations\n *\n * V5 changes vs V4:\n * - forceHiddenElementsVisible() uses targeted selectors instead of querySelectorAll('*')\n * - All heavy operations debounced/throttled to prevent layout thrashing\n * - Reduced delayed re-scans from 6 to 2 with requestIdleCallback\n * - MutationObserver callback debounced (100ms)\n * - Periodic scan interval increased from 500ms to 2000ms\n * - CSS rule explicitly excludes #accessify-root and its subtree\n *\n * DOES NOT:\n * - Monkey-patch IntersectionObserver (breaks lazy loading)\n * - Override requestAnimationFrame (breaks entire page)\n * - Set opacity:1 !important via CSS (breaks modals/hidden elements)\n * - Use animation:none or transition:none (breaks JS events)\n */\nexport default function createAnimationStopModule(): FeatureModule {\n let enabled = false;\n const STYLE_ID = 'a11y-stop-animations';\n const STORAGE_KEY = 'accessify-animation-stop';\n\n // --- State ---\n let mutationObserver: MutationObserver | null = null;\n let scanInterval: ReturnType<typeof setInterval> | null = null;\n let scrollHandler: (() => void) | null = null;\n let originalVideoPlay: typeof HTMLVideoElement.prototype.play | null = null;\n let originalAnimate: typeof Element.prototype.animate | null = null;\n let pausedVideos: HTMLVideoElement[] = [];\n let gifOriginals = new Map<HTMLImageElement, string>();\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n let delayedTimers: ReturnType<typeof setTimeout>[] = [];\n\n // =========================================================================\n // Helpers\n // =========================================================================\n\n /** Check if an element belongs to the Accessify widget. */\n function isWidgetElement(el: Element | Node | null): boolean {\n try {\n let node: Node | null = el;\n while (node) {\n if ((node as Element).id === 'accessify-root') return true;\n const parent: Node | null =\n (node as Node).parentNode ||\n ((node as unknown as ShadowRoot).host as Node | null) ||\n null;\n if (parent === node) break;\n node = parent;\n }\n } catch { /* ignore */ }\n return false;\n }\n\n // =========================================================================\n // Layer 0: Element.prototype.animate() intercept\n // =========================================================================\n\n const VISUAL_ONLY_PROPS = new Set([\n 'transform', 'scale', 'rotate', 'translate',\n 'filter', 'backdropFilter', 'backdrop-filter',\n 'webkitTransform', 'webkitFilter', '-webkit-transform', '-webkit-filter',\n 'offset', 'easing', 'composite',\n ]);\n\n function isVisualOnlyKeyframes(\n keyframes: Keyframe[] | PropertyIndexedKeyframes | null,\n ): boolean {\n if (!keyframes) return false;\n try {\n if (Array.isArray(keyframes)) {\n for (const kf of keyframes) {\n if (!kf || typeof kf !== 'object') return false;\n for (const key of Object.keys(kf)) {\n if (!VISUAL_ONLY_PROPS.has(key)) return false;\n }\n }\n return true;\n }\n for (const key of Object.keys(keyframes)) {\n if (!VISUAL_ONLY_PROPS.has(key)) return false;\n }\n return true;\n } catch {\n return false;\n }\n }\n\n function patchAnimate() {\n if (originalAnimate) return;\n originalAnimate = Element.prototype.animate;\n\n Element.prototype.animate = function (\n this: Element,\n keyframes: Keyframe[] | PropertyIndexedKeyframes | null,\n options?: number | KeyframeAnimationOptions,\n ): Animation {\n if (!enabled) {\n return originalAnimate!.call(this, keyframes, options);\n }\n\n // Never interfere with the widget's own animations.\n if (isWidgetElement(this)) {\n return originalAnimate!.call(this, keyframes, options);\n }\n\n const visualOnly = isVisualOnlyKeyframes(keyframes);\n\n let opts: KeyframeAnimationOptions;\n if (typeof options === 'number') {\n opts = { duration: 0.001, fill: 'forwards' as FillMode };\n } else {\n opts = {\n ...(options || {}),\n duration: 0.001,\n delay: 0,\n iterations: 1,\n fill: 'forwards' as FillMode,\n };\n delete (opts as any).iterationStart;\n delete (opts as any).endDelay;\n }\n\n const anim = originalAnimate!.call(this, keyframes, opts);\n try {\n if (visualOnly) {\n anim.cancel();\n } else {\n anim.finish();\n }\n } catch { /* ignore */ }\n return anim;\n };\n }\n\n function restoreAnimate() {\n if (originalAnimate) {\n Element.prototype.animate = originalAnimate;\n originalAnimate = null;\n }\n }\n\n // =========================================================================\n // Layer 1: CSS Injection\n //\n // The universal rule kills all CSS-driven animation/transition on the page.\n // Shadow DOM isolates the widget internals, but we also explicitly exclude\n // #accessify-root (the host element) for belt-and-suspenders safety.\n // =========================================================================\n\n function injectStyles() {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n *:not(#accessify-root):not(#accessify-root *),\n *:not(#accessify-root):not(#accessify-root *)::before,\n *:not(#accessify-root):not(#accessify-root *)::after {\n animation-duration: 0.001ms !important;\n animation-iteration-count: 1 !important;\n animation-delay: 0s !important;\n animation-fill-mode: forwards !important;\n transition-duration: 0.001ms !important;\n transition-delay: 0s !important;\n scroll-behavior: auto !important;\n animation-timeline: auto !important;\n scroll-timeline: none !important;\n }\n /* Neutralize interaction transforms (hover zoom, click scale, focus\n lift). Without this, CSS like \\`.card:hover { transform: scale(1.05) }\\`\n still visibly changes the element — just instantly. */\n *:not(#accessify-root):not(#accessify-root *):hover,\n *:not(#accessify-root):not(#accessify-root *):focus,\n *:not(#accessify-root):not(#accessify-root *):focus-within,\n *:not(#accessify-root):not(#accessify-root *):focus-visible,\n *:not(#accessify-root):not(#accessify-root *):active {\n transform: none !important;\n scale: 1 !important;\n rotate: 0deg !important;\n translate: 0 0 !important;\n filter: none !important;\n -webkit-filter: none !important;\n }\n `;\n document.head.appendChild(style);\n }\n\n function removeStyles() {\n document.getElementById(STYLE_ID)?.remove();\n }\n\n // =========================================================================\n // Layer 2: Web Animations API — finish all WAAPI animations\n // =========================================================================\n\n function isWidgetAnimation(anim: Animation): boolean {\n try {\n const target = (anim.effect as any)?.target as Element | null;\n if (!target) return false;\n return isWidgetElement(target);\n } catch { /* ignore */ }\n return false;\n }\n\n function finishAllAnimations() {\n try {\n const animations = document.getAnimations?.();\n if (!animations) return;\n for (const anim of animations) {\n if (isWidgetAnimation(anim)) continue;\n try {\n anim.finish();\n } catch {\n try { anim.cancel(); } catch { /* ignore */ }\n }\n }\n } catch { /* getAnimations not supported */ }\n }\n\n // =========================================================================\n // Layer 3: JS animation library detection + inline style freeze\n //\n // V5: Uses TARGETED selectors instead of querySelectorAll('*') to avoid\n // catastrophic layout thrashing. Only processes elements that show signs\n // of animation-driven hiding (inline opacity/transform/visibility/clip).\n // =========================================================================\n\n function patchGSAP() {\n const g = (window as any).gsap;\n if (g?.globalTimeline) {\n try {\n g.globalTimeline.timeScale(0);\n (window as any)._a11yGsapPatched = true;\n } catch { /* ignore */ }\n }\n }\n\n function restoreGSAP() {\n const g = (window as any).gsap;\n if ((window as any)._a11yGsapPatched && g?.globalTimeline) {\n try {\n g.globalTimeline.timeScale(1);\n delete (window as any)._a11yGsapPatched;\n } catch { /* ignore */ }\n }\n }\n\n /**\n * Force hidden-by-animation elements visible.\n *\n * V5: Instead of scanning ALL elements (querySelectorAll('*')), we use\n * targeted selectors that match elements likely hidden by animation\n * frameworks (inline opacity, transform, visibility, clip-path).\n * This reduces the scan from 1000+ elements to typically 10-50.\n */\n function forceHiddenElementsVisible() {\n const viewH = window.innerHeight;\n const margin = viewH * 1.5;\n\n // Target elements with inline styles that suggest animation-driven hiding.\n // These selectors match Framer Motion, GSAP, anime.js, AOS, etc.\n const candidates = document.querySelectorAll<HTMLElement>(\n '[style*=\"opacity\"]:not(#accessify-root):not(#accessify-root *),' +\n '[style*=\"transform\"]:not(#accessify-root):not(#accessify-root *),' +\n '[style*=\"visibility\"]:not(#accessify-root):not(#accessify-root *),' +\n '[style*=\"clip-path\"]:not(#accessify-root):not(#accessify-root *),' +\n '[data-framer-appear-id]:not(#accessify-root):not(#accessify-root *)'\n );\n\n for (const el of candidates) {\n if (el.tagName === 'SCRIPT' || el.tagName === 'STYLE' || el.tagName === 'NOSCRIPT') continue;\n if (el.dataset.a11yOrigStyle) continue; // Already processed\n\n // Skip elements far outside viewport\n const rect = el.getBoundingClientRect();\n if (rect.top > viewH + margin || rect.bottom < -margin) continue;\n\n const computed = window.getComputedStyle(el);\n if (computed.display === 'none') continue;\n\n const inline = el.style;\n let needsFix = false;\n const originals: Record<string, string> = {};\n\n // Inline opacity 0 or near-0\n const opacityVal = parseFloat(computed.opacity);\n if (opacityVal < 0.1 && (inline.opacity !== '' || el.hasAttribute('data-framer-appear-id'))) {\n originals.opacity = inline.opacity || '';\n el.style.opacity = '1';\n needsFix = true;\n }\n\n // Inline transform with translate that moves element off-screen\n if (inline.transform && /translate[XY3d]\\([^0]/.test(inline.transform)) {\n originals.transform = inline.transform;\n el.style.transform = 'none';\n needsFix = true;\n }\n\n // Inline visibility hidden\n if (inline.visibility === 'hidden') {\n originals.visibility = inline.visibility;\n el.style.visibility = 'visible';\n needsFix = true;\n }\n\n // Inline clip-path that hides element\n if (inline.clipPath && inline.clipPath !== 'none') {\n originals.clipPath = inline.clipPath;\n el.style.clipPath = 'none';\n needsFix = true;\n }\n\n if (needsFix) {\n el.dataset.a11yOrigStyle = JSON.stringify(originals);\n }\n }\n }\n\n function restoreHiddenElements() {\n document.querySelectorAll<HTMLElement>('[data-a11y-orig-style]').forEach(el => {\n try {\n const orig: Record<string, string> = JSON.parse(el.dataset.a11yOrigStyle || '{}');\n for (const [prop, val] of Object.entries(orig)) {\n if (val === '') {\n el.style.removeProperty(prop);\n } else {\n (el.style as any)[prop] = val;\n }\n }\n } catch { /* malformed JSON */ }\n delete el.dataset.a11yOrigStyle;\n });\n }\n\n /**\n * Freeze inline-animated styles so scroll-handlers can't update them.\n */\n function freezeScrollAnimations() {\n document.querySelectorAll<HTMLElement>(\n '[style*=\"transform\"]:not(#accessify-root):not(#accessify-root *),' +\n '[style*=\"opacity\"]:not(#accessify-root):not(#accessify-root *)'\n ).forEach(el => {\n if (el.dataset.a11yFrozenStyle) return;\n const s = el.style;\n if (s.transform || s.opacity) {\n el.dataset.a11yFrozenStyle = JSON.stringify({\n transform: s.transform || '',\n opacity: s.opacity || '',\n });\n }\n });\n\n if (!scrollHandler) {\n scrollHandler = () => {\n if (!enabled) return;\n document.querySelectorAll<HTMLElement>('[data-a11y-frozen-style]').forEach(el => {\n try {\n const frozen = JSON.parse(el.dataset.a11yFrozenStyle || '{}');\n if (frozen.transform && el.style.transform !== frozen.transform) {\n el.style.transform = frozen.transform;\n }\n } catch { /* ignore */ }\n });\n };\n window.addEventListener('scroll', scrollHandler, { passive: true, capture: true });\n }\n }\n\n function unfreezeScrollAnimations() {\n if (scrollHandler) {\n window.removeEventListener('scroll', scrollHandler, true);\n scrollHandler = null;\n }\n document.querySelectorAll<HTMLElement>('[data-a11y-frozen-style]').forEach(el => {\n delete el.dataset.a11yFrozenStyle;\n });\n }\n\n // =========================================================================\n // Layer 4: Media\n // =========================================================================\n\n function pauseAllVideos() {\n document.querySelectorAll<HTMLVideoElement>('video').forEach(v => {\n if (!v.paused) {\n v.dataset.a11yPaused = 'true';\n v.pause();\n pausedVideos.push(v);\n }\n });\n }\n\n function interceptVideoPlay() {\n if (originalVideoPlay) return;\n originalVideoPlay = HTMLVideoElement.prototype.play;\n HTMLVideoElement.prototype.play = function () {\n if (enabled) return Promise.resolve();\n return originalVideoPlay!.call(this);\n };\n }\n\n function restoreVideoPlay() {\n if (originalVideoPlay) {\n HTMLVideoElement.prototype.play = originalVideoPlay;\n originalVideoPlay = null;\n }\n }\n\n function resumeAllVideos() {\n restoreVideoPlay();\n document.querySelectorAll<HTMLVideoElement>('video[data-a11y-paused]').forEach(v => {\n try { v.play(); } catch { /* gone */ }\n delete v.dataset.a11yPaused;\n });\n pausedVideos = [];\n }\n\n function freezeGif(img: HTMLImageElement) {\n const src = (img.currentSrc || img.src || '').toLowerCase();\n if (!src.match(/\\.gif(\\?|$)/i)) return;\n if (gifOriginals.has(img)) return;\n\n const doFreeze = () => {\n try {\n const w = img.naturalWidth || img.width;\n const h = img.naturalHeight || img.height;\n if (w === 0 || h === 0) return;\n const c = document.createElement('canvas');\n c.width = w; c.height = h;\n const ctx = c.getContext('2d');\n if (!ctx) return;\n ctx.drawImage(img, 0, 0);\n gifOriginals.set(img, img.src);\n img.src = c.toDataURL('image/png');\n } catch { /* CORS */ }\n };\n\n if (img.complete && img.naturalWidth > 0) doFreeze();\n else img.addEventListener('load', doFreeze, { once: true });\n }\n\n function freezeAllGifs() {\n document.querySelectorAll<HTMLImageElement>('img').forEach(freezeGif);\n }\n\n function restoreAllGifs() {\n for (const [img, src] of gifOriginals) {\n try { img.src = src; } catch { /* gone */ }\n }\n gifOriginals.clear();\n }\n\n function pauseSVG() {\n document.querySelectorAll('svg').forEach(s => {\n try { (s as any).pauseAnimations?.(); } catch { /* ignore */ }\n });\n }\n\n function resumeSVG() {\n document.querySelectorAll('svg').forEach(s => {\n try { (s as any).unpauseAnimations?.(); } catch { /* ignore */ }\n });\n }\n\n function stopMarquees() {\n document.querySelectorAll('marquee').forEach(m => {\n try { (m as any).stop?.(); } catch { /* ignore */ }\n });\n }\n\n function startMarquees() {\n document.querySelectorAll('marquee').forEach(m => {\n try { (m as any).start?.(); } catch { /* ignore */ }\n });\n }\n\n // =========================================================================\n // MutationObserver — dynamic content (debounced)\n // =========================================================================\n\n function debouncedRescan() {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (!enabled) return;\n finishAllAnimations();\n forceHiddenElementsVisible();\n pauseAllVideos();\n freezeAllGifs();\n pauseSVG();\n }, 100);\n }\n\n function setupObserver() {\n if (mutationObserver) return;\n mutationObserver = new MutationObserver(mutations => {\n if (!enabled) return;\n let hasNewContent = false;\n for (const m of mutations) {\n if (m.addedNodes.length > 0) { hasNewContent = true; break; }\n }\n if (hasNewContent) {\n debouncedRescan();\n }\n });\n mutationObserver.observe(document.body, { childList: true, subtree: true });\n }\n\n function teardownObserver() {\n mutationObserver?.disconnect();\n mutationObserver = null;\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n debounceTimer = null;\n }\n }\n\n // =========================================================================\n // Periodic re-scan — frameworks create new animations constantly\n // V5: reduced from 500ms to 2000ms (sufficient for catching new animations)\n // =========================================================================\n\n function startPeriodicScan() {\n if (scanInterval) return;\n scanInterval = setInterval(() => {\n if (!enabled) return;\n finishAllAnimations();\n }, 2000);\n }\n\n function stopPeriodicScan() {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n }\n\n // =========================================================================\n // Lifecycle\n // =========================================================================\n\n function activate() {\n if (enabled) return;\n enabled = true;\n\n // Layer 0: Intercept Element.animate()\n patchAnimate();\n\n // Layer 1: CSS — instant, no layout cost\n injectStyles();\n\n // Layer 2: Kill all currently running WAAPI animations\n finishAllAnimations();\n\n // Layer 3: JS libs + inline style fixes\n patchGSAP();\n forceHiddenElementsVisible();\n freezeScrollAnimations();\n\n // Layer 4: Media\n pauseAllVideos();\n interceptVideoPlay();\n freezeAllGifs();\n pauseSVG();\n stopMarquees();\n\n // Observers\n setupObserver();\n startPeriodicScan();\n\n // V5: Only 2 delayed re-scans (reduced from 6) using requestIdleCallback\n // where available, falling back to setTimeout.\n const scheduleIdle = typeof requestIdleCallback === 'function'\n ? (fn: () => void, timeout: number) => {\n const id = setTimeout(() => { /* fallback if idle never fires */ }, timeout + 500);\n requestIdleCallback(() => { clearTimeout(id); if (enabled) fn(); }, { timeout });\n return id;\n }\n : (fn: () => void, timeout: number) => setTimeout(() => { if (enabled) fn(); }, timeout);\n\n const rescan = () => {\n finishAllAnimations();\n forceHiddenElementsVisible();\n freezeScrollAnimations();\n pauseAllVideos();\n freezeAllGifs();\n };\n\n delayedTimers.push(scheduleIdle(rescan, 300));\n delayedTimers.push(scheduleIdle(rescan, 2000));\n\n localStorage.setItem(STORAGE_KEY, 'true');\n }\n\n function deactivate() {\n enabled = false;\n\n // Clear all delayed timers\n for (const t of delayedTimers) clearTimeout(t);\n delayedTimers = [];\n\n stopPeriodicScan();\n teardownObserver();\n restoreAnimate();\n unfreezeScrollAnimations();\n restoreGSAP();\n restoreHiddenElements();\n startMarquees();\n resumeSVG();\n restoreAllGifs();\n resumeAllVideos();\n removeStyles();\n\n localStorage.removeItem(STORAGE_KEY);\n }\n\n return {\n id: 'animation-stop',\n name: () => 'Stop Animations',\n description: 'Pause all animations, transitions, and auto-playing videos (WCAG 2.3.1)',\n icon: 'animation-stop',\n category: 'visual',\n activate,\n deactivate,\n getState: (): FeatureState => ({ id: 'animation-stop', enabled }),\n setState: (state: { enabled: boolean }) => {\n if (state.enabled) activate();\n else deactivate();\n },\n };\n}\n"],"names":[],"mappings":"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"}