@active-reach/web-sdk 1.15.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +35 -54
  2. package/dist/aegis-sw.js +1 -1
  3. package/dist/aegis.min.js +1 -1
  4. package/dist/aegis.min.js.map +1 -1
  5. package/dist/{analytics-CjLItVo2.mjs → analytics-DblhjFhs.mjs} +66 -3
  6. package/dist/analytics-DblhjFhs.mjs.map +1 -0
  7. package/dist/cdn.d.ts +5 -2
  8. package/dist/cdn.d.ts.map +1 -1
  9. package/dist/chat/AegisChat.d.ts +138 -0
  10. package/dist/chat/AegisChat.d.ts.map +1 -0
  11. package/dist/chat/index.d.ts +3 -0
  12. package/dist/chat/index.d.ts.map +1 -0
  13. package/dist/core/analytics.d.ts +37 -2
  14. package/dist/core/analytics.d.ts.map +1 -1
  15. package/dist/ecommerce/index.d.ts +32 -14
  16. package/dist/ecommerce/index.d.ts.map +1 -1
  17. package/dist/inapp/AegisInAppManager.d.ts +323 -7
  18. package/dist/inapp/AegisInAppManager.d.ts.map +1 -1
  19. package/dist/inapp/devicePairing.d.ts +70 -0
  20. package/dist/inapp/devicePairing.d.ts.map +1 -0
  21. package/dist/inapp/index.d.ts +2 -0
  22. package/dist/inapp/index.d.ts.map +1 -1
  23. package/dist/inapp/renderPreview.d.ts.map +1 -1
  24. package/dist/inapp/renderers/active-web-chat.d.ts +38 -0
  25. package/dist/inapp/renderers/active-web-chat.d.ts.map +1 -0
  26. package/dist/inapp/renderers/carousel-cards.d.ts.map +1 -1
  27. package/dist/inapp/renderers/coachmark-tour.d.ts.map +1 -1
  28. package/dist/inapp/renderers/games.d.ts +27 -0
  29. package/dist/inapp/renderers/games.d.ts.map +1 -0
  30. package/dist/inapp/renderers/index.d.ts +8 -3
  31. package/dist/inapp/renderers/index.d.ts.map +1 -1
  32. package/dist/inapp/renderers/product-recommendation.d.ts +4 -4
  33. package/dist/inapp/renderers/product-recommendation.d.ts.map +1 -1
  34. package/dist/inapp/renderers/progress-bar.d.ts +14 -0
  35. package/dist/inapp/renderers/progress-bar.d.ts.map +1 -1
  36. package/dist/inapp/renderers/sticky-bar.d.ts.map +1 -1
  37. package/dist/inapp/renderers/stories.d.ts +31 -0
  38. package/dist/inapp/renderers/stories.d.ts.map +1 -0
  39. package/dist/inapp/renderers/types.d.ts +73 -2
  40. package/dist/inapp/renderers/types.d.ts.map +1 -1
  41. package/dist/inapp/renderers/video.d.ts +20 -0
  42. package/dist/inapp/renderers/video.d.ts.map +1 -0
  43. package/dist/index.d.ts +5 -3
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +8576 -3169
  46. package/dist/index.js.map +1 -1
  47. package/dist/loyalty/AegisLoyaltyManager.d.ts +120 -0
  48. package/dist/loyalty/AegisLoyaltyManager.d.ts.map +1 -0
  49. package/dist/loyalty/index.d.ts +3 -0
  50. package/dist/loyalty/index.d.ts.map +1 -0
  51. package/dist/push/AegisWebPush.d.ts.map +1 -1
  52. package/dist/push/AegisWebPush.js +13 -2
  53. package/dist/push/AegisWebPush.js.map +1 -1
  54. package/dist/react.js +1 -1
  55. package/dist/runtime/AegisMessageRuntime.d.ts +78 -1
  56. package/dist/runtime/AegisMessageRuntime.d.ts.map +1 -1
  57. package/dist/triggers/ContactScoresFetcher.d.ts +6 -0
  58. package/dist/triggers/ContactScoresFetcher.d.ts.map +1 -1
  59. package/dist/triggers/IntentRuleEvaluator.d.ts +29 -4
  60. package/dist/triggers/IntentRuleEvaluator.d.ts.map +1 -1
  61. package/package.json +7 -6
  62. package/dist/analytics-CjLItVo2.mjs.map +0 -1
  63. package/dist/placements/AegisPlacementManager.d.ts +0 -97
  64. package/dist/placements/AegisPlacementManager.d.ts.map +0 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils/debounce.ts","../src/inapp/renderers/carousel-cards.ts","../src/inapp/renderers/sticky-bar.ts","../src/inapp/renderers/progress-bar.ts","../src/inapp/renderers/coachmark-tour.ts","../src/inapp/renderers/product-recommendation.ts","../src/inapp/AegisInAppManager.ts","../src/inapp/renderPreview.ts","../src/placements/AegisPlacementManager.ts","../src/triggers/TriggerEngine.ts","../src/triggers/IntentRuleEvaluator.ts","../src/triggers/ContactScoresFetcher.ts","../src/core/sdk-config-poller.ts","../src/core/prefetch-bundle-client.ts","../src/inbox/AegisInbox.ts","../src/widgets/AegisWidgetManager.ts","../src/runtime/AegisMessageRuntime.ts","../src/core/bootstrap.ts","../src/index.ts"],"sourcesContent":["export function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n return function debounced(...args: Parameters<T>): void {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n\n timeoutId = setTimeout(() => {\n func(...args);\n timeoutId = null;\n }, wait);\n };\n}\n\nexport function throttle<T extends (...args: any[]) => any>(\n func: T,\n limit: number\n): (...args: Parameters<T>) => void {\n let inThrottle = false;\n\n return function throttled(...args: Parameters<T>): void {\n if (!inThrottle) {\n func(...args);\n inThrottle = true;\n setTimeout(() => {\n inThrottle = false;\n }, limit);\n }\n };\n}\n","/**\n * CarouselCards renderer — a swipeable / autoplaying sequence of product\n * cards. Used for post-purchase upsells, cross-sell, and \"recently viewed\"\n * surfaces. The entire card list is pre-bundled — no network call on\n * trigger; slide advance is pure client state.\n *\n * Data shape (interactive_config, populated at campaign create time and\n * validated server-side):\n * cards: Array<{ image_url?, title, body?, cta_text?, cta_url? }>\n * autoplay_ms?: number // 0 = manual advance only\n * loop?: boolean // wrap to card 0 on last-next\n */\n\nimport type { RenderContext } from './types';\n\ntype Card = {\n image_url?: string;\n title?: string;\n body?: string;\n cta_text?: string;\n cta_url?: string;\n};\n\nconst MAX_CARDS_RENDERED = 10;\n\nexport function renderCarouselCards(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const rawCards = Array.isArray(ic.cards) ? (ic.cards as Card[]) : [];\n const cards = rawCards.slice(0, MAX_CARDS_RENDERED);\n\n if (cards.length === 0) {\n log('carousel_cards rendered with zero cards — skipping', 'warn');\n return;\n }\n\n const autoplay = Number(ic.autoplay_ms) || 0;\n const loop = ic.loop !== false; // default true\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#ffffff');\n const fg = sanitizeColor((campaign.text_color as string) || '#0f172a');\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-carousel-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText = `\n position: fixed; left: 0; right: 0; bottom: 0;\n z-index: 99999; padding: 12px 12px 20px;\n background: rgba(0,0,0,0.12); backdrop-filter: blur(8px);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n `;\n\n const card = document.createElement('div');\n card.style.cssText = `\n background: ${bg}; color: ${fg}; border-radius: 16px;\n box-shadow: 0 8px 20px rgba(0,0,0,0.08); padding: 16px;\n max-width: 520px; margin: 0 auto; position: relative;\n `;\n\n const header = document.createElement('div');\n header.style.cssText = 'display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 12px;';\n\n const headerText = document.createElement('div');\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 700; font-size: 15px; margin-bottom: 2px;';\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.75;';\n headerText.appendChild(title);\n headerText.appendChild(body);\n header.appendChild(headerText);\n\n const closeBtn = document.createElement('button');\n closeBtn.textContent = '✕';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 16px; cursor: pointer; opacity: 0.6; padding: 2px 6px;\n `;\n closeBtn.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n });\n header.appendChild(closeBtn);\n card.appendChild(header);\n\n const track = document.createElement('div');\n track.style.cssText = `\n display: flex; gap: 10px; overflow-x: auto; scroll-snap-type: x mandatory;\n scrollbar-width: none; -ms-overflow-style: none; padding-bottom: 4px;\n `;\n (track.style as unknown as { msOverflowStyle?: string }).msOverflowStyle = 'none';\n track.addEventListener('wheel', (e) => {\n if (Math.abs(e.deltaX) < Math.abs(e.deltaY)) return;\n track.scrollLeft += e.deltaX;\n });\n\n cards.forEach((c, i) => {\n const tile = document.createElement('div');\n tile.setAttribute('data-card-index', String(i));\n tile.style.cssText = `\n flex: 0 0 auto; width: 140px; scroll-snap-align: start;\n background: ${fg}0a; border-radius: 12px; padding: 10px;\n display: flex; flex-direction: column; gap: 6px;\n cursor: ${c.cta_url ? 'pointer' : 'default'};\n `;\n if (c.image_url) {\n const img = document.createElement('img');\n const safe = sanitizeUrl(c.image_url);\n if (safe) {\n img.src = safe;\n img.alt = '';\n img.loading = 'lazy';\n img.style.cssText = 'width: 100%; height: 96px; border-radius: 8px; object-fit: cover;';\n tile.appendChild(img);\n }\n }\n if (c.title) {\n const t = document.createElement('div');\n t.textContent = c.title;\n t.style.cssText = 'font-weight: 600; font-size: 13px; line-height: 1.3;';\n tile.appendChild(t);\n }\n if (c.body) {\n const b = document.createElement('div');\n b.textContent = c.body;\n b.style.cssText = 'font-size: 11.5px; opacity: 0.72; line-height: 1.3;';\n tile.appendChild(b);\n }\n if (c.cta_text && c.cta_url) {\n const cta = document.createElement('button');\n cta.textContent = c.cta_text;\n cta.style.cssText = `\n margin-top: auto; background: ${fg}; color: ${bg};\n border: none; padding: 6px 10px; border-radius: 999px;\n font-size: 12px; font-weight: 600; cursor: pointer;\n `;\n const goto = (e: Event) => {\n e.stopPropagation();\n trackEvent(campaign.id, 'clicked');\n const safe = sanitizeUrl(c.cta_url!);\n if (safe) window.location.href = safe;\n };\n cta.addEventListener('click', goto);\n tile.appendChild(cta);\n tile.addEventListener('click', goto);\n }\n track.appendChild(tile);\n });\n card.appendChild(track);\n\n // Dots + autoplay\n const dots = document.createElement('div');\n dots.style.cssText = 'display: flex; justify-content: center; gap: 6px; margin-top: 10px;';\n const dotEls: HTMLSpanElement[] = [];\n cards.forEach(() => {\n const dot = document.createElement('span');\n dot.style.cssText = `\n width: 6px; height: 6px; border-radius: 999px; background: ${fg};\n opacity: 0.25; transition: opacity 0.2s;\n `;\n dotEls.push(dot);\n dots.appendChild(dot);\n });\n card.appendChild(dots);\n\n const setActive = (idx: number) => {\n dotEls.forEach((d, i) => (d.style.opacity = i === idx ? '0.9' : '0.25'));\n };\n setActive(0);\n\n let activeIdx = 0;\n const tiles = track.querySelectorAll<HTMLDivElement>('[data-card-index]');\n const goto = (idx: number) => {\n activeIdx = ((idx % cards.length) + cards.length) % cards.length;\n const el = tiles[activeIdx];\n if (el) {\n el.scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest' });\n setActive(activeIdx);\n }\n };\n\n let autoplayTimer: ReturnType<typeof setInterval> | null = null;\n if (autoplay > 0 && cards.length > 1) {\n autoplayTimer = setInterval(() => {\n const next = activeIdx + 1;\n if (next >= cards.length && !loop) {\n if (autoplayTimer) clearInterval(autoplayTimer);\n return;\n }\n goto(next);\n }, autoplay);\n }\n\n overlay.addEventListener('remove', () => {\n if (autoplayTimer) clearInterval(autoplayTimer);\n });\n\n // Observe scroll to keep dots in sync when the user swipes.\n track.addEventListener('scroll', () => {\n const approx = Math.round(track.scrollLeft / 150);\n if (approx !== activeIdx && approx >= 0 && approx < cards.length) {\n activeIdx = approx;\n setActive(activeIdx);\n }\n });\n\n overlay.appendChild(card);\n document.body.appendChild(overlay);\n}\n","/**\n * StickyBar renderer — a pinned notification strip at the top or bottom\n * of the viewport. Used for free-shipping hints, flash-sale banners,\n * cart-reminder strips. Dismissible, optionally auto-hiding.\n *\n * interactive_config:\n * sticky_position: 'top' | 'bottom' (required)\n * sticky_bg_color?: string\n * sticky_dismissible?: boolean default true\n * sticky_auto_hide_ms?: number 0 = never\n */\n\nimport type { RenderContext } from './types';\n\n// Persist per-campaign dismissal across reloads so we don't re-show a\n// bar the user already closed. Scoped per campaign ID; storage key\n// survives navigation but is cleared when the user explicitly clears site data.\nconst DISMISS_STORAGE_PREFIX = 'aegis_sticky_dismissed:';\n\nexport function renderStickyBar(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const position = ic.sticky_position === 'top' ? 'top' : 'bottom';\n const dismissible = ic.sticky_dismissible !== false;\n const autoHide = Number(ic.sticky_auto_hide_ms) || 0;\n\n // Already dismissed this session? Skip silently — the prefetch bundle\n // keeps re-offering it, but the user's explicit close stands until TTL.\n try {\n if (\n typeof localStorage !== 'undefined' &&\n localStorage.getItem(DISMISS_STORAGE_PREFIX + campaign.id)\n ) {\n log(`sticky_bar ${campaign.id} suppressed — user dismissed earlier`);\n return;\n }\n } catch {\n // localStorage blocked — fall through and render\n }\n\n addAnimationStyles();\n\n const bg = sanitizeColor(\n (ic.sticky_bg_color as string) || (campaign.background_color as string) || '#4169e1',\n );\n const fg = sanitizeColor((campaign.text_color as string) || '#ffffff');\n\n const bar = document.createElement('div');\n bar.className = 'aegis-in-app-sticky-bar';\n bar.setAttribute('data-campaign-id', campaign.id);\n\n const positionCss =\n position === 'top'\n ? 'top: 0; left: 0; right: 0; animation: aegisSlideDown 0.3s ease-out;'\n : 'bottom: 0; left: 0; right: 0; animation: aegisSlideInFromBottom 0.3s ease-out;';\n\n bar.style.cssText = `\n position: fixed; ${positionCss}\n background: ${bg}; color: ${fg};\n padding: 10px 14px; z-index: 999998;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n display: flex; align-items: center; gap: 12px; justify-content: center;\n box-shadow: 0 ${position === 'top' ? '2px' : '-2px'} 8px rgba(0,0,0,0.08);\n `;\n\n const label = document.createElement('div');\n label.style.cssText = 'flex: 0 1 auto; font-size: 13px; font-weight: 500; text-align: center;';\n const strong = document.createElement('strong');\n strong.textContent = campaign.title;\n strong.style.cssText = 'margin-right: 6px; font-weight: 700;';\n label.appendChild(strong);\n label.appendChild(document.createTextNode(campaign.body));\n bar.appendChild(label);\n\n if (campaign.action_url && campaign.button_text) {\n const cta = document.createElement('button');\n cta.textContent = campaign.button_text;\n cta.style.cssText = `\n background: ${fg}; color: ${bg};\n border: none; padding: 6px 14px; border-radius: 999px;\n font-size: 12px; font-weight: 700; cursor: pointer; white-space: nowrap;\n `;\n cta.addEventListener('click', () => {\n trackEvent(campaign.id, 'clicked');\n const safe = sanitizeUrl(campaign.action_url!);\n if (safe) window.location.href = safe;\n });\n bar.appendChild(cta);\n }\n\n let autoHideTimer: ReturnType<typeof setTimeout> | null = null;\n const remove = (persist: boolean) => {\n if (autoHideTimer) clearTimeout(autoHideTimer);\n if (persist) {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(DISMISS_STORAGE_PREFIX + campaign.id, '1');\n }\n } catch {\n // swallow — localStorage may be disabled\n }\n }\n bar.remove();\n };\n\n if (dismissible) {\n const close = document.createElement('button');\n close.textContent = '✕';\n close.setAttribute('aria-label', 'Dismiss');\n close.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 16px; cursor: pointer; padding: 0 4px; opacity: 0.75;\n `;\n close.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n remove(true);\n });\n bar.appendChild(close);\n }\n\n if (autoHide > 0) {\n autoHideTimer = setTimeout(() => remove(false), autoHide);\n }\n\n document.body.appendChild(bar);\n}\n","/**\n * ProgressBar renderer — a persistent bar that shows the user's progress\n * toward a reward threshold (free shipping, loyalty tier, referral bonus).\n *\n * Two sources of the current value:\n * 'client' — cheap: read from window.Shopify / WooCommerce / Magento\n * cart globals. Untrusted; fine for visual-only hints.\n * 'sse' — trusted: cell-plane pushes current_value via SSE to the\n * already-shipped realtime server. For cart-gated rewards\n * (must agree with server-side checkout guard), prefer SSE.\n *\n * For Phase 1 we implement CLIENT mode end-to-end. SSE mode reads\n * `window.__aegisProgressSSE[campaign.id]` if populated by a parent app\n * — higher-level integration (the SSE bridge) can push values there.\n *\n * interactive_config:\n * progress_goal_type: 'cart_total' | 'items_in_cart' | 'loyalty_points' | 'referrals'\n * progress_threshold: number\n * progress_reward_text?: string\n * progress_source?: 'client' | 'sse' default 'client'\n */\n\nimport type { RenderContext } from './types';\n\ntype GoalType = 'cart_total' | 'items_in_cart' | 'loyalty_points' | 'referrals';\n\nexport function renderProgressBar(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const goalType = (ic.progress_goal_type as GoalType) || 'cart_total';\n const threshold = Number(ic.progress_threshold);\n if (!(threshold > 0)) {\n log('progress_bar requires a positive progress_threshold — skipping', 'warn');\n return;\n }\n const rewardText =\n (ic.progress_reward_text as string) || (campaign.body as string) || 'Unlocked!';\n const source = ic.progress_source === 'sse' ? 'sse' : 'client';\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#f8fafc');\n const fill = sanitizeColor((campaign.text_color as string) || '#4169e1');\n const fg = '#0f172a';\n\n const bar = document.createElement('div');\n bar.className = 'aegis-in-app-progress-bar';\n bar.setAttribute('data-campaign-id', campaign.id);\n bar.style.cssText = `\n position: fixed; left: 12px; right: 12px; bottom: 12px;\n max-width: 540px; margin: 0 auto;\n background: ${bg}; color: ${fg}; border-radius: 12px;\n padding: 10px 14px; z-index: 999997;\n box-shadow: 0 8px 20px rgba(0,0,0,0.08);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n `;\n\n const label = document.createElement('div');\n label.style.cssText = 'display: flex; justify-content: space-between; font-size: 13px; font-weight: 600; margin-bottom: 6px;';\n\n const leading = document.createElement('span');\n leading.textContent = campaign.title;\n label.appendChild(leading);\n\n const numeric = document.createElement('span');\n numeric.style.cssText = 'opacity: 0.7; font-weight: 500;';\n label.appendChild(numeric);\n bar.appendChild(label);\n\n const shell = document.createElement('div');\n shell.style.cssText = `\n height: 8px; border-radius: 999px; background: ${fill}22;\n overflow: hidden;\n `;\n const fillEl = document.createElement('div');\n fillEl.style.cssText = `\n height: 100%; border-radius: 999px; background: ${fill};\n width: 0%; transition: width 0.4s cubic-bezier(.4,0,.2,1);\n `;\n shell.appendChild(fillEl);\n bar.appendChild(shell);\n\n const footnote = document.createElement('div');\n footnote.style.cssText = 'font-size: 11.5px; opacity: 0.65; margin-top: 6px;';\n bar.appendChild(footnote);\n\n const readCurrentValue = (): number => {\n if (source === 'sse') {\n const hook = (window as unknown as {\n __aegisProgressSSE?: Record<string, number>;\n }).__aegisProgressSSE;\n return (hook && typeof hook[campaign.id] === 'number' ? hook[campaign.id] : 0) as number;\n }\n // client mode — read the platform cart globals the widget manager\n // already normalises (Shopify/Woo/Magento). We peek at the same\n // locations without pulling in AegisWidgetManager's 2k-line module.\n try {\n if (goalType === 'cart_total' || goalType === 'items_in_cart') {\n const win = window as unknown as {\n Shopify?: { checkout?: { total_price?: string | number } };\n aegis_cart?: { cart_total?: number; cart_items?: unknown[] };\n localStorage?: Storage;\n };\n if (win.Shopify?.checkout) {\n const v = parseFloat(String(win.Shopify.checkout.total_price || 0));\n return goalType === 'cart_total' ? v : 0;\n }\n if (win.aegis_cart) {\n if (goalType === 'items_in_cart') {\n return Array.isArray(win.aegis_cart.cart_items) ? win.aegis_cart.cart_items.length : 0;\n }\n return Number(win.aegis_cart.cart_total || 0);\n }\n // Magento cache fallback\n try {\n const cacheStr = window.localStorage?.getItem('mage-cache-storage');\n if (cacheStr) {\n const cache = JSON.parse(cacheStr) as { cart?: { subtotalAmount?: number; items?: unknown[] } };\n const cart = cache.cart;\n if (cart) {\n return goalType === 'cart_total'\n ? Number(cart.subtotalAmount || 0)\n : Array.isArray(cart.items)\n ? cart.items.length\n : 0;\n }\n }\n } catch {\n /* noop */\n }\n }\n // loyalty_points / referrals are expected to flow via SSE/push; in\n // client mode we cannot trust a local counter.\n return 0;\n } catch {\n return 0;\n }\n };\n\n let lastFiredUnlock = false;\n const update = () => {\n const cur = readCurrentValue();\n const pct = Math.max(0, Math.min(100, (cur / threshold) * 100));\n fillEl.style.width = `${pct}%`;\n numeric.textContent = `${cur.toFixed(0)} / ${threshold.toFixed(0)}`;\n if (pct >= 100) {\n footnote.textContent = rewardText;\n if (!lastFiredUnlock) {\n lastFiredUnlock = true;\n trackEvent(campaign.id, 'clicked'); // \"unlocked\" recorded as click\n }\n } else {\n const remaining = Math.max(0, threshold - cur);\n footnote.textContent = `Add ${remaining.toFixed(0)} more to unlock: ${rewardText}`;\n }\n };\n\n update();\n\n // Client-mode cart state changes fire events on the storefront globals\n // (Shopify emits `cart:updated`, Woo emits its own). Poll fallback at\n // 1s — negligible overhead because every tick is synchronous.\n const pollTimer = setInterval(update, 1000);\n const cleanup = () => clearInterval(pollTimer);\n window.addEventListener('beforeunload', cleanup, { once: true });\n bar.addEventListener('remove', cleanup);\n\n document.body.appendChild(bar);\n}\n","/**\n * CoachmarkTour renderer — a guided, multi-step walkthrough anchored to\n * DOM elements via CSS selectors. One tooltip appears at a time with\n * next/back navigation; completion + skip are persisted per contact via\n * localStorage under the `resume_key`, so an abandoned tour resumes on\n * the next visit instead of restarting or re-bothering the user.\n *\n * interactive_config:\n * steps: Array<{\n * anchor_web?: string, // CSS selector for THIS platform\n * anchor_android?: string, // ignored on web\n * anchor_ios?: string, // ignored on web\n * title: string,\n * body: string,\n * placement?: 'top' | 'bottom' | 'left' | 'right',\n * cta_text?: string,\n * }>\n * resume_key: string,\n * allow_skip?: boolean,\n * show_progress_dots?: boolean,\n */\n\nimport type { RenderContext } from './types';\n\ntype Step = {\n anchor_web?: string;\n anchor_android?: string;\n anchor_ios?: string;\n title: string;\n body: string;\n placement?: 'top' | 'bottom' | 'left' | 'right';\n cta_text?: string;\n};\n\nconst RESUME_PREFIX = 'aegis_coachmark_progress:';\n\nfunction readResumeIdx(resumeKey: string): number {\n try {\n if (typeof localStorage === 'undefined') return 0;\n const raw = localStorage.getItem(RESUME_PREFIX + resumeKey);\n const n = raw ? parseInt(raw, 10) : 0;\n return Number.isFinite(n) && n >= 0 ? n : 0;\n } catch {\n return 0;\n }\n}\n\nfunction writeResumeIdx(resumeKey: string, idx: number): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(RESUME_PREFIX + resumeKey, String(idx));\n }\n } catch {\n /* noop */\n }\n}\n\nfunction clearResume(resumeKey: string): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem(RESUME_PREFIX + resumeKey);\n }\n } catch {\n /* noop */\n }\n}\n\nexport function renderCoachmarkTour(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const resumeKey = ic.resume_key as string | undefined;\n if (!resumeKey) {\n log('coachmark_tour requires interactive_config.resume_key — skipping', 'warn');\n return;\n }\n\n const steps = Array.isArray(ic.steps) ? (ic.steps as Step[]) : [];\n if (steps.length === 0) {\n log('coachmark_tour has no steps — skipping', 'warn');\n return;\n }\n\n const allowSkip = ic.allow_skip !== false;\n const showDots = ic.show_progress_dots !== false;\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#0f172a');\n const fg = sanitizeColor((campaign.text_color as string) || '#ffffff');\n\n // Resume or start at 0.\n let current = readResumeIdx(resumeKey);\n if (current >= steps.length) {\n log(`coachmark_tour ${resumeKey} already complete — not re-showing`);\n return;\n }\n\n // Track the single overall impression once per mount.\n trackEvent(campaign.id, 'impression');\n\n let pointerEl: HTMLElement | null = null;\n let tipEl: HTMLElement | null = null;\n let highlightEl: HTMLElement | null = null;\n\n const cleanupOne = () => {\n pointerEl?.remove();\n tipEl?.remove();\n highlightEl?.remove();\n pointerEl = null;\n tipEl = null;\n highlightEl = null;\n };\n\n const finish = (opts: { skipped: boolean }) => {\n cleanupOne();\n if (opts.skipped) {\n trackEvent(campaign.id, 'dismissed');\n } else {\n trackEvent(campaign.id, 'clicked'); // completion\n }\n // Mark tour as complete so we never restart it for this contact.\n writeResumeIdx(resumeKey, steps.length);\n };\n\n const showStep = (idx: number) => {\n cleanupOne();\n const step = steps[idx];\n if (!step) {\n finish({ skipped: false });\n return;\n }\n writeResumeIdx(resumeKey, idx);\n\n const selector = step.anchor_web;\n let anchor: Element | null = null;\n if (selector) {\n try {\n anchor = document.querySelector(selector);\n } catch {\n anchor = null;\n }\n }\n if (!anchor) {\n log(`coachmark step ${idx} — selector '${selector}' not found; advancing`, 'warn');\n showStep(idx + 1);\n return;\n }\n\n const rect = anchor.getBoundingClientRect();\n // Slight highlight around the anchor so the user's eye snaps to it.\n highlightEl = document.createElement('div');\n highlightEl.style.cssText = `\n position: fixed;\n top: ${rect.top - 6}px; left: ${rect.left - 6}px;\n width: ${rect.width + 12}px; height: ${rect.height + 12}px;\n border-radius: 10px; z-index: 999998;\n box-shadow: 0 0 0 2px ${fg}, 0 0 0 9999px rgba(0,0,0,0.4);\n pointer-events: none;\n transition: all 0.2s ease;\n `;\n document.body.appendChild(highlightEl);\n\n const placement = step.placement || 'bottom';\n tipEl = document.createElement('div');\n tipEl.setAttribute('data-campaign-id', campaign.id);\n tipEl.style.cssText = `\n position: fixed; z-index: 999999;\n background: ${bg}; color: ${fg};\n padding: 12px 14px; border-radius: 12px;\n max-width: 260px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.25);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisFadeIn 0.2s ease;\n `;\n\n const titleEl = document.createElement('div');\n titleEl.textContent = step.title;\n titleEl.style.cssText = 'font-weight: 700; font-size: 13px; margin-bottom: 4px;';\n tipEl.appendChild(titleEl);\n\n const bodyEl = document.createElement('div');\n bodyEl.textContent = step.body;\n bodyEl.style.cssText = 'font-size: 12.5px; line-height: 1.4; opacity: 0.9;';\n tipEl.appendChild(bodyEl);\n\n const controls = document.createElement('div');\n controls.style.cssText = 'display: flex; align-items: center; justify-content: space-between; margin-top: 10px; gap: 8px;';\n\n // Dots\n if (showDots) {\n const dots = document.createElement('div');\n dots.style.cssText = 'display: flex; gap: 4px;';\n steps.forEach((_, i) => {\n const d = document.createElement('span');\n d.style.cssText = `\n width: 5px; height: 5px; border-radius: 999px;\n background: ${fg}; opacity: ${i === idx ? '0.95' : '0.3'};\n `;\n dots.appendChild(d);\n });\n controls.appendChild(dots);\n } else {\n controls.appendChild(document.createElement('span'));\n }\n\n const buttons = document.createElement('div');\n buttons.style.cssText = 'display: flex; gap: 6px;';\n\n if (allowSkip && idx < steps.length - 1) {\n const skip = document.createElement('button');\n skip.textContent = 'Skip';\n skip.style.cssText = `\n background: transparent; color: inherit; opacity: 0.7;\n border: none; font-size: 12px; cursor: pointer; padding: 6px 8px;\n `;\n skip.addEventListener('click', () => finish({ skipped: true }));\n buttons.appendChild(skip);\n }\n\n const next = document.createElement('button');\n const isLast = idx === steps.length - 1;\n next.textContent = step.cta_text || (isLast ? 'Done' : 'Next');\n next.style.cssText = `\n background: ${fg}; color: ${bg};\n border: none; padding: 6px 12px; border-radius: 999px;\n font-size: 12px; font-weight: 700; cursor: pointer;\n `;\n next.addEventListener('click', () => {\n if (isLast) {\n finish({ skipped: false });\n } else {\n showStep(idx + 1);\n }\n });\n buttons.appendChild(next);\n\n controls.appendChild(buttons);\n tipEl.appendChild(controls);\n document.body.appendChild(tipEl);\n\n // Position after insertion so we know the tip's own dimensions.\n const tipRect = tipEl.getBoundingClientRect();\n const margin = 12;\n let top = rect.bottom + margin;\n let left = rect.left;\n if (placement === 'top') {\n top = rect.top - tipRect.height - margin;\n } else if (placement === 'left') {\n top = rect.top;\n left = rect.left - tipRect.width - margin;\n } else if (placement === 'right') {\n top = rect.top;\n left = rect.right + margin;\n }\n // Clamp to viewport.\n top = Math.max(8, Math.min(window.innerHeight - tipRect.height - 8, top));\n left = Math.max(8, Math.min(window.innerWidth - tipRect.width - 8, left));\n tipEl.style.top = `${top}px`;\n tipEl.style.left = `${left}px`;\n };\n\n showStep(current);\n\n // If the host page unloads mid-tour, leave the current index persisted so\n // the next session resumes from there. Nothing else to do — writeResumeIdx\n // was called in showStep.\n // Expose a cancel hook so app code can reset the tour from Dev Tools etc.\n (window as unknown as { aegisResetTour?: (key: string) => void }).aegisResetTour = (key: string) => clearResume(key);\n}\n","/**\n * ProductRecommendation renderer — personalized product grid/row rendered\n * from `interactive_config.cards[]` that the cell-plane populated at\n * bundle-assembly time. The SDK never calls a product-API at render\n * time — the preload contract is that the recommended products are\n * already in the bundle.\n *\n * The layout is narrower than the generic carousel because product recs\n * should feel like a first-class product grid, not a marketing slider.\n * Three layouts: grid (2-col / 3-col responsive), row (horizontal-scroll),\n * carousel (same as carousel_cards but different framing copy).\n *\n * interactive_config:\n * rec_source?: 'viewed' | 'abandoned' | 'cross_sell' | 'trending' | 'personalized'\n * (metadata only — the actual product list is in `cards[]`)\n * rec_count?: number (display hint; rendering is driven by cards.length)\n * rec_layout?: 'grid' | 'row' | 'carousel' default 'grid'\n * rec_cta_text?: string default 'Shop now'\n * cards: Array<{ image_url?, title?, body?, cta_url?, metadata? }>\n */\n\nimport type { RenderContext } from './types';\n\ntype Card = {\n image_url?: string;\n title?: string;\n body?: string;\n cta_text?: string;\n cta_url?: string;\n metadata?: Record<string, unknown>;\n};\n\nconst MAX_PRODUCTS = 24;\n\nexport function renderProductRecommendation(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const rawCards = Array.isArray(ic.cards) ? (ic.cards as Card[]) : [];\n const cards = rawCards.slice(0, MAX_PRODUCTS);\n if (cards.length === 0) {\n log('product_recommendation rendered with zero products — skipping', 'warn');\n return;\n }\n\n const layout = (ic.rec_layout as string) || 'grid';\n const ctaDefault = (ic.rec_cta_text as string) || 'Shop now';\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#ffffff');\n const fg = sanitizeColor((campaign.text_color as string) || '#0f172a');\n const accent = sanitizeColor('#4169e1');\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-product-rec';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText = `\n position: fixed; inset: 0;\n background: rgba(15,23,42,0.55); backdrop-filter: blur(4px);\n display: flex; align-items: flex-end; justify-content: center;\n z-index: 99999; animation: aegisFadeIn 0.25s ease;\n `;\n\n const sheet = document.createElement('div');\n sheet.style.cssText = `\n background: ${bg}; color: ${fg};\n max-width: 560px; width: 100%; max-height: 80vh; overflow-y: auto;\n border-radius: 20px 20px 0 0;\n padding: 18px 16px 22px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n box-shadow: 0 -12px 30px rgba(0,0,0,0.12);\n `;\n\n // Drag handle (decorative, for mobile context)\n const handle = document.createElement('div');\n handle.style.cssText = `\n width: 36px; height: 4px; border-radius: 999px; background: ${fg}1f;\n margin: 0 auto 12px;\n `;\n sheet.appendChild(handle);\n\n const header = document.createElement('div');\n header.style.cssText = 'display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;';\n\n const headerText = document.createElement('div');\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 700; font-size: 16px; margin-bottom: 2px;';\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.7; line-height: 1.4;';\n headerText.appendChild(title);\n headerText.appendChild(body);\n header.appendChild(headerText);\n\n const close = document.createElement('button');\n close.textContent = '✕';\n close.setAttribute('aria-label', 'Close');\n close.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 18px; cursor: pointer; padding: 4px 8px; opacity: 0.7;\n `;\n close.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n });\n header.appendChild(close);\n sheet.appendChild(header);\n\n const grid = document.createElement('div');\n if (layout === 'row' || layout === 'carousel') {\n grid.style.cssText = `\n display: flex; gap: 10px; overflow-x: auto;\n scroll-snap-type: x mandatory; padding: 14px 0 4px;\n `;\n } else {\n grid.style.cssText = `\n display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;\n padding-top: 14px;\n `;\n }\n\n cards.forEach((c) => {\n const tile = document.createElement('div');\n const isRow = layout === 'row' || layout === 'carousel';\n tile.style.cssText = `\n background: ${fg}08; border-radius: 12px;\n padding: 10px; display: flex; flex-direction: column; gap: 6px;\n cursor: ${c.cta_url ? 'pointer' : 'default'};\n ${isRow ? 'flex: 0 0 150px; scroll-snap-align: start;' : ''}\n transition: transform 0.15s ease;\n `;\n\n if (c.image_url) {\n const img = document.createElement('img');\n const safe = sanitizeUrl(c.image_url);\n if (safe) {\n img.src = safe;\n img.alt = '';\n img.loading = 'lazy';\n img.style.cssText = 'width: 100%; aspect-ratio: 1 / 1; border-radius: 8px; object-fit: cover;';\n tile.appendChild(img);\n }\n }\n\n if (c.title) {\n const t = document.createElement('div');\n t.textContent = c.title;\n t.style.cssText = 'font-weight: 600; font-size: 13px; line-height: 1.3;';\n tile.appendChild(t);\n }\n\n // Price lives in metadata.price per the dashboard schema; we show it\n // prominently if present.\n const price = c.metadata && typeof c.metadata === 'object' ? (c.metadata as Record<string, unknown>).price : undefined;\n if (price !== undefined) {\n const p = document.createElement('div');\n p.textContent = String(price);\n p.style.cssText = `color: ${accent}; font-weight: 700; font-size: 13px;`;\n tile.appendChild(p);\n } else if (c.body) {\n const b = document.createElement('div');\n b.textContent = c.body;\n b.style.cssText = 'font-size: 11.5px; opacity: 0.72; line-height: 1.3;';\n tile.appendChild(b);\n }\n\n const cta = document.createElement('button');\n cta.textContent = c.cta_text || ctaDefault;\n cta.style.cssText = `\n margin-top: auto;\n background: ${accent}; color: #fff;\n border: none; padding: 7px 10px; border-radius: 999px;\n font-size: 12px; font-weight: 600; cursor: pointer;\n `;\n const go = (e: Event) => {\n e.stopPropagation();\n trackEvent(campaign.id, 'clicked');\n if (c.cta_url) {\n const safe = sanitizeUrl(c.cta_url);\n if (safe) window.location.href = safe;\n }\n };\n cta.addEventListener('click', go);\n tile.appendChild(cta);\n if (c.cta_url) tile.addEventListener('click', go);\n\n grid.appendChild(tile);\n });\n\n sheet.appendChild(grid);\n overlay.appendChild(sheet);\n\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n }\n });\n\n document.body.appendChild(overlay);\n}\n","/**\n * AegisInAppManager - Web SDK In-App Messaging Module\n *\n * HTTP polling architecture with client-side evaluation.\n *\n * Security:\n * - XSS Protection: Uses DOM APIs (createElement, textContent) instead of innerHTML\n * - URL Validation: Prevents javascript: protocol injection\n * - CSP Compatible: No inline styles in HTML strings\n *\n * Architecture (RFC 2026-04-16):\n * - Polls /v1/in-app/active on initialize + on identity change\n * - Caches campaigns locally in memory\n * - Evaluates trigger rules client-side\n * - Tracks events (impression, click, dismiss) asynchronously\n *\n * NOTE: Persistent SSE for downstream delivery is disabled by default\n * (enableSSE=false). Tenant dashboards that need realtime (inbox, chat,\n * live page) open SSE directly via Next.js API routes — not via this SDK.\n * End-user storefronts use polling + Web Push for background delivery.\n */\n\nimport type { RenderContext } from './renderers';\nimport {\n renderCarouselCards,\n renderCoachmarkTour,\n renderProductRecommendation,\n renderProgressBar,\n renderStickyBar,\n} from './renderers';\nimport { Storage } from '../utils/storage';\n\n// Read the SDK's persisted anonymous_id from localStorage/cookie if available.\n// Returns undefined when called server-side (no document/window) or when no\n// id has been minted yet — caller falls through to leaving userId unset.\nfunction readAnonIdFromStorage(): string | undefined {\n if (typeof document === 'undefined') return undefined;\n try {\n const storage = new Storage();\n return storage.get('anon_id') ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface InAppCampaign {\n id: string;\n type:\n | 'modal'\n | 'banner'\n | 'tooltip'\n | 'full_screen'\n | 'half_interstitial'\n | 'alert'\n | 'pip'\n // Preload-first display types (2026-04-22 §5.4 of the expansion plan)\n | 'carousel_cards'\n | 'sticky_bar'\n | 'progress_bar'\n | 'coachmark_tour'\n | 'product_recommendation';\n sub_type?: string;\n title: string;\n body: string;\n image_url?: string;\n video_url?: string;\n action_url?: string;\n button_text?: string;\n background_color?: string;\n text_color?: string;\n priority: number;\n expires_at?: string;\n frequency?: {\n max_impressions?: number;\n max_impressions_per_day?: number;\n cooldown_seconds?: number;\n // Conversion-aware suppression — added by Micro-Intent Engine P0a (2026-04-30).\n // Mirrors cell-plane FrequencyCap. When the host app calls\n // `notifyConversion(goalName)`, every armed campaign whose\n // `suppress_after_conversion_seconds` is set gets silenced for that\n // many seconds (session-scoped via sessionStorage). Prevents the\n // \"showing 10% off to a buyer who just paid full price\" failure mode.\n suppress_after_conversion_seconds?: number;\n suppress_after_dismiss_seconds?: number;\n scope?: 'session' | 'user' | 'user_sku';\n };\n interactive_config?: Record<string, unknown>;\n client_trigger?: {\n type: string;\n config?: Record<string, unknown>;\n };\n assigned_variant_id?: string;\n // F2 — campaign-delivery surface selection. When the array contains\n // 'embedded_card' AND the page has a `[data-aegis-slot=\"<widget_category>\"]`\n // anchor, the SDK renders this campaign INTO the slot (in addition to or\n // instead of an overlay; see `renderIntoSlots`). Defaults to\n // `['in_app_overlay']` server-side so legacy campaigns keep auto-overlay\n // behavior unchanged.\n delivery_modes?: Array<'in_app_overlay' | 'embedded_card' | 'standalone_page'>;\n // F3 — wide grouping discriminator used as the slot lookup key. A campaign\n // with `widget_category='feedback'` will fill the first\n // `[data-aegis-slot=\"feedback\"]` element on the page (if `embedded_card` is\n // among its delivery_modes).\n widget_category?: 'feedback' | 'loyalty' | 'promo' | 'commerce' | 'support' | 'custom';\n // F2 — page-key for `standalone_page` delivery mode. Read by the Next.js\n // route handler in `apps/cashier-portal/src/app/s/[slug]/[workspace]/[page_key]`.\n // Matches the existing storefront vocabulary (`rewards`/`members`)\n // in apps/cashier-portal/src/app/s/[slug]/{rewards,members}/page.tsx.\n page_key?: 'bill' | 'rewards' | 'feedback' | 'reviews' | 'members';\n}\n\n/**\n * Payload for `campaign-click` lifecycle event. CANCELLABLE — return `false`\n * (or call `evt.preventDefault()`) from the handler to suppress the SDK's\n * default `window.location.href` navigation, e.g. to route via a SPA router.\n */\nexport interface CampaignClickEvent {\n campaign: InAppCampaign;\n /** Sanitized destination URL — already passed through `sanitizeUrl()`. */\n action_url: string;\n /** Best-effort button identifier — populated when the click came from a\n * named button in a multi-button campaign (modals, alerts). `cta` for the\n * primary CTA on single-button campaigns. */\n button_id?: string;\n /** Mutate via `evt.preventDefault()` to signal the SDK to skip its\n * default hard-navigation. Identical semantics to DOM CustomEvent. */\n preventDefault: () => void;\n defaultPrevented: boolean;\n}\n\n/** Payload for `campaign-dismiss` lifecycle event. */\nexport interface CampaignDismissEvent {\n campaign: InAppCampaign;\n /** Source of dismissal — close button, swipe, ESC key, programmatic. */\n source: 'close_button' | 'overlay' | 'esc' | 'auto_timeout' | 'programmatic';\n}\n\n/** Payload for `error` lifecycle event. Aggregates non-fatal SDK errors so\n * host apps can wire them into Sentry / Datadog RUM / similar. */\nexport interface AegisErrorEvent {\n message: string;\n error: unknown;\n /** Optional structured context — `{ event: 'campaign-click' }` for handler\n * throws, `{ campaign_id, stage }` for render path failures, etc. */\n context: Record<string, unknown>;\n}\n\n/**\n * Map of lifecycle event name → handler signature. Used by the typed\n * `on(event, handler)` overload below so TS correctly narrows the payload\n * type per event without a discriminated union at the call site.\n */\nexport interface InAppLifecycleEventMap {\n 'campaigns-loaded': (campaigns: InAppCampaign[]) => void;\n 'campaign-will-show': (campaign: InAppCampaign) => void | false;\n 'campaign-shown': (campaign: InAppCampaign) => void;\n 'campaign-click': (evt: CampaignClickEvent) => void | false;\n 'campaign-dismiss': (evt: CampaignDismissEvent) => void;\n 'error': (evt: AegisErrorEvent) => void;\n}\n\nexport interface AegisInAppConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n // Resolved by POST /v1/sdk/bootstrap — required in production. Campaigns\n // with a non-empty `target_properties` list are filtered against this on\n // the server, so passing the wrong id (or omitting it) narrows visible\n // campaigns to the property-agnostic ones only.\n propertyId?: string;\n debugMode?: boolean;\n enableSSE?: boolean;\n /**\n * Callback invoked when the manager receives an in-app campaign with\n * a gamification sub_type (spin_wheel / scratch_card). The facade\n * (AegisMessageRuntime) wires this to the widget-renderer path so\n * interactive campaigns render correctly. When this is undefined,\n * gamification campaigns are logged and skipped.\n */\n onInteractiveCampaign?: (campaign: InAppCampaign) => void;\n /**\n * Workspace cascade reader. Set this from the host SDK as\n * `getWorkspaceId: () => aegis.getEffectiveWorkspaceId()` so in-app\n * impressions/clicks/dismisses carry the same workspace context the\n * main analytics SDK sees (URL path slug, ?ws=, setWorkspace runtime).\n * Without it, in-app engagement events arrive at event-ingress with\n * no workspace_id stamped → cross-outlet attribution silently falls\n * back to the org's primary workspace.\n */\n getWorkspaceId?: () => string | undefined;\n}\n\nexport class AegisInAppManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private propertyId?: string;\n private debugMode: boolean;\n private enableSSE: boolean;\n private onInteractiveCampaign?: (campaign: InAppCampaign) => void;\n private getWorkspaceId?: () => string | undefined;\n\n private campaigns: InAppCampaign[] = [];\n private displayedCampaigns = new Set<string>();\n // Conversion-aware suppression — campaign_id -> epoch_ms when suppression expires.\n // Populated by `notifyConversion()` and rehydrated from sessionStorage in\n // `refreshCampaigns()` so a navigation between pages preserves silence.\n private suppressedUntil = new Map<string, number>();\n private eventSource?: EventSource;\n private isInitialized = false;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n // sessionStorage key prefix — one entry per goal so we can introspect what\n // converted and when. Format: { ts: epoch_ms }.\n private static readonly CONVERSION_STORAGE_PREFIX = 'aegis_conv_';\n\n // ── Lifecycle event bus (1.8.0) ────────────────────────────────────────\n // Typed callback registry — host apps register handlers via the public\n // `on*` methods below. Each handler is stored once; calling the\n // returned unsubscribe fn removes it. Multiple subscribers per event are\n // supported. Callbacks that return `false` (or call `evt.preventDefault()`\n // on cancellable events) signal the SDK to skip its default behaviour.\n //\n // Industry parity: matches CleverTap `notificationCallback`, WebEngage\n // `onCallback`, MoEngage `onSelfHandledClick`, Iterable url-delegate, etc.\n // The DOM CustomEvent path (window.dispatchEvent('aegis:campaign-click'))\n // is preserved for backward compat + advanced multi-subscriber + pre-init\n // patterns where typed methods aren't reachable yet.\n private hooks = new Map<string, Set<(...args: unknown[]) => void | false | undefined>>();\n // `aegis.inApp.ready` resolves when the first refreshCampaigns completes\n // — matches CleverTap `onLoad`, WebEngage `onReady`. Lets host apps await\n // a known-good state before reading `campaigns` or registering handlers\n // that need armed campaigns visible.\n private readyResolve!: () => void;\n readonly ready: Promise<void> = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n\n private emit<T>(eventName: string, payload: T): boolean {\n const handlers = this.hooks.get(eventName);\n if (!handlers || handlers.size === 0) return true;\n let proceed = true;\n for (const handler of handlers) {\n try {\n const result = (handler as (p: T) => void | false | undefined)(payload);\n if (result === false) proceed = false;\n } catch (err) {\n // Don't let a misbehaving host handler crash the SDK render path.\n // Surface via onError but keep going for the remaining handlers.\n this.emitError(err, { event: eventName });\n }\n }\n return proceed;\n }\n\n private emitError(err: unknown, context?: Record<string, unknown>): void {\n const handlers = this.hooks.get('error');\n if (!handlers || handlers.size === 0) {\n // No subscriber — log to console so errors aren't completely silent.\n this.log(`Active Reach SDK error: ${err instanceof Error ? err.message : String(err)}`, 'error');\n return;\n }\n for (const handler of handlers) {\n try {\n (handler as (e: AegisErrorEvent) => void)({\n message: err instanceof Error ? err.message : String(err),\n error: err,\n context: context ?? {},\n });\n } catch {\n // ignore — we already tried to surface\n }\n }\n }\n\n private register<T>(\n eventName: string,\n handler: (payload: T) => void | false | undefined,\n ): () => void {\n if (!this.hooks.has(eventName)) this.hooks.set(eventName, new Set());\n this.hooks.get(eventName)!.add(handler as (...args: unknown[]) => void | false | undefined);\n return () => {\n this.hooks.get(eventName)?.delete(handler as (...args: unknown[]) => void | false | undefined);\n };\n }\n\n /**\n * Subscribe to in-app message lifecycle events. Returns an unsubscribe\n * function — call to remove the handler (matches React `useEffect` cleanup\n * convention).\n *\n * Supported events: `campaigns-loaded`, `campaign-will-show` (cancellable),\n * `campaign-shown`, `campaign-click` (cancellable), `campaign-dismiss`,\n * `error`. Cancellable events: handler returns `false` to suppress the\n * SDK's default behaviour (e.g., prevent the hard navigation on click,\n * skip rendering on will-show).\n */\n on<E extends keyof InAppLifecycleEventMap>(\n event: E,\n handler: InAppLifecycleEventMap[E],\n ): () => void {\n return this.register(event, handler as never);\n }\n\n /** Sugar: subscribe to `campaigns-loaded`. Fires after every successful\n * `/v1/in-app/active` poll with the full active-campaign list. */\n onCampaignsLoaded(\n handler: (campaigns: InAppCampaign[]) => void,\n ): () => void {\n return this.register('campaigns-loaded', handler);\n }\n\n /** Sugar: subscribe to `campaign-will-show`. CANCELLABLE — return `false`\n * to suppress rendering this campaign (host-side suppression rules,\n * route-aware blocking, etc.). */\n onCampaignWillShow(\n handler: (campaign: InAppCampaign) => void | false,\n ): () => void {\n return this.register('campaign-will-show', handler);\n }\n\n /** Sugar: subscribe to `campaign-shown`. Fires after the SDK has painted\n * the campaign to the DOM (post-impression). */\n onCampaignShown(\n handler: (campaign: InAppCampaign) => void,\n ): () => void {\n return this.register('campaign-shown', handler);\n }\n\n /** Sugar: subscribe to `campaign-click`. CANCELLABLE — return `false` (or\n * call `evt.preventDefault()`) to suppress the SDK's default\n * `window.location.href` navigation, e.g. to route via a SPA router. */\n onCampaignClick(\n handler: (evt: CampaignClickEvent) => void | false,\n ): () => void {\n return this.register('campaign-click', handler);\n }\n\n /** Sugar: subscribe to `campaign-dismiss`. Fires when user closes/swipes\n * away the campaign before clicking through. */\n onCampaignDismiss(\n handler: (evt: CampaignDismissEvent) => void,\n ): () => void {\n return this.register('campaign-dismiss', handler);\n }\n\n /** Sugar: subscribe to `error`. Aggregates non-fatal SDK errors — fetch\n * failures, render exceptions, host-handler throws. Wire this into your\n * error monitoring (Sentry, Datadog RUM, etc.). */\n onError(\n handler: (evt: AegisErrorEvent) => void,\n ): () => void {\n return this.register('error', handler);\n }\n \n constructor(config: AegisInAppConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n // Fall back to the SDK's persisted anonymous_id (set on first /v1/sdk/bootstrap\n // and reused across the main analytics SDK) so anonymous storefront users\n // get journey-driven in-app messages keyed to the same identity used in\n // /v1/batch payloads. Without this, polling defaults to \"anonymous\" on the\n // server and bucket-misses every per-contact priority queue.\n this.userId = config.userId ?? readAnonIdFromStorage();\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.propertyId = config.propertyId;\n this.debugMode = config.debugMode || false;\n // SSE is disabled by default. Kept as opt-in capability for future tenant\n // dashboards that embed the Active Reach SDK and need realtime updates. End-user\n // storefronts must NOT enable this — persistent-per-tab SSE doesn't scale.\n this.enableSSE = config.enableSSE === true;\n this.onInteractiveCampaign = config.onInteractiveCampaign;\n this.getWorkspaceId = config.getWorkspaceId;\n }\n \n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisInApp already initialized');\n return;\n }\n\n // Mark user as returning for subsequent visits\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem('aegis_returning_user', '1');\n }\n\n await this.refreshCampaigns();\n\n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n \n this.isInitialized = true;\n this.log('AegisInApp initialized successfully');\n }\n \n updateUserId(userId: string): void {\n this.userId = userId;\n this.refreshCampaigns();\n }\n \n updateContactId(contactId: string): void {\n this.contactId = contactId;\n this.disconnectSSE();\n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n this.refreshCampaigns();\n }\n\n // --- Qualifying-event refresh (DLR Tracker 1 / P1, 2026-05-28) ---------\n //\n // Burst-coalescing debounce timer for `refreshOnEvent`. Cleared and\n // re-armed on every call so a flurry of `aegis.track('cart_item_added')`\n // calls (e.g. 10 within 100ms while a shopper rapidly adds items)\n // collapses to a single `/v1/in-app/active` fetch ~300ms after the last\n // call. Without this debounce, an active storefront would hammer the\n // endpoint and our connection-load budget — see\n // memory/feedback_web_sdk_rest_not_sse.md for why polling has to stay\n // gentle.\n private refreshDebounceTimer?: ReturnType<typeof setTimeout>;\n private static readonly REFRESH_DEBOUNCE_MS = 300;\n\n /**\n * Qualifying-event refresh — schedule a debounced `refreshCampaigns()`\n * call in response to a host-app SDK event (`aegis.page()`,\n * `aegis.screen()`, `aegis.track(name)`). Matches CleverTap / MoEngage /\n * WebEngage's \"refresh on qualifying event\" shape, translated to the\n * browser session.\n *\n * Why: new server-side eligibility opens on these events (a `page` view\n * arms route-targeted campaigns; a `track('product_viewed')` arms\n * trigger-gated campaigns whose `client_trigger.config.event` matches).\n * Pre-P1, the SDK only refreshed on `initialize()` + `updateContactId()`\n * + the SSE update channel (which storefront has disabled by design),\n * so newly armed campaigns were invisible until the next identity flip.\n *\n * Debounce: 300ms. Five `page()` calls inside the window coalesce to\n * one fetch; a sixth call ≥300ms after the prior burst starts a new\n * fetch. The trailing-edge schedule (re-arm on every call) is correct\n * for storefront rage-clicks + SPA route bursts — we want the LATEST\n * URL's eligibility, not the first.\n *\n * Safe to call on the server (no-op when `setTimeout` is unavailable\n * — though that's vanishingly rare in any modern environment we ship to).\n *\n * `eventName` is currently used only for the debug log line; it's\n * preserved on the signature so a future P-phase can pass it through\n * to `/v1/in-app/active?trigger_event=<name>` for the optional\n * server-side eligibility-on-this-event optimization noted in the\n * P1 plan.\n */\n refreshOnEvent(eventName: string): void {\n if (!this.isInitialized) {\n // Pre-init events are silently dropped — the first refresh fires\n // from `initialize()` so there's nothing to coalesce against yet.\n this.log(`refreshOnEvent(${eventName}) before initialize — ignored`);\n return;\n }\n if (this.refreshDebounceTimer) {\n clearTimeout(this.refreshDebounceTimer);\n }\n this.refreshDebounceTimer = setTimeout(() => {\n this.refreshDebounceTimer = undefined;\n this.log(`refreshOnEvent(${eventName}) — firing refreshCampaigns()`);\n void this.refreshCampaigns();\n }, AegisInAppManager.REFRESH_DEBOUNCE_MS);\n }\n\n /**\n * Conversion-aware suppression. Call this when the host app observes a\n * goal event (purchase, order_placed, checkout_completed, or any custom\n * goal the workspace has configured per-campaign).\n *\n * For every armed campaign whose `frequency.suppress_after_conversion_seconds`\n * is set, this:\n * 1. Persists the conversion in sessionStorage (so subsequent page\n * loads in the same tab retain silence).\n * 2. Computes an expiry epoch_ms and stores it in `suppressedUntil`.\n * 3. The two campaign-evaluation paths (`tryDisplayNextCampaign`\n * and `onClientEvent`) skip campaigns whose `suppressedUntil`\n * has not yet passed.\n *\n * Scope: only `session` is implemented in P0a. `user` and `user_sku`\n * scopes degrade to session-only with a debug log; the schema accepts\n * them so future expansion is non-breaking.\n *\n * Safe to call repeatedly for the same goal — each call refreshes the\n * sessionStorage timestamp and re-applies suppression to any campaigns\n * loaded since the last call.\n */\n notifyConversion(goalName: string): void {\n if (!goalName) {\n this.log('notifyConversion called with empty goalName; ignored', 'warn');\n return;\n }\n const ts = Date.now();\n if (typeof sessionStorage !== 'undefined') {\n try {\n sessionStorage.setItem(\n `${AegisInAppManager.CONVERSION_STORAGE_PREFIX}${goalName}`,\n JSON.stringify({ ts }),\n );\n } catch {\n // sessionStorage may be disabled (Safari private mode, blocked\n // third-party context). Suppression still applies for the\n // current page lifetime via the in-memory map.\n }\n }\n this.applySuppressionFromCampaigns(ts);\n this.log(`notifyConversion: ${goalName} — suppressing ${this.suppressedUntil.size} armed campaigns`);\n }\n\n /**\n * Compute and store `suppressedUntil` entries for every armed campaign\n * whose `frequency.suppress_after_conversion_seconds` is set. Called by\n * `notifyConversion()` and `refreshCampaigns()` (the latter rehydrates\n * suppression for newly-loaded campaigns when a prior conversion event\n * exists in sessionStorage).\n *\n * `convertedAt` is the epoch_ms of the conversion; pass `Date.now()`\n * when called from `notifyConversion`, or the `ts` recovered from\n * sessionStorage when rehydrating.\n */\n private applySuppressionFromCampaigns(convertedAt: number): void {\n for (const c of this.campaigns) {\n const seconds = c.frequency?.suppress_after_conversion_seconds;\n if (typeof seconds !== 'number' || seconds <= 0) continue;\n const scope = c.frequency?.scope ?? 'session';\n if (scope !== 'session') {\n // P0a only implements session scope. Schema accepts user / user_sku\n // so future work doesn't break wire compatibility, but for now we\n // degrade to session and log.\n this.log(\n `applySuppressionFromCampaigns: scope=${scope} not implemented; degrading to session for campaign ${c.id}`,\n 'warn',\n );\n }\n const expiresAt = convertedAt + seconds * 1000;\n // Take the max so a later/longer suppression wins over an earlier one.\n const existing = this.suppressedUntil.get(c.id);\n if (existing === undefined || existing < expiresAt) {\n this.suppressedUntil.set(c.id, expiresAt);\n }\n }\n }\n\n /**\n * Recover any prior conversion timestamps from sessionStorage and apply\n * suppression to currently-loaded campaigns. Called from\n * `refreshCampaigns()` after `this.campaigns` is populated. This is the\n * mechanism that prevents a converted buyer from seeing a discount popup\n * on the next page load within the same session.\n */\n private rehydrateSuppressionFromStorage(): void {\n if (typeof sessionStorage === 'undefined') return;\n let earliestTs: number | null = null;\n try {\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i);\n if (!key || !key.startsWith(AegisInAppManager.CONVERSION_STORAGE_PREFIX)) continue;\n const raw = sessionStorage.getItem(key);\n if (!raw) continue;\n const parsed = JSON.parse(raw) as { ts?: number };\n if (typeof parsed.ts === 'number') {\n earliestTs = earliestTs === null ? parsed.ts : Math.min(earliestTs, parsed.ts);\n }\n }\n } catch {\n // Malformed entries are silently skipped — suppression simply\n // doesn't apply for them.\n return;\n }\n if (earliestTs !== null) {\n this.applySuppressionFromCampaigns(earliestTs);\n }\n }\n\n /**\n * Returns true if the campaign is currently suppressed (Date.now() is\n * before the stored expiry). Used by both display paths.\n */\n private isSuppressed(campaignId: string): boolean {\n const expiresAt = this.suppressedUntil.get(campaignId);\n if (expiresAt === undefined) return false;\n if (Date.now() >= expiresAt) {\n this.suppressedUntil.delete(campaignId);\n return false;\n }\n return true;\n }\n \n private connectSSE(): void {\n if (this.eventSource) {\n this.disconnectSSE();\n }\n \n if (!this.organizationId) {\n this.log('Cannot connect SSE without organization ID', 'warn');\n return;\n }\n \n const url = new URL('/v1/stream/realtime', this.apiHost);\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Organization-ID': this.organizationId,\n };\n \n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n \n const queryParams = new URLSearchParams();\n Object.entries(headers).forEach(([key, value]) => {\n queryParams.append(key, value);\n });\n \n this.eventSource = new EventSource(`${url}?${queryParams.toString()}`);\n \n this.eventSource.addEventListener('open', () => {\n this.log('SSE connection established');\n this.reconnectAttempts = 0;\n });\n \n this.eventSource.addEventListener('in_app_campaign_updated', (event: MessageEvent) => {\n try {\n const data = JSON.parse(event.data);\n this.log(`Received in-app campaign update: ${data.campaign_id}`);\n this.refreshCampaigns();\n } catch (error) {\n this.log(`Error parsing SSE event: ${error}`, 'error');\n }\n });\n \n this.eventSource.addEventListener('heartbeat', () => {\n this.log('SSE heartbeat received');\n });\n\n this.eventSource.addEventListener('error', () => {\n this.log('SSE connection error', 'error');\n\n if (this.eventSource?.readyState === EventSource.CLOSED) {\n this.attemptReconnect();\n }\n });\n }\n \n private disconnectSSE(): void {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = undefined;\n this.log('SSE connection closed');\n }\n }\n \n private attemptReconnect(): void {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n this.log('Max reconnect attempts reached, giving up', 'warn');\n return;\n }\n \n this.reconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);\n \n this.log(`Reconnecting SSE in ${delay}ms (attempt ${this.reconnectAttempts})`);\n \n setTimeout(() => {\n if (this.isInitialized && this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n }, delay);\n }\n \n private async refreshCampaigns(): Promise<void> {\n try {\n // Build URL with client context for server-side targeting (Critical Fix B)\n const context = new URLSearchParams({\n device_type: this.detectDeviceType(),\n page_url: typeof window !== 'undefined' ? window.location.pathname : '/',\n });\n\n // Geo is resolved server-side from IP — no need to send\n context.set('is_new_user', this.isNewUser() ? 'true' : 'false');\n\n const url = `${this.apiHost}/v1/in-app/active?${context.toString()}`;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n\n if (this.userId) {\n headers['X-User-ID'] = this.userId;\n }\n\n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n\n if (this.organizationId) {\n headers['X-Organization-ID'] = this.organizationId;\n }\n\n if (this.propertyId) {\n headers['X-Property-Id'] = this.propertyId;\n }\n\n // Send cached A/B assignments so server can skip re-evaluation (Critical Fix C)\n const abAssignments = this.getABAssignments();\n if (Object.keys(abAssignments).length > 0) {\n headers['X-AB-Assignments'] = btoa(JSON.stringify(abAssignments));\n }\n\n const response = await fetch(url, {\n method: 'GET',\n headers,\n credentials: 'include',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch campaigns: ${response.status}`);\n }\n\n const payload = await response.json();\n // Server returns an array; defensively handle error bodies (HTML\n // from misconfigured gateways, {} from maintenance endpoints, etc.)\n // so a bad response doesn't turn `updateContactId` into a thrower.\n this.campaigns = Array.isArray(payload) ? payload : [];\n\n // Process A/B assignments from server response (Critical Fix C)\n this.processABAssignments(this.campaigns);\n\n // Rehydrate conversion suppression from sessionStorage so a buyer\n // who converted on a prior page load in the same tab does not see\n // a discount popup on this load. Must run after this.campaigns is\n // populated and BEFORE tryDisplayNextCampaign so the first display\n // attempt honors suppression.\n this.rehydrateSuppressionFromStorage();\n\n this.log(`Fetched ${this.campaigns.length} campaigns`);\n\n // Lifecycle: `campaigns-loaded` — fires after every successful refresh\n // with the full active-campaign list. Host apps subscribe to drive\n // route-aware allowlists, sticky inboxes, badge counts, etc.\n this.emit('campaigns-loaded', this.campaigns);\n\n // Resolve `aegis.inApp.ready` after the FIRST successful poll so host\n // apps can `await aegis.inApp.ready` before reading `campaigns` or\n // making decisions that depend on a known-good initial state. Idempotent\n // — calling resolve() twice is a no-op for an already-settled promise.\n this.readyResolve();\n\n this.tryDisplayNextCampaign();\n\n // F2/F3 / U8 — fill any `[data-aegis-slot]` anchors with matching\n // `embedded_card`-mode campaigns. Independent of the overlay path:\n // a campaign with delivery_modes=[overlay,card] renders both ways\n // (overlay if conditions match + card if the page has a slot).\n // No-op when no slots are on the page.\n this.renderIntoSlots();\n\n // PR-B U7 — also fill any `[data-aegis-token-data]` anchors with\n // a server-injected campaign payload. Used by the standalone-page\n // route at `/s/[slug]/[workspace]/[page_key]?t=<token>`: the page\n // handler verifies the token server-side (via F16 internal),\n // embeds the resolved campaign data inline, and the SDK uses the\n // SAME renderer dispatch as the slot path. No separate widget\n // code, no public token-resolve endpoint.\n this.renderTokenAnchors();\n\n } catch (error) {\n this.emitError(error, { stage: 'refresh-campaigns' });\n this.log(`Error refreshing campaigns: ${error}`, 'error');\n }\n }\n\n // --- Client Context Helpers (Critical Fix B) ---\n\n private detectDeviceType(): 'mobile' | 'desktop' | 'tablet' {\n if (typeof navigator === 'undefined') return 'desktop';\n const ua = navigator.userAgent;\n if (/Mobi|Android/i.test(ua)) return 'mobile';\n if (/iPad|Tablet/i.test(ua)) return 'tablet';\n return 'desktop';\n }\n\n private isNewUser(): boolean {\n if (typeof localStorage === 'undefined') return true;\n return !localStorage.getItem('aegis_returning_user');\n }\n\n // --- A/B Assignment Persistence (Critical Fix C) ---\n\n private getABAssignments(): Record<string, string> {\n if (typeof localStorage === 'undefined') return {};\n try {\n return JSON.parse(localStorage.getItem('aegis_ab_assignments') || '{}');\n } catch {\n return {};\n }\n }\n\n private processABAssignments(campaigns: InAppCampaign[]): void {\n if (typeof localStorage === 'undefined') return;\n const stored = this.getABAssignments();\n for (const campaign of campaigns) {\n if (campaign.assigned_variant_id) {\n stored[campaign.id] = campaign.assigned_variant_id;\n }\n }\n localStorage.setItem('aegis_ab_assignments', JSON.stringify(stored));\n }\n\n private getVariantId(campaignId: string): string | undefined {\n const assignments = this.getABAssignments();\n return assignments[campaignId] ?? undefined;\n }\n \n private tryDisplayNextCampaign(): void {\n // Only auto-display campaigns that DO NOT have a client_trigger.\n // Trigger-gated campaigns wait for the host app to call\n // `onClientEvent()` or for TriggerEngine to fire the matching\n // behavioural event. This preserves the preload-first contract —\n // the campaign is armed but the render is gated.\n // Conversion-aware suppression: campaigns silenced by a prior\n // notifyConversion() call (or rehydrated from sessionStorage) are\n // skipped until their suppression window expires.\n const campaign = this.campaigns.find((c) =>\n !this.displayedCampaigns.has(c.id) && !c.client_trigger && !this.isSuppressed(c.id),\n );\n\n if (campaign) {\n this.displayCampaign(campaign);\n }\n }\n\n // --- F2/F3 / U8: embedded-card slot rendering ---------------------------\n //\n // Tracks slot DOM elements we've already filled so a second\n // refresh-cycle (SSE update, polling tick) doesn't re-render the same\n // campaign on top of itself. WeakSet so DOM removals get GC'd.\n private filledSlots = new WeakSet<Element>();\n\n /**\n * Scan the page for `[data-aegis-slot]` anchors and render any\n * campaign whose `widget_category` matches the slot key AND whose\n * `delivery_modes` includes `'embedded_card'`.\n *\n * Runs after every refresh-campaigns success — the WeakSet guard\n * keeps it idempotent across re-fetches. The slot key is the campaign's\n * `widget_category` (the wide grouping discriminator from F3), so a\n * `<div data-aegis-slot=\"feedback\">` will accept the first active\n * campaign with `widget_category='feedback'` + embedded_card mode.\n */\n private renderIntoSlots(): void {\n if (typeof document === 'undefined') return;\n const slots = document.querySelectorAll('[data-aegis-slot]');\n if (slots.length === 0) return;\n\n // First-active-per-category wins. Caller-side ordering of\n // `this.campaigns` is priority-sorted by the cell-plane endpoint.\n const eligibleByCategory = new Map<string, InAppCampaign>();\n for (const c of this.campaigns) {\n const modes = c.delivery_modes;\n const category = c.widget_category;\n if (!modes || !modes.includes('embedded_card')) continue;\n if (!category) continue;\n if (!eligibleByCategory.has(category)) {\n eligibleByCategory.set(category, c);\n }\n }\n if (eligibleByCategory.size === 0) return;\n\n slots.forEach((slot) => {\n if (this.filledSlots.has(slot)) return;\n const key = slot.getAttribute('data-aegis-slot');\n if (!key) return;\n const campaign = eligibleByCategory.get(key);\n if (!campaign) return;\n this.renderCampaignIntoSlot(campaign, slot as HTMLElement);\n this.filledSlots.add(slot);\n });\n }\n\n /**\n * U7 — render server-injected token-bound campaigns.\n *\n * The standalone-page route at `apps/cashier-portal/src/app/s/[slug]/\n * [workspace]/[page_key]/page.tsx` (and the `/c/[token]` Aegis-hosted\n * fallback) verify the URL token server-side via the F16 internal\n * endpoint, then embed the resolved campaign payload as JSON inside\n * a `<div data-aegis-token-data=\"...\">` anchor. This SDK method\n * scans for those anchors, parses the payload, and dispatches to\n * the SAME `renderCampaignIntoSlot` used by the [data-aegis-slot]\n * path — so widget rendering code is single-sourced.\n *\n * Why server-injected (not client-fetched): keeps INTERNAL_API_SECRET\n * server-side, avoids an extra browser round-trip for verify, gives\n * Next.js SSR-friendly initial HTML for SEO/no-JS users (rendered\n * via the page handler's React tree alongside the SDK anchor).\n *\n * Idempotency: filledSlots is the same WeakSet used by\n * renderIntoSlots — re-running on SSE/poll refresh is a no-op for\n * already-filled anchors.\n */\n private renderTokenAnchors(): void {\n if (typeof document === 'undefined') return;\n const anchors = document.querySelectorAll('[data-aegis-token-data]');\n if (anchors.length === 0) return;\n\n anchors.forEach((anchor) => {\n if (this.filledSlots.has(anchor)) return;\n const raw = anchor.getAttribute('data-aegis-token-data');\n if (!raw) return;\n\n let payload:\n | { campaign?: InAppCampaign; submit_url?: string }\n | null = null;\n try {\n payload = JSON.parse(raw);\n } catch (e) {\n this.log(\n `data-aegis-token-data: invalid JSON, skipping anchor (${e})`,\n 'warn',\n );\n this.filledSlots.add(anchor); // don't retry on next refresh\n return;\n }\n if (!payload || !payload.campaign || !payload.campaign.id) {\n this.log(\n 'data-aegis-token-data: missing `campaign` in payload, skipping',\n 'warn',\n );\n this.filledSlots.add(anchor);\n return;\n }\n\n // U7 step 3 — pass the submit_url through to the renderer so\n // click handlers can POST the structured response (rating value,\n // NPS score, etc.) and atomically consume the token.\n this.renderCampaignIntoSlot(\n payload.campaign,\n anchor as HTMLElement,\n { submitUrl: payload.submit_url },\n );\n this.filledSlots.add(anchor);\n });\n }\n\n /**\n * Slot-mode counterpart to `displayCampaign`. Reuses the existing\n * lifecycle hooks (`campaign-will-show`, `displayedCampaigns`,\n * `campaign-shown`, impression tracking) so analytics + frequency\n * caps work the same way as overlay renders.\n *\n * Only the sub_types that make UX sense embedded are handled; the\n * rest (modal, full_screen, half_interstitial, alert, pip) silently\n * skip — those types only make sense as fullscreen overlays.\n */\n private renderCampaignIntoSlot(\n campaign: InAppCampaign,\n target: HTMLElement,\n options?: { submitUrl?: string },\n ): void {\n const proceed = this.emit('campaign-will-show', campaign);\n if (!proceed) {\n this.log(\n `slot campaign ${campaign.id} suppressed by campaign-will-show handler`,\n );\n return;\n }\n\n this.displayedCampaigns.add(campaign.id);\n this.addAnimationStyles();\n\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const bg = this.sanitizeColor(campaign.background_color || '#4169e1');\n const text = this.sanitizeColor(campaign.text_color || '#ffffff');\n const submitUrl = options?.submitUrl;\n\n let rendered = false;\n switch (campaign.sub_type) {\n case 'star_rating':\n rendered = this.renderStarRatingSlot(\n campaign, ic, bg, text, target, submitUrl,\n );\n break;\n case 'nps_survey':\n rendered = this.renderNPSSurveySlot(\n campaign, ic, bg, text, target, submitUrl,\n );\n break;\n // Future sub_types (quick_poll, countdown_offer, quiz, sticky_bar,\n // progress_bar, carousel_cards, product_recommendation) get added\n // here as merchants need them embedded. Until then, fall through\n // to the warn below — campaigns will still render as overlays via\n // the parallel `tryDisplayNextCampaign` path.\n default:\n this.log(\n `slot mode not yet supported for sub_type: ${campaign.sub_type ?? campaign.type}`,\n 'warn',\n );\n // Roll back the displayed marker so the overlay path can still\n // run — slot fallback shouldn't burn the campaign.\n this.displayedCampaigns.delete(campaign.id);\n return;\n }\n\n if (!rendered) return;\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n }\n\n /**\n * Slot-mode wrappers. They build a small card container (no overlay\n * positioning, no close button) and append the SHARED body element\n * the overlay path also uses. Body construction lives in the\n * `_buildXxxBody` helpers below so visual output stays identical\n * between overlay and slot modes — adding a renderer feature in\n * one place updates both.\n */\n private renderStarRatingSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n submitUrl?: string,\n ): boolean {\n const card = this._wrapInSlotCard(\n 'aegis-in-app-rating-card', campaign.id, bg, text,\n );\n card.appendChild(\n this._buildStarRatingBody(campaign, ic, text, 'slot', submitUrl),\n );\n target.appendChild(card);\n return true;\n }\n\n private renderNPSSurveySlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n submitUrl?: string,\n ): boolean {\n const card = this._wrapInSlotCard(\n 'aegis-in-app-nps-card', campaign.id, bg, text,\n );\n card.appendChild(\n this._buildNPSSurveyBody(campaign, ic, text, 'slot', submitUrl),\n );\n target.appendChild(card);\n return true;\n }\n\n /**\n * Token-bound submission helper. POSTs the structured response to\n * the per-token submit URL the page handler embedded. Best-effort\n * — failure is logged but doesn't throw (the customer already\n * clicked; we can't undo their interaction).\n */\n private _submitTokenResponse(\n submitUrl: string,\n payload: Record<string, unknown>,\n ): void {\n if (!submitUrl) return;\n // Fire-and-forget; we don't gate the UI on the response.\n fetch(submitUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ response: payload }),\n keepalive: true,\n }).catch((err) => {\n this.log(`token submit failed: ${err}`, 'warn');\n });\n }\n\n // --- Shared body builders (used by both overlay + slot paths) ----------\n //\n // Sizing: `'overlay'` matches the legacy fullscreen-modal scale (24px\n // padding, 18px title, 32px stars). `'slot'` is the embedded card\n // scale (20px padding, 16px title, 28px stars) — proportional, doesn't\n // dwarf merchant page chrome. Adding a new variant means a new tuple\n // here, not a new renderer.\n\n private _wrapInSlotCard(\n className: string,\n campaignId: string,\n bg: string,\n text: string,\n ): HTMLElement {\n const card = document.createElement('div');\n card.className = className;\n card.setAttribute('data-campaign-id', campaignId);\n card.style.cssText = `\n width: 100%; border-radius: 12px; overflow: hidden;\n background: ${bg}; color: ${text};\n box-shadow: 0 4px 12px rgba(0,0,0,0.06);\n `;\n return card;\n }\n\n private _buildStarRatingBody(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n text: string,\n variant: 'overlay' | 'slot',\n submitUrl?: string,\n ): HTMLElement {\n const isOverlay = variant === 'overlay';\n const padding = isOverlay ? '24px' : '20px';\n const titleSize = isOverlay ? '18px' : '16px';\n const titleWeight = isOverlay ? '700' : '600';\n const titleMargin = isOverlay ? '16px' : '12px';\n const starSize = isOverlay ? '32px' : '28px';\n const starsMarginBottom = isOverlay ? '16px' : '0';\n const hoverScale = isOverlay ? '1.2' : '1.15';\n\n const body = document.createElement('div');\n body.style.cssText = `padding: ${padding}; text-align: center;`;\n\n const title = document.createElement('div');\n title.style.cssText =\n `font-size: ${titleSize}; font-weight: ${titleWeight}; margin-bottom: ${titleMargin};`;\n title.textContent = campaign.title || 'Rate your experience';\n body.appendChild(title);\n\n const stars = document.createElement('div');\n stars.style.cssText =\n `display: flex; gap: 8px; justify-content: center;` +\n (starsMarginBottom !== '0' ? ` margin-bottom: ${starsMarginBottom};` : '');\n const maxStars = (ic.rating_scale as number) || 5;\n for (let i = 1; i <= maxStars; i++) {\n const star = document.createElement('span');\n star.style.cssText =\n `font-size: ${starSize}; cursor: pointer; transition: transform 0.1s; user-select: none;` +\n (text ? ` color: ${text};` : '');\n star.textContent = '☆'; // ☆\n const value = i;\n star.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, {\n sub_type: 'star_rating', value,\n });\n }\n });\n star.addEventListener('mouseenter', () => {\n star.style.transform = `scale(${hoverScale})`;\n });\n star.addEventListener('mouseleave', () => {\n star.style.transform = 'scale(1)';\n });\n stars.appendChild(star);\n }\n body.appendChild(stars);\n return body;\n }\n\n private _buildNPSSurveyBody(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n text: string,\n variant: 'overlay' | 'slot',\n submitUrl?: string,\n ): HTMLElement {\n const isOverlay = variant === 'overlay';\n const padding = isOverlay ? '24px' : '20px';\n const titleAlign = isOverlay ? 'center' : 'center';\n\n const body = document.createElement('div');\n body.style.cssText = `padding: ${padding};` +\n (isOverlay ? ' text-align: center;' : '');\n\n const title = document.createElement('div');\n title.style.cssText =\n `font-size: 16px; font-weight: ${isOverlay ? '700' : '600'}; ` +\n `margin-bottom: ${isOverlay ? '16px' : '12px'}; text-align: ${titleAlign};`;\n title.textContent =\n (ic.nps_question as string) || campaign.title ||\n 'How likely are you to recommend us?';\n body.appendChild(title);\n\n if (isOverlay) {\n // Overlay variant uses the round-pip scale + Not/Very labels\n // below — keeps the legacy modal look pixel-identical.\n const scale = document.createElement('div');\n scale.style.cssText =\n 'display: flex; gap: 4px; justify-content: center; flex-wrap: wrap; margin-bottom: 12px;';\n for (let i = 0; i <= 10; i++) {\n const btn = document.createElement('span');\n btn.style.cssText = `\n width: 28px; height: 28px; border-radius: 6px; display: flex;\n align-items: center; justify-content: center; font-size: 11px;\n font-weight: 600; cursor: pointer; background: ${text}33; color: ${text};\n transition: transform 0.1s;\n `;\n btn.textContent = String(i);\n const value = i;\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, {\n sub_type: 'nps_survey', value,\n });\n }\n });\n scale.appendChild(btn);\n }\n body.appendChild(scale);\n\n const labels = document.createElement('div');\n labels.style.cssText =\n 'display: flex; justify-content: space-between; font-size: 11px; opacity: 0.6; margin-bottom: 16px;';\n const notLikely = document.createElement('span');\n notLikely.textContent = 'Not likely';\n const veryLikely = document.createElement('span');\n veryLikely.textContent = 'Very likely';\n labels.appendChild(notLikely);\n labels.appendChild(veryLikely);\n body.appendChild(labels);\n return body;\n }\n\n // Slot variant: 11-column grid of bordered buttons — fits inline\n // card width without scrolling. No Not/Very labels (slot is small\n // enough that the customer sees both ends without prompting).\n const grid = document.createElement('div');\n grid.style.cssText =\n 'display: grid; grid-template-columns: repeat(11, 1fr); gap: 4px;';\n for (let n = 0; n <= 10; n++) {\n const btn = document.createElement('button');\n btn.style.cssText = `\n padding: 8px 0; border-radius: 6px; border: 1px solid ${text}33;\n background: transparent; color: ${text}; font-size: 13px; font-weight: 600;\n cursor: pointer; transition: background 0.15s;\n `;\n btn.textContent = String(n);\n const value = n;\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, {\n sub_type: 'nps_survey', value,\n });\n }\n });\n grid.appendChild(btn);\n }\n body.appendChild(grid);\n return body;\n }\n\n /**\n * Evaluate the currently armed campaigns against a client-side event\n * and render any that match their `client_trigger`.\n *\n * Called by the host app (e.g., the EcommerceTracker on product_viewed),\n * or by future TriggerEngine bridges. Safe to call repeatedly for the\n * same event — dedup happens via `displayedCampaigns`.\n *\n * Supported trigger types (align with the cell-plane server-side\n * `display_rules.trigger_type`):\n * - `custom_event` : fire when eventName matches config.event\n * - `product_match` : fire on `product_viewed` when eventData.product_id\n * matches config.product_id (string or string[])\n * - `delay` : client-side setTimeout — evaluated at armeng\n * time (kicked off from `displayCampaign`), not here.\n */\n onClientEvent(eventName: string, eventData: Record<string, unknown> = {}): void {\n for (const c of this.campaigns) {\n if (this.displayedCampaigns.has(c.id)) continue;\n if (!c.client_trigger) continue;\n // Conversion-aware suppression: trigger-gated campaigns silenced by\n // a prior notifyConversion() call are skipped until expiry.\n if (this.isSuppressed(c.id)) continue;\n if (this.matchesClientTrigger(c.client_trigger, eventName, eventData)) {\n this.displayCampaign(c);\n }\n }\n }\n\n private matchesClientTrigger(\n trigger: { type: string; config?: Record<string, unknown> },\n eventName: string,\n eventData: Record<string, unknown>,\n ): boolean {\n const cfg = trigger.config || {};\n switch (trigger.type) {\n case 'custom_event':\n return typeof cfg.event === 'string' && cfg.event === eventName;\n case 'product_match': {\n if (eventName !== 'product_viewed' && eventName !== 'product_view') {\n return false;\n }\n const wantedRaw = cfg.product_id;\n const wanted: string[] = Array.isArray(wantedRaw)\n ? (wantedRaw as string[])\n : typeof wantedRaw === 'string'\n ? [wantedRaw]\n : [];\n if (wanted.length === 0) return false;\n const actual = String(\n eventData.product_id ??\n eventData.productId ??\n (eventData.product as Record<string, unknown> | undefined)?.id ??\n '',\n );\n return wanted.includes(actual);\n }\n default:\n // Unknown or server-evaluated — do not auto-fire from the client.\n return false;\n }\n }\n \n private displayCampaign(campaign: InAppCampaign): void {\n // Lifecycle: `campaign-will-show` — CANCELLABLE. Host returns `false` to\n // suppress render (e.g. route-aware blocking, host-side frequency caps,\n // self-handled mode). When suppressed we DO NOT mark the campaign as\n // displayed so a subsequent `tryDisplayNextCampaign` (after the host\n // unblocks) can re-evaluate it.\n const proceed = this.emit('campaign-will-show', campaign);\n if (!proceed) {\n this.log(`campaign ${campaign.id} suppressed by campaign-will-show handler`);\n return;\n }\n\n this.displayedCampaigns.add(campaign.id);\n\n // Sub-type routing: interactive types are handled by dedicated renderers\n const interactiveSubTypes = new Set([\n 'spin_wheel', 'scratch_card', 'nps_survey', 'quiz',\n 'countdown_offer', 'star_rating', 'quick_poll',\n ]);\n\n if (campaign.sub_type && interactiveSubTypes.has(campaign.sub_type)) {\n this.renderInteractive(campaign);\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n }\n\n switch (campaign.type) {\n case 'modal':\n this.renderModal(campaign);\n break;\n case 'banner':\n this.renderBanner(campaign);\n break;\n case 'full_screen':\n this.renderFullScreen(campaign);\n break;\n case 'half_interstitial':\n this.renderHalfInterstitial(campaign);\n break;\n case 'alert':\n this.renderAlert(campaign);\n break;\n case 'pip':\n this.renderPIP(campaign);\n break;\n case 'tooltip':\n this.renderTooltip(campaign);\n break;\n // Preload-first display types (2026-04-22). These renderers own their\n // own impression tracking so we don't double-count alongside the\n // trailing `this.trackEvent(... 'impression')` below — return early.\n case 'carousel_cards':\n renderCarouselCards(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'sticky_bar':\n renderStickyBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'progress_bar':\n renderProgressBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'coachmark_tour':\n // coachmark_tour fires its own impression/dismiss/click events\n // from within its state machine — don't double-report here.\n renderCoachmarkTour(this.buildRenderContext(campaign));\n this.emit('campaign-shown', campaign);\n return;\n case 'product_recommendation':\n renderProductRecommendation(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n }\n\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n }\n\n /**\n * Build the shared context passed into the preload-first renderers.\n * Matches the interface in `./renderers/types.ts`. Kept as a private\n * method (rather than inlined at each call-site) so future renderer\n * additions stay consistent and easy to audit.\n */\n private buildRenderContext(campaign: InAppCampaign): RenderContext {\n return {\n campaign,\n trackEvent: (id, evt) => {\n void this.trackEvent(id, evt);\n },\n sanitizeUrl: (url: string) => this.sanitizeUrl(url),\n sanitizeColor: (color: string) => this.sanitizeColor(color),\n log: (msg: string, level?: 'log' | 'warn' | 'error') => this.log(msg, level),\n addAnimationStyles: () => this.addAnimationStyles(),\n };\n }\n\n /**\n * Renders interactive sub-type campaigns (spin wheel, NPS, quiz, etc.)\n * using DOM-safe rendering. These sub-types use the campaign's\n * interactive_config payload for type-specific behavior.\n */\n private renderInteractive(campaign: InAppCampaign): void {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const bg = this.sanitizeColor(campaign.background_color || '#4169e1');\n const text = this.sanitizeColor(campaign.text_color || '#ffffff');\n\n switch (campaign.sub_type) {\n case 'nps_survey':\n this.renderNPSSurvey(campaign, ic, bg, text);\n break;\n case 'countdown_offer':\n this.renderCountdownOffer(campaign, ic, bg, text);\n break;\n case 'star_rating':\n this.renderStarRating(campaign, ic, bg, text);\n break;\n case 'quick_poll':\n this.renderQuickPoll(campaign, ic, bg, text);\n break;\n case 'quiz':\n this.renderQuiz(campaign, ic, bg, text);\n break;\n case 'spin_wheel':\n case 'scratch_card':\n if (this.onInteractiveCampaign) {\n this.onInteractiveCampaign(campaign);\n } else {\n this.log(\n `${campaign.sub_type} campaign received but no onInteractiveCampaign handler wired — install via AegisMessageRuntime`,\n 'warn',\n );\n }\n break;\n default:\n this.log(`Unknown interactive sub_type: ${campaign.sub_type}`, 'warn');\n this.renderModal(campaign);\n }\n }\n\n // --- Interactive Renderers ---\n\n private renderNPSSurvey(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-nps-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 360px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = this._buildNPSSurveyBody(campaign, ic, text, 'overlay');\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderCountdownOffer(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-countdown-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 20px; font-weight: 700; margin-bottom: 8px;';\n title.textContent = campaign.title || 'Flash Sale';\n body.appendChild(title);\n\n const label = document.createElement('div');\n label.style.cssText = 'font-size: 13px; opacity: 0.8; margin-bottom: 12px;';\n label.textContent = (ic.countdown_label as string) || 'Sale ends in:';\n body.appendChild(label);\n\n // Countdown digits\n const digits = document.createElement('div');\n digits.style.cssText = 'display: flex; gap: 8px; justify-content: center; margin-bottom: 16px;';\n const digitStyle = `padding: 8px 12px; border-radius: 8px; font-size: 24px; font-weight: 700; font-family: monospace; background: ${text}22;`;\n for (const val of ['00', ':', '00', ':', '00']) {\n const el = document.createElement('span');\n if (val === ':') {\n el.style.cssText = 'font-size: 24px; font-weight: 700; align-self: center;';\n } else {\n el.style.cssText = digitStyle;\n }\n el.textContent = val;\n digits.appendChild(el);\n }\n body.appendChild(digits);\n\n // Start countdown from target or 2h default\n const targetStr = ic.countdown_target as string | undefined;\n if (targetStr) {\n const target = new Date(targetStr).getTime();\n const update = () => {\n const diff = Math.max(0, target - Date.now());\n const h = String(Math.floor(diff / 3600000)).padStart(2, '0');\n const m = String(Math.floor((diff % 3600000) / 60000)).padStart(2, '0');\n const s = String(Math.floor((diff % 60000) / 1000)).padStart(2, '0');\n const spans = digits.querySelectorAll('span');\n if (spans.length >= 5) {\n spans[0].textContent = h;\n spans[2].textContent = m;\n spans[4].textContent = s;\n }\n if (diff > 0) requestAnimationFrame(update);\n };\n update();\n }\n\n if (campaign.body) {\n const desc = document.createElement('div');\n desc.style.cssText = 'font-size: 14px; opacity: 0.85; margin-bottom: 16px;';\n desc.textContent = campaign.body;\n body.appendChild(desc);\n }\n\n if (campaign.button_text) {\n const btn = this.createCTAButton(campaign, bg, text);\n body.appendChild(btn);\n }\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderStarRating(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-rating-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = this._buildStarRatingBody(campaign, ic, text, 'overlay');\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderQuickPoll(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-poll-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 16px; font-weight: 700; margin-bottom: 16px;';\n title.textContent = campaign.title || 'Quick question';\n body.appendChild(title);\n\n const options = (ic.poll_options as string[]) || [];\n const optionsList = document.createElement('div');\n optionsList.style.cssText = 'display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px;';\n for (const opt of options) {\n const optBtn = document.createElement('button');\n optBtn.style.cssText = `\n padding: 10px 16px; border-radius: 10px; border: 1px solid ${text}33;\n background: transparent; color: ${text}; font-size: 14px; cursor: pointer;\n text-align: left; transition: background 0.15s;\n `;\n optBtn.textContent = opt;\n optBtn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n });\n optionsList.appendChild(optBtn);\n }\n body.appendChild(optionsList);\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderQuiz(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-quiz-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 360px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 20px 60px rgba(0,0,0,0.15);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 18px; font-weight: 700; margin-bottom: 8px;';\n title.textContent = campaign.title || 'Quiz';\n body.appendChild(title);\n\n const questions = (ic.questions as Array<{ question: string; options: string[] }>) || [];\n let currentQ = 0;\n\n const renderQuestion = () => {\n // Clear previous content except title\n while (body.childNodes.length > 1) {\n body.removeChild(body.lastChild!);\n }\n\n if (currentQ >= questions.length) {\n const result = document.createElement('div');\n result.style.cssText = 'font-size: 16px; margin: 16px 0;';\n result.textContent = (ic.thank_you_message as string) || 'Thanks for completing the quiz!';\n body.appendChild(result);\n this.trackEvent(campaign.id, 'clicked');\n this.addCloseButton(body, overlay, campaign.id);\n return;\n }\n\n const q = questions[currentQ];\n const progress = document.createElement('div');\n progress.style.cssText = 'font-size: 12px; opacity: 0.6; margin-bottom: 12px;';\n progress.textContent = `Question ${currentQ + 1} of ${questions.length}`;\n body.appendChild(progress);\n\n const questionText = document.createElement('div');\n questionText.style.cssText = 'font-size: 14px; font-weight: 600; margin-bottom: 16px;';\n questionText.textContent = q.question;\n body.appendChild(questionText);\n\n const optionsDiv = document.createElement('div');\n optionsDiv.style.cssText = 'display: flex; flex-direction: column; gap: 8px;';\n for (const opt of q.options) {\n const optBtn = document.createElement('button');\n optBtn.style.cssText = `\n padding: 10px 16px; border-radius: 10px; border: 1px solid ${text}33;\n background: transparent; color: ${text}; font-size: 14px; cursor: pointer;\n text-align: left; transition: background 0.15s;\n `;\n optBtn.textContent = opt;\n optBtn.addEventListener('click', () => {\n currentQ++;\n renderQuestion();\n });\n optionsDiv.appendChild(optBtn);\n }\n body.appendChild(optionsDiv);\n this.addCloseButton(body, overlay, campaign.id);\n };\n\n renderQuestion();\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n // --- Shared Rendering Helpers ---\n\n private createOverlay(className: string): HTMLElement {\n const overlay = document.createElement('div');\n overlay.className = className;\n overlay.style.cssText = `\n position: fixed; top: 0; left: 0; right: 0; bottom: 0;\n background: rgba(0,0,0,0.5); display: flex; align-items: center;\n justify-content: center; z-index: 99999; animation: aegisFadeIn 0.3s ease;\n `;\n return overlay;\n }\n\n private createCTAButton(campaign: InAppCampaign, bg: string, text: string): HTMLElement {\n const btn = document.createElement('button');\n btn.style.cssText = `\n display: inline-block; padding: 10px 28px; border-radius: 999px;\n font-size: 14px; font-weight: 600; cursor: pointer; border: none;\n background: ${text}; color: ${bg}; transition: transform 0.15s;\n `;\n btn.textContent = campaign.button_text || 'OK';\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (campaign.action_url) {\n const safeUrl = this.sanitizeUrl(campaign.action_url);\n if (safeUrl) window.open(safeUrl, '_blank');\n }\n });\n return btn;\n }\n\n private addCloseButton(container: HTMLElement, overlay: HTMLElement, campaignId: string): void {\n const close = document.createElement('div');\n close.style.cssText = 'margin-top: 12px; font-size: 12px; opacity: 0.6; cursor: pointer;';\n close.textContent = 'Close';\n close.addEventListener('click', () => {\n this.trackEvent(campaignId, 'dismissed');\n this.removeModal(overlay);\n });\n container.appendChild(close);\n }\n \n /**\n * Navigate to a campaign CTA URL.\n *\n * Dispatches a cancellable `aegis:campaign-click` CustomEvent so host\n * apps (e.g., the storefront SPA) can intercept and route in-place via\n * their client-side router, avoiding a full page reload that re-runs\n * SSR + re-renders the location picker / banner / cart drawer state.\n *\n * The host calls `event.preventDefault()` to suppress the hard nav and\n * handle the URL itself. If no listener calls preventDefault, the SDK\n * falls through to `window.location.href` so plain HTML pages without a\n * SPA still get the user to the destination.\n *\n * Industry parallel: CleverTap dispatches `clevertap-deeplink-click`,\n * MoEngage dispatches `MoE_inappRedirect`. The pattern lets the same\n * SDK serve both vanilla websites (full nav fallback) and SPAs\n * (in-place state change) without per-host configuration.\n */\n private navigateToCampaignAction(\n campaign: InAppCampaign,\n safeUrl: string,\n buttonId: string = 'cta',\n ): void {\n if (typeof window === 'undefined') return;\n\n // Typed lifecycle hook (1.8.0). Mirror the DOM `preventDefault` contract\n // — a handler returning `false` OR mutating `defaultPrevented` via the\n // helper suppresses the SDK's hard-nav. Built first so handlers attached\n // via the typed API see the click before the DOM event fires.\n let typedDefaultPrevented = false;\n const typedEvent: CampaignClickEvent = {\n campaign,\n action_url: safeUrl,\n button_id: buttonId,\n preventDefault: () => {\n typedDefaultPrevented = true;\n typedEvent.defaultPrevented = true;\n },\n defaultPrevented: false,\n };\n const typedProceed = this.emit('campaign-click', typedEvent);\n\n // DOM CustomEvent path — preserved for backward compat (1.7.x consumers\n // already listen for `aegis:campaign-click`) and for advanced patterns\n // (multi-frame embeds, host-app code that runs before the SDK is\n // instantiated, debugging via DevTools event listener panel).\n const domEvent = new CustomEvent('aegis:campaign-click', {\n detail: {\n campaign_id: campaign.id,\n campaign_type: campaign.type,\n action_url: safeUrl,\n button_id: buttonId,\n },\n cancelable: true,\n });\n const domProceed = window.dispatchEvent(domEvent);\n\n // Either path can suppress the hard-nav. We OR the prevent signals so\n // host apps don't have to remember to handle both — registering on\n // either API is enough.\n const suppressed =\n !typedProceed ||\n typedDefaultPrevented ||\n !domProceed ||\n domEvent.defaultPrevented;\n\n if (!suppressed) {\n window.location.href = safeUrl;\n }\n }\n\n private renderBanner(campaign: InAppCampaign): void {\n const banner = document.createElement('div');\n banner.className = 'aegis-in-app-banner';\n banner.setAttribute('data-campaign-id', campaign.id);\n \n banner.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n background: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.text_color || '#ffffff')};\n padding: 16px;\n z-index: 999999;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideDown 0.3s ease-out;\n `;\n \n const contentContainer = document.createElement('div');\n contentContainer.style.cssText = 'flex: 1; display: flex; align-items: center; gap: 12px;';\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 40px; height: 40px; border-radius: 4px; object-fit: cover;';\n contentContainer.appendChild(img);\n }\n }\n \n const textContainer = document.createElement('div');\n textContainer.style.cssText = 'flex: 1;';\n \n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 600; font-size: 14px; margin-bottom: 4px;';\n textContainer.appendChild(title);\n \n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.9;';\n textContainer.appendChild(body);\n \n contentContainer.appendChild(textContainer);\n \n const actionsContainer = document.createElement('div');\n actionsContainer.style.cssText = 'display: flex; align-items: center; gap: 12px; margin-left: 16px;';\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: white;\n color: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-weight: 600;\n cursor: pointer;\n font-size: 13px;\n white-space: nowrap;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeBanner(banner);\n });\n \n actionsContainer.appendChild(ctaButton);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n background: transparent;\n border: none;\n color: inherit;\n font-size: 20px;\n cursor: pointer;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0.7;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeBanner(banner);\n });\n \n actionsContainer.appendChild(closeButton);\n \n banner.appendChild(contentContainer);\n banner.appendChild(actionsContainer);\n \n this.addAnimationStyles();\n document.body.appendChild(banner);\n }\n \n private renderModal(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-modal-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-in-app-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 8px;\n max-width: 500px;\n width: 90%;\n max-height: 80vh;\n overflow: auto;\n box-shadow: 0 10px 40px rgba(0,0,0,0.2);\n animation: aegisScaleIn 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 200px; object-fit: cover; border-radius: 8px 8px 0 0;';\n modal.appendChild(img);\n }\n }\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 24px;';\n \n const title = document.createElement('h2');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 20px; font-weight: 600; color: #1a1a1a;';\n content.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0 0 20px 0; font-size: 15px; line-height: 1.5; color: #4a4a4a;';\n content.appendChild(body);\n \n const actions = document.createElement('div');\n actions.style.cssText = 'display: flex; gap: 12px; justify-content: flex-end;';\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.text_color || '#ffffff')};\n border: none;\n padding: 10px 24px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n \n actions.appendChild(ctaButton);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: transparent;\n border: 1px solid #d0d0d0;\n color: #4a4a4a;\n padding: 10px 24px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n actions.appendChild(closeButton);\n \n content.appendChild(actions);\n modal.appendChild(content);\n overlay.appendChild(modal);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderFullScreen(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-fullscreen-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: ${this.sanitizeColor(campaign.background_color || '#ffffff')};\n color: ${this.sanitizeColor(campaign.text_color || '#1a1a1a')};\n z-index: 1000001;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n animation: aegisFadeIn 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n overflow-y: auto;\n `;\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'max-width: 100%; max-height: 40vh; object-fit: contain; margin-bottom: 32px;';\n overlay.appendChild(img);\n }\n }\n \n const contentContainer = document.createElement('div');\n contentContainer.style.cssText = 'max-width: 600px; text-align: center;';\n \n const title = document.createElement('h1');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 32px; font-weight: 700;';\n contentContainer.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0 0 32px 0; font-size: 18px; line-height: 1.6; opacity: 0.9;';\n contentContainer.appendChild(body);\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(campaign.text_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.background_color || '#ffffff')};\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 18px;\n cursor: pointer;\n margin-bottom: 16px;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n \n contentContainer.appendChild(ctaButton);\n }\n \n overlay.appendChild(contentContainer);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 20px;\n right: 20px;\n background: transparent;\n border: none;\n color: inherit;\n font-size: 32px;\n cursor: pointer;\n padding: 0;\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0.6;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n overlay.appendChild(closeButton);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderHalfInterstitial(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-half-interstitial-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 1000000;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-in-app-half-interstitial';\n modal.style.cssText = `\n background: white;\n border-radius: 16px 16px 0 0;\n width: 100%;\n max-width: 600px;\n max-height: 60vh;\n overflow: auto;\n box-shadow: 0 -4px 20px rgba(0,0,0,0.2);\n animation: aegisSlideUp 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 200px; object-fit: cover;';\n modal.appendChild(img);\n }\n }\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 32px 24px;';\n \n const title = document.createElement('h2');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n content.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; line-height: 1.5; color: #4a4a4a;';\n content.appendChild(body);\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(campaign.background_color || '#1a73e8')};\n color: ${this.sanitizeColor(campaign.text_color || '#ffffff')};\n border: none;\n padding: 14px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n \n content.appendChild(ctaButton);\n }\n \n modal.appendChild(content);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: rgba(255,255,255,0.9);\n border: none;\n color: #333;\n font-size: 24px;\n cursor: pointer;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderAlert(campaign: InAppCampaign): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-alert-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.6);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.2s ease-out;\n `;\n \n const alert = document.createElement('div');\n alert.className = 'aegis-in-app-alert';\n alert.style.cssText = `\n background: white;\n border-radius: 12px;\n max-width: 320px;\n width: 85%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n animation: aegisScaleIn 0.2s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n overflow: hidden;\n `;\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 24px 20px; text-align: center;';\n \n const title = document.createElement('h3');\n title.textContent = campaign.title;\n title.style.cssText = 'margin: 0 0 8px 0; font-size: 18px; font-weight: 700; color: #1a1a1a;';\n content.appendChild(title);\n \n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = 'margin: 0; font-size: 14px; line-height: 1.4; color: #666;';\n content.appendChild(body);\n \n alert.appendChild(content);\n \n const buttonContainer = document.createElement('div');\n buttonContainer.style.cssText = 'display: flex; border-top: 1px solid #e0e0e0;';\n \n if (campaign.action_url && campaign.button_text) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = campaign.button_text;\n ctaButton.style.cssText = `\n flex: 1;\n background: transparent;\n border: none;\n border-right: 1px solid #e0e0e0;\n color: #1a73e8;\n padding: 14px;\n font-weight: 600;\n font-size: 16px;\n cursor: pointer;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n \n buttonContainer.appendChild(ctaButton);\n }\n \n const cancelButton = document.createElement('button');\n cancelButton.textContent = 'Cancel';\n cancelButton.style.cssText = `\n flex: 1;\n background: transparent;\n border: none;\n color: #666;\n padding: 14px;\n font-weight: 600;\n font-size: 16px;\n cursor: pointer;\n `;\n \n cancelButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n buttonContainer.appendChild(cancelButton);\n \n alert.appendChild(buttonContainer);\n overlay.appendChild(alert);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderPIP(campaign: InAppCampaign): void {\n const pip = document.createElement('div');\n pip.className = 'aegis-in-app-pip';\n pip.setAttribute('data-campaign-id', campaign.id);\n \n pip.style.cssText = `\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 320px;\n background: black;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 8px 24px rgba(0,0,0,0.3);\n z-index: 999999;\n animation: aegisSlideUp 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (campaign.video_url) {\n const video = document.createElement('video');\n const safeUrl = this.sanitizeUrl(campaign.video_url);\n if (safeUrl) {\n video.src = safeUrl;\n video.controls = true;\n video.autoplay = true;\n video.muted = true;\n video.style.cssText = 'width: 100%; display: block;';\n pip.appendChild(video);\n }\n } else if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; display: block;';\n pip.appendChild(img);\n }\n }\n \n const overlay = document.createElement('div');\n overlay.style.cssText = `\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: linear-gradient(to top, rgba(0,0,0,0.9), transparent);\n padding: 40px 16px 16px;\n color: white;\n `;\n \n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-size: 14px; font-weight: 600; margin-bottom: 4px;';\n overlay.appendChild(title);\n \n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 12px; opacity: 0.9;';\n overlay.appendChild(body);\n \n pip.appendChild(overlay);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 8px;\n right: 8px;\n background: rgba(0,0,0,0.6);\n border: none;\n color: white;\n font-size: 18px;\n cursor: pointer;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n pip.style.animation = 'aegisSlideDown 0.3s ease-out';\n setTimeout(() => {\n if (pip.parentNode) {\n pip.parentNode.removeChild(pip);\n }\n }, 300);\n });\n \n pip.appendChild(closeButton);\n \n if (campaign.action_url) {\n pip.style.cursor = 'pointer';\n pip.addEventListener('click', (e) => {\n if (e.target !== closeButton) {\n this.trackEvent(campaign.id, 'clicked');\n const safeUrl = this.sanitizeUrl(campaign.action_url!);\n if (safeUrl) {\n window.open(safeUrl, '_blank');\n }\n }\n });\n }\n \n this.addAnimationStyles();\n document.body.appendChild(pip);\n }\n \n private removeBanner(banner: HTMLElement): void {\n banner.style.animation = 'aegisSlideUp 0.3s ease-out';\n setTimeout(() => {\n if (banner.parentNode) {\n banner.parentNode.removeChild(banner);\n }\n }, 300);\n }\n \n private removeModal(overlay: HTMLElement): void {\n overlay.style.animation = 'aegisFadeOut 0.3s ease-out';\n setTimeout(() => {\n if (overlay.parentNode) {\n overlay.parentNode.removeChild(overlay);\n }\n }, 300);\n }\n \n private renderTooltip(campaign: InAppCampaign): void {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const anchorSelector = (ic.tooltip_anchor_selector as string) || '[data-aegis-tooltip]';\n const preferredPosition = (ic.tooltip_position as string) || 'bottom'; // top | bottom | left | right\n\n const anchor = document.querySelector(anchorSelector);\n if (!anchor) {\n this.log(`Tooltip anchor not found: ${anchorSelector}`, 'warn');\n return;\n }\n\n const bg = this.sanitizeColor(campaign.background_color || '#1a1a1a');\n const textColor = this.sanitizeColor(campaign.text_color || '#ffffff');\n\n // Tooltip container (positioned absolute to body)\n const tooltip = document.createElement('div');\n tooltip.className = 'aegis-in-app-tooltip';\n tooltip.setAttribute('data-campaign-id', campaign.id);\n tooltip.style.cssText = `\n position: absolute; z-index: 1000001; max-width: 280px; width: max-content;\n background: ${bg}; color: ${textColor}; border-radius: 10px; padding: 14px 16px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.18); font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.2s ease-out; pointer-events: auto;\n `;\n\n // Arrow\n const arrow = document.createElement('div');\n arrow.className = 'aegis-tooltip-arrow';\n arrow.style.cssText = `\n position: absolute; width: 10px; height: 10px; background: ${bg};\n transform: rotate(45deg);\n `;\n\n // Close button\n const closeBtn = document.createElement('button');\n closeBtn.textContent = '\\u00d7';\n closeBtn.style.cssText = `\n position: absolute; top: 6px; right: 8px; background: none; border: none;\n color: ${textColor}; opacity: 0.6; font-size: 16px; cursor: pointer; padding: 0; line-height: 1;\n `;\n\n const dismiss = () => {\n tooltip.style.animation = 'aegisFadeOut 0.2s ease-out';\n setTimeout(() => { tooltip.parentNode?.removeChild(tooltip); }, 200);\n this.trackEvent(campaign.id, 'dismissed');\n };\n\n closeBtn.addEventListener('click', (e) => { e.stopPropagation(); dismiss(); });\n\n // Title\n if (campaign.title) {\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-size: 13px; font-weight: 700; margin-bottom: 4px; padding-right: 16px;';\n tooltip.appendChild(title);\n }\n\n // Body\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 12px; line-height: 1.4; opacity: 0.9;';\n tooltip.appendChild(body);\n\n // CTA button\n if (campaign.button_text && campaign.action_url) {\n const cta = document.createElement('a');\n cta.textContent = campaign.button_text;\n cta.href = campaign.action_url;\n cta.style.cssText = `\n display: inline-block; margin-top: 8px; font-size: 12px; font-weight: 600;\n color: ${textColor}; text-decoration: underline; cursor: pointer;\n `;\n cta.addEventListener('click', () => { this.trackEvent(campaign.id, 'clicked'); });\n tooltip.appendChild(cta);\n }\n\n tooltip.appendChild(closeBtn);\n tooltip.appendChild(arrow);\n document.body.appendChild(tooltip);\n\n // Position relative to anchor\n const anchorRect = anchor.getBoundingClientRect();\n const tooltipRect = tooltip.getBoundingClientRect();\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n const gap = 10;\n\n let top = 0;\n let left = 0;\n let arrowTop = '';\n let arrowLeft = '';\n let arrowBottom = '';\n let arrowRight = '';\n\n switch (preferredPosition) {\n case 'top':\n top = anchorRect.top + scrollY - tooltipRect.height - gap;\n left = anchorRect.left + scrollX + (anchorRect.width - tooltipRect.width) / 2;\n arrowBottom = '-5px';\n arrowLeft = `${tooltipRect.width / 2 - 5}px`;\n break;\n case 'left':\n top = anchorRect.top + scrollY + (anchorRect.height - tooltipRect.height) / 2;\n left = anchorRect.left + scrollX - tooltipRect.width - gap;\n arrowRight = '-5px';\n arrowTop = `${tooltipRect.height / 2 - 5}px`;\n break;\n case 'right':\n top = anchorRect.top + scrollY + (anchorRect.height - tooltipRect.height) / 2;\n left = anchorRect.right + scrollX + gap;\n arrowLeft = '-5px';\n arrowTop = `${tooltipRect.height / 2 - 5}px`;\n break;\n default: // bottom\n top = anchorRect.bottom + scrollY + gap;\n left = anchorRect.left + scrollX + (anchorRect.width - tooltipRect.width) / 2;\n arrowTop = '-5px';\n arrowLeft = `${tooltipRect.width / 2 - 5}px`;\n break;\n }\n\n // Clamp to viewport\n left = Math.max(8, Math.min(left, window.innerWidth + scrollX - tooltipRect.width - 8));\n top = Math.max(8, top);\n\n tooltip.style.top = `${top}px`;\n tooltip.style.left = `${left}px`;\n arrow.style.top = arrowTop || '';\n arrow.style.left = arrowLeft || '';\n arrow.style.bottom = arrowBottom || '';\n arrow.style.right = arrowRight || '';\n\n // Dismiss on outside click\n const outsideClickHandler = (e: MouseEvent) => {\n if (!tooltip.contains(e.target as Node) && !anchor.contains(e.target as Node)) {\n document.removeEventListener('click', outsideClickHandler);\n dismiss();\n }\n };\n setTimeout(() => document.addEventListener('click', outsideClickHandler), 100);\n }\n\n private addAnimationStyles(): void {\n if (document.getElementById('aegis-in-app-styles')) {\n return;\n }\n \n const style = document.createElement('style');\n style.id = 'aegis-in-app-styles';\n style.textContent = `\n @keyframes aegisSlideDown {\n from { transform: translateY(-100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes aegisSlideUp {\n from { transform: translateY(0); opacity: 1; }\n to { transform: translateY(-100%); opacity: 0; }\n }\n \n @keyframes aegisFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n \n @keyframes aegisFadeOut {\n from { opacity: 1; }\n to { opacity: 0; }\n }\n \n @keyframes aegisScaleIn {\n from { transform: scale(0.9); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n }\n\n /* Bottom-anchored slide IN (opposite of aegisSlideUp which slides OUT).\n Used by the preload-first renderers: sticky_bar (bottom),\n progress_bar, carousel_cards, product_recommendation. */\n @keyframes aegisSlideInFromBottom {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n `;\n \n document.head.appendChild(style);\n }\n \n private sanitizeUrl(url: string): string | null {\n try {\n const parsedUrl = new URL(url, window.location.origin);\n \n if (parsedUrl.protocol === 'javascript:' || parsedUrl.protocol === 'data:') {\n this.log(`Blocked unsafe URL: ${url}`, 'error');\n return null;\n }\n \n return parsedUrl.href;\n } catch (error) {\n this.log(`Invalid URL: ${url}`, 'error');\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n if (/^#[0-9A-Fa-f]{3,6}$/.test(color)) {\n return color;\n }\n \n if (/^rgb\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*\\)$/.test(color)) {\n return color;\n }\n \n if (/^rgba\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*[\\d.]+\\s*\\)$/.test(color)) {\n return color;\n }\n \n const namedColors = ['white', 'black', 'red', 'green', 'blue', 'yellow', 'orange', 'purple', 'pink', 'gray', 'transparent'];\n if (namedColors.includes(color.toLowerCase())) {\n return color;\n }\n \n return '#000000';\n }\n \n /**\n * Track in-app event via the standard Event Ingress pipeline.\n *\n * Events flow: SDK → Event Ingress → Kafka → Governance Consumer\n * → Event Engine → ClickHouse (in_app_events + events_with_ttl)\n *\n * The event_type uses the canonical prefix `in_app.` so the event\n * switchboard maps it to the correct canonical form:\n * in_app.impression → engagement.view\n * in_app.clicked → engagement.click\n * in_app.dismissed → engagement.dismiss\n */\n private async trackEvent(campaignId: string, eventType: 'impression' | 'clicked' | 'dismissed'): Promise<void> {\n // Lifecycle: `campaign-dismiss` — fire from this single chokepoint so\n // every renderer (8 sites today + future ones) emits consistently.\n // Source granularity (close_button / overlay / esc / auto_timeout) can\n // be refined in a future minor by passing source through to trackEvent;\n // for 1.8.0 we surface the event itself since that's the high-value\n // signal host apps need (inbox state updates, dismiss analytics).\n if (eventType === 'dismissed') {\n const campaign = this.campaigns.find((c) => c.id === campaignId);\n if (campaign) {\n this.emit('campaign-dismiss', {\n campaign,\n source: 'close_button',\n });\n }\n }\n\n try {\n // Use the public SDK scheme (/v1/in_app/events) — the gateway has an\n // explicit handler that auths via X-Aegis-Write-Key and forwards to\n // event-switchboard. Direct POST to /api/v1/events bypasses the SDK\n // auth model and hits the JWT preHandler → 401.\n // See docs/architecture/API_ROUTING.md §5.\n const url = `${this.apiHost}/v1/in_app/events`;\n const externalEventId = `inapp_${campaignId}_${eventType}_${Date.now()}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey,\n };\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n\n // Plumb the same workspace cascade the main analytics SDK uses\n // (config → ?ws= → URL path slug → setWorkspace runtime → session\n // storage). Without this, in-app engagement events arrive at\n // event-ingress unscoped and fall back to the org's primary\n // workspace — see PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n const workspaceId = this.getWorkspaceId?.();\n\n const body = {\n campaign_id: campaignId,\n event_type: eventType,\n user_id: this.userId,\n contact_id: this.contactId,\n anonymous_id: this.userId,\n platform: 'web',\n workspace_id: workspaceId,\n metadata: {\n property_id: this.propertyId,\n variant_id: this.getVariantId(campaignId) ?? undefined,\n },\n idempotency_key: externalEventId,\n };\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n credentials: 'include',\n }).catch(error => {\n this.log(`Error tracking event: ${error}`, 'error');\n });\n\n this.log(`Tracked ${eventType} event for campaign ${campaignId}`);\n } catch (error) {\n this.log(`Error tracking event: ${error}`, 'error');\n }\n }\n \n private log(message: string, level: 'log' | 'warn' | 'error' = 'log'): void {\n if (this.debugMode) {\n console[level](`[AegisInApp] ${message}`);\n }\n }\n \n destroy(options?: { clearABState?: boolean }): void {\n this.disconnectSSE();\n\n // P1 — clear any pending qualifying-event refresh so a destroy() during\n // the debounce window doesn't fire a stray fetch after the manager is gone.\n if (this.refreshDebounceTimer) {\n clearTimeout(this.refreshDebounceTimer);\n this.refreshDebounceTimer = undefined;\n }\n\n if (typeof document !== 'undefined') {\n document.querySelectorAll(\n '.aegis-in-app-banner, .aegis-in-app-modal-overlay, .aegis-in-app-fullscreen-overlay, ' +\n '.aegis-in-app-half-interstitial-overlay, .aegis-in-app-alert-overlay, .aegis-in-app-pip, ' +\n '.aegis-in-app-nps-overlay, .aegis-in-app-countdown-overlay, .aegis-in-app-rating-overlay, ' +\n '.aegis-in-app-poll-overlay, .aegis-in-app-quiz-overlay, ' +\n // F2/F3 / U8 — slot-rendered card classes\n '.aegis-in-app-rating-card, .aegis-in-app-nps-card'\n ).forEach(el => {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n });\n\n const styles = document.getElementById('aegis-in-app-styles');\n if (styles && styles.parentNode) {\n styles.parentNode.removeChild(styles);\n }\n }\n\n // Optionally clear A/B assignment state\n if (options?.clearABState && typeof localStorage !== 'undefined') {\n localStorage.removeItem('aegis_ab_assignments');\n }\n\n this.isInitialized = false;\n this.log('AegisInApp destroyed');\n }\n}\n","/**\n * renderPreview — Static Preview Renderer for Dashboard iframe (Critical Fix A)\n *\n * Used exclusively by the sandboxed iframe preview route\n * (`/api/preview/in-app/route.tsx`). Renders a single campaign into the\n * current document body using the same rendering logic as the production SDK.\n *\n * Data flow:\n * editor-sidebar.tsx → onChange → formState → postMessage({type:'preview_update', config})\n * → iframe receives message → calls renderPreview(config)\n *\n * This ensures 100% fidelity between the dashboard editor preview and\n * production rendering — both use the same SDK code.\n */\n\nimport type { InAppCampaign } from './AegisInAppManager';\nimport { AegisInAppManager } from './AegisInAppManager';\n\n/**\n * Renders a single in-app campaign into the current document for preview.\n *\n * Creates a temporary AegisInAppManager with preview-only config (no tracking,\n * no SSE, no network requests). Calls the same rendering pipeline as production.\n */\nexport function renderPreview(config: InAppCampaign & { interactive_config?: Record<string, unknown> }): void {\n // Clear previous preview\n document.querySelectorAll(\n '[class^=\"aegis-in-app-\"]'\n ).forEach((el) => {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n });\n\n if (!config) return;\n\n // Create a lightweight preview-only manager\n const manager = new AegisInAppManager({\n writeKey: 'preview-mode',\n apiHost: '',\n debugMode: false,\n enableSSE: false,\n });\n\n // Override trackEvent to be a no-op in preview mode\n // Access private via any cast — preview only, not production code\n const m = manager as unknown as {\n displayCampaign: (campaign: InAppCampaign) => void;\n trackEvent: (campaignId: string, eventType: string) => Promise<void>;\n addAnimationStyles: () => void;\n };\n\n // No-op tracking for preview\n m.trackEvent = async () => {};\n\n // Ensure animation styles are injected\n m.addAnimationStyles();\n\n // Render the campaign\n m.displayCampaign(config);\n}\n","/**\n * AegisPlacementManager - Web SDK Placement Module\n * \n * Real-time SSE architecture for inline content placements.\n * \n * Security:\n * - XSS Protection: Uses DOMPurify (when available) with allowlisted tags/attrs; safe text-only fallback\n * - URL Validation: Prevents javascript: protocol injection\n * - CSP Compatible: No inline styles in HTML strings\n * \n * Architecture:\n * - Connects to SSE endpoint for real-time placement updates\n * - Initial fetch on load, then SSE for updates\n * - Caches placement content locally in memory\n * - Renders content into pre-defined UI slots (inline, not overlay)\n * - Tracks events (impression, click, conversion) asynchronously\n * \n * Key Differences from In-App Messages:\n * - INLINE content (part of layout), not overlays\n * - Content rendered immediately on slot registration\n * - No trigger rules (shown when slot loads)\n * - Supports banner, card, carousel, video, HTML content types\n */\n\nexport interface PlacementContent {\n placement_id: string;\n variant_id: string;\n content_type: 'banner' | 'card' | 'carousel' | 'video' | 'html' | 'dynamic_injection';\n content: Record<string, any>;\n css_selector?: string;\n injection_mode?: 'replace' | 'append' | 'prepend';\n}\n\nexport interface PlacementSlot {\n placementId: string;\n containerId: string;\n fallbackContent?: string;\n onRender?: (content: PlacementContent) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface AegisPlacementConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n debugMode?: boolean;\n enableSSE?: boolean;\n /**\n * Workspace cascade reader. Host SDK sets this to\n * `() => aegis.getEffectiveWorkspaceId()` so placement\n * impression/click/conversion events arrive at the gateway with the\n * same workspace context the main analytics SDK uses. See\n * PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n */\n getWorkspaceId?: () => string | undefined;\n}\n\nexport class AegisPlacementManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private debugMode: boolean;\n private enableSSE: boolean;\n private getWorkspaceId?: () => string | undefined;\n\n private placements: Map<string, PlacementContent> = new Map();\n private slots: Map<string, PlacementSlot> = new Map();\n private renderedSlots = new Set<string>();\n private eventSource?: EventSource;\n private isInitialized = false;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n\n constructor(config: AegisPlacementConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n this.userId = config.userId;\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.debugMode = config.debugMode || false;\n this.enableSSE = config.enableSSE !== false;\n this.getWorkspaceId = config.getWorkspaceId;\n }\n \n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisPlacements already initialized');\n return;\n }\n \n await this.refreshPlacements();\n \n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n \n this.isInitialized = true;\n this.log('AegisPlacements initialized successfully');\n }\n \n register(placementId: string, options: Omit<PlacementSlot, 'placementId'>): void {\n const slot: PlacementSlot = {\n placementId,\n ...options\n };\n \n this.slots.set(placementId, slot);\n this.log(`Registered placement slot: ${placementId}`);\n \n const existingContent = this.placements.get(placementId);\n if (existingContent) {\n this.renderSlot(slot, existingContent);\n } else if (options.fallbackContent) {\n this.renderFallback(slot);\n }\n }\n \n unregister(placementId: string): void {\n this.slots.delete(placementId);\n this.renderedSlots.delete(placementId);\n this.log(`Unregistered placement slot: ${placementId}`);\n }\n \n async refreshPlacements(): Promise<void> {\n try {\n const placementIds = Array.from(this.slots.keys());\n \n if (placementIds.length === 0) {\n this.log('No registered slots, skipping refresh');\n return;\n }\n \n const url = `${this.apiHost}/v1/placements/content?placement_ids=${placementIds.join(',')}`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Device-Type': this.getDeviceType(),\n 'X-Platform': 'web'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, { headers });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch placements: ${response.status}`);\n }\n \n const data = await response.json();\n \n this.placements.clear();\n \n for (const placement of data.placements || []) {\n this.placements.set(placement.placement_id, placement);\n }\n \n this.renderAllSlots();\n \n this.log(`Refreshed ${this.placements.size} placements`);\n \n } catch (error) {\n this.log(`Error refreshing placements: ${error}`, true);\n }\n }\n \n private renderAllSlots(): void {\n for (const [placementId, slot] of this.slots.entries()) {\n const content = this.placements.get(placementId);\n \n if (content) {\n this.renderSlot(slot, content);\n } else if (slot.fallbackContent) {\n this.renderFallback(slot);\n }\n }\n }\n \n private renderSlot(slot: PlacementSlot, content: PlacementContent): void {\n try {\n if (content.content_type === 'dynamic_injection') {\n this.renderDynamicInjection(content);\n } else {\n const container = document.getElementById(slot.containerId);\n \n if (!container) {\n this.log(`Container not found: ${slot.containerId}`, true);\n return;\n }\n \n container.innerHTML = '';\n \n switch (content.content_type) {\n case 'banner':\n this.renderBanner(container, content);\n break;\n case 'card':\n this.renderCard(container, content);\n break;\n case 'carousel':\n this.renderCarousel(container, content);\n break;\n case 'video':\n this.renderVideo(container, content);\n break;\n case 'html':\n this.renderHTML(container, content);\n break;\n default:\n this.log(`Unknown content type: ${content.content_type}`, true);\n return;\n }\n }\n \n if (!this.renderedSlots.has(slot.placementId)) {\n this.trackEvent(content.placement_id, content.variant_id, 'impression');\n this.renderedSlots.add(slot.placementId);\n }\n \n if (slot.onRender) {\n slot.onRender(content);\n }\n \n this.log(`Rendered placement: ${content.placement_id} (${content.content_type})`);\n \n } catch (error) {\n this.log(`Error rendering placement: ${error}`, true);\n \n if (slot.onError) {\n slot.onError(error as Error);\n }\n }\n }\n \n private renderBanner(container: HTMLElement, content: PlacementContent): void {\n const { title, body, image_url, cta_text, cta_url, background_color, text_color } = content.content;\n \n const banner = document.createElement('div');\n banner.className = 'aegis-placement-banner';\n banner.style.cssText = `\n background: ${this.sanitizeColor(background_color || '#1a73e8')};\n color: ${this.sanitizeColor(text_color || '#ffffff')};\n padding: 24px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n gap: 16px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 80px; height: 80px; border-radius: 8px; object-fit: cover;';\n banner.appendChild(img);\n }\n }\n \n const textContainer = document.createElement('div');\n textContainer.style.cssText = 'flex: 1;';\n \n if (title) {\n const titleEl = document.createElement('div');\n titleEl.textContent = title;\n titleEl.style.cssText = 'font-size: 18px; font-weight: 600; margin-bottom: 8px;';\n textContainer.appendChild(titleEl);\n }\n \n if (body) {\n const bodyEl = document.createElement('div');\n bodyEl.textContent = body;\n bodyEl.style.cssText = 'font-size: 14px; opacity: 0.9;';\n textContainer.appendChild(bodyEl);\n }\n \n banner.appendChild(textContainer);\n \n if (cta_text && cta_url) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = cta_text;\n ctaButton.style.cssText = `\n background: white;\n color: ${this.sanitizeColor(background_color || '#1a73e8')};\n border: none;\n padding: 12px 24px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n white-space: nowrap;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n const safeUrl = this.sanitizeUrl(cta_url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n \n banner.appendChild(ctaButton);\n }\n \n container.appendChild(banner);\n }\n \n private renderCard(container: HTMLElement, content: PlacementContent): void {\n const { title, body, image_url, cta_text, cta_url } = content.content;\n \n const card = document.createElement('div');\n card.className = 'aegis-placement-card';\n card.style.cssText = `\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = title || '';\n img.style.cssText = 'width: 100%; height: 200px; object-fit: cover;';\n card.appendChild(img);\n }\n }\n \n const cardBody = document.createElement('div');\n cardBody.style.cssText = 'padding: 20px;';\n \n if (title) {\n const titleEl = document.createElement('h3');\n titleEl.textContent = title;\n titleEl.style.cssText = 'margin: 0 0 12px 0; font-size: 20px; font-weight: 600; color: #1a1a1a;';\n cardBody.appendChild(titleEl);\n }\n \n if (body) {\n const bodyEl = document.createElement('p');\n bodyEl.textContent = body;\n bodyEl.style.cssText = 'margin: 0 0 16px 0; font-size: 14px; color: #666; line-height: 1.5;';\n cardBody.appendChild(bodyEl);\n }\n \n if (cta_text && cta_url) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = cta_text;\n ctaButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 10px 20px;\n border-radius: 6px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n const safeUrl = this.sanitizeUrl(cta_url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n \n cardBody.appendChild(ctaButton);\n }\n \n card.appendChild(cardBody);\n container.appendChild(card);\n }\n \n private renderCarousel(container: HTMLElement, content: PlacementContent): void {\n const { items } = content.content;\n \n if (!Array.isArray(items) || items.length === 0) {\n this.log('Carousel items empty or invalid', true);\n return;\n }\n \n const carousel = document.createElement('div');\n carousel.className = 'aegis-placement-carousel';\n carousel.style.cssText = `\n display: flex;\n gap: 16px;\n overflow-x: auto;\n padding: 8px 0;\n scroll-behavior: smooth;\n -webkit-overflow-scrolling: touch;\n `;\n \n for (const item of items) {\n const carouselItem = document.createElement('div');\n carouselItem.style.cssText = `\n flex: 0 0 250px;\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n overflow: hidden;\n cursor: pointer;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n if (item.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(item.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = item.title || '';\n img.style.cssText = 'width: 100%; height: 150px; object-fit: cover;';\n carouselItem.appendChild(img);\n }\n }\n \n const itemContent = document.createElement('div');\n itemContent.style.cssText = 'padding: 12px;';\n \n if (item.title) {\n const title = document.createElement('div');\n title.textContent = item.title;\n title.style.cssText = 'font-size: 14px; font-weight: 600; margin-bottom: 4px; color: #1a1a1a;';\n itemContent.appendChild(title);\n }\n \n if (item.price) {\n const price = document.createElement('div');\n price.textContent = item.price;\n price.style.cssText = 'font-size: 16px; font-weight: 700; color: #1a73e8;';\n itemContent.appendChild(price);\n }\n \n carouselItem.appendChild(itemContent);\n \n if (item.url) {\n carouselItem.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click', { item_index: items.indexOf(item) });\n const safeUrl = this.sanitizeUrl(item.url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n }\n \n carousel.appendChild(carouselItem);\n }\n \n container.appendChild(carousel);\n }\n \n private renderVideo(container: HTMLElement, content: PlacementContent): void {\n const { video_url, poster_url, autoplay, muted } = content.content;\n \n if (!video_url) {\n this.log('Video URL missing', true);\n return;\n }\n \n const safeVideoUrl = this.sanitizeUrl(video_url);\n if (!safeVideoUrl) {\n this.log('Invalid video URL', true);\n return;\n }\n \n const video = document.createElement('video');\n video.src = safeVideoUrl;\n video.controls = true;\n video.autoplay = autoplay || false;\n video.muted = muted || false;\n video.style.cssText = 'width: 100%; border-radius: 8px;';\n \n if (poster_url) {\n const safePosterUrl = this.sanitizeUrl(poster_url);\n if (safePosterUrl) {\n video.poster = safePosterUrl;\n }\n }\n \n video.addEventListener('play', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click', { action: 'video_play' });\n });\n \n container.appendChild(video);\n }\n \n private renderHTML(container: HTMLElement, content: PlacementContent): void {\n const { html } = content.content;\n \n if (!html) {\n this.log('HTML content missing', true);\n return;\n }\n \n const wrapper = document.createElement('div');\n wrapper.className = 'aegis-placement-html';\n wrapper.innerHTML = this.sanitizeHTML(html);\n \n const links = wrapper.querySelectorAll('a');\n links.forEach((link) => {\n link.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n });\n });\n \n container.appendChild(wrapper);\n }\n \n private renderDynamicInjection(content: PlacementContent): void {\n const { html } = content.content;\n const cssSelector = content.css_selector;\n const injectionMode = content.injection_mode || 'replace';\n \n if (!cssSelector) {\n this.log('CSS selector missing for dynamic injection', true);\n return;\n }\n \n if (!html) {\n this.log('HTML content missing for dynamic injection', true);\n return;\n }\n \n let targetElement: HTMLElement | null = null;\n \n try {\n targetElement = document.querySelector(cssSelector);\n } catch (error) {\n this.log(`Invalid CSS selector: ${cssSelector}`, true);\n return;\n }\n \n if (!targetElement) {\n this.log(`Target element not found for selector: ${cssSelector}`, true);\n return;\n }\n \n const wrapper = document.createElement('div');\n wrapper.className = 'aegis-dynamic-injection';\n wrapper.setAttribute('data-placement-id', content.placement_id);\n wrapper.setAttribute('data-variant-id', content.variant_id);\n wrapper.innerHTML = this.sanitizeHTML(html);\n \n const links = wrapper.querySelectorAll('a');\n links.forEach((link) => {\n link.addEventListener('click', () => {\n this.trackEvent(content.placement_id, content.variant_id, 'click');\n });\n });\n \n switch (injectionMode) {\n case 'replace':\n targetElement.innerHTML = '';\n targetElement.appendChild(wrapper);\n this.log(`Replaced content in ${cssSelector}`, false);\n break;\n \n case 'append':\n targetElement.appendChild(wrapper);\n this.log(`Appended content to ${cssSelector}`, false);\n break;\n \n case 'prepend':\n targetElement.insertBefore(wrapper, targetElement.firstChild);\n this.log(`Prepended content to ${cssSelector}`, false);\n break;\n \n default:\n this.log(`Unknown injection mode: ${injectionMode}`, true);\n return;\n }\n \n this.log(`Dynamically injected content for ${content.placement_id} into ${cssSelector} (${injectionMode})`);\n }\n \n private renderFallback(slot: PlacementSlot): void {\n if (!slot.fallbackContent) return;\n \n const container = document.getElementById(slot.containerId);\n if (!container) return;\n \n container.innerHTML = slot.fallbackContent;\n this.log(`Rendered fallback content for: ${slot.placementId}`);\n }\n \n private async trackEvent(\n placementId: string,\n variantId: string,\n eventType: 'impression' | 'click' | 'conversion',\n metadata: Record<string, any> = {}\n ): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/placements/track`;\n \n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Device-Type': this.getDeviceType(),\n 'X-Platform': 'web'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n // Plumb the same workspace cascade the main analytics SDK uses\n // (config → ?ws= → URL path slug → setWorkspace runtime → session\n // storage). Without this, placement events arrive at event-ingress\n // unscoped and silently attribute to the org's primary workspace.\n const workspaceId = this.getWorkspaceId?.();\n\n const body = {\n placement_id: placementId,\n variant_id: variantId,\n event_type: eventType,\n workspace_id: workspaceId,\n metadata: {\n device_type: this.getDeviceType(),\n platform: 'web',\n ...metadata\n }\n };\n \n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body)\n }).catch(err => this.log(`Track event failed: ${err}`, true));\n \n this.log(`Tracked ${eventType}: ${placementId}`);\n \n } catch (error) {\n this.log(`Error tracking event: ${error}`, true);\n }\n }\n \n private connectSSE(): void {\n if (this.eventSource) {\n this.disconnectSSE();\n }\n \n if (!this.organizationId) {\n this.log('Cannot connect SSE without organization ID', true);\n return;\n }\n \n const url = new URL('/v1/stream/realtime', this.apiHost);\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Organization-ID': this.organizationId,\n };\n \n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n \n const queryParams = new URLSearchParams();\n Object.entries(headers).forEach(([key, value]) => {\n queryParams.append(key, value);\n });\n \n this.eventSource = new EventSource(`${url}?${queryParams.toString()}`);\n \n this.eventSource.addEventListener('open', () => {\n this.log('SSE connection established');\n this.reconnectAttempts = 0;\n });\n \n this.eventSource.addEventListener('placement_content_updated', (event: MessageEvent) => {\n try {\n const data = JSON.parse(event.data);\n this.log(`Received placement content update: ${data.placement_id}`);\n this.refreshPlacements();\n } catch (error) {\n this.log(`Error parsing SSE event: ${error}`, true);\n }\n });\n \n this.eventSource.addEventListener('heartbeat', () => {\n this.log('SSE heartbeat received');\n });\n\n this.eventSource.addEventListener('error', () => {\n this.log('SSE connection error', true);\n \n if (this.eventSource?.readyState === EventSource.CLOSED) {\n this.attemptReconnect();\n }\n });\n }\n \n private disconnectSSE(): void {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = undefined;\n this.log('SSE connection closed');\n }\n }\n \n private attemptReconnect(): void {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n this.log('Max reconnect attempts reached, giving up', true);\n return;\n }\n \n this.reconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);\n \n this.log(`Reconnecting SSE in ${delay}ms (attempt ${this.reconnectAttempts})`);\n \n setTimeout(() => {\n if (this.isInitialized && this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n }, delay);\n }\n \n private getDeviceType(): string {\n const width = window.innerWidth;\n if (width < 768) return 'mobile_web';\n if (width < 1024) return 'tablet_web';\n return 'desktop_web';\n }\n \n private sanitizeUrl(url: string): string | null {\n try {\n const parsed = new URL(url, window.location.href);\n \n if (parsed.protocol === 'javascript:' || parsed.protocol === 'data:') {\n this.log(`Blocked unsafe URL protocol: ${parsed.protocol}`, true);\n return null;\n }\n \n return parsed.href;\n } catch {\n this.log(`Invalid URL: ${url}`, true);\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n const hexPattern = /^#[0-9A-Fa-f]{3,6}$/;\n const rgbPattern = /^rgba?\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*(,\\s*[\\d.]+\\s*)?\\)$/;\n const namedColors = ['white', 'black', 'red', 'blue', 'green', 'yellow', 'transparent'];\n \n if (hexPattern.test(color) || rgbPattern.test(color) || namedColors.includes(color.toLowerCase())) {\n return color;\n }\n \n this.log(`Invalid color: ${color}`, true);\n return '#000000';\n }\n \n private sanitizeHTML(html: string): string {\n // Use DOMPurify if available (recommended for production)\n const purify = (window as unknown as Record<string, unknown>).DOMPurify as\n | { sanitize: (dirty: string, cfg?: Record<string, unknown>) => string }\n | undefined;\n\n if (purify?.sanitize) {\n return purify.sanitize(html, {\n ALLOWED_TAGS: [\n 'a', 'b', 'br', 'div', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'i', 'img', 'li', 'ol', 'p', 'span', 'strong', 'u', 'ul', 'table',\n 'thead', 'tbody', 'tr', 'th', 'td', 'blockquote', 'hr', 'figure',\n 'figcaption', 'picture', 'source', 'video', 'section', 'article',\n ],\n ALLOWED_ATTR: [\n 'href', 'target', 'rel', 'src', 'alt', 'width', 'height', 'class',\n 'id', 'style', 'title', 'loading', 'srcset', 'sizes', 'type',\n 'media', 'controls', 'poster',\n ],\n ALLOW_DATA_ATTR: false,\n });\n }\n\n // Built-in fallback: strip all tags via DOM parsing, then re-allow safe subset\n this.log(\n 'DOMPurify not found — falling back to built-in sanitizer. ' +\n 'For full HTML placement support, add <script src=\"https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.4/purify.min.js\"></script>',\n false\n );\n const tempDiv = document.createElement('div');\n tempDiv.textContent = html;\n return tempDiv.innerHTML;\n }\n \n private log(message: string, isError = false): void {\n if (this.debugMode || isError) {\n console[isError ? 'error' : 'log'](`[AegisPlacements] ${message}`);\n }\n }\n \n destroy(): void {\n this.disconnectSSE();\n this.slots.clear();\n this.placements.clear();\n this.renderedSlots.clear();\n this.isInitialized = false;\n this.log('AegisPlacements destroyed');\n }\n}\n","/**\n * TriggerEngine - Client-Side Trigger Evaluation\n * \n * Evaluates behavioral triggers that require real-time client state:\n * - Scroll depth (e.g., user scrolled >= 50%)\n * - Time on page (e.g., >= 30 seconds on current page)\n * - Exit intent (mouse leaving viewport toward browser controls)\n * - Inactivity (no user interaction for X seconds)\n * - Scroll velocity (mobile exit intent - fast upward scroll)\n * - Visibility change (tab/app switching)\n * - Back button (history navigation)\n * \n * Architecture:\n * - Server evaluates historical triggers (event counts, segments)\n * - Client evaluates behavioral triggers (scroll, time, exit intent)\n * - Zero latency - no server round trip needed\n * \n * Usage:\n * const trigger = new TriggerEngine();\n * trigger.on('scroll_depth_50', (data) => {\n * console.log('User scrolled to 50%', data);\n * });\n * trigger.start();\n */\n\nexport interface TriggerRule {\n type: 'scroll_depth' | 'time_on_page' | 'exit_intent' | 'inactivity' | 'scroll_velocity' | 'visibility_change' | 'back_button';\n config: ScrollDepthConfig | TimeOnPageConfig | ExitIntentConfig | InactivityConfig | ScrollVelocityConfig | VisibilityChangeConfig | BackButtonConfig;\n}\n\nexport interface ScrollDepthConfig {\n depth_percent: number;\n}\n\nexport interface TimeOnPageConfig {\n seconds: number;\n}\n\nexport interface ExitIntentConfig {\n enabled: boolean;\n}\n\nexport interface InactivityConfig {\n idle_seconds: number;\n}\n\nexport interface ScrollVelocityConfig {\n threshold: number;\n minScrollPosition: number;\n cooldown: number;\n}\n\nexport interface VisibilityChangeConfig {\n enabled: boolean;\n}\n\nexport interface BackButtonConfig {\n enabled: boolean;\n}\n\n/**\n * Rage-click detection (Micro-Intent Engine P2 Task 1).\n *\n * Per-intent ring buffer: when ≥ `threshold` clicks land on the same\n * intent inside `windowMs`, the engine emits `rage_click` with the\n * intent name + current count + window. Frustration signal used by the\n * Stuck-at-Checkout pattern (e.g., rage-clicking the coupon input four\n * times in 800ms).\n *\n * Defaults match the plan:\n * threshold = 3 clicks\n * windowMs = 1000 ms\n *\n * TriggerEngine does NOT attach its own pointerdown listener — the\n * SelectorBinder (P1 Task 5) owns the global, delegated listener and\n * dispatches per-intent click events. The IntentSnapshotCollector\n * (P2 Task 5) wires `SelectorBinder.onIntent` to\n * `TriggerEngine.noteClick(intent)` so TriggerEngine sees a clean\n * intent-stamped stream instead of raw DOM events.\n */\nexport interface RageClickConfig {\n threshold: number;\n windowMs: number;\n}\n\n/** Payload emitted on the `rage_click` event. */\nexport interface RageClickData {\n intent: string;\n count: number;\n window_ms: number;\n}\n\n/**\n * Hover-dwell tracking (Micro-Intent Engine P2 Task 2).\n *\n * Tracks per-intent hover duration in milliseconds. `getHoverMs(intent)`\n * returns:\n * - if currently hovering the intent: ms since hover_start (live)\n * - else: ms duration of the most recent hover on that intent (sticky)\n * - if never hovered: 0\n *\n * The sticky behaviour is deliberate. The canonical use case\n * (MICRO_INTENT_ENGINE.md Story 1):\n * \"Priya hovers price for 1.8s, considers, moves cursor away.\n * Exit_intent fires. Rule checks price_hover_ms >= 1500 → true.\"\n * The rule evaluator queries `price_hover_ms` AFTER the hover ends. If\n * we reset to 0 on hover_end, the rule never matches the very pattern\n * the engine exists to detect.\n *\n * Threshold-based emission: when a hover crosses one of the registered\n * dwell targets (e.g. 1500ms), a `<intent>_hover_dwell_<ms>` event\n * fires. Useful for journeys that want event-style hooks; the\n * snapshot-style `getHoverMs` is the primary surface for the\n * compound-rule evaluator.\n */\nexport interface HoverDwellConfig {\n /** Dwell thresholds (ms) per intent. The engine fires\n * `<intent>_hover_dwell_<ms>` when an active hover crosses each\n * threshold. Defaults: price→[1500], cta→[1500]. */\n thresholdsByIntent?: Partial<Record<string, ReadonlyArray<number>>>;\n}\n\n/**\n * Mouse velocity toward the viewport top (Micro-Intent Engine P2 Task 3).\n *\n * Detects the early phase of exit-intent: the mouse moving rapidly\n * upward before it actually crosses out of the viewport. The signal is\n * a continuous px/ms value (positive = moving up), updated as samples\n * arrive. When velocity crosses `threshold`, a `mouse_velocity_to_top`\n * event fires (once per session-window cooldown to avoid spamming on a\n * single gesture).\n *\n * Sampling: callers feed positions via `noteMousePosition(x, y, ts)`.\n * The engine keeps a sliding `windowMs` ring buffer of samples and\n * computes velocity as the average dy / dt over samples in the window.\n * Per the plan: sampled at 100ms, 400ms window. That bound is\n * configurable.\n *\n * Why \"to top\" specifically: exit-intent fires only when y crosses 0;\n * we want the warning BEFORE that. A typical exit-intent gesture has\n * upward velocity well above any normal browsing motion.\n */\nexport interface MouseVelocityConfig {\n /** Threshold in px/ms (positive = moving up). Default 1.5 px/ms,\n * ≈ moving 600px in 400ms, which only happens during a deliberate\n * upward sweep. */\n threshold: number;\n /** Rolling-window length over which to compute velocity. */\n windowMs: number;\n /** Cooldown after a fire before the signal can fire again. */\n cooldownMs: number;\n}\n\nexport interface TriggerEvent {\n type: string;\n data: Record<string, any>;\n timestamp: number;\n}\n\ntype TriggerCallback = (event: TriggerEvent) => void;\n\nexport class TriggerEngine {\n private listeners: Map<string, Set<TriggerCallback>> = new Map();\n private isStarted = false;\n \n private scrollDepthTargets = new Set<number>();\n private scrollDepthReached = new Set<number>();\n \n private timeOnPageTargets = new Map<number, number>();\n private pageLoadTime?: number;\n \n private exitIntentEnabled = false;\n private exitIntentFired = false;\n \n private inactivityTargets = new Map<number, number>();\n private lastActivityTime = Date.now();\n private inactivityCheckInterval?: number;\n \n private scrollVelocityEnabled = false;\n private scrollVelocityFired = false;\n private scrollVelocityConfig: ScrollVelocityConfig = {\n threshold: 0.5,\n minScrollPosition: 100,\n cooldown: 5000\n };\n private lastScrollY = 0;\n private lastScrollTime = Date.now();\n private scrollVelocityCooldownTimer?: number;\n \n private visibilityChangeEnabled = false;\n\n private backButtonEnabled = false;\n private backButtonFired = false;\n\n // Rage-click state (P2 Task 1). Buffer indexed by intent name (price /\n // cta / coupon / checkout). Per-intent so rage-clicking the coupon\n // input doesn't get conflated with rapid CTA presses.\n private rageClickEnabled = false;\n private rageClickConfig: RageClickConfig = { threshold: 3, windowMs: 1000 };\n private rageClickBuffer = new Map<string, number[]>();\n /** Tracks whether a rage_click event has already fired for an intent\n * in the current burst. Reset when the buffer empties below threshold.\n * Prevents the same burst from firing the event N-2 times as each\n * click after threshold pushes the count higher. */\n private rageClickFiredInBurst = new Set<string>();\n\n // Hover-dwell state (P2 Task 2). Tracks live + sticky-last dwell per\n // intent. `hoverStartAt` undefined means no active hover.\n private hoverEnabled = false;\n private hoverStartAt = new Map<string, number>();\n private hoverLastMs = new Map<string, number>();\n private hoverThresholds = new Map<string, ReadonlyArray<number>>([\n ['price', [1500]],\n ['cta', [1500]],\n ]);\n /** Track which (intent, threshold) pairs have already fired in the\n * current hover so a single long hover doesn't double-fire as time\n * marches on. Reset on hover_start. */\n private hoverThresholdsFired = new Map<string, Set<number>>();\n /** Pending threshold timers, keyed by intent. Cleared on hover_end. */\n private hoverThresholdTimers = new Map<string, number[]>();\n\n // Mouse-velocity-to-top state (P2 Task 3).\n private mouseVelEnabled = false;\n private mouseVelConfig: MouseVelocityConfig = {\n threshold: 1.5,\n windowMs: 400,\n cooldownMs: 5000,\n };\n /** Ring buffer of (x, y, ts) samples within the rolling window. */\n private mouseSamples: Array<{ x: number; y: number; ts: number }> = [];\n /** Last computed velocity-to-top in px/ms (positive = moving up). */\n private mouseVelLast = 0;\n /** Epoch ms when the velocity event last fired — gates cooldown. */\n private mouseVelLastFiredAt = 0;\n\n constructor() {}\n \n on(eventType: string, callback: TriggerCallback): void {\n if (!this.listeners.has(eventType)) {\n this.listeners.set(eventType, new Set());\n }\n this.listeners.get(eventType)!.add(callback);\n }\n \n off(eventType: string, callback: TriggerCallback): void {\n const callbacks = this.listeners.get(eventType);\n if (callbacks) {\n callbacks.delete(callback);\n }\n }\n \n registerScrollDepth(depthPercent: number): void {\n this.scrollDepthTargets.add(depthPercent);\n }\n \n registerTimeOnPage(seconds: number): void {\n if (!this.timeOnPageTargets.has(seconds)) {\n const timerId = window.setTimeout(() => {\n this.emit(`time_on_page_${seconds}`, {\n seconds,\n page_url: window.location.href\n });\n this.timeOnPageTargets.delete(seconds);\n }, seconds * 1000);\n \n this.timeOnPageTargets.set(seconds, timerId);\n }\n }\n \n registerExitIntent(): void {\n this.exitIntentEnabled = true;\n }\n \n registerInactivity(idleSeconds: number): void {\n if (!this.inactivityTargets.has(idleSeconds)) {\n const timerId = window.setTimeout(() => {\n const idleTime = (Date.now() - this.lastActivityTime) / 1000;\n \n if (idleTime >= idleSeconds) {\n this.emit(`inactivity_${idleSeconds}`, {\n idle_seconds: idleSeconds,\n actual_idle_time: idleTime\n });\n }\n \n this.inactivityTargets.delete(idleSeconds);\n }, idleSeconds * 1000);\n \n this.inactivityTargets.set(idleSeconds, timerId);\n }\n }\n \n registerScrollVelocity(config?: Partial<ScrollVelocityConfig>): void {\n this.scrollVelocityEnabled = true;\n \n if (config) {\n this.scrollVelocityConfig = {\n threshold: config.threshold ?? this.scrollVelocityConfig.threshold,\n minScrollPosition: config.minScrollPosition ?? this.scrollVelocityConfig.minScrollPosition,\n cooldown: config.cooldown ?? this.scrollVelocityConfig.cooldown\n };\n }\n }\n \n registerVisibilityChange(): void {\n this.visibilityChangeEnabled = true;\n }\n \n registerBackButton(): void {\n this.backButtonEnabled = true;\n }\n\n /**\n * Enable rage-click detection (P2 Task 1).\n *\n * After calling this, feed click events via `noteClick(intent)`.\n * SelectorBinder (P1 Task 5) is the upstream source; the wiring lives\n * in IntentSnapshotCollector (P2 Task 5). Calling `noteClick` without\n * a prior `registerRageClick()` is a no-op so legacy callers don't\n * accidentally enable the feature.\n */\n registerRageClick(config?: Partial<RageClickConfig>): void {\n this.rageClickEnabled = true;\n if (config) {\n this.rageClickConfig = {\n threshold: config.threshold ?? this.rageClickConfig.threshold,\n windowMs: config.windowMs ?? this.rageClickConfig.windowMs,\n };\n }\n }\n\n /**\n * Feed a click event for rage-click detection. Returns the current\n * count within-window for the intent — useful for the snapshot\n * collector (P2 Task 5) which updates IntentRuleEvaluator with\n * `rage_click_count` continuously, not just at the burst threshold.\n *\n * Idempotent w.r.t. `registerRageClick` — when not enabled, this\n * returns 0 without buffering.\n */\n noteClick(intent: string, timestamp: number = Date.now()): number {\n if (!this.rageClickEnabled) return 0;\n const buf = this.rageClickBuffer.get(intent) ?? [];\n const cutoff = timestamp - this.rageClickConfig.windowMs;\n // Drop expired timestamps (clicks older than the window).\n // The buffer is append-only and timestamps are non-decreasing in\n // practice (Date.now is monotonic per device, modulo system-clock\n // adjustments), so an in-place trim from the head is correct.\n let trimStart = 0;\n while (trimStart < buf.length && buf[trimStart] < cutoff) trimStart++;\n const recent = trimStart === 0 ? buf : buf.slice(trimStart);\n recent.push(timestamp);\n this.rageClickBuffer.set(intent, recent);\n\n // Burst reset: when the recent count drops below threshold (because\n // older clicks aged out), the burst is over — re-arm the per-intent\n // fire-once latch so a fresh burst can fire again.\n if (recent.length < this.rageClickConfig.threshold) {\n this.rageClickFiredInBurst.delete(intent);\n }\n\n if (\n recent.length >= this.rageClickConfig.threshold &&\n !this.rageClickFiredInBurst.has(intent)\n ) {\n this.rageClickFiredInBurst.add(intent);\n this.emit('rage_click', {\n intent,\n count: recent.length,\n window_ms: this.rageClickConfig.windowMs,\n });\n }\n\n return recent.length;\n }\n\n /** Snapshot the current rage_click count for an intent. The\n * IntentSnapshotCollector (P2 Task 5) calls this when building the\n * `rage_click_count` signal value for the IntentRuleEvaluator. */\n getRageClickCount(intent: string): number {\n if (!this.rageClickEnabled) return 0;\n const buf = this.rageClickBuffer.get(intent);\n if (!buf) return 0;\n const cutoff = Date.now() - this.rageClickConfig.windowMs;\n // Lazy prune on read so the count reflects only currently-valid\n // clicks. Cheap because buffers are tiny (cap at threshold + 1 in\n // practice — older entries get dropped on every note).\n let live = 0;\n for (const ts of buf) {\n if (ts >= cutoff) live++;\n }\n return live;\n }\n\n /**\n * Enable hover-dwell tracking (P2 Task 2). After registration, feed\n * hover events via `noteHoverStart(intent, ts)` / `noteHoverEnd`.\n * SelectorBinder (P1 Task 5) is the upstream source; wiring lands in\n * P2 Task 5.\n */\n registerHoverDwell(config?: HoverDwellConfig): void {\n this.hoverEnabled = true;\n if (config?.thresholdsByIntent) {\n for (const [intent, thresholds] of Object.entries(config.thresholdsByIntent)) {\n if (thresholds) this.hoverThresholds.set(intent, thresholds);\n }\n }\n }\n\n /** Record the start of a hover on the named intent. Schedules\n * per-threshold timers that emit `<intent>_hover_dwell_<ms>` when\n * the active hover passes each registered threshold. */\n noteHoverStart(intent: string, timestamp: number = Date.now()): void {\n if (!this.hoverEnabled) return;\n // If a prior hover is still pending (no hover_end fired — possible\n // when the DOM node was unmounted mid-hover), close it out first to\n // keep `hoverLastMs` consistent.\n if (this.hoverStartAt.has(intent)) {\n this.noteHoverEnd(intent, timestamp);\n }\n this.hoverStartAt.set(intent, timestamp);\n this.hoverThresholdsFired.set(intent, new Set());\n\n // Schedule threshold timers. Uses the global setTimeout (works in\n // both browser and node, and vitest's fake-timers stub the global).\n // registerHoverDwell with no thresholds for an intent => no events,\n // only the snapshot value.\n const thresholds = this.hoverThresholds.get(intent);\n if (thresholds) {\n const timers: number[] = [];\n for (const ms of thresholds) {\n const timerId = setTimeout(() => {\n // Only fire if still hovering this intent — the event must\n // not fire after hover_end.\n if (!this.hoverStartAt.has(intent)) return;\n const firedSet = this.hoverThresholdsFired.get(intent);\n if (firedSet?.has(ms)) return;\n firedSet?.add(ms);\n this.emit(`${intent}_hover_dwell_${ms}`, {\n intent,\n threshold_ms: ms,\n actual_ms: Date.now() - timestamp,\n });\n }, ms) as unknown as number;\n timers.push(timerId);\n }\n this.hoverThresholdTimers.set(intent, timers);\n }\n }\n\n /** Record the end of a hover on the named intent. Updates the sticky\n * `lastHoverMs` so `getHoverMs` keeps returning the last-known\n * duration until the next hover_start. */\n noteHoverEnd(intent: string, timestamp: number = Date.now()): void {\n if (!this.hoverEnabled) return;\n const startAt = this.hoverStartAt.get(intent);\n if (startAt === undefined) return;\n const dwell = Math.max(0, timestamp - startAt);\n this.hoverLastMs.set(intent, dwell);\n this.hoverStartAt.delete(intent);\n // Clear pending threshold timers for this intent.\n const pending = this.hoverThresholdTimers.get(intent);\n if (pending) {\n for (const id of pending) clearTimeout(id);\n this.hoverThresholdTimers.delete(intent);\n }\n this.hoverThresholdsFired.delete(intent);\n }\n\n /**\n * Enable mouse-velocity-to-top tracking (P2 Task 3). After\n * registration, feed positions via `noteMousePosition(x, y, ts?)`.\n * IntentSnapshotCollector (P2 Task 5) wires window 'mousemove' to\n * this method, with throttling to ~100ms per the plan.\n */\n registerMouseVelocityToTop(config?: Partial<MouseVelocityConfig>): void {\n this.mouseVelEnabled = true;\n if (config) {\n this.mouseVelConfig = {\n threshold: config.threshold ?? this.mouseVelConfig.threshold,\n windowMs: config.windowMs ?? this.mouseVelConfig.windowMs,\n cooldownMs: config.cooldownMs ?? this.mouseVelConfig.cooldownMs,\n };\n }\n }\n\n /** Feed a mouse-position sample. Recomputes the rolling-window\n * velocity-to-top and fires `mouse_velocity_to_top` when the value\n * crosses the configured threshold (subject to cooldown). */\n noteMousePosition(x: number, y: number, timestamp: number = Date.now()): number {\n if (!this.mouseVelEnabled) return 0;\n const cutoff = timestamp - this.mouseVelConfig.windowMs;\n // Trim expired samples from the head; keep the buffer small.\n let trimStart = 0;\n while (trimStart < this.mouseSamples.length && this.mouseSamples[trimStart].ts < cutoff) {\n trimStart++;\n }\n if (trimStart > 0) this.mouseSamples = this.mouseSamples.slice(trimStart);\n this.mouseSamples.push({ x, y, ts: timestamp });\n\n // Velocity-to-top = -(dy / dt) over the oldest-to-newest pair in\n // the window. Positive value = moving up. With 2+ samples this is\n // the instantaneous slope across the window; with 1 sample we\n // return 0 (cannot compute velocity from a single point).\n if (this.mouseSamples.length < 2) {\n this.mouseVelLast = 0;\n return 0;\n }\n const oldest = this.mouseSamples[0];\n const newest = this.mouseSamples[this.mouseSamples.length - 1];\n const dt = newest.ts - oldest.ts;\n if (dt <= 0) {\n this.mouseVelLast = 0;\n return 0;\n }\n const velocity = -(newest.y - oldest.y) / dt; // px/ms; up = +\n this.mouseVelLast = velocity;\n\n // Threshold + cooldown firing. Initial state allows the first fire\n // — only subsequent fires within cooldownMs of the prior are gated.\n const cooldownOk =\n this.mouseVelLastFiredAt === 0 ||\n timestamp - this.mouseVelLastFiredAt >= this.mouseVelConfig.cooldownMs;\n if (velocity >= this.mouseVelConfig.threshold && cooldownOk) {\n this.mouseVelLastFiredAt = timestamp;\n this.emit('mouse_velocity_to_top', {\n velocity,\n threshold: this.mouseVelConfig.threshold,\n window_ms: this.mouseVelConfig.windowMs,\n samples: this.mouseSamples.length,\n });\n }\n return velocity;\n }\n\n /** Snapshot the current velocity-to-top in px/ms (positive = up).\n * Returns 0 when not enabled or insufficient samples. */\n getMouseVelocityToTop(): number {\n return this.mouseVelEnabled ? this.mouseVelLast : 0;\n }\n\n /**\n * Snapshot the hover dwell for an intent.\n * - Currently hovering: returns `Date.now() - hover_start_at`.\n * - Hovered before, not currently: returns the most recent hover's\n * duration (sticky — the rule evaluator queries this AFTER\n * mouseleave to see \"did Priya hover the price ≥ 1.5s?\").\n * - Never hovered: returns 0.\n */\n getHoverMs(intent: string): number {\n if (!this.hoverEnabled) return 0;\n const startAt = this.hoverStartAt.get(intent);\n if (startAt !== undefined) {\n return Math.max(0, Date.now() - startAt);\n }\n return this.hoverLastMs.get(intent) ?? 0;\n }\n\n start(): void {\n if (this.isStarted) {\n return;\n }\n \n this.pageLoadTime = Date.now();\n this.lastActivityTime = Date.now();\n this.lastScrollY = window.scrollY || 0;\n this.lastScrollTime = Date.now();\n \n if (this.scrollDepthTargets.size > 0) {\n this.attachScrollListener();\n }\n \n if (this.exitIntentEnabled) {\n this.attachExitIntentListener();\n }\n \n if (this.scrollVelocityEnabled) {\n this.attachScrollVelocityListener();\n }\n \n if (this.visibilityChangeEnabled) {\n this.attachVisibilityChangeListener();\n }\n \n if (this.backButtonEnabled) {\n this.attachBackButtonListener();\n }\n \n this.attachActivityListeners();\n \n this.startInactivityCheck();\n \n this.isStarted = true;\n }\n \n stop(): void {\n if (!this.isStarted) {\n return;\n }\n \n this.removeScrollListener();\n this.removeExitIntentListener();\n this.removeScrollVelocityListener();\n this.removeVisibilityChangeListener();\n this.removeBackButtonListener();\n this.removeActivityListeners();\n \n this.timeOnPageTargets.forEach(timerId => clearTimeout(timerId));\n this.timeOnPageTargets.clear();\n \n this.inactivityTargets.forEach(timerId => clearTimeout(timerId));\n this.inactivityTargets.clear();\n \n if (this.inactivityCheckInterval) {\n clearInterval(this.inactivityCheckInterval);\n this.inactivityCheckInterval = undefined;\n }\n \n if (this.scrollVelocityCooldownTimer) {\n clearTimeout(this.scrollVelocityCooldownTimer);\n this.scrollVelocityCooldownTimer = undefined;\n }\n \n this.isStarted = false;\n }\n \n reset(): void {\n this.scrollDepthReached.clear();\n this.exitIntentFired = false;\n this.scrollVelocityFired = false;\n this.backButtonFired = false;\n this.pageLoadTime = Date.now();\n this.lastActivityTime = Date.now();\n this.lastScrollY = window.scrollY || 0;\n this.lastScrollTime = Date.now();\n \n if (this.scrollVelocityCooldownTimer) {\n clearTimeout(this.scrollVelocityCooldownTimer);\n this.scrollVelocityCooldownTimer = undefined;\n }\n }\n \n private attachScrollListener(): void {\n window.addEventListener('scroll', this.handleScroll, { passive: true });\n this.handleScroll();\n }\n \n private removeScrollListener(): void {\n window.removeEventListener('scroll', this.handleScroll);\n }\n \n private handleScroll = (): void => {\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;\n const scrollPercent = scrollHeight > 0 ? (scrollTop / scrollHeight) * 100 : 0;\n \n for (const targetDepth of this.scrollDepthTargets) {\n if (scrollPercent >= targetDepth && !this.scrollDepthReached.has(targetDepth)) {\n this.scrollDepthReached.add(targetDepth);\n \n this.emit(`scroll_depth_${targetDepth}`, {\n depth_percent: targetDepth,\n actual_percent: scrollPercent,\n scroll_top: scrollTop,\n scroll_height: scrollHeight\n });\n }\n }\n };\n \n private attachExitIntentListener(): void {\n document.addEventListener('mouseleave', this.handleExitIntent);\n }\n \n private removeExitIntentListener(): void {\n document.removeEventListener('mouseleave', this.handleExitIntent);\n }\n \n private handleExitIntent = (event: MouseEvent): void => {\n if (this.exitIntentFired) {\n return;\n }\n \n if (event.clientY < 10) {\n this.exitIntentFired = true;\n \n this.emit('exit_intent', {\n client_y: event.clientY,\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n }\n };\n \n private attachScrollVelocityListener(): void {\n window.addEventListener('scroll', this.handleScrollVelocity, { passive: true });\n }\n \n private removeScrollVelocityListener(): void {\n window.removeEventListener('scroll', this.handleScrollVelocity);\n }\n \n private handleScrollVelocity = (): void => {\n if (this.scrollVelocityFired) {\n return;\n }\n \n const currentY = window.scrollY || document.documentElement.scrollTop;\n const currentTime = Date.now();\n const timeDiff = currentTime - this.lastScrollTime;\n \n if (timeDiff > 100) {\n const distance = this.lastScrollY - currentY;\n const velocity = Math.abs(distance / timeDiff);\n \n if (\n distance > 0 &&\n velocity > this.scrollVelocityConfig.threshold &&\n currentY > this.scrollVelocityConfig.minScrollPosition\n ) {\n this.scrollVelocityFired = true;\n \n this.emit('mobile_exit_intent', {\n scroll_velocity: velocity,\n scroll_distance: distance,\n current_position: currentY,\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n \n this.scrollVelocityCooldownTimer = window.setTimeout(() => {\n this.scrollVelocityFired = false;\n }, this.scrollVelocityConfig.cooldown);\n }\n \n this.lastScrollY = currentY;\n this.lastScrollTime = currentTime;\n }\n };\n \n private attachVisibilityChangeListener(): void {\n document.addEventListener('visibilitychange', this.handleVisibilityChange);\n }\n \n private removeVisibilityChangeListener(): void {\n document.removeEventListener('visibilitychange', this.handleVisibilityChange);\n }\n \n private handleVisibilityChange = (): void => {\n if (document.hidden) {\n this.emit('visibility_hidden', {\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n } else {\n this.emit('visibility_visible', {\n page_url: window.location.href\n });\n }\n };\n \n private attachBackButtonListener(): void {\n if (typeof window !== 'undefined' && window.history) {\n window.history.pushState(null, '', window.location.href);\n window.addEventListener('popstate', this.handleBackButton);\n }\n }\n \n private removeBackButtonListener(): void {\n window.removeEventListener('popstate', this.handleBackButton);\n }\n \n private handleBackButton = (): void => {\n if (this.backButtonFired) {\n return;\n }\n \n this.backButtonFired = true;\n \n window.history.pushState(null, '', window.location.href);\n \n this.emit('back_button', {\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n };\n \n private attachActivityListeners(): void {\n const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];\n events.forEach(event => {\n document.addEventListener(event, this.handleActivity, { passive: true });\n });\n }\n \n private removeActivityListeners(): void {\n const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];\n events.forEach(event => {\n document.removeEventListener(event, this.handleActivity);\n });\n }\n \n private handleActivity = (): void => {\n this.lastActivityTime = Date.now();\n };\n \n private startInactivityCheck(): void {\n this.inactivityCheckInterval = window.setInterval(() => {\n const idleTime = (Date.now() - this.lastActivityTime) / 1000;\n \n for (const [idleSeconds] of this.inactivityTargets) {\n if (idleTime >= idleSeconds) {\n this.emit(`inactivity_${idleSeconds}`, {\n idle_seconds: idleSeconds,\n actual_idle_time: idleTime\n });\n \n const timerId = this.inactivityTargets.get(idleSeconds);\n if (timerId) {\n clearTimeout(timerId);\n this.inactivityTargets.delete(idleSeconds);\n }\n }\n }\n }, 1000);\n }\n \n private emit(eventType: string, data: Record<string, any>): void {\n const event: TriggerEvent = {\n type: eventType,\n data,\n timestamp: Date.now()\n };\n \n const callbacks = this.listeners.get(eventType);\n if (callbacks) {\n callbacks.forEach(callback => {\n try {\n callback(event);\n } catch (error) {\n console.error(`Error in trigger callback for ${eventType}:`, error);\n }\n });\n }\n \n const wildcardCallbacks = this.listeners.get('*');\n if (wildcardCallbacks) {\n wildcardCallbacks.forEach(callback => {\n try {\n callback(event);\n } catch (error) {\n console.error(`Error in wildcard trigger callback:`, error);\n }\n });\n }\n }\n}\n","/**\n * Micro-Intent Engine — compound rule evaluator (P1 Task 4).\n *\n * Pure, side-effect-free evaluation of an IntentRule predicate tree against\n * a current snapshot of Layer-1 (identity) + Layer-2 (session) signal values.\n *\n * Why a separate class from TriggerEngine\n * ----------------------------------------\n * TriggerEngine.ts owns signal CAPTURE (scroll, time-on-page, exit-intent,\n * etc.) and emits named events like `scroll_depth_50`. IntentRuleEvaluator\n * owns rule EVALUATION — given a compound predicate and the current state\n * of all known signals, return whether the rule fires now. The two\n * concerns separate cleanly: capture is global per-page (one engine\n * instance), evaluation is per-rule (the manager re-runs every armed\n * rule when a `fire_on` signal fires).\n *\n * Type strategy\n * -------------\n * Types are declared LOCALLY in this file rather than imported from\n * `@aegis/shared-types`. The SDK is published standalone on npm and\n * cannot pull in workspace packages at runtime. A drift-check test\n * (`libs/web-sdk/tests/intent-evaluator-shared-types-drift.test.ts`)\n * parses both files and asserts the local types and the canonical\n * `libs/shared-types/src/intent.ts` declare the same set of signal /\n * comparator values.\n *\n * Plan reference: docs/architecture/MICRO_INTENT_ENGINE.md §\"Schemas\"\n */\n\n// ───────────────────────────────────────────────────────────────────────────\n// Types — local mirror of libs/shared-types/src/intent.ts\n// ───────────────────────────────────────────────────────────────────────────\n\nexport type IntentSignal =\n // Layer-2 session\n | 'scroll_depth'\n | 'time_on_page'\n | 'exit_intent'\n | 'back_button'\n | 'scroll_velocity'\n | 'inactivity'\n | 'visibility_change'\n | 'rage_click'\n | 'price_hover_ms'\n | 'cta_hover_ms'\n | 'cum_dwell_sku'\n | 'session_count_sku'\n | 'cart_value'\n | 'converted_in_session'\n // Layer-1 identity scores\n | 'rfm_segment'\n | 'rfm_score'\n | 'lifecycle_stage'\n | 'purchase_intent_score'\n | 'purchase_intent_tier'\n | 'churn_risk_score'\n | 'churn_risk_tier'\n | 'predicted_ltv'\n | 'predicted_ltv_tier'\n | 'uninstall_risk_tier'\n | 'engagement_level'\n | 'price_tier'\n | 'price_sensitivity_score'\n | 'top_category'\n | 'avg_cart_value'\n | 'scoring_tier';\n\nexport type Comparator = 'gte' | 'lte' | 'gt' | 'lt' | 'eq' | 'neq' | 'in' | 'nin';\n\nexport type IntentLeafValue =\n | number\n | string\n | boolean\n | ReadonlyArray<number | string | boolean>;\n\nexport interface IntentLeaf {\n signal: IntentSignal;\n op: Comparator;\n value: IntentLeafValue;\n}\n\nexport interface IntentNode {\n op: 'AND' | 'OR' | 'NOT';\n operands: ReadonlyArray<IntentExpr>;\n}\n\nexport type IntentExpr = IntentNode | IntentLeaf;\n\nexport interface IntentRule {\n fire_on: ReadonlyArray<IntentSignal>;\n when: IntentExpr;\n priority: number;\n suppress_competing: boolean;\n}\n\n/** A scalar a signal can hold in the snapshot. null = signal not (yet)\n * populated — happens for Layer-1 scores on anonymous sessions and for\n * Layer-2 signals before the user triggers them. */\nexport type SignalValue = number | string | boolean | null;\n\n/** Current state of every known signal. Missing keys are treated the\n * same as `null`. */\nexport type IntentSnapshot = Partial<Record<IntentSignal, SignalValue>>;\n\n// ───────────────────────────────────────────────────────────────────────────\n// Type guards\n// ───────────────────────────────────────────────────────────────────────────\n\nexport function isIntentLeaf(expr: IntentExpr): expr is IntentLeaf {\n return 'signal' in expr;\n}\n\nexport function isIntentNode(expr: IntentExpr): expr is IntentNode {\n return 'operands' in expr;\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Pure leaf evaluator\n// ───────────────────────────────────────────────────────────────────────────\n\n/**\n * Evaluate a single leaf comparison against a snapshot.\n *\n * Missing-signal semantics (per the plan's \"Graceful degradation rules\"):\n * - The CALLER (evaluateExpr) decides AND/OR semantics on missing\n * operands; this function answers strictly for THIS leaf.\n * - When the signal is missing from the snapshot, the leaf is\n * \"unknown\" → return null so the parent node can interpret it.\n *\n * Comparator semantics:\n * - gte/lte/gt/lt: numeric only; comparing strings/bools returns false.\n * - eq/neq: any type; strict equality.\n * - in/nin: leaf value must be a list; membership test on the snapshot\n * value. `nin` returns true for missing snapshot values (the\n * contact's RFM segment is \"not in\" the forbidden list if we don't\n * know it yet — conservative).\n */\nexport function evaluateLeaf(leaf: IntentLeaf, snapshot: IntentSnapshot): boolean | null {\n const actual = snapshot[leaf.signal];\n if (actual === undefined || actual === null) {\n // Missing signal — let the parent decide.\n return null;\n }\n\n const want = leaf.value;\n\n switch (leaf.op) {\n case 'gte':\n case 'lte':\n case 'gt':\n case 'lt': {\n if (typeof actual !== 'number' || typeof want !== 'number') return false;\n if (leaf.op === 'gte') return actual >= want;\n if (leaf.op === 'lte') return actual <= want;\n if (leaf.op === 'gt') return actual > want;\n return actual < want; // lt\n }\n case 'eq':\n return actual === want;\n case 'neq':\n return actual !== want;\n case 'in':\n case 'nin': {\n if (!Array.isArray(want)) return false;\n const isMember = want.some((v) => v === actual);\n return leaf.op === 'in' ? isMember : !isMember;\n }\n default: {\n // Exhaustiveness check — TS will flag a new Comparator that doesn't\n // have a case here, but the runtime fallback returns false.\n const _exhaustive: never = leaf.op;\n void _exhaustive;\n return false;\n }\n }\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Pure tree evaluator\n// ───────────────────────────────────────────────────────────────────────────\n\n/**\n * Evaluate the full predicate tree.\n *\n * AND/OR/NOT semantics with missing-value handling (per plan §\"Graceful\n * degradation rules\"):\n *\n * AND(a, b, c) where any operand is null → false (conservative; the\n * rule doesn't fire when we can't prove all conditions).\n * OR(a, b, c) where some operands are null → if any non-null operand\n * is true, returns true. If all operands are null OR all are\n * false, returns false.\n * NOT(a) where a is null → null (parent decides). When this propagates\n * to the top-level evaluateExpr, the rule does NOT fire.\n *\n * The \"AND treats missing as unmet\" + \"OR treats missing as inert\" rule\n * from the plan maps exactly onto this implementation: AND short-circuits\n * to false on any null operand; OR ignores nulls and looks at the rest.\n *\n * Top-level: a null result from the root expression means the rule\n * cannot be evaluated yet — do NOT fire.\n */\nexport function evaluateExpr(expr: IntentExpr, snapshot: IntentSnapshot): boolean | null {\n if (isIntentLeaf(expr)) {\n return evaluateLeaf(expr, snapshot);\n }\n\n switch (expr.op) {\n case 'AND': {\n // AND requires ALL operands true. Any null = unprovable = false.\n for (const operand of expr.operands) {\n const v = evaluateExpr(operand, snapshot);\n if (v === null) return false;\n if (!v) return false;\n }\n return true;\n }\n case 'OR': {\n // OR is satisfied by any true operand. Nulls are skipped (inert).\n let allNull = true;\n for (const operand of expr.operands) {\n const v = evaluateExpr(operand, snapshot);\n if (v === true) return true;\n if (v !== null) allNull = false;\n }\n // If every operand was null, propagate null upward — caller decides.\n // Otherwise all operands evaluated false.\n return allNull ? null : false;\n }\n case 'NOT': {\n // Validator at write time guarantees operands.length === 1; the\n // evaluator trusts that and reads operands[0].\n const v = evaluateExpr(expr.operands[0], snapshot);\n if (v === null) return null;\n return !v;\n }\n default: {\n // Exhaustiveness check — if a new op is added to IntentExpr and\n // not handled above, TypeScript narrows `expr` to `never` here\n // and assigning it to a non-`never` would fail at compile time.\n // The earlier draft did `expr.op` which itself dereferences\n // `never` and explodes; assign `expr` directly instead.\n const _exhaustive: never = expr;\n void _exhaustive;\n return false;\n }\n }\n}\n\n/** Top-level \"does the rule fire right now?\" check. Treats a null\n * evaluation result as \"do not fire\" (we can't prove the rule's\n * conditions are met). */\nexport function evaluateRule(rule: IntentRule, snapshot: IntentSnapshot): boolean {\n const result = evaluateExpr(rule.when, snapshot);\n return result === true;\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Stateful evaluator class — what AegisInAppManager talks to\n// ───────────────────────────────────────────────────────────────────────────\n\n/** A campaign carrying a compound rule, in the SDK's runtime shape.\n * Mirrors the cell-plane payload at /v1/in-app/active when\n * client_trigger.type === 'micro_intent'. */\nexport interface ArmedCampaign {\n id: string;\n rule: IntentRule;\n}\n\n/** The decision the evaluator returns when a signal fires.\n *\n * fire : caller should display this campaign now.\n * suppress : caller should silence the listed competing campaign IDs\n * for the rest of the session (the bouncing-researcher\n * pattern — a rule whose only job is to silence others).\n * none : no rule matched, do nothing.\n */\nexport interface EvaluationDecision {\n kind: 'fire' | 'suppress' | 'none';\n campaignId?: string;\n suppressIds?: ReadonlyArray<string>;\n}\n\nexport class IntentRuleEvaluator {\n /** All campaigns currently armed on this page. Caller (the\n * AegisInAppManager) replaces this on every refresh. */\n private armed: ArmedCampaign[] = [];\n\n /** Latest signal values. Caller pushes updates via updateSignal /\n * updateSnapshot whenever TriggerEngine emits a state change or\n * contact-scores fetch completes. */\n private snapshot: IntentSnapshot = {};\n\n /** Campaigns that have already fired this session — never re-fire. */\n private firedThisSession = new Set<string>();\n\n /** Campaigns silenced by a prior `suppress_competing` win. The set\n * resets on session boundary (new tab / new pageview after timeout).\n * The AegisInAppManager owns durability semantics; this set is\n * in-memory only. */\n private silencedThisSession = new Set<string>();\n\n // ─── snapshot management ───\n\n updateSignal(signal: IntentSignal, value: SignalValue): void {\n this.snapshot[signal] = value;\n }\n\n updateSnapshot(partial: IntentSnapshot): void {\n Object.assign(this.snapshot, partial);\n }\n\n getSnapshot(): Readonly<IntentSnapshot> {\n return this.snapshot;\n }\n\n // ─── armed-campaign management ───\n\n setArmed(campaigns: ArmedCampaign[]): void {\n this.armed = [...campaigns];\n }\n\n getArmed(): ReadonlyArray<ArmedCampaign> {\n return this.armed;\n }\n\n markFired(campaignId: string): void {\n this.firedThisSession.add(campaignId);\n }\n\n /** Clear all per-session state. Caller invokes on logout or explicit\n * session reset. */\n reset(): void {\n this.firedThisSession.clear();\n this.silencedThisSession.clear();\n }\n\n // ─── the main dispatch ───\n\n /**\n * Called every time a signal value changes meaningfully (e.g. a\n * TriggerEngine `exit_intent` event, or a `scroll_depth_50` crossing\n * threshold, or the Layer-1 fetch finishing). Returns the decision the\n * caller should act on.\n *\n * Algorithm:\n * 1. Filter armed campaigns to those whose `fire_on` includes the\n * signal that just changed.\n * 2. Drop already-fired and silenced campaigns.\n * 3. Sort the remainder by priority DESC, tie-broken by campaign id\n * lexicographic (per plan §\"Pattern ordering rules\").\n * 4. Walk the sorted list:\n * - If a suppress_competing rule matches, emit a 'suppress'\n * decision listing every lower-priority armed campaign id.\n * Mark those as silenced internally too.\n * - Otherwise the first matching rule emits 'fire'.\n * 5. If nothing matches, return 'none'.\n */\n onSignalChanged(signal: IntentSignal): EvaluationDecision {\n const candidates = this.armed\n .filter((c) => c.rule.fire_on.includes(signal))\n .filter((c) => !this.firedThisSession.has(c.id))\n .filter((c) => !this.silencedThisSession.has(c.id))\n .sort((a, b) => {\n if (b.rule.priority !== a.rule.priority) {\n return b.rule.priority - a.rule.priority;\n }\n // Tie-break: lexicographic on id, ascending.\n return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;\n });\n\n for (let i = 0; i < candidates.length; i++) {\n const c = candidates[i];\n if (!evaluateRule(c.rule, this.snapshot)) continue;\n\n if (c.rule.suppress_competing) {\n // Silence every other armed campaign for the rest of session.\n // Specifically: every armed campaign EXCEPT this one. We don't\n // restrict to \"lower priority\" because suppress_competing is\n // explicitly a bouncing-researcher / margin-protection signal —\n // it means \"if this matches, don't show ANYTHING\".\n const suppressIds = this.armed\n .filter((other) => other.id !== c.id)\n .map((other) => other.id);\n suppressIds.forEach((id) => this.silencedThisSession.add(id));\n return {\n kind: 'suppress',\n campaignId: c.id,\n suppressIds,\n };\n }\n\n return { kind: 'fire', campaignId: c.id };\n }\n\n return { kind: 'none' };\n }\n}\n\n// Re-export pure helpers so tests can reach them without instantiating\n// the class.\nexport const MAX_RULE_DEPTH = 3 as const;\n","/**\n * Micro-Intent Engine — contact-scores fetcher (P4a bridge).\n *\n * Bridges `GET /v1/sdk/contact-scores` into the SDK's\n * `IntentRuleEvaluator` snapshot. Without this, identified-contact\n * micro-intent patterns (VIP Whisper, Win-back At-Risk, Price-Sensitive\n * Nudge, etc.) cannot fire because their AND-compound rules evaluate\n * `rfm_segment` / `lifecycle_stage` / `churn_risk_tier` /\n * `predicted_ltv_tier` / `price_sensitivity_score` against an empty\n * snapshot and always return false.\n *\n * Lifecycle\n * ---------\n * AegisMessageRuntime.initialize() → fetch if contactId known\n * AegisMessageRuntime.updateContactId → fetch for the new contact\n *\n * The fetcher is session-deduped: a second `fetchForContact(sameId)`\n * call within `dedupWindowMs` is a no-op. This stops a hot navigation\n * loop from hammering the endpoint when SPA route changes re-call\n * identify() with the same id.\n *\n * Empty state\n * -----------\n * The endpoint returns 204 for unknown contacts AND for contacts whose\n * `scoring_tier='none'`. Either way the fetcher leaves the snapshot\n * unchanged — the evaluator's leaf eval treats absent Layer-1 keys as\n * null, which fail-closes any AND clause involving them. Anonymous\n * patterns continue to work normally.\n *\n * Privacy posture\n * ---------------\n * The endpoint's default response is the tiered form (`predicted_ltv_tier`).\n * Tenants who opt into raw `predicted_ltv` via\n * `organizations.settings.score_serving_raw_ltv = true` will see the\n * float on the snapshot too. Both are valid IntentSignals; rule\n * authors pick whichever matches their tenant config.\n *\n * Plan reference: docs/architecture/MICRO_INTENT_ENGINE.md §P4a.\n */\n\nimport type { IntentRuleEvaluator, IntentSnapshot } from './IntentRuleEvaluator';\n\n/** Shape of the Layer-1 score response from /v1/sdk/contact-scores. */\nexport interface ContactScoresResponse {\n rfm_segment?: string;\n lifecycle_stage?: string;\n churn_risk_tier?: 'low' | 'medium' | 'high';\n predicted_ltv_tier?: 'low' | 'medium' | 'high';\n predicted_ltv?: number;\n price_sensitivity_score?: number;\n scoring_tier?: string;\n scores_updated_at?: string | null;\n}\n\nexport interface ContactScoresFetcherConfig {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n /** Optional. When provided, the fetcher pushes the response into the\n * evaluator's snapshot automatically on every successful fetch. */\n evaluator?: IntentRuleEvaluator;\n /** Minimum time between repeat fetches for the same contactId.\n * Default 60 seconds. */\n dedupWindowMs?: number;\n /** Override for tests / non-browser environments. */\n fetchImpl?: typeof fetch;\n /** Console.warn channel. */\n onError?: (err: unknown, contactId: string) => void;\n}\n\nexport class ContactScoresFetcher {\n private readonly apiHost: string;\n private readonly writeKey: string;\n private organizationId?: string;\n private readonly evaluator?: IntentRuleEvaluator;\n private readonly dedupWindowMs: number;\n private readonly fetchImpl: typeof fetch;\n private readonly onError?: (err: unknown, contactId: string) => void;\n\n private lastFetchedContactId?: string;\n private lastFetchedAt = 0;\n private latestSnapshot: ContactScoresResponse | null = null;\n\n constructor(cfg: ContactScoresFetcherConfig) {\n this.apiHost = cfg.apiHost.replace(/\\/$/, '');\n this.writeKey = cfg.writeKey;\n this.organizationId = cfg.organizationId;\n this.evaluator = cfg.evaluator;\n this.dedupWindowMs = cfg.dedupWindowMs ?? 60_000;\n this.fetchImpl = cfg.fetchImpl ?? (typeof fetch !== 'undefined' ? fetch.bind(globalThis) : (() => Promise.reject(new Error('fetch unavailable'))) as typeof fetch);\n this.onError = cfg.onError;\n }\n\n /** Update the org so subsequent fetches scope correctly (e.g. when\n * the SDK resolves an org id after init). */\n updateOrganizationId(organizationId: string | undefined): void {\n this.organizationId = organizationId;\n }\n\n /** Most recent successful response. `null` when no fetch has succeeded\n * yet, OR when the endpoint returned 204 (unscored). Consumers can\n * poll this for diagnostic UIs; campaign evaluation does not need to\n * read it directly because the evaluator (if configured) already has\n * the snapshot applied. */\n getSnapshot(): Readonly<ContactScoresResponse> | null {\n return this.latestSnapshot;\n }\n\n /** Fetch scores for `contactId` and apply to the configured evaluator\n * (if any). Returns the response on success, null on 204 / error.\n *\n * Session-dedup: repeat calls for the same contactId within\n * `dedupWindowMs` are no-ops. Pass `force: true` to override. */\n async fetchForContact(\n contactId: string,\n opts: { force?: boolean } = {},\n ): Promise<ContactScoresResponse | null> {\n if (!contactId) return null;\n\n const now = Date.now();\n if (\n !opts.force &&\n this.lastFetchedContactId === contactId &&\n now - this.lastFetchedAt < this.dedupWindowMs\n ) {\n return this.latestSnapshot;\n }\n\n this.lastFetchedContactId = contactId;\n this.lastFetchedAt = now;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Contact-ID': contactId,\n 'X-User-ID': contactId,\n };\n if (this.organizationId) {\n headers['X-Organization-ID'] = this.organizationId;\n }\n\n try {\n const resp = await this.fetchImpl(\n `${this.apiHost}/v1/sdk/contact-scores`,\n {\n method: 'GET',\n headers,\n credentials: 'include',\n },\n );\n if (resp.status === 204) {\n this.latestSnapshot = null;\n return null;\n }\n if (!resp.ok) {\n this.latestSnapshot = null;\n return null;\n }\n const payload = (await resp.json()) as ContactScoresResponse;\n this.latestSnapshot = payload;\n if (this.evaluator) {\n this.evaluator.updateSnapshot(toIntentSnapshot(payload));\n }\n return payload;\n } catch (err) {\n // Network errors / aborted fetches must not block in-app rendering.\n // Anonymous patterns keep working; identified-contact patterns\n // simply don't fire this session.\n this.onError?.(err, contactId);\n return null;\n }\n }\n}\n\n/** Project the wire response onto the evaluator's IntentSnapshot shape.\n * Strings (rfm_segment / lifecycle_stage / *_tier) map straight across;\n * numerics (price_sensitivity_score / predicted_ltv) are passed through\n * as numbers. Missing keys are omitted so the evaluator's leaf eval\n * treats them as null (per IntentRuleEvaluator semantics).\n *\n * Exported for the smoke test — drift guard pins the mapping. */\nexport function toIntentSnapshot(r: ContactScoresResponse): IntentSnapshot {\n const snap: IntentSnapshot = {};\n if (r.rfm_segment) snap.rfm_segment = r.rfm_segment;\n if (r.lifecycle_stage) snap.lifecycle_stage = r.lifecycle_stage;\n if (r.churn_risk_tier) snap.churn_risk_tier = r.churn_risk_tier;\n if (r.predicted_ltv_tier) snap.predicted_ltv_tier = r.predicted_ltv_tier;\n if (typeof r.predicted_ltv === 'number') snap.predicted_ltv = r.predicted_ltv;\n if (typeof r.price_sensitivity_score === 'number') {\n snap.price_sensitivity_score = r.price_sensitivity_score;\n }\n if (r.scoring_tier) snap.scoring_tier = r.scoring_tier;\n return snap;\n}\n","/**\n * SDK Config Poller\n *\n * Fetches non-sensitive SDK configuration from GET /v1/sdk/config\n * with ETag/If-None-Match support for 304 responses.\n *\n * Polls every 5 minutes by default. Config changes are applied\n * to push/in-app managers without re-initialization.\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface SdkConfig {\n version: string;\n push: {\n enabled: boolean;\n vapid_public_key: string | null;\n platforms: string[];\n };\n in_app: {\n enabled: boolean;\n };\n consent: {\n channels_requiring_opt_in: string[];\n };\n}\n\nexport interface SdkConfigPollerOptions {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n pollIntervalMs?: number;\n}\n\nexport type ConfigChangeCallback = (config: SdkConfig) => void;\n\nexport class SdkConfigPoller {\n private options: Required<Omit<SdkConfigPollerOptions, 'organizationId'>> & { organizationId?: string };\n private currentETag: string | null = null;\n private currentConfig: SdkConfig | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private listeners: ConfigChangeCallback[] = [];\n\n constructor(options: SdkConfigPollerOptions) {\n this.options = {\n pollIntervalMs: 300_000, // 5 minutes\n ...options,\n };\n }\n\n /**\n * Fetch config once (on init) and start polling.\n */\n async start(): Promise<SdkConfig | null> {\n const config = await this.fetchConfig();\n\n this.pollTimer = setInterval(() => {\n this.fetchConfig().catch((err) => {\n logger.warn('SDK config poll failed:', err);\n });\n }, this.options.pollIntervalMs);\n\n return config;\n }\n\n /**\n * Stop polling.\n */\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n /**\n * Register a callback for config changes.\n */\n onChange(callback: ConfigChangeCallback): () => void {\n this.listeners.push(callback);\n return () => {\n const idx = this.listeners.indexOf(callback);\n if (idx >= 0) this.listeners.splice(idx, 1);\n };\n }\n\n /**\n * Get current cached config.\n */\n getConfig(): SdkConfig | null {\n return this.currentConfig;\n }\n\n /**\n * Fetch config with ETag/304 support.\n */\n private async fetchConfig(): Promise<SdkConfig | null> {\n try {\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.options.writeKey,\n 'Accept': 'application/json',\n };\n\n if (this.options.organizationId) {\n headers['X-Organization-ID'] = this.options.organizationId;\n }\n\n if (this.currentETag) {\n headers['If-None-Match'] = this.currentETag;\n }\n\n const response = await fetch(`${this.options.apiHost}/v1/sdk/config`, {\n method: 'GET',\n headers,\n });\n\n // 304 Not Modified — config unchanged\n if (response.status === 304) {\n return this.currentConfig;\n }\n\n if (!response.ok) {\n logger.warn(`SDK config fetch failed: HTTP ${response.status}`);\n return this.currentConfig;\n }\n\n const config: SdkConfig = await response.json();\n const newETag = response.headers.get('ETag');\n\n if (newETag) {\n this.currentETag = newETag;\n }\n\n // Detect changes\n const changed = !this.currentConfig ||\n JSON.stringify(this.currentConfig) !== JSON.stringify(config);\n\n this.currentConfig = config;\n\n if (changed) {\n for (const listener of this.listeners) {\n try {\n listener(config);\n } catch (err) {\n logger.warn('SDK config change listener error:', err);\n }\n }\n }\n\n return config;\n } catch (err) {\n logger.warn('SDK config fetch error:', err);\n return this.currentConfig;\n }\n }\n}\n","/**\n * PrefetchBundleClient — unified init-time resolver for in-app state.\n *\n * Fetches /v1/sdk/prefetch-bundle at SDK init and on a 5-minute ETag\n * refresh cadence. The bundle payload carries:\n * • `campaigns[]` — eligible, property-scoped, A/B-assigned campaigns\n * armed for this contact. EVERY in-app type is in\n * here (modal, banner, spin_wheel, carousel_cards,\n * sticky_bar, progress_bar, coachmark_tour, etc.).\n * • `inbox` — first page + unread count for the notification\n * drawer; lets AegisInbox hydrate without a second\n * round-trip.\n * • `etag` — content-hashed, stable when state is unchanged;\n * 304 responses cost ~50ms and consume no body.\n * • `invalidation_topic` — SSE channel name the cell-plane publishes\n * to when a playbook arms a campaign mid-session.\n * The SDK does NOT open SSE on that topic today —\n * we rely on the 5-minute poll + an explicit\n * `refresh()` hook that app code (AegisInAppManager,\n * AegisInbox) call on relevant user actions.\n *\n * This is the cornerstone of the preload-first contract from\n * docs/architecture/IN_APP_MESSAGES_EXPANSION_PLAN.md §1. The render\n * path must NEVER hit the network at trigger time — the bundle is\n * populated at init, and everything renders from memory.\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface PrefetchBundleCampaign {\n id: string;\n type: string;\n sub_type?: string;\n title: string;\n body: string;\n image_url?: string;\n action_url?: string;\n button_text?: string;\n background_color?: string;\n text_color?: string;\n priority: number;\n expires_at?: string | null;\n frequency?: {\n max_impressions?: number;\n max_impressions_per_day?: number;\n cooldown_seconds?: number;\n };\n interactive_config?: Record<string, unknown>;\n client_trigger?: {\n type: string;\n config?: Record<string, unknown>;\n };\n assigned_variant_id?: string;\n inbox_enabled?: boolean;\n}\n\nexport interface PrefetchBundleInboxEntry {\n id: string;\n source: string;\n campaign_id: string | null;\n title: string;\n body: string;\n media_url: string | null;\n cta_url: string | null;\n metadata: Record<string, unknown> | null;\n read: boolean;\n read_at: string | null;\n created_at: string | null;\n expires_at: string | null;\n}\n\nexport interface PrefetchBundleInbox {\n unread_count: number;\n page: PrefetchBundleInboxEntry[];\n cursor: string | null;\n}\n\nexport interface PrefetchBundle {\n etag: string;\n generated_at: string;\n ttl_seconds: number;\n invalidation_topic: string;\n campaigns: PrefetchBundleCampaign[];\n inbox: PrefetchBundleInbox;\n}\n\nexport interface PrefetchBundleContext {\n device_type?: string;\n page_url?: string;\n geo?: string;\n is_new_user?: boolean;\n}\n\nexport interface PrefetchBundleClientOptions {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n contactId?: string;\n userId?: string;\n propertyId?: string;\n /** Cached AB assignments from localStorage, base64-json. */\n abAssignments?: Record<string, string>;\n /** Polling cadence; defaults to the bundle's own `ttl_seconds` (300s). */\n pollIntervalMs?: number;\n /** Factory for client context — re-evaluated on each fetch so device/page\n * state stays fresh without forcing callers to re-instantiate the client. */\n contextProvider?: () => PrefetchBundleContext;\n}\n\nexport type PrefetchBundleListener = (bundle: PrefetchBundle) => void;\n\nconst DEFAULT_POLL_MS = 300_000; // 5 minutes — aligns with cell-plane TTL\n\nexport class PrefetchBundleClient {\n private apiHost: string;\n private writeKey: string;\n private organizationId?: string;\n private contactId?: string;\n private userId?: string;\n private propertyId?: string;\n private abAssignments: Record<string, string>;\n private pollIntervalMs: number;\n private contextProvider: () => PrefetchBundleContext;\n\n private currentETag: string | null = null;\n private currentBundle: PrefetchBundle | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private listeners: PrefetchBundleListener[] = [];\n private inflightRefetch: Promise<PrefetchBundle | null> | null = null;\n\n constructor(options: PrefetchBundleClientOptions) {\n this.apiHost = options.apiHost;\n this.writeKey = options.writeKey;\n this.organizationId = options.organizationId;\n this.contactId = options.contactId;\n this.userId = options.userId;\n this.propertyId = options.propertyId;\n this.abAssignments = options.abAssignments ?? {};\n this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_MS;\n this.contextProvider = options.contextProvider ?? (() => ({}));\n }\n\n /**\n * Initial fetch + start the background ETag poll. Resolves to the bundle\n * (or `null` if the first fetch failed — callers should fall back to an\n * empty campaign list, not abort SDK init).\n */\n async start(): Promise<PrefetchBundle | null> {\n const bundle = await this.fetch();\n this.pollTimer = setInterval(() => {\n this.fetch().catch((err) => logger.warn('prefetch-bundle poll failed:', err));\n }, this.pollIntervalMs);\n return bundle;\n }\n\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n getBundle(): PrefetchBundle | null {\n return this.currentBundle;\n }\n\n getCampaigns(): PrefetchBundleCampaign[] {\n return this.currentBundle?.campaigns ?? [];\n }\n\n getInbox(): PrefetchBundleInbox {\n return this.currentBundle?.inbox ?? { unread_count: 0, page: [], cursor: null };\n }\n\n /** Force a refresh (dedupes concurrent calls). Exposed so inbox mutations\n * and campaign-activation SSE messages can trigger a refetch on demand. */\n async refresh(): Promise<PrefetchBundle | null> {\n if (this.inflightRefetch) return this.inflightRefetch;\n this.inflightRefetch = this.fetch();\n try {\n return await this.inflightRefetch;\n } finally {\n this.inflightRefetch = null;\n }\n }\n\n /** Subscribe to bundle changes (emits on first fetch + on any content\n * change — ETag 304 does NOT fire the listener). Returns an unsubscribe. */\n onChange(listener: PrefetchBundleListener): () => void {\n this.listeners.push(listener);\n return () => {\n const idx = this.listeners.indexOf(listener);\n if (idx >= 0) this.listeners.splice(idx, 1);\n };\n }\n\n /**\n * Update the identity tuple — called by AegisInAppManager when the host\n * app resolves a contactId post-init (e.g., after login). Triggers an\n * immediate refresh since the eligible campaigns + inbox will differ.\n */\n updateIdentity(partial: {\n contactId?: string;\n userId?: string;\n organizationId?: string;\n propertyId?: string;\n }): void {\n let changed = false;\n if (partial.contactId !== undefined && partial.contactId !== this.contactId) {\n this.contactId = partial.contactId;\n changed = true;\n }\n if (partial.userId !== undefined && partial.userId !== this.userId) {\n this.userId = partial.userId;\n changed = true;\n }\n if (\n partial.organizationId !== undefined &&\n partial.organizationId !== this.organizationId\n ) {\n this.organizationId = partial.organizationId;\n changed = true;\n }\n if (partial.propertyId !== undefined && partial.propertyId !== this.propertyId) {\n this.propertyId = partial.propertyId;\n changed = true;\n }\n if (changed) {\n // Identity change invalidates ETag — drop the cached tag so the next\n // fetch gets a fresh payload instead of a 304 bound to the old identity.\n this.currentETag = null;\n this.refresh().catch((err) =>\n logger.warn('prefetch-bundle identity-refresh failed:', err),\n );\n }\n }\n\n /** Update cached AB assignments. Called by downstream renderers after\n * they display a variant. Persisted to localStorage by higher layers. */\n setAbAssignments(assignments: Record<string, string>): void {\n this.abAssignments = { ...assignments };\n }\n\n /**\n * Wire an already-open realtime subscriber (from `aegis.realtime.subscribe`\n * or a caller-provided EventSource) so the prefetch bundle refreshes\n * instantly when the cell-plane signals `bundle.invalidate` — covering\n * the window between an event (cart abandon, inbox write) and the\n * 5-min ETag poll.\n *\n * `subscriber.onMessage(handler)` must fire with parsed message bodies\n * from the contact's SSE stream. The handler filters for\n * `type === 'bundle.invalidate'` and calls `refresh()`. Returns an\n * unsubscribe function.\n *\n * Degrades gracefully: if the subscriber is missing or throws, the\n * 5-min poll still keeps state converging.\n */\n subscribeInvalidations(subscriber: {\n onMessage: (handler: (msg: { type?: string; [k: string]: unknown }) => void) => () => void;\n }): () => void {\n try {\n const unsub = subscriber.onMessage((msg) => {\n if (msg && msg.type === 'bundle.invalidate') {\n this.refresh().catch((err) =>\n logger.warn('prefetch-bundle invalidate-refresh failed:', err),\n );\n }\n });\n return unsub;\n } catch (err) {\n logger.warn('prefetch-bundle subscribeInvalidations failed — relying on poll:', err);\n return () => {};\n }\n }\n\n // ── internals ──────────────────────────────────────────────────────────\n\n private async fetch(): Promise<PrefetchBundle | null> {\n const ctx = this.contextProvider();\n const qs = new URLSearchParams();\n if (ctx.device_type) qs.set('device_type', ctx.device_type);\n if (ctx.page_url) qs.set('page_url', ctx.page_url);\n if (ctx.geo) qs.set('geo', ctx.geo);\n qs.set('is_new_user', ctx.is_new_user ? 'true' : 'false');\n\n const url = `${this.apiHost}/v1/sdk/prefetch-bundle?${qs.toString()}`;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n Accept: 'application/json',\n };\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.propertyId) headers['X-Property-Id'] = this.propertyId;\n if (this.currentETag) headers['If-None-Match'] = this.currentETag;\n if (Object.keys(this.abAssignments).length > 0) {\n try {\n headers['X-AB-Assignments'] = btoa(JSON.stringify(this.abAssignments));\n } catch {\n // base64 on non-ASCII campaign IDs — skip rather than 400 the request\n }\n }\n\n let response: Response;\n try {\n response = await fetch(url, { method: 'GET', headers });\n } catch (err) {\n logger.warn('prefetch-bundle fetch network error:', err);\n return this.currentBundle;\n }\n\n // 304 — same bundle; listeners are intentionally NOT fired.\n if (response.status === 304) {\n return this.currentBundle;\n }\n\n if (!response.ok) {\n logger.warn(`prefetch-bundle fetch failed: HTTP ${response.status}`);\n return this.currentBundle;\n }\n\n const etag = response.headers.get('ETag');\n let bundle: PrefetchBundle;\n try {\n bundle = (await response.json()) as PrefetchBundle;\n } catch (err) {\n logger.warn('prefetch-bundle invalid JSON:', err);\n return this.currentBundle;\n }\n\n if (etag) this.currentETag = etag;\n this.currentBundle = bundle;\n\n for (const l of this.listeners) {\n try {\n l(bundle);\n } catch (err) {\n logger.warn('prefetch-bundle listener threw:', err);\n }\n }\n\n return bundle;\n }\n}\n","/**\n * AegisInbox — client-side App Inbox (Message Center).\n *\n * Backs the notification drawer on actii.me WebView and every tenant\n * storefront that embeds the Web SDK. Operates against cell-plane's\n * /v1/in-app/inbox family of endpoints (list, unread-count, read,\n * dismiss, read-all).\n *\n * Design choices:\n * • Hydrate from the prefetch bundle at init — no extra HTTP on first\n * paint. PrefetchBundleClient seeds us; we then own the live copy.\n * • Mutations are optimistic + beacon-backed. Read / dismiss writes to\n * local state immediately, then POSTs with `keepalive: true` so an\n * in-flight dismiss survives page unload.\n * • Badge polling uses the tiny `/unread-count` endpoint on a 60-second\n * cadence — matches the `inbox_poll_interval_ms` from sdk_config's\n * TransportConfig.hybrid mode.\n * • No external dependencies; IndexedDB is optional (we gracefully fall\n * back to in-memory when unavailable, e.g., in private browsing).\n */\n\nimport type { PrefetchBundleClient } from '../core/prefetch-bundle-client';\nimport { logger } from '../utils/logger';\n\nexport interface AegisInboxEntry {\n id: string;\n source: string;\n campaign_id: string | null;\n title: string;\n body: string;\n media_url: string | null;\n cta_url: string | null;\n metadata: Record<string, unknown> | null;\n read: boolean;\n read_at: string | null;\n dismissed_at?: string | null;\n created_at: string | null;\n expires_at: string | null;\n}\n\nexport interface AegisInboxConfig {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n contactId?: string;\n propertyId?: string;\n bundleClient?: PrefetchBundleClient;\n unreadPollIntervalMs?: number;\n}\n\nexport type InboxListener = (state: { entries: AegisInboxEntry[]; unreadCount: number }) => void;\n\nconst DEFAULT_UNREAD_POLL = 60_000;\n\n/** IndexedDB schema version + constants. Offline cache is a nice-to-have,\n * so we never break the app if IDB operations fail. */\nconst IDB_NAME = 'aegis-inbox';\nconst IDB_STORE = 'messages';\nconst IDB_VERSION = 1;\n\nexport class AegisInbox {\n private apiHost: string;\n private writeKey: string;\n private organizationId?: string;\n private contactId?: string;\n private propertyId?: string;\n private bundleClient?: PrefetchBundleClient;\n private unreadPollIntervalMs: number;\n\n private entries: AegisInboxEntry[] = [];\n private unreadCount = 0;\n private cursor: string | null = null;\n private listeners: InboxListener[] = [];\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private bundleUnsub: (() => void) | null = null;\n\n constructor(config: AegisInboxConfig) {\n this.apiHost = config.apiHost;\n this.writeKey = config.writeKey;\n this.organizationId = config.organizationId;\n this.contactId = config.contactId;\n this.propertyId = config.propertyId;\n this.bundleClient = config.bundleClient;\n this.unreadPollIntervalMs = config.unreadPollIntervalMs ?? DEFAULT_UNREAD_POLL;\n }\n\n /** Hydrate from bundle (if available), restore the IDB cache (if any),\n * then start the background unread-count poll. */\n async initialize(): Promise<void> {\n // Inbox is contact-scoped — if the host app hasn't resolved a contact\n // yet, stay dormant. The host will call setIdentity() later.\n if (!this.contactId || !this.propertyId) {\n logger.warn('AegisInbox: no contact/property yet — staying dormant');\n return;\n }\n\n // Try IDB cache for instant paint on cold start.\n const cached = await this.readCache();\n if (cached.length > 0) {\n this.entries = cached;\n this.recomputeUnread();\n this.emit();\n }\n\n // Hydrate from prefetch bundle if we have one — this is the preload\n // path, no additional network round-trip.\n if (this.bundleClient) {\n const inbox = this.bundleClient.getInbox();\n this.seedFromBundle(inbox.page, inbox.unread_count);\n // Keep following bundle changes — when the bundle-poller refreshes,\n // the inbox slice refreshes too.\n this.bundleUnsub = this.bundleClient.onChange((bundle) => {\n this.seedFromBundle(bundle.inbox.page, bundle.inbox.unread_count);\n });\n } else {\n // No bundle client — do one list call to prime.\n await this.refreshList();\n }\n\n this.pollTimer = setInterval(() => {\n this.refreshUnreadCount().catch((err) =>\n logger.warn('inbox unread-count poll failed:', err),\n );\n }, this.unreadPollIntervalMs);\n }\n\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n if (this.bundleUnsub) {\n this.bundleUnsub();\n this.bundleUnsub = null;\n }\n }\n\n /** Update identity after login / property switch. Clears the local\n * inbox since it's intrinsically contact+property scoped. */\n setIdentity(partial: { contactId?: string; propertyId?: string; organizationId?: string }): void {\n let changed = false;\n if (partial.contactId !== undefined && partial.contactId !== this.contactId) {\n this.contactId = partial.contactId;\n changed = true;\n }\n if (partial.propertyId !== undefined && partial.propertyId !== this.propertyId) {\n this.propertyId = partial.propertyId;\n changed = true;\n }\n if (partial.organizationId !== undefined && partial.organizationId !== this.organizationId) {\n this.organizationId = partial.organizationId;\n changed = true;\n }\n if (changed) {\n this.entries = [];\n this.unreadCount = 0;\n this.cursor = null;\n this.emit();\n void this.clearCache();\n void this.refreshList();\n }\n }\n\n // ── Read-side API ────────────────────────────────────────────────────\n\n getEntries(): AegisInboxEntry[] {\n return this.entries;\n }\n\n getUnreadCount(): number {\n return this.unreadCount;\n }\n\n /** Pagination cursor (ISO-8601 timestamp of the oldest entry currently\n * held). Pass it back via `loadMore()` to fetch older history. */\n getCursor(): string | null {\n return this.cursor;\n }\n\n /** Append one more page of older entries using the current cursor. */\n async loadMore(): Promise<void> {\n if (!this.contactId || !this.propertyId || !this.cursor) return;\n try {\n const url = `${this.apiHost}/v1/in-app/inbox?limit=20&cursor=${encodeURIComponent(this.cursor)}`;\n const resp = await fetch(url, { headers: this.headers() });\n if (!resp.ok) return;\n const body = (await resp.json()) as {\n entries: AegisInboxEntry[];\n unread_count: number;\n cursor: string | null;\n };\n const byId = new Set(this.entries.map((e) => e.id));\n for (const e of body.entries) {\n if (!byId.has(e.id)) this.entries.push(e);\n }\n this.cursor = body.cursor;\n void this.writeCache();\n this.emit();\n } catch (err) {\n logger.warn('inbox loadMore failed:', err);\n }\n }\n\n onChange(l: InboxListener): () => void {\n this.listeners.push(l);\n return () => {\n const i = this.listeners.indexOf(l);\n if (i >= 0) this.listeners.splice(i, 1);\n };\n }\n\n async refreshList(): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n const resp = await fetch(\n `${this.apiHost}/v1/in-app/inbox?limit=20`,\n { headers: this.headers() },\n );\n if (!resp.ok) {\n logger.warn(`inbox list fetch failed: HTTP ${resp.status}`);\n return;\n }\n const body = (await resp.json()) as {\n entries: AegisInboxEntry[];\n unread_count: number;\n cursor: string | null;\n };\n this.entries = body.entries;\n this.unreadCount = body.unread_count;\n this.cursor = body.cursor;\n void this.writeCache();\n this.emit();\n } catch (err) {\n logger.warn('inbox list fetch error:', err);\n }\n }\n\n async refreshUnreadCount(): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n const resp = await fetch(\n `${this.apiHost}/v1/in-app/inbox/unread-count`,\n { headers: this.headers() },\n );\n if (!resp.ok) return;\n const body = (await resp.json()) as { unread_count: number };\n if (body.unread_count !== this.unreadCount) {\n this.unreadCount = body.unread_count;\n this.emit();\n // New messages detected — do a list refresh to get them.\n if (this.unreadCount > 0) {\n void this.refreshList();\n }\n }\n } catch {\n /* swallow — transient network */\n }\n }\n\n // ── Mutations (optimistic + beacon) ──────────────────────────────────\n\n async markRead(messageId: string): Promise<void> {\n const entry = this.entries.find((e) => e.id === messageId);\n if (!entry || entry.read) return;\n entry.read = true;\n entry.read_at = new Date().toISOString();\n this.recomputeUnread();\n void this.writeCache();\n this.emit();\n await this.postBeacon(`/v1/in-app/inbox/${messageId}/read`);\n }\n\n async dismiss(messageId: string): Promise<void> {\n const idx = this.entries.findIndex((e) => e.id === messageId);\n if (idx < 0) return;\n const [entry] = this.entries.splice(idx, 1);\n if (entry && !entry.read) {\n this.recomputeUnread();\n }\n void this.writeCache();\n this.emit();\n await this.postBeacon(`/v1/in-app/inbox/${messageId}/dismiss`);\n }\n\n async markAllRead(): Promise<void> {\n const now = new Date().toISOString();\n for (const e of this.entries) {\n if (!e.read) {\n e.read = true;\n e.read_at = now;\n }\n }\n this.unreadCount = 0;\n void this.writeCache();\n this.emit();\n await this.postBeacon('/v1/in-app/inbox/read-all');\n }\n\n // ── Internals ────────────────────────────────────────────────────────\n\n private seedFromBundle(page: AegisInboxEntry[], unreadCount: number): void {\n // Merge rather than overwrite — an entry we already marked read\n // locally should stay read even if the bundle is slightly stale.\n const byId = new Map(this.entries.map((e) => [e.id, e] as const));\n const merged = page.map((incoming) => {\n const existing = byId.get(incoming.id);\n if (existing && existing.read && !incoming.read) {\n return { ...incoming, read: true, read_at: existing.read_at };\n }\n return incoming;\n });\n // Preserve any locally-cached entries that aren't in this bundle page\n // (e.g., older history not included in the first slice).\n for (const [id, e] of byId) {\n if (!merged.find((m) => m.id === id)) merged.push(e);\n }\n merged.sort((a, b) => (b.created_at || '').localeCompare(a.created_at || ''));\n this.entries = merged;\n this.unreadCount = unreadCount;\n void this.writeCache();\n this.emit();\n }\n\n private recomputeUnread(): void {\n this.unreadCount = this.entries.filter((e) => !e.read).length;\n }\n\n private emit(): void {\n const snapshot = { entries: [...this.entries], unreadCount: this.unreadCount };\n for (const l of this.listeners) {\n try {\n l(snapshot);\n } catch (err) {\n logger.warn('inbox listener threw:', err);\n }\n }\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n Accept: 'application/json',\n };\n if (this.organizationId) h['X-Organization-ID'] = this.organizationId;\n if (this.contactId) h['X-Contact-ID'] = this.contactId;\n if (this.propertyId) h['X-Property-Id'] = this.propertyId;\n return h;\n }\n\n /** Best-effort beacon-style POST. Uses `keepalive: true` so it survives\n * a navigation away from the current page (e.g., user taps the CTA\n * which takes them to another URL right after dismiss). */\n private async postBeacon(path: string): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n await fetch(`${this.apiHost}${path}`, {\n method: 'POST',\n headers: this.headers(),\n keepalive: true,\n });\n } catch (err) {\n // The mutation is already applied locally; failed delivery will be\n // reconciled on the next refreshList().\n logger.warn(`inbox mutation POST ${path} failed:`, err);\n }\n }\n\n // ── IndexedDB cache (non-critical) ───────────────────────────────────\n\n private async openDb(): Promise<IDBDatabase | null> {\n if (typeof indexedDB === 'undefined') return null;\n return new Promise((resolve) => {\n try {\n const req = indexedDB.open(IDB_NAME, IDB_VERSION);\n req.onerror = () => resolve(null);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(IDB_STORE)) {\n db.createObjectStore(IDB_STORE);\n }\n };\n req.onsuccess = () => resolve(req.result);\n } catch {\n resolve(null);\n }\n });\n }\n\n private cacheKey(): string | null {\n if (!this.contactId || !this.propertyId) return null;\n return `${this.organizationId || 'default'}:${this.propertyId}:${this.contactId}`;\n }\n\n private async writeCache(): Promise<void> {\n const key = this.cacheKey();\n if (!key) return;\n const db = await this.openDb();\n if (!db) return;\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).put(this.entries, key);\n await new Promise<void>((res, rej) => {\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n } catch {\n /* noop */\n } finally {\n db.close();\n }\n }\n\n private async readCache(): Promise<AegisInboxEntry[]> {\n const key = this.cacheKey();\n if (!key) return [];\n const db = await this.openDb();\n if (!db) return [];\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const req = tx.objectStore(IDB_STORE).get(key);\n return await new Promise<AegisInboxEntry[]>((res) => {\n req.onsuccess = () => res((req.result as AegisInboxEntry[]) || []);\n req.onerror = () => res([]);\n });\n } catch {\n return [];\n } finally {\n db.close();\n }\n }\n\n private async clearCache(): Promise<void> {\n const key = this.cacheKey();\n if (!key) return;\n const db = await this.openDb();\n if (!db) return;\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).delete(key);\n await new Promise<void>((res) => {\n tx.oncomplete = () => res();\n tx.onerror = () => res();\n });\n } catch {\n /* noop */\n } finally {\n db.close();\n }\n }\n}\n","/**\n * AegisWidgetManager - Web SDK Widget Module\n * \n * Smart Pull architecture for persistent web widgets.\n * \n * Features:\n * - Gamification (spin wheel, scratch card) with server-side prize generation\n * - Chat bubbles (WhatsApp, support)\n * - Social proof toasts (real-time purchase notifications)\n * - Feedback forms (NPS, surveys)\n * \n * Security:\n * - XSS Protection: Uses DOM APIs instead of innerHTML\n * - Server-side prize generation prevents client manipulation\n * - URL validation prevents javascript: protocol injection\n * \n * Architecture:\n * - Fetches widget configs from /v1/widgets/config on page load\n * - Integrates with TriggerEngine for behavioral triggers\n * - Tracks widget events (show, click, dismiss, submit)\n * - Server-side prize generation for gamification\n */\n\nimport { TriggerEngine } from '../triggers/TriggerEngine';\nimport { Storage } from '../utils/storage';\n\n// Read the SDK's persisted anonymous_id from localStorage/cookie if available.\n// Returns undefined when called server-side or when no id has been minted yet.\n// See AegisInAppManager for the same pattern + canonical contract in\n// docs/architecture/API_ROUTING.md §3.\nfunction readAnonIdFromStorage(): string | undefined {\n if (typeof document === 'undefined') return undefined;\n try {\n const storage = new Storage();\n return storage.get('anon_id') ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface WidgetConfig {\n widget_id: string;\n widget_type: 'chat_bubble' | 'spin_wheel' | 'scratch_card' | 'toast' | 'feedback_form' | 'exit_intent_popup';\n name: string;\n config: Record<string, any>;\n position?: string;\n priority: number;\n trigger_rules?: {\n type: 'exit_intent' | 'scroll_depth' | 'time_on_page' | 'immediate';\n config?: Record<string, any>;\n };\n}\n\nexport interface GamificationPrize {\n prize_label: string;\n prize_value?: string;\n coupon_code?: string;\n play_id: string;\n}\n\nexport interface AegisWidgetConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n debugMode?: boolean;\n triggerEngine?: TriggerEngine;\n /** If true, WidgetManager takes ownership of the TriggerEngine and\n * will call `triggerEngine.stop()` on destroy(). Leave false when\n * the caller shares the engine across managers (e.g. the facade). */\n ownsTriggerEngine?: boolean;\n enablePrefetch?: boolean;\n cssCustomization?: WidgetCSSCustomization;\n onEvent?: (eventType: string, data: any) => void;\n /** Source platform passed as X-Source-Platform header so the API\n * can filter campaigns whose display_rules.sources restricts them\n * to specific integrations (e.g. 'shopify', 'woocommerce'). */\n sourcePlatform?: 'web' | 'shopify' | 'woocommerce' | 'mobile_sdk';\n /**\n * Workspace cascade reader. Host SDK sets this to\n * `() => aegis.getEffectiveWorkspaceId()` so widget interaction events\n * (impressions, clicks, spin/scratch plays, feedback submissions)\n * arrive at the gateway with the same workspace context the main\n * analytics SDK uses. See PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n */\n getWorkspaceId?: () => string | undefined;\n}\n\nexport interface WidgetCSSCustomization {\n exitIntent?: {\n backgroundColor?: string;\n textColor?: string;\n accentColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n overlayOpacity?: number;\n };\n spinWheel?: {\n backgroundColor?: string;\n textColor?: string;\n accentColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n wheelColors?: string[];\n buttonColor?: string;\n };\n chatBubble?: {\n backgroundColor?: string;\n textColor?: string;\n position?: 'bottom_right' | 'bottom_left' | 'top_right' | 'top_left';\n size?: 'small' | 'medium' | 'large';\n };\n}\n\nexport interface PrefetchWidgetConfig {\n exit_intent?: {\n enabled: boolean;\n type: 'cart_recovery' | 'lead_gen';\n tier?: string;\n title?: string;\n message?: string;\n discount_code?: string;\n discount_percentage?: number;\n cta_text?: string;\n cta_url?: string;\n background_color?: string;\n text_color?: string;\n accent_color?: string;\n show_cart_items?: boolean;\n show_timer?: boolean;\n timer_minutes?: number;\n priority: number;\n mobile_triggers?: {\n scroll_velocity?: boolean;\n scroll_threshold?: number;\n scroll_min_position?: number;\n scroll_cooldown?: number;\n idle_timer?: boolean;\n idle_seconds?: number;\n visibility_change?: boolean;\n back_button?: boolean;\n };\n };\n spin_wheel?: {\n enabled: boolean;\n type: 'lead_gen' | 'cart_recovery';\n title?: string;\n prizes?: any[];\n priority: number;\n };\n}\n\nexport interface CartData {\n cart_id: string;\n cart_total: number;\n cart_currency: string;\n cart_items: Array<{\n product_id: string;\n product_name?: string;\n quantity: number;\n price?: number;\n }>;\n}\n\nexport class AegisWidgetManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private debugMode: boolean;\n private triggerEngine?: TriggerEngine;\n private enablePrefetch: boolean;\n private cssCustomization: WidgetCSSCustomization;\n private onEvent?: (eventType: string, data: any) => void;\n private sourcePlatform?: string;\n private getWorkspaceId?: () => string | undefined;\n\n private widgets: WidgetConfig[] = [];\n private renderedWidgets = new Set<string>();\n private isInitialized = false;\n private isDestroyed = false;\n private ownsTriggerEngine: boolean;\n\n private prefetchWidgetConfigs: PrefetchWidgetConfig = {};\n private cartData?: CartData;\n \n constructor(config: AegisWidgetConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n // Fall back to the SDK's persisted anonymous_id when callers don't pass\n // userId explicitly. Without this, /v1/widgets/config requests omit\n // X-User-ID and the cell-plane buckets the call into \"anonymous\", which\n // misses any user-targeted widget configs. Mirror in AegisInAppManager.\n this.userId = config.userId ?? readAnonIdFromStorage();\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.debugMode = config.debugMode || false;\n this.triggerEngine = config.triggerEngine;\n this.ownsTriggerEngine = config.ownsTriggerEngine === true;\n this.enablePrefetch = config.enablePrefetch !== false;\n this.cssCustomization = config.cssCustomization || {};\n this.onEvent = config.onEvent;\n this.sourcePlatform = config.sourcePlatform;\n this.getWorkspaceId = config.getWorkspaceId;\n }\n \n updateCSSCustomization(customization: WidgetCSSCustomization): void {\n this.cssCustomization = { ...this.cssCustomization, ...customization };\n this.log('CSS customization updated');\n }\n\n /**\n * Swap the identity that outgoing widget requests are attributed to.\n * Safe to call at any time; if prefetch is enabled and the manager\n * has already initialised, this will re-fetch the per-contact widget\n * configs so subsequent renders target the new identity. Does NOT\n * re-render already-visible widgets — a full teardown requires destroy().\n */\n async updateContactId(contactId: string | undefined): Promise<void> {\n if (this.contactId === contactId) return;\n this.contactId = contactId;\n this.log(`Contact ID updated → ${contactId ?? '(cleared)'}`);\n if (this.isInitialized && !this.isDestroyed && this.enablePrefetch && contactId) {\n await this.fetchPrefetchConfigs();\n this.preloadWidgetAssets();\n }\n }\n\n /**\n * Render an in-app campaign whose sub_type routes it to the\n * gamification-widget code path (spin_wheel / scratch_card).\n * InAppCampaign is adapted to the minimal WidgetConfig shape that\n * the internal renderers already understand — no rewrite needed.\n *\n * AegisMessageRuntime wires this method as AegisInAppManager's\n * `onInteractiveCampaign` callback so impressions from the inbox\n * prefetch bundle actually land on screen.\n */\n renderInteractiveCampaign(campaign: {\n id: string;\n title: string;\n sub_type?: string;\n priority?: number;\n interactive_config?: Record<string, unknown>;\n }): void {\n if (this.isDestroyed) return;\n if (typeof document === 'undefined') return;\n const subType = campaign.sub_type;\n if (subType !== 'spin_wheel' && subType !== 'scratch_card') {\n this.log(`renderInteractiveCampaign: unsupported sub_type \"${subType}\"`, true);\n return;\n }\n const widget: WidgetConfig = {\n widget_id: campaign.id,\n widget_type: subType,\n name: campaign.title,\n config: (campaign.interactive_config ?? {}) as Record<string, any>,\n priority: campaign.priority ?? 0,\n };\n if (this.renderedWidgets.has(widget.widget_id)) return;\n this.renderedWidgets.add(widget.widget_id);\n if (subType === 'spin_wheel') {\n this.renderSpinWheel(widget);\n } else {\n this.renderScratchCard(widget);\n }\n }\n\n /**\n * Tear down everything the manager installed: trigger listeners (if\n * we own the TriggerEngine), injected style sheets, and any rendered\n * widget roots. Further render attempts from in-flight triggers are\n * short-circuited by the `isDestroyed` flag.\n */\n destroy(): void {\n if (this.isDestroyed) return;\n this.isDestroyed = true;\n\n if (this.triggerEngine && this.ownsTriggerEngine) {\n this.triggerEngine.stop();\n }\n\n if (typeof document !== 'undefined') {\n const animationStyle = document.getElementById('aegis-widget-animations');\n animationStyle?.remove();\n document.querySelectorAll('[data-aegis-widget-root]').forEach((node) => {\n node.remove();\n });\n }\n\n this.renderedWidgets.clear();\n this.widgets = [];\n this.isInitialized = false;\n this.log('AegisWidgets destroyed');\n this.emitEvent('destroyed', {});\n }\n\n /**\n * Fire a lifecycle event to the consumer-supplied callback. Public-API\n * hook configured via `AegisWidgetConfig.onEvent`. Currently only used\n * by external callers passing their own logger; internal widget lifecycle\n * events get wired through here as they're added.\n */\n private emitEvent(eventType: string, data: unknown): void {\n if (this.onEvent) {\n try {\n this.onEvent(eventType, data);\n } catch (error) {\n this.log(`Error in event callback: ${error}`, true);\n }\n }\n }\n\n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisWidgets already initialized');\n return;\n }\n \n if (this.enablePrefetch && this.contactId) {\n await this.fetchPrefetchConfigs();\n this.preloadWidgetAssets();\n }\n \n await this.fetchWidgets();\n \n this.renderImmediateWidgets();\n \n this.setupTriggerListeners();\n \n this.setupExitIntentWithPrefetch();\n \n this.isInitialized = true;\n this.log('AegisWidgets initialized successfully');\n }\n \n setCartData(cartData: CartData): void {\n this.cartData = cartData;\n this.log(`Cart data updated: ${cartData.cart_items.length} items, total: ${cartData.cart_currency} ${cartData.cart_total}`);\n }\n \n private detectPlatformCart(): CartData | null {\n const shopifyCart = this.normalizeShopifyCart();\n if (shopifyCart) {\n this.log('Detected Shopify cart via browser globals');\n return shopifyCart;\n }\n \n const wooCart = this.normalizeWooCart();\n if (wooCart) {\n this.log('Detected WooCommerce cart via injected data');\n return wooCart;\n }\n \n const magentoCart = this.normalizeMagentoCart();\n if (magentoCart) {\n this.log('Detected Magento cart via localStorage');\n return magentoCart;\n }\n \n if (this.cartData) {\n this.log('Using manually set cart data');\n return this.cartData;\n }\n \n return null;\n }\n \n private normalizeShopifyCart(): CartData | null {\n try {\n if (typeof window === 'undefined') return null;\n \n const win = window as any;\n \n if (win.Shopify?.checkout) {\n const checkout = win.Shopify.checkout;\n return {\n cart_id: checkout.token || `shopify_${Date.now()}`,\n cart_total: parseFloat(checkout.total_price) || 0,\n cart_currency: checkout.currency || 'USD',\n cart_items: (checkout.line_items || []).map((item: any) => ({\n product_id: String(item.product_id || item.id),\n product_name: item.title || item.product_title,\n quantity: item.quantity || 1,\n price: parseFloat(item.price) || 0\n }))\n };\n }\n \n const cartJsonEl = document.getElementById('cart-json');\n if (cartJsonEl?.textContent) {\n const cart = JSON.parse(cartJsonEl.textContent);\n return {\n cart_id: cart.token || `shopify_${Date.now()}`,\n cart_total: (cart.total_price || 0) / 100,\n cart_currency: cart.currency || 'USD',\n cart_items: (cart.items || []).map((item: any) => ({\n product_id: String(item.product_id || item.id),\n product_name: item.product_title || item.title,\n quantity: item.quantity || 1,\n price: (item.price || 0) / 100\n }))\n };\n }\n \n return null;\n } catch (error) {\n this.log(`Error detecting Shopify cart: ${error}`, true);\n return null;\n }\n }\n \n private normalizeWooCart(): CartData | null {\n try {\n if (typeof window === 'undefined') return null;\n \n const win = window as any;\n \n if (win.aegis_cart) {\n const cart = win.aegis_cart;\n return {\n cart_id: cart.cart_id || `woo_${Date.now()}`,\n cart_total: parseFloat(cart.cart_total) || 0,\n cart_currency: cart.cart_currency || 'USD',\n cart_items: (cart.cart_items || []).map((item: any) => ({\n product_id: String(item.product_id),\n product_name: item.product_name,\n quantity: item.quantity || 1,\n price: parseFloat(item.price) || 0\n }))\n };\n }\n \n return null;\n } catch (error) {\n this.log(`Error detecting WooCommerce cart: ${error}`, true);\n return null;\n }\n }\n \n private normalizeMagentoCart(): CartData | null {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return null;\n \n const mageCacheStr = localStorage.getItem('mage-cache-storage');\n if (!mageCacheStr) return null;\n \n const mageCache = JSON.parse(mageCacheStr);\n if (!mageCache?.cart) return null;\n \n const cart = mageCache.cart;\n \n return {\n cart_id: cart.quote_id || cart.id || `magento_${Date.now()}`,\n cart_total: parseFloat(cart.subtotalAmount || cart.subtotal || 0),\n cart_currency: cart.currencyCode || 'USD',\n cart_items: (cart.items || []).map((item: any) => ({\n product_id: String(item.item_id || item.product_id),\n product_name: item.product_name || item.name,\n quantity: item.qty || 1,\n price: parseFloat(item.product_price_value || item.price || 0)\n }))\n };\n } catch (error) {\n this.log(`Error detecting Magento cart: ${error}`, true);\n return null;\n }\n }\n \n private preloadWidgetAssets(): void {\n try {\n const exitIntentConfig = this.prefetchWidgetConfigs.exit_intent;\n if (exitIntentConfig?.enabled) {\n const imageUrl = (exitIntentConfig as any).image_url;\n if (imageUrl) {\n const img = new Image();\n img.src = imageUrl;\n this.log(`Preloading exit intent image: ${imageUrl}`);\n }\n }\n \n const spinWheelConfig = this.prefetchWidgetConfigs.spin_wheel;\n if (spinWheelConfig?.enabled) {\n const imageUrl = (spinWheelConfig as any).image_url;\n if (imageUrl) {\n const img = new Image();\n img.src = imageUrl;\n this.log(`Preloading spin wheel image: ${imageUrl}`);\n }\n }\n } catch (error) {\n this.log(`Error preloading widget assets: ${error}`, true);\n }\n }\n \n private async fetchPrefetchConfigs(): Promise<void> {\n try {\n const startTime = performance.now();\n const url = `${this.apiHost}/v1/widgets/config/prefetch`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n };\n \n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, { headers, credentials: 'include' });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch prefetch configs: ${response.status}`);\n }\n \n this.prefetchWidgetConfigs = await response.json();\n \n const elapsed = performance.now() - startTime;\n this.log(`Fetched prefetch widget configs in ${elapsed.toFixed(2)}ms`);\n \n } catch (error) {\n this.log(`Error fetching prefetch configs: ${error}`, true);\n }\n }\n \n private async fetchWidgets(): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/widgets/config`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Device-Platform': 'web',\n 'X-Device-Type': this.getDeviceType()\n };\n\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.sourcePlatform) headers['X-Source-Platform'] = this.sourcePlatform;\n \n const response = await fetch(url, { headers, credentials: 'include' });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch widgets: ${response.status}`);\n }\n \n this.widgets = await response.json();\n \n this.log(`Fetched ${this.widgets.length} widgets`);\n \n } catch (error) {\n this.log(`Error fetching widgets: ${error}`, true);\n }\n }\n \n private renderImmediateWidgets(): void {\n const immediateWidgets = this.widgets.filter(w => \n !w.trigger_rules || w.trigger_rules.type === 'immediate'\n );\n \n immediateWidgets.forEach(widget => this.renderWidget(widget));\n }\n \n private setupTriggerListeners(): void {\n if (!this.triggerEngine) {\n this.log('TriggerEngine not provided, skipping trigger-based widgets');\n return;\n }\n \n this.widgets.forEach(widget => {\n if (!widget.trigger_rules) return;\n \n const { type, config } = widget.trigger_rules;\n \n switch (type) {\n case 'exit_intent':\n this.triggerEngine!.registerExitIntent();\n this.triggerEngine!.on('exit_intent', () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n \n case 'scroll_depth':\n const depthPercent = (config as any)?.depth_percent || 50;\n this.triggerEngine!.registerScrollDepth(depthPercent);\n this.triggerEngine!.on(`scroll_depth_${depthPercent}`, () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n \n case 'time_on_page':\n const seconds = (config as any)?.seconds || 30;\n this.triggerEngine!.registerTimeOnPage(seconds);\n this.triggerEngine!.on(`time_on_page_${seconds}`, () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n }\n });\n }\n \n private setupExitIntentWithPrefetch(): void {\n if (!this.enablePrefetch || !this.triggerEngine) {\n return;\n }\n \n const spinWheelConfig = this.prefetchWidgetConfigs.spin_wheel;\n const exitIntentConfig = this.prefetchWidgetConfigs.exit_intent;\n \n if (spinWheelConfig && spinWheelConfig.enabled) {\n const isMobile = this.isMobileDevice();\n const mobileConfig = exitIntentConfig?.mobile_triggers || {};\n \n const handleSpinWheelIntent = () => {\n const widgetId = `prefetch_spin_wheel_${Date.now()}`;\n \n if (this.renderedWidgets.has(widgetId)) {\n return;\n }\n \n this.renderedWidgets.add(widgetId);\n \n const detectedCart = this.detectPlatformCart();\n \n if (spinWheelConfig.type === 'cart_recovery' && detectedCart) {\n this.cartData = detectedCart;\n this.renderSpinWheelWidget(widgetId, spinWheelConfig);\n this.sendCartAbandonmentBeacon();\n } else if (spinWheelConfig.type === 'lead_gen') {\n this.renderSpinWheelWidget(widgetId, spinWheelConfig);\n }\n };\n \n if (isMobile) {\n const scrollVelocityEnabled = mobileConfig.scroll_velocity !== false;\n if (scrollVelocityEnabled) {\n this.triggerEngine.registerScrollVelocity({\n threshold: mobileConfig.scroll_threshold || 0.5,\n minScrollPosition: mobileConfig.scroll_min_position || 100,\n cooldown: mobileConfig.scroll_cooldown || 5000\n });\n this.triggerEngine.on('mobile_exit_intent', handleSpinWheelIntent);\n this.log('Registered mobile scroll velocity trigger for spin wheel');\n }\n \n const idleTimerEnabled = mobileConfig.idle_timer !== false;\n if (idleTimerEnabled) {\n const idleSeconds = mobileConfig.idle_seconds || 15;\n this.triggerEngine.registerInactivity(idleSeconds);\n this.triggerEngine.on(`inactivity_${idleSeconds}`, handleSpinWheelIntent);\n this.log(`Registered mobile idle timer trigger for spin wheel: ${idleSeconds}s`);\n }\n \n const visibilityChangeEnabled = mobileConfig.visibility_change !== false;\n if (visibilityChangeEnabled) {\n const detectedCart = this.detectPlatformCart();\n if (detectedCart && detectedCart.cart_items && detectedCart.cart_items.length > 0) {\n this.triggerEngine.registerVisibilityChange();\n this.triggerEngine.on('visibility_hidden', handleSpinWheelIntent);\n this.log('Registered mobile visibility change trigger for spin wheel (cart detected)');\n }\n }\n \n const backButtonEnabled = mobileConfig.back_button === true;\n if (backButtonEnabled) {\n this.triggerEngine.registerBackButton();\n this.triggerEngine.on('back_button', handleSpinWheelIntent);\n this.log('Registered mobile back button trigger for spin wheel');\n }\n \n this.log(`Setup mobile spin wheel: type=${spinWheelConfig.type}, priority=${spinWheelConfig.priority}`);\n } else {\n this.triggerEngine.registerExitIntent();\n this.triggerEngine.on('exit_intent', handleSpinWheelIntent);\n this.log(`Setup desktop spin wheel exit intent: type=${spinWheelConfig.type}, priority=${spinWheelConfig.priority}`);\n }\n \n return;\n }\n \n if (!exitIntentConfig || !exitIntentConfig.enabled) {\n this.log('No exit intent config found in prefetch');\n return;\n }\n \n const isMobile = this.isMobileDevice();\n const mobileConfig = exitIntentConfig.mobile_triggers || {};\n \n const handleExitIntent = () => {\n const widgetId = `prefetch_exit_intent_${Date.now()}`;\n \n if (this.renderedWidgets.has(widgetId)) {\n return;\n }\n \n this.renderedWidgets.add(widgetId);\n \n const detectedCart = this.detectPlatformCart();\n \n if (exitIntentConfig.type === 'cart_recovery' && detectedCart) {\n this.cartData = detectedCart;\n this.renderCartRecoveryPopup(widgetId, exitIntentConfig);\n this.sendCartAbandonmentBeacon();\n } else if (exitIntentConfig.type === 'lead_gen') {\n this.renderLeadGenPopup(widgetId, exitIntentConfig);\n } else {\n this.log('Unknown exit intent type or missing cart data');\n }\n };\n \n if (isMobile) {\n const scrollVelocityEnabled = mobileConfig.scroll_velocity !== false;\n if (scrollVelocityEnabled) {\n this.triggerEngine.registerScrollVelocity({\n threshold: mobileConfig.scroll_threshold || 0.5,\n minScrollPosition: mobileConfig.scroll_min_position || 100,\n cooldown: mobileConfig.scroll_cooldown || 5000\n });\n this.triggerEngine.on('mobile_exit_intent', handleExitIntent);\n this.log('Registered mobile scroll velocity trigger');\n }\n \n const idleTimerEnabled = mobileConfig.idle_timer !== false;\n if (idleTimerEnabled) {\n const idleSeconds = mobileConfig.idle_seconds || 15;\n this.triggerEngine.registerInactivity(idleSeconds);\n this.triggerEngine.on(`inactivity_${idleSeconds}`, handleExitIntent);\n this.log(`Registered mobile idle timer trigger: ${idleSeconds}s`);\n }\n \n const visibilityChangeEnabled = mobileConfig.visibility_change !== false;\n if (visibilityChangeEnabled) {\n const detectedCart = this.detectPlatformCart();\n if (detectedCart && detectedCart.cart_items && detectedCart.cart_items.length > 0) {\n this.triggerEngine.registerVisibilityChange();\n this.triggerEngine.on('visibility_hidden', handleExitIntent);\n this.log('Registered mobile visibility change trigger (cart detected)');\n } else {\n this.log('Skipped visibility change trigger (no cart items)');\n }\n }\n \n const backButtonEnabled = mobileConfig.back_button === true;\n if (backButtonEnabled) {\n this.triggerEngine.registerBackButton();\n this.triggerEngine.on('back_button', handleExitIntent);\n this.log('Registered mobile back button trigger (aggressive mode)');\n }\n \n this.log(`Setup mobile exit intent: type=${exitIntentConfig.type}, priority=${exitIntentConfig.priority}`);\n } else {\n this.triggerEngine.registerExitIntent();\n this.triggerEngine.on('exit_intent', handleExitIntent);\n this.log(`Setup desktop exit intent: type=${exitIntentConfig.type}, priority=${exitIntentConfig.priority}`);\n }\n }\n \n private sendCartAbandonmentBeacon(): void {\n if (!this.cartData) {\n this.log('No cart data available for beacon', true);\n return;\n }\n \n const beaconData = {\n organization_id: this.organizationId || 'default',\n contact_id: this.contactId,\n cart_id: this.cartData.cart_id,\n cart_total: this.cartData.cart_total,\n cart_currency: this.cartData.cart_currency,\n cart_items: this.cartData.cart_items,\n user_email: this.userId,\n abandoned_at: new Date().toISOString(),\n page_url: window.location.href,\n referrer: document.referrer\n };\n \n const beaconUrl = `${this.apiHost}/v1/widgets/beacon/cart-abandoned`;\n \n if (navigator.sendBeacon) {\n const blob = new Blob([JSON.stringify(beaconData)], { type: 'application/json' });\n const sent = navigator.sendBeacon(beaconUrl, blob);\n \n if (sent) {\n this.log('Cart abandonment beacon sent successfully');\n } else {\n this.log('Failed to send cart abandonment beacon', true);\n }\n } else {\n fetch(beaconUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey\n },\n body: JSON.stringify(beaconData),\n keepalive: true,\n credentials: 'include',\n }).catch(err => {\n this.log(`Error sending cart abandonment via fetch: ${err}`, true);\n });\n }\n }\n \n private renderWidget(widget: WidgetConfig): void {\n if (this.isDestroyed) return;\n if (this.renderedWidgets.has(widget.widget_id)) {\n return;\n }\n\n this.renderedWidgets.add(widget.widget_id);\n \n switch (widget.widget_type) {\n case 'chat_bubble':\n this.renderChatBubble(widget);\n break;\n case 'spin_wheel':\n this.renderSpinWheel(widget);\n break;\n case 'scratch_card':\n this.renderScratchCard(widget);\n break;\n case 'toast':\n this.renderToast(widget);\n break;\n case 'feedback_form':\n this.renderFeedbackForm(widget);\n break;\n case 'exit_intent_popup':\n this.renderExitIntentPopup(widget);\n break;\n default:\n this.log(`Unknown widget type: ${widget.widget_type}`, true);\n }\n \n this.trackEvent(widget.widget_id, 'show');\n }\n \n private renderChatBubble(widget: WidgetConfig): void {\n const { text, icon_url, link_url, background_color, text_color } = widget.config;\n const position = widget.position || 'bottom_right';\n \n const bubble = document.createElement('div');\n bubble.className = 'aegis-chat-bubble';\n bubble.setAttribute('data-widget-id', widget.widget_id);\n \n const positionStyles: Record<string, string> = {\n bottom_right: 'bottom: 20px; right: 20px;',\n bottom_left: 'bottom: 20px; left: 20px;',\n top_right: 'top: 20px; right: 20px;',\n top_left: 'top: 20px; left: 20px;'\n };\n \n bubble.style.cssText = `\n position: fixed;\n ${positionStyles[position] || positionStyles.bottom_right}\n background: ${this.sanitizeColor(background_color || '#25D366')};\n color: ${this.sanitizeColor(text_color || '#ffffff')};\n padding: 16px 24px;\n border-radius: 50px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n cursor: pointer;\n z-index: 999999;\n display: flex;\n align-items: center;\n gap: 12px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n font-weight: 600;\n font-size: 14px;\n animation: aegisBubbleIn 0.3s ease-out;\n `;\n \n if (icon_url) {\n const icon = document.createElement('img');\n const safeUrl = this.sanitizeUrl(icon_url);\n if (safeUrl) {\n icon.src = safeUrl;\n icon.alt = '';\n icon.style.cssText = 'width: 24px; height: 24px;';\n bubble.appendChild(icon);\n }\n }\n \n const textEl = document.createElement('span');\n textEl.textContent = text || 'Chat with us';\n bubble.appendChild(textEl);\n \n bubble.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'click');\n const safeUrl = this.sanitizeUrl(link_url);\n if (safeUrl) {\n window.open(safeUrl, '_blank');\n }\n });\n \n this.addAnimationStyles();\n bubble.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(bubble);\n }\n \n private renderSpinWheel(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-gamification-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-spin-wheel-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'Spin to Win!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Try your luck and win exclusive prizes!';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n modal.appendChild(description);\n \n // Draw an SVG wheel that honours the tenant's configured segments.\n // Each segment's `color` + `label` is painted as a pie slice; falls\n // back to a 4-color placeholder if no segments are provided.\n const segments: Array<{ label: string; color?: string }> = Array.isArray(\n (widget.config as any).segments,\n )\n ? (widget.config as any).segments\n : [\n { label: 'Prize 1', color: '#ff6b6b' },\n { label: 'Prize 2', color: '#feca57' },\n { label: 'Prize 3', color: '#48dbfb' },\n { label: 'Prize 4', color: '#ff6348' },\n ];\n\n const SVG_NS = 'http://www.w3.org/2000/svg';\n const wheel = document.createElementNS(SVG_NS, 'svg');\n wheel.setAttribute('viewBox', '-160 -160 320 320');\n wheel.setAttribute('width', '300');\n wheel.setAttribute('height', '300');\n wheel.style.cssText = 'margin: 0 auto 24px; display: block;';\n\n const n = segments.length;\n const anglePer = (2 * Math.PI) / n;\n const radius = 140;\n for (let i = 0; i < n; i++) {\n const start = i * anglePer - Math.PI / 2;\n const end = start + anglePer;\n const x1 = Math.cos(start) * radius;\n const y1 = Math.sin(start) * radius;\n const x2 = Math.cos(end) * radius;\n const y2 = Math.sin(end) * radius;\n const largeArc = anglePer > Math.PI ? 1 : 0;\n const path = document.createElementNS(SVG_NS, 'path');\n path.setAttribute(\n 'd',\n `M 0 0 L ${x1.toFixed(2)} ${y1.toFixed(2)} A ${radius} ${radius} 0 ${largeArc} 1 ${x2.toFixed(2)} ${y2.toFixed(2)} Z`,\n );\n path.setAttribute('fill', this.sanitizeColor(segments[i].color || '#cccccc'));\n path.setAttribute('stroke', '#ffffff');\n path.setAttribute('stroke-width', '2');\n wheel.appendChild(path);\n\n const labelAngle = start + anglePer / 2;\n const lx = Math.cos(labelAngle) * radius * 0.65;\n const ly = Math.sin(labelAngle) * radius * 0.65;\n const text = document.createElementNS(SVG_NS, 'text');\n text.setAttribute('x', lx.toFixed(2));\n text.setAttribute('y', ly.toFixed(2));\n text.setAttribute('fill', '#ffffff');\n text.setAttribute('font-size', '13');\n text.setAttribute('font-weight', '600');\n text.setAttribute('text-anchor', 'middle');\n text.setAttribute('dominant-baseline', 'middle');\n text.textContent = segments[i].label || `#${i + 1}`;\n wheel.appendChild(text);\n }\n modal.appendChild(wheel);\n \n const spinButton = document.createElement('button');\n spinButton.textContent = 'SPIN NOW!';\n spinButton.style.cssText = `\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n margin-bottom: 16px;\n `;\n \n spinButton.addEventListener('click', async () => {\n spinButton.disabled = true;\n spinButton.textContent = 'SPINNING...';\n \n try {\n const prize = await this.generatePrize(widget.config.config_id);\n\n wheel.style.animation = 'aegisSpin 2s ease-out';\n\n setTimeout(() => {\n this.showPrizeResult(modal, prize);\n }, 2000);\n \n } catch (error) {\n this.log(`Error generating prize: ${error}`, true);\n spinButton.disabled = false;\n spinButton.textContent = 'TRY AGAIN';\n }\n });\n \n modal.appendChild(spinButton);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderSpinWheelWidget(widgetId: string, config: NonNullable<PrefetchWidgetConfig['spin_wheel']>): void {\n if (this.isDestroyed) return;\n const cart = this.detectPlatformCart();\n \n if (config.type === 'cart_recovery' && !cart) {\n this.log('Spin wheel requires cart, but none detected');\n return;\n }\n \n if (cart) {\n this.cartData = cart;\n }\n \n const customization = this.cssCustomization.spinWheel || {};\n const accentColor = customization.accentColor || (config as any).accent_color || '#FF6B6B';\n const backgroundColor = customization.backgroundColor || (config as any).background_color || '#FFFFFF';\n const textColor = customization.textColor || (config as any).text_color || '#333333';\n const buttonColor = customization.buttonColor || (config as any).button_color || accentColor;\n const wheelColors = customization.wheelColors || ['#FF6B6B', '#4ECDC4', '#FFE66D', '#95E1D3'];\n \n const overlay = document.createElement('div');\n overlay.className = 'aegis-spin-wheel-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.7);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 999999;\n animation: aegisFadeIn 0.3s ease;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-spin-wheel-modal';\n modal.style.cssText = `\n background: ${this.sanitizeColor(backgroundColor)};\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n position: relative;\n animation: aegisScaleIn 0.4s ease;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n const closeBtn = document.createElement('button');\n closeBtn.innerHTML = '✕';\n closeBtn.className = 'aegis-spin-wheel-close';\n closeBtn.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #999;\n `;\n closeBtn.onclick = () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'spin_wheel' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n };\n modal.appendChild(closeBtn);\n \n const title = document.createElement('h2');\n title.textContent = this.interpolateCartVariables((config as any).title || 'Spin to Win!');\n title.style.cssText = `\n margin: 0 0 16px 0;\n font-size: 28px;\n font-weight: bold;\n text-align: center;\n color: ${this.sanitizeColor(textColor)};\n `;\n modal.appendChild(title);\n \n if (cart) {\n const subtitle = document.createElement('p');\n subtitle.textContent = `Complete your ${cart.cart_currency} ${cart.cart_total.toFixed(2)} order and save!`;\n subtitle.style.cssText = `\n margin: 0 0 24px 0;\n font-size: 16px;\n text-align: center;\n color: #666;\n `;\n modal.appendChild(subtitle);\n }\n \n const wheelContainer = document.createElement('div');\n wheelContainer.className = 'aegis-wheel-container';\n wheelContainer.style.cssText = `\n width: 300px;\n height: 300px;\n margin: 0 auto 24px auto;\n background: conic-gradient(\n from 0deg,\n ${wheelColors[0]} 0deg 90deg,\n ${wheelColors[1]} 90deg 180deg,\n ${wheelColors[2]} 180deg 270deg,\n ${wheelColors[3]} 270deg 360deg\n );\n border-radius: 50%;\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n \n const form = document.createElement('form');\n form.className = 'aegis-spin-form';\n form.style.cssText = 'display: block;';\n \n const phoneInput = document.createElement('input');\n phoneInput.type = 'tel';\n phoneInput.placeholder = 'Enter your phone number';\n phoneInput.required = true;\n phoneInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(phoneInput);\n \n const emailInput = document.createElement('input');\n emailInput.type = 'email';\n emailInput.placeholder = 'Enter your email (optional)';\n emailInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(emailInput);\n \n const nameInput = document.createElement('input');\n nameInput.type = 'text';\n nameInput.placeholder = 'Enter your name (optional)';\n nameInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(nameInput);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Spin the Wheel!';\n submitButton.style.cssText = `\n width: 100%;\n padding: 14px;\n background: ${this.sanitizeColor(buttonColor)};\n color: white;\n border: none;\n border-radius: 8px;\n font-size: 16px;\n font-weight: 700;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n const errorMessage = document.createElement('div');\n errorMessage.className = 'aegis-spin-error';\n errorMessage.style.cssText = `\n color: #d32f2f;\n font-size: 14px;\n margin-top: 12px;\n text-align: center;\n display: none;\n `;\n form.appendChild(errorMessage);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n const phone = phoneInput.value.trim();\n const email = emailInput.value.trim();\n const name = nameInput.value.trim();\n \n if (!this.validatePhone(phone)) {\n errorMessage.textContent = 'Please enter a valid phone number (e.g., +1234567890)';\n errorMessage.style.display = 'block';\n return;\n }\n \n if (email && !this.validateEmail(email)) {\n errorMessage.textContent = 'Please enter a valid email address';\n errorMessage.style.display = 'block';\n return;\n }\n \n errorMessage.style.display = 'none';\n submitButton.disabled = true;\n submitButton.textContent = 'Spinning...';\n \n wheelContainer.style.animation = 'aegisSpin 2s ease-out';\n \n setTimeout(async () => {\n try {\n const prize = await this.submitSpinWheel({\n phone,\n email,\n name,\n cart,\n widgetId\n });\n \n this.showSpinWheelPrize(modal, prize);\n this.trackEvent(widgetId, 'submit', {\n type: 'spin_wheel',\n prize_label: prize.prize_label,\n has_email: !!email\n });\n \n } catch (error) {\n this.log(`Error submitting spin wheel: ${error}`, true);\n errorMessage.textContent = 'Failed to submit. Please try again.';\n errorMessage.style.display = 'block';\n submitButton.disabled = false;\n submitButton.textContent = 'Spin the Wheel!';\n wheelContainer.style.animation = '';\n }\n }, 2000);\n });\n \n modal.appendChild(wheelContainer);\n modal.appendChild(form);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'spin_wheel' });\n }\n \n private validatePhone(phone: string): boolean {\n const e164Regex = /^\\+?[1-9]\\d{1,14}$/;\n return e164Regex.test(phone.replace(/[\\s()-]/g, ''));\n }\n \n private validateEmail(email: string): boolean {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n }\n \n private async submitSpinWheel(data: {\n phone: string;\n email: string;\n name: string;\n cart: CartData | null;\n widgetId: string;\n }): Promise<GamificationPrize> {\n const url = `${this.apiHost}/v1/widgets/spin-wheel/submit`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const geoRegion = this.detectGeoRegion();\n const deviceType = this.getDeviceType();\n const utmParams = this.getUTMParams();\n \n const body: any = {\n phone: data.phone.replace(/[\\s()-]/g, ''),\n email: data.email || undefined,\n name: data.name || undefined,\n cart_id: data.cart?.cart_id || `web_${Date.now()}`,\n cart_token: data.cart?.cart_id,\n cart_total: data.cart?.cart_total || 0,\n cart_currency: data.cart?.cart_currency || 'USD',\n cart_items: data.cart?.cart_items || [],\n cart_url: window.location.href,\n platform: 'web',\n geo_region: geoRegion,\n device_type: deviceType,\n session_id: this.getSessionId() || undefined,\n anonymous_id: this.getAnonymousId() || undefined,\n utm_source: utmParams.utm_source,\n utm_medium: utmParams.utm_medium,\n utm_campaign: utmParams.utm_campaign\n };\n \n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n credentials: 'include',\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to submit spin wheel: ${response.status} - ${errorText}`);\n }\n \n return await response.json();\n }\n \n private showSpinWheelPrize(modal: HTMLElement, prize: GamificationPrize): void {\n modal.innerHTML = '';\n \n const resultContainer = document.createElement('div');\n resultContainer.style.cssText = 'text-align: center; padding: 40px 20px;';\n \n const emoji = document.createElement('div');\n emoji.textContent = '🎉';\n emoji.style.cssText = 'font-size: 60px; margin-bottom: 20px;';\n resultContainer.appendChild(emoji);\n \n const title = document.createElement('h2');\n title.textContent = 'Congratulations!';\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 28px; font-weight: 700; color: #1a73e8;';\n resultContainer.appendChild(title);\n \n const prizeLabel = document.createElement('p');\n prizeLabel.textContent = prize.prize_label;\n prizeLabel.style.cssText = 'margin: 0 0 20px 0; font-size: 20px; font-weight: 600; color: #333;';\n resultContainer.appendChild(prizeLabel);\n \n if (prize.coupon_code) {\n const couponContainer = document.createElement('div');\n couponContainer.style.cssText = `\n background: #f5f5f5;\n padding: 16px;\n border-radius: 8px;\n margin-bottom: 20px;\n border: 2px dashed #1a73e8;\n `;\n \n const couponLabel = document.createElement('div');\n couponLabel.textContent = 'Your coupon code:';\n couponLabel.style.cssText = 'font-size: 12px; color: #666; margin-bottom: 8px;';\n couponContainer.appendChild(couponLabel);\n \n const couponCode = document.createElement('div');\n couponCode.textContent = prize.coupon_code;\n couponCode.style.cssText = 'font-size: 24px; font-weight: 700; color: #1a73e8; letter-spacing: 2px;';\n couponContainer.appendChild(couponCode);\n \n resultContainer.appendChild(couponContainer);\n }\n \n const message = document.createElement('p');\n message.textContent = 'Check your WhatsApp/SMS for your discount code and cart link!';\n message.style.cssText = 'margin: 0 0 20px 0; font-size: 14px; color: #666;';\n resultContainer.appendChild(message);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n \n closeButton.addEventListener('click', () => {\n const overlay = modal.parentElement;\n if (overlay && document.body.contains(overlay)) {\n document.body.removeChild(overlay);\n }\n });\n \n resultContainer.appendChild(closeButton);\n modal.appendChild(resultContainer);\n }\n \n private detectGeoRegion(): string {\n const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n \n if (timezone.includes('America')) return 'north_america';\n if (timezone.includes('Europe')) return 'europe';\n if (timezone.includes('Asia/Kolkata') || timezone.includes('Asia/Calcutta')) return 'india';\n if (timezone.includes('Asia/Singapore') || timezone.includes('Asia/Bangkok') || timezone.includes('Asia/Jakarta')) return 'southeast_asia';\n if (timezone.includes('Asia/Dubai') || timezone.includes('Asia/Riyadh')) return 'middle_east';\n if (timezone.includes('America') && (timezone.includes('Sao_Paulo') || timezone.includes('Buenos_Aires'))) return 'latin_america';\n if (timezone.includes('Australia') || timezone.includes('Pacific/Auckland')) return 'oceania';\n \n return 'north_america';\n }\n \n private getUTMParams(): { utm_source?: string; utm_medium?: string; utm_campaign?: string } {\n const params = new URLSearchParams(window.location.search);\n return {\n utm_source: params.get('utm_source') || undefined,\n utm_medium: params.get('utm_medium') || undefined,\n utm_campaign: params.get('utm_campaign') || undefined\n };\n }\n \n private getSessionId(): string | null {\n return sessionStorage.getItem('aegis_session_id');\n }\n \n private getAnonymousId(): string | null {\n return localStorage.getItem('aegis_anonymous_id');\n }\n \n private renderScratchCard(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-gamification-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-scratch-card-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'Scratch & Win!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Scratch to reveal your prize!';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n modal.appendChild(description);\n \n const canvas = document.createElement('canvas');\n canvas.width = 300;\n canvas.height = 200;\n canvas.style.cssText = `\n border-radius: 8px;\n cursor: pointer;\n margin: 0 auto 24px;\n display: block;\n box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n `;\n modal.appendChild(canvas);\n \n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.fillStyle = '#c0c0c0';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.fillStyle = '#888';\n ctx.font = '20px Arial';\n ctx.textAlign = 'center';\n ctx.fillText('Scratch here!', canvas.width / 2, canvas.height / 2);\n \n let isScratching = false;\n \n const scratch = (x: number, y: number) => {\n ctx.globalCompositeOperation = 'destination-out';\n ctx.beginPath();\n ctx.arc(x, y, 20, 0, Math.PI * 2);\n ctx.fill();\n };\n \n canvas.addEventListener('mousedown', () => { isScratching = true; });\n canvas.addEventListener('mouseup', () => { isScratching = false; });\n canvas.addEventListener('mousemove', (e) => {\n if (isScratching) {\n const rect = canvas.getBoundingClientRect();\n scratch(e.clientX - rect.left, e.clientY - rect.top);\n }\n });\n }\n \n const scratchButton = document.createElement('button');\n scratchButton.textContent = 'REVEAL PRIZE';\n scratchButton.style.cssText = `\n background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n color: white;\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n `;\n \n scratchButton.addEventListener('click', async () => {\n scratchButton.disabled = true;\n scratchButton.textContent = 'REVEALING...';\n \n try {\n const prize = await this.generatePrize(widget.config.config_id);\n this.showPrizeResult(modal, prize);\n } catch (error) {\n this.log(`Error generating prize: ${error}`, true);\n scratchButton.disabled = false;\n scratchButton.textContent = 'TRY AGAIN';\n }\n });\n \n modal.appendChild(scratchButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderToast(widget: WidgetConfig): void {\n const { message, icon, duration } = widget.config;\n const position = widget.position || 'bottom_left';\n \n const toast = document.createElement('div');\n toast.className = 'aegis-toast';\n toast.setAttribute('data-widget-id', widget.widget_id);\n \n const positionStyles: Record<string, string> = {\n bottom_left: 'bottom: 20px; left: 20px;',\n bottom_right: 'bottom: 20px; right: 20px;',\n top_left: 'top: 20px; left: 20px;',\n top_right: 'top: 20px; right: 20px;'\n };\n \n toast.style.cssText = `\n position: fixed;\n ${positionStyles[position] || positionStyles.bottom_left}\n background: white;\n padding: 16px 20px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n z-index: 999998;\n display: flex;\n align-items: center;\n gap: 12px;\n max-width: 350px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisToastIn 0.3s ease-out;\n `;\n \n if (icon) {\n const iconEl = document.createElement('div');\n iconEl.textContent = icon;\n iconEl.style.cssText = 'font-size: 20px;';\n toast.appendChild(iconEl);\n }\n \n const messageEl = document.createElement('div');\n messageEl.textContent = message || 'Someone just made a purchase!';\n messageEl.style.cssText = 'flex: 1; font-size: 13px; color: #333;';\n toast.appendChild(messageEl);\n \n this.addAnimationStyles();\n toast.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(toast);\n \n setTimeout(() => {\n toast.style.animation = 'aegisToastOut 0.3s ease-out';\n setTimeout(() => {\n if (document.body.contains(toast)) {\n document.body.removeChild(toast);\n }\n this.renderedWidgets.delete(widget.widget_id);\n }, 300);\n }, duration || 5000);\n }\n \n private renderFeedbackForm(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-feedback-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 400px;\n background: white;\n box-shadow: -4px 0 20px rgba(0,0,0,0.15);\n z-index: 1000000;\n padding: 32px;\n overflow-y: auto;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInRight 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'We value your feedback!';\n title.style.cssText = 'margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #1a1a1a;';\n overlay.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Help us improve your experience.';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n overlay.appendChild(description);\n \n const form = document.createElement('form');\n \n const label = document.createElement('label');\n label.textContent = 'How likely are you to recommend us? (0-10)';\n label.style.cssText = 'display: block; font-size: 14px; font-weight: 600; margin-bottom: 8px; color: #333;';\n form.appendChild(label);\n \n const input = document.createElement('input');\n input.type = 'number';\n input.min = '0';\n input.max = '10';\n input.style.cssText = `\n width: 100%;\n padding: 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-size: 14px;\n margin-bottom: 16px;\n `;\n form.appendChild(input);\n \n const textareaLabel = document.createElement('label');\n textareaLabel.textContent = 'Tell us more (optional)';\n textareaLabel.style.cssText = 'display: block; font-size: 14px; font-weight: 600; margin-bottom: 8px; color: #333;';\n form.appendChild(textareaLabel);\n \n const textarea = document.createElement('textarea');\n textarea.rows = 4;\n textarea.style.cssText = `\n width: 100%;\n padding: 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-size: 14px;\n resize: vertical;\n margin-bottom: 16px;\n font-family: inherit;\n `;\n form.appendChild(textarea);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Submit Feedback';\n submitButton.style.cssText = `\n width: 100%;\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px;\n border-radius: 6px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n submitButton.disabled = true;\n submitButton.textContent = 'Submitting...';\n \n try {\n await this.submitFeedback(widget.widget_id, {\n score: parseInt(input.value),\n comment: textarea.value\n });\n \n overlay.innerHTML = '<div style=\"text-align: center; padding: 60px 20px;\"><h3 style=\"margin: 0 0 12px 0; color: #1a73e8;\">Thank you!</h3><p style=\"margin: 0; color: #666;\">Your feedback helps us improve.</p></div>';\n \n setTimeout(() => {\n document.body.removeChild(overlay);\n }, 2000);\n \n } catch (error) {\n this.log(`Error submitting feedback: ${error}`, true);\n submitButton.disabled = false;\n submitButton.textContent = 'Submit Feedback';\n }\n });\n \n overlay.appendChild(form);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n overlay.appendChild(closeButton);\n \n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderExitIntentPopup(widget: WidgetConfig): void {\n const { title, description, cta_text, cta_url, image_url } = widget.config;\n \n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-exit-popup-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n max-width: 600px;\n width: 90%;\n overflow: hidden;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n if (image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 250px; object-fit: cover;';\n modal.appendChild(img);\n }\n }\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 32px;';\n \n const titleEl = document.createElement('h2');\n titleEl.textContent = title || 'Wait! Don\\'t leave yet!';\n titleEl.style.cssText = 'margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: #1a1a1a;';\n content.appendChild(titleEl);\n \n const descEl = document.createElement('p');\n descEl.textContent = description || 'Get 10% off your first order!';\n descEl.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; color: #666; line-height: 1.5;';\n content.appendChild(descEl);\n \n if (cta_text && cta_url) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = cta_text;\n ctaButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'click');\n const safeUrl = this.sanitizeUrl(cta_url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n \n content.appendChild(ctaButton);\n }\n \n modal.appendChild(content);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: white;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #666;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private async generatePrize(configId: string): Promise<GamificationPrize> {\n const url = `${this.apiHost}/v1/widgets/gamification/generate-prize`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({ config_id: configId }),\n credentials: 'include',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to generate prize: ${response.status}`);\n }\n \n return await response.json();\n }\n \n private showPrizeResult(modal: HTMLElement, prize: GamificationPrize): void {\n modal.innerHTML = '';\n \n const resultContainer = document.createElement('div');\n resultContainer.style.cssText = 'text-align: center; padding: 40px 20px;';\n \n const emoji = document.createElement('div');\n emoji.textContent = '🎉';\n emoji.style.cssText = 'font-size: 60px; margin-bottom: 20px;';\n resultContainer.appendChild(emoji);\n \n const title = document.createElement('h2');\n title.textContent = 'Congratulations!';\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 28px; font-weight: 700; color: #1a73e8;';\n resultContainer.appendChild(title);\n \n const prizeLabel = document.createElement('p');\n prizeLabel.textContent = prize.prize_label;\n prizeLabel.style.cssText = 'margin: 0 0 20px 0; font-size: 20px; font-weight: 600; color: #333;';\n resultContainer.appendChild(prizeLabel);\n \n if (prize.coupon_code) {\n const couponContainer = document.createElement('div');\n couponContainer.style.cssText = `\n background: #f5f5f5;\n padding: 16px;\n border-radius: 8px;\n margin-bottom: 20px;\n border: 2px dashed #1a73e8;\n `;\n \n const couponLabel = document.createElement('div');\n couponLabel.textContent = 'Your coupon code:';\n couponLabel.style.cssText = 'font-size: 12px; color: #666; margin-bottom: 8px;';\n couponContainer.appendChild(couponLabel);\n \n const couponCode = document.createElement('div');\n couponCode.textContent = prize.coupon_code;\n couponCode.style.cssText = 'font-size: 24px; font-weight: 700; color: #1a73e8; letter-spacing: 2px;';\n couponContainer.appendChild(couponCode);\n \n resultContainer.appendChild(couponContainer);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n \n closeButton.addEventListener('click', () => {\n const overlay = modal.parentElement;\n if (overlay && document.body.contains(overlay)) {\n document.body.removeChild(overlay);\n }\n });\n \n resultContainer.appendChild(closeButton);\n modal.appendChild(resultContainer);\n }\n \n private async submitFeedback(widgetId: string, data: Record<string, any>): Promise<void> {\n const url = `${this.apiHost}/v1/widgets/track-event`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n // Plumb workspace cascade so feedback submissions are attributed to\n // the same outlet the customer was viewing. See\n // PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n const workspaceId = this.getWorkspaceId?.();\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n widget_id: widgetId,\n event_type: 'submit',\n event_data: data,\n workspace_id: workspaceId,\n }),\n credentials: 'include',\n });\n \n if (!response.ok) {\n throw new Error(`Failed to submit feedback: ${response.status}`);\n }\n }\n \n private async trackEvent(widgetId: string, eventType: string, metadata?: Record<string, any>): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/widgets/track-event`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n\n const workspaceId = this.getWorkspaceId?.();\n\n await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n widget_id: widgetId,\n event_type: eventType,\n event_data: metadata || {},\n workspace_id: workspaceId,\n }),\n credentials: 'include',\n });\n\n } catch (error) {\n this.log(`Error tracking widget event: ${error}`, true);\n }\n }\n \n private sanitizeUrl(url?: string): string | null {\n if (!url) return null;\n \n try {\n const parsed = new URL(url, window.location.href);\n if (parsed.protocol === 'javascript:' || parsed.protocol === 'data:') {\n this.log(`Blocked dangerous URL: ${url}`, true);\n return null;\n }\n return parsed.href;\n } catch {\n this.log(`Invalid URL: ${url}`, true);\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n if (/^#[0-9A-F]{3,8}$/i.test(color)) {\n return color;\n }\n \n if (/^rgb\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*\\)$/i.test(color)) {\n return color;\n }\n \n if (/^rgba\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*[\\d.]+\\s*\\)$/i.test(color)) {\n return color;\n }\n \n return '#1a73e8';\n }\n \n private getDeviceType(): string {\n const ua = navigator.userAgent;\n if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {\n return 'tablet';\n }\n if (/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(ua)) {\n return 'mobile';\n }\n return 'desktop';\n }\n \n private isMobileDevice(): boolean {\n const deviceType = this.getDeviceType();\n return deviceType === 'mobile' || deviceType === 'tablet';\n }\n \n private addAnimationStyles(): void {\n if (document.getElementById('aegis-widget-animations')) {\n return;\n }\n \n const style = document.createElement('style');\n style.id = 'aegis-widget-animations';\n style.textContent = `\n @keyframes aegisFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n \n @keyframes aegisScaleIn {\n from { transform: scale(0.8); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n }\n \n @keyframes aegisBubbleIn {\n from { transform: translateY(20px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes aegisToastIn {\n from { transform: translateX(-100%); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n }\n \n @keyframes aegisToastOut {\n from { transform: translateX(0); opacity: 1; }\n to { transform: translateX(-100%); opacity: 0; }\n }\n \n @keyframes aegisSlideInRight {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n }\n \n @keyframes aegisSpin {\n from { transform: rotate(0deg); }\n to { transform: rotate(1440deg); }\n }\n `;\n document.head.appendChild(style);\n }\n \n private renderCartRecoveryPopup(widgetId: string, config: NonNullable<PrefetchWidgetConfig['exit_intent']>): void {\n if (this.isDestroyed) return;\n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n overlay.setAttribute('data-aegis-widget-root', '');\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-cart-recovery-modal';\n modal.style.cssText = `\n background: ${this.sanitizeColor(config.background_color || '#FFFFFF')};\n color: ${this.sanitizeColor(config.text_color || '#333333')};\n border-radius: 16px;\n max-width: 600px;\n width: 90%;\n padding: 40px;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n position: relative;\n `;\n \n const title = document.createElement('h2');\n const titleText = this.interpolateCartVariables(config.title || 'Complete Your Order');\n title.textContent = titleText;\n title.style.cssText = `margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: ${this.sanitizeColor(config.accent_color || '#FF6B00')};`;\n modal.appendChild(title);\n \n const message = document.createElement('p');\n const messageText = this.interpolateCartVariables(config.message || 'Your cart is waiting for you!');\n message.textContent = messageText;\n message.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; line-height: 1.5;';\n modal.appendChild(message);\n \n if (config.show_cart_items && this.cartData) {\n const cartItems = document.createElement('div');\n cartItems.style.cssText = 'margin: 0 0 24px 0; padding: 16px; background: rgba(0,0,0,0.05); border-radius: 8px;';\n \n const cartTitle = document.createElement('div');\n cartTitle.textContent = `${this.cartData.cart_items.length} items in your cart`;\n cartTitle.style.cssText = 'font-weight: 600; margin-bottom: 12px;';\n cartItems.appendChild(cartTitle);\n \n this.cartData.cart_items.slice(0, 3).forEach(item => {\n const itemDiv = document.createElement('div');\n itemDiv.textContent = `${item.quantity}× ${item.product_name || item.product_id}`;\n itemDiv.style.cssText = 'font-size: 14px; margin-bottom: 4px;';\n cartItems.appendChild(itemDiv);\n });\n \n modal.appendChild(cartItems);\n }\n \n if (config.discount_code) {\n const discountBox = document.createElement('div');\n discountBox.style.cssText = `\n margin: 0 0 24px 0;\n padding: 16px;\n background: ${this.sanitizeColor(config.accent_color || '#FF6B00')};\n color: white;\n border-radius: 8px;\n text-align: center;\n font-weight: 700;\n font-size: 18px;\n `;\n discountBox.textContent = `Use code: ${config.discount_code} for ${config.discount_percentage || 10}% off!`;\n modal.appendChild(discountBox);\n }\n \n if (config.show_timer && config.timer_minutes) {\n const timer = document.createElement('div');\n timer.style.cssText = 'margin: 0 0 24px 0; text-align: center; font-size: 14px; color: #999;';\n timer.textContent = `⏰ Offer expires in ${config.timer_minutes} minutes`;\n modal.appendChild(timer);\n }\n \n const ctaButton = document.createElement('button');\n ctaButton.textContent = config.cta_text || 'Complete Checkout';\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(config.accent_color || '#FF6B00')};\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'click', { type: 'cart_recovery' });\n const checkoutUrl = this.sanitizeUrl(config.cta_url || '/checkout');\n if (checkoutUrl) {\n window.location.href = checkoutUrl;\n }\n });\n \n modal.appendChild(ctaButton);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'cart_recovery' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n });\n \n modal.appendChild(closeButton);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'cart_recovery', tier: config.tier });\n }\n \n private renderLeadGenPopup(widgetId: string, config: NonNullable<PrefetchWidgetConfig['exit_intent']>): void {\n if (this.isDestroyed) return;\n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n overlay.setAttribute('data-aegis-widget-root', '');\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-leadgen-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n max-width: 500px;\n width: 90%;\n padding: 40px;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n position: relative;\n `;\n \n const title = document.createElement('h2');\n title.textContent = config.title || 'Get 10% Off Your First Order!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const message = document.createElement('p');\n message.textContent = config.message || 'Subscribe to our newsletter and get an exclusive discount code.';\n message.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; color: #666;';\n modal.appendChild(message);\n \n const form = document.createElement('form');\n \n const emailInput = document.createElement('input');\n emailInput.type = 'email';\n emailInput.placeholder = 'Enter your email';\n emailInput.required = true;\n emailInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 16px;\n box-sizing: border-box;\n `;\n form.appendChild(emailInput);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Get My Discount';\n submitButton.style.cssText = `\n width: 100%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n submitButton.disabled = true;\n submitButton.textContent = 'Submitting...';\n \n try {\n await this.trackEvent(widgetId, 'submit', { \n type: 'lead_gen',\n email: emailInput.value \n });\n \n modal.innerHTML = `\n <div style=\"text-align: center; padding: 20px;\">\n <div style=\"font-size: 48px; margin-bottom: 16px;\">✅</div>\n <h3 style=\"margin: 0 0 12px 0; color: #1a73e8;\">Thank You!</h3>\n <p style=\"margin: 0; color: #666;\">Check your email for your discount code!</p>\n </div>\n `;\n \n setTimeout(() => {\n document.body.removeChild(overlay);\n }, 2500);\n \n } catch (error) {\n this.log(`Error submitting lead gen form: ${error}`, true);\n submitButton.disabled = false;\n submitButton.textContent = 'Get My Discount';\n }\n });\n \n modal.appendChild(form);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'lead_gen' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n });\n \n modal.appendChild(closeButton);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'lead_gen' });\n }\n \n private interpolateCartVariables(template: string): string {\n if (!this.cartData) return template;\n \n return template\n .replace(/\\{\\{cart_total\\}\\}/g, `${this.cartData.cart_currency} ${this.cartData.cart_total.toFixed(2)}`)\n .replace(/\\{\\{cart_currency\\}\\}/g, this.cartData.cart_currency)\n .replace(/\\{\\{cart_items_count\\}\\}/g, this.cartData.cart_items.length.toString());\n }\n \n private log(message: string, isError: boolean = false): void {\n if (this.debugMode || isError) {\n const method = isError ? 'error' : 'log';\n console[method](`[AegisWidgets] ${message}`);\n }\n }\n}\n","/**\n * AegisMessageRuntime — unified facade for in-app messaging.\n *\n * The sole public entry point for all 20 in-app types (announce +\n * collect + assist buckets) plus the legacy gamification surface\n * (chat_bubble / toast / exit_intent_popup configured via\n * /v1/widgets/config). Under the hood it composes an\n * `AegisInAppManager` + `AegisWidgetManager`; callers never touch them\n * directly.\n *\n * Public API:\n * new AegisMessageRuntime({ writeKey, apiHost, ... })\n * await runtime.initialize()\n * await runtime.updateContactId(id)\n * runtime.onClientEvent(eventName, data)\n * runtime.destroy()\n *\n * Internal wiring: spin_wheel + scratch_card campaigns land in the\n * inbox prefetch bundle but need DOM renderers that live in\n * WidgetManager. The facade passes an `onInteractiveCampaign` callback\n * into the InAppManager constructor; the callback forwards to\n * `widgets.renderInteractiveCampaign(campaign)` — no CustomEvent bus,\n * no listeners, no registration-order bugs.\n */\n\nimport { AegisInAppManager, type AegisInAppConfig, type InAppCampaign } from '../inapp';\nimport { AegisWidgetManager, type AegisWidgetConfig } from '../widgets';\nimport { TriggerEngine } from '../triggers/TriggerEngine';\nimport { IntentRuleEvaluator } from '../triggers/IntentRuleEvaluator';\nimport { ContactScoresFetcher } from '../triggers/ContactScoresFetcher';\n\nexport interface AegisMessageRuntimeConfig extends AegisInAppConfig {\n /** If set, a `TriggerEngine` from the SDK is wired to the WidgetManager\n * for its exit-intent / scroll-velocity / inactivity handlers. Leave\n * undefined to have the runtime construct one internally. */\n triggerEngine?: AegisWidgetConfig['triggerEngine'];\n /** WidgetManager prefetch toggle. Defaults to true — matches the\n * existing behaviour where spin_wheel / scratch_card prefetch their\n * configs from `/v1/widgets/config/prefetch`. */\n enableWidgetPrefetch?: boolean;\n /** Source platform for gamification attribution (shopify / woocommerce\n * / magento / mobile_sdk / web). Passed through to WidgetManager. */\n sourcePlatform?: AegisWidgetConfig['sourcePlatform'];\n}\n\n/**\n * One runtime, all in-app types. Consumers should prefer this over\n * importing AegisInAppManager / AegisWidgetManager directly. Those two\n * classes remain exported for a deprecation window — see `./deprecated.ts`.\n */\nexport class AegisMessageRuntime {\n readonly inApp: AegisInAppManager;\n readonly widgets: AegisWidgetManager;\n /** Shared IntentRuleEvaluator for identified-contact micro-intent\n * patterns. The ContactScoresFetcher writes Layer-1 signals into its\n * snapshot; IntentSnapshotCollector (if wired by the consumer) writes\n * Layer-2 signals. Exposed so apps that pre-existed P4a can swap in\n * their own evaluator if they need to. */\n readonly intentRuleEvaluator: IntentRuleEvaluator;\n /** Bridges GET /v1/sdk/contact-scores into the evaluator snapshot.\n * Triggered automatically on initialize() and updateContactId(). */\n readonly contactScores: ContactScoresFetcher;\n private contactId?: string;\n private initialized = false;\n\n constructor(config: AegisMessageRuntimeConfig) {\n const triggerEngine = config.triggerEngine ?? new TriggerEngine();\n const ownsTriggerEngine = !config.triggerEngine;\n this.contactId = config.contactId;\n // Ownership of the engine is tracked downstream by WidgetManager\n // (which is the only consumer that needs to call lifecycle methods\n // on it). The facade itself only forwards.\n\n this.widgets = new AegisWidgetManager({\n writeKey: config.writeKey,\n apiHost: config.apiHost,\n userId: config.userId,\n contactId: config.contactId,\n organizationId: config.organizationId,\n debugMode: config.debugMode,\n triggerEngine,\n ownsTriggerEngine,\n enablePrefetch: config.enableWidgetPrefetch !== false,\n sourcePlatform: config.sourcePlatform,\n getWorkspaceId: config.getWorkspaceId,\n });\n\n this.inApp = new AegisInAppManager({\n writeKey: config.writeKey,\n apiHost: config.apiHost,\n userId: config.userId,\n contactId: config.contactId,\n organizationId: config.organizationId,\n propertyId: config.propertyId,\n debugMode: config.debugMode,\n enableSSE: config.enableSSE,\n // Route gamification sub_types straight to the widget renderer —\n // replaces the old CustomEvent('aegis:render-widget') bridge which\n // had no listener and silently dropped impressions.\n onInteractiveCampaign: (campaign) => {\n this.widgets.renderInteractiveCampaign(campaign);\n },\n getWorkspaceId: config.getWorkspaceId,\n });\n\n this.intentRuleEvaluator = new IntentRuleEvaluator();\n this.contactScores = new ContactScoresFetcher({\n // Falls back to same-origin when no apiHost configured (storefront\n // typical case) — matches WidgetManager/InAppManager handling\n // where `config.apiHost` is also `string | undefined`.\n apiHost: config.apiHost ?? '',\n writeKey: config.writeKey,\n organizationId: config.organizationId,\n evaluator: this.intentRuleEvaluator,\n });\n }\n\n /**\n * Boots both managers in parallel. Safe to call multiple times — the\n * second + subsequent calls are no-ops.\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n this.initialized = true;\n await Promise.all([\n this.inApp.initialize(),\n this.widgets.initialize(),\n ]);\n // Fire-and-forget the Layer-1 score fetch when we already know the\n // contact at init. Identified-contact micro-intent patterns need\n // this snapshot — without it their AND-compound rules eval to\n // false. Anonymous patterns are unaffected.\n if (this.contactId) {\n void this.contactScores.fetchForContact(this.contactId);\n }\n }\n\n /**\n * Both managers carry contactId. Updates both so the server-side\n * targeting pipeline sees the identity for campaign eligibility AND\n * the widget prefetch includes per-contact segment configs. The\n * widgets call is async (may re-fetch prefetch configs) but we don't\n * wait — callers that care about the fetched state await on the\n * returned promise.\n */\n async updateContactId(contactId: string): Promise<void> {\n this.contactId = contactId;\n this.inApp.updateContactId?.(contactId);\n await this.widgets.updateContactId(contactId);\n // Re-fetch Layer-1 scores for the new identity. Session-dedup in\n // the fetcher means a repeat call with the same contactId is a\n // no-op, so SPA navigation that re-calls identify() is cheap.\n void this.contactScores.fetchForContact(contactId);\n }\n\n /**\n * Forward a client-side event (product_viewed, cart_idle_90s, etc.)\n * to the in-app manager's client-trigger evaluator. The WidgetManager\n * has its own TriggerEngine wiring (exit-intent, scroll-velocity) so\n * we don't forward there — events it cares about arrive through that\n * channel already.\n */\n onClientEvent(eventName: string, eventData: Record<string, unknown> = {}): void {\n this.inApp.onClientEvent?.(eventName, eventData);\n }\n\n // --- Qualifying-event refresh facade (DLR Tracker 1 / P1, 2026-05-28) ---\n //\n // `track`, `page`, and `screen` here are thin trigger taps for the\n // in-app subsystem — they tell `AegisInAppManager.refreshOnEvent` that\n // a host-app event happened, and the debounced refresh re-fetches\n // `/v1/in-app/active` so newly armed campaigns become visible without\n // waiting for the next identity flip. They are NOT a substitute for\n // the main analytics SDK (`Aegis` in `core/analytics.ts`) — those\n // methods own the canonical capture path (batch uplink, governance,\n // workspace resolution, etc.). Integrations that already call\n // `aegis.track(...)` should also call `runtime.track(...)` to drive\n // the in-app refresh. A future P-phase will bridge the two so a single\n // call on the public analytics surface drives both behaviors.\n\n /**\n * Notify the in-app subsystem that a tracked event occurred. Schedules\n * a debounced refresh of armed campaigns so newly eligible in-app\n * messages (e.g., trigger-gated on `cart_item_added`) become visible\n * within ~300ms — bursts coalesce. See\n * `AegisInAppManager.refreshOnEvent` for debounce semantics and why\n * this matters under storefront polling.\n */\n track(eventName: string): void {\n if (!eventName) return;\n this.inApp.refreshOnEvent(eventName);\n }\n\n /**\n * Notify the in-app subsystem that a URL-bound page view occurred.\n * Mirrors `aegis.page()` semantics — fires `'page_view'` as the\n * qualifying event so the trailing debounce covers SPA route bursts\n * (history.pushState rapid-fire) without spamming the endpoint.\n */\n page(name?: string): void {\n this.inApp.refreshOnEvent(name ?? 'page_view');\n }\n\n /**\n * Notify the in-app subsystem that a SPA-logical screen view occurred\n * (cart drawer open, checkout step transition — anywhere `aegis.screen()`\n * is called). Refresh-on-screen lets per-screen-targeted campaigns\n * arm without a URL change.\n */\n screen(name: string): void {\n if (!name) return;\n this.inApp.refreshOnEvent(name);\n }\n\n /**\n * Conversion-aware suppression — call when the host app observes a\n * goal event (purchase / order_completed / checkout_completed / custom).\n *\n * Forwards to AegisInAppManager.notifyConversion() which:\n * - Persists the conversion in sessionStorage so subsequent page loads\n * in the same tab keep armed campaigns silenced.\n * - For every armed campaign whose\n * `frequency.suppress_after_conversion_seconds` is set, computes an\n * expiry epoch_ms and silences it until then.\n *\n * Storefronts integrate via the React provider's useCommerceEvents\n * helper which calls this after `ecom.orderCompleted(...)`. Direct SDK\n * users call it themselves.\n *\n * Added by Micro-Intent Engine P0a Task 6 (2026-04-30).\n */\n notifyConversion(goalName: string): void {\n this.inApp.notifyConversion?.(goalName);\n }\n\n /**\n * Tear down both managers. Used by React component unmounts + during\n * identity switches where we want a full reset. If the facade created\n * its own TriggerEngine, WidgetManager.destroy() will stop it;\n * caller-supplied engines are left alone.\n */\n destroy(): void {\n this.inApp.destroy?.();\n this.widgets.destroy();\n this.initialized = false;\n }\n\n /**\n * Current armed campaigns visible to the InAppManager. Accessible for\n * the Prefetch Inspector and for debugging. WidgetManager's prefetched\n * spin_wheel / scratch_card configs are NOT in this list — they live\n * in `this.widgets` and have their own lifecycle.\n */\n getCampaigns(): InAppCampaign[] {\n // AegisInAppManager keeps `campaigns` as a private field. Expose it\n // via bracket access; the field is stable as of SDK 1.5.0. Once\n // Phase 7c unifies render paths this becomes a first-class getter.\n return ((this.inApp as unknown as { campaigns?: InAppCampaign[] }).campaigns) ?? [];\n }\n}\n","/**\n * SDK Bootstrap\n *\n * Strict origin-assertion handshake against the control-plane. Called once\n * at SDK init — resolves writeKey → propertyId, asserts origin, and returns\n * the VAPID public key + first-party cookie id the SDK needs for the rest\n * of the session.\n *\n * A failed bootstrap (401/403) aborts SDK init — the SDK refuses to emit\n * events or request push permission against an origin it cannot prove it\n * owns.\n *\n * See docs/architecture/SUBSCRIPTION_PROPERTY_ARCHITECTURE.md §5.\n */\n\nconst COOKIE_NAME = 'aegis_fpc';\nconst COOKIE_MAX_AGE_DAYS = 365 * 2;\n\nexport interface BootstrapRequest {\n writeKey: string;\n currentOrigin?: string;\n firstPartyCookieId?: string;\n attestationToken?: string;\n userAgent?: string;\n}\n\nimport type { EventGovernanceHint } from '../governance';\n\nexport interface BootstrapResult {\n propertyId: string;\n organizationId: string;\n workspaceId: string;\n propertyType: 'shopify_store' | 'hosted_commerce' | 'custom_website' | 'mobile_app';\n vapidPublicKey: string | null;\n allowedOrigins: string[];\n pushEnabled: boolean;\n inAppEnabled: boolean;\n transportMode: string;\n firstPartyCookieId: string;\n /**\n * Event-governance hint for SDK-side unique-event-name cap enforcement.\n * Null = Enterprise plan / CP outage / org has no cap. Safe to pass\n * directly to `aegis.ingestGovernanceHint()`.\n */\n eventGovernance: EventGovernanceHint | null;\n /**\n * @deprecated since P15.1 (2026-05-26) — use `locationCodes` instead.\n * Pre-2026-05-26 the path segment after the brand subdomain was a\n * workspace_code; the canonical hierarchy reversal made it a\n * location_code (outlet under a brand). Field name retained for\n * backward compat with SDK consumers that haven't migrated; new\n * consumers MUST read `locationCodes`. Server still populates BOTH\n * with the same array during the deprecation window so a stale\n * SDK keeps working.\n */\n workspaceCodes: string[];\n /**\n * P15.1 — outlet-code allowlist for SDK path-segment detection.\n * Empty array = no outlet codes registered for this org (single-\n * outlet tenant). SDK uses this set to decide whether\n * `location.pathname.split('/')[1]` is a valid outlet code vs a\n * generic route (`/products`, `/collections`). Pass to\n * `aegis.ingestLocationCodes()` after bootstrap completes.\n *\n * Same array contents as `workspaceCodes` during the deprecation\n * window — renaming the field gives semantic clarity (these ARE\n * location codes under the new hierarchy) without breaking\n * existing consumers.\n */\n locationCodes: string[];\n}\n\nexport class BootstrapError extends Error {\n constructor(public readonly status: number, message: string) {\n super(message);\n this.name = 'BootstrapError';\n }\n}\n\n/**\n * Read the first-party cookie id from document.cookie. Returns null if\n * unset — caller should pass undefined so the server issues a fresh one.\n */\nexport function readFirstPartyCookie(): string | null {\n if (typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${COOKIE_NAME}=([^;]+)`));\n return match ? decodeURIComponent(match[1]) : null;\n}\n\n/**\n * Persist the first-party cookie id returned by the server. Stored as a\n * first-party cookie (readable by JS — it's not a secret, it's a device\n * id) so that the same browser hitting a second origin on the same\n * registrable domain gets the same cookie back.\n */\nexport function writeFirstPartyCookie(cookieId: string): void {\n if (typeof document === 'undefined') return;\n const expires = new Date();\n expires.setDate(expires.getDate() + COOKIE_MAX_AGE_DAYS);\n // Derive the registrable-domain boundary where possible so the cookie is\n // shared across subdomains (e.g., shop.sweettruths.com + www.sweettruths.com).\n // We conservatively use the current host without a leading dot —\n // browsers scope the cookie to that host. For cross-registrable-domain\n // siblings (Shopify myshopify.com + actii.me), each domain gets its own\n // cookie, which is the expected per-origin behavior.\n document.cookie =\n `${COOKIE_NAME}=${encodeURIComponent(cookieId)};` +\n `expires=${expires.toUTCString()};` +\n `path=/;SameSite=Lax`;\n // Also mirror into localStorage so the SDK can read it synchronously at\n // init time even in environments where document.cookie is delayed.\n try {\n window.localStorage.setItem(COOKIE_NAME, cookieId);\n } catch {\n // private mode / storage disabled — cookie alone is sufficient\n }\n}\n\n/**\n * Perform the bootstrap handshake.\n *\n * @throws BootstrapError on 4xx — the SDK should stop init and surface the\n * error to the console. 5xx are retried once.\n */\nexport async function bootstrap(\n apiHost: string,\n req: BootstrapRequest\n): Promise<BootstrapResult> {\n const body: Record<string, unknown> = { writeKey: req.writeKey };\n if (req.currentOrigin) body.currentOrigin = req.currentOrigin;\n if (req.firstPartyCookieId) body.firstPartyCookieId = req.firstPartyCookieId;\n if (req.attestationToken) body.attestationToken = req.attestationToken;\n if (req.userAgent) body.userAgent = req.userAgent;\n\n const url = `${apiHost.replace(/\\/$/, '')}/v1/sdk/bootstrap`;\n\n const doFetch = async (): Promise<Response> =>\n fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n credentials: 'omit',\n });\n\n let resp = await doFetch();\n if (resp.status >= 500) {\n await new Promise((r) => setTimeout(r, 750));\n resp = await doFetch();\n }\n\n if (resp.status === 401) {\n throw new BootstrapError(401, 'writeKey not recognized or revoked');\n }\n if (resp.status === 403) {\n throw new BootstrapError(403, 'Origin validation failed — this writeKey is bound to a different property');\n }\n if (!resp.ok) {\n throw new BootstrapError(resp.status, `Bootstrap failed: HTTP ${resp.status}`);\n }\n\n const json = (await resp.json()) as BootstrapResult;\n writeFirstPartyCookie(json.firstPartyCookieId);\n return json;\n}\n\n/**\n * Derive a deterministic device fingerprint from the first-party cookie id\n * and a few stable UA parts. This is the value sent on every push-subscribe\n * call — its stability lets the backend UPSERT on (property_id, fingerprint)\n * across re-subscribes and VAPID rotations.\n */\nexport async function deriveDeviceFingerprint(firstPartyCookieId: string): Promise<string> {\n const ua = typeof navigator !== 'undefined' ? navigator.userAgent : '';\n const platform = typeof navigator !== 'undefined' ? (navigator.platform || '') : '';\n const language = typeof navigator !== 'undefined' ? (navigator.language || '') : '';\n const input = `${firstPartyCookieId}|${ua}|${platform}|${language}`;\n\n // Prefer subtle.crypto — available in all push-capable browsers.\n if (typeof crypto !== 'undefined' && crypto.subtle) {\n const bytes = new TextEncoder().encode(input);\n const hash = await crypto.subtle.digest('SHA-256', bytes);\n const hex = Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n return hex;\n }\n\n // Last-resort fallback — basic 32-bit FNV hash (non-cryptographic but\n // stable). Push-capable browsers always have subtle.crypto so this path\n // is practically unreachable; included only for completeness.\n let h = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n }\n return `fnv-${h.toString(16)}`;\n}\n","import { Aegis } from './core/analytics';\n\nconst aegis = new Aegis();\n\nexport default aegis;\n\nexport { Aegis } from './core/analytics';\nexport type { AegisConfig, CellEndpoint, CellRegion } from './types/config';\nexport type {\n AegisEvent,\n TrackEvent,\n IdentifyEvent,\n PageEvent,\n ScreenEvent,\n GroupEvent,\n AliasEvent,\n EventContext,\n BatchPayload,\n BatchResponse,\n} from './types/events';\nexport { UserNamespace } from './core/user-namespace';\nexport type { OptInChannel } from './core/user-namespace';\nexport type { Plugin, PluginRegistry } from './types/plugin';\nexport { debounce, throttle } from './utils/debounce';\nexport type {\n ConsentPreferences,\n ConsentCategory,\n ConsentStatus,\n} from './utils/consent';\n// In-app + widget types are re-exported for callers that configure\n// AegisMessageRuntime or read campaign objects. The underlying manager\n// classes are intentionally NOT exported — use AegisMessageRuntime.\nexport type {\n InAppCampaign,\n AegisInAppConfig,\n CampaignClickEvent,\n CampaignDismissEvent,\n AegisErrorEvent,\n InAppLifecycleEventMap,\n} from './inapp';\nexport { renderPreview } from './inapp';\n\nexport { AegisPlacementManager } from './placements/AegisPlacementManager';\nexport type {\n PlacementContent,\n PlacementSlot,\n AegisPlacementConfig,\n} from './placements/AegisPlacementManager';\n\nexport type {\n WidgetConfig,\n GamificationPrize,\n AegisWidgetConfig,\n} from './widgets';\n\nexport { TriggerEngine } from './triggers';\nexport type {\n TriggerRule,\n ScrollDepthConfig,\n TimeOnPageConfig,\n ExitIntentConfig,\n InactivityConfig,\n TriggerEvent,\n} from './triggers';\n\nexport { SdkConfigPoller } from './core/sdk-config-poller';\nexport type { SdkConfig, SdkConfigPollerOptions, ConfigChangeCallback } from './core/sdk-config-poller';\n\n// Preload-first bundle (2026-04-22) — fetches armed campaigns + inbox\n// slice once at init; everything renders from memory on trigger.\nexport { PrefetchBundleClient } from './core/prefetch-bundle-client';\nexport type {\n PrefetchBundle,\n PrefetchBundleCampaign,\n PrefetchBundleInbox,\n PrefetchBundleInboxEntry,\n PrefetchBundleClientOptions,\n PrefetchBundleContext,\n PrefetchBundleListener,\n} from './core/prefetch-bundle-client';\n\n// App Inbox — persistent message-center client.\nexport { AegisInbox } from './inbox';\nexport type { AegisInboxConfig, AegisInboxEntry, InboxListener } from './inbox';\n\n// Unified message runtime — the single entry point for in-app + widgets.\n// All 20 in-app types (modal/banner/tooltip/full_screen/spin_wheel/\n// scratch_card/nps_survey/quiz/countdown_offer/star_rating/...) flow\n// through this one class. The underlying AegisInAppManager +\n// AegisWidgetManager implementations are internal to the package.\nexport { AegisMessageRuntime } from './runtime';\nexport type { AegisMessageRuntimeConfig } from './runtime';\n\nexport { AegisWebPush } from './push/AegisWebPush';\nexport type {\n AegisWebPushConfig,\n AegisAPIClient,\n ContactIdentity,\n PushEventTracker,\n} from './push/AegisWebPush';\n\nexport {\n bootstrap,\n readFirstPartyCookie,\n writeFirstPartyCookie,\n deriveDeviceFingerprint,\n BootstrapError,\n} from './core/bootstrap';\nexport type { BootstrapRequest, BootstrapResult } from './core/bootstrap';\n\nexport { RateLimiter } from './core/rate-limiter';\nexport type { RateLimiterOptions } from './core/rate-limiter';\n\n// Event-governance — SDK-side cap enforcement. The NameGovernor is wired\n// into `Aegis.captureEvent()` automatically; callers only interact with it\n// via `aegis.ingestGovernanceHint(bootstrapResult.eventGovernance)`.\nexport { NameGovernor, BloomFilter, murmurhash3_x86_32 } from './governance';\nexport type { EventGovernanceHint, DropReport, BloomFilterParams } from './governance';\n\n// NOTE: SSE-based realtime subscription is intentionally NOT exported from the\n// public SDK surface. The Aegis Web SDK uses HTTP batch uplink + HTTP polling\n// downstream (via AegisInAppManager) + Web Push (via AegisWebPush). Tenant\n// dashboards that need SSE open it directly via their own Next.js API routes,\n// not through this SDK. See RFC 2026-04-16 §A.\n\nexport { EcommerceTracker } from './ecommerce';\nexport type {\n EcommerceProduct,\n EcommerceCart,\n EcommerceCheckout,\n EcommerceOrder,\n EcommerceCoupon,\n EcommerceSearch,\n EcommerceProductList,\n EcommerceWishlist,\n EcommerceWaitlist,\n EcommercePromotion,\n} from './ecommerce';\n"],"names":["goto","readAnonIdFromStorage","m","isMobile","mobileConfig"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/utils/debounce.ts","../src/inapp/renderers/carousel-cards.ts","../src/inapp/renderers/sticky-bar.ts","../src/inapp/renderers/progress-bar.ts","../src/inapp/renderers/coachmark-tour.ts","../src/inapp/renderers/product-recommendation.ts","../src/inapp/renderers/stories.ts","../src/inapp/renderers/games.ts","../src/inapp/renderers/video.ts","../src/chat/AegisChat.ts","../src/triggers/TriggerEngine.ts","../src/inapp/renderers/active-web-chat.ts","../src/inapp/AegisInAppManager.ts","../src/inapp/renderPreview.ts","../src/inapp/devicePairing.ts","../src/triggers/IntentRuleEvaluator.ts","../src/triggers/ContactScoresFetcher.ts","../src/core/sdk-config-poller.ts","../src/core/prefetch-bundle-client.ts","../src/inbox/AegisInbox.ts","../src/widgets/AegisWidgetManager.ts","../src/loyalty/AegisLoyaltyManager.ts","../src/runtime/AegisMessageRuntime.ts","../src/core/bootstrap.ts","../src/index.ts"],"sourcesContent":["export function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n return function debounced(...args: Parameters<T>): void {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n\n timeoutId = setTimeout(() => {\n func(...args);\n timeoutId = null;\n }, wait);\n };\n}\n\nexport function throttle<T extends (...args: any[]) => any>(\n func: T,\n limit: number\n): (...args: Parameters<T>) => void {\n let inThrottle = false;\n\n return function throttled(...args: Parameters<T>): void {\n if (!inThrottle) {\n func(...args);\n inThrottle = true;\n setTimeout(() => {\n inThrottle = false;\n }, limit);\n }\n };\n}\n","/**\n * CarouselCards renderer — a swipeable / autoplaying sequence of product\n * cards. Used for post-purchase upsells, cross-sell, and \"recently viewed\"\n * surfaces. The entire card list is pre-bundled — no network call on\n * trigger; slide advance is pure client state.\n *\n * Data shape (interactive_config, populated at campaign create time and\n * validated server-side):\n * cards: Array<{ image_url?, title, body?, cta_text?, cta_url? }>\n * autoplay_ms?: number // 0 = manual advance only\n * loop?: boolean // wrap to card 0 on last-next\n */\n\nimport type { RenderContext } from './types';\n\ntype Card = {\n image_url?: string;\n video_url?: string;\n title?: string;\n body?: string;\n cta_text?: string;\n cta_url?: string;\n};\n\nconst MAX_CARDS_RENDERED = 10;\n\nexport function renderCarouselCards(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const rawCards = Array.isArray(ic.cards) ? (ic.cards as Card[]) : [];\n const cards = rawCards.slice(0, MAX_CARDS_RENDERED);\n\n if (cards.length === 0) {\n log('carousel_cards rendered with zero cards — skipping', 'warn');\n return;\n }\n\n const autoplay = Number(ic.autoplay_ms) || 0;\n const loop = ic.loop !== false; // default true\n\n addAnimationStyles();\n\n // Commerce surface: neutral card canvas (product imagery needs it) + the BRAND\n // accent (operator's background_color — what the promo widgets fill with) on\n // the emphasis elements (CTA / active dot). Falls back to brand blue.\n const bg = '#ffffff';\n const fg = '#0f172a';\n const accent = sanitizeColor((campaign.background_color as string) || '#4169e1');\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-carousel-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText = `\n position: fixed; left: 0; right: 0; bottom: 0;\n z-index: 99999; padding: 12px 12px 20px;\n background: rgba(0,0,0,0.12); backdrop-filter: blur(8px);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n `;\n\n const card = document.createElement('div');\n card.style.cssText = `\n background: ${bg}; color: ${fg}; border-radius: 16px;\n box-shadow: 0 8px 20px rgba(0,0,0,0.08); padding: 16px;\n max-width: 520px; margin: 0 auto; position: relative;\n `;\n\n const header = document.createElement('div');\n header.style.cssText = 'display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 12px;';\n\n const headerText = document.createElement('div');\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 700; font-size: 15px; margin-bottom: 2px;';\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.75;';\n headerText.appendChild(title);\n headerText.appendChild(body);\n header.appendChild(headerText);\n\n const closeBtn = document.createElement('button');\n closeBtn.textContent = '✕';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 16px; cursor: pointer; opacity: 0.6; padding: 2px 6px;\n `;\n closeBtn.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n });\n header.appendChild(closeBtn);\n card.appendChild(header);\n\n const track = document.createElement('div');\n // Native horizontal scroll (same as the product-rec row, which scrolls\n // smoothly). `proximity` snap lets the user rest anywhere — `mandatory` +\n // start-align made the LAST card unreachable (it can't align to the start\n // when there's no content after it) and felt janky. No custom wheel handler:\n // it double-scrolled and fought the native scroller.\n track.style.cssText = `\n display: flex; gap: 10px; overflow-x: auto; scroll-snap-type: x proximity;\n scroll-padding-left: 0; scrollbar-width: none; -ms-overflow-style: none;\n padding-bottom: 4px; -webkit-overflow-scrolling: touch;\n `;\n (track.style as unknown as { msOverflowStyle?: string }).msOverflowStyle = 'none';\n\n cards.forEach((c, i) => {\n const tile = document.createElement('div');\n tile.setAttribute('data-card-index', String(i));\n tile.style.cssText = `\n flex: 0 0 auto; width: 140px; scroll-snap-align: start;\n background: ${fg}0a; border-radius: 12px; padding: 10px;\n display: flex; flex-direction: column; gap: 6px;\n cursor: ${c.cta_url ? 'pointer' : 'default'};\n `;\n // A card is a VIDEO when video_url is set (muted/inline/looped autoplay),\n // else an IMAGE. Mirror this in every carousel render path.\n const safeVideo = c.video_url ? sanitizeUrl(c.video_url) : '';\n if (safeVideo) {\n const vid = document.createElement('video');\n vid.src = safeVideo;\n vid.muted = true;\n vid.loop = true;\n vid.autoplay = true;\n vid.playsInline = true;\n vid.setAttribute('playsinline', '');\n vid.style.cssText = 'width: 100%; height: 96px; border-radius: 8px; object-fit: cover;';\n tile.appendChild(vid);\n } else if (c.image_url) {\n const img = document.createElement('img');\n const safe = sanitizeUrl(c.image_url);\n if (safe) {\n img.src = safe;\n img.alt = '';\n img.loading = 'lazy';\n img.style.cssText = 'width: 100%; height: 96px; border-radius: 8px; object-fit: cover;';\n tile.appendChild(img);\n }\n }\n if (c.title) {\n const t = document.createElement('div');\n t.textContent = c.title;\n t.style.cssText = 'font-weight: 600; font-size: 13px; line-height: 1.3;';\n tile.appendChild(t);\n }\n if (c.body) {\n const b = document.createElement('div');\n b.textContent = c.body;\n b.style.cssText = 'font-size: 11.5px; opacity: 0.72; line-height: 1.3;';\n tile.appendChild(b);\n }\n if (c.cta_text && c.cta_url) {\n const cta = document.createElement('button');\n cta.className = 'aegis-cta';\n cta.textContent = c.cta_text;\n cta.style.cssText = `\n margin-top: auto; background: ${accent}; color: #fff;\n border: none; padding: 6px 10px; border-radius: 999px;\n font-size: 12px; font-weight: 600; cursor: pointer;\n `;\n const goto = (e: Event) => {\n e.stopPropagation();\n // P3 — per-card step_id so the funnel-drop-off report can\n // attribute clicks to specific carousel position. step_0 = first.\n trackEvent(campaign.id, 'clicked', { stepId: `card_${i}` });\n const safe = sanitizeUrl(c.cta_url!);\n if (safe) window.location.href = safe;\n };\n cta.addEventListener('click', goto);\n tile.appendChild(cta);\n tile.addEventListener('click', goto);\n }\n track.appendChild(tile);\n });\n card.appendChild(track);\n\n // Dots + autoplay\n const dots = document.createElement('div');\n dots.style.cssText = 'display: flex; justify-content: center; gap: 6px; margin-top: 10px;';\n const dotEls: HTMLSpanElement[] = [];\n cards.forEach(() => {\n const dot = document.createElement('span');\n dot.style.cssText = `\n width: 6px; height: 6px; border-radius: 999px; background: ${fg};\n opacity: 0.25; transition: opacity 0.2s;\n `;\n dotEls.push(dot);\n dots.appendChild(dot);\n });\n card.appendChild(dots);\n\n // P3 — emit `impression` per card so the funnel-drop-off report can\n // measure how many users actually viewed each carousel position.\n // sessionStorage dedup on (campaign × card) prevents flooding when\n // a user swipes back and forth.\n const seenCards = new Set<number>();\n const setActive = (idx: number) => {\n dotEls.forEach((d, i) => {\n d.style.opacity = i === idx ? '1' : '0.25';\n d.style.background = i === idx ? accent : fg; // active dot = brand accent\n });\n if (!seenCards.has(idx)) {\n seenCards.add(idx);\n trackEvent(campaign.id, 'impression', { stepId: `card_${idx}` });\n }\n };\n setActive(0);\n\n let activeIdx = 0;\n const tiles = track.querySelectorAll<HTMLDivElement>('[data-card-index]');\n const goto = (idx: number) => {\n activeIdx = ((idx % cards.length) + cards.length) % cards.length;\n const el = tiles[activeIdx];\n if (el) {\n // Scroll the TRACK only — never `el.scrollIntoView()`, which scrolls the\n // nearest scrollable ancestor (the page / preview iframe) and visibly\n // jitters when it fights the user's own scroll. Compute the horizontal\n // delta from the track's own viewport and move just `track.scrollLeft`.\n const delta =\n el.getBoundingClientRect().left - track.getBoundingClientRect().left;\n track.scrollTo({ left: track.scrollLeft + delta, behavior: 'smooth' });\n setActive(activeIdx);\n }\n };\n\n // Prev/next arrows — swipe + dots are touch-first; desktop needs buttons to\n // advance the carousel. Flanks the dots row.\n if (cards.length > 1) {\n const mkArrow = (glyph: string, label: string, step: number): HTMLButtonElement => {\n const b = document.createElement('button');\n b.type = 'button';\n b.textContent = glyph;\n b.setAttribute('aria-label', label);\n b.style.cssText = `background: transparent; border: none; color: ${fg}; opacity: 0.55; font-size: 18px; line-height: 1; cursor: pointer; padding: 0 4px;`;\n b.addEventListener('click', () => { stopAutoplay(); goto(activeIdx + step); });\n return b;\n };\n dots.style.alignItems = 'center';\n dots.insertBefore(mkArrow('‹', 'Previous', -1), dots.firstChild);\n dots.appendChild(mkArrow('›', 'Next', 1));\n }\n\n let autoplayTimer: ReturnType<typeof setInterval> | null = null;\n const stopAutoplay = () => {\n if (autoplayTimer) {\n clearInterval(autoplayTimer);\n autoplayTimer = null;\n }\n };\n if (autoplay > 0 && cards.length > 1) {\n autoplayTimer = setInterval(() => {\n // The overlay may have been removed (e.g. a preview re-render replaced\n // it) — DOM `removeChild` fires no event, so self-terminate here rather\n // than leak a timer that scrolls a detached node.\n if (!document.body.contains(overlay)) {\n stopAutoplay();\n return;\n }\n const next = activeIdx + 1;\n if (next >= cards.length && !loop) {\n stopAutoplay();\n return;\n }\n goto(next);\n }, autoplay);\n }\n\n // Stop auto-advancing the moment the user takes manual control — autoplay\n // fighting a live scroll/drag is the classic carousel jitter.\n (['pointerdown', 'wheel', 'touchstart'] as const).forEach((evt) =>\n track.addEventListener(evt, stopAutoplay, { passive: true }),\n );\n\n // Observe scroll to keep dots in sync when the user swipes.\n track.addEventListener('scroll', () => {\n const approx = Math.round(track.scrollLeft / 150);\n if (approx !== activeIdx && approx >= 0 && approx < cards.length) {\n activeIdx = approx;\n setActive(activeIdx);\n }\n });\n\n overlay.appendChild(card);\n document.body.appendChild(overlay);\n}\n","/**\n * StickyBar renderer — a pinned notification strip at the top or bottom\n * of the viewport. Used for free-shipping hints, flash-sale banners,\n * cart-reminder strips. Dismissible, optionally auto-hiding.\n *\n * interactive_config:\n * sticky_position: 'top' | 'bottom' (required)\n * sticky_bg_color?: string\n * sticky_dismissible?: boolean default true\n * sticky_auto_hide_ms?: number 0 = never\n */\n\nimport type { RenderContext } from './types';\n\n// Persist per-campaign dismissal across reloads so we don't re-show a\n// bar the user already closed. Scoped per campaign ID; storage key\n// survives navigation but is cleared when the user explicitly clears site data.\nconst DISMISS_STORAGE_PREFIX = 'aegis_sticky_dismissed:';\n\nexport function renderStickyBar(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const position = ic.sticky_position === 'top' ? 'top' : 'bottom';\n const dismissible = ic.sticky_dismissible !== false;\n const autoHide = Number(ic.sticky_auto_hide_ms) || 0;\n\n // Already dismissed this session? Skip silently — the prefetch bundle\n // keeps re-offering it, but the user's explicit close stands until TTL.\n try {\n if (\n typeof localStorage !== 'undefined' &&\n localStorage.getItem(DISMISS_STORAGE_PREFIX + campaign.id)\n ) {\n log(`sticky_bar ${campaign.id} suppressed — user dismissed earlier`);\n return;\n }\n } catch {\n // localStorage blocked — fall through and render\n }\n\n addAnimationStyles();\n\n const bg = sanitizeColor(\n (ic.sticky_bg_color as string) || (campaign.background_color as string) || '#4169e1',\n );\n const fg = sanitizeColor((campaign.text_color as string) || '#ffffff');\n\n const bar = document.createElement('div');\n bar.className = 'aegis-in-app-sticky-bar';\n bar.setAttribute('data-campaign-id', campaign.id);\n\n const positionCss =\n position === 'top'\n ? 'top: 0; left: 0; right: 0; animation: aegisSlideDown 0.3s ease-out;'\n : 'bottom: 0; left: 0; right: 0; animation: aegisSlideInFromBottom 0.3s ease-out;';\n\n bar.style.cssText = `\n position: fixed; ${positionCss}\n background: ${bg}; color: ${fg};\n padding: 10px 14px; z-index: 999998;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n display: flex; align-items: center; gap: 12px; justify-content: center;\n box-shadow: 0 ${position === 'top' ? '2px' : '-2px'} 8px rgba(0,0,0,0.08);\n `;\n\n const label = document.createElement('div');\n label.style.cssText = 'flex: 0 1 auto; font-size: 13px; font-weight: 500; text-align: center;';\n const strong = document.createElement('strong');\n strong.textContent = campaign.title;\n strong.style.cssText = 'margin-right: 6px; font-weight: 700;';\n label.appendChild(strong);\n label.appendChild(document.createTextNode(campaign.body));\n bar.appendChild(label);\n\n // CTA renders whenever LABELLED (was hidden unless BOTH set).\n const stickyCtaLabel = campaign.button_text || (campaign.action_url ? 'Shop now' : '');\n if (stickyCtaLabel) {\n const cta = document.createElement('button');\n cta.className = 'aegis-cta';\n cta.textContent = stickyCtaLabel;\n cta.style.cssText = `\n background: ${fg}; color: ${bg};\n border: none; padding: 6px 14px; border-radius: 999px;\n font-size: 12px; font-weight: 700; cursor: pointer; white-space: nowrap;\n `;\n cta.addEventListener('click', () => {\n trackEvent(campaign.id, 'clicked');\n if (campaign.action_url) {\n const safe = sanitizeUrl(campaign.action_url);\n if (safe) window.location.href = safe;\n }\n });\n bar.appendChild(cta);\n }\n\n let autoHideTimer: ReturnType<typeof setTimeout> | null = null;\n const remove = (persist: boolean) => {\n if (autoHideTimer) clearTimeout(autoHideTimer);\n if (persist) {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(DISMISS_STORAGE_PREFIX + campaign.id, '1');\n }\n } catch {\n // swallow — localStorage may be disabled\n }\n }\n bar.remove();\n };\n\n if (dismissible) {\n const close = document.createElement('button');\n close.textContent = '✕';\n close.setAttribute('aria-label', 'Dismiss');\n close.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 16px; cursor: pointer; padding: 0 4px; opacity: 0.75;\n `;\n close.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n remove(true);\n });\n bar.appendChild(close);\n }\n\n if (autoHide > 0) {\n autoHideTimer = setTimeout(() => remove(false), autoHide);\n }\n\n document.body.appendChild(bar);\n}\n","/**\n * ProgressBar renderer — a persistent bar that shows the user's progress\n * toward a reward threshold (free shipping, loyalty tier, referral bonus).\n *\n * Two sources of the current value:\n * 'client' — cheap: read from window.Shopify / WooCommerce / Magento\n * cart globals. Untrusted; fine for visual-only hints.\n * 'sse' — trusted: cell-plane pushes current_value via SSE to the\n * already-shipped realtime server. For cart-gated rewards\n * (must agree with server-side checkout guard), prefer SSE.\n *\n * For Phase 1 we implement CLIENT mode end-to-end. SSE mode reads\n * `window.__aegisProgressSSE[campaign.id]` if populated by a parent app\n * — higher-level integration (the SSE bridge) can push values there.\n *\n * interactive_config:\n * progress_goal_type: 'cart_total' | 'items_in_cart' | 'loyalty_points' | 'referrals'\n * progress_threshold: number\n * progress_reward_text?: string\n * progress_source?: 'client' | 'sse' default 'client'\n */\n\nimport type { RenderContext } from './types';\n\ntype GoalType = 'cart_total' | 'items_in_cart' | 'loyalty_points' | 'referrals';\n\n/**\n * Build the progress-bar element + wire its live update loop. Shared by the\n * fixed overlay (`renderProgressBar`) and the inline slot variant\n * (`renderProgressBarInline`). Returns the element, or null when the campaign\n * is misconfigured (non-positive threshold). The caller positions/appends it:\n * - overlay → fixed bottom, appended to document.body\n * - inline → static, full-width, appended into a `[data-aegis-slot]` anchor\n * (the slot card supplies the chrome; the bar is just the mechanic)\n */\nfunction buildProgressBar(ctx: RenderContext, inline: boolean): HTMLElement | null {\n const { campaign, trackEvent, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const goalType = (ic.progress_goal_type as GoalType) || 'cart_total';\n const threshold = Number(ic.progress_threshold);\n if (!(threshold > 0)) {\n log('progress_bar requires a positive progress_threshold — skipping', 'warn');\n return null;\n }\n const rewardText =\n (ic.progress_reward_text as string) || (campaign.body as string) || 'Unlocked!';\n const source = ic.progress_source === 'sse' ? 'sse' : 'client';\n\n addAnimationStyles();\n\n // Surface-aware palette (matches the other widgets):\n // clean (default) — neutral WHITE card, dark text, BRAND-accent fill.\n // branded — BRAND-colour card, light text, WHITE fill.\n // The old code used background_color as the CARD bg, so a brand-blue campaign\n // rendered a blue card with a blue fill (invisible). brand is the accent.\n const brand = sanitizeColor((campaign.background_color as string) || '#4169e1');\n const branded = (ic.surface_style as string) === 'branded';\n const bg = branded ? brand : '#ffffff';\n const fg = sanitizeColor((campaign.text_color as string) || (branded ? '#ffffff' : '#0f172a'));\n const fill = sanitizeColor(\n (ic.progress_fill_color as string) || (branded ? '#ffffff' : brand),\n );\n // Track tint: a faint wash of the fill (branded uses a white wash on brand).\n const track = branded ? 'rgba(255,255,255,0.25)' : `${fill}22`;\n\n const bar = document.createElement('div');\n bar.className = 'aegis-in-app-progress-bar';\n bar.setAttribute('data-campaign-id', campaign.id);\n // Inline: no fixed positioning / shadow / slide-in — the host slot card owns\n // the chrome, so the bar fills the slot width and reads as part of the card.\n bar.style.cssText = inline\n ? `\n background: ${bg}; color: ${fg};\n padding: 10px 14px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `\n : `\n position: fixed; left: 12px; right: 12px; bottom: 12px;\n max-width: 540px; margin: 0 auto;\n background: ${bg}; color: ${fg}; border-radius: 12px;\n padding: 10px 14px; z-index: 999997;\n box-shadow: 0 8px 20px rgba(0,0,0,0.08);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n `;\n\n const label = document.createElement('div');\n label.style.cssText = 'display: flex; justify-content: space-between; font-size: 13px; font-weight: 600; margin-bottom: 6px;';\n\n const leading = document.createElement('span');\n leading.textContent = campaign.title;\n label.appendChild(leading);\n\n const numeric = document.createElement('span');\n numeric.style.cssText = 'opacity: 0.7; font-weight: 500;';\n label.appendChild(numeric);\n bar.appendChild(label);\n\n const shell = document.createElement('div');\n shell.style.cssText = `\n height: 8px; border-radius: 999px; background: ${track};\n overflow: hidden;\n `;\n const fillEl = document.createElement('div');\n fillEl.style.cssText = `\n position: relative; overflow: hidden;\n height: 100%; border-radius: 999px; background: ${fill};\n width: 0%; transition: width 0.4s cubic-bezier(.4,0,.2,1);\n `;\n // Animated shimmer sweep — makes the bar feel live as it fills.\n if (typeof document !== 'undefined' && !document.getElementById('aegis-progress-styles')) {\n const s = document.createElement('style');\n s.id = 'aegis-progress-styles';\n s.textContent = '@keyframes aegisProgShimmer{0%{transform:translateX(-100%)}60%,100%{transform:translateX(220%)}}';\n document.head.appendChild(s);\n }\n const shimmer = document.createElement('div');\n shimmer.style.cssText =\n 'position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.38), transparent); transform: translateX(-100%); animation: aegisProgShimmer 1.8s ease-in-out infinite;';\n fillEl.appendChild(shimmer);\n shell.appendChild(fillEl);\n bar.appendChild(shell);\n\n const footnote = document.createElement('div');\n footnote.style.cssText = 'font-size: 11.5px; opacity: 0.65; margin-top: 6px;';\n bar.appendChild(footnote);\n\n const readCurrentValue = (): number => {\n if (source === 'sse') {\n const hook = (window as unknown as {\n __aegisProgressSSE?: Record<string, number>;\n }).__aegisProgressSSE;\n return (hook && typeof hook[campaign.id] === 'number' ? hook[campaign.id] : 0) as number;\n }\n // First-party path — a headless storefront feeds live cart state into\n // PRIVATE SDK state via `runtime.setCartState(...)`; we read it here in\n // preference to the `window.*` globals below. This is how a Next.js\n // storefront (no `window.Shopify` / `window.aegis_cart`) drives the bar.\n if (goalType === 'cart_total' || goalType === 'items_in_cart') {\n const rc = ctx.getCartState?.();\n if (rc) {\n return goalType === 'items_in_cart' ? Number(rc.itemCount) || 0 : Number(rc.total) || 0;\n }\n }\n // client mode — read the platform cart globals the widget manager\n // already normalises (Shopify/Woo/Magento). We peek at the same\n // locations without pulling in AegisWidgetManager's 2k-line module.\n try {\n if (goalType === 'cart_total' || goalType === 'items_in_cart') {\n const win = window as unknown as {\n Shopify?: { checkout?: { total_price?: string | number } };\n aegis_cart?: { cart_total?: number; cart_items?: unknown[] };\n localStorage?: Storage;\n };\n if (win.Shopify?.checkout) {\n const v = parseFloat(String(win.Shopify.checkout.total_price || 0));\n return goalType === 'cart_total' ? v : 0;\n }\n if (win.aegis_cart) {\n if (goalType === 'items_in_cart') {\n return Array.isArray(win.aegis_cart.cart_items) ? win.aegis_cart.cart_items.length : 0;\n }\n return Number(win.aegis_cart.cart_total || 0);\n }\n // Magento cache fallback\n try {\n const cacheStr = window.localStorage?.getItem('mage-cache-storage');\n if (cacheStr) {\n const cache = JSON.parse(cacheStr) as { cart?: { subtotalAmount?: number; items?: unknown[] } };\n const cart = cache.cart;\n if (cart) {\n return goalType === 'cart_total'\n ? Number(cart.subtotalAmount || 0)\n : Array.isArray(cart.items)\n ? cart.items.length\n : 0;\n }\n }\n } catch {\n /* noop */\n }\n }\n // loyalty_points / referrals are expected to flow via SSE/push; in\n // client mode we cannot trust a local counter.\n return 0;\n } catch {\n return 0;\n }\n };\n\n // P3 — milestone-based step_id. Each 25%-quartile crossing fires its\n // own impression (`q25`, `q50`, `q75`) so the funnel-drop-off report\n // can show where users gave up before unlocking.\n let lastFiredUnlock = false;\n const milestonesFired = new Set<string>();\n const fireMilestone = (id: string) => {\n if (milestonesFired.has(id)) return;\n milestonesFired.add(id);\n trackEvent(campaign.id, 'impression', { stepId: id });\n };\n const update = () => {\n const cur = readCurrentValue();\n const pct = Math.max(0, Math.min(100, (cur / threshold) * 100));\n fillEl.style.width = `${pct}%`;\n numeric.textContent = `${cur.toFixed(0)} / ${threshold.toFixed(0)} · ${Math.round(pct)}%`;\n // Hide the shimmer once complete (nothing left to fill).\n shimmer.style.display = pct >= 100 ? 'none' : '';\n if (pct >= 25) fireMilestone('q25');\n if (pct >= 50) fireMilestone('q50');\n if (pct >= 75) fireMilestone('q75');\n if (pct >= 100) {\n footnote.textContent = rewardText;\n if (!lastFiredUnlock) {\n lastFiredUnlock = true;\n trackEvent(campaign.id, 'clicked', { stepId: 'unlocked' });\n }\n } else {\n const remaining = Math.max(0, threshold - cur);\n footnote.textContent = `Add ${remaining.toFixed(0)} more to unlock: ${rewardText}`;\n }\n };\n\n update();\n\n // Client-mode cart state changes fire events on the storefront globals\n // (Shopify emits `cart:updated`, Woo emits its own). Poll fallback at\n // 1s — negligible overhead because every tick is synchronous.\n const pollTimer = setInterval(update, 1000);\n const cleanup = () => clearInterval(pollTimer);\n window.addEventListener('beforeunload', cleanup, { once: true });\n bar.addEventListener('remove', cleanup);\n\n return bar;\n}\n\n/**\n * Overlay progress bar — a fixed bar pinned to the bottom of the viewport.\n * Used by third-party storefront embeds (Shopify/Woo/Magento) that have no\n * native footer to host the mechanic.\n */\nexport function renderProgressBar(ctx: RenderContext): void {\n const bar = buildProgressBar(ctx, false);\n if (bar) document.body.appendChild(bar);\n}\n\n/**\n * Inline progress bar — renders the SAME live mechanic into a\n * `[data-aegis-slot]` anchor instead of a fixed overlay. This is how a\n * first-party storefront's value-bar footer is driven by a campaign: the host\n * owns the structural cart-summary card + a slot, and an operator-authored\n * `progress_bar` campaign fills the slot (replacing any host-rendered default).\n * Returns true when rendered so the slot dispatcher can track the impression.\n */\nexport function renderProgressBarInline(ctx: RenderContext, target: HTMLElement): boolean {\n const bar = buildProgressBar(ctx, true);\n if (!bar) return false;\n target.appendChild(bar);\n return true;\n}\n","/**\n * CoachmarkTour renderer — a guided, multi-step walkthrough anchored to\n * DOM elements via CSS selectors. One tooltip appears at a time with\n * next/back navigation; completion + skip are persisted per contact via\n * localStorage under the `resume_key`, so an abandoned tour resumes on\n * the next visit instead of restarting or re-bothering the user.\n *\n * interactive_config:\n * steps: Array<{\n * anchor_web?: string, // CSS selector for THIS platform\n * anchor_android?: string, // ignored on web\n * anchor_ios?: string, // ignored on web\n * title: string,\n * body: string,\n * placement?: 'top' | 'bottom' | 'left' | 'right',\n * cta_text?: string,\n * }>\n * resume_key: string,\n * allow_skip?: boolean,\n * show_progress_dots?: boolean,\n */\n\nimport type { RenderContext } from './types';\n\ntype Step = {\n anchor_web?: string;\n anchor_android?: string;\n anchor_ios?: string;\n title: string;\n body: string;\n placement?: 'top' | 'bottom' | 'left' | 'right';\n cta_text?: string;\n};\n\nconst RESUME_PREFIX = 'aegis_coachmark_progress:';\n\nfunction readResumeIdx(resumeKey: string): number {\n try {\n if (typeof localStorage === 'undefined') return 0;\n const raw = localStorage.getItem(RESUME_PREFIX + resumeKey);\n const n = raw ? parseInt(raw, 10) : 0;\n return Number.isFinite(n) && n >= 0 ? n : 0;\n } catch {\n return 0;\n }\n}\n\nfunction writeResumeIdx(resumeKey: string, idx: number): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(RESUME_PREFIX + resumeKey, String(idx));\n }\n } catch {\n /* noop */\n }\n}\n\nfunction clearResume(resumeKey: string): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem(RESUME_PREFIX + resumeKey);\n }\n } catch {\n /* noop */\n }\n}\n\nexport function renderCoachmarkTour(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const resumeKey = ic.resume_key as string | undefined;\n if (!resumeKey) {\n log('coachmark_tour requires interactive_config.resume_key — skipping', 'warn');\n return;\n }\n\n const steps = Array.isArray(ic.steps) ? (ic.steps as Step[]) : [];\n if (steps.length === 0) {\n log('coachmark_tour has no steps — skipping', 'warn');\n return;\n }\n\n const allowSkip = ic.allow_skip !== false;\n const showDots = ic.show_progress_dots !== false;\n\n addAnimationStyles();\n\n const bg = sanitizeColor((campaign.background_color as string) || '#0f172a');\n const fg = sanitizeColor((campaign.text_color as string) || '#ffffff');\n // Masked spotlight (vs the legacy ring). Spotlight punches a stronger,\n // configurable transparent hole around each step's anchor.\n const spotlight = (ic.highlight_style as string) === 'spotlight';\n const spotPad = typeof ic.spotlight_padding === 'number' ? (ic.spotlight_padding as number) : 6;\n const spotRadius = (ic.spotlight_shape as string) === 'circle' ? '50%' : '10px';\n const spotDim = typeof ic.spotlight_dim === 'number'\n ? Math.max(0, Math.min(95, ic.spotlight_dim as number)) / 100\n : (spotlight ? 0.64 : 0.4);\n // Backdrop colour: dark slate (default) · brand accent (bg) · black · custom.\n const dimMode = (ic.spotlight_dim_color as string) || 'dark';\n const dimBase = dimMode === 'black' ? '#000000'\n : dimMode === 'brand' ? bg\n : dimMode === 'custom' ? sanitizeColor((ic.spotlight_dim_custom as string) || '#0f172a')\n : '#0f172a';\n const dimAlpha = Math.round(Math.max(0, Math.min(1, spotDim)) * 255).toString(16).padStart(2, '0');\n const dimColor = /^#[0-9a-fA-F]{6}$/.test(dimBase) ? `${dimBase}${dimAlpha}` : `rgba(15,23,42,${spotDim})`;\n\n // Resume or start at 0.\n let current = readResumeIdx(resumeKey);\n if (current >= steps.length) {\n log(`coachmark_tour ${resumeKey} already complete — not re-showing`);\n return;\n }\n\n // Track the single overall impression once per mount.\n trackEvent(campaign.id, 'impression');\n\n let pointerEl: HTMLElement | null = null;\n let tipEl: HTMLElement | null = null;\n let highlightEl: HTMLElement | null = null;\n\n const cleanupOne = () => {\n pointerEl?.remove();\n tipEl?.remove();\n highlightEl?.remove();\n pointerEl = null;\n tipEl = null;\n highlightEl = null;\n };\n\n const finish = (opts: { skipped: boolean; lastStepIdx: number }) => {\n cleanupOne();\n const stepId = `step_${opts.lastStepIdx}`;\n if (opts.skipped) {\n trackEvent(campaign.id, 'dismissed', { stepId });\n } else {\n trackEvent(campaign.id, 'clicked', { stepId }); // completion\n // Finished the whole tour — timeline + funnel signal (no reward).\n void ctx.submitResponse?.('tour_complete', { steps: steps.length });\n }\n // Mark tour as complete so we never restart it for this contact.\n writeResumeIdx(resumeKey, steps.length);\n };\n\n const showStep = (idx: number) => {\n cleanupOne();\n const step = steps[idx];\n if (!step) {\n finish({ skipped: false, lastStepIdx: idx - 1 });\n return;\n }\n writeResumeIdx(resumeKey, idx);\n\n const selector = step.anchor_web;\n let anchor: Element | null = null;\n if (selector) {\n try {\n anchor = document.querySelector(selector);\n } catch {\n anchor = null;\n }\n }\n // Silent-anchor footgun: this step declared an anchor but it isn't on the\n // page, so the tip renders centered (below) instead of pointing at the\n // target — and the operator's impression metrics still look healthy. Stamp\n // `anchor_resolved: false` on the per-step impression and emit a dedicated\n // `anchor_unresolved` event so the misconfiguration is visible. On native\n // apps the same `anchor_*` key must be registered via registerInAppAnchor()\n // and adding a new one needs an app release.\n const anchorUnresolved = !!selector && !anchor;\n if (anchorUnresolved) {\n console.warn(\n `[AegisInApp] Coachmark step ${idx} anchor \"${selector}\" not found on this surface — rendering centered fallback.`,\n );\n trackEvent(campaign.id, 'anchor_unresolved', {\n stepId: `step_${idx}`,\n meta: { anchor_resolved: false, anchor_selector: selector, widget_type: 'coachmark_tour' },\n });\n }\n // P3 — per-step impression so the funnel-drop-off report can\n // distinguish \"made it to step N\" from \"made it to step N+1\".\n // Idx 0 still fires alongside the tour-level impression on mount\n // (line 100); downstream dedup on (campaign_id, step_id, contact_id)\n // collapses repeat fires within a step's display.\n trackEvent(campaign.id, 'impression', {\n stepId: `step_${idx}`,\n ...(anchorUnresolved ? { meta: { anchor_resolved: false } } : {}),\n });\n // A step whose anchor can't be resolved (the target isn't on this page\n // yet, or we're rendering in an isolated preview frame) still shows its\n // guidance — centered, over a dim scrim — instead of being silently\n // skipped. The tour stays interactive everywhere.\n const anchorRect = anchor ? anchor.getBoundingClientRect() : null;\n highlightEl = document.createElement('div');\n highlightEl.className = 'aegis-in-app-coachmark-highlight';\n if (anchorRect) {\n // Masked spotlight cutout around the anchor so the user's eye snaps to it.\n // spotlight = bright ring + accent glow + a strong configurable dim; ring\n // = the legacy thin ring + lighter dim.\n const shadow = spotlight\n ? `0 0 0 3px rgba(255,255,255,0.92), 0 0 0 7px ${bg}66, 0 0 0 9999px ${dimColor}`\n : `0 0 0 2px ${fg}, 0 0 0 9999px rgba(0,0,0,${spotDim})`;\n highlightEl.style.cssText = `\n position: fixed;\n top: ${anchorRect.top - spotPad}px; left: ${anchorRect.left - spotPad}px;\n width: ${anchorRect.width + spotPad * 2}px; height: ${anchorRect.height + spotPad * 2}px;\n border-radius: ${spotlight ? spotRadius : '10px'}; z-index: 999998;\n box-shadow: ${shadow};\n pointer-events: none;\n transition: all 0.2s ease;\n `;\n } else {\n // No anchor → a plain dim scrim behind the centered tip.\n highlightEl.style.cssText = `\n position: fixed; inset: 0; z-index: 999998;\n background: ${dimColor}; pointer-events: none;\n `;\n }\n document.body.appendChild(highlightEl);\n\n const placement = step.placement || 'bottom';\n tipEl = document.createElement('div');\n tipEl.className = 'aegis-in-app-coachmark-tip';\n tipEl.setAttribute('data-campaign-id', campaign.id);\n tipEl.style.cssText = `\n position: fixed; z-index: 999999;\n background: ${bg}; color: ${fg};\n padding: 12px 14px; border-radius: 12px;\n max-width: 260px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.25);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisFadeIn 0.2s ease;\n `;\n\n const titleEl = document.createElement('div');\n titleEl.textContent = step.title;\n titleEl.style.cssText = 'font-weight: 700; font-size: 13px; margin-bottom: 4px;';\n tipEl.appendChild(titleEl);\n\n const bodyEl = document.createElement('div');\n bodyEl.textContent = step.body;\n bodyEl.style.cssText = 'font-size: 12.5px; line-height: 1.4; opacity: 0.9;';\n tipEl.appendChild(bodyEl);\n\n const controls = document.createElement('div');\n controls.style.cssText = 'display: flex; align-items: center; justify-content: space-between; margin-top: 10px; gap: 8px;';\n\n // Dots\n if (showDots) {\n const dots = document.createElement('div');\n dots.style.cssText = 'display: flex; gap: 4px;';\n steps.forEach((_, i) => {\n const d = document.createElement('span');\n d.style.cssText = `\n width: 5px; height: 5px; border-radius: 999px;\n background: ${fg}; opacity: ${i === idx ? '0.95' : '0.3'};\n `;\n dots.appendChild(d);\n });\n controls.appendChild(dots);\n } else {\n controls.appendChild(document.createElement('span'));\n }\n\n const buttons = document.createElement('div');\n buttons.style.cssText = 'display: flex; gap: 6px;';\n\n // Back — step navigation was forward-only (Next/Skip); a multi-step tour\n // needs to let the user return to a prior step.\n if (idx > 0) {\n const back = document.createElement('button');\n back.textContent = 'Back';\n back.style.cssText = `\n background: transparent; color: inherit; opacity: 0.7;\n border: none; font-size: 12px; cursor: pointer; padding: 6px 8px;\n `;\n back.addEventListener('click', () => showStep(idx - 1));\n buttons.appendChild(back);\n }\n\n if (allowSkip && idx < steps.length - 1) {\n const skip = document.createElement('button');\n skip.textContent = 'Skip';\n skip.style.cssText = `\n background: transparent; color: inherit; opacity: 0.7;\n border: none; font-size: 12px; cursor: pointer; padding: 6px 8px;\n `;\n skip.addEventListener('click', () => finish({ skipped: true, lastStepIdx: idx }));\n buttons.appendChild(skip);\n }\n\n const next = document.createElement('button');\n const isLast = idx === steps.length - 1;\n next.textContent = step.cta_text || (isLast ? 'Done' : 'Next');\n next.style.cssText = `\n background: ${fg}; color: ${bg};\n border: none; padding: 6px 12px; border-radius: 999px;\n font-size: 12px; font-weight: 700; cursor: pointer;\n `;\n next.addEventListener('click', () => {\n if (isLast) {\n finish({ skipped: false, lastStepIdx: idx });\n } else {\n showStep(idx + 1);\n }\n });\n buttons.appendChild(next);\n\n controls.appendChild(buttons);\n tipEl.appendChild(controls);\n document.body.appendChild(tipEl);\n\n // Position after insertion so we know the tip's own dimensions.\n const tipRect = tipEl.getBoundingClientRect();\n const margin = 12;\n let top: number;\n let left: number;\n if (anchorRect) {\n top = anchorRect.bottom + margin;\n left = anchorRect.left;\n if (placement === 'top') {\n top = anchorRect.top - tipRect.height - margin;\n } else if (placement === 'left') {\n top = anchorRect.top;\n left = anchorRect.left - tipRect.width - margin;\n } else if (placement === 'right') {\n top = anchorRect.top;\n left = anchorRect.right + margin;\n }\n } else {\n // Centered fallback (no anchor).\n top = (window.innerHeight - tipRect.height) / 2;\n left = (window.innerWidth - tipRect.width) / 2;\n }\n // Clamp to viewport.\n top = Math.max(8, Math.min(window.innerHeight - tipRect.height - 8, top));\n left = Math.max(8, Math.min(window.innerWidth - tipRect.width - 8, left));\n tipEl.style.top = `${top}px`;\n tipEl.style.left = `${left}px`;\n };\n\n showStep(current);\n\n // If the host page unloads mid-tour, leave the current index persisted so\n // the next session resumes from there. Nothing else to do — writeResumeIdx\n // was called in showStep.\n // Expose a cancel hook so app code can reset the tour from Dev Tools etc.\n (window as unknown as { aegisResetTour?: (key: string) => void }).aegisResetTour = (key: string) => clearResume(key);\n}\n","/**\n * ProductRecommendation renderer — personalized product grid/row rendered\n * from `interactive_config.cards[]` that the cell-plane populated at\n * bundle-assembly time. The SDK never calls a product-API at render\n * time — the preload contract is that the recommended products are\n * already in the bundle.\n *\n * The layout is narrower than the generic carousel because product recs\n * should feel like a first-class product grid, not a marketing slider.\n * Two layouts: grid (2-col responsive) and row (horizontal-scroll).\n *\n * interactive_config:\n * rec_source?: 'similar_items' | 'also_viewed' | 'also_purchased' | 'trending'\n * | 'personalized' | 'manual'\n * (metadata only — the actual product list is in `cards[]`)\n * rec_count?: number (display hint; rendering is driven by cards.length)\n * rec_layout?: 'grid' | 'row' default 'grid'\n * rec_cta_text?: string default 'Shop now'\n * cards: Array<{ image_url?, title?, body?, cta_url?, metadata? }>\n */\n\nimport type { RenderContext } from './types';\n\ntype Card = {\n image_url?: string;\n title?: string;\n body?: string;\n cta_text?: string;\n cta_url?: string;\n metadata?: Record<string, unknown>;\n};\n\nconst MAX_PRODUCTS = 24;\n\nexport function renderProductRecommendation(ctx: RenderContext): void {\n const { campaign, trackEvent, sanitizeUrl, sanitizeColor, log, addAnimationStyles } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n\n const rawCards = Array.isArray(ic.cards) ? (ic.cards as Card[]) : [];\n const cards = rawCards.slice(0, MAX_PRODUCTS);\n if (cards.length === 0) {\n log('product_recommendation rendered with zero products — skipping', 'warn');\n return;\n }\n\n const layout = (ic.rec_layout as string) || 'grid';\n const ctaDefault = (ic.rec_cta_text as string) || 'Shop now';\n\n addAnimationStyles();\n\n // Commerce surface pattern: the product SHEET stays a clean NEUTRAL canvas\n // (saturated brand colour fights product photos), and the BRAND accent\n // (operator's background_color — the same hue the promo widgets fill with) is\n // applied to the emphasis elements (CTA / price / dots / badge) so it still\n // reads on-brand. accent falls back to brand blue when none is set.\n const bg = '#ffffff';\n const fg = '#0f172a';\n const accent = sanitizeColor((campaign.background_color as string) || '#4169e1');\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-product-rec';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText = `\n position: fixed; inset: 0;\n background: rgba(15,23,42,0.55); backdrop-filter: blur(4px);\n display: flex; align-items: flex-end; justify-content: center;\n z-index: 99999; animation: aegisFadeIn 0.25s ease;\n `;\n\n const sheet = document.createElement('div');\n sheet.style.cssText = `\n background: ${bg}; color: ${fg};\n max-width: 560px; width: 100%; max-height: 80vh; overflow-y: auto;\n border-radius: 20px 20px 0 0;\n padding: 18px 16px 22px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n box-shadow: 0 -12px 30px rgba(0,0,0,0.12);\n `;\n\n // Drag handle (decorative, for mobile context)\n const handle = document.createElement('div');\n handle.style.cssText = `\n width: 36px; height: 4px; border-radius: 999px; background: ${fg}1f;\n margin: 0 auto 12px;\n `;\n sheet.appendChild(handle);\n\n const header = document.createElement('div');\n header.style.cssText = 'display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;';\n\n const headerText = document.createElement('div');\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-weight: 700; font-size: 16px; margin-bottom: 2px;';\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.7; line-height: 1.4;';\n headerText.appendChild(title);\n headerText.appendChild(body);\n header.appendChild(headerText);\n\n const close = document.createElement('button');\n close.textContent = '✕';\n close.setAttribute('aria-label', 'Close');\n close.style.cssText = `\n background: transparent; border: none; color: inherit;\n font-size: 18px; cursor: pointer; padding: 4px 8px; opacity: 0.7;\n `;\n close.addEventListener('click', () => {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n });\n header.appendChild(close);\n sheet.appendChild(header);\n\n const grid = document.createElement('div');\n if (layout === 'row') {\n grid.style.cssText = `\n display: flex; gap: 10px; overflow-x: auto;\n scroll-snap-type: x mandatory; padding: 14px 0 4px;\n `;\n } else {\n grid.style.cssText = `\n display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;\n padding-top: 14px;\n `;\n }\n\n cards.forEach((c) => {\n const tile = document.createElement('div');\n const isRow = layout === 'row';\n tile.style.cssText = `\n background: ${fg}08; border-radius: 12px;\n padding: 10px; display: flex; flex-direction: column; gap: 6px;\n cursor: ${c.cta_url ? 'pointer' : 'default'};\n ${isRow ? 'flex: 0 0 150px; scroll-snap-align: start;' : ''}\n transition: transform 0.15s ease;\n `;\n\n if (c.image_url) {\n const img = document.createElement('img');\n const safe = sanitizeUrl(c.image_url);\n if (safe) {\n img.src = safe;\n img.alt = '';\n img.loading = 'lazy';\n img.style.cssText = 'width: 100%; aspect-ratio: 1 / 1; border-radius: 8px; object-fit: cover;';\n tile.appendChild(img);\n }\n }\n\n if (c.title) {\n const t = document.createElement('div');\n t.textContent = c.title;\n t.style.cssText = 'font-weight: 600; font-size: 13px; line-height: 1.3;';\n tile.appendChild(t);\n }\n\n // Price lives in metadata.price; an optional metadata.compare_at_price shows\n // the original (strikethrough) + a discount badge — the standard rec pattern.\n const meta = c.metadata && typeof c.metadata === 'object' ? (c.metadata as Record<string, unknown>) : {};\n const price = meta.price;\n const compareAt = meta.compare_at_price ?? meta.compare_at ?? meta.original_price;\n if (price !== undefined) {\n const priceRow = document.createElement('div');\n priceRow.style.cssText = 'display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;';\n const p = document.createElement('span');\n p.textContent = String(price);\n p.style.cssText = `color: ${accent}; font-weight: 700; font-size: 13px;`;\n priceRow.appendChild(p);\n const pNum = parseFloat(String(price).replace(/[^0-9.]/g, ''));\n const cNum = compareAt !== undefined ? parseFloat(String(compareAt).replace(/[^0-9.]/g, '')) : NaN;\n if (isFinite(cNum) && isFinite(pNum) && cNum > pNum) {\n const orig = document.createElement('span');\n orig.textContent = String(compareAt);\n orig.style.cssText = 'text-decoration: line-through; opacity: 0.5; font-size: 11px;';\n priceRow.appendChild(orig);\n const off = document.createElement('span');\n off.textContent = `-${Math.round((1 - pNum / cNum) * 100)}%`;\n off.style.cssText = 'background: #ef444422; color: #ef4444; font-weight: 700; font-size: 10px; padding: 1px 5px; border-radius: 999px;';\n priceRow.appendChild(off);\n }\n tile.appendChild(priceRow);\n } else if (c.body) {\n const b = document.createElement('div');\n b.textContent = c.body;\n b.style.cssText = 'font-size: 11.5px; opacity: 0.72; line-height: 1.3;';\n tile.appendChild(b);\n }\n\n const cta = document.createElement('button');\n cta.className = 'aegis-cta';\n cta.textContent = c.cta_text || ctaDefault;\n cta.style.cssText = `\n margin-top: auto;\n background: ${accent}; color: #fff;\n border: none; padding: 7px 10px; border-radius: 999px;\n font-size: 12px; font-weight: 600; cursor: pointer;\n `;\n const go = (e: Event) => {\n e.stopPropagation();\n trackEvent(campaign.id, 'clicked');\n if (c.cta_url) {\n const safe = sanitizeUrl(c.cta_url);\n if (safe) window.location.href = safe;\n }\n };\n cta.addEventListener('click', go);\n tile.appendChild(cta);\n if (c.cta_url) tile.addEventListener('click', go);\n\n grid.appendChild(tile);\n });\n\n sheet.appendChild(grid);\n overlay.appendChild(sheet);\n\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) {\n trackEvent(campaign.id, 'dismissed');\n overlay.remove();\n }\n });\n\n document.body.appendChild(overlay);\n}\n","/**\n * Stories renderer — Instagram/Plotline-style stories, in two surfaces:\n *\n * 1. LAUNCHER BAR (the collapsed entry) — a horizontal row of story-GROUP\n * thumbnails. Each group is one bubble (circular gradient ring OR\n * rectangular cover card) with a title + cover; tapping it opens the\n * player and plays that group's FRAMES in sequence. Renders inline in a\n * `[data-aegis-slot]` anchor (the embedded widget, Plotline-parity).\n * 2. PLAYER — full-screen tap-through. tap RIGHT → next frame · tap LEFT →\n * previous · press-and-hold → pause · segmented progress fills per frame ·\n * ✕ / Esc closes · ←/→ navigate.\n *\n * Data shape (interactive_config):\n * stories: Array<{ id?, title?, cover_image_url?, frames: Frame[] }> // GROUPS\n * Frame: { image_url?, video_url?, title?, body?, cta_text?, cta_url?, cta_target?, duration_ms? }\n * stories_thumbnail_shape?: 'circle' | 'rectangle'\n * stories_ring_style?: 'brand' | 'instagram' | 'custom' // default brand\n * stories_ring_color?: string // for 'custom'\n * stories_autoplay?: boolean · stories_loop?: boolean · stories_show_progress?: boolean\n * stories_default_duration_ms?: number\n * surface_style?: 'clean' | 'branded' // branded → brand-fill launcher bar\n *\n * A flat `stories: Frame[]` (pre-groups shape) is tolerated — treated as one group.\n */\n\nimport type { RenderContext } from './types';\n\ntype Frame = {\n image_url?: string;\n video_url?: string;\n title?: string;\n body?: string;\n cta_text?: string;\n cta_url?: string;\n duration_ms?: number;\n};\n\ntype Group = {\n id?: string;\n title?: string;\n cover_image_url?: string;\n frames: Frame[];\n};\n\ntype StoriesConfig = {\n groups: Group[];\n thumbnailShape: 'circle' | 'rectangle';\n ringBg: string;\n ringBgLinear: string;\n branded: boolean;\n brand: string;\n autoplay: boolean;\n loop: boolean;\n showProgress: boolean;\n defaultDuration: number;\n reduceMotion: boolean;\n};\n\nconst MAX_GROUPS = 12;\nconst MAX_FRAMES = 20;\nconst DEFAULT_DURATION_MS = 5000;\nconst TAP_MAX_MS = 220;\n\n// Per-frame fallback gradients so a frame with no image still looks designed.\nconst FRAME_GRADIENTS = [\n 'linear-gradient(160deg, #6366f1, #a855f7)',\n 'linear-gradient(160deg, #ec4899, #f43f5e)',\n 'linear-gradient(160deg, #0ea5e9, #22d3ee)',\n 'linear-gradient(160deg, #f59e0b, #ef4444)',\n 'linear-gradient(160deg, #10b981, #14b8a6)',\n 'linear-gradient(160deg, #8b5cf6, #6366f1)',\n];\nconst frameGradient = (i: number): string => FRAME_GRADIENTS[i % FRAME_GRADIENTS.length];\n\n// The Instagram story ring (gradient sweep).\nconst RING_GRADIENT_IG =\n 'conic-gradient(from 0deg, #feda75, #fa7e1e, #d62976, #962fbf, #4f5bd5, #feda75)';\n// Brand / custom ring — a light+dark sweep of the chosen colour so the rotation\n// animation reads (a flat colour wouldn't appear to spin). color-mix is broadly\n// supported; if unsupported the browser falls back to the base colour stop.\nconst sheenRing = (c: string): string =>\n `conic-gradient(from 0deg, ${c}, color-mix(in srgb, ${c} 50%, #ffffff), ${c}, color-mix(in srgb, ${c} 72%, #000000), ${c})`;\n\n// LINEAR variants for RECTANGLE cards. A conic gradient is for the rotating\n// CIRCLE ring; rectangles must NOT rotate (a spinning square reads as broken),\n// so they use a linear gradient that shimmers via `background-position` instead.\nconst RING_GRADIENT_IG_LINEAR =\n 'linear-gradient(110deg, #feda75, #fa7e1e, #d62976, #962fbf, #4f5bd5, #feda75)';\nconst sheenRingLinear = (c: string): string =>\n `linear-gradient(110deg, ${c}, color-mix(in srgb, ${c} 50%, #ffffff), ${c}, color-mix(in srgb, ${c} 72%, #000000), ${c})`;\n\n// Normalise to GROUPS — accept the groups shape, or a flat frame array (legacy)\n// treated as a single group.\nfunction normalizeGroups(raw: unknown): Group[] {\n if (!Array.isArray(raw) || raw.length === 0) return [];\n const first = raw[0] as Record<string, unknown> | undefined;\n if (first && Array.isArray((first as { frames?: unknown }).frames)) {\n return (raw as Group[])\n .slice(0, MAX_GROUPS)\n .map((g) => ({ ...g, frames: (g.frames || []).slice(0, MAX_FRAMES) }))\n .filter((g) => g.frames.length > 0);\n }\n return [{ frames: (raw as Frame[]).slice(0, MAX_FRAMES) }];\n}\n\nfunction readConfig(ctx: RenderContext): StoriesConfig | null {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const groups = normalizeGroups(ic.stories);\n if (groups.length === 0) {\n ctx.log('stories rendered with zero groups — skipping', 'warn');\n return null;\n }\n const brand = ctx.sanitizeColor((ctx.campaign.background_color as string) || '#4169e1');\n const ringStyle = (ic.stories_ring_style as string) || 'brand';\n let ringBg: string;\n let ringBgLinear: string;\n if (ringStyle === 'instagram') {\n ringBg = RING_GRADIENT_IG;\n ringBgLinear = RING_GRADIENT_IG_LINEAR;\n } else if (ringStyle === 'custom') {\n const c = ctx.sanitizeColor((ic.stories_ring_color as string) || brand);\n ringBg = sheenRing(c);\n ringBgLinear = sheenRingLinear(c);\n } else {\n ringBg = sheenRing(brand);\n ringBgLinear = sheenRingLinear(brand);\n }\n\n return {\n groups,\n thumbnailShape: ic.stories_thumbnail_shape === 'rectangle' ? 'rectangle' : 'circle',\n ringBg,\n ringBgLinear,\n branded: (ic.surface_style as string) === 'branded',\n brand,\n autoplay: ic.stories_autoplay !== false,\n loop: ic.stories_loop === true,\n showProgress: ic.stories_show_progress !== false,\n defaultDuration: Number(ic.stories_default_duration_ms) || DEFAULT_DURATION_MS,\n reduceMotion:\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches,\n };\n}\n\n/** Overlay entry — a stories campaign delivered as an OVERLAY is a full-screen\n * takeover; open at the first group and auto-advance through every group. */\nexport function renderStories(ctx: RenderContext): void {\n const cfg = readConfig(ctx);\n if (!cfg) return;\n ctx.addAnimationStyles();\n injectStoryStyles();\n openViewer(ctx, cfg, 0, 0);\n}\n\n/** Slot/embedded entry — the inline launcher bar of group thumbnails. */\nexport function renderStoriesRings(ctx: RenderContext, target: HTMLElement | null): boolean {\n const cfg = readConfig(ctx);\n if (!cfg) return false;\n ctx.addAnimationStyles();\n injectStoryStyles();\n renderLauncherBar(ctx, cfg, target);\n return true;\n}\n\n// ── Launcher bar (collapsed entry) ─────────────────────────────────────────\nfunction renderLauncherBar(ctx: RenderContext, cfg: StoriesConfig, target: HTMLElement | null): void {\n const { campaign } = ctx;\n const floating = !target;\n const labelColor = cfg.branded ? '#ffffff' : '#334155';\n\n const bar = document.createElement('div');\n bar.className = 'aegis-in-app-stories-tray';\n bar.setAttribute('data-campaign-id', campaign.id);\n // Generous left padding so the first bubble never kisses the edge; scroll\n // padding keeps it clear when scrolled too.\n const surfaceBg = cfg.branded\n ? cfg.brand\n : floating\n ? 'rgba(255,255,255,0.96)'\n : 'transparent';\n bar.style.cssText = floating\n ? `\n position: fixed; left: 0; right: 0; bottom: 0; z-index: 99998;\n display: flex; gap: 16px; align-items: flex-start; overflow-x: auto;\n padding: 14px 18px 16px 20px; scroll-padding-left: 20px;\n background: ${surfaceBg}; backdrop-filter: blur(8px);\n box-shadow: 0 -4px 16px rgba(0,0,0,0.08); scrollbar-width: none;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInFromBottom 0.3s ease-out;\n `\n : `\n display: flex; gap: 16px; align-items: flex-start; overflow-x: auto;\n padding: 12px 18px 12px 18px; scroll-padding-left: 18px;\n background: ${surfaceBg}; ${cfg.branded ? 'border-radius: 16px;' : ''}\n scrollbar-width: none;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n\n cfg.groups.forEach((g, i) => bar.appendChild(buildGroupBubble(ctx, cfg, g, i, labelColor)));\n\n if (floating) {\n const dismiss = document.createElement('button');\n dismiss.type = 'button';\n dismiss.textContent = '✕';\n dismiss.setAttribute('aria-label', 'Dismiss stories');\n dismiss.style.cssText = `\n flex: 0 0 auto; align-self: center; margin-left: auto;\n width: 28px; height: 28px; border: none; border-radius: 999px;\n background: ${cfg.branded ? 'rgba(255,255,255,0.18)' : 'rgba(0,0,0,0.06)'};\n color: ${cfg.branded ? '#fff' : '#475569'}; font-size: 14px; cursor: pointer;\n `;\n dismiss.addEventListener('click', () => {\n ctx.trackEvent(campaign.id, 'dismissed');\n bar.remove();\n });\n bar.appendChild(dismiss);\n }\n\n if (target) target.appendChild(bar);\n else document.body.appendChild(bar);\n}\n\nfunction groupCover(g: Group): { img: string | null; index: number } {\n if (g.cover_image_url) return { img: g.cover_image_url, index: 0 };\n const firstWithImg = g.frames.findIndex((f) => f.image_url);\n if (firstWithImg >= 0) return { img: g.frames[firstWithImg].image_url || null, index: firstWithImg };\n return { img: null, index: 0 };\n}\n\nfunction buildGroupBubble(\n ctx: RenderContext,\n cfg: StoriesConfig,\n g: Group,\n i: number,\n labelColor: string,\n): HTMLElement {\n const rectangle = cfg.thumbnailShape === 'rectangle';\n const title = g.title || g.frames[0]?.title || `Story ${i + 1}`;\n const cover = groupCover(g);\n const safeImg = cover.img ? ctx.sanitizeUrl(cover.img) : null;\n const grad = frameGradient(i);\n\n const wrap = document.createElement('button');\n wrap.type = 'button';\n wrap.setAttribute('aria-label', `Open ${title} (${g.frames.length} frames)`);\n wrap.style.cssText =\n 'flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 5px; border: none; background: transparent; cursor: pointer; padding: 0;';\n\n if (rectangle) {\n const cardWrap = document.createElement('div');\n // Rectangle cards must NOT rotate (a spinning square reads as broken). Use a\n // LINEAR gradient border that shimmers via background-position — a gentle\n // left↔right sheen, never a rotation. Static gradient when reduced-motion.\n cardWrap.style.cssText = `\n width: 92px; height: 124px; border-radius: 14px; padding: 2.5px;\n background: ${cfg.ringBgLinear}; background-size: 220% 100%; background-position: 0% 50%;\n ${cfg.reduceMotion ? '' : 'animation: aegisStoryShimmer 3s ease-in-out infinite;'}\n `;\n const card = document.createElement('div');\n card.style.cssText = `\n position: relative; width: 100%; height: 100%; border-radius: 12px; overflow: hidden;\n background: ${grad}; display: flex; align-items: flex-end;\n `;\n if (safeImg) {\n const img = document.createElement('img');\n img.src = safeImg; img.alt = '';\n img.style.cssText = 'position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;';\n card.appendChild(img);\n }\n const scrim = document.createElement('div');\n scrim.style.cssText = 'position: absolute; inset: 0; background: linear-gradient(to top, rgba(0,0,0,0.6), rgba(0,0,0,0) 55%);';\n card.appendChild(scrim);\n const t = document.createElement('div');\n t.textContent = title;\n t.style.cssText = 'position: relative; z-index: 1; padding: 7px 8px; color: #fff; font-size: 11px; font-weight: 700; line-height: 1.2; text-shadow: 0 1px 4px rgba(0,0,0,0.5);';\n card.appendChild(t);\n cardWrap.appendChild(card);\n wrap.appendChild(cardWrap);\n wrap.addEventListener('click', () => openViewer(ctx, cfg, i, 0));\n return wrap;\n }\n\n const ringBox = document.createElement('div');\n ringBox.style.cssText = 'position: relative; width: 66px; height: 66px;';\n const ring = document.createElement('div');\n ring.style.cssText = `\n position: absolute; inset: 0; border-radius: 50%; background: ${cfg.ringBg};\n ${cfg.reduceMotion ? '' : 'animation: aegisStoryRing 4s linear infinite;'}\n `;\n ringBox.appendChild(ring);\n const gap = document.createElement('div');\n gap.style.cssText = `position: absolute; inset: 3px; border-radius: 50%; background: ${cfg.branded ? cfg.brand : '#fff'};`;\n ringBox.appendChild(gap);\n const thumb = document.createElement('div');\n thumb.style.cssText = `position: absolute; inset: 5px; border-radius: 50%; overflow: hidden; background: ${grad}; display: flex; align-items: center; justify-content: center;`;\n if (safeImg) {\n const img = document.createElement('img');\n img.src = safeImg; img.alt = '';\n img.style.cssText = 'width: 100%; height: 100%; object-fit: cover;';\n thumb.appendChild(img);\n } else {\n const initial = document.createElement('span');\n initial.textContent = title.trim().charAt(0).toUpperCase();\n initial.style.cssText = 'color: #fff; font-weight: 800; font-size: 22px; text-shadow: 0 1px 4px rgba(0,0,0,0.25);';\n thumb.appendChild(initial);\n }\n ringBox.appendChild(thumb);\n wrap.appendChild(ringBox);\n\n const label = document.createElement('span');\n label.textContent = title;\n label.style.cssText = `max-width: 70px; font-size: 11px; color: ${labelColor}; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;`;\n wrap.appendChild(label);\n\n wrap.addEventListener('click', () => openViewer(ctx, cfg, i, 0));\n return wrap;\n}\n\n// ── Player (full-screen) ───────────────────────────────────────────────────\n// Group-aware: plays the starting group's frames, then auto-advances to the\n// NEXT group (Instagram-style continuous playback) until the last group ends.\nfunction openViewer(ctx: RenderContext, cfg: StoriesConfig, startGroupIndex: number, startFrameIndex = 0): void {\n const { campaign, trackEvent, sanitizeUrl, log } = ctx;\n const { loop, autoplay, showProgress, defaultDuration, reduceMotion } = cfg;\n const groups = cfg.groups;\n if (groups.length === 0) return;\n let gIdx = Math.max(0, Math.min(startGroupIndex, groups.length - 1));\n let frames = groups[gIdx].frames;\n log(`stories viewer open @ group ${gIdx}`);\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-stories-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.setAttribute('role', 'dialog');\n overlay.setAttribute('aria-label', campaign.title || 'Stories');\n overlay.style.cssText = `\n position: fixed; inset: 0; z-index: 100000; background: #000;\n display: flex; align-items: center; justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisFadeIn 0.25s ease;\n `;\n\n const stage = document.createElement('div');\n stage.style.cssText = 'position: relative; width: 100%; height: 100%; max-width: 440px; max-height: 100vh; background: #111; overflow: hidden;';\n overlay.appendChild(stage);\n\n const frameLayer = document.createElement('div');\n frameLayer.style.cssText = 'position: absolute; inset: 0;';\n stage.appendChild(frameLayer);\n\n // Progress row is REBUILT per group (each group has its own frame count).\n const progressRow = document.createElement('div');\n progressRow.style.cssText = 'position: absolute; top: 0; left: 0; right: 0; z-index: 4; display: flex; gap: 4px; padding: 10px 10px 0;';\n stage.appendChild(progressRow);\n let bars: HTMLElement[] = [];\n const buildBars = (): void => {\n progressRow.replaceChildren();\n bars = [];\n if (!showProgress) return;\n frames.forEach(() => {\n const track = document.createElement('div');\n track.style.cssText = 'flex: 1; height: 2.5px; border-radius: 999px; background: rgba(255,255,255,0.32); overflow: hidden;';\n const fill = document.createElement('div');\n fill.style.cssText = 'width: 0%; height: 100%; background: #fff; border-radius: 999px;';\n track.appendChild(fill);\n progressRow.appendChild(track);\n bars.push(fill);\n });\n };\n\n const close = document.createElement('button');\n close.type = 'button';\n close.textContent = '✕';\n close.setAttribute('aria-label', 'Close');\n close.style.cssText = 'position: absolute; top: 12px; right: 10px; z-index: 5; width: 34px; height: 34px; border: none; border-radius: 999px; background: rgba(0,0,0,0.32); color: #fff; font-size: 18px; cursor: pointer; display: flex; align-items: center; justify-content: center; line-height: 1;';\n stage.appendChild(close);\n\n let idx = startFrameIndex;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let rafId: number | null = null;\n let frameStart = 0;\n let elapsedBeforePause = 0;\n let paused = false;\n let currentVideo: HTMLVideoElement | null = null;\n const seen = new Set<string>();\n\n const clearTimers = () => {\n if (timer) { clearTimeout(timer); timer = null; }\n if (rafId !== null) { cancelAnimationFrame(rafId); rafId = null; }\n };\n let completionFired = false;\n const teardown = (reason: 'dismissed' | 'completed') => {\n clearTimers();\n document.removeEventListener('keydown', onKey);\n if (reason === 'dismissed') {\n trackEvent(campaign.id, 'dismissed');\n } else if (!completionFired) {\n // Watched to the end — engagement-funnel + timeline signal (no reward).\n completionFired = true;\n void ctx.submitResponse?.('story_complete', { groups: cfg.groups.length });\n }\n overlay.remove();\n };\n const frameDuration = (i: number): number => {\n const d = Number(frames[i]?.duration_ms);\n return d >= 1000 ? d : defaultDuration;\n };\n const tickProgress = () => {\n if (!showProgress || paused) return;\n const dur = frameDuration(idx);\n const elapsed = elapsedBeforePause + (Date.now() - frameStart);\n const pct = Math.max(0, Math.min(100, (elapsed / dur) * 100));\n if (bars[idx]) bars[idx].style.width = `${pct}%`;\n if (pct < 100) rafId = requestAnimationFrame(tickProgress);\n };\n const scheduleAdvance = () => {\n if (!autoplay) return;\n const remaining = frameDuration(idx) - elapsedBeforePause;\n frameStart = Date.now();\n timer = setTimeout(() => advance(1), Math.max(0, remaining));\n if (showProgress && !reduceMotion) rafId = requestAnimationFrame(tickProgress);\n else if (showProgress && bars[idx]) bars[idx].style.width = '0%';\n };\n const paintBarsUpTo = (active: number) => {\n if (!showProgress) return;\n bars.forEach((b, i) => { b.style.width = i < active ? '100%' : '0%'; });\n };\n\n const renderFrame = (i: number): void => {\n const f = frames[i];\n frameLayer.replaceChildren();\n currentVideo = null;\n const safeVideo = f.video_url ? sanitizeUrl(f.video_url) : null;\n const safeImage = f.image_url ? sanitizeUrl(f.image_url) : null;\n if (safeVideo) {\n const vid = document.createElement('video');\n vid.src = safeVideo;\n vid.muted = true; vid.loop = true; vid.autoplay = true; vid.playsInline = true;\n vid.setAttribute('playsinline', '');\n vid.style.cssText = 'position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;';\n frameLayer.appendChild(vid);\n currentVideo = vid;\n void vid.play?.().catch(() => {});\n } else if (safeImage) {\n const img = document.createElement('img');\n img.src = safeImage; img.alt = f.title || '';\n img.style.cssText = 'position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;';\n frameLayer.appendChild(img);\n } else {\n const bgFill = document.createElement('div');\n bgFill.style.cssText = `position: absolute; inset: 0; background: ${cfg.branded ? cfg.brand : frameGradient(i)};`;\n frameLayer.appendChild(bgFill);\n }\n\n const scrim = document.createElement('div');\n scrim.style.cssText = 'position: absolute; inset: 0; pointer-events: none; background: linear-gradient(to top, rgba(0,0,0,0.72) 0%, rgba(0,0,0,0.18) 38%, rgba(0,0,0,0) 60%);';\n frameLayer.appendChild(scrim);\n\n const copy = document.createElement('div');\n copy.style.cssText = 'position: absolute; left: 0; right: 0; bottom: 0; z-index: 3; padding: 20px 18px 30px; color: #fff; text-align: left;';\n if (f.title) {\n const t = document.createElement('div');\n t.textContent = f.title;\n t.style.cssText = \"font-family: 'Inter Tight', Inter, system-ui, sans-serif; font-size: 21px; font-weight: 800; letter-spacing: -0.01em; line-height: 1.2; margin-bottom: 6px; text-shadow: 0 1px 8px rgba(0,0,0,0.4);\";\n copy.appendChild(t);\n }\n if (f.body) {\n const b = document.createElement('div');\n b.textContent = f.body;\n b.style.cssText = 'font-size: 14px; line-height: 1.45; opacity: 0.92; text-shadow: 0 1px 6px rgba(0,0,0,0.4);';\n copy.appendChild(b);\n }\n const ctaUrl = f.cta_url ? sanitizeUrl(f.cta_url) : null;\n const ctaLabel = f.cta_text || (ctaUrl ? 'Learn more' : '');\n if (ctaLabel) {\n const cta = document.createElement('button');\n cta.type = 'button';\n cta.className = 'aegis-cta';\n cta.textContent = ctaLabel;\n cta.style.cssText = 'margin-top: 14px; padding: 11px 22px; border: none; border-radius: 999px; background: #fff; color: #0f172a; font-size: 14px; font-weight: 700; cursor: pointer;';\n cta.addEventListener('pointerdown', (e) => e.stopPropagation());\n cta.addEventListener('click', (e) => {\n e.stopPropagation();\n trackEvent(campaign.id, 'clicked', { stepId: `g${gIdx}_f${i}` });\n if (ctaUrl) {\n clearTimers();\n if (ctx.navigate) ctx.navigate(ctaUrl, `g${gIdx}_f${i}`);\n else window.location.href = ctaUrl;\n }\n });\n copy.appendChild(cta);\n }\n frameLayer.appendChild(copy);\n\n const key = `${gIdx}_${i}`;\n if (!seen.has(key)) {\n seen.add(key);\n trackEvent(campaign.id, 'impression', { stepId: `g${gIdx}_f${i}` });\n }\n };\n\n const show = (i: number): void => {\n clearTimers();\n elapsedBeforePause = 0;\n paused = false;\n idx = i;\n paintBarsUpTo(i);\n renderFrame(i);\n scheduleAdvance();\n };\n\n // Move to another group (rebuilds the progress bars for its frame count).\n const loadGroup = (gi: number, startFrame: number): void => {\n gIdx = gi;\n frames = groups[gi].frames;\n buildBars();\n show(Math.max(0, Math.min(startFrame, frames.length - 1)));\n };\n\n function advance(dir: number): void {\n const next = idx + dir;\n if (next < 0) {\n // Back past the first frame → previous group's LAST frame (or stay).\n if (gIdx > 0) loadGroup(gIdx - 1, groups[gIdx - 1].frames.length - 1);\n else show(0);\n return;\n }\n if (next >= frames.length) {\n // Past the last frame → next GROUP; wrap to the first group if looping,\n // else the whole sequence is done.\n if (gIdx + 1 < groups.length) loadGroup(gIdx + 1, 0);\n else if (loop) { seen.clear(); loadGroup(0, 0); }\n else teardown('completed');\n return;\n }\n show(next);\n }\n\n const pause = () => {\n if (paused) return;\n paused = true;\n if (timer) { clearTimeout(timer); timer = null; }\n if (rafId !== null) { cancelAnimationFrame(rafId); rafId = null; }\n elapsedBeforePause += Date.now() - frameStart;\n currentVideo?.pause?.();\n };\n const resume = () => {\n if (!paused) return;\n paused = false;\n currentVideo?.play?.().catch(() => {});\n scheduleAdvance();\n };\n\n let pointerDownAt = 0;\n let pointerX = 0;\n stage.addEventListener('pointerdown', (e) => { pointerDownAt = Date.now(); pointerX = e.clientX; pause(); });\n stage.addEventListener('pointerup', () => {\n const held = Date.now() - pointerDownAt;\n if (held <= TAP_MAX_MS) {\n const rect = stage.getBoundingClientRect();\n advance(pointerX - rect.left < rect.width / 3 ? -1 : 1);\n } else resume();\n });\n stage.addEventListener('pointercancel', resume);\n stage.addEventListener('pointerleave', resume);\n\n close.addEventListener('pointerdown', (e) => e.stopPropagation());\n close.addEventListener('click', (e) => { e.stopPropagation(); teardown('dismissed'); });\n\n function onKey(e: KeyboardEvent): void {\n if (e.key === 'Escape') teardown('dismissed');\n else if (e.key === 'ArrowRight') advance(1);\n else if (e.key === 'ArrowLeft') advance(-1);\n }\n document.addEventListener('keydown', onKey);\n\n buildBars();\n document.body.appendChild(overlay);\n show(startFrameIndex);\n}\n\nfunction injectStoryStyles(): void {\n if (typeof document === 'undefined') return;\n if (document.getElementById('aegis-stories-styles')) return;\n const style = document.createElement('style');\n style.id = 'aegis-stories-styles';\n style.textContent = `\n @keyframes aegisStoryRing { to { transform: rotate(360deg); } }\n @keyframes aegisStoryShimmer { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }\n .aegis-in-app-stories-tray::-webkit-scrollbar { display: none; }\n `;\n document.head.appendChild(style);\n}\n","/**\n * Gamification renderers — the 11 locked game mechanics (2026-06-14):\n * streak · milestone · challenge · achievements · leaderboard · check_in ·\n * stamp_card · mystery_box · tier_ladder · lucky_draw · slot_machine\n *\n * All are config-authored (operator sets the values / demo state via\n * interactive_config; the serve endpoint can later enrich with the customer's\n * real streak/stamps/tier). Each reuses campaign.title/body for the heading and\n * grants its reward via `ctx.submitResponse` on the key action (claim / play /\n * reveal) + the campaign CTA via `ctx.navigate`. Dispatched from\n * AegisInAppManager.renderInteractive (these are interactive sub_types).\n */\n\nimport type { RenderContext } from './types';\n\nconst num = (v: unknown, d: number): number => { const n = Number(v); return Number.isFinite(n) ? n : d; };\nconst str = (v: unknown, d = ''): string => (typeof v === 'string' ? v : d);\nconst arr = <T = Record<string, unknown>>(v: unknown): T[] => (Array.isArray(v) ? (v as T[]) : []);\n\nfunction brandAccent(ctx: RenderContext): string {\n return ctx.sanitizeColor((ctx.campaign.background_color as string) || '#4169e1');\n}\n\ninterface GameShell {\n overlay: HTMLElement;\n card: HTMLElement;\n content: HTMLElement;\n accent: string;\n branded: boolean;\n dismiss: (track?: boolean) => void;\n ctaButton: (label: string, onClick?: () => void) => HTMLButtonElement | null;\n}\n\n// Shared centred-modal scaffold for every game (title/body header + close +\n// content area + optional accent CTA). Does NOT fire impression — the\n// renderInteractive dispatch does.\n/** One-time injection of game-specific keyframes (rattle/anticipation). The\n * shared celebration keyframes come from ctx.addAnimationStyles(). */\nfunction injectGameStyles(): void {\n if (typeof document === 'undefined' || document.getElementById('aegis-game-styles')) return;\n if (typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;\n const el = document.createElement('style');\n el.id = 'aegis-game-styles';\n el.textContent =\n '@keyframes aegisBoxRattle{0%,100%{transform:scale(1) rotate(0)}20%{transform:scale(1.05) rotate(-4deg)}40%{transform:scale(1.05) rotate(4deg)}60%{transform:scale(1.06) rotate(-3deg)}80%{transform:scale(1.06) rotate(3deg)}}' +\n // Stamp \"thunk\" — slams in oversized + rotated, settles to a hand-stamp tilt.\n '@keyframes aegisStampIn{0%{transform:scale(2.4) rotate(-20deg);opacity:0}55%{transform:scale(0.82) rotate(7deg);opacity:1}100%{transform:scale(1) rotate(-6deg);opacity:1}}' +\n // Badge unlock pop — springs up from nothing with a tiny overshoot.\n '@keyframes aegisBadgePop{0%{transform:scale(0) rotate(-12deg);opacity:0}70%{transform:scale(1.18) rotate(4deg);opacity:1}100%{transform:scale(1) rotate(0);opacity:1}}';\n document.head.appendChild(el);\n}\n\nfunction openGameModal(ctx: RenderContext, className: string, maxWidth = 360): GameShell {\n const { campaign, trackEvent, addAnimationStyles } = ctx;\n addAnimationStyles();\n injectGameStyles();\n const accent = brandAccent(ctx);\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const branded = (ic.surface_style as string) === 'branded';\n const bg = branded ? accent : '#ffffff';\n const fg = branded ? '#ffffff' : '#0f172a';\n\n const overlay = document.createElement('div');\n overlay.className = className;\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText =\n 'position:fixed;inset:0;z-index:100000;background:rgba(15,23,42,0.55);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;padding:16px;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif;animation:aegisFadeIn 0.25s ease;';\n\n const card = document.createElement('div');\n card.style.cssText = `position:relative;width:100%;max-width:${maxWidth}px;max-height:88vh;overflow-y:auto;background:${bg};color:${fg};border-radius:20px;padding:24px 20px 20px;box-shadow:0 16px 48px rgba(0,0,0,0.22);animation:aegisScaleIn 0.3s ease;text-align:center;`;\n\n let removed = false;\n const dismiss = (track = false): void => {\n if (removed) return;\n removed = true;\n if (track) trackEvent(campaign.id, 'dismissed');\n overlay.style.animation = 'aegisFadeOut 0.2s ease';\n setTimeout(() => overlay.remove(), 180);\n };\n\n const close = document.createElement('button');\n close.type = 'button';\n close.textContent = '✕';\n close.setAttribute('aria-label', 'Close');\n close.style.cssText = `position:absolute;top:10px;right:10px;width:30px;height:30px;border:none;border-radius:999px;background:${branded ? 'rgba(255,255,255,0.18)' : 'rgba(0,0,0,0.05)'};color:${branded ? '#fff' : '#475569'};font-size:15px;cursor:pointer;z-index:1;`;\n close.addEventListener('click', () => dismiss(true));\n card.appendChild(close);\n overlay.addEventListener('click', (e) => { if (e.target === overlay) dismiss(true); });\n\n if (campaign.title) {\n const t = document.createElement('div');\n t.textContent = campaign.title;\n t.style.cssText = \"font-family:'Inter Tight',Inter,system-ui,sans-serif;font-size:18px;font-weight:800;letter-spacing:-0.01em;margin:2px 24px 4px;line-height:1.25;\";\n card.appendChild(t);\n }\n if (campaign.body) {\n const b = document.createElement('div');\n b.textContent = campaign.body;\n b.style.cssText = 'font-size:13px;opacity:0.72;margin:0 6px 12px;line-height:1.4;';\n card.appendChild(b);\n }\n\n const content = document.createElement('div');\n card.appendChild(content);\n overlay.appendChild(card);\n document.body.appendChild(overlay);\n\n const ctaButton = (label: string, onClick?: () => void): HTMLButtonElement | null => {\n if (!label) return null;\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'aegis-cta';\n btn.textContent = label;\n btn.style.cssText = `margin-top:16px;width:100%;padding:12px 20px;border:none;border-radius:999px;background:${branded ? '#fff' : accent};color:${branded ? accent : '#fff'};font-size:14px;font-weight:700;cursor:pointer;`;\n btn.addEventListener('click', () => {\n trackEvent(campaign.id, 'clicked');\n if (onClick) onClick();\n const url = str(campaign.action_url);\n if (url) { if (ctx.navigate) ctx.navigate(url, 'cta'); else window.location.href = url; }\n });\n card.appendChild(btn);\n return btn;\n };\n\n return { overlay, card, content, accent, branded, dismiss, ctaButton };\n}\n\n// Small helpers for repeated bits. ALL DOM is built with textContent — NEVER\n// innerHTML — so operator config + customer data (leaderboard names, prizes,\n// merge-tags) can never inject markup/script (XSS-safe by construction).\nfunction gEl(tag: string, css: string, text?: string): HTMLElement {\n const e = document.createElement(tag);\n if (css) e.style.cssText = css;\n if (text != null) e.textContent = text;\n return e;\n}\n\n// Progress bar as a DOM node (no innerHTML).\nfunction fillBar(accent: string, pct: number, h = 8): HTMLElement {\n const track = gEl('div', `height:${h}px;border-radius:999px;background:rgba(148,163,184,0.25);overflow:hidden;margin:10px 0`);\n track.appendChild(gEl('div', `height:100%;width:${Math.max(0, Math.min(100, pct))}%;background:${accent};border-radius:999px;transition:width .5s ease`));\n return track;\n}\n\n// ── 1. Daily streak ─────────────────────────────────────────────────────────\nexport function renderStreak(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-streak');\n const count = num(ic.streak_count, 5);\n const goal = num(ic.streak_goal, count + 1);\n const reward = str(ic.streak_reward_text, 'Come back tomorrow to keep it going.');\n const days = ['M', 'T', 'W', 'T', 'F', 'S', 'S'];\n s.content.appendChild(gEl('div', 'font-size:44px;line-height:1', '🔥'));\n s.content.appendChild(gEl('div', 'font-size:22px;font-weight:800;margin:4px 0 2px', `${count}-day streak!`));\n const chips = gEl('div', 'display:flex;justify-content:center;gap:8px;margin:12px 0');\n for (let i = 0; i < 7; i++) {\n const chip = gEl('div', 'display:inline-flex;flex-direction:column;align-items:center;gap:3px;font-size:11px;opacity:0.8');\n chip.appendChild(gEl('span', '', days[i]));\n chip.appendChild(gEl('span', 'font-size:16px', i < count % 7 || (count >= 7 && i < 7) ? '✅' : i === count % 7 ? '🔥' : '⚪'));\n chips.appendChild(chip);\n }\n s.content.appendChild(chips);\n const note = gEl('div', 'font-size:13px;opacity:0.8');\n note.appendChild(document.createTextNode(reward + ' '));\n note.appendChild(gEl('b', '', `Day ${goal}`));\n note.appendChild(document.createTextNode(' unlocks a reward.'));\n s.content.appendChild(note);\n s.ctaButton(str(ic.streak_cta_text, 'Keep my streak'), () => {\n ctx.haptic?.(20);\n ctx.playReaction?.(s.card, 'affirm');\n void ctx.submitResponse?.('streak', { streak_count: count });\n });\n}\n\n// ── 2. Milestone tracker ────────────────────────────────────────────────────\nexport function renderMilestone(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-milestone');\n const unit = str(ic.milestone_unit, '');\n const cur = num(ic.milestone_current, 1200);\n const target = num(ic.milestone_target, 2000);\n const steps = arr<{ value: number; reward: string }>(ic.milestone_steps);\n const pct = target > 0 ? (cur / target) * 100 : 0;\n s.content.appendChild(gEl('div', 'font-size:13px;opacity:0.8;margin-bottom:2px', `${unit}${cur} of ${unit}${target}`));\n s.content.appendChild(fillBar(s.accent, pct));\n s.content.appendChild(gEl('div', 'font-size:13px;font-weight:600', `${unit}${Math.max(0, target - cur)} to go`));\n if (steps.length) {\n const row = gEl('div', 'display:flex;justify-content:space-between;margin-top:6px;font-size:10px;opacity:0.7');\n steps.forEach((st) => {\n const cell = gEl('span', 'display:flex;flex-direction:column;text-align:center;max-width:64px');\n cell.appendChild(gEl('span', '', `${unit}${num(st.value, 0)}`));\n cell.appendChild(gEl('span', '', str(st.reward)));\n row.appendChild(cell);\n });\n s.content.appendChild(row);\n }\n s.ctaButton(str(ic.milestone_cta_text, 'Shop now'));\n}\n\n// ── 3. Challenges / quests ──────────────────────────────────────────────────\nexport function renderChallenge(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-challenge');\n const tasks = arr<{ label: string; points?: number; done?: boolean }>(ic.challenge_tasks);\n const done = tasks.filter((t) => t.done).length;\n const pct = tasks.length ? (done / tasks.length) * 100 : 0;\n if (str(ic.challenge_deadline_text)) s.content.appendChild(gEl('div', 'font-size:12px;opacity:0.65;margin-bottom:8px', str(ic.challenge_deadline_text)));\n tasks.forEach((t) => {\n const row = gEl('div', 'display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid rgba(148,163,184,0.18);font-size:13px;text-align:left');\n row.appendChild(gEl('span', '', t.done ? '☑' : '☐'));\n row.appendChild(gEl('span', `flex:1;${t.done ? 'opacity:0.6' : ''}`, str(t.label)));\n if (t.points) row.appendChild(gEl('span', 'opacity:0.7;font-size:12px', `+${num(t.points, 0)}`));\n s.content.appendChild(row);\n });\n s.content.appendChild(fillBar(s.accent, pct));\n s.content.appendChild(gEl('div', 'font-size:13px;font-weight:600', `${done} of ${tasks.length} · ${str(ic.challenge_bonus_text, 'finish all to earn a bonus')}`));\n s.ctaButton(str(ic.challenge_cta_text, 'Continue'));\n}\n\n// ── 4. Badges / achievements ────────────────────────────────────────────────\nexport function renderAchievements(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-achievements', 380);\n const items = arr<{ label: string; icon?: string; unlocked?: boolean }>(ic.achievements_items);\n const got = items.filter((i) => i.unlocked).length;\n const reduce = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n const grid = gEl('div', 'display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:6px 0 10px');\n let unlockSeen = 0;\n items.forEach((i) => {\n const cell = gEl('div', `display:flex;flex-direction:column;align-items:center;gap:4px;padding:10px 6px;border-radius:12px;background:${i.unlocked ? s.accent + '1f' : 'rgba(148,163,184,0.12)'};${i.unlocked ? '' : 'opacity:0.55'}`);\n const icon = gEl('span', 'font-size:24px;display:inline-block', i.unlocked ? str(i.icon, '🏅') : '🔒');\n cell.appendChild(icon);\n cell.appendChild(gEl('span', 'font-size:10.5px;line-height:1.15', str(i.label)));\n if (i.unlocked && !reduce) {\n icon.style.animation = `aegisBadgePop 0.5s cubic-bezier(0.2,1.4,0.4,1) ${unlockSeen * 0.08}s both`;\n unlockSeen++;\n }\n grid.appendChild(cell);\n });\n s.content.appendChild(grid);\n s.content.appendChild(gEl('div', 'font-size:13px;font-weight:600', `${got} of ${items.length} unlocked`));\n if (str(ic.achievements_next_text)) s.content.appendChild(gEl('div', 'font-size:12px;opacity:0.7;margin-top:2px', str(ic.achievements_next_text)));\n if (got > 0 && !reduce) { ctx.haptic?.(12); ctx.playReaction?.(s.card, 'affirm'); }\n s.ctaButton(str(ctx.campaign.button_text, ''));\n}\n\n// ── 5. Leaderboard ──────────────────────────────────────────────────────────\nexport function renderLeaderboard(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-leaderboard');\n const rows = arr<{ name: string; score: number; you?: boolean }>(ic.leaderboard_rows);\n const medal = ['🥇', '🥈', '🥉'];\n if (str(ic.leaderboard_period_text)) s.content.appendChild(gEl('div', 'font-size:12px;opacity:0.65;margin-bottom:6px', str(ic.leaderboard_period_text)));\n rows.forEach((r, i) => {\n const row = gEl('div', `display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:10px;${r.you ? `background:${s.accent}14;font-weight:700` : ''};font-size:13px;text-align:left`);\n row.appendChild(gEl('span', 'width:22px', i < 3 ? medal[i] : String(i + 1)));\n // r.name is CUSTOMER data (contact first_name) — textContent makes it inert.\n row.appendChild(gEl('span', 'flex:1', str(r.name) + (r.you ? ' (You)' : '')));\n row.appendChild(gEl('span', '', num(r.score, 0).toLocaleString()));\n s.content.appendChild(row);\n });\n if (str(ic.leaderboard_gap_text)) s.content.appendChild(gEl('div', 'font-size:12.5px;opacity:0.8;margin-top:10px', str(ic.leaderboard_gap_text)));\n s.ctaButton(str(ctx.campaign.button_text, ''));\n}\n\n// ── 6. Daily check-in ───────────────────────────────────────────────────────\nexport function renderCheckIn(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-checkin', 380);\n const daysCfg = arr<{ label: string; reward: string; state?: string }>(ic.checkin_days);\n const strip = gEl('div', 'display:flex;gap:8px;overflow-x:auto;padding:6px 2px 10px;scrollbar-width:none');\n daysCfg.forEach((d) => {\n const hi = d.state === 'today';\n const cell = gEl('div', `flex:0 0 auto;width:60px;display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 4px;border-radius:12px;background:${hi ? s.accent + '1a' : 'rgba(148,163,184,0.12)'};border:1.5px solid ${hi ? s.accent : 'transparent'}`);\n cell.appendChild(gEl('span', 'font-size:11px;opacity:0.7', str(d.label)));\n cell.appendChild(gEl('span', 'font-size:18px', d.state === 'claimed' ? '✅' : hi ? '🎁' : '🔒'));\n cell.appendChild(gEl('span', 'font-size:11px;font-weight:700', str(d.reward)));\n strip.appendChild(cell);\n });\n s.content.appendChild(strip);\n const today = daysCfg.find((d) => d.state === 'today');\n s.ctaButton(str(ic.checkin_cta_text, today ? `Claim ${str(today.label)} · ${str(today.reward)}` : 'Claim'), () => {\n ctx.haptic?.([0, 20, 15, 30]);\n ctx.playReaction?.(s.card, 'celebrate', 'gift.json');\n void ctx.submitResponse?.('check_in', { day: str(today?.label), reset: str(ic.checkin_reset) || 'daily' });\n });\n}\n\n// Shared lazy AudioContext for game SFX. A short percussive \"thunk\" for a stamp\n// landing — synth, no assets. Best-effort (autoplay-policy / no-WebAudio safe).\nlet _gameAudioCtx: AudioContext | null = null;\nfunction playStampThunk(): void {\n try {\n if (typeof window === 'undefined') return;\n const Ctx = window.AudioContext || (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Ctx) return;\n if (!_gameAudioCtx) _gameAudioCtx = new Ctx();\n const ac = _gameAudioCtx;\n if (ac.state === 'suspended') void ac.resume();\n const t = ac.currentTime;\n const osc = ac.createOscillator();\n const gain = ac.createGain();\n osc.type = 'triangle';\n osc.frequency.setValueAtTime(190, t);\n osc.frequency.exponentialRampToValueAtTime(68, t + 0.12);\n gain.gain.setValueAtTime(0.0001, t);\n gain.gain.exponentialRampToValueAtTime(0.22, t + 0.006);\n gain.gain.exponentialRampToValueAtTime(0.0001, t + 0.16);\n osc.connect(gain); gain.connect(ac.destination);\n osc.start(t); osc.stop(t + 0.18);\n } catch { /* no audio — silent */ }\n}\n\n// ── 7. Stamp / punch card ───────────────────────────────────────────────────\n// A REAL punch card: each earned slot receives an INK STAMP of the brand mark\n// (the tenant logo, tinted in the brand colour + a slight hand-stamp tilt), the\n// newest one slamming in with a \"thunk\". Empty slots are dashed wells; the final\n// slot is the reward. Falls back to a check glyph when no logo is configured.\nexport function renderStampCard(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-stamp', 380);\n const total = num(ic.stamp_total, 9);\n const filled = Math.min(total, num(ic.stamp_filled, 1));\n const reduce = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n // Default to the brand logo (campaign image / background logo) — same default\n // as the scratch-card foil. Operators can override with stamp_logo_url. Only\n // sanitize a NON-EMPTY value: sanitizeUrl('') resolves to the page origin (a\n // truthy non-image URL) which would load + fail → the ✓ fallback stuck forever.\n const logoRaw = str(ic.stamp_logo_url) || str(ctx.campaign.image_url);\n const logo = logoRaw ? ctx.sanitizeUrl(logoRaw) : null;\n\n // Reward checkpoints by stamp position (1-based). Falls back to the single\n // completion reward at the last stamp, then to a plain \"free reward\" at the end.\n const rewards = arr<{ at?: number; label?: string; prize_value?: string; icon?: string }>(ic.stamp_rewards);\n const rewardAt = new Map<number, string>();\n const rewardIconAt = new Map<number, string>(); // the prize's own icon at this step\n if (rewards.length) {\n rewards.forEach((r) => {\n if (typeof r.at === 'number' && r.at >= 1 && r.at <= total) {\n rewardAt.set(r.at, str(r.label) || str(r.prize_value) || 'Reward');\n rewardIconAt.set(r.at, str(r.icon) || '🎁');\n }\n });\n } else {\n rewardAt.set(total, str((ic.stamp_reward as { label?: string } | undefined)?.label) || str(ic.stamp_reward_text) || 'Reward');\n rewardIconAt.set(total, '🎁');\n }\n\n // 3 BIG stamps per row. Each earned slot is a real GREEN INK stamp: the brand\n // mark reproduced as a single-colour emerald silhouette inside a green ring.\n const ink = '#10b981'; // emerald — same green as the Active Bill \"PAID\" stamp\n const cols = Math.min(total, 3);\n const grid = document.createElement('div');\n grid.style.cssText = `display:grid;grid-template-columns:repeat(${cols},1fr);gap:16px;margin:14px auto 16px;max-width:${cols * 110}px`;\n const logoHosts: HTMLElement[] = []; // filled-slot stamp areas to fill with the logo silhouette\n let stampOrder = 0; // stagger index across filled stamps (for the stamp-on-load)\n for (let i = 0; i < total; i++) {\n const pos = i + 1;\n const isReward = rewardAt.has(pos);\n const isFilled = i < filled;\n const slot = document.createElement('div');\n slot.title = isReward ? `Reward: ${rewardAt.get(pos)}` : '';\n slot.style.cssText = `position:relative;width:100%;aspect-ratio:1;border-radius:50%;display:flex;align-items:center;justify-content:center;overflow:visible;` +\n (isFilled\n ? `border:2.5px solid ${ink};background:${ink}14;${isReward ? `box-shadow:0 0 0 3px ${ink}55;` : ''}`\n : `border:2.5px dashed ${isReward ? ink + 'aa' : 'rgba(148,163,184,0.5)'};background:${isReward ? ink + '10' : 'transparent'};`);\n if (isFilled) {\n // The stamp area: circular, clips the logo silhouette; shows a ✓ until the\n // brand logo loads (and as the fallback if the URL is empty/blocked).\n const host = gEl('div', 'width:92%;height:92%;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;');\n host.appendChild(gEl('span', `font-size:32px;font-weight:900;color:${ink};transform:rotate(-6deg)`, '✓'));\n host.style.transform = 'rotate(-6deg) scale(1.02)';\n if (!reduce) {\n const delay = Math.min(stampOrder, 9) * 0.1;\n host.style.opacity = '0';\n host.style.animation = `aegisStampIn 0.45s cubic-bezier(0.2,1.3,0.4,1) ${delay}s both`;\n const order = stampOrder;\n window.setTimeout(() => { playStampThunk(); ctx.haptic?.(14); }, delay * 1000 + (order === 0 ? 80 : 0));\n }\n if (logo) logoHosts.push(host);\n stampOrder++;\n slot.appendChild(host);\n } else if (isReward) {\n // Unfilled reward slot → the PRIZE’s own icon (🎟/🏷/💎…), not a generic gift.\n slot.appendChild(gEl('span', 'font-size:30px', rewardIconAt.get(pos) || '🎁'));\n }\n // Reward step → a prize badge so it reads as a milestone. When the slot is\n // STAMPED, the prize icon OVERLAYS the stamp (corner badge).\n if (isReward && isFilled) {\n slot.appendChild(gEl('span', 'position:absolute;top:-3px;right:-3px;font-size:17px;line-height:1;filter:drop-shadow(0 1px 1px rgba(0,0,0,0.25))', rewardIconAt.get(pos) || '🎁'));\n }\n grid.appendChild(slot);\n }\n s.content.appendChild(grid);\n\n // Stamp every filled slot with the brand logo. NB: no `crossOrigin` — we only\n // DISPLAY the canvas, never read its pixels for OUTPUT, so it loads even from\n // hosts WITHOUT CORS headers. Forcing crossOrigin='anonymous' made the logo\n // fail to load on a no-CORS host → the ✓ fallback stuck forever (the bug).\n if (logo && logoHosts.length) {\n const im = new Image();\n im.onload = (): void => {\n // Downscale to a small master (cap the longest side) — the raw logo can be\n // multiple thousand px; cloning that into every slot is wasteful and the\n // stamp only renders ~90px. Keeps the preview snappy on re-render.\n const CAP = 160;\n const nw = im.naturalWidth || 96, nh = im.naturalHeight || 96;\n const scale = Math.min(1, CAP / Math.max(nw, nh));\n const w = Math.max(1, Math.round(nw * scale));\n const h = Math.max(1, Math.round(nh * scale));\n const master = document.createElement('canvas');\n master.width = w; master.height = h;\n const mctx = master.getContext('2d');\n if (!mctx) return;\n mctx.drawImage(im, 0, 0, w, h);\n // A TRANSPARENT logo → recolour to a clean emerald ink silhouette (the true\n // rubber-stamp look). An OPAQUE logo → keep it as-is, because a source-in\n // recolour would paint the whole rectangle a solid green blob. Detect via\n // corner-alpha; if the canvas is tainted (cross-origin, no CORS) the read\n // throws → fall back to a URL hint (the brand-kit birefnet variant is named\n // `..._transparent.png`). Either way the brand mark shows — never the ✓.\n let transparent = false;\n try {\n const corners: ReadonlyArray<readonly [number, number]> = [[0, 0], [w - 1, 0], [0, h - 1], [w - 1, h - 1]];\n transparent = corners.some(([x, y]) => mctx.getImageData(x, y, 1, 1).data[3] < 16);\n } catch { transparent = /transparent/i.test(logo || ''); }\n if (transparent) {\n mctx.globalCompositeOperation = 'source-in';\n mctx.fillStyle = ink;\n mctx.fillRect(0, 0, w, h);\n }\n logoHosts.forEach((host) => {\n const cv = document.createElement('canvas');\n cv.width = w; cv.height = h;\n cv.style.cssText = 'width:100%;height:100%;object-fit:contain;';\n const c = cv.getContext('2d');\n if (c) c.drawImage(master, 0, 0);\n host.replaceChildren(cv);\n });\n };\n im.onerror = (): void => { /* keep the ✓ fallback */ };\n im.src = logo;\n }\n\n // Next reward checkpoint ahead of the customer.\n const nextReward = [...rewardAt.keys()].filter((p) => p > filled).sort((a, b) => a - b)[0];\n const progressTxt = nextReward\n ? `${nextReward - filled} more → ${rewardAt.get(nextReward)}`\n : 'Card complete!';\n const sub = gEl('div', 'font-size:13px;font-weight:600;margin-top:2px');\n sub.appendChild(fillBar(ink, (filled / total) * 100));\n sub.appendChild(gEl('div', '', `${filled} of ${total}`));\n // The operator's reward text is the subtitle when set; else the computed hint.\n sub.appendChild(gEl('div', 'font-weight:400;opacity:0.82;margin-top:1px', str(ic.stamp_reward_text) || progressTxt));\n s.content.appendChild(sub);\n\n s.ctaButton(str(ic.stamp_cta_text, 'Order & earn'), () => { ctx.haptic?.(12); });\n\n // REVEAL — the serve binder injects `stamp_just_unlocked` when a milestone was\n // freshly granted this session. Celebrate it: gift-box Lottie + a banner that\n // the reward (and its coupon) is on the customer's account.\n const unlocked = ic.stamp_just_unlocked as { label?: string; icon?: string; coupon_code?: string; redeemable?: boolean } | undefined;\n if (unlocked && typeof unlocked === 'object') {\n const banner = gEl('div', `margin-top:12px;padding:11px 12px;border-radius:14px;background:${ink}14;border:1.5px solid ${ink}55;text-align:center`);\n banner.appendChild(gEl('div', 'font-size:24px', str(unlocked.icon) || '🎁'));\n banner.appendChild(gEl('div', `font-size:13.5px;font-weight:800;color:${ink}`, `Unlocked: ${str(unlocked.label) || 'Reward'}`));\n banner.appendChild(gEl('div', 'font-size:11.5px;opacity:0.8;margin-top:1px',\n unlocked.coupon_code ? `Coupon ${String(unlocked.coupon_code)} added to your account` : 'Added to your account'));\n s.content.appendChild(banner);\n if (!reduce) { ctx.haptic?.([0, 30, 20, 40]); ctx.playReaction?.(s.card, 'celebrate', 'gift.json'); }\n }\n}\n\n// ── 8. Mystery box ──────────────────────────────────────────────────────────\nexport function renderMysteryBox(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-mystery');\n const boxes = arr<{ prize: string }>(ic.mystery_boxes);\n const list = boxes.length ? boxes : [{ prize: '10% OFF' }, { prize: 'Free shipping' }, { prize: '50 points' }];\n if (str(ic.mystery_subtitle)) {\n const sub = document.createElement('div'); sub.textContent = str(ic.mystery_subtitle);\n sub.style.cssText = 'font-size:12.5px;opacity:0.75;margin-bottom:8px'; s.content.appendChild(sub);\n }\n const row = document.createElement('div');\n row.style.cssText = 'display:flex;gap:12px;justify-content:center;margin:8px 0 4px';\n let opened = false;\n list.forEach((b, i) => {\n const box = document.createElement('button');\n box.type = 'button';\n box.style.cssText = `flex:1;max-width:96px;aspect-ratio:3/4;border:none;border-radius:14px;background:${s.accent}1a;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;cursor:pointer;font-size:13px;font-weight:700;color:#0f172a;transition:transform .15s`;\n box.appendChild(gEl('span', 'font-size:30px', '🎁'));\n box.appendChild(gEl('span', 'opacity:0.7', `Box ${String.fromCharCode(65 + i)}`));\n box.addEventListener('click', () => {\n if (opened) return;\n opened = true;\n ctx.haptic?.(12); // light tap\n // Anticipation: the chosen box rattles + others dim, then a brief suspense\n // pause before the reveal (dopamine ramps during the wait, not the prize).\n Array.from(row.children).forEach((c) => { if (c !== box) { (c as HTMLElement).style.opacity = '0.4'; (c as HTMLElement).style.transform = 'scale(0.94)'; } });\n box.style.animation = 'aegisBoxRattle 0.45s ease-in-out';\n // Server-authoritative: the SERVER picks win/lose + which prize from the\n // authored prize_pool (the box the user taps does NOT decide the reward).\n // We send the client prize as the no-pool fallback signal; if the campaign\n // has a prize_pool, the returned `prize` overrides the reveal.\n const submitP = ctx.submitResponse?.('mystery_box', { box_index: i, prize: str(b.prize) });\n const revealBox = async (): Promise<void> => {\n box.style.animation = '';\n let won = true;\n let prizeLabel = str(b.prize, 'You won!');\n try {\n const res = await submitP;\n const sp = res ? (res.prize as Record<string, unknown> | null) : null;\n if (sp) { won = sp.win !== false; if (sp.prize_label) prizeLabel = String(sp.prize_label); }\n } catch { /* network fail-soft → keep optimistic client prize */ }\n box.style.background = won ? `${s.accent}` : 'rgba(148,163,184,0.22)';\n box.style.color = won ? '#fff' : '#475569';\n box.style.transform = 'scale(1.08)';\n box.replaceChildren();\n box.appendChild(gEl('span', 'font-size:28px', won ? '🎉' : '🙈'));\n box.appendChild(gEl('span', '', won ? prizeLabel : 'Not this time'));\n if (won) { ctx.haptic?.([0, 30, 20, 40]); ctx.playReaction?.(s.card, 'celebrate', 'gift.json'); }\n else { ctx.haptic?.(15); ctx.playReaction?.(s.card, 'empathize'); }\n };\n window.setTimeout(() => { void revealBox(); }, 520);\n });\n row.appendChild(box);\n });\n s.content.appendChild(row);\n s.ctaButton(str(ic.mystery_cta_text, ''));\n}\n\n// ── 9. Tier ladder ──────────────────────────────────────────────────────────\nexport function renderTierLadder(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-tier');\n const tiers = arr<{ name: string; icon?: string }>(ic.tiers);\n const list = tiers.length ? tiers : [{ name: 'Bronze', icon: '🥉' }, { name: 'Silver', icon: '🥈' }, { name: 'Gold', icon: '🥇' }];\n const curIdx = Math.min(list.length - 1, num(ic.tier_current_index, 1));\n const curPts = num(ic.tier_current_points, 640);\n const nextPts = num(ic.tier_next_points, 1000);\n const pct = nextPts > 0 ? (curPts / nextPts) * 100 : 0;\n const perks = arr<string>(ic.tier_perks);\n const next = list[Math.min(list.length - 1, curIdx + 1)];\n const ladder = gEl('div', 'display:flex;align-items:flex-start;justify-content:center;margin:6px 0 12px');\n list.forEach((t, i) => {\n if (i > 0) ladder.appendChild(gEl('span', 'flex:1;height:2px;background:rgba(148,163,184,0.4);margin:12px 4px 0;align-self:flex-start'));\n const tier = gEl('div', `display:flex;flex-direction:column;align-items:center;gap:3px;${i === curIdx ? 'font-weight:800' : 'opacity:0.6'}`);\n tier.appendChild(gEl('span', 'font-size:24px', str(t.icon, '◆')));\n tier.appendChild(gEl('span', 'font-size:11px', str(t.name)));\n if (i === curIdx) tier.appendChild(gEl('span', `font-size:9px;color:${s.accent}`, '▲ you'));\n ladder.appendChild(tier);\n });\n s.content.appendChild(ladder);\n s.content.appendChild(fillBar(s.accent, pct));\n s.content.appendChild(gEl('div', 'font-size:13px;font-weight:600', `${Math.max(0, nextPts - curPts)} pts to ${str(next?.name, 'next tier')}`));\n if (perks.length) {\n const box = gEl('div', 'text-align:left;margin-top:10px;font-size:12.5px;opacity:0.85');\n box.appendChild(gEl('div', '', `${str(next?.name, 'Next')} unlocks:`));\n perks.forEach((p) => box.appendChild(gEl('div', '', `• ${str(p)}`)));\n s.content.appendChild(box);\n }\n s.ctaButton(str(ic.tier_cta_text, ''));\n}\n\n// ── 10. Lucky draw / raffle ─────────────────────────────────────────────────\nexport function renderLuckyDraw(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-draw');\n const entries = num(ic.draw_entries, 6);\n const actions = arr<{ label: string; entries?: number; done?: boolean }>(ic.draw_actions);\n if (str(ic.draw_deadline_text)) s.content.appendChild(gEl('div', 'font-size:12px;opacity:0.65;margin-bottom:6px', str(ic.draw_deadline_text)));\n s.content.appendChild(gEl('div', 'font-size:30px', '🎟️'));\n s.content.appendChild(gEl('div', 'font-size:15px;font-weight:800;margin:2px 0 10px', `${entries} entries`));\n s.content.appendChild(gEl('div', 'font-size:12px;opacity:0.7;margin-bottom:4px;text-align:left', 'Earn more entries:'));\n actions.forEach((a) => {\n const row = gEl('div', 'display:flex;align-items:center;gap:8px;padding:7px 0;border-bottom:1px solid rgba(148,163,184,0.18);font-size:13px;text-align:left');\n row.appendChild(gEl('span', '', a.done ? '✅' : '☐'));\n row.appendChild(gEl('span', `flex:1;${a.done ? 'opacity:0.6' : ''}`, str(a.label)));\n row.appendChild(gEl('span', 'opacity:0.7;font-size:12px', `+${num(a.entries, 1)}`));\n s.content.appendChild(row);\n });\n if (str(ic.draw_pool_text)) s.content.appendChild(gEl('div', 'font-size:12px;opacity:0.7;margin-top:8px', str(ic.draw_pool_text)));\n // Record this contact's entry weight in the raffle pool — the server-side\n // winner-selection job tallies the MAX entries per contact, so re-opening is\n // harmless. Seeing the draw enters you with your current entry count.\n void ctx.submitResponse?.('lucky_draw', { entries });\n s.ctaButton(str(ic.draw_cta_text, 'Get more entries'), () => { ctx.haptic?.(12); });\n}\n\n// ── 11. Slot machine ────────────────────────────────────────────────────────\n// A REAL slot machine: vertical reel STRIPS that roll past a masked window with\n// motion blur, decelerate with an ease-out + slight overshoot, stop staggered\n// L→R with an anticipation hold on the last reel, and a pull LEVER beside the\n// reels. The strip is pre-positioned to the server-decided outcome (the prize is\n// chosen server-side; the reels stop ON it). Reduced-motion → instant settle.\ninterface SlotReel { el: HTMLElement; startSpin: () => void; stop: (sym: string, done: () => void) => void; }\n\nfunction makeSlotReel(pool: string[], cell: number): SlotReel {\n const reduce = typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n const win = document.createElement('div');\n win.style.cssText = `position:relative;width:${cell}px;height:${cell}px;overflow:hidden;border-radius:10px;background:linear-gradient(180deg,#ffffff,#f1f5f9);box-shadow:inset 0 6px 8px -4px rgba(0,0,0,0.35),inset 0 -6px 8px -4px rgba(0,0,0,0.35)`;\n const period = pool.length * cell; // height of one full symbol cycle\n const STRIP = pool.length * 8; // enough repeats for a long roll\n const strip = document.createElement('div');\n strip.style.cssText = 'position:absolute;left:0;top:0;width:100%;will-change:transform';\n for (let i = 0; i < STRIP; i++) {\n const c = document.createElement('div');\n c.style.cssText = `height:${cell}px;display:flex;align-items:center;justify-content:center;font-size:${Math.round(cell * 0.55)}px`;\n c.textContent = pool[i % pool.length];\n strip.appendChild(c);\n }\n win.appendChild(strip);\n\n let pos = 0; // px scrolled (downward roll)\n let raf: number | null = null;\n const draw = () => { strip.style.transform = `translateY(${-(pos % period)}px)`; };\n draw();\n\n const startSpin = () => {\n if (reduce) return;\n strip.style.transition = '';\n strip.style.filter = 'blur(1.5px)';\n const tick = () => { pos += 34; draw(); raf = requestAnimationFrame(tick); };\n raf = requestAnimationFrame(tick);\n };\n\n const stop = (sym: string, done: () => void) => {\n if (raf !== null) { cancelAnimationFrame(raf); raf = null; }\n const residue = (Math.max(0, pool.indexOf(sym)) % pool.length) * cell;\n const cur = pos % period;\n if (reduce) {\n pos = residue; strip.style.filter = ''; draw(); done(); return;\n }\n const delta = ((residue - cur) % period + period) % period;\n const final = cur + 2 * period + delta; // ~2+ full spins, land on target\n strip.style.filter = '';\n strip.style.transition = 'transform 0.9s cubic-bezier(0.18,0.86,0.28,1.12)'; // ease-out + slight overshoot\n strip.style.transform = `translateY(${-final}px)`;\n const onEnd = () => {\n strip.removeEventListener('transitionend', onEnd);\n pos = residue; strip.style.transition = ''; draw(); // normalise back into range\n done();\n };\n strip.addEventListener('transitionend', onEnd);\n };\n\n return { el: win, startSpin, stop };\n}\n\nfunction makeSlotLever(accent: string, onPull: () => void): { el: HTMLElement; pull: () => void } {\n const wrap = document.createElement('div');\n wrap.style.cssText = 'position:relative;width:26px;height:96px;display:flex;justify-content:center;cursor:pointer;user-select:none';\n wrap.setAttribute('role', 'button');\n wrap.setAttribute('aria-label', 'Pull the lever');\n const track = document.createElement('div');\n track.style.cssText = 'position:absolute;top:10px;bottom:10px;width:6px;border-radius:3px;background:linear-gradient(180deg,#64748b,#334155)';\n const knob = document.createElement('div');\n knob.style.cssText = `position:absolute;top:0;width:26px;height:26px;border-radius:50%;background:radial-gradient(circle at 34% 30%,#ffffff,${accent});box-shadow:0 3px 7px rgba(0,0,0,0.45);z-index:1`;\n wrap.appendChild(track); wrap.appendChild(knob);\n const pull = () => {\n knob.style.transition = 'transform 0.12s ease-in';\n knob.style.transform = 'translateY(60px)';\n window.setTimeout(() => {\n knob.style.transition = 'transform 0.5s cubic-bezier(0.2,1.5,0.4,1)'; // springy return\n knob.style.transform = 'translateY(0)';\n }, 130);\n };\n wrap.addEventListener('click', onPull);\n return { el: wrap, pull };\n}\n\nexport function renderSlotMachine(ctx: RenderContext): void {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n const s = openGameModal(ctx, 'aegis-in-app-slot', 400);\n const symbols = arr<string>(ic.slot_symbols).filter((x) => typeof x === 'string' && x);\n const pool = symbols.length >= 3 ? symbols : ['🍒', '7️⃣', '🍋', '⭐', '🔔'];\n const CELL = 68;\n const rnd = (n: number): number => Math.floor(Math.random() * n);\n\n // Machine: reels in a recessed cabinet + a win line + a lever on the right.\n const machine = document.createElement('div');\n machine.style.cssText = 'display:flex;align-items:center;justify-content:center;gap:12px;margin:12px 0 6px';\n const cabinet = document.createElement('div');\n cabinet.style.cssText = `position:relative;display:flex;gap:8px;padding:12px;border-radius:18px;background:linear-gradient(180deg,#1f2937,#0f172a);box-shadow:inset 0 3px 10px rgba(0,0,0,0.55),0 6px 16px rgba(0,0,0,0.25)`;\n const reels = [0, 1, 2].map(() => makeSlotReel(pool, CELL));\n reels.forEach((r) => cabinet.appendChild(r.el));\n const winLine = document.createElement('div');\n winLine.style.cssText = `position:absolute;left:8px;right:8px;top:50%;height:${CELL}px;transform:translateY(-50%);border:2.5px solid transparent;border-radius:12px;pointer-events:none;transition:border-color 0.3s,box-shadow 0.3s`;\n cabinet.appendChild(winLine);\n const lever = makeSlotLever(s.accent, () => { void spin(); });\n machine.appendChild(cabinet);\n machine.appendChild(lever.el);\n s.content.appendChild(machine);\n\n const result = document.createElement('div');\n result.style.cssText = 'font-size:13px;font-weight:700;min-height:18px;margin-top:8px';\n s.content.appendChild(result);\n\n let spinning = false;\n const playBtn = s.ctaButton(str(ic.slot_cta_text, 'PULL 🎰'), () => {});\n const fresh = playBtn ? (playBtn.cloneNode(true) as HTMLButtonElement) : null;\n if (playBtn && fresh) { playBtn.replaceWith(fresh); fresh.addEventListener('click', () => { void spin(); }); }\n\n const spin = async (): Promise<void> => {\n if (spinning) return;\n spinning = true;\n if (fresh) fresh.disabled = true;\n lever.pull();\n ctx.haptic?.(18);\n result.textContent = '';\n winLine.style.borderColor = 'transparent';\n winLine.style.boxShadow = 'none';\n reels.forEach((r) => r.startSpin());\n\n // Provisional client outcome (no-pool fallback) + ask the server to decide.\n const prov = [pool[rnd(pool.length)], pool[rnd(pool.length)], pool[rnd(pool.length)]];\n const provWin = prov[0] === prov[1] && prov[1] === prov[2];\n const submitP = ctx.submitResponse?.('slot_machine', { win: provWin, symbols: prov });\n\n let serverPrize: Record<string, unknown> | null = null;\n try {\n const res = await Promise.race([\n submitP ?? Promise.resolve(null),\n new Promise<null>((resolve) => window.setTimeout(() => resolve(null), 1400)),\n ]);\n serverPrize = res ? ((res as Record<string, unknown>).prize as Record<string, unknown> | null) : null;\n } catch { /* network fail-soft → provisional */ }\n\n const win = serverPrize ? serverPrize.win !== false : provWin;\n const label = serverPrize && serverPrize.prize_label ? String(serverPrize.prize_label) : str(ic.slot_win_text, 'You win!');\n let target: string[];\n if (serverPrize) {\n if (win) { const sym = pool[rnd(pool.length)]; target = [sym, sym, sym]; }\n else { target = [pool[rnd(pool.length)], pool[rnd(pool.length)], pool[rnd(pool.length)]]; if (target[0] === target[1] && target[1] === target[2]) target[2] = pool[(pool.indexOf(target[2]) + 1) % pool.length]; }\n } else { target = prov; }\n\n const finish = (): void => {\n result.textContent = win ? `🎉 ${label}` : 'So close — try again next time!';\n result.style.color = win ? s.accent : '#94a3b8';\n if (win) {\n winLine.style.borderColor = s.accent;\n winLine.style.boxShadow = `0 0 14px ${s.accent}aa, inset 0 0 14px ${s.accent}55`;\n ctx.haptic?.([0, 30, 20, 40]);\n ctx.playReaction?.(s.card, 'celebrate');\n } else {\n ctx.haptic?.(15);\n ctx.playReaction?.(s.card, 'empathize');\n }\n ctx.trackEvent(ctx.campaign.id, 'clicked', { stepId: win ? 'win' : 'lose' });\n spinning = false;\n };\n\n // Stop reels L→R after a minimum spin, with an anticipation hold before the last.\n const stopReel = (i: number): void => {\n reels[i].stop(target[i], () => {\n ctx.haptic?.(10);\n if (i < reels.length - 1) window.setTimeout(() => stopReel(i + 1), i === reels.length - 2 ? 560 : 320);\n else finish();\n });\n };\n window.setTimeout(() => stopReel(0), 620);\n };\n}\n\n// Dispatcher — maps a game sub_type to its renderer. Returns true if handled.\nconst GAME_RENDERERS: Record<string, (ctx: RenderContext) => void> = {\n streak: renderStreak,\n milestone: renderMilestone,\n challenge: renderChallenge,\n achievements: renderAchievements,\n leaderboard: renderLeaderboard,\n check_in: renderCheckIn,\n stamp_card: renderStampCard,\n mystery_box: renderMysteryBox,\n tier_ladder: renderTierLadder,\n lucky_draw: renderLuckyDraw,\n slot_machine: renderSlotMachine,\n};\n\nexport const GAME_SUB_TYPES = Object.keys(GAME_RENDERERS);\n\nexport function renderGame(ctx: RenderContext, subType: string): boolean {\n const fn = GAME_RENDERERS[subType];\n if (!fn) return false;\n fn(ctx);\n return true;\n}\n","/**\n * Standalone video hero (\"Video Banner\", 2026-06-14) — a prominent\n * muted-autoplay-loop video with an unmute pill, optional poster, and\n * title/body/CTA either OVERLAID on the video or BELOW it. Two surfaces:\n * - inline (renders into a `[data-aegis-slot]` anchor) — the Video Banner\n * - overlay (centred hero card) — the takeover\n * Distinct from `pip` (small floating corner) and `full_screen` (full-bleed\n * takeover). Reuses interactive_config.video_url + image_url (poster) + the\n * campaign title/body/button_text/action_url.\n *\n * interactive_config:\n * video_url (the muted-inline video) · video_aspect '16:9'|'9:16'|'1:1'|'4:5'\n * video_caption 'overlay'|'below' · video_autoplay (default true) · video_loop (default true)\n */\n\nimport type { RenderContext } from './types';\n\nconst ASPECT: Record<string, string> = { '16:9': '16 / 9', '9:16': '9 / 16', '1:1': '1 / 1', '4:5': '4 / 5' };\n\nfunction buildVideo(ctx: RenderContext, aspect: string, autoplay: boolean, loop: boolean): HTMLElement {\n const { campaign, sanitizeUrl } = ctx;\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const videoUrl = sanitizeUrl((ic.video_url as string) || (campaign as unknown as Record<string, unknown>).video_url as string || '');\n const poster = campaign.image_url ? sanitizeUrl(campaign.image_url) : null;\n\n const wrap = document.createElement('div');\n wrap.style.cssText = `position:relative;width:100%;aspect-ratio:${ASPECT[aspect] || ASPECT['16:9']};background:#0b1220;border-radius:14px;overflow:hidden;`;\n\n if (videoUrl) {\n const vid = document.createElement('video');\n vid.src = videoUrl;\n vid.muted = true;\n vid.loop = loop;\n vid.autoplay = autoplay;\n vid.playsInline = true;\n vid.setAttribute('playsinline', '');\n if (poster) vid.poster = poster;\n vid.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;object-fit:cover;';\n wrap.appendChild(vid);\n if (autoplay) void vid.play?.().catch(() => {});\n\n // Watch-completion — fired ONCE when the viewer reaches ~90% (works even\n // with loop=true, where 'ended' never fires). Engagement-funnel + timeline\n // signal (no reward). Threshold avoids counting a 1-second glance.\n let watchedFired = false;\n const onProgress = () => {\n if (watchedFired || !vid.duration || !isFinite(vid.duration)) return;\n if (vid.currentTime / vid.duration >= 0.9) {\n watchedFired = true;\n void ctx.submitResponse?.('video_complete', { duration_s: Math.round(vid.duration) });\n }\n };\n vid.addEventListener('timeupdate', onProgress);\n vid.addEventListener('ended', () => {\n if (!watchedFired) { watchedFired = true; void ctx.submitResponse?.('video_complete', { duration_s: Math.round(vid.duration || 0) }); }\n });\n\n // Unmute pill (browsers require muted autoplay; let the viewer turn sound on).\n const pill = document.createElement('button');\n pill.type = 'button';\n pill.textContent = '🔇';\n pill.setAttribute('aria-label', 'Unmute');\n pill.style.cssText = 'position:absolute;bottom:10px;right:10px;z-index:2;width:34px;height:34px;border:none;border-radius:999px;background:rgba(0,0,0,0.45);color:#fff;font-size:14px;cursor:pointer;';\n pill.addEventListener('click', (e) => {\n e.stopPropagation();\n vid.muted = !vid.muted;\n pill.textContent = vid.muted ? '🔇' : '🔊';\n if (!vid.muted) void vid.play?.().catch(() => {});\n });\n wrap.appendChild(pill);\n } else if (poster) {\n const img = document.createElement('img');\n img.src = poster; img.alt = '';\n img.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;object-fit:cover;';\n wrap.appendChild(img);\n } else {\n wrap.style.background = 'linear-gradient(160deg,#1f2937,#0f172a)';\n }\n return wrap;\n}\n\nfunction caption(ctx: RenderContext, accent: string, onCard: boolean): HTMLElement | null {\n const { campaign } = ctx;\n if (!campaign.title && !campaign.body && !campaign.button_text && !campaign.action_url) return null;\n const box = document.createElement('div');\n box.style.cssText = onCard\n ? 'position:absolute;left:0;right:0;bottom:0;z-index:2;padding:18px 16px 16px;color:#fff;text-align:left;background:linear-gradient(to top,rgba(0,0,0,0.72),rgba(0,0,0,0) 80%);'\n : 'padding:14px 4px 2px;text-align:left;color:#0f172a;';\n if (campaign.title) {\n const t = document.createElement('div');\n t.textContent = campaign.title;\n t.style.cssText = `font-family:'Inter Tight',Inter,system-ui,sans-serif;font-size:17px;font-weight:800;letter-spacing:-0.01em;line-height:1.2;${onCard ? 'text-shadow:0 1px 8px rgba(0,0,0,0.4);' : ''}`;\n box.appendChild(t);\n }\n if (campaign.body) {\n const b = document.createElement('div');\n b.textContent = campaign.body;\n b.style.cssText = `font-size:13px;line-height:1.45;margin-top:3px;${onCard ? 'opacity:0.92;text-shadow:0 1px 6px rgba(0,0,0,0.4);' : 'opacity:0.7;'}`;\n box.appendChild(b);\n }\n const label = campaign.button_text || (campaign.action_url ? 'Watch now' : '');\n if (label) {\n const cta = document.createElement('button');\n cta.type = 'button';\n cta.className = 'aegis-cta';\n cta.textContent = label;\n cta.style.cssText = `margin-top:12px;padding:10px 22px;border:none;border-radius:999px;background:${onCard ? '#fff' : accent};color:${onCard ? '#0f172a' : '#fff'};font-size:13px;font-weight:700;cursor:pointer;`;\n cta.addEventListener('click', (e) => {\n e.stopPropagation();\n ctx.trackEvent(campaign.id, 'clicked');\n const url = (campaign.action_url as string) || '';\n if (url) { if (ctx.navigate) ctx.navigate(url, 'cta'); else window.location.href = url; }\n });\n box.appendChild(cta);\n }\n return box;\n}\n\nfunction readOpts(ctx: RenderContext) {\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n return {\n accent: ctx.sanitizeColor((ctx.campaign.background_color as string) || '#4169e1'),\n aspect: (ic.video_aspect as string) || '16:9',\n overlayCaption: (ic.video_caption as string) !== 'below',\n autoplay: ic.video_autoplay !== false,\n loop: ic.video_loop !== false,\n };\n}\n\n/** Overlay entry — a centred video hero card. */\nexport function renderVideo(ctx: RenderContext): void {\n const { campaign, trackEvent, addAnimationStyles } = ctx;\n addAnimationStyles();\n const o = readOpts(ctx);\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-video-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText = 'position:fixed;inset:0;z-index:100000;background:rgba(15,23,42,0.6);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;padding:16px;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif;animation:aegisFadeIn 0.25s ease;';\n\n const card = document.createElement('div');\n card.style.cssText = `position:relative;width:100%;max-width:${o.aspect === '9:16' ? 320 : 460}px;background:#fff;border-radius:18px;overflow:hidden;box-shadow:0 16px 48px rgba(0,0,0,0.28);animation:aegisScaleIn 0.3s ease;`;\n\n const media = buildVideo(ctx, o.aspect, o.autoplay, o.loop);\n if (o.overlayCaption) { const c = caption(ctx, o.accent, true); if (c) media.appendChild(c); }\n card.appendChild(media);\n if (!o.overlayCaption) { const c = caption(ctx, o.accent, false); if (c) { c.style.padding = '14px 16px 16px'; card.appendChild(c); } }\n\n const close = document.createElement('button');\n close.type = 'button'; close.textContent = '✕'; close.setAttribute('aria-label', 'Close');\n close.style.cssText = 'position:absolute;top:10px;left:10px;z-index:3;width:32px;height:32px;border:none;border-radius:999px;background:rgba(0,0,0,0.4);color:#fff;font-size:15px;cursor:pointer;';\n close.addEventListener('click', () => { trackEvent(campaign.id, 'dismissed'); overlay.remove(); });\n card.appendChild(close);\n overlay.addEventListener('click', (e) => { if (e.target === overlay) { trackEvent(campaign.id, 'dismissed'); overlay.remove(); } });\n\n overlay.appendChild(card);\n document.body.appendChild(overlay);\n}\n\n/** Slot/embedded entry — the inline Video Banner. */\nexport function renderVideoInline(ctx: RenderContext, target: HTMLElement | null): boolean {\n if (!target) { renderVideo(ctx); return true; }\n ctx.addAnimationStyles();\n const o = readOpts(ctx);\n const banner = document.createElement('div');\n banner.className = 'aegis-in-app-video-banner';\n banner.setAttribute('data-campaign-id', ctx.campaign.id);\n banner.style.cssText = 'width:100%;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif;';\n const media = buildVideo(ctx, o.aspect, o.autoplay, o.loop);\n if (o.overlayCaption) { const c = caption(ctx, o.accent, true); if (c) media.appendChild(c); }\n banner.appendChild(media);\n if (!o.overlayCaption) { const c = caption(ctx, o.accent, false); if (c) banner.appendChild(c); }\n target.appendChild(banner);\n return true;\n}\n","/**\n * AegisChat — the website / in-app \"Shopping Assistant\" launcher (Track A).\n *\n * A floating bottom-right bubble that expands into a chat panel, letting a\n * customer converse with the SAME channel-neutral chat agent that powers\n * WhatsApp. This is pure transport + surface — it does NOT contain any agent\n * intelligence. Messages go to the gateway (`POST /v1/chat/message` →\n * `chatbot.inbound channel='web'`); replies arrive as a thin `chat.message`\n * SSE nudge (per-session, ticket-authed) that triggers a re-fetch of the\n * rendered thread from `GET /v1/chat/history`. REST polling is the fallback\n * when the panel is closed or SSE drops.\n *\n * Identity: true-anonymous visitors work — we send the SDK's `anonymous_id`\n * (first-party cookie) and the server resolves/creates a stable contact. The\n * server returns the opaque `contact_id`, which we echo on every subsequent\n * message so the server hits the indexed PK path (and the anon→known stitch\n * upgrades the contact when the customer later identifies).\n *\n * Rendering reuses the `web` payload the backend already emits\n * (`chat_response_renderer.py`): text + `{type:'product_carousel', products:[…]}`.\n */\n\nimport { Storage } from '../utils/storage';\n\nexport interface AegisChatConfig {\n writeKey: string;\n /** Gateway origin (the single public SDK surface). Falls back to same-origin. */\n apiHost?: string;\n organizationId?: string;\n /** Known contact id when the visitor is already identified; else anonymous. */\n contactId?: string;\n /** 'web' (browser) or 'in_app' (mobile webview). Opaque to the agent. */\n channel?: 'web' | 'in_app';\n debugMode?: boolean;\n /** Launcher header title shown to the customer. Default \"Shopping Assistant\";\n * the storefront passes \"Ask {Brand}\". */\n title?: string;\n /** First assistant greeting bubble + attention tooltip text. */\n greeting?: string;\n /** Accent colour for the bubble + customer bubbles. Defaults to brand. */\n accentColor?: string;\n /** Bubble icon style. 'sparkle' (default, signals AI) | 'chat' (plain bubble)\n * | 'logo' (renders `logoUrl`). No robot — brand-friendly by design. */\n icon?: 'sparkle' | 'chat' | 'logo';\n /** Image URL used when `icon: 'logo'` (brand logo / mascot). */\n logoUrl?: string;\n /** Corner the launcher docks to. */\n position?: 'bottom-right' | 'bottom-left';\n /** Chat agent persona key bound to this launcher (campaign-driven). Sent to\n * the backend on /v1/chat/message; honored server-side (Active Web Chat\n * Phase E). Absent = the tenant's default persona. */\n agentPersona?: string;\n /** Quick-reply chips offered under the greeting (campaign-driven). */\n quickReplies?: string[];\n /** Fired when the panel transitions closed→open — a chat session begins.\n * Used by the Active Web Chat renderer to report a campaign engagement. */\n onSessionStart?: () => void;\n /** Fired when the panel transitions open→closed — the session ends. */\n onSessionEnd?: () => void;\n /** Fired after a customer message is accepted by the server. */\n onMessageSent?: () => void;\n}\n\ninterface ChatHistoryMessage {\n id: string;\n sender: 'customer' | 'assistant' | 'system';\n role: string;\n content: string;\n media_url?: string | null;\n media_type?: string | null;\n interactive?: Array<Record<string, unknown>> | null;\n created_at?: string | null;\n}\n\ninterface IngestResponse {\n accepted: boolean;\n contact_id: string;\n is_new_contact: boolean;\n message_id: string;\n channel: string;\n sse_ticket: string;\n sse_ticket_expires_at: number;\n}\n\nconst STYLE_ID = 'aegis-chat-styles';\nconst POLL_INTERVAL_MS = 5000;\n/** Delay before the bubble pulses + the greeting tooltip appears (ms). */\nconst ATTENTION_DELAY_MS = 4500;\n\nexport class AegisChat {\n private readonly writeKey: string;\n private readonly apiHost: string;\n private contactId?: string;\n private readonly channel: 'web' | 'in_app';\n private readonly debugMode: boolean;\n private readonly title: string;\n private readonly greeting: string;\n private readonly accent: string;\n private readonly icon: 'sparkle' | 'chat' | 'logo';\n private readonly logoUrl?: string;\n private readonly position: 'bottom-right' | 'bottom-left';\n private readonly agentPersona?: string;\n private readonly quickReplies?: string[];\n private readonly onSessionStart?: () => void;\n private readonly onSessionEnd?: () => void;\n private readonly onMessageSent?: () => void;\n\n private anonymousId?: string;\n /** Per-session SSE ticket from the last /message response. Authorizes both\n * the SSE subscription AND the contact-scoped /history read (the server\n * requires it — chat history is not readable by contact_id alone). */\n private sseTicket?: string;\n private open = false;\n private initialized = false;\n\n // DOM\n private root?: HTMLDivElement;\n private bubble?: HTMLButtonElement;\n private panel?: HTMLDivElement;\n private thread?: HTMLDivElement;\n private input?: HTMLTextAreaElement;\n private unread = 0;\n private badge?: HTMLSpanElement;\n\n // Transport\n private eventSource?: EventSource;\n private pollTimer?: ReturnType<typeof setInterval>;\n private renderedIds = new Set<string>();\n /** Contents of optimistically-rendered customer messages awaiting their\n * server echo — used to dedup the history refetch (double-message fix). */\n private pendingEcho: string[] = [];\n private typingEl?: HTMLDivElement;\n private greetingTip?: HTMLDivElement;\n private attentionTimer?: ReturnType<typeof setTimeout>;\n private hasInteracted = false;\n\n constructor(config: AegisChatConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = (config.apiHost ?? '').replace(/\\/$/, '');\n this.contactId = config.contactId;\n this.channel = config.channel ?? 'web';\n this.debugMode = config.debugMode ?? false;\n this.title = config.title ?? 'Shopping Assistant';\n this.greeting = config.greeting ?? 'Hi! 👋 How can I help you today?';\n this.accent = config.accentColor ?? '#4169e1';\n this.icon = config.icon ?? 'sparkle';\n this.logoUrl = config.logoUrl;\n this.position = config.position ?? 'bottom-right';\n this.agentPersona = config.agentPersona;\n this.quickReplies = config.quickReplies;\n this.onSessionStart = config.onSessionStart;\n this.onSessionEnd = config.onSessionEnd;\n this.onMessageSent = config.onMessageSent;\n this.anonymousId = this.readAnonId();\n }\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n initialize(): void {\n if (this.initialized || typeof document === 'undefined') return;\n this.initialized = true;\n this.injectStyles();\n this.mount();\n this.scheduleAttention();\n }\n\n /** Called by the runtime when the visitor identifies. */\n updateContactId(contactId: string): void {\n if (!contactId || contactId === this.contactId) return;\n this.contactId = contactId;\n }\n\n /** Programmatic open (used by the proactive TriggerEngine wiring). */\n openPanel(prefill?: string): void {\n if (!this.panel) this.initialize();\n if (this.open) return;\n this.open = true;\n this.hasInteracted = true;\n // Closed→open transition — a chat session begins (campaign engagement).\n try { this.onSessionStart?.(); } catch { /* host callback — never block UI */ }\n this.dismissAttention();\n this.panel?.classList.add('aegis-chat-panel--open');\n this.bubble?.classList.add('aegis-chat-bubble--hidden');\n this.clearUnread();\n if (prefill && this.input) this.input.value = prefill;\n void this.refreshHistory();\n // SSE needs a per-session ticket, which only arrives on the first /message\n // response — so on open we poll to bridge that gap. As soon as SSE connects\n // (after the first send), `onopen` stops polling. While the panel is CLOSED\n // there is neither SSE nor polling — zero background load.\n this.startPolling();\n this.input?.focus();\n }\n\n closePanel(): void {\n const wasOpen = this.open;\n this.open = false;\n this.panel?.classList.remove('aegis-chat-panel--open');\n this.bubble?.classList.remove('aegis-chat-bubble--hidden');\n this.disconnectSSE();\n this.stopPolling();\n // Open→closed transition — the session ends. Guarded so a redundant\n // closePanel() (e.g. teardown after an already-closed panel) doesn't\n // double-report.\n if (wasOpen) {\n try { this.onSessionEnd?.(); } catch { /* host callback — never block UI */ }\n }\n }\n\n destroy(): void {\n this.disconnectSSE();\n this.stopPolling();\n this.root?.remove();\n this.initialized = false;\n }\n\n // ── Send ─────────────────────────────────────────────────────────────────\n\n private async send(text: string): Promise<void> {\n const message = text.trim();\n if (!message) return;\n // Optimistic echo so the customer sees their message immediately. Track the\n // content so the history refetch reconciles (adopts) the server copy instead\n // of rendering it a second time.\n this.appendBubble({ id: `local_${Date.now()}`, sender: 'customer', role: 'user', content: message });\n this.pendingEcho.push(message);\n if (this.input) {\n this.input.value = '';\n this.input.style.height = 'auto';\n }\n // Assistant is working — show the typing indicator until its reply lands.\n this.showTyping();\n\n try {\n const res = await fetch(`${this.apiHost}/v1/chat/message`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-Aegis-Write-Key': this.writeKey },\n body: JSON.stringify({\n message_text: message,\n channel: this.channel,\n anonymous_id: this.anonymousId,\n contact_id: this.contactId,\n // Active Web Chat — binds the campaign-configured persona. Optional;\n // the backend falls back to the tenant default if unknown/absent\n // (honored server-side in Phase E). JSON.stringify drops it if absent.\n agent_persona: this.agentPersona,\n }),\n keepalive: true,\n });\n if (!res.ok) {\n this.log('send failed', res.status);\n this.appendSystem('Sorry — your message could not be delivered. Please try again.');\n return;\n }\n const data = (await res.json()) as IngestResponse;\n try { this.onMessageSent?.(); } catch { /* host callback — never block UI */ }\n // Echo the resolved contact id on subsequent sends (indexed PK path) and\n // (re)connect SSE with the fresh per-session ticket. The ticket also\n // authorizes the /history read, so retain it.\n this.contactId = data.contact_id;\n this.sseTicket = data.sse_ticket;\n this.connectSSE(data.sse_ticket);\n // Now that we hold a ticket, pull the rendered thread (the optimistic echo\n // covered the gap until here).\n void this.refreshHistory();\n } catch (err) {\n this.log('send error', err);\n this.appendSystem('Sorry — your message could not be delivered. Please try again.');\n }\n }\n\n // ── Reply transport: SSE nudge + history refetch (poll fallback) ──────────\n\n private connectSSE(ticket?: string): void {\n // Hard guarantee: SSE only exists while the panel is open. Guards the\n // async race where a send()'s /message response resolves AFTER the user\n // closed the panel — without this, connectSSE would reopen a stream on a\n // closed panel and leak a connection.\n if (!this.open) return;\n if (typeof EventSource === 'undefined' || !this.contactId) return;\n // Mint-on-send: the ticket comes from the /message response. If we don't\n // have one yet (panel opened before first send), we rely on polling until\n // the first reply arrives and a ticket is issued.\n if (!ticket) return;\n this.disconnectSSE();\n const url = new URL('/v1/stream/realtime', this.apiHost || window.location.origin);\n url.searchParams.set('ticket', ticket);\n url.searchParams.set('mode', 'ephemeral');\n try {\n this.eventSource = new EventSource(url.toString());\n this.eventSource.onopen = () => {\n // SSE is the live path — stop the REST-poll fallback so we don't run\n // both at once. Polling resumes only if the stream drops (onerror).\n this.stopPolling();\n this.log('SSE connected');\n };\n this.eventSource.addEventListener('chat.message', () => {\n void this.refreshHistory();\n });\n this.eventSource.onerror = () => {\n // Stream dropped — fall back to polling until the browser reconnects\n // (onopen will stop it again).\n this.startPolling();\n };\n } catch (err) {\n this.log('SSE connect failed', err);\n this.startPolling();\n }\n }\n\n private disconnectSSE(): void {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = undefined;\n }\n }\n\n private startPolling(): void {\n // Same hard guarantee as connectSSE: no background fetch loop unless the\n // panel is open (covers an onerror firing after a close race).\n if (!this.open) return;\n if (this.pollTimer) return;\n this.pollTimer = setInterval(() => {\n void this.refreshHistory();\n }, POLL_INTERVAL_MS);\n }\n\n private stopPolling(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = undefined;\n }\n }\n\n private async refreshHistory(): Promise<void> {\n if (!this.contactId) return;\n // The server requires the per-session ticket to authorize this contact-\n // scoped read (history is not readable by contact_id alone). Until the first\n // send mints one, there is nothing to fetch — the optimistic echo + local\n // greeting cover the panel, and the post-send refreshHistory() backfills.\n if (!this.sseTicket) return;\n try {\n const url = new URL('/v1/chat/history', this.apiHost || window.location.origin);\n url.searchParams.set('contact_id', this.contactId);\n url.searchParams.set('ticket', this.sseTicket);\n url.searchParams.set('channel', this.channel);\n url.searchParams.set('limit', '50');\n const res = await fetch(url.toString(), {\n method: 'GET',\n headers: { 'X-Aegis-Write-Key': this.writeKey },\n });\n if (!res.ok) return;\n const data = (await res.json()) as { messages: ChatHistoryMessage[] };\n let appended = false;\n for (const msg of data.messages || []) {\n if (this.renderedIds.has(msg.id)) continue;\n // Reconcile the optimistic customer echo: a server customer-message that\n // matches a pending locally-rendered one is the SAME message with a real\n // id — adopt the id and skip the re-render (double-message fix).\n if (msg.sender === 'customer') {\n const idx = this.pendingEcho.indexOf(msg.content || '');\n if (idx !== -1) {\n this.pendingEcho.splice(idx, 1);\n if (msg.id) this.renderedIds.add(msg.id);\n continue;\n }\n }\n // An assistant reply has arrived — drop the typing indicator.\n if (msg.sender === 'assistant') this.hideTyping();\n this.appendBubble(msg);\n appended = true;\n if (msg.sender === 'assistant' && !this.open) this.bumpUnread();\n }\n if (appended) this.scrollToBottom();\n } catch (err) {\n this.log('history fetch error', err);\n }\n }\n\n // ── DOM ──────────────────────────────────────────────────────────────────\n\n /** Bubble glyph by config. Default 'sparkle' (signals AI, brand-friendly —\n * never a robot). 'logo' renders the brand image; falls back to sparkle. */\n private bubbleIconHtml(): string {\n const SPARKLE =\n '<svg width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">' +\n '<path d=\"M12 2.3l1.85 5.0 5.0 1.85-5.0 1.85L12 16l-1.85-5.0L5.15 9.15l5.0-1.85L12 2.3z\"/>' +\n '<path d=\"M18.7 14.3l.78 2.1 2.1.78-2.1.78-.78 2.1-.78-2.1-2.1-.78 2.1-.78.78-2.1z\" opacity=\"0.85\"/></svg>';\n const CHAT =\n '<svg width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">' +\n '<path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>';\n if (this.icon === 'chat') return CHAT;\n if (this.icon === 'logo' && this.logoUrl && /^https?:\\/\\//i.test(this.logoUrl)) {\n const safe = this.logoUrl.replace(/\"/g, '&quot;');\n return `<img class=\"aegis-chat-bubble-logo\" src=\"${safe}\" alt=\"\" />`;\n }\n return SPARKLE;\n }\n\n private mount(): void {\n const root = document.createElement('div');\n root.className = `aegis-chat-root aegis-chat-root--${this.position}`;\n root.style.setProperty('--aegis-chat-accent', this.accent);\n\n // Bubble\n const bubble = document.createElement('button');\n bubble.className = 'aegis-chat-bubble';\n bubble.setAttribute('aria-label', `Open ${this.title}`);\n bubble.innerHTML = this.bubbleIconHtml();\n const badge = document.createElement('span');\n badge.className = 'aegis-chat-badge';\n badge.style.display = 'none';\n bubble.appendChild(badge);\n bubble.addEventListener('click', () => this.openPanel());\n\n // Panel\n const panel = document.createElement('div');\n panel.className = 'aegis-chat-panel';\n panel.setAttribute('role', 'dialog');\n panel.setAttribute('aria-label', this.title);\n\n const header = document.createElement('div');\n header.className = 'aegis-chat-header';\n const titleEl = document.createElement('span');\n titleEl.className = 'aegis-chat-title';\n titleEl.textContent = this.title;\n const closeBtn = document.createElement('button');\n closeBtn.className = 'aegis-chat-close';\n closeBtn.setAttribute('aria-label', 'Close chat');\n closeBtn.textContent = '✕';\n closeBtn.addEventListener('click', () => this.closePanel());\n header.appendChild(titleEl);\n header.appendChild(closeBtn);\n\n const thread = document.createElement('div');\n thread.className = 'aegis-chat-thread';\n\n // Composer\n const composer = document.createElement('form');\n composer.className = 'aegis-chat-composer';\n const input = document.createElement('textarea');\n input.className = 'aegis-chat-input';\n input.rows = 1;\n input.placeholder = 'Type a message…';\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n void this.send(input.value);\n }\n });\n const sendBtn = document.createElement('button');\n sendBtn.type = 'submit';\n sendBtn.className = 'aegis-chat-send';\n sendBtn.setAttribute('aria-label', 'Send message');\n sendBtn.innerHTML =\n '<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/><polygon points=\"22 2 15 22 11 13 2 9 22 2\"/></svg>';\n composer.addEventListener('submit', (e) => {\n e.preventDefault();\n void this.send(input.value);\n });\n composer.appendChild(input);\n composer.appendChild(sendBtn);\n\n panel.appendChild(header);\n panel.appendChild(thread);\n panel.appendChild(composer);\n\n // One-time greeting tooltip (\"👋 Need help?\") — a high-intent affordance\n // that signals the assistant is live and ready, without a heavy Lottie\n // dependency. Shown by scheduleAttention(), dismissed on open.\n const tip = document.createElement('div');\n tip.className = 'aegis-chat-tip';\n const tipText = document.createElement('span');\n tipText.textContent = this.greeting || 'Need help finding something? Ask me 👋';\n const tipClose = document.createElement('button');\n tipClose.className = 'aegis-chat-tip-close';\n tipClose.setAttribute('aria-label', 'Dismiss');\n tipClose.textContent = '✕';\n tipClose.addEventListener('click', (e) => { e.stopPropagation(); this.dismissAttention(); });\n tip.appendChild(tipText);\n tip.appendChild(tipClose);\n tip.addEventListener('click', () => this.openPanel());\n\n root.appendChild(panel);\n root.appendChild(tip);\n root.appendChild(bubble);\n document.body.appendChild(root);\n\n this.greetingTip = tip;\n this.root = root;\n this.bubble = bubble;\n this.badge = badge;\n this.panel = panel;\n this.thread = thread;\n this.input = input;\n\n // Local greeting (server greeting also arrives via history on first turn).\n this.appendSystemGreeting(this.greeting);\n this.renderQuickReplies();\n }\n\n /** Campaign-configured quick-reply chips shown under the greeting. Tapping a\n * chip sends it as the customer's first message, then the row is removed. */\n private renderQuickReplies(): void {\n if (!this.thread || !this.quickReplies?.length) return;\n const row = document.createElement('div');\n row.className = 'aegis-chat-quickreplies';\n for (const label of this.quickReplies) {\n if (typeof label !== 'string' || !label.trim()) continue;\n const chip = document.createElement('button');\n chip.type = 'button';\n chip.className = 'aegis-chat-chip';\n chip.textContent = label;\n chip.addEventListener('click', () => {\n row.remove();\n void this.send(label);\n });\n row.appendChild(chip);\n }\n if (row.childElementCount > 0) this.thread.appendChild(row);\n }\n\n private appendBubble(msg: ChatHistoryMessage): void {\n if (!this.thread) return;\n if (msg.id) this.renderedIds.add(msg.id);\n\n const row = document.createElement('div');\n row.className = `aegis-chat-msg aegis-chat-msg--${msg.sender}`;\n\n if (msg.content) {\n const bubble = document.createElement('div');\n bubble.className = 'aegis-chat-bubbletext';\n bubble.textContent = msg.content;\n row.appendChild(bubble);\n }\n\n // Interactive payload: reuse the backend `web` render shape.\n if (msg.interactive && Array.isArray(msg.interactive)) {\n for (const inter of msg.interactive) {\n const el = this.renderInteractive(inter);\n if (el) row.appendChild(el);\n }\n }\n\n this.thread.appendChild(row);\n this.scrollToBottom();\n }\n\n /** Render a `web`-format interactive message. Currently product_carousel. */\n private renderInteractive(inter: Record<string, unknown>): HTMLElement | null {\n const type = inter?.type as string | undefined;\n if (type !== 'product_carousel') return null;\n const products = (inter.products as Array<Record<string, unknown>>) || [];\n if (!products.length) return null;\n\n const carousel = document.createElement('div');\n carousel.className = 'aegis-chat-carousel';\n for (const p of products) {\n const card = document.createElement('a');\n card.className = 'aegis-chat-card';\n const href = (p.cta_url as string) || '#';\n card.href = href;\n card.target = '_blank';\n card.rel = 'noopener noreferrer';\n\n if (p.image_url) {\n const img = document.createElement('img');\n img.className = 'aegis-chat-card-img';\n img.src = p.image_url as string;\n img.alt = (p.name as string) || '';\n img.loading = 'lazy';\n card.appendChild(img);\n }\n const name = document.createElement('div');\n name.className = 'aegis-chat-card-name';\n name.textContent = (p.name as string) || '';\n card.appendChild(name);\n\n if (p.price != null) {\n const price = document.createElement('div');\n price.className = 'aegis-chat-card-price';\n price.textContent = typeof p.price === 'number' ? String(p.price) : String(p.price);\n card.appendChild(price);\n }\n carousel.appendChild(card);\n }\n\n if (typeof inter.browse_all_url === 'string' && inter.browse_all_url) {\n const more = document.createElement('a');\n more.className = 'aegis-chat-card aegis-chat-card--more';\n more.href = inter.browse_all_url;\n more.target = '_blank';\n more.rel = 'noopener noreferrer';\n more.textContent = 'View all →';\n carousel.appendChild(more);\n }\n return carousel;\n }\n\n private appendSystem(textContent: string): void {\n this.appendBubble({ id: `sys_${Date.now()}`, sender: 'system', role: 'system', content: textContent });\n }\n\n private appendSystemGreeting(textContent: string): void {\n this.appendBubble({ id: `greeting_${Date.now()}`, sender: 'assistant', role: 'bot', content: textContent });\n }\n\n // ── Unread badge ─────────────────────────────────────────────────────────\n\n private bumpUnread(): void {\n this.unread += 1;\n if (this.badge) {\n this.badge.textContent = String(this.unread);\n this.badge.style.display = 'flex';\n }\n }\n\n private clearUnread(): void {\n this.unread = 0;\n if (this.badge) this.badge.style.display = 'none';\n }\n\n // ── helpers ──────────────────────────────────────────────────────────────\n\n private scrollToBottom(): void {\n if (this.thread) this.thread.scrollTop = this.thread.scrollHeight;\n }\n\n private readAnonId(): string | undefined {\n if (typeof document === 'undefined') return undefined;\n try {\n return new Storage().get('anon_id') ?? undefined;\n } catch {\n return undefined;\n }\n }\n\n // ── Typing indicator ───────────────────────────────────────────────────────\n\n private showTyping(): void {\n if (!this.thread || this.typingEl) return;\n const row = document.createElement('div');\n row.className = 'aegis-chat-msg aegis-chat-msg--assistant aegis-chat-typing';\n row.innerHTML =\n '<div class=\"aegis-chat-bubbletext aegis-chat-typingdots\"><span></span><span></span><span></span></div>';\n this.thread.appendChild(row);\n this.typingEl = row;\n this.scrollToBottom();\n }\n\n private hideTyping(): void {\n if (this.typingEl) {\n this.typingEl.remove();\n this.typingEl = undefined;\n }\n }\n\n // ── Attention affordance (pulse + one-time greeting tooltip) ────────────────\n\n private scheduleAttention(): void {\n if (typeof window === 'undefined') return;\n // Let the page settle, then draw the eye to the bubble: a pulsing ring +\n // the greeting tooltip. Only if the visitor hasn't engaged yet.\n this.attentionTimer = setTimeout(() => {\n if (this.hasInteracted || this.open) return;\n this.bubble?.classList.add('aegis-chat-bubble--pulse');\n this.greetingTip?.classList.add('aegis-chat-tip--show');\n }, ATTENTION_DELAY_MS);\n }\n\n private dismissAttention(): void {\n if (this.attentionTimer) {\n clearTimeout(this.attentionTimer);\n this.attentionTimer = undefined;\n }\n this.bubble?.classList.remove('aegis-chat-bubble--pulse');\n this.greetingTip?.classList.remove('aegis-chat-tip--show');\n }\n\n private log(...args: unknown[]): void {\n if (this.debugMode) console.log('[AegisChat]', ...args);\n }\n\n private injectStyles(): void {\n if (typeof document === 'undefined' || document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = CHAT_CSS;\n document.head.appendChild(style);\n }\n}\n\nconst CHAT_CSS = `\n.aegis-chat-root{position:fixed;bottom:20px;right:20px;z-index:2147483000;font-family:Inter,system-ui,-apple-system,sans-serif}\n.aegis-chat-root--bottom-left{left:20px;right:auto}\n.aegis-chat-root--bottom-left .aegis-chat-panel{left:0;right:auto}\n.aegis-chat-bubble-logo{width:34px;height:34px;border-radius:9999px;object-fit:cover}\n.aegis-chat-bubble{width:60px;height:60px;border-radius:9999px;border:none;background:var(--aegis-chat-accent,#4169e1);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 8px 24px rgba(0,0,0,.18);transition:transform .18s ease,box-shadow .18s ease;position:relative;animation:aegis-chat-in .4s cubic-bezier(.16,1,.3,1)}\n.aegis-chat-bubble:hover{transform:translateY(-2px) scale(1.04);box-shadow:0 12px 28px rgba(0,0,0,.22)}\n.aegis-chat-bubble--hidden{display:none}\n/* Attention pulse — an expanding accent ring that draws the eye to a live, ready assistant. */\n.aegis-chat-bubble--pulse::before{content:\"\";position:absolute;inset:0;border-radius:9999px;background:var(--aegis-chat-accent,#4169e1);z-index:-1;animation:aegis-chat-pulse 1.8s ease-out infinite}\n.aegis-chat-bubble--pulse{animation:aegis-chat-in .4s cubic-bezier(.16,1,.3,1),aegis-chat-nudge 1.8s ease-in-out 2}\n@keyframes aegis-chat-in{from{opacity:0;transform:scale(.6)}to{opacity:1;transform:scale(1)}}\n@keyframes aegis-chat-pulse{0%{transform:scale(1);opacity:.55}100%{transform:scale(1.9);opacity:0}}\n@keyframes aegis-chat-nudge{0%,100%{transform:translateY(0)}25%{transform:translateY(-5px)}50%{transform:translateY(0)}}\n/* One-time greeting tooltip */\n.aegis-chat-tip{position:absolute;bottom:14px;right:74px;max-width:230px;background:#fff;color:#0f172a;border:1px solid #e2e8f0;border-radius:14px;border-bottom-right-radius:4px;box-shadow:0 10px 30px rgba(0,0,0,.16);padding:10px 30px 10px 13px;font-size:13.5px;line-height:1.4;cursor:pointer;opacity:0;transform:translateX(8px) scale(.92);transform-origin:bottom right;pointer-events:none;transition:opacity .25s ease,transform .25s ease}\n.aegis-chat-tip--show{opacity:1;transform:translateX(0) scale(1);pointer-events:auto}\n.aegis-chat-tip-close{position:absolute;top:5px;right:6px;width:18px;height:18px;border:none;background:transparent;color:#94a3b8;font-size:12px;line-height:1;cursor:pointer;border-radius:9999px}\n.aegis-chat-tip-close:hover{background:#f1f5f9;color:#475569}\n@media (prefers-reduced-motion:reduce){.aegis-chat-bubble,.aegis-chat-bubble--pulse{animation:none}.aegis-chat-bubble--pulse::before{animation:none;display:none}}\n.aegis-chat-badge{position:absolute;top:-2px;right:-2px;min-width:20px;height:20px;padding:0 5px;border-radius:9999px;background:#ef4444;color:#fff;font-size:12px;font-weight:600;display:flex;align-items:center;justify-content:center}\n.aegis-chat-panel{position:absolute;bottom:0;right:0;width:380px;max-width:calc(100vw - 32px);height:560px;max-height:calc(100vh - 48px);background:#fff;border-radius:16px;box-shadow:0 16px 48px rgba(0,0,0,.24);display:none;flex-direction:column;overflow:hidden}\n.aegis-chat-panel--open{display:flex}\n.aegis-chat-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;background:var(--aegis-chat-accent,#4169e1);color:#fff}\n.aegis-chat-title{font-weight:600;font-size:15px}\n.aegis-chat-close{background:transparent;border:none;color:#fff;font-size:16px;cursor:pointer;opacity:.85}\n.aegis-chat-close:hover{opacity:1}\n.aegis-chat-thread{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px;background:#f8fafc}\n.aegis-chat-msg{display:flex;flex-direction:column;max-width:85%}\n.aegis-chat-msg--customer{align-self:flex-end;align-items:flex-end}\n.aegis-chat-msg--assistant,.aegis-chat-msg--system{align-self:flex-start;align-items:flex-start}\n.aegis-chat-bubbletext{padding:9px 13px;border-radius:14px;font-size:14px;line-height:1.45;white-space:pre-wrap;word-break:break-word}\n.aegis-chat-msg--customer .aegis-chat-bubbletext{background:var(--aegis-chat-accent,#4169e1);color:#fff;border-bottom-right-radius:4px}\n.aegis-chat-msg--assistant .aegis-chat-bubbletext{background:#fff;color:#0f172a;border:1px solid #e2e8f0;border-bottom-left-radius:4px}\n.aegis-chat-quickreplies{display:flex;flex-wrap:wrap;gap:6px;padding:2px 4px 6px;justify-content:flex-start}\n.aegis-chat-chip{appearance:none;cursor:pointer;border:1px solid var(--aegis-chat-accent,#4169e1);background:#fff;color:var(--aegis-chat-accent,#4169e1);border-radius:9999px;padding:6px 12px;font-size:13px;line-height:1;font-family:inherit;transition:background .15s,color .15s}\n.aegis-chat-chip:hover{background:var(--aegis-chat-accent,#4169e1);color:#fff}\n.aegis-chat-msg--system .aegis-chat-bubbletext{background:#fef3c7;color:#92400e;font-size:13px}\n.aegis-chat-typingdots{display:flex;gap:4px;align-items:center;padding:12px 14px}\n.aegis-chat-typingdots span{width:7px;height:7px;border-radius:9999px;background:#94a3b8;display:inline-block;animation:aegis-chat-typing 1.2s infinite ease-in-out}\n.aegis-chat-typingdots span:nth-child(2){animation-delay:.18s}\n.aegis-chat-typingdots span:nth-child(3){animation-delay:.36s}\n@keyframes aegis-chat-typing{0%,80%,100%{transform:translateY(0);opacity:.4}40%{transform:translateY(-4px);opacity:1}}\n.aegis-chat-carousel{display:flex;gap:10px;overflow-x:auto;padding:8px 0;max-width:320px;scroll-snap-type:x mandatory}\n.aegis-chat-card{flex:0 0 140px;scroll-snap-align:start;background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:8px;text-decoration:none;color:#0f172a;display:flex;flex-direction:column;gap:4px;transition:box-shadow .15s ease}\n.aegis-chat-card:hover{box-shadow:0 6px 16px rgba(0,0,0,.1)}\n.aegis-chat-card-img{width:100%;height:96px;object-fit:cover;border-radius:8px}\n.aegis-chat-card-name{font-size:13px;font-weight:500;line-height:1.3;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.aegis-chat-card-price{font-size:13px;font-weight:600;color:var(--aegis-chat-accent,#4169e1)}\n.aegis-chat-card--more{align-items:center;justify-content:center;font-weight:600;color:var(--aegis-chat-accent,#4169e1)}\n.aegis-chat-composer{display:flex;align-items:flex-end;gap:8px;padding:12px;border-top:1px solid #e2e8f0;background:#fff}\n.aegis-chat-input{flex:1;resize:none;border:1px solid #e2e8f0;border-radius:12px;padding:9px 12px;font-size:14px;font-family:inherit;max-height:96px;outline:none}\n.aegis-chat-input:focus{border-color:var(--aegis-chat-accent,#4169e1)}\n.aegis-chat-send{width:40px;height:40px;border-radius:9999px;border:none;background:var(--aegis-chat-accent,#4169e1);color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;flex:0 0 auto}\n/* Mobile: raise the bubble above the storefront's full-width cart bar so they\n never overlap; widen the panel and reduce the tooltip width. */\n@media (max-width:480px){\n .aegis-chat-root{bottom:84px;right:16px}\n .aegis-chat-panel{width:calc(100vw - 24px);height:calc(100vh - 140px)}\n .aegis-chat-tip{max-width:200px}\n}\n`;\n","/**\n * TriggerEngine - Client-Side Trigger Evaluation\n * \n * Evaluates behavioral triggers that require real-time client state:\n * - Scroll depth (e.g., user scrolled >= 50%)\n * - Time on page (e.g., >= 30 seconds on current page)\n * - Exit intent (mouse leaving viewport toward browser controls)\n * - Inactivity (no user interaction for X seconds)\n * - Scroll velocity (mobile exit intent - fast upward scroll)\n * - Visibility change (tab/app switching)\n * - Back button (history navigation)\n * \n * Architecture:\n * - Server evaluates historical triggers (event counts, segments)\n * - Client evaluates behavioral triggers (scroll, time, exit intent)\n * - Zero latency - no server round trip needed\n * \n * Usage:\n * const trigger = new TriggerEngine();\n * trigger.on('scroll_depth_50', (data) => {\n * console.log('User scrolled to 50%', data);\n * });\n * trigger.start();\n */\n\nexport interface TriggerRule {\n type: 'scroll_depth' | 'time_on_page' | 'exit_intent' | 'inactivity' | 'scroll_velocity' | 'visibility_change' | 'back_button';\n config: ScrollDepthConfig | TimeOnPageConfig | ExitIntentConfig | InactivityConfig | ScrollVelocityConfig | VisibilityChangeConfig | BackButtonConfig;\n}\n\nexport interface ScrollDepthConfig {\n depth_percent: number;\n}\n\nexport interface TimeOnPageConfig {\n seconds: number;\n}\n\nexport interface ExitIntentConfig {\n enabled: boolean;\n}\n\nexport interface InactivityConfig {\n idle_seconds: number;\n}\n\nexport interface ScrollVelocityConfig {\n threshold: number;\n minScrollPosition: number;\n cooldown: number;\n}\n\nexport interface VisibilityChangeConfig {\n enabled: boolean;\n}\n\nexport interface BackButtonConfig {\n enabled: boolean;\n}\n\n/**\n * Rage-click detection (Micro-Intent Engine P2 Task 1).\n *\n * Per-intent ring buffer: when ≥ `threshold` clicks land on the same\n * intent inside `windowMs`, the engine emits `rage_click` with the\n * intent name + current count + window. Frustration signal used by the\n * Stuck-at-Checkout pattern (e.g., rage-clicking the coupon input four\n * times in 800ms).\n *\n * Defaults match the plan:\n * threshold = 3 clicks\n * windowMs = 1000 ms\n *\n * TriggerEngine does NOT attach its own pointerdown listener — the\n * SelectorBinder (P1 Task 5) owns the global, delegated listener and\n * dispatches per-intent click events. The IntentSnapshotCollector\n * (P2 Task 5) wires `SelectorBinder.onIntent` to\n * `TriggerEngine.noteClick(intent)` so TriggerEngine sees a clean\n * intent-stamped stream instead of raw DOM events.\n */\nexport interface RageClickConfig {\n threshold: number;\n windowMs: number;\n}\n\n/** Payload emitted on the `rage_click` event. */\nexport interface RageClickData {\n intent: string;\n count: number;\n window_ms: number;\n}\n\n/**\n * Hover-dwell tracking (Micro-Intent Engine P2 Task 2).\n *\n * Tracks per-intent hover duration in milliseconds. `getHoverMs(intent)`\n * returns:\n * - if currently hovering the intent: ms since hover_start (live)\n * - else: ms duration of the most recent hover on that intent (sticky)\n * - if never hovered: 0\n *\n * The sticky behaviour is deliberate. The canonical use case\n * (MICRO_INTENT_ENGINE.md Story 1):\n * \"Priya hovers price for 1.8s, considers, moves cursor away.\n * Exit_intent fires. Rule checks price_hover_ms >= 1500 → true.\"\n * The rule evaluator queries `price_hover_ms` AFTER the hover ends. If\n * we reset to 0 on hover_end, the rule never matches the very pattern\n * the engine exists to detect.\n *\n * Threshold-based emission: when a hover crosses one of the registered\n * dwell targets (e.g. 1500ms), a `<intent>_hover_dwell_<ms>` event\n * fires. Useful for journeys that want event-style hooks; the\n * snapshot-style `getHoverMs` is the primary surface for the\n * compound-rule evaluator.\n */\nexport interface HoverDwellConfig {\n /** Dwell thresholds (ms) per intent. The engine fires\n * `<intent>_hover_dwell_<ms>` when an active hover crosses each\n * threshold. Defaults: price→[1500], cta→[1500]. */\n thresholdsByIntent?: Partial<Record<string, ReadonlyArray<number>>>;\n}\n\n/**\n * Mouse velocity toward the viewport top (Micro-Intent Engine P2 Task 3).\n *\n * Detects the early phase of exit-intent: the mouse moving rapidly\n * upward before it actually crosses out of the viewport. The signal is\n * a continuous px/ms value (positive = moving up), updated as samples\n * arrive. When velocity crosses `threshold`, a `mouse_velocity_to_top`\n * event fires (once per session-window cooldown to avoid spamming on a\n * single gesture).\n *\n * Sampling: callers feed positions via `noteMousePosition(x, y, ts)`.\n * The engine keeps a sliding `windowMs` ring buffer of samples and\n * computes velocity as the average dy / dt over samples in the window.\n * Per the plan: sampled at 100ms, 400ms window. That bound is\n * configurable.\n *\n * Why \"to top\" specifically: exit-intent fires only when y crosses 0;\n * we want the warning BEFORE that. A typical exit-intent gesture has\n * upward velocity well above any normal browsing motion.\n */\nexport interface MouseVelocityConfig {\n /** Threshold in px/ms (positive = moving up). Default 1.5 px/ms,\n * ≈ moving 600px in 400ms, which only happens during a deliberate\n * upward sweep. */\n threshold: number;\n /** Rolling-window length over which to compute velocity. */\n windowMs: number;\n /** Cooldown after a fire before the signal can fire again. */\n cooldownMs: number;\n}\n\nexport interface TriggerEvent {\n type: string;\n data: Record<string, any>;\n timestamp: number;\n}\n\ntype TriggerCallback = (event: TriggerEvent) => void;\n\nexport class TriggerEngine {\n private listeners: Map<string, Set<TriggerCallback>> = new Map();\n private isStarted = false;\n \n private scrollDepthTargets = new Set<number>();\n private scrollDepthReached = new Set<number>();\n \n private timeOnPageTargets = new Map<number, number>();\n private pageLoadTime?: number;\n \n private exitIntentEnabled = false;\n private exitIntentFired = false;\n \n private inactivityTargets = new Map<number, number>();\n private lastActivityTime = Date.now();\n private inactivityCheckInterval?: number;\n \n private scrollVelocityEnabled = false;\n private scrollVelocityFired = false;\n private scrollVelocityConfig: ScrollVelocityConfig = {\n threshold: 0.5,\n minScrollPosition: 100,\n cooldown: 5000\n };\n private lastScrollY = 0;\n private lastScrollTime = Date.now();\n private scrollVelocityCooldownTimer?: number;\n \n private visibilityChangeEnabled = false;\n\n private backButtonEnabled = false;\n private backButtonFired = false;\n\n // Rage-click state (P2 Task 1). Buffer indexed by intent name (price /\n // cta / coupon / checkout). Per-intent so rage-clicking the coupon\n // input doesn't get conflated with rapid CTA presses.\n private rageClickEnabled = false;\n private rageClickConfig: RageClickConfig = { threshold: 3, windowMs: 1000 };\n private rageClickBuffer = new Map<string, number[]>();\n /** Tracks whether a rage_click event has already fired for an intent\n * in the current burst. Reset when the buffer empties below threshold.\n * Prevents the same burst from firing the event N-2 times as each\n * click after threshold pushes the count higher. */\n private rageClickFiredInBurst = new Set<string>();\n\n // Hover-dwell state (P2 Task 2). Tracks live + sticky-last dwell per\n // intent. `hoverStartAt` undefined means no active hover.\n private hoverEnabled = false;\n private hoverStartAt = new Map<string, number>();\n private hoverLastMs = new Map<string, number>();\n private hoverThresholds = new Map<string, ReadonlyArray<number>>([\n ['price', [1500]],\n ['cta', [1500]],\n ]);\n /** Track which (intent, threshold) pairs have already fired in the\n * current hover so a single long hover doesn't double-fire as time\n * marches on. Reset on hover_start. */\n private hoverThresholdsFired = new Map<string, Set<number>>();\n /** Pending threshold timers, keyed by intent. Cleared on hover_end. */\n private hoverThresholdTimers = new Map<string, number[]>();\n\n // Mouse-velocity-to-top state (P2 Task 3).\n private mouseVelEnabled = false;\n private mouseVelConfig: MouseVelocityConfig = {\n threshold: 1.5,\n windowMs: 400,\n cooldownMs: 5000,\n };\n /** Ring buffer of (x, y, ts) samples within the rolling window. */\n private mouseSamples: Array<{ x: number; y: number; ts: number }> = [];\n /** Last computed velocity-to-top in px/ms (positive = moving up). */\n private mouseVelLast = 0;\n /** Epoch ms when the velocity event last fired — gates cooldown. */\n private mouseVelLastFiredAt = 0;\n\n constructor() {}\n \n on(eventType: string, callback: TriggerCallback): void {\n if (!this.listeners.has(eventType)) {\n this.listeners.set(eventType, new Set());\n }\n this.listeners.get(eventType)!.add(callback);\n }\n \n off(eventType: string, callback: TriggerCallback): void {\n const callbacks = this.listeners.get(eventType);\n if (callbacks) {\n callbacks.delete(callback);\n }\n }\n \n registerScrollDepth(depthPercent: number): void {\n this.scrollDepthTargets.add(depthPercent);\n }\n \n registerTimeOnPage(seconds: number): void {\n if (!this.timeOnPageTargets.has(seconds)) {\n const timerId = window.setTimeout(() => {\n this.emit(`time_on_page_${seconds}`, {\n seconds,\n page_url: window.location.href\n });\n this.timeOnPageTargets.delete(seconds);\n }, seconds * 1000);\n \n this.timeOnPageTargets.set(seconds, timerId);\n }\n }\n \n registerExitIntent(): void {\n this.exitIntentEnabled = true;\n }\n \n registerInactivity(idleSeconds: number): void {\n if (!this.inactivityTargets.has(idleSeconds)) {\n const timerId = window.setTimeout(() => {\n const idleTime = (Date.now() - this.lastActivityTime) / 1000;\n \n if (idleTime >= idleSeconds) {\n this.emit(`inactivity_${idleSeconds}`, {\n idle_seconds: idleSeconds,\n actual_idle_time: idleTime\n });\n }\n \n this.inactivityTargets.delete(idleSeconds);\n }, idleSeconds * 1000);\n \n this.inactivityTargets.set(idleSeconds, timerId);\n }\n }\n \n registerScrollVelocity(config?: Partial<ScrollVelocityConfig>): void {\n this.scrollVelocityEnabled = true;\n \n if (config) {\n this.scrollVelocityConfig = {\n threshold: config.threshold ?? this.scrollVelocityConfig.threshold,\n minScrollPosition: config.minScrollPosition ?? this.scrollVelocityConfig.minScrollPosition,\n cooldown: config.cooldown ?? this.scrollVelocityConfig.cooldown\n };\n }\n }\n \n registerVisibilityChange(): void {\n this.visibilityChangeEnabled = true;\n }\n \n registerBackButton(): void {\n this.backButtonEnabled = true;\n }\n\n /**\n * Enable rage-click detection (P2 Task 1).\n *\n * After calling this, feed click events via `noteClick(intent)`.\n * SelectorBinder (P1 Task 5) is the upstream source; the wiring lives\n * in IntentSnapshotCollector (P2 Task 5). Calling `noteClick` without\n * a prior `registerRageClick()` is a no-op so legacy callers don't\n * accidentally enable the feature.\n */\n registerRageClick(config?: Partial<RageClickConfig>): void {\n this.rageClickEnabled = true;\n if (config) {\n this.rageClickConfig = {\n threshold: config.threshold ?? this.rageClickConfig.threshold,\n windowMs: config.windowMs ?? this.rageClickConfig.windowMs,\n };\n }\n }\n\n /**\n * Feed a click event for rage-click detection. Returns the current\n * count within-window for the intent — useful for the snapshot\n * collector (P2 Task 5) which updates IntentRuleEvaluator with\n * `rage_click_count` continuously, not just at the burst threshold.\n *\n * Idempotent w.r.t. `registerRageClick` — when not enabled, this\n * returns 0 without buffering.\n */\n noteClick(intent: string, timestamp: number = Date.now()): number {\n if (!this.rageClickEnabled) return 0;\n const buf = this.rageClickBuffer.get(intent) ?? [];\n const cutoff = timestamp - this.rageClickConfig.windowMs;\n // Drop expired timestamps (clicks older than the window).\n // The buffer is append-only and timestamps are non-decreasing in\n // practice (Date.now is monotonic per device, modulo system-clock\n // adjustments), so an in-place trim from the head is correct.\n let trimStart = 0;\n while (trimStart < buf.length && buf[trimStart] < cutoff) trimStart++;\n const recent = trimStart === 0 ? buf : buf.slice(trimStart);\n recent.push(timestamp);\n this.rageClickBuffer.set(intent, recent);\n\n // Burst reset: when the recent count drops below threshold (because\n // older clicks aged out), the burst is over — re-arm the per-intent\n // fire-once latch so a fresh burst can fire again.\n if (recent.length < this.rageClickConfig.threshold) {\n this.rageClickFiredInBurst.delete(intent);\n }\n\n if (\n recent.length >= this.rageClickConfig.threshold &&\n !this.rageClickFiredInBurst.has(intent)\n ) {\n this.rageClickFiredInBurst.add(intent);\n this.emit('rage_click', {\n intent,\n count: recent.length,\n window_ms: this.rageClickConfig.windowMs,\n });\n }\n\n return recent.length;\n }\n\n /** Snapshot the current rage_click count for an intent. The\n * IntentSnapshotCollector (P2 Task 5) calls this when building the\n * `rage_click_count` signal value for the IntentRuleEvaluator. */\n getRageClickCount(intent: string): number {\n if (!this.rageClickEnabled) return 0;\n const buf = this.rageClickBuffer.get(intent);\n if (!buf) return 0;\n const cutoff = Date.now() - this.rageClickConfig.windowMs;\n // Lazy prune on read so the count reflects only currently-valid\n // clicks. Cheap because buffers are tiny (cap at threshold + 1 in\n // practice — older entries get dropped on every note).\n let live = 0;\n for (const ts of buf) {\n if (ts >= cutoff) live++;\n }\n return live;\n }\n\n /**\n * Enable hover-dwell tracking (P2 Task 2). After registration, feed\n * hover events via `noteHoverStart(intent, ts)` / `noteHoverEnd`.\n * SelectorBinder (P1 Task 5) is the upstream source; wiring lands in\n * P2 Task 5.\n */\n registerHoverDwell(config?: HoverDwellConfig): void {\n this.hoverEnabled = true;\n if (config?.thresholdsByIntent) {\n for (const [intent, thresholds] of Object.entries(config.thresholdsByIntent)) {\n if (thresholds) this.hoverThresholds.set(intent, thresholds);\n }\n }\n }\n\n /** Record the start of a hover on the named intent. Schedules\n * per-threshold timers that emit `<intent>_hover_dwell_<ms>` when\n * the active hover passes each registered threshold. */\n noteHoverStart(intent: string, timestamp: number = Date.now()): void {\n if (!this.hoverEnabled) return;\n // If a prior hover is still pending (no hover_end fired — possible\n // when the DOM node was unmounted mid-hover), close it out first to\n // keep `hoverLastMs` consistent.\n if (this.hoverStartAt.has(intent)) {\n this.noteHoverEnd(intent, timestamp);\n }\n this.hoverStartAt.set(intent, timestamp);\n this.hoverThresholdsFired.set(intent, new Set());\n\n // Schedule threshold timers. Uses the global setTimeout (works in\n // both browser and node, and vitest's fake-timers stub the global).\n // registerHoverDwell with no thresholds for an intent => no events,\n // only the snapshot value.\n const thresholds = this.hoverThresholds.get(intent);\n if (thresholds) {\n const timers: number[] = [];\n for (const ms of thresholds) {\n const timerId = setTimeout(() => {\n // Only fire if still hovering this intent — the event must\n // not fire after hover_end.\n if (!this.hoverStartAt.has(intent)) return;\n const firedSet = this.hoverThresholdsFired.get(intent);\n if (firedSet?.has(ms)) return;\n firedSet?.add(ms);\n this.emit(`${intent}_hover_dwell_${ms}`, {\n intent,\n threshold_ms: ms,\n actual_ms: Date.now() - timestamp,\n });\n }, ms) as unknown as number;\n timers.push(timerId);\n }\n this.hoverThresholdTimers.set(intent, timers);\n }\n }\n\n /** Record the end of a hover on the named intent. Updates the sticky\n * `lastHoverMs` so `getHoverMs` keeps returning the last-known\n * duration until the next hover_start. */\n noteHoverEnd(intent: string, timestamp: number = Date.now()): void {\n if (!this.hoverEnabled) return;\n const startAt = this.hoverStartAt.get(intent);\n if (startAt === undefined) return;\n const dwell = Math.max(0, timestamp - startAt);\n this.hoverLastMs.set(intent, dwell);\n this.hoverStartAt.delete(intent);\n // Clear pending threshold timers for this intent.\n const pending = this.hoverThresholdTimers.get(intent);\n if (pending) {\n for (const id of pending) clearTimeout(id);\n this.hoverThresholdTimers.delete(intent);\n }\n this.hoverThresholdsFired.delete(intent);\n }\n\n /**\n * Enable mouse-velocity-to-top tracking (P2 Task 3). After\n * registration, feed positions via `noteMousePosition(x, y, ts?)`.\n * IntentSnapshotCollector (P2 Task 5) wires window 'mousemove' to\n * this method, with throttling to ~100ms per the plan.\n */\n registerMouseVelocityToTop(config?: Partial<MouseVelocityConfig>): void {\n this.mouseVelEnabled = true;\n if (config) {\n this.mouseVelConfig = {\n threshold: config.threshold ?? this.mouseVelConfig.threshold,\n windowMs: config.windowMs ?? this.mouseVelConfig.windowMs,\n cooldownMs: config.cooldownMs ?? this.mouseVelConfig.cooldownMs,\n };\n }\n }\n\n /** Feed a mouse-position sample. Recomputes the rolling-window\n * velocity-to-top and fires `mouse_velocity_to_top` when the value\n * crosses the configured threshold (subject to cooldown). */\n noteMousePosition(x: number, y: number, timestamp: number = Date.now()): number {\n if (!this.mouseVelEnabled) return 0;\n const cutoff = timestamp - this.mouseVelConfig.windowMs;\n // Trim expired samples from the head; keep the buffer small.\n let trimStart = 0;\n while (trimStart < this.mouseSamples.length && this.mouseSamples[trimStart].ts < cutoff) {\n trimStart++;\n }\n if (trimStart > 0) this.mouseSamples = this.mouseSamples.slice(trimStart);\n this.mouseSamples.push({ x, y, ts: timestamp });\n\n // Velocity-to-top = -(dy / dt) over the oldest-to-newest pair in\n // the window. Positive value = moving up. With 2+ samples this is\n // the instantaneous slope across the window; with 1 sample we\n // return 0 (cannot compute velocity from a single point).\n if (this.mouseSamples.length < 2) {\n this.mouseVelLast = 0;\n return 0;\n }\n const oldest = this.mouseSamples[0];\n const newest = this.mouseSamples[this.mouseSamples.length - 1];\n const dt = newest.ts - oldest.ts;\n if (dt <= 0) {\n this.mouseVelLast = 0;\n return 0;\n }\n const velocity = -(newest.y - oldest.y) / dt; // px/ms; up = +\n this.mouseVelLast = velocity;\n\n // Threshold + cooldown firing. Initial state allows the first fire\n // — only subsequent fires within cooldownMs of the prior are gated.\n const cooldownOk =\n this.mouseVelLastFiredAt === 0 ||\n timestamp - this.mouseVelLastFiredAt >= this.mouseVelConfig.cooldownMs;\n if (velocity >= this.mouseVelConfig.threshold && cooldownOk) {\n this.mouseVelLastFiredAt = timestamp;\n this.emit('mouse_velocity_to_top', {\n velocity,\n threshold: this.mouseVelConfig.threshold,\n window_ms: this.mouseVelConfig.windowMs,\n samples: this.mouseSamples.length,\n });\n }\n return velocity;\n }\n\n /** Snapshot the current velocity-to-top in px/ms (positive = up).\n * Returns 0 when not enabled or insufficient samples. */\n getMouseVelocityToTop(): number {\n return this.mouseVelEnabled ? this.mouseVelLast : 0;\n }\n\n /**\n * Snapshot the hover dwell for an intent.\n * - Currently hovering: returns `Date.now() - hover_start_at`.\n * - Hovered before, not currently: returns the most recent hover's\n * duration (sticky — the rule evaluator queries this AFTER\n * mouseleave to see \"did Priya hover the price ≥ 1.5s?\").\n * - Never hovered: returns 0.\n */\n getHoverMs(intent: string): number {\n if (!this.hoverEnabled) return 0;\n const startAt = this.hoverStartAt.get(intent);\n if (startAt !== undefined) {\n return Math.max(0, Date.now() - startAt);\n }\n return this.hoverLastMs.get(intent) ?? 0;\n }\n\n start(): void {\n if (this.isStarted) {\n return;\n }\n \n this.pageLoadTime = Date.now();\n this.lastActivityTime = Date.now();\n this.lastScrollY = window.scrollY || 0;\n this.lastScrollTime = Date.now();\n \n if (this.scrollDepthTargets.size > 0) {\n this.attachScrollListener();\n }\n \n if (this.exitIntentEnabled) {\n this.attachExitIntentListener();\n }\n \n if (this.scrollVelocityEnabled) {\n this.attachScrollVelocityListener();\n }\n \n if (this.visibilityChangeEnabled) {\n this.attachVisibilityChangeListener();\n }\n \n if (this.backButtonEnabled) {\n this.attachBackButtonListener();\n }\n \n this.attachActivityListeners();\n \n this.startInactivityCheck();\n \n this.isStarted = true;\n }\n \n stop(): void {\n if (!this.isStarted) {\n return;\n }\n \n this.removeScrollListener();\n this.removeExitIntentListener();\n this.removeScrollVelocityListener();\n this.removeVisibilityChangeListener();\n this.removeBackButtonListener();\n this.removeActivityListeners();\n \n this.timeOnPageTargets.forEach(timerId => clearTimeout(timerId));\n this.timeOnPageTargets.clear();\n \n this.inactivityTargets.forEach(timerId => clearTimeout(timerId));\n this.inactivityTargets.clear();\n \n if (this.inactivityCheckInterval) {\n clearInterval(this.inactivityCheckInterval);\n this.inactivityCheckInterval = undefined;\n }\n \n if (this.scrollVelocityCooldownTimer) {\n clearTimeout(this.scrollVelocityCooldownTimer);\n this.scrollVelocityCooldownTimer = undefined;\n }\n \n this.isStarted = false;\n }\n \n reset(): void {\n this.scrollDepthReached.clear();\n this.exitIntentFired = false;\n this.scrollVelocityFired = false;\n this.backButtonFired = false;\n this.pageLoadTime = Date.now();\n this.lastActivityTime = Date.now();\n this.lastScrollY = window.scrollY || 0;\n this.lastScrollTime = Date.now();\n \n if (this.scrollVelocityCooldownTimer) {\n clearTimeout(this.scrollVelocityCooldownTimer);\n this.scrollVelocityCooldownTimer = undefined;\n }\n }\n \n private attachScrollListener(): void {\n window.addEventListener('scroll', this.handleScroll, { passive: true });\n this.handleScroll();\n }\n \n private removeScrollListener(): void {\n window.removeEventListener('scroll', this.handleScroll);\n }\n \n private handleScroll = (): void => {\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;\n const scrollPercent = scrollHeight > 0 ? (scrollTop / scrollHeight) * 100 : 0;\n \n for (const targetDepth of this.scrollDepthTargets) {\n if (scrollPercent >= targetDepth && !this.scrollDepthReached.has(targetDepth)) {\n this.scrollDepthReached.add(targetDepth);\n \n this.emit(`scroll_depth_${targetDepth}`, {\n depth_percent: targetDepth,\n actual_percent: scrollPercent,\n scroll_top: scrollTop,\n scroll_height: scrollHeight\n });\n }\n }\n };\n \n private attachExitIntentListener(): void {\n document.addEventListener('mouseleave', this.handleExitIntent);\n }\n \n private removeExitIntentListener(): void {\n document.removeEventListener('mouseleave', this.handleExitIntent);\n }\n \n private handleExitIntent = (event: MouseEvent): void => {\n if (this.exitIntentFired) {\n return;\n }\n \n if (event.clientY < 10) {\n this.exitIntentFired = true;\n \n this.emit('exit_intent', {\n client_y: event.clientY,\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n }\n };\n \n private attachScrollVelocityListener(): void {\n window.addEventListener('scroll', this.handleScrollVelocity, { passive: true });\n }\n \n private removeScrollVelocityListener(): void {\n window.removeEventListener('scroll', this.handleScrollVelocity);\n }\n \n private handleScrollVelocity = (): void => {\n if (this.scrollVelocityFired) {\n return;\n }\n \n const currentY = window.scrollY || document.documentElement.scrollTop;\n const currentTime = Date.now();\n const timeDiff = currentTime - this.lastScrollTime;\n \n if (timeDiff > 100) {\n const distance = this.lastScrollY - currentY;\n const velocity = Math.abs(distance / timeDiff);\n \n if (\n distance > 0 &&\n velocity > this.scrollVelocityConfig.threshold &&\n currentY > this.scrollVelocityConfig.minScrollPosition\n ) {\n this.scrollVelocityFired = true;\n \n this.emit('mobile_exit_intent', {\n scroll_velocity: velocity,\n scroll_distance: distance,\n current_position: currentY,\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n \n this.scrollVelocityCooldownTimer = window.setTimeout(() => {\n this.scrollVelocityFired = false;\n }, this.scrollVelocityConfig.cooldown);\n }\n \n this.lastScrollY = currentY;\n this.lastScrollTime = currentTime;\n }\n };\n \n private attachVisibilityChangeListener(): void {\n document.addEventListener('visibilitychange', this.handleVisibilityChange);\n }\n \n private removeVisibilityChangeListener(): void {\n document.removeEventListener('visibilitychange', this.handleVisibilityChange);\n }\n \n private handleVisibilityChange = (): void => {\n if (document.hidden) {\n this.emit('visibility_hidden', {\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n } else {\n this.emit('visibility_visible', {\n page_url: window.location.href\n });\n }\n };\n \n private attachBackButtonListener(): void {\n if (typeof window !== 'undefined' && window.history) {\n window.history.pushState(null, '', window.location.href);\n window.addEventListener('popstate', this.handleBackButton);\n }\n }\n \n private removeBackButtonListener(): void {\n window.removeEventListener('popstate', this.handleBackButton);\n }\n \n private handleBackButton = (): void => {\n if (this.backButtonFired) {\n return;\n }\n \n this.backButtonFired = true;\n \n window.history.pushState(null, '', window.location.href);\n \n this.emit('back_button', {\n page_url: window.location.href,\n time_on_page: this.pageLoadTime ? (Date.now() - this.pageLoadTime) / 1000 : 0\n });\n };\n \n private attachActivityListeners(): void {\n const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];\n events.forEach(event => {\n document.addEventListener(event, this.handleActivity, { passive: true });\n });\n }\n \n private removeActivityListeners(): void {\n const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];\n events.forEach(event => {\n document.removeEventListener(event, this.handleActivity);\n });\n }\n \n private handleActivity = (): void => {\n this.lastActivityTime = Date.now();\n };\n \n private startInactivityCheck(): void {\n this.inactivityCheckInterval = window.setInterval(() => {\n const idleTime = (Date.now() - this.lastActivityTime) / 1000;\n \n for (const [idleSeconds] of this.inactivityTargets) {\n if (idleTime >= idleSeconds) {\n this.emit(`inactivity_${idleSeconds}`, {\n idle_seconds: idleSeconds,\n actual_idle_time: idleTime\n });\n \n const timerId = this.inactivityTargets.get(idleSeconds);\n if (timerId) {\n clearTimeout(timerId);\n this.inactivityTargets.delete(idleSeconds);\n }\n }\n }\n }, 1000);\n }\n \n private emit(eventType: string, data: Record<string, any>): void {\n const event: TriggerEvent = {\n type: eventType,\n data,\n timestamp: Date.now()\n };\n \n const callbacks = this.listeners.get(eventType);\n if (callbacks) {\n callbacks.forEach(callback => {\n try {\n callback(event);\n } catch (error) {\n console.error(`Error in trigger callback for ${eventType}:`, error);\n }\n });\n }\n \n const wildcardCallbacks = this.listeners.get('*');\n if (wildcardCallbacks) {\n wildcardCallbacks.forEach(callback => {\n try {\n callback(event);\n } catch (error) {\n console.error(`Error in wildcard trigger callback:`, error);\n }\n });\n }\n }\n}\n","/**\n * Active Web Chat renderer — the \"Shopping Assistant\" chat launcher delivered\n * as a first-class in-app campaign widget (type `active_web_chat`).\n *\n * Unlike the preload-first renderers in this directory (pure DOM mutation, no\n * I/O), Active Web Chat is a *persistent launcher* backed by a stateful chat\n * engine. It does NOT reimplement chat transport — it instantiates the existing\n * `AegisChat` engine (chat/AegisChat.ts) and feeds it config from the campaign's\n * `interactive_config`. The chat SSE stays OFF until the customer opens the\n * panel and is torn down on close — that lifecycle lives entirely in AegisChat\n * (connectSSE/disconnectSSE are panel-gated); this renderer only wires the\n * campaign config + analytics bridge.\n *\n * Singleton per page: there is at most one chat launcher on screen. A repeat\n * delivery (SSE/poll refresh re-arming the same campaign) is a no-op.\n *\n * See docs/architecture/CHAT_WIDGET_AS_INAPP_CAMPAIGN_TRACKER.md.\n */\n\nimport { AegisChat, type AegisChatConfig } from '../../chat/AegisChat';\nimport { TriggerEngine } from '../../triggers/TriggerEngine';\n\nimport type { RenderContext } from './types';\n\n/** Inactivity window (seconds) that `cart_idle` proactive open maps to —\n * matches the legacy runtime's `inactivity_60` chat trigger. */\nconst PROACTIVE_IDLE_SECONDS = 60;\n\n/** SDK credentials the chat engine needs that the campaign payload doesn't\n * carry. Supplied by `AegisInAppManager` (which owns them). */\nexport interface ActiveWebChatCredentials {\n writeKey: string;\n apiHost: string;\n contactId?: string;\n channel?: 'web' | 'in_app';\n}\n\n/** Module-level singleton — at most one launcher per page. */\nlet activeInstance: AegisChat | null = null;\n/** Proactive-open trigger engine for the active launcher (Phase C). */\nlet activeTriggers: TriggerEngine | null = null;\n\nfunction str(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n\n/**\n * Mount the Active Web Chat launcher for `ctx.campaign`. Returns the engine\n * instance (or the existing one if already mounted), or null in non-DOM\n * environments. The bubble is mounted immediately; the chat session (and its\n * SSE) is established only when the customer opens the panel.\n */\nexport function renderActiveWebChat(\n ctx: RenderContext,\n creds: ActiveWebChatCredentials,\n): AegisChat | null {\n if (typeof document === 'undefined') return null;\n // Persistent launcher: one per page. A re-delivery is a no-op (the open\n // session — if any — must not be torn down and re-created underneath the user).\n if (activeInstance) return activeInstance;\n\n const ic = (ctx.campaign.interactive_config || {}) as Record<string, unknown>;\n\n const accent = str(ic.chat_accent_color);\n const logo = str(ic.chat_logo_url);\n const icon = str(ic.chat_icon);\n\n const cfg: AegisChatConfig = {\n writeKey: creds.writeKey,\n apiHost: creds.apiHost,\n contactId: creds.contactId,\n channel: creds.channel ?? 'web',\n title: str(ic.chat_title),\n greeting: str(ic.chat_greeting),\n accentColor: accent ? ctx.sanitizeColor(accent) : undefined,\n icon: icon === 'sparkle' || icon === 'chat' || icon === 'logo' ? icon : undefined,\n logoUrl: logo ? ctx.sanitizeUrl(logo) ?? undefined : undefined,\n position: ic.chat_position === 'bottom-left' ? 'bottom-left' : undefined,\n agentPersona: str(ic.chat_agent_persona),\n quickReplies: Array.isArray(ic.chat_quick_replies)\n ? (ic.chat_quick_replies as unknown[]).filter((q): q is string => typeof q === 'string')\n : undefined,\n // Bridge the engine's session lifecycle to campaign analytics. Per the\n // tracker's event mapping: panel open = engagement (`clicked`), panel close\n // = session end (`dismissed`), disambiguated by the `action` meta. The\n // bubble being visible is the `impression` — fired by the manager.\n onSessionStart: () =>\n ctx.trackEvent(ctx.campaign.id, 'clicked', { meta: { action: 'session_start' } }),\n onSessionEnd: () =>\n ctx.trackEvent(ctx.campaign.id, 'dismissed', { meta: { action: 'session_end' } }),\n onMessageSent: () =>\n ctx.trackEvent(ctx.campaign.id, 'clicked', { meta: { action: 'message_sent' } }),\n };\n\n const chat = new AegisChat(cfg);\n chat.initialize(); // mounts the bubble; NO chat SSE until the panel opens\n activeInstance = chat;\n\n // Phase C — proactive auto-open. Reuses the shared TriggerEngine (the same\n // primitive that powers chat proactive-open in AegisMessageRuntime). The\n // trigger ONLY opens the panel; openPanel() is a no-op if already open, and\n // exit-intent / inactivity each fire once, so this never nags.\n const proactive = (ic.chat_proactive || {}) as Record<string, unknown>;\n const wantExit = proactive.exit_intent === true;\n const wantIdle = proactive.cart_idle === true;\n if (wantExit || wantIdle) {\n const engine = new TriggerEngine();\n if (wantExit) {\n engine.registerExitIntent();\n engine.on('exit_intent', () => chat.openPanel());\n }\n if (wantIdle) {\n engine.registerInactivity(PROACTIVE_IDLE_SECONDS);\n engine.on(`inactivity_${PROACTIVE_IDLE_SECONDS}`, () => chat.openPanel());\n }\n engine.start();\n activeTriggers = engine;\n }\n\n return chat;\n}\n\n/** Tear down the launcher (manager teardown / page unload). */\nexport function disposeActiveWebChat(): void {\n activeTriggers?.stop();\n activeTriggers = null;\n activeInstance?.destroy();\n activeInstance = null;\n}\n","/**\n * AegisInAppManager - Web SDK In-App Messaging Module\n *\n * HTTP polling architecture with client-side evaluation.\n *\n * Security:\n * - XSS Protection: Uses DOM APIs (createElement, textContent) instead of innerHTML\n * - URL Validation: Prevents javascript: protocol injection\n * - CSP Compatible: No inline styles in HTML strings\n *\n * Architecture (RFC 2026-04-16):\n * - Polls /v1/in-app/active on initialize + on identity change\n * - Caches campaigns locally in memory\n * - Evaluates trigger rules client-side\n * - Tracks events (impression, click, dismiss) asynchronously\n *\n * NOTE: Persistent SSE for downstream delivery is disabled by default\n * (enableSSE=false). Tenant dashboards that need realtime (inbox, chat,\n * live page) open SSE directly via Next.js API routes — not via this SDK.\n * End-user storefronts use polling + Web Push for background delivery.\n */\n\nimport type { RenderContext, CartState } from './renderers';\nimport {\n renderCarouselCards,\n renderCoachmarkTour,\n renderProductRecommendation,\n renderProgressBar,\n renderProgressBarInline,\n renderStickyBar,\n renderStories,\n renderStoriesRings,\n renderGame,\n GAME_SUB_TYPES,\n renderVideo,\n renderVideoInline,\n renderActiveWebChat,\n disposeActiveWebChat,\n} from './renderers';\nimport type { AegisChat } from '../chat/AegisChat';\nimport { Storage } from '../utils/storage';\n\n// Read the SDK's persisted anonymous_id from localStorage/cookie if available.\n// Returns undefined when called server-side (no document/window) or when no\n// id has been minted yet — caller falls through to leaving userId unset.\nfunction readAnonIdFromStorage(): string | undefined {\n if (typeof document === 'undefined') return undefined;\n try {\n const storage = new Storage();\n return storage.get('anon_id') ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface InAppCampaign {\n id: string;\n type:\n | 'modal'\n | 'banner'\n | 'tooltip'\n | 'full_screen'\n | 'half_interstitial'\n | 'alert'\n | 'pip'\n | 'video'\n // Stories — full-screen tap-through story/reel sequence (2026-06-14)\n | 'stories'\n // Preload-first display types (2026-04-22 §5.4 of the expansion plan)\n | 'carousel_cards'\n | 'sticky_bar'\n | 'progress_bar'\n | 'coachmark_tour'\n | 'product_recommendation'\n // Active Web Chat — persistent chat launcher backed by the AegisChat engine\n // (2026-06-15). See CHAT_WIDGET_AS_INAPP_CAMPAIGN_TRACKER.md.\n | 'active_web_chat'\n | 'custom_html';\n sub_type?: string;\n title: string;\n body: string;\n image_url?: string;\n video_url?: string;\n action_url?: string;\n button_text?: string;\n background_color?: string;\n text_color?: string;\n priority: number;\n expires_at?: string;\n frequency?: {\n max_impressions?: number;\n max_impressions_per_day?: number;\n cooldown_seconds?: number;\n // Conversion-aware suppression — added by Micro-Intent Engine P0a (2026-04-30).\n // Mirrors cell-plane FrequencyCap. When the host app calls\n // `notifyConversion(goalName)`, every armed campaign whose\n // `suppress_after_conversion_seconds` is set gets silenced for that\n // many seconds (session-scoped via sessionStorage). Prevents the\n // \"showing 10% off to a buyer who just paid full price\" failure mode.\n suppress_after_conversion_seconds?: number;\n suppress_after_dismiss_seconds?: number;\n scope?: 'session' | 'user' | 'user_sku';\n };\n interactive_config?: Record<string, unknown>;\n client_trigger?: {\n type: string;\n config?: Record<string, unknown>;\n };\n assigned_variant_id?: string;\n // F2 — campaign-delivery surface selection. When the array contains\n // 'embedded_card' AND the page has a `[data-aegis-slot=\"<widget_category>\"]`\n // anchor, the SDK renders this campaign INTO the slot (in addition to or\n // instead of an overlay; see `renderIntoSlots`). Defaults to\n // `['in_app_overlay']` server-side so legacy campaigns keep auto-overlay\n // behavior unchanged.\n delivery_modes?: Array<'in_app_overlay' | 'embedded_card' | 'standalone_page'>;\n // F3 — wide grouping discriminator used as the slot lookup key. A campaign\n // with `widget_category='feedback'` will fill the first\n // `[data-aegis-slot=\"feedback\"]` element on the page (if `embedded_card` is\n // among its delivery_modes).\n widget_category?: 'feedback' | 'loyalty' | 'promo' | 'commerce' | 'support' | 'custom';\n // F2 — page-key for `standalone_page` delivery mode. Read by the Next.js\n // route handler in `apps/cashier-portal/src/app/s/[slug]/[workspace]/[page_key]`.\n // Matches the existing storefront vocabulary (`rewards`/`members`)\n // in apps/cashier-portal/src/app/s/[slug]/{rewards,members}/page.tsx.\n page_key?: 'bill' | 'rewards' | 'feedback' | 'reviews' | 'members';\n // Surface filter (In-App Surface Filter tracker P2). Canonical placement\n // keys this campaign may render on. NULL/undefined or [] = all surfaces\n // (legacy default). A non-empty array gates slot-fill: the SDK only renders\n // this campaign when the host page's declared surface (via aegis.page(name)\n // / aegis.screen(name)) is included. Mirrors the server-side filter at\n // /v1/in-app/active — this in-memory gate is defense-in-depth for stale\n // cached campaigns. The enum is server-locked (cell-plane Pydantic + alembic\n // CHECK); the SDK accepts any string the host declares.\n surface?: string[];\n // Dynamic Screens P2 — free-form screen names (operator-selected from\n // discovered traffic, e.g. 'storefront.cart') matched against the host's raw\n // `currentScreen`. Distinct from the 8-enum `surface`. NULL/empty = none.\n target_screens?: string[];\n}\n\n/**\n * Payload for `campaign-click` lifecycle event. CANCELLABLE — return `false`\n * (or call `evt.preventDefault()`) from the handler to suppress the SDK's\n * default `window.location.href` navigation, e.g. to route via a SPA router.\n */\nexport interface CampaignClickEvent {\n campaign: InAppCampaign;\n /** Sanitized destination URL — already passed through `sanitizeUrl()`. */\n action_url: string;\n /** Best-effort button identifier — populated when the click came from a\n * named button in a multi-button campaign (modals, alerts). `cta` for the\n * primary CTA on single-button campaigns. */\n button_id?: string;\n /** Mutate via `evt.preventDefault()` to signal the SDK to skip its\n * default hard-navigation. Identical semantics to DOM CustomEvent. */\n preventDefault: () => void;\n defaultPrevented: boolean;\n}\n\n/** Payload for `campaign-dismiss` lifecycle event. */\nexport interface CampaignDismissEvent {\n campaign: InAppCampaign;\n /** Source of dismissal — close button, swipe, ESC key, programmatic. */\n source: 'close_button' | 'overlay' | 'esc' | 'auto_timeout' | 'programmatic';\n}\n\n/** Payload for `error` lifecycle event. Aggregates non-fatal SDK errors so\n * host apps can wire them into Sentry / Datadog RUM / similar. */\nexport interface AegisErrorEvent {\n message: string;\n error: unknown;\n /** Optional structured context — `{ event: 'campaign-click' }` for handler\n * throws, `{ campaign_id, stage }` for render path failures, etc. */\n context: Record<string, unknown>;\n}\n\n/**\n * Map of lifecycle event name → handler signature. Used by the typed\n * `on(event, handler)` overload below so TS correctly narrows the payload\n * type per event without a discriminated union at the call site.\n */\nexport interface InAppLifecycleEventMap {\n 'campaigns-loaded': (campaigns: InAppCampaign[]) => void;\n 'campaign-will-show': (campaign: InAppCampaign) => void | false;\n 'campaign-shown': (campaign: InAppCampaign) => void;\n 'campaign-click': (evt: CampaignClickEvent) => void | false;\n 'campaign-dismiss': (evt: CampaignDismissEvent) => void;\n 'error': (evt: AegisErrorEvent) => void;\n}\n\nexport interface AegisInAppConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n // Resolved by POST /v1/sdk/bootstrap — required in production. Campaigns\n // with a non-empty `target_properties` list are filtered against this on\n // the server, so passing the wrong id (or omitting it) narrows visible\n // campaigns to the property-agnostic ones only.\n propertyId?: string;\n debugMode?: boolean;\n enableSSE?: boolean;\n /**\n * Callback invoked when the manager receives an in-app campaign with\n * a gamification sub_type (spin_wheel / scratch_card). The facade\n * (AegisMessageRuntime) wires this to the widget-renderer path so\n * interactive campaigns render correctly. When this is undefined,\n * gamification campaigns are logged and skipped.\n */\n onInteractiveCampaign?: (campaign: InAppCampaign) => void;\n /**\n * Workspace cascade reader. Set this from the host SDK as\n * `getWorkspaceId: () => aegis.getEffectiveWorkspaceId()` so in-app\n * impressions/clicks/dismisses carry the same workspace context the\n * main analytics SDK sees (URL path slug, ?ws=, setWorkspace runtime).\n * Without it, in-app engagement events arrive at event-ingress with\n * no workspace_id stamped → cross-outlet attribution silently falls\n * back to the org's primary workspace.\n */\n getWorkspaceId?: () => string | undefined;\n /**\n * Live cart-state reader, set by the runtime from its imperative\n * `setCartState(...)`. Threaded into the renderer `RenderContext` so the\n * progress-bar renderer can read a first-party cart value instead of\n * `window.*` cart globals. Undefined for embeds that never feed a cart.\n */\n getCartState?: () => CartState | undefined;\n}\n\n/** Parse a TRUSTED, static SVG string (the SDK's own constant icon markup) into\n * a DOM node — so we never assign innerHTML on a live element. Returns null on\n * any parse error; callers fall back gracefully. NEVER pass campaign/customer\n * data here (it's only for hardcoded SDK icons). */\nfunction svgNode(svg: string): Node | null {\n try {\n const doc = new DOMParser().parseFromString(svg, 'image/svg+xml');\n const root = doc.documentElement;\n if (!root || root.getElementsByTagName('parsererror').length > 0) return null;\n return document.importNode(root, true);\n } catch {\n return null;\n }\n}\n\nexport class AegisInAppManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private propertyId?: string;\n private debugMode: boolean;\n private enableSSE: boolean;\n private onInteractiveCampaign?: (campaign: InAppCampaign) => void;\n private getWorkspaceId?: () => string | undefined;\n private getCartState?: () => CartState | undefined;\n\n private campaigns: InAppCampaign[] = [];\n private displayedCampaigns = new Set<string>();\n // Conversion-aware suppression — campaign_id -> epoch_ms when suppression expires.\n // Populated by `notifyConversion()` and rehydrated from sessionStorage in\n // `refreshCampaigns()` so a navigation between pages preserves silence.\n private suppressedUntil = new Map<string, number>();\n private eventSource?: EventSource;\n private isInitialized = false;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n // sessionStorage key prefix — one entry per goal so we can introspect what\n // converted and when. Format: { ts: epoch_ms }.\n private static readonly CONVERSION_STORAGE_PREFIX = 'aegis_conv_';\n\n // ── Lifecycle event bus (1.8.0) ────────────────────────────────────────\n // Typed callback registry — host apps register handlers via the public\n // `on*` methods below. Each handler is stored once; calling the\n // returned unsubscribe fn removes it. Multiple subscribers per event are\n // supported. Callbacks that return `false` (or call `evt.preventDefault()`\n // on cancellable events) signal the SDK to skip its default behaviour.\n //\n // Industry parity: matches CleverTap `notificationCallback`, WebEngage\n // `onCallback`, MoEngage `onSelfHandledClick`, Iterable url-delegate, etc.\n // The DOM CustomEvent path (window.dispatchEvent('aegis:campaign-click'))\n // is preserved for backward compat + advanced multi-subscriber + pre-init\n // patterns where typed methods aren't reachable yet.\n private hooks = new Map<string, Set<(...args: unknown[]) => void | false | undefined>>();\n // `aegis.inApp.ready` resolves when the first refreshCampaigns completes\n // — matches CleverTap `onLoad`, WebEngage `onReady`. Lets host apps await\n // a known-good state before reading `campaigns` or registering handlers\n // that need armed campaigns visible.\n private readyResolve!: () => void;\n readonly ready: Promise<void> = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n\n private emit<T>(eventName: string, payload: T): boolean {\n const handlers = this.hooks.get(eventName);\n if (!handlers || handlers.size === 0) return true;\n let proceed = true;\n for (const handler of handlers) {\n try {\n const result = (handler as (p: T) => void | false | undefined)(payload);\n if (result === false) proceed = false;\n } catch (err) {\n // Don't let a misbehaving host handler crash the SDK render path.\n // Surface via onError but keep going for the remaining handlers.\n this.emitError(err, { event: eventName });\n }\n }\n return proceed;\n }\n\n private emitError(err: unknown, context?: Record<string, unknown>): void {\n const handlers = this.hooks.get('error');\n if (!handlers || handlers.size === 0) {\n // No subscriber — log to console so errors aren't completely silent.\n this.log(`Active Reach SDK error: ${err instanceof Error ? err.message : String(err)}`, 'error');\n return;\n }\n for (const handler of handlers) {\n try {\n (handler as (e: AegisErrorEvent) => void)({\n message: err instanceof Error ? err.message : String(err),\n error: err,\n context: context ?? {},\n });\n } catch {\n // ignore — we already tried to surface\n }\n }\n }\n\n private register<T>(\n eventName: string,\n handler: (payload: T) => void | false | undefined,\n ): () => void {\n if (!this.hooks.has(eventName)) this.hooks.set(eventName, new Set());\n this.hooks.get(eventName)!.add(handler as (...args: unknown[]) => void | false | undefined);\n return () => {\n this.hooks.get(eventName)?.delete(handler as (...args: unknown[]) => void | false | undefined);\n };\n }\n\n /**\n * Subscribe to in-app message lifecycle events. Returns an unsubscribe\n * function — call to remove the handler (matches React `useEffect` cleanup\n * convention).\n *\n * Supported events: `campaigns-loaded`, `campaign-will-show` (cancellable),\n * `campaign-shown`, `campaign-click` (cancellable), `campaign-dismiss`,\n * `error`. Cancellable events: handler returns `false` to suppress the\n * SDK's default behaviour (e.g., prevent the hard navigation on click,\n * skip rendering on will-show).\n */\n on<E extends keyof InAppLifecycleEventMap>(\n event: E,\n handler: InAppLifecycleEventMap[E],\n ): () => void {\n return this.register(event, handler as never);\n }\n\n /** Sugar: subscribe to `campaigns-loaded`. Fires after every successful\n * `/v1/in-app/active` poll with the full active-campaign list. */\n onCampaignsLoaded(\n handler: (campaigns: InAppCampaign[]) => void,\n ): () => void {\n return this.register('campaigns-loaded', handler);\n }\n\n /** Sugar: subscribe to `campaign-will-show`. CANCELLABLE — return `false`\n * to suppress rendering this campaign (host-side suppression rules,\n * route-aware blocking, etc.). */\n onCampaignWillShow(\n handler: (campaign: InAppCampaign) => void | false,\n ): () => void {\n return this.register('campaign-will-show', handler);\n }\n\n /** Sugar: subscribe to `campaign-shown`. Fires after the SDK has painted\n * the campaign to the DOM (post-impression). */\n onCampaignShown(\n handler: (campaign: InAppCampaign) => void,\n ): () => void {\n return this.register('campaign-shown', handler);\n }\n\n /** Sugar: subscribe to `campaign-click`. CANCELLABLE — return `false` (or\n * call `evt.preventDefault()`) to suppress the SDK's default\n * `window.location.href` navigation, e.g. to route via a SPA router. */\n onCampaignClick(\n handler: (evt: CampaignClickEvent) => void | false,\n ): () => void {\n return this.register('campaign-click', handler);\n }\n\n /** Sugar: subscribe to `campaign-dismiss`. Fires when user closes/swipes\n * away the campaign before clicking through. */\n onCampaignDismiss(\n handler: (evt: CampaignDismissEvent) => void,\n ): () => void {\n return this.register('campaign-dismiss', handler);\n }\n\n /** Sugar: subscribe to `error`. Aggregates non-fatal SDK errors — fetch\n * failures, render exceptions, host-handler throws. Wire this into your\n * error monitoring (Sentry, Datadog RUM, etc.). */\n onError(\n handler: (evt: AegisErrorEvent) => void,\n ): () => void {\n return this.register('error', handler);\n }\n \n constructor(config: AegisInAppConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n // Fall back to the SDK's persisted anonymous_id (set on first /v1/sdk/bootstrap\n // and reused across the main analytics SDK) so anonymous storefront users\n // get journey-driven in-app messages keyed to the same identity used in\n // /v1/batch payloads. Without this, polling defaults to \"anonymous\" on the\n // server and bucket-misses every per-contact priority queue.\n this.userId = config.userId ?? readAnonIdFromStorage();\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.propertyId = config.propertyId;\n this.debugMode = config.debugMode || false;\n // SSE is disabled by default. Kept as opt-in capability for future tenant\n // dashboards that embed the Active Reach SDK and need realtime updates. End-user\n // storefronts must NOT enable this — persistent-per-tab SSE doesn't scale.\n this.enableSSE = config.enableSSE === true;\n this.onInteractiveCampaign = config.onInteractiveCampaign;\n this.getWorkspaceId = config.getWorkspaceId;\n this.getCartState = config.getCartState;\n }\n \n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisInApp already initialized');\n return;\n }\n\n // Mark user as returning for subsequent visits\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem('aegis_returning_user', '1');\n }\n\n await this.refreshCampaigns();\n\n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n \n this.isInitialized = true;\n this.log('AegisInApp initialized successfully');\n }\n \n updateUserId(userId: string): void {\n this.userId = userId;\n this.refreshCampaigns();\n }\n \n updateContactId(contactId: string): void {\n this.contactId = contactId;\n // Keep the chat launcher's identity in lockstep so the anon→known stitch\n // hits the indexed contact path on the next message.\n this.activeWebChat?.updateContactId(contactId);\n this.disconnectSSE();\n if (this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n this.refreshCampaigns();\n }\n\n // --- Qualifying-event refresh (DLR Tracker 1 / P1, 2026-05-28) ---------\n //\n // Burst-coalescing debounce timer for `refreshOnEvent`. Cleared and\n // re-armed on every call so a flurry of `aegis.track('cart_item_added')`\n // calls (e.g. 10 within 100ms while a shopper rapidly adds items)\n // collapses to a single `/v1/in-app/active` fetch ~300ms after the last\n // call. Without this debounce, an active storefront would hammer the\n // endpoint and our connection-load budget — see\n // memory/feedback_web_sdk_rest_not_sse.md for why polling has to stay\n // gentle.\n private refreshDebounceTimer?: ReturnType<typeof setTimeout>;\n private static readonly REFRESH_DEBOUNCE_MS = 300;\n\n // Surface filter (In-App Surface Filter tracker P2). The logical surface\n // last declared by the host page via aegis.page(name) / aegis.screen(name).\n // Threaded to /v1/in-app/active?current_surface=<name> on the next refresh\n // and used as the in-memory slot-fill gate. Set-replace, no clear-on-unmount\n // (the latest declaration wins — see tracker Open decision #7).\n private currentSurface: string | null = null;\n\n // Dynamic Screens P2 — the RAW screen name last declared via\n // aegis.page(name) / aegis.screen(name), un-normalized (e.g.\n // 'storefront.cart'). Distinct from `currentSurface` (which is gated to the\n // 8 canonical keys): this is the free-form tier. Threaded to\n // /v1/in-app/active?current_screen=<name> and matched against a campaign's\n // `target_screens`. Only page/screen declarations set it — NOT track().\n private currentScreen: string | null = null;\n\n // Outlet context — the outlet the customer is ACTIVELY viewing (storefront\n // outlet switcher / location-code), set via aegis.setLocation(outletId).\n // Threaded to /v1/in-app/active?location_id=<id>; the server prefers it over\n // the property's STATIC configured outlet so outlet-scoped campaigns follow\n // the switcher on a SHARED multi-outlet storefront (one property, N outlets).\n // null → server falls back to the property's outlet, then brand-wide.\n private currentLocationId: string | null = null;\n\n // The 8 canonical surface keys. We only capture `eventName` as\n // `currentSurface` when it matches one of these — so an arbitrary\n // aegis.track('product_viewed') still triggers a refresh (existing\n // behavior) but never poisons the surface state (tracker Open decision #9).\n // Server-locked enum (cell-plane Pydantic + alembic CHECK); kept in lockstep\n // via the P6 cross-source triangulation guard.\n private static readonly KNOWN_SURFACES: ReadonlySet<string> = new Set([\n 'bill',\n 'storefront_catalog',\n 'storefront_rewards',\n 'storefront_feedback',\n 'storefront_reviews',\n 'storefront_members',\n 'external_website',\n 'external_mobile_screen',\n ]);\n\n /**\n * Qualifying-event refresh — schedule a debounced `refreshCampaigns()`\n * call in response to a host-app SDK event (`aegis.page()`,\n * `aegis.screen()`, `aegis.track(name)`). Matches CleverTap / MoEngage /\n * WebEngage's \"refresh on qualifying event\" shape, translated to the\n * browser session.\n *\n * Why: new server-side eligibility opens on these events (a `page` view\n * arms route-targeted campaigns; a `track('product_viewed')` arms\n * trigger-gated campaigns whose `client_trigger.config.event` matches).\n * Pre-P1, the SDK only refreshed on `initialize()` + `updateContactId()`\n * + the SSE update channel (which storefront has disabled by design),\n * so newly armed campaigns were invisible until the next identity flip.\n *\n * Debounce: 300ms. Five `page()` calls inside the window coalesce to\n * one fetch; a sixth call ≥300ms after the prior burst starts a new\n * fetch. The trailing-edge schedule (re-arm on every call) is correct\n * for storefront rage-clicks + SPA route bursts — we want the LATEST\n * URL's eligibility, not the first.\n *\n * Safe to call on the server (no-op when `setTimeout` is unavailable\n * — though that's vanishingly rare in any modern environment we ship to).\n *\n * Surface capture (In-App Surface Filter tracker P2): when `eventName`\n * matches one of the 8 canonical surface keys, it is captured into\n * `currentSurface` and threaded to `/v1/in-app/active?current_surface=<name>`\n * on the next refresh — wiring the existing `aegis.page(name)` /\n * `aegis.screen(name)` argument through to campaign targeting. Unknown names\n * (e.g. `aegis.track('product_viewed')`) still trigger a refresh but do NOT\n * change `currentSurface`, so arbitrary events never poison the surface gate.\n */\n refreshOnEvent(eventName: string, isScreenDeclaration = false): void {\n if (!this.isInitialized) {\n // Pre-init events are silently dropped — the first refresh fires\n // from `initialize()` so there's nothing to coalesce against yet.\n this.log(`refreshOnEvent(${eventName}) before initialize — ignored`);\n return;\n }\n // Capture canonical surface declarations only. 'page_view' (the default\n // aegis.page() forwards when called with no name) and arbitrary track()\n // event names are intentionally ignored here.\n if (eventName && AegisInAppManager.KNOWN_SURFACES.has(eventName)) {\n this.currentSurface = eventName;\n }\n // Dynamic Screens P2 — capture the RAW screen name for the free-form tier,\n // but ONLY from a page/screen declaration (isScreenDeclaration), never a\n // track() event (a 'product_viewed' track must not masquerade as a screen).\n // 'page_view' is the no-arg aegis.page() sentinel → not a real screen.\n if (isScreenDeclaration && eventName && eventName !== 'page_view') {\n this.currentScreen = eventName;\n }\n if (this.refreshDebounceTimer) {\n clearTimeout(this.refreshDebounceTimer);\n }\n this.refreshDebounceTimer = setTimeout(() => {\n this.refreshDebounceTimer = undefined;\n this.log(`refreshOnEvent(${eventName}) — firing refreshCampaigns()`);\n void this.refreshCampaigns();\n }, AegisInAppManager.REFRESH_DEBOUNCE_MS);\n }\n\n /**\n * Outlet context — declare the outlet the customer is actively viewing\n * (storefront outlet switcher / location-code). The host calls this when the\n * shopper picks an outlet (or on initial outlet-scoped page load) and again\n * with the new id when they switch. Threaded to\n * `/v1/in-app/active?location_id=<id>` so the server serves outlet-scoped\n * campaigns for THIS outlet (preferred over the property's static outlet) —\n * the fix that makes a SHARED multi-outlet storefront's switcher actually\n * drive in-app targeting. Pass `null` to clear (back to property/brand-wide).\n *\n * No-ops when the value is unchanged; otherwise debounce-refreshes so the\n * armed campaign set follows the switcher within ~300ms.\n */\n setLocation(locationId: string | null): void {\n const next = locationId || null;\n if (next === this.currentLocationId) return;\n this.currentLocationId = next;\n if (!this.isInitialized) return; // first refresh fires from initialize()\n if (this.refreshDebounceTimer) {\n clearTimeout(this.refreshDebounceTimer);\n }\n this.refreshDebounceTimer = setTimeout(() => {\n this.refreshDebounceTimer = undefined;\n this.log(`setLocation(${next}) — firing refreshCampaigns()`);\n void this.refreshCampaigns();\n }, AegisInAppManager.REFRESH_DEBOUNCE_MS);\n }\n\n /**\n * Conversion-aware suppression. Call this when the host app observes a\n * goal event (purchase, order_placed, checkout_completed, or any custom\n * goal the workspace has configured per-campaign).\n *\n * For every armed campaign whose `frequency.suppress_after_conversion_seconds`\n * is set, this:\n * 1. Persists the conversion in sessionStorage (so subsequent page\n * loads in the same tab retain silence).\n * 2. Computes an expiry epoch_ms and stores it in `suppressedUntil`.\n * 3. The two campaign-evaluation paths (`tryDisplayNextCampaign`\n * and `onClientEvent`) skip campaigns whose `suppressedUntil`\n * has not yet passed.\n *\n * Scope: only `session` is implemented in P0a. `user` and `user_sku`\n * scopes degrade to session-only with a debug log; the schema accepts\n * them so future expansion is non-breaking.\n *\n * Safe to call repeatedly for the same goal — each call refreshes the\n * sessionStorage timestamp and re-applies suppression to any campaigns\n * loaded since the last call.\n */\n notifyConversion(goalName: string): void {\n if (!goalName) {\n this.log('notifyConversion called with empty goalName; ignored', 'warn');\n return;\n }\n const ts = Date.now();\n if (typeof sessionStorage !== 'undefined') {\n try {\n sessionStorage.setItem(\n `${AegisInAppManager.CONVERSION_STORAGE_PREFIX}${goalName}`,\n JSON.stringify({ ts }),\n );\n } catch {\n // sessionStorage may be disabled (Safari private mode, blocked\n // third-party context). Suppression still applies for the\n // current page lifetime via the in-memory map.\n }\n }\n this.applySuppressionFromCampaigns(ts);\n this.log(`notifyConversion: ${goalName} — suppressing ${this.suppressedUntil.size} armed campaigns`);\n }\n\n /**\n * Compute and store `suppressedUntil` entries for every armed campaign\n * whose `frequency.suppress_after_conversion_seconds` is set. Called by\n * `notifyConversion()` and `refreshCampaigns()` (the latter rehydrates\n * suppression for newly-loaded campaigns when a prior conversion event\n * exists in sessionStorage).\n *\n * `convertedAt` is the epoch_ms of the conversion; pass `Date.now()`\n * when called from `notifyConversion`, or the `ts` recovered from\n * sessionStorage when rehydrating.\n */\n private applySuppressionFromCampaigns(convertedAt: number): void {\n for (const c of this.campaigns) {\n const seconds = c.frequency?.suppress_after_conversion_seconds;\n if (typeof seconds !== 'number' || seconds <= 0) continue;\n const scope = c.frequency?.scope ?? 'session';\n if (scope !== 'session') {\n // P0a only implements session scope. Schema accepts user / user_sku\n // so future work doesn't break wire compatibility, but for now we\n // degrade to session and log.\n this.log(\n `applySuppressionFromCampaigns: scope=${scope} not implemented; degrading to session for campaign ${c.id}`,\n 'warn',\n );\n }\n const expiresAt = convertedAt + seconds * 1000;\n // Take the max so a later/longer suppression wins over an earlier one.\n const existing = this.suppressedUntil.get(c.id);\n if (existing === undefined || existing < expiresAt) {\n this.suppressedUntil.set(c.id, expiresAt);\n }\n }\n }\n\n /**\n * Recover any prior conversion timestamps from sessionStorage and apply\n * suppression to currently-loaded campaigns. Called from\n * `refreshCampaigns()` after `this.campaigns` is populated. This is the\n * mechanism that prevents a converted buyer from seeing a discount popup\n * on the next page load within the same session.\n */\n private rehydrateSuppressionFromStorage(): void {\n if (typeof sessionStorage === 'undefined') return;\n let earliestTs: number | null = null;\n try {\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i);\n if (!key || !key.startsWith(AegisInAppManager.CONVERSION_STORAGE_PREFIX)) continue;\n const raw = sessionStorage.getItem(key);\n if (!raw) continue;\n const parsed = JSON.parse(raw) as { ts?: number };\n if (typeof parsed.ts === 'number') {\n earliestTs = earliestTs === null ? parsed.ts : Math.min(earliestTs, parsed.ts);\n }\n }\n } catch {\n // Malformed entries are silently skipped — suppression simply\n // doesn't apply for them.\n return;\n }\n if (earliestTs !== null) {\n this.applySuppressionFromCampaigns(earliestTs);\n }\n }\n\n /**\n * Returns true if the campaign is currently suppressed (Date.now() is\n * before the stored expiry). Used by both display paths.\n */\n private isSuppressed(campaignId: string): boolean {\n const expiresAt = this.suppressedUntil.get(campaignId);\n if (expiresAt === undefined) return false;\n if (Date.now() >= expiresAt) {\n this.suppressedUntil.delete(campaignId);\n return false;\n }\n return true;\n }\n \n private connectSSE(): void {\n if (this.eventSource) {\n this.disconnectSSE();\n }\n \n if (!this.organizationId) {\n this.log('Cannot connect SSE without organization ID', 'warn');\n return;\n }\n \n const url = new URL('/v1/stream/realtime', this.apiHost);\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Organization-ID': this.organizationId,\n };\n \n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n \n const queryParams = new URLSearchParams();\n Object.entries(headers).forEach(([key, value]) => {\n queryParams.append(key, value);\n });\n \n this.eventSource = new EventSource(`${url}?${queryParams.toString()}`);\n \n this.eventSource.addEventListener('open', () => {\n this.log('SSE connection established');\n this.reconnectAttempts = 0;\n });\n \n this.eventSource.addEventListener('in_app_campaign_updated', (event: MessageEvent) => {\n try {\n const data = JSON.parse(event.data);\n this.log(`Received in-app campaign update: ${data.campaign_id}`);\n this.refreshCampaigns();\n } catch (error) {\n this.log(`Error parsing SSE event: ${error}`, 'error');\n }\n });\n \n this.eventSource.addEventListener('heartbeat', () => {\n this.log('SSE heartbeat received');\n });\n\n this.eventSource.addEventListener('error', () => {\n this.log('SSE connection error', 'error');\n\n if (this.eventSource?.readyState === EventSource.CLOSED) {\n this.attemptReconnect();\n }\n });\n }\n \n private disconnectSSE(): void {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = undefined;\n this.log('SSE connection closed');\n }\n }\n \n private attemptReconnect(): void {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n this.log('Max reconnect attempts reached, giving up', 'warn');\n return;\n }\n \n this.reconnectAttempts++;\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);\n \n this.log(`Reconnecting SSE in ${delay}ms (attempt ${this.reconnectAttempts})`);\n \n setTimeout(() => {\n if (this.isInitialized && this.enableSSE && this.organizationId) {\n this.connectSSE();\n }\n }, delay);\n }\n \n private async refreshCampaigns(): Promise<void> {\n try {\n // Build URL with client context for server-side targeting (Critical Fix B)\n const context = new URLSearchParams({\n device_type: this.detectDeviceType(),\n page_url: typeof window !== 'undefined' ? window.location.pathname : '/',\n });\n\n // Geo is resolved server-side from IP — no need to send\n context.set('is_new_user', this.isNewUser() ? 'true' : 'false');\n\n // Surface filter (In-App Surface Filter tracker P2). Thread the\n // host-declared surface (from aegis.page(name) / aegis.screen(name))\n // through so the server drops campaigns scoped to other surfaces.\n // Omitted when no surface was declared → server applies no filter\n // (back-compat with hosts that haven't wired a surface declaration).\n if (this.currentSurface) {\n context.set('current_surface', this.currentSurface);\n }\n // Dynamic Screens P2 — thread the raw screen name so the server matches\n // it against campaigns' free-form `target_screens`. Omitted when no\n // screen declared (no free-form match attempted).\n if (this.currentScreen) {\n context.set('current_screen', this.currentScreen);\n }\n // Outlet switcher — thread the actively-viewed outlet so the server serves\n // outlet-scoped campaigns for THIS outlet (preferred over the property's\n // static outlet). Omitted when no outlet declared → property/brand-wide.\n if (this.currentLocationId) {\n context.set('location_id', this.currentLocationId);\n }\n\n const url = `${this.apiHost}/v1/in-app/active?${context.toString()}`;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n\n if (this.userId) {\n headers['X-User-ID'] = this.userId;\n }\n\n if (this.contactId) {\n headers['X-Contact-ID'] = this.contactId;\n }\n\n if (this.organizationId) {\n headers['X-Organization-ID'] = this.organizationId;\n }\n\n if (this.propertyId) {\n headers['X-Property-Id'] = this.propertyId;\n }\n\n // Send cached A/B assignments so server can skip re-evaluation (Critical Fix C)\n const abAssignments = this.getABAssignments();\n if (Object.keys(abAssignments).length > 0) {\n headers['X-AB-Assignments'] = btoa(JSON.stringify(abAssignments));\n }\n\n const response = await fetch(url, {\n method: 'GET',\n headers,\n credentials: 'include',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch campaigns: ${response.status}`);\n }\n\n const payload = await response.json();\n // Server returns an array; defensively handle error bodies (HTML\n // from misconfigured gateways, {} from maintenance endpoints, etc.)\n // so a bad response doesn't turn `updateContactId` into a thrower.\n this.campaigns = Array.isArray(payload) ? payload : [];\n\n // Process A/B assignments from server response (Critical Fix C)\n this.processABAssignments(this.campaigns);\n\n // Rehydrate conversion suppression from sessionStorage so a buyer\n // who converted on a prior page load in the same tab does not see\n // a discount popup on this load. Must run after this.campaigns is\n // populated and BEFORE tryDisplayNextCampaign so the first display\n // attempt honors suppression.\n this.rehydrateSuppressionFromStorage();\n\n this.log(`Fetched ${this.campaigns.length} campaigns`);\n\n // P2 of WEB_SDK_DLR_ENHANCEMENT_TRACKER — fire `served` for each\n // freshly-arrived campaign. Idempotent on the server side via\n // idempotency_key; sessionStorage dedup here suppresses re-fires\n // within the same tab (the same campaign can be in multiple\n // refreshCampaigns responses across a session).\n this.emitServedEvents(this.campaigns);\n\n // Lifecycle: `campaigns-loaded` — fires after every successful refresh\n // with the full active-campaign list. Host apps subscribe to drive\n // route-aware allowlists, sticky inboxes, badge counts, etc.\n this.emit('campaigns-loaded', this.campaigns);\n\n // Resolve `aegis.inApp.ready` after the FIRST successful poll so host\n // apps can `await aegis.inApp.ready` before reading `campaigns` or\n // making decisions that depend on a known-good initial state. Idempotent\n // — calling resolve() twice is a no-op for an already-settled promise.\n this.readyResolve();\n\n this.tryDisplayNextCampaign();\n\n // F2/F3 / U8 — fill any `[data-aegis-slot]` anchors with matching\n // `embedded_card`-mode campaigns. Independent of the overlay path:\n // a campaign with delivery_modes=[overlay,card] renders both ways\n // (overlay if conditions match + card if the page has a slot).\n // No-op when no slots are on the page.\n this.renderIntoSlots();\n\n // Surface-Canvas inline element anchoring — render inline-format\n // campaigns (progress_bar / banner / milestone / carousel / rec) into a\n // host element picked via the element inspector (interactive_config.anchor\n // .element_selector). Unlike `data-aegis-slot` (host declares the slot),\n // the operator anchors to ANY existing element — the Plotline/WebEngage\n // model. No-op when no campaign carries an `anchor`.\n this.renderIntoAnchors();\n\n // PR-B U7 — also fill any `[data-aegis-token-data]` anchors with\n // a server-injected campaign payload. Used by the standalone-page\n // route at `/s/[slug]/[workspace]/[page_key]?t=<token>`: the page\n // handler verifies the token server-side (via F16 internal),\n // embeds the resolved campaign data inline, and the SDK uses the\n // SAME renderer dispatch as the slot path. No separate widget\n // code, no public token-resolve endpoint.\n this.renderTokenAnchors();\n\n } catch (error) {\n this.emitError(error, { stage: 'refresh-campaigns' });\n this.log(`Error refreshing campaigns: ${error}`, 'error');\n }\n }\n\n // P2 of WEB_SDK_DLR_ENHANCEMENT_TRACKER — `served` event emission.\n //\n // Fired once per campaign per session after the SDK has the payload\n // in hand (post-refreshCampaigns). Distinct from `impression` which\n // fires only after DOM visibility is confirmed via IntersectionObserver.\n //\n // The (campaign × session) dedup key is `aegis_served_fired:<id>` in\n // sessionStorage so a campaign that survives across multiple page\n // navigations in one tab does NOT re-fire `served` on every refresh.\n // The server side is also idempotent via `idempotency_key`; this is\n // just to keep network volume sane.\n private static readonly SERVED_DEDUP_PREFIX = 'aegis_served_fired:';\n\n private emitServedEvents(campaigns: InAppCampaign[]): void {\n if (typeof sessionStorage === 'undefined') {\n // No session storage (SSR, worker context) — fire unconditionally;\n // the server idempotency key still prevents duplicates.\n for (const c of campaigns) {\n void this.trackEvent(c.id, 'served');\n }\n return;\n }\n for (const c of campaigns) {\n const key = AegisInAppManager.SERVED_DEDUP_PREFIX + c.id;\n if (sessionStorage.getItem(key)) continue;\n try {\n sessionStorage.setItem(key, '1');\n } catch {\n // sessionStorage quota / disabled — fire anyway, server dedupes.\n }\n void this.trackEvent(c.id, 'served');\n }\n }\n\n // --- Client Context Helpers (Critical Fix B) ---\n\n private detectDeviceType(): 'mobile' | 'desktop' | 'tablet' {\n if (typeof navigator === 'undefined') return 'desktop';\n const ua = navigator.userAgent;\n if (/Mobi|Android/i.test(ua)) return 'mobile';\n if (/iPad|Tablet/i.test(ua)) return 'tablet';\n return 'desktop';\n }\n\n private isNewUser(): boolean {\n if (typeof localStorage === 'undefined') return true;\n return !localStorage.getItem('aegis_returning_user');\n }\n\n // --- A/B Assignment Persistence (Critical Fix C) ---\n\n private getABAssignments(): Record<string, string> {\n if (typeof localStorage === 'undefined') return {};\n try {\n return JSON.parse(localStorage.getItem('aegis_ab_assignments') || '{}');\n } catch {\n return {};\n }\n }\n\n private processABAssignments(campaigns: InAppCampaign[]): void {\n if (typeof localStorage === 'undefined') return;\n const stored = this.getABAssignments();\n for (const campaign of campaigns) {\n if (campaign.assigned_variant_id) {\n stored[campaign.id] = campaign.assigned_variant_id;\n }\n }\n localStorage.setItem('aegis_ab_assignments', JSON.stringify(stored));\n }\n\n private getVariantId(campaignId: string): string | undefined {\n const assignments = this.getABAssignments();\n return assignments[campaignId] ?? undefined;\n }\n \n private tryDisplayNextCampaign(): void {\n // Only auto-display campaigns that DO NOT have a client_trigger.\n // Trigger-gated campaigns wait for the host app to call\n // `onClientEvent()` or for TriggerEngine to fire the matching\n // behavioural event. This preserves the preload-first contract —\n // the campaign is armed but the render is gated.\n // Conversion-aware suppression: campaigns silenced by a prior\n // notifyConversion() call (or rehydrated from sessionStorage) are\n // skipped until their suppression window expires.\n const campaign = this.campaigns.find((c) =>\n !this.displayedCampaigns.has(c.id) && !c.client_trigger && !this.isSuppressed(c.id),\n );\n\n if (campaign) {\n this.displayCampaign(campaign);\n }\n }\n\n // --- F2/F3 / U8: embedded-card slot rendering ---------------------------\n //\n // Tracks slot DOM elements we've already filled so a second\n // refresh-cycle (SSE update, polling tick) doesn't re-render the same\n // campaign on top of itself. WeakSet so DOM removals get GC'd.\n private filledSlots = new WeakSet<Element>();\n\n /**\n * Scan the page for `[data-aegis-slot]` anchors and render any\n * campaign whose `widget_category` matches the slot key AND whose\n * `delivery_modes` includes `'embedded_card'`.\n *\n * Runs after every refresh-campaigns success — the WeakSet guard\n * keeps it idempotent across re-fetches. The slot key is the campaign's\n * `widget_category` (the wide grouping discriminator from F3), so a\n * `<div data-aegis-slot=\"feedback\">` will accept the first active\n * campaign with `widget_category='feedback'` + embedded_card mode.\n */\n /**\n * Surface predicate (In-App Surface Filter tracker P2). Byte-for-byte the\n * same logic as the server-side `_surface_matches` in\n * apps/cell-plane/app/api/v1/in_app/campaigns.py:\n * - campaign with no `surface` (undefined / []) renders on every surface\n * - no declared `currentSurface` => no filter (back-compat)\n * - otherwise the current surface must be in the campaign's surface array\n */\n private matchesCurrentSurface(c: InAppCampaign): boolean {\n if (!c.surface || c.surface.length === 0) return true;\n if (this.currentSurface === null) return true;\n return c.surface.includes(this.currentSurface);\n }\n\n /**\n * Dynamic Screens P2 — combined surface + free-form screen predicate.\n * Byte-for-byte the server's `_screen_or_surface_matches`: when the campaign\n * has no `target_screens` this is exactly `matchesCurrentSurface` (every\n * existing campaign → zero behaviour change). A screen-only campaign matches\n * strictly on `currentScreen`; a dual campaign ORs the two tiers.\n */\n private matchesCurrentScreenOrSurface(c: InAppCampaign): boolean {\n const screens = c.target_screens;\n if (!screens || screens.length === 0) {\n return this.matchesCurrentSurface(c);\n }\n const screenOk = this.currentScreen !== null && screens.includes(this.currentScreen);\n if (!c.surface || c.surface.length === 0) return screenOk;\n return screenOk || this.matchesCurrentSurface(c);\n }\n\n private renderIntoSlots(): void {\n if (typeof document === 'undefined') return;\n const slots = document.querySelectorAll('[data-aegis-slot]');\n if (slots.length === 0) return;\n\n // ALL eligible campaigns per category, priority-sorted (the cell-plane\n // endpoint already orders `this.campaigns` by priority DESC). A slot with\n // `data-aegis-slot-rotate` cycles through them; otherwise the first wins.\n const eligibleByCategory = new Map<string, InAppCampaign[]>();\n for (const c of this.campaigns) {\n // Surface gate (In-App Surface Filter tracker P2). Defense-in-depth\n // for stale cached campaigns — the server-side filter at\n // /v1/in-app/active already drops mismatched campaigns, but this\n // catches any campaign cached from a fetch made on a different surface.\n if (!this.matchesCurrentScreenOrSurface(c)) continue;\n const modes = c.delivery_modes;\n const category = c.widget_category;\n if (!modes || !modes.includes('embedded_card')) continue;\n if (!category) continue;\n const arr = eligibleByCategory.get(category);\n if (arr) arr.push(c);\n else eligibleByCategory.set(category, [c]);\n }\n if (eligibleByCategory.size === 0) return;\n\n slots.forEach((slot) => {\n if (this.filledSlots.has(slot)) return;\n const key = slot.getAttribute('data-aegis-slot');\n if (!key) return;\n const list = eligibleByCategory.get(key);\n if (!list || list.length === 0) return;\n // A slot may ship a host-rendered DEFAULT (e.g. the storefront value-bar's\n // free-delivery strip). Remove it before injecting the campaign(s) so the\n // two don't double up — the campaign REPLACES the default.\n slot.querySelectorAll(':scope > [data-aegis-slot-default]').forEach((d) => d.remove());\n // Rotation is OPT-IN per slot via `data-aegis-slot-rotate=\"<ms>\"`. When set\n // AND more than one campaign is eligible, cycle them one at a time (the\n // storefront sticky-footer value bar). Absent → first-active-per-category\n // wins (every existing slot, e.g. the bill, is unchanged).\n const rotateMs = parseInt(slot.getAttribute('data-aegis-slot-rotate') || '0', 10);\n if (rotateMs > 0 && list.length > 1) {\n this.renderRotatingSlot(slot as HTMLElement, list, rotateMs);\n } else {\n this.renderCampaignIntoSlot(list[0], slot as HTMLElement);\n }\n this.filledSlots.add(slot);\n });\n }\n\n /**\n * Rotating slot — cycles eligible campaigns one at a time inside a single host\n * slot (the storefront sticky-footer \"value bar\"). Each campaign is pre-rendered\n * into its own hidden pane so a live `progress_bar` keeps tracking the cart even\n * while off-screen; only the visibility toggles every `rotateMs`. The impression\n * is deferred at render and fired per campaign on FIRST visibility, so hidden\n * panes never over-count. One rendered pane → no rotation (just shows it).\n */\n private renderRotatingSlot(\n slot: HTMLElement,\n campaigns: InAppCampaign[],\n rotateMs: number,\n ): void {\n const panes: Array<{ el: HTMLElement; campaign: InAppCampaign }> = [];\n for (const c of campaigns) {\n const pane = document.createElement('div');\n pane.setAttribute('data-aegis-rotate-pane', c.id);\n pane.style.display = 'none';\n slot.appendChild(pane);\n this.renderCampaignIntoSlot(c, pane, { deferImpression: true });\n if (pane.childElementCount > 0) panes.push({ el: pane, campaign: c });\n else pane.remove(); // renderer no-op'd (e.g. missing config) — drop empty pane\n }\n if (panes.length === 0) return;\n\n const impressed = new Set<string>();\n const markVisible = (c: InAppCampaign) => {\n if (impressed.has(c.id)) return;\n impressed.add(c.id);\n void this.trackEvent(c.id, 'impression');\n this.emit('campaign-shown', c);\n };\n\n let idx = 0;\n panes[0].el.style.display = '';\n markVisible(panes[0].campaign);\n if (panes.length === 1) return;\n\n const timer = setInterval(() => {\n panes[idx].el.style.display = 'none';\n idx = (idx + 1) % panes.length;\n panes[idx].el.style.display = '';\n markVisible(panes[idx].campaign);\n }, rotateMs);\n if (typeof window !== 'undefined') {\n window.addEventListener('beforeunload', () => clearInterval(timer), { once: true });\n }\n }\n\n /**\n * Surface-Canvas inline element anchoring (Plotline / WebEngage model).\n *\n * Render inline-format campaigns into a HOST element the operator picked via\n * the element inspector — `interactive_config.anchor.element_selector` — instead\n * of a host-declared `[data-aegis-slot]`. `position` controls placement:\n * inside (default) — append into the element (e.g. the storefront footer card)\n * replace — clear the element's host-default children, then render in\n * before / after — render into a wrapper inserted as a sibling\n *\n * Reuses `renderCampaignIntoSlot` (same sub_type dispatch → `renderProgressBarInline`\n * etc.) so inline render code is single-sourced with the slot path. Embedded-card\n * gated (so an anchored campaign never ALSO renders as an overlay), surface-gated,\n * and idempotent via `filledSlots` keyed on the resolved element. A selector that\n * doesn't resolve emits `anchor_unresolved` (parity with tooltip anchoring).\n */\n private renderIntoAnchors(): void {\n if (typeof document === 'undefined') return;\n for (const c of this.campaigns) {\n if (!this.matchesCurrentScreenOrSurface(c)) continue;\n const modes = c.delivery_modes;\n if (!modes || !modes.includes('embedded_card')) continue;\n const ic = c.interactive_config as Record<string, unknown> | undefined;\n const anchor = ic?.anchor as\n | { element_selector?: string; position?: string }\n | undefined;\n const selector = anchor?.element_selector;\n if (!selector) continue;\n\n let el: Element | null = null;\n try {\n el = document.querySelector(selector);\n } catch {\n // Invalid selector — treat as unresolved below.\n el = null;\n }\n if (!el) {\n void this.trackEvent(c.id, 'anchor_unresolved', {\n meta: { anchor_resolved: false, anchor_selector: selector, widget_type: c.sub_type },\n });\n continue;\n }\n\n const position = (anchor?.position as string) || 'inside';\n // Resolve the actual render target by position.\n let target: HTMLElement;\n if (position === 'before' || position === 'after') {\n target = document.createElement('div');\n target.setAttribute('data-aegis-anchor-wrapper', c.id);\n el.parentNode?.insertBefore(target, position === 'before' ? el : el.nextSibling);\n } else {\n target = el as HTMLElement;\n if (position === 'replace') {\n // Mirror the slot-default contract — clear host-rendered default\n // children so the campaign REPLACES them (never double-renders).\n target.querySelectorAll(':scope > [data-aegis-slot-default]').forEach((d) => d.remove());\n }\n }\n\n if (this.filledSlots.has(target)) continue;\n this.renderCampaignIntoSlot(c, target);\n this.filledSlots.add(target);\n }\n }\n\n /**\n * U7 — render server-injected token-bound campaigns.\n *\n * The standalone-page route at `apps/cashier-portal/src/app/s/[slug]/\n * [workspace]/[page_key]/page.tsx` (and the `/c/[token]` Aegis-hosted\n * fallback) verify the URL token server-side via the F16 internal\n * endpoint, then embed the resolved campaign payload as JSON inside\n * a `<div data-aegis-token-data=\"...\">` anchor. This SDK method\n * scans for those anchors, parses the payload, and dispatches to\n * the SAME `renderCampaignIntoSlot` used by the [data-aegis-slot]\n * path — so widget rendering code is single-sourced.\n *\n * Why server-injected (not client-fetched): keeps INTERNAL_API_SECRET\n * server-side, avoids an extra browser round-trip for verify, gives\n * Next.js SSR-friendly initial HTML for SEO/no-JS users (rendered\n * via the page handler's React tree alongside the SDK anchor).\n *\n * Idempotency: filledSlots is the same WeakSet used by\n * renderIntoSlots — re-running on SSE/poll refresh is a no-op for\n * already-filled anchors.\n */\n private renderTokenAnchors(): void {\n if (typeof document === 'undefined') return;\n const anchors = document.querySelectorAll('[data-aegis-token-data]');\n if (anchors.length === 0) return;\n\n anchors.forEach((anchor) => {\n if (this.filledSlots.has(anchor)) return;\n const raw = anchor.getAttribute('data-aegis-token-data');\n if (!raw) return;\n\n let payload:\n | { campaign?: InAppCampaign; submit_url?: string }\n | null = null;\n try {\n payload = JSON.parse(raw);\n } catch (e) {\n this.log(\n `data-aegis-token-data: invalid JSON, skipping anchor (${e})`,\n 'warn',\n );\n this.filledSlots.add(anchor); // don't retry on next refresh\n return;\n }\n if (!payload || !payload.campaign || !payload.campaign.id) {\n this.log(\n 'data-aegis-token-data: missing `campaign` in payload, skipping',\n 'warn',\n );\n this.filledSlots.add(anchor);\n return;\n }\n\n // U7 step 3 — pass the submit_url through to the renderer so\n // click handlers can POST the structured response (rating value,\n // NPS score, etc.) and atomically consume the token.\n this.renderCampaignIntoSlot(\n payload.campaign,\n anchor as HTMLElement,\n { submitUrl: payload.submit_url },\n );\n this.filledSlots.add(anchor);\n });\n }\n\n /**\n * Slot-mode counterpart to `displayCampaign`. Reuses the existing\n * lifecycle hooks (`campaign-will-show`, `displayedCampaigns`,\n * `campaign-shown`, impression tracking) so analytics + frequency\n * caps work the same way as overlay renders.\n *\n * Only the sub_types that make UX sense embedded are handled; the\n * rest (modal, full_screen, half_interstitial, alert, pip) silently\n * skip — those types only make sense as fullscreen overlays.\n */\n private renderCampaignIntoSlot(\n campaign: InAppCampaign,\n target: HTMLElement,\n // deferImpression: the caller (a rotating slot) fires the impression when\n // the campaign actually becomes VISIBLE, not at render time — so hidden\n // panes in a rotator don't over-count.\n options?: { submitUrl?: string; deferImpression?: boolean },\n ): void {\n const proceed = this.emit('campaign-will-show', campaign);\n if (!proceed) {\n this.log(\n `slot campaign ${campaign.id} suppressed by campaign-will-show handler`,\n );\n return;\n }\n\n this.displayedCampaigns.add(campaign.id);\n this.addAnimationStyles();\n\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const { bg, text } = this._surfacePalette(campaign);\n const submitUrl = options?.submitUrl;\n\n // §7.13.I — an embedded FORM (profile completion). Recognised by its\n // field-map `interactive_config.form_fields` (the bill's `multi_step_form`\n // block), independent of sub_type. Renders input fields inline + submits to\n // /in-app/responses so the answers enrich the contact.\n const _formFields = Array.isArray(ic.form_fields)\n ? (ic.form_fields as Array<Record<string, unknown>>)\n : null;\n\n let rendered = false;\n if (_formFields && _formFields.length > 0) {\n rendered = this.renderFormSlot(campaign, _formFields, bg, text, target);\n if (!rendered) { this.displayedCampaigns.delete(campaign.id); return; }\n if (!options?.deferImpression) {\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n }\n return;\n }\n switch (campaign.sub_type) {\n case 'star_rating':\n rendered = this.renderStarRatingSlot(\n campaign, ic, bg, text, target, submitUrl,\n );\n break;\n case 'nps_survey':\n rendered = this.renderNPSSurveySlot(\n campaign, ic, bg, text, target, submitUrl,\n );\n break;\n // Parity tracker — built-in embedded gamification renderers (no\n // AegisMessageRuntime callback needed, so they work on the bill).\n case 'spin_wheel':\n rendered = this.renderSpinWheelSlot(campaign, ic, bg, text, target);\n break;\n case 'quick_poll':\n rendered = this.renderQuickPollSlot(campaign, ic, bg, text, target);\n break;\n case 'carousel_cards':\n rendered = this.renderCarouselCardsSlot(campaign, ic, bg, text, target);\n break;\n case 'countdown_offer':\n rendered = this.renderCountdownSlot(campaign, ic, bg, text, target);\n break;\n case 'scratch_card':\n rendered = this.renderScratchCardSlot(campaign, ic, bg, text, target);\n break;\n case 'custom_html':\n rendered = this.renderCustomHtmlSlot(campaign, ic, bg, text, target);\n break;\n case 'stories':\n // Inline story-group thumbnail launcher (Plotline-parity embedded\n // widget) — the rings/cover tray; tapping a thumbnail opens the player.\n rendered = renderStoriesRings(this.buildRenderContext(campaign), target);\n break;\n case 'video':\n // Inline video banner (the Video Banner surface); tap-to-unmute hero.\n rendered = renderVideoInline(this.buildRenderContext(campaign), target);\n break;\n case 'progress_bar':\n // Inline progress bar (free-delivery / cart-total goal) embedded into a\n // host slot — e.g. the storefront value-bar footer's `footer_nudge`\n // slot. Reads live cart via runtime.setCartState() and self-updates.\n rendered = renderProgressBarInline(this.buildRenderContext(campaign), target);\n break;\n case 'quiz':\n // Inline quiz on the slot; falls back to a generic card when it has no\n // questions authored (renderQuizSlot returns false).\n rendered = this.renderQuizSlot(campaign, ic, bg, text, target);\n if (!rendered) {\n rendered = this.renderGenericCardSlot(campaign, ic, bg, text, target);\n }\n break;\n // Remaining sub_types (sticky_bar, progress_bar,\n // product_recommendation) render as a generic card on the bill slot\n // (overlay path handles their full UX); dedicated slot variants get added\n // here as merchants need them.\n default:\n // §7.13.H/I — any other embedded card (banner / coupon nudge /\n // birthday / referral / app-install / win-back / generic) renders as a\n // card with its copy, optional image, coupon chip and CTA. Without this\n // the gallery nudges silently never appeared on the bill (only\n // star_rating / nps_survey / form were handled).\n rendered = this.renderGenericCardSlot(campaign, ic, bg, text, target);\n break;\n }\n\n if (!rendered) return;\n if (!options?.deferImpression) {\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n }\n }\n\n /**\n * Slot-mode wrappers. They build a small card container (no overlay\n * positioning, no close button) and append the SHARED body element\n * the overlay path also uses. Body construction lives in the\n * `_buildXxxBody` helpers below so visual output stays identical\n * between overlay and slot modes — adding a renderer feature in\n * one place updates both.\n */\n private renderStarRatingSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n submitUrl?: string,\n ): boolean {\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard(\n 'aegis-in-app-rating-card', campaign.id, bg, text, st.radius,\n );\n card.appendChild(\n this._buildStarRatingBody(campaign, ic, text, 'slot', submitUrl, st),\n );\n target.appendChild(card);\n return true;\n }\n\n private renderNPSSurveySlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n submitUrl?: string,\n ): boolean {\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard(\n 'aegis-in-app-nps-card', campaign.id, bg, text, st.radius,\n );\n card.appendChild(\n this._buildNPSSurveyBody(campaign, ic, text, 'slot', submitUrl, st),\n );\n target.appendChild(card);\n return true;\n }\n\n /** §7.13.H — generic embedded card: image / title / body / coupon chip / CTA.\n * The catch-all for banner + nudge sub_types (birthday, referral, app-install,\n * win-back, etc.) so EVERY gallery nudge renders on the bill (previously only\n * star_rating / nps_survey / form were handled → nudges never appeared). */\n private renderGenericCardSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n ): boolean {\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard('aegis-in-app-generic-card', campaign.id, bg, text, st.radius);\n const c = campaign as unknown as Record<string, unknown>;\n const img = typeof c.image_url === 'string' ? (c.image_url as string) : '';\n const couponCode = typeof ic.coupon_code === 'string' ? (ic.coupon_code as string) : '';\n const buttonText = typeof c.button_text === 'string' ? (c.button_text as string) : '';\n const actionUrl = typeof c.action_url === 'string' ? (c.action_url as string) : '';\n\n if (img) {\n const im = document.createElement('img');\n im.src = img;\n im.alt = '';\n im.style.cssText = 'width: 100%; height: 96px; object-fit: cover; display: block;';\n card.appendChild(im);\n }\n const cbody = document.createElement('div');\n cbody.style.cssText = `padding: ${st.padY ?? 12}px ${st.padX ?? 12}px; display: flex; flex-direction: column; gap: 6px;`;\n if (campaign.title) {\n const t = document.createElement('div');\n t.style.cssText = `font-size: 13px; font-weight: ${st.weight ?? '700'};`;\n t.textContent = campaign.title;\n cbody.appendChild(t);\n }\n if (campaign.body) {\n const b = document.createElement('div');\n b.style.cssText = 'font-size: 11px; opacity: 0.85; line-height: 1.35;';\n b.textContent = campaign.body;\n cbody.appendChild(b);\n }\n if (couponCode) {\n const chip = document.createElement('span');\n chip.style.cssText = `align-self: flex-start; border: 1px dashed ${text}66; border-radius: 6px; padding: 2px 8px; font-family: monospace; font-size: 11px; letter-spacing: 0.04em;`;\n chip.textContent = couponCode;\n cbody.appendChild(chip);\n }\n if (buttonText) {\n const btn = document.createElement('button');\n btn.textContent = buttonText;\n btn.style.cssText = `margin-top: 2px; align-self: flex-start; padding: 8px 14px; border-radius: ${st.btnRadius ?? 9}px; border: none; background: ${text}; color: ${bg}; font-size: 13px; font-weight: 600; cursor: pointer;`;\n btn.addEventListener('click', () => {\n void this.trackEvent(campaign.id, 'clicked');\n if (actionUrl) window.open(actionUrl, '_blank', 'noopener');\n });\n cbody.appendChild(btn);\n }\n card.appendChild(cbody);\n target.appendChild(card);\n return true;\n }\n\n /**\n * §7.13.I — embedded profile FORM. Renders one input per `form_fields` entry\n * and, on submit, POSTs `{response_type:'form', payload:{fields:{key:value}}}`\n * to `/in-app/responses` — the cell-plane enrichment writes the mapped answers\n * back onto the contact. Keyed by each field's `key` so it matches the\n * campaign's field→contact map.\n */\n private renderFormSlot(\n campaign: InAppCampaign,\n fields: Array<Record<string, unknown>>,\n bg: string,\n text: string,\n target: HTMLElement,\n ): boolean {\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard('aegis-in-app-form-card', campaign.id, bg, text, st.radius);\n card.appendChild(this._buildFormBody(campaign, fields, bg, text, st));\n target.appendChild(card);\n return true;\n }\n\n /** Shared form body — the input fields + submit. Used embedded (slot) today;\n * the overlay form path reuses it too. */\n private _buildFormBody(\n campaign: InAppCampaign,\n fields: Array<Record<string, unknown>>,\n bg: string,\n text: string,\n slotStyle?: { padX?: number; padY?: number; btnRadius?: number; weight?: string },\n ): HTMLElement {\n const body = document.createElement('div');\n body.style.cssText = `padding: ${slotStyle?.padY ?? 16}px ${slotStyle?.padX ?? 16}px; display: flex; flex-direction: column; gap: 10px;`;\n\n if (campaign.title) {\n const t = document.createElement('div');\n t.style.cssText = `font-size: 14px; font-weight: ${slotStyle?.weight ?? '700'};`;\n t.textContent = campaign.title;\n body.appendChild(t);\n }\n if (campaign.body) {\n const b = document.createElement('div');\n b.style.cssText = 'font-size: 12px; opacity: 0.8; margin-top: -4px;';\n b.textContent = campaign.body;\n body.appendChild(b);\n }\n\n type FormControl = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n const inputs = new Map<string, FormControl>();\n const requiredKeys = new Set<string>();\n // Theme-aware control (was a hardcoded white input that clashed on dark\n // modals). A faint tint of the text color works on both light + dark.\n const ctrlCss = `padding: 9px 11px; border-radius: 9px; border: 1px solid ${text}33; background: ${text}0d; color: ${text}; font-size: 13px; width: 100%; box-sizing: border-box; font-family: inherit;`;\n for (const f of fields) {\n const key = typeof f.key === 'string' ? f.key : null;\n if (!key) continue;\n const ftype = typeof f.type === 'string' ? f.type : 'text';\n const labelText = (typeof f.label === 'string' && f.label) || key;\n const req = f.required === true;\n if (req) requiredKeys.add(key);\n\n const wrap = document.createElement('div');\n wrap.style.cssText = 'display: flex; flex-direction: column; gap: 4px;';\n // Visible label (was placeholder-only — bad a11y + vanished on focus).\n const lbl = document.createElement('label');\n lbl.textContent = labelText + (req ? ' *' : '');\n lbl.style.cssText = `font-size: 11px; font-weight: 600; opacity: 0.8; color: ${text};`;\n wrap.appendChild(lbl);\n\n let ctrl: FormControl;\n if (ftype === 'select') {\n const sel = document.createElement('select');\n sel.style.cssText = ctrlCss;\n const ph = document.createElement('option');\n ph.value = '';\n ph.textContent = (typeof f.placeholder === 'string' && f.placeholder) || 'Select…';\n sel.appendChild(ph);\n (Array.isArray(f.options) ? (f.options as string[]) : []).forEach((o) => {\n const op = document.createElement('option');\n op.value = o; op.textContent = o; sel.appendChild(op);\n });\n ctrl = sel;\n } else if (ftype === 'textarea') {\n const ta = document.createElement('textarea');\n ta.className = 'aegis-field';\n ta.rows = 3;\n ta.placeholder = (typeof f.placeholder === 'string' && f.placeholder) || labelText;\n ta.style.cssText = `${ctrlCss} resize: vertical;`;\n ctrl = ta;\n } else {\n const input = document.createElement('input');\n input.className = 'aegis-field';\n input.type = ftype === 'email' ? 'email' : ftype === 'date' ? 'date' : ftype === 'tel' ? 'tel' : ftype === 'number' ? 'number' : 'text';\n input.placeholder = (typeof f.placeholder === 'string' && f.placeholder) || labelText;\n input.style.cssText = ctrlCss;\n ctrl = input;\n }\n if (req) ctrl.required = true;\n inputs.set(key, ctrl);\n wrap.appendChild(ctrl);\n body.appendChild(wrap);\n }\n\n const submit = document.createElement('button');\n const _cAny = campaign as unknown as Record<string, unknown>;\n submit.textContent = (typeof _cAny.button_text === 'string' && (_cAny.button_text as string)) || 'Save';\n submit.style.cssText = `margin-top: 4px; padding: 10px 16px; border-radius: ${slotStyle?.btnRadius ?? 10}px; border: none; background: ${text}; color: ${bg}; font-size: 14px; font-weight: 600; cursor: pointer;`;\n submit.addEventListener('click', () => {\n const collected: Record<string, string> = {};\n let ok = true;\n for (const [key, input] of inputs) {\n const v = (input.value || '').trim();\n if (requiredKeys.has(key) && !v) { ok = false; input.style.borderColor = '#e11d48'; }\n else input.style.borderColor = `${text}33`;\n if (v) collected[key] = v;\n }\n if (!ok || Object.keys(collected).length === 0) return;\n void this.submitFormResponse(campaign, collected);\n void this.trackEvent(campaign.id, 'clicked', { meta: { fields: Object.keys(collected) } });\n // Thank-you state. The completion Lottie (~150px) would be CLIPPED by the\n // modal's overflow:hidden once the body collapses to one line — reserve\n // room + let the modal overflow (same fix as the star/nps thank-you).\n while (body.firstChild) body.removeChild(body.firstChild);\n const modalEl = body.parentElement as HTMLElement | null;\n if (modalEl) modalEl.style.overflow = 'visible';\n body.style.position = 'relative';\n body.style.minHeight = '176px';\n body.style.alignItems = 'center';\n body.style.justifyContent = 'center';\n const done = document.createElement('div');\n done.style.cssText = 'padding: 8px 0; font-size: 13px; font-weight: 600; text-align: center;';\n done.textContent = (typeof (campaign.interactive_config as Record<string, unknown> | undefined)?.thank_you_message === 'string'\n ? ((campaign.interactive_config as Record<string, unknown>).thank_you_message as string)\n : '✓ Thanks — your details are saved.');\n body.appendChild(done);\n this._playReaction(body, 'affirm', 'check.json', campaign.interactive_config as Record<string, unknown> | undefined); // form complete → check + confetti\n });\n body.appendChild(submit);\n return body;\n }\n\n /** POST a form response to /in-app/responses (gateway → cell-plane). The\n * cell-plane enriches the contact from the campaign's field-map. Best-effort. */\n private async submitFormResponse(\n campaign: InAppCampaign,\n fields: Record<string, string>,\n ): Promise<void> {\n if (!this.organizationId) {\n this.log('submitFormResponse: no organizationId — cannot submit', 'warn');\n return;\n }\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Organization-ID': this.organizationId,\n };\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n const variantId = (campaign as unknown as Record<string, unknown>).assigned_variant_id as string | undefined;\n const res = await fetch(`${this.apiHost}/v1/in-app/responses`, {\n method: 'POST',\n headers,\n keepalive: true,\n body: JSON.stringify({\n campaign_id: campaign.id,\n response_type: 'form',\n contact_id: this.contactId,\n user_id: this.userId,\n variant_id: variantId,\n platform: 'web',\n payload: { fields },\n }),\n });\n if (!res.ok) this.log(`submitFormResponse failed (${res.status})`, 'warn');\n } catch (e) {\n this.log(`submitFormResponse error: ${e}`, 'warn');\n }\n }\n\n /**\n * Generic interactive response submit → POST /v1/in-app/responses. Returns the\n * parsed server response (which for spin/scratch carries the server-picked\n * `prize`) or null. Interactive Widgets Parity tracker — every embedded widget\n * records a response so analytics + prize-from-segments work uniformly.\n */\n private async submitWidgetResponse(\n campaign: InAppCampaign,\n responseType: string,\n payload: Record<string, unknown>,\n ): Promise<Record<string, unknown> | null> {\n if (!this.organizationId) return null;\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Organization-ID': this.organizationId,\n };\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n const variantId = (campaign as unknown as Record<string, unknown>).assigned_variant_id as string | undefined;\n const res = await fetch(`${this.apiHost}/v1/in-app/responses`, {\n method: 'POST',\n headers,\n keepalive: true,\n body: JSON.stringify({\n campaign_id: campaign.id,\n response_type: responseType,\n contact_id: this.contactId,\n user_id: this.userId,\n variant_id: variantId,\n platform: 'web',\n payload,\n }),\n });\n if (!res.ok) {\n this.log(`submitWidgetResponse ${responseType} failed (${res.status})`, 'warn');\n return null;\n }\n return (await res.json().catch(() => null)) as Record<string, unknown> | null;\n } catch (e) {\n this.log(`submitWidgetResponse ${responseType} error: ${e}`, 'warn');\n return null;\n }\n }\n\n /**\n * Built-in embedded SPIN WHEEL (no AegisMessageRuntime callback dependency —\n * works on the bill). Slices come from `interactive_config.segments`; on Spin\n * it submits to /in-app/responses, the server picks the prize from the AUTHORED\n * segments, and the wheel animates to that segment + reveals the prize/coupon.\n */\n private renderSpinWheelSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n ): boolean {\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard('aegis-in-app-spin-card', campaign.id, bg, text, st.radius);\n const segs = Array.isArray(ic.segments) ? (ic.segments as Array<Record<string, unknown>>) : [];\n // Keep the authored segment objects aligned to the displayed slices so we\n // can read the landed slice's `prize_type` (a `no_prize` slice — e.g.\n // \"Try again\" — is a LOSS → empathetic reaction, not a celebration).\n const shown = segs.filter((s) => typeof s.label === 'string' && (s.label as string));\n const labels = shown.map((s) => s.label as string);\n const n = labels.length >= 2 ? labels.length : 8;\n const isLossSeg = (i: number): boolean =>\n !!shown[i] && String(shown[i].prize_type || '').toLowerCase() === 'no_prize';\n // W3: the contact's outstanding unredeemed prize for THIS campaign, bound\n // server-side from the canonical contact_entitlements ledger (rides ic like\n // every other serve-time bind). When present we show the won card instead of\n // a fresh, re-rollable wheel — covers returning visitors AND mid-spin dropouts.\n const alreadyWon = (ic.already_won && typeof ic.already_won === 'object')\n ? (ic.already_won as Record<string, unknown>) : null;\n const colorOf = (i: number): string => {\n const c = shown[i] && typeof shown[i].color === 'string' ? (shown[i].color as string) : '';\n return c || (i % 2 === 0 ? text : `${text}40`);\n };\n // Slice geometry is PROPORTIONAL to each segment's probability, so the wheel\n // visually reflects the odds (matches the editor odds bar). Falls back to\n // equal slices when no usable weights exist.\n const rawW = Array.from({ length: n }, (_, i) => {\n const p = shown[i] && typeof shown[i].probability === 'number' ? (shown[i].probability as number) : NaN;\n return Number.isFinite(p) && p > 0 ? p : 0;\n });\n const sumW = rawW.reduce((a, b) => a + b, 0);\n const weights = sumW > 0 ? rawW : Array.from({ length: n }, () => 1);\n const wTotal = sumW > 0 ? sumW : n;\n // `equal` = uniform visual slices (classic wheel; odds stay rigged by the\n // server). `proportional` = slice size reflects each segment's probability.\n // Either way, probability ALWAYS drives the server-picked prize.\n const sizing = typeof ic.spin_slice_sizing === 'string' ? ic.spin_slice_sizing : 'proportional';\n const spans = sizing === 'equal'\n ? Array.from({ length: n }, () => 360 / n)\n : weights.map((w) => (w / wTotal) * 360);\n const starts: number[] = [];\n spans.reduce((acc, s, i) => { starts[i] = acc; return acc + s; }, 0);\n const midOf = (i: number): number => starts[i] + spans[i] / 2;\n const sliceAt = (deg: number): number => {\n const d = ((deg % 360) + 360) % 360;\n for (let i = 0; i < n; i++) { if (d >= starts[i] && d < starts[i] + spans[i]) return i; }\n return n - 1;\n };\n const stops = Array.from({ length: n }, (_, i) => `${colorOf(i)} ${starts[i]}deg ${starts[i] + spans[i]}deg`).join(', ');\n\n // ── Look & feel + interactivity knobs (all optional, default-safe) ──────\n const cfgStr = (k: string): string => (typeof ic[k] === 'string' ? (ic[k] as string) : '');\n const spinMode = cfgStr('spin_mode') || 'both'; // button | drag | both\n const idleAnim = cfgStr('spin_idle_animation') || 'shimmer'; // none | shimmer | wobble\n const winReveal = cfgStr('spin_win_reveal') || 'inline'; // inline (default) | takeover\n const hapticsOn = ic.spin_haptics_enabled !== false;\n let soundOn = ic.spin_sound_enabled !== false;\n const pointerColor = cfgStr('spin_pointer_color') || '#ffffff';\n const hubImg = cfgStr('spin_hub_image_url');\n // W4 asset-swap: wheel_background_url replaces the conic slice face with\n // operator art (labels + dividers suppressed); pointer_image_url swaps the\n // CSS pointer for a custom image. Anchor stays top_center.\n const wheelBgImg = cfgStr('wheel_background_url');\n const pointerImg = cfgStr('pointer_image_url');\n const isUrl = (s: string): boolean => /^https?:\\/\\//i.test(s);\n const now = (): number => (typeof performance !== 'undefined' && performance.now ? performance.now() : Date.now());\n let rotation = 0;\n\n // One-time keyframes for the idle attract loop + the win reveal.\n if (typeof document !== 'undefined' && !document.getElementById('aegis-spin-kf')) {\n const kf = document.createElement('style');\n kf.id = 'aegis-spin-kf';\n kf.textContent =\n '@keyframes aegisSpinWobble{0%,100%{transform:rotate(-5deg)}50%{transform:rotate(5deg)}}' +\n '@keyframes aegisSpinSheen{0%{transform:translateX(-130%)}100%{transform:translateX(360%)}}' +\n '@keyframes aegisSpinRevealIn{0%{opacity:0;transform:scale(0.86)}100%{opacity:1;transform:scale(1)}}';\n document.head.appendChild(kf);\n }\n\n // Lightweight WebAudio tick/chime — created lazily on the first user gesture\n // (AudioContext can only start after interaction). Synth-based; no assets.\n let audioCtx: AudioContext | null = null;\n const ensureAudio = (): AudioContext | null => {\n if (!soundOn) return null;\n try {\n if (!audioCtx) {\n const Ctx = window.AudioContext\n || (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Ctx) return null;\n audioCtx = new Ctx();\n }\n if (audioCtx.state === 'suspended') void audioCtx.resume();\n return audioCtx;\n } catch { return null; }\n };\n const beep = (freq: number, durMs: number, type: OscillatorType = 'triangle', gain = 0.06): void => {\n const ac = ensureAudio();\n if (!ac) return;\n const osc = ac.createOscillator();\n const g = ac.createGain();\n osc.type = type;\n osc.frequency.value = freq;\n g.gain.setValueAtTime(gain, ac.currentTime);\n g.gain.exponentialRampToValueAtTime(0.0001, ac.currentTime + durMs / 1000);\n osc.connect(g); g.connect(ac.destination);\n osc.start();\n osc.stop(ac.currentTime + durMs / 1000);\n };\n const vibrate = (p: number | number[]): void => {\n if (!hapticsOn) return;\n try { (navigator as unknown as { vibrate?: (x: number | number[]) => boolean }).vibrate?.(p); }\n catch { /* haptics unsupported — noop */ }\n };\n const tickFx = (): void => { beep(1180, 26, 'square', 0.035); vibrate(5); };\n const winFx = (): void => {\n [523, 659, 784, 1047].forEach((f, i) => window.setTimeout(() => beep(f, 170, 'sine', 0.07), i * 105));\n vibrate([0, 35, 25, 35, 25, 90]);\n };\n const loseFx = (): void => { beep(320, 220, 'sine', 0.05); vibrate(18); };\n\n const body = document.createElement('div');\n body.style.cssText = `padding: ${st.padY ?? 22}px ${st.padX ?? 20}px 20px; display: flex; flex-direction: column; align-items: center; gap: 16px;`;\n if (campaign.title) {\n const t = document.createElement('div');\n t.style.cssText =\n `font-size: 18px; font-weight: 800; letter-spacing: -0.01em; text-align: center; ` +\n `font-family: 'Inter Tight', Inter, system-ui, -apple-system, sans-serif;`;\n t.textContent = campaign.title;\n body.appendChild(t);\n }\n if (campaign.body) {\n const sub = document.createElement('div');\n sub.style.cssText = 'font-size: 12.5px; opacity: 0.82; text-align: center; margin-top: -8px; line-height: 1.35;';\n sub.textContent = campaign.body;\n body.appendChild(sub);\n }\n const SIZE = 172;\n const radius = SIZE / 2;\n const wheelWrap = document.createElement('div');\n wheelWrap.style.cssText = `position: relative; width: ${SIZE}px; height: ${SIZE}px; filter: drop-shadow(0 10px 22px rgba(0,0,0,0.30));`;\n const pointer = document.createElement('div');\n // Crisp teardrop pointer dipping into the rim, with a soft shadow.\n // transform-origin at the top-center = the flap's hinge; the tip (pointing\n // into the rim) swings when a peg kicks it (see the flapper physics below).\n pointer.style.cssText = pointerImg\n ? `position: absolute; left: 50%; top: -10px; transform: translateX(-50%); transform-origin: 50% 0; width: 26px; height: 30px; background: center / contain no-repeat url(\"${pointerImg}\"); z-index: 5; filter: drop-shadow(0 2px 2px rgba(0,0,0,0.35));`\n : `position: absolute; left: 50%; top: -7px; transform: translateX(-50%); transform-origin: 50% 0; width: 0; height: 0; border-left: 9px solid transparent; border-right: 9px solid transparent; border-top: 16px solid ${pointerColor}; z-index: 5; filter: drop-shadow(0 2px 2px rgba(0,0,0,0.35));`;\n const wheel = document.createElement('div');\n // Thick white rim + inset shading for a tactile, glossy disc. Rotation is\n // JS-driven (rAF) so we can do flick-momentum + per-slice ticks, so NO CSS\n // transition on transform here.\n const wheelFace = wheelBgImg ? `center / cover no-repeat url(\"${wheelBgImg}\")` : `conic-gradient(${stops})`;\n wheel.style.cssText = `position: relative; width: ${SIZE}px; height: ${SIZE}px; border-radius: 50%; border: 5px solid #ffffff; box-shadow: 0 0 0 2px ${text}2e, inset 0 0 22px rgba(0,0,0,0.20); background: ${wheelFace}; overflow: hidden; will-change: transform; touch-action: none; cursor: ${spinMode === 'button' ? 'default' : 'grab'};`;\n if (idleAnim === 'wobble') wheel.style.animation = 'aegisSpinWobble 3s ease-in-out infinite';\n\n // Crisp white hairline dividers at each (variable) slice boundary — drawn as\n // thin radial lines from center to rim so they track the proportional slices.\n // Operator art (wheelBgImg) carries its own slice lines → suppress ours.\n if (!wheelBgImg) starts.forEach((b) => {\n const ln = document.createElement('div');\n ln.style.cssText = `position: absolute; left: 50%; top: 0; width: 1.5px; height: 50%; background: rgba(255,255,255,0.55); transform-origin: bottom center; transform: translateX(-50%) rotate(${b}deg); pointer-events: none;`;\n wheel.appendChild(ln);\n });\n\n // Segment labels are RADIAL — laid along each slice's bisector (reading\n // outward), so they use the long radius instead of the narrow chord and\n // never run over the hub. Text is flipped on the lower hemisphere to stay\n // upright, the font AUTO-FITS the slice (shrinks for long labels / thin\n // slices), and the optional icon sits just outboard of the label.\n const rHub = 22; // keep clear of the center cap\n const rRim = radius - 8; // keep clear of the rim\n const bandLen = rRim - rHub; // usable radial length for the label\n const rText = (rHub + rRim) / 2; // band center\n if (!wheelBgImg) labels.forEach((label, i) => {\n const mid = midOf(i); // degrees clockwise from top (proportional slice mid)\n // W4.2: a per-wedge image replaces the text label — the prize art reads as\n // the slice itself. Reuses the SAME radial placement as labels/icons (band\n // center, flipped on the lower hemisphere); no canvas rewrite.\n const wedgeImg = shown[i] && typeof shown[i].image_url === 'string' ? (shown[i].image_url as string) : '';\n if (wedgeImg && isUrl(wedgeImg)) {\n const flipImg = mid > 180 && mid < 360;\n const isz = Math.max(18, Math.min(40, bandLen * 0.62));\n const wim = document.createElement('img');\n wim.src = wedgeImg; wim.alt = label || '';\n wim.style.cssText =\n `position: absolute; left: 50%; top: 50%; width: ${isz}px; height: ${isz}px; object-fit: contain; ` +\n `transform: translate(-50%, -50%) rotate(${mid}deg) translateY(-${rText}px) rotate(${flipImg ? 90 : -90}deg); ` +\n `filter: drop-shadow(0 1px 3px rgba(0,0,0,0.55)); pointer-events: none;`;\n wheel.appendChild(wim);\n return;\n }\n const icoVal = shown[i] && typeof shown[i].icon === 'string' ? (shown[i].icon as string) : '';\n // Auto-fit: cap by the slice's angular thickness (chord) AND by the radial\n // length the text would need on one line.\n const chord = 2 * rText * Math.sin((spans[i] * Math.PI) / 180 / 2);\n const byThickness = chord * 0.6;\n const byLength = bandLen / Math.max(4, label.length * 0.62 + (icoVal ? 1.6 : 0));\n const fontPx = Math.max(7, Math.min(13, Math.floor(Math.min(byThickness, byLength))));\n // Lower hemisphere would render upside-down → flip 180° and reverse order.\n const flip = mid > 180 && mid < 360;\n const textRot = flip ? 90 : -90;\n const lab = document.createElement('div');\n lab.style.cssText =\n `position: absolute; left: 50%; top: 50%; width: ${bandLen}px; ` +\n `transform: translate(-50%, -50%) rotate(${mid}deg) translateY(-${rText}px) rotate(${textRot}deg); ` +\n `display: flex; flex-direction: ${flip ? 'row-reverse' : 'row'}; align-items: center; justify-content: center; gap: 4px; ` +\n `white-space: nowrap; pointer-events: none;`;\n if (icoVal) {\n if (isUrl(icoVal)) {\n const im = document.createElement('img');\n im.src = icoVal; im.alt = '';\n im.style.cssText = `width: ${fontPx + 6}px; height: ${fontPx + 6}px; object-fit: contain; flex: 0 0 auto; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.5));`;\n lab.appendChild(im);\n } else {\n const em = document.createElement('span');\n em.textContent = icoVal;\n em.style.cssText = `font-size: ${fontPx + 4}px; line-height: 1; flex: 0 0 auto;`;\n lab.appendChild(em);\n }\n }\n const tx = document.createElement('span');\n tx.textContent = label;\n tx.style.cssText =\n `white-space: nowrap; line-height: 1.05; font-size: ${fontPx}px; font-weight: 900; ` +\n `font-family: 'Inter Tight', Inter, system-ui, -apple-system, sans-serif; ` +\n `letter-spacing: 0.2px; text-transform: uppercase; color: #fff; ` +\n `text-shadow: 0 1px 3px rgba(0,0,0,0.65), 0 0 1px rgba(0,0,0,0.9); -webkit-font-smoothing: antialiased;`;\n lab.appendChild(tx);\n wheel.appendChild(lab);\n });\n\n // Static glossy sheen over the disc (light from the top — does NOT rotate).\n const sheen = document.createElement('div');\n sheen.style.cssText = `position: absolute; inset: 0; border-radius: 50%; pointer-events: none; z-index: 2; background: radial-gradient(circle at 50% 22%, rgba(255,255,255,0.30), rgba(255,255,255,0.04) 42%, transparent 62%);`;\n\n // Idle attract sweep (shimmer) — a clipped light bar that drifts across the\n // disc until the customer interacts, then it's removed.\n let idleClip: HTMLElement | null = null;\n if (idleAnim === 'shimmer') {\n const clip = document.createElement('div');\n clip.style.cssText = 'position: absolute; inset: 0; border-radius: 50%; overflow: hidden; pointer-events: none; z-index: 3;';\n const bar = document.createElement('div');\n bar.style.cssText = 'position: absolute; top: -25%; left: 0; width: 36%; height: 150%; transform: skewX(-12deg); background: linear-gradient(90deg, transparent, rgba(255,255,255,0.5), transparent); animation: aegisSpinSheen 2.8s ease-in-out infinite; animation-delay: 0.5s;';\n clip.appendChild(bar);\n idleClip = clip;\n }\n\n const hub = document.createElement('div');\n // Glossy center cap (or a branded logo) — sits above the disc + sheen.\n hub.style.cssText = `position: absolute; left: 50%; top: 50%; width: 40px; height: 40px; transform: translate(-50%, -50%); border-radius: 50%; background: radial-gradient(circle at 35% 30%, #ffffff, #e9edf5); border: 3px solid #fff; box-shadow: 0 3px 8px rgba(0,0,0,0.30); z-index: 4; overflow: hidden; display: flex; align-items: center; justify-content: center;`;\n if (hubImg) {\n // Render the logo as a dark-grey silhouette (source-in tint) so a light\n // brand logo still reads on the white cap — same treatment as the scratch\n // foil. Drawn into a canvas, contain-fit.\n const hc = document.createElement('canvas');\n hc.width = 40; hc.height = 40;\n hc.style.cssText = 'width: 100%; height: 100%;';\n const hcx = hc.getContext('2d');\n const him = new Image(); him.crossOrigin = 'anonymous';\n him.onload = (): void => {\n if (!hcx) return;\n const ar = him.width / him.height || 1;\n let w = 32, h = 32;\n if (ar > 1) h = 32 / ar; else w = 32 * ar;\n hcx.drawImage(him, (40 - w) / 2, (40 - h) / 2, w, h);\n hcx.globalCompositeOperation = 'source-in';\n hcx.fillStyle = '#5b626e';\n hcx.fillRect(0, 0, 40, 40);\n };\n him.onerror = (): void => { /* keep the plain cap */ };\n him.src = hubImg;\n hub.appendChild(hc);\n } else {\n const hubDot = document.createElement('div');\n hubDot.style.cssText = `width: 11px; height: 11px; border-radius: 50%; background: ${bg};`;\n hub.appendChild(hubDot);\n }\n wheelWrap.appendChild(pointer);\n wheelWrap.appendChild(wheel);\n wheelWrap.appendChild(sheen);\n if (idleClip) wheelWrap.appendChild(idleClip);\n wheelWrap.appendChild(hub);\n body.appendChild(wheelWrap);\n\n if (!card.style.position) card.style.position = 'relative';\n\n const result = document.createElement('div');\n result.style.cssText = 'font-size: 14px; font-weight: 800; min-height: 20px; text-align: center; letter-spacing: 0.2px;';\n\n // Tiny unobtrusive mute toggle (only when sound is configured on).\n if (ic.spin_sound_enabled !== false) {\n const soundBtn = document.createElement('button');\n soundBtn.type = 'button';\n soundBtn.setAttribute('aria-label', 'Toggle sound');\n soundBtn.textContent = soundOn ? '🔊' : '🔇';\n soundBtn.style.cssText = 'position: absolute; top: 10px; left: 12px; background: transparent; border: none; font-size: 15px; cursor: pointer; opacity: 0.65; z-index: 6; line-height: 1;';\n soundBtn.addEventListener('click', () => { soundOn = !soundOn; soundBtn.textContent = soundOn ? '🔊' : '🔇'; });\n card.appendChild(soundBtn);\n }\n\n const btn = document.createElement('button');\n btn.textContent = (campaign as unknown as Record<string, unknown>).button_text as string || 'Spin the wheel';\n // Pill CTA with depth + a press/hover lift.\n btn.style.cssText =\n `padding: 12px 32px; border-radius: 999px; border: none; background: #ffffff; color: ${bg}; ` +\n `font-size: 15px; font-weight: 800; letter-spacing: 0.2px; cursor: pointer; ` +\n `box-shadow: 0 6px 16px rgba(0,0,0,0.22); transition: transform 0.15s, box-shadow 0.15s; ` +\n `font-family: 'Inter Tight', Inter, system-ui, -apple-system, sans-serif;`;\n btn.addEventListener('mouseenter', () => {\n if (btn.disabled) return;\n btn.style.transform = 'translateY(-1px)';\n btn.style.boxShadow = '0 9px 22px rgba(0,0,0,0.28)';\n });\n btn.addEventListener('mouseleave', () => {\n if (btn.disabled) return;\n btn.style.transform = 'translateY(0)';\n btn.style.boxShadow = '0 6px 16px rgba(0,0,0,0.22)';\n });\n\n let spinning = false;\n let resolved = false; // one spin per customer — block re-spin via flick after resolve\n let lastTickSlice = -1;\n\n const stopIdle = (): void => {\n try { idleClip?.remove(); } catch { /* noop */ }\n wheel.style.animation = '';\n };\n\n // ── Flapper pointer physics ──────────────────────────────────────────────\n // The pointer is a hinged flap: each peg (slice boundary) passing under it\n // gives it a kick (scaled by the wheel's current speed) and a spring-damper\n // pulls it back to rest — so it ratchets WITH the wheel and the kicks shrink\n // as the wheel slows, settling at the stop.\n let spinSpeed = 0; // degrees the wheel moved on the last frame/move\n let pDefl = 0, pVel = 0; // pointer deflection (deg) + its angular velocity\n let pointerRaf = 0;\n const stepPointer = (): void => {\n pVel += -pDefl * 0.18; // spring toward rest\n pVel *= 0.7; // damping\n pDefl += pVel;\n if (Math.abs(pDefl) > 0.06 || Math.abs(pVel) > 0.06) {\n pointer.style.transform = `translateX(-50%) rotate(${pDefl.toFixed(2)}deg)`;\n pointerRaf = requestAnimationFrame(stepPointer);\n } else {\n pDefl = 0; pVel = 0;\n pointer.style.transform = 'translateX(-50%) rotate(0deg)';\n pointerRaf = 0;\n }\n };\n const flickPointer = (): void => {\n pVel += Math.min(9, 1.4 + spinSpeed * 0.5); // bigger kick when faster\n if (!pointerRaf) pointerRaf = requestAnimationFrame(stepPointer);\n };\n\n // Fire a tick (sound + haptic + pointer flick) each time a slice boundary\n // crosses the pointer.\n const playTicks = (deg: number): void => {\n const norm = (((360 - (deg % 360)) % 360) + 360) % 360;\n const slice = sliceAt(norm);\n if (slice !== lastTickSlice) { lastTickSlice = slice; tickFx(); flickPointer(); }\n };\n\n // rAF ease-out to an absolute target angle, with a small overshoot-settle.\n const animateTo = (finalDeg: number, durationMs: number, done: () => void): void => {\n const start = rotation;\n const delta = finalDeg - start;\n const t0 = now();\n const easeOut = (p: number): number => 1 - Math.pow(1 - p, 3);\n let lastRot = start;\n const frame = (): void => {\n const p = Math.min(1, (now() - t0) / durationMs);\n rotation = start + delta * easeOut(p);\n spinSpeed = Math.abs(rotation - lastRot); lastRot = rotation;\n wheel.style.transform = `rotate(${rotation}deg)`;\n playTicks(rotation);\n if (p < 1) { requestAnimationFrame(frame); return; }\n // Settle: tiny back-overshoot then snap to exact, for a tactile stop.\n wheel.style.transition = 'transform 0.18s ease-out';\n wheel.style.transform = `rotate(${finalDeg - 2}deg)`;\n window.setTimeout(() => {\n wheel.style.transform = `rotate(${finalDeg}deg)`;\n rotation = finalDeg;\n window.setTimeout(() => { wheel.style.transition = ''; done(); }, 180);\n }, 70);\n };\n requestAnimationFrame(frame);\n };\n\n type SpinResult = { label: string; code: string; won: boolean; kind?: string };\n\n const retireCta = (): void => {\n btn.style.transition = 'opacity 0.3s ease';\n btn.style.opacity = '0';\n btn.style.pointerEvents = 'none';\n window.setTimeout(() => { btn.style.display = 'none'; }, 320);\n };\n\n const renderTakeover = (r: SpinResult): void => {\n const ov = document.createElement('div');\n ov.style.cssText = `position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 22px; text-align: center; background: ${bg}; color: ${text}; border-radius: inherit; animation: aegisSpinRevealIn 0.4s cubic-bezier(0.16,0.86,0.28,1); z-index: 7;`;\n const eyebrow = document.createElement('div');\n eyebrow.textContent = '🎉 You won';\n eyebrow.style.cssText = 'font-size: 13px; font-weight: 700; letter-spacing: 0.3px; opacity: 0.8;';\n const big = document.createElement('div');\n big.textContent = r.label;\n big.style.cssText = `font-size: 24px; font-weight: 900; letter-spacing: -0.02em; font-family: 'Inter Tight', Inter, system-ui, -apple-system, sans-serif;`;\n ov.appendChild(eyebrow); ov.appendChild(big);\n if (r.code) {\n const chip = document.createElement('button');\n chip.type = 'button';\n chip.textContent = `${r.code} ⧉`;\n chip.style.cssText = `margin-top: 4px; padding: 9px 16px; border-radius: 999px; border: 1.5px dashed ${text}66; background: transparent; color: ${text}; font-weight: 800; font-size: 14px; letter-spacing: 1px; cursor: pointer;`;\n chip.addEventListener('click', () => {\n try { void navigator.clipboard?.writeText(r.code); chip.textContent = 'Copied ✓'; }\n catch { /* clipboard unsupported — noop */ }\n });\n ov.appendChild(chip);\n } else if (r.kind === 'freebie') {\n // Freebie has no auto-redeem code — it's claimed manually (in-store /\n // by the team). Say so, rather than implying an auto-applied reward.\n const hint = document.createElement('div');\n hint.textContent = '🎟️ Show this screen to claim';\n hint.style.cssText = 'margin-top: 2px; font-size: 12.5px; font-weight: 600; opacity: 0.85;';\n ov.appendChild(hint);\n }\n const claim = document.createElement('button');\n claim.type = 'button';\n claim.textContent = 'Awesome!';\n claim.style.cssText = `margin-top: 6px; padding: 11px 28px; border-radius: 999px; border: none; background: ${text}; color: ${bg}; font-weight: 800; font-size: 14px; cursor: pointer;`;\n claim.addEventListener('click', () => {\n void this.trackEvent(campaign.id, 'clicked');\n ov.style.transition = 'opacity 0.25s ease'; ov.style.opacity = '0';\n window.setTimeout(() => ov.remove(), 250);\n });\n ov.appendChild(claim);\n card.appendChild(ov);\n };\n\n const reveal = (r: SpinResult): void => {\n resolved = true;\n if (r.won) { winFx(); this._playReaction(card, 'celebrate', undefined, ic); }\n else { loseFx(); this._playReaction(card, 'empathize', undefined, ic); }\n if (winReveal === 'takeover' && r.won) renderTakeover(r);\n else if (r.label && r.code) {\n // Inline reveal WITH a code — give it the same copy-to-clipboard chip the\n // takeover card has (W2), instead of printing the code as dead text.\n result.textContent = '';\n const tag = document.createElement('span');\n tag.textContent = `${r.label} — `;\n const chip = document.createElement('button');\n chip.type = 'button';\n chip.textContent = `${r.code} ⧉`;\n chip.style.cssText = `padding: 2px 8px; border-radius: 999px; border: 1.5px dashed ${text}66; background: transparent; color: ${text}; font-weight: 800; font-size: 12px; letter-spacing: 0.5px; cursor: pointer;`;\n chip.addEventListener('click', () => {\n try { void navigator.clipboard?.writeText(r.code); chip.textContent = 'Copied ✓'; }\n catch { /* clipboard unsupported — noop */ }\n });\n result.appendChild(tag); result.appendChild(chip);\n }\n else result.textContent = r.label || 'Thanks for playing!';\n retireCta();\n };\n\n // velocityDegPerMs scales how many full turns the wheel spins (flick feel).\n // We DON'T wait for the server before moving: the wheel spins at a constant\n // velocity the instant the user commits (no dead pause), the ticker keeps\n // clicking, and we hand off to the ease-out the moment the authoritative\n // prize lands — matching the ease-out duration to the live loop speed so\n // there's no velocity jump. The server is the source of truth; the timeout\n // only guards a genuinely dead network. The prize itself is already durable\n // in contact_entitlements regardless of what this animation lands on, so a\n // graceful-loss fallback can never destroy a granted reward.\n const beginSpin = (velocityDegPerMs: number): void => {\n if (spinning || resolved) return;\n spinning = true;\n stopIdle();\n btn.disabled = true; btn.style.opacity = '0.6'; btn.style.transform = 'scale(0.97)';\n result.textContent = '';\n void this.trackEvent(campaign.id, 'clicked');\n ensureAudio();\n const v = Math.min(2.4, Math.max(0.25, velocityDegPerMs || 0.6));\n const turns = Math.round(3 + v * 2.0); // ~3..8 full rotations on the ease-out\n const provisional = Math.floor(Math.random() * n);\n\n // Constant-velocity idle loop — runs until the prize resolves. No landing\n // target yet; just keeps the wheel (and ticker) alive during the round-trip.\n const loopSpeed = 0.5 + v * 0.35; // deg/ms — flick speed sets the loop pace\n let looping = true;\n let done = false;\n let lastTs = now();\n const loopFrame = (): void => {\n if (!looping) return;\n const t = now();\n const moved = loopSpeed * (t - lastTs);\n lastTs = t;\n rotation += moved;\n spinSpeed = moved; // feed the pointer-flick magnitude\n wheel.style.transform = `rotate(${rotation}deg)`;\n playTicks(rotation);\n requestAnimationFrame(loopFrame);\n };\n requestAnimationFrame(loopFrame);\n\n // The slice to land on if the network is truly dead — prefer an authored\n // no_prize slice so the wheel still stops somewhere sensible.\n const lossIndex = (): number => {\n for (let i = 0; i < n; i++) { if (isLossSeg(i)) return i; }\n return provisional;\n };\n\n const launch = (idx: number, r: SpinResult): void => {\n if (done) return; done = true;\n looping = false; // animateTo now drives rotation, taking over from the LIVE angle\n const segMid = midOf(idx);\n const want = (((360 - segMid) % 360) + 360) % 360; // rotation that puts slice mid under pointer\n const base = rotation;\n let target = base - (((base % 360) + 360) % 360) + want + turns * 360;\n if (target <= base + 360) target += 360;\n // Match duration to entry speed: cubic ease-out opens at 3·delta/duration,\n // so this sets its opening slope ≈ loopSpeed — a smooth bleed, not a jump.\n const matched = (3 * (target - base)) / Math.max(0.05, loopSpeed);\n const duration = Math.min(4200, Math.max(2300, matched));\n animateTo(target, duration, () => { spinning = false; reveal(r); });\n };\n\n // Backend picks the authoritative prize from the AUTHORED segments.\n void this.submitWidgetResponse(campaign, 'spin', { segment_index: provisional }).then((resp) => {\n const prize = (resp && (resp as Record<string, unknown>).prize\n ? (resp as Record<string, unknown>).prize : null) as Record<string, unknown> | null;\n let idx = provisional;\n if (prize && typeof prize.segment_index === 'number') idx = (prize.segment_index as number) % n;\n const label = prize && typeof prize.prize_label === 'string' ? (prize.prize_label as string) : (labels[idx] || '');\n const code = prize && typeof prize.coupon_code === 'string' ? (prize.coupon_code as string) : '';\n const kind = prize && typeof prize.prize_type === 'string'\n ? (prize.prize_type as string).toLowerCase()\n : (shown[idx] && typeof shown[idx].prize_type === 'string' ? String(shown[idx].prize_type).toLowerCase() : '');\n const lost = prize ? String(prize.prize_type || '').toLowerCase() === 'no_prize' : isLossSeg(idx);\n launch(idx, { label, code, won: !!label && !lost, kind });\n }).catch(() => { /* dead network → the timeout below lands a graceful loss */ });\n\n // Dead-network safety net: keep spinning, then (only after 8s) decelerate\n // to a graceful loss. Crucially it never resolves on a guessed prize\n // mid-flight, so a slow-but-OK response can't be overwritten by a wrong,\n // codeless result (the old 900ms trap). 8s is a tunable dead-halt bound.\n window.setTimeout(() => {\n if (done) return;\n const li = lossIndex();\n launch(li, {\n label: labels[li] || '', code: '', won: false,\n kind: shown[li] && typeof shown[li].prize_type === 'string' ? String(shown[li].prize_type).toLowerCase() : 'no_prize',\n });\n }, 8000);\n };\n\n if (spinMode === 'button' || spinMode === 'both') {\n btn.addEventListener('click', () => beginSpin(0.7));\n } else {\n btn.style.display = 'none';\n }\n\n if (spinMode === 'drag' || spinMode === 'both') {\n // Flick-to-spin: track the pointer's angle around the wheel center; the\n // release angular velocity drives the spin length.\n let dragging = false;\n let startAngle = 0;\n let startRotation = 0;\n let lastA = 0; let lastT = 0; let vel = 0;\n const angleAt = (e: PointerEvent): number => {\n const rect = wheel.getBoundingClientRect();\n const cx = rect.left + rect.width / 2; const cy = rect.top + rect.height / 2;\n return Math.atan2(e.clientY - cy, e.clientX - cx) * 180 / Math.PI;\n };\n wheel.addEventListener('pointerdown', (e: PointerEvent) => {\n if (spinning || resolved) return;\n dragging = true;\n startAngle = angleAt(e); startRotation = rotation;\n lastA = startAngle; lastT = now(); vel = 0;\n wheel.style.cursor = 'grabbing';\n stopIdle();\n try { wheel.setPointerCapture(e.pointerId); } catch { /* noop */ }\n });\n wheel.addEventListener('pointermove', (e: PointerEvent) => {\n if (!dragging) return;\n const a = angleAt(e);\n const prevRot = rotation;\n rotation = startRotation + (a - startAngle);\n spinSpeed = Math.abs(rotation - prevRot);\n wheel.style.transform = `rotate(${rotation}deg)`;\n playTicks(rotation);\n const t = now(); const dt = t - lastT;\n if (dt > 0) {\n let da = a - lastA;\n if (da > 180) da -= 360; if (da < -180) da += 360;\n vel = da / dt; lastA = a; lastT = t;\n }\n });\n const endDrag = (e: PointerEvent): void => {\n if (!dragging) return;\n dragging = false;\n wheel.style.cursor = 'grab';\n try { wheel.releasePointerCapture(e.pointerId); } catch { /* noop */ }\n const speed = Math.abs(vel); // deg/ms\n if (speed > 0.15) beginSpin(speed);\n };\n wheel.addEventListener('pointerup', endDrag);\n wheel.addEventListener('pointercancel', endDrag);\n }\n body.appendChild(result);\n body.appendChild(btn);\n card.appendChild(body);\n target.appendChild(card);\n // If the contact already won this campaign (returning visitor, or a mid-spin\n // dropout after the server granted), reveal that prize via the SAME reveal()\n // path instead of a fresh, re-rollable wheel. reveal() sets resolved=true,\n // which also neutralizes the button/drag triggers wired above.\n if (alreadyWon) {\n stopIdle();\n const wonKind = String(alreadyWon.prize_type || '').toLowerCase();\n reveal({\n label: String(alreadyWon.label || ''),\n code: String(alreadyWon.coupon_code || ''),\n won: wonKind !== 'no_prize',\n kind: wonKind,\n });\n }\n return true;\n }\n\n /** Built-in embedded QUICK POLL — option buttons submit the chosen index. */\n private renderQuickPollSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n ): boolean {\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard('aegis-in-app-poll-card', campaign.id, bg, text, st.radius);\n const opts = Array.isArray(ic.poll_options)\n ? (ic.poll_options as unknown[]).filter((o): o is string => typeof o === 'string')\n : [];\n const body = document.createElement('div');\n body.style.cssText = `padding: ${st.padY ?? 12}px ${st.padX ?? 12}px; display: flex; flex-direction: column; gap: 6px;`;\n if (campaign.title) {\n const t = document.createElement('div');\n t.style.cssText = `font-size: 13px; font-weight: ${st.weight ?? '700'};`;\n t.textContent = campaign.title;\n body.appendChild(t);\n }\n const buttons: HTMLButtonElement[] = [];\n opts.forEach((opt, i) => {\n const ob = document.createElement('button');\n // position:relative so the result fill bar can layer behind the label.\n ob.style.cssText = `position: relative; overflow: hidden; text-align: left; padding: 8px 10px; border-radius: ${st.btnRadius ?? 8}px; border: 1px solid ${text}40; background: transparent; color: ${text}; font-size: 12px; cursor: pointer; transition: border-color 0.2s ease;`;\n const lbl = document.createElement('span');\n lbl.style.cssText = 'position: relative; z-index: 1; display: flex; justify-content: space-between; gap: 8px;';\n const lblText = document.createElement('span');\n lblText.textContent = opt;\n const lblPct = document.createElement('span');\n lblPct.style.cssText = 'font-weight: 700; opacity: 0; transition: opacity 0.3s ease;';\n lbl.appendChild(lblText);\n lbl.appendChild(lblPct);\n ob.appendChild(lbl);\n ob.addEventListener('click', () => {\n void this.trackEvent(campaign.id, 'clicked');\n buttons.forEach((b) => (b.disabled = true));\n // Optimistic confirmation immediately; upgrade to real distribution\n // if the server returns one (no fabricated tallies).\n this._paintPollResult(buttons, opts, i, null, text);\n this.addAnimationStyles();\n void this.submitWidgetResponse(campaign, 'poll', { option_index: i, option_label: opt })\n .then((resp) => {\n const dist = this._readPollDistribution(resp, opts.length);\n if (dist) this._paintPollResult(buttons, opts, i, dist, text);\n });\n this._playReaction(card, 'affirm', 'check.json', ic); // poll answered → check + confetti\n });\n buttons.push(ob);\n body.appendChild(ob);\n });\n card.appendChild(body);\n target.appendChild(card);\n return true;\n }\n\n /** Pull a poll vote distribution out of the server response, if present.\n * Accepts `results`/`distribution`/`tallies` as a number[] aligned to the\n * option order. Returns null when the server didn't surface tallies (then\n * we only confirm the chosen option — never fabricate percentages). */\n private _readPollDistribution(\n resp: Record<string, unknown> | null,\n count: number,\n ): number[] | null {\n if (!resp) return null;\n const raw =\n (resp.results as unknown) ?? (resp.distribution as unknown) ?? (resp.tallies as unknown);\n if (!Array.isArray(raw) || raw.length !== count) return null;\n const nums = raw.map((v) => (typeof v === 'number' && isFinite(v) && v >= 0 ? v : 0));\n return nums.some((n) => n > 0) ? nums : null;\n }\n\n /** Animate result bars on the poll options. With a real `dist` it renders\n * each option's share; without one it just fills the selected option 100%\n * as a \"vote locked in\" confirmation. */\n private _paintPollResult(\n buttons: HTMLButtonElement[],\n _opts: string[],\n selected: number,\n dist: number[] | null,\n text: string,\n ): void {\n const total = dist ? dist.reduce((a, b) => a + b, 0) || 1 : 1;\n buttons.forEach((ob, i) => {\n const pct = dist ? Math.round((dist[i] / total) * 100) : i === selected ? 100 : 0;\n let fill = ob.querySelector<HTMLElement>('.aegis-poll-fill');\n if (!fill) {\n fill = document.createElement('span');\n fill.className = 'aegis-poll-fill';\n fill.style.cssText = `position: absolute; inset: 0 auto 0 0; z-index: 0; background: ${i === selected ? text : text + '22'}; opacity: ${i === selected ? '0.16' : '0.1'};`;\n ob.insertBefore(fill, ob.firstChild);\n }\n fill.style.setProperty('--pct', `${pct}%`);\n fill.style.animation = 'aegisPollFill 0.5s ease forwards';\n if (i === selected) ob.style.borderColor = text;\n const pctLabel = ob.querySelector<HTMLElement>('span > span:last-child');\n if (pctLabel && dist) {\n pctLabel.textContent = `${pct}%`;\n pctLabel.style.opacity = '0.8';\n } else if (pctLabel && i === selected) {\n pctLabel.textContent = '✓';\n pctLabel.style.opacity = '0.8';\n }\n });\n }\n\n /**\n * Built-in embedded IMAGE/VIDEO CAROUSEL — a swipeable horizontal strip of\n * `interactive_config.cards` (image OR video + title + body + CTA), contained\n * to the slot (the parent overflow:hidden + this strip's own scroll). Each card\n * reuses the same shape as the In-App carousel editor authors.\n */\n private renderCarouselCardsSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n ): boolean {\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard('aegis-in-app-carousel-card', campaign.id, bg, text, st.radius);\n const cards = Array.isArray(ic.cards) ? (ic.cards as Array<Record<string, unknown>>) : [];\n if (campaign.title) {\n const h = document.createElement('div');\n h.style.cssText = `padding: ${st.padY ?? 12}px ${st.padX ?? 12}px 0; font-size: 13px; font-weight: ${st.weight ?? '700'};`;\n h.textContent = campaign.title;\n card.appendChild(h);\n }\n const strip = document.createElement('div');\n strip.style.cssText = `display: flex; gap: 8px; overflow-x: auto; scroll-snap-type: x mandatory; padding: ${st.padY ?? 12}px ${st.padX ?? 12}px;`;\n cards.forEach((c, i) => {\n const tile = document.createElement('div');\n const ctaUrl = typeof c.cta_url === 'string' ? (c.cta_url as string) : '';\n tile.style.cssText = `flex: 0 0 auto; width: 150px; scroll-snap-align: start; background: ${text}0a; border-radius: 10px; overflow: hidden; display: flex; flex-direction: column; gap: 6px; cursor: ${ctaUrl ? 'pointer' : 'default'};`;\n const videoUrl = typeof c.video_url === 'string' ? (c.video_url as string) : '';\n const imageUrl = typeof c.image_url === 'string' ? (c.image_url as string) : '';\n if (videoUrl) {\n const v = document.createElement('video');\n v.src = videoUrl; v.muted = true; v.loop = true; v.autoplay = true; v.playsInline = true;\n v.setAttribute('playsinline', '');\n v.style.cssText = 'width: 100%; height: 90px; object-fit: cover; display: block;';\n tile.appendChild(v);\n } else if (imageUrl) {\n const im = document.createElement('img');\n im.src = imageUrl; im.alt = ''; im.loading = 'lazy';\n im.style.cssText = 'width: 100%; height: 90px; object-fit: cover; display: block;';\n tile.appendChild(im);\n }\n const tb = document.createElement('div');\n tb.style.cssText = 'padding: 0 8px 8px; display: flex; flex-direction: column; gap: 4px;';\n if (typeof c.title === 'string' && c.title) {\n const tt = document.createElement('div');\n tt.style.cssText = 'font-size: 12px; font-weight: 600; line-height: 1.3;';\n tt.textContent = c.title as string;\n tb.appendChild(tt);\n }\n if (typeof c.body === 'string' && c.body) {\n const tbd = document.createElement('div');\n tbd.style.cssText = 'font-size: 10.5px; opacity: 0.72; line-height: 1.3;';\n tbd.textContent = c.body as string;\n tb.appendChild(tbd);\n }\n const ctaText = typeof c.cta_text === 'string' ? (c.cta_text as string) : '';\n if (ctaText && ctaUrl) {\n const cta = document.createElement('button');\n cta.textContent = ctaText;\n cta.style.cssText = `margin-top: auto; align-self: flex-start; background: ${text}; color: ${bg}; border: none; padding: 5px 10px; border-radius: ${st.btnRadius ?? 999}px; font-size: 11px; font-weight: 600; cursor: pointer;`;\n const goto = (e: Event) => {\n e.stopPropagation();\n void this.trackEvent(campaign.id, 'clicked', { stepId: `card_${i}` });\n window.open(ctaUrl, '_blank', 'noopener');\n };\n cta.addEventListener('click', goto);\n tile.addEventListener('click', goto);\n tb.appendChild(cta);\n }\n tile.appendChild(tb);\n strip.appendChild(tile);\n });\n card.appendChild(strip);\n target.appendChild(card);\n return true;\n }\n\n /** Built-in embedded COUNTDOWN — live H:M:S digits that pulse red in the\n * final stretch (<60s) to create urgency, plus the CTA. */\n private renderCountdownSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n ): boolean {\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard('aegis-in-app-countdown-card', campaign.id, bg, text, st.radius);\n const body = document.createElement('div');\n body.style.cssText = `padding: ${st.padY ?? 12}px ${st.padX ?? 12}px; display: flex; flex-direction: column; gap: 8px; align-items: center; text-align: center;`;\n if (campaign.title) {\n const t = document.createElement('div');\n t.style.cssText = `font-size: 13px; font-weight: ${st.weight ?? '700'};`;\n t.textContent = campaign.title;\n body.appendChild(t);\n }\n const label = document.createElement('div');\n label.style.cssText = 'font-size: 11px; opacity: 0.75;';\n label.textContent = (ic.countdown_label as string) || 'Ends in';\n body.appendChild(label);\n\n const digits = document.createElement('div');\n digits.style.cssText = 'display: flex; gap: 6px; justify-content: center;';\n const mkDigit = () => {\n const el = document.createElement('span');\n el.style.cssText = `padding: 6px 9px; border-radius: 8px; font-size: 18px; font-weight: 700; font-family: ui-monospace, monospace; background: ${text}1a; transition: background 0.3s ease, color 0.3s ease;`;\n el.textContent = '00';\n return el;\n };\n const hEl = mkDigit();\n const mEl = mkDigit();\n const sEl = mkDigit();\n [hEl, ':', mEl, ':', sEl].forEach((d) => {\n if (d === ':') {\n const sep = document.createElement('span');\n sep.style.cssText = 'font-size: 18px; font-weight: 700; align-self: center;';\n sep.textContent = ':';\n digits.appendChild(sep);\n } else {\n digits.appendChild(d as HTMLElement);\n }\n });\n body.appendChild(digits);\n\n const targetStr = ic.countdown_target as string | undefined;\n // No authored target (preview) → 10-min demo so it ticks in its NORMAL state\n // (a 10s demo opened already in the final-minute \"urgent\" style).\n const deadline = targetStr ? new Date(targetStr).getTime() : Date.now() + 600_000;\n let urgent = false;\n const tick = () => {\n if (!document.body.contains(card)) return; // stop when removed\n const diff = Math.max(0, deadline - Date.now());\n const h = Math.floor(diff / 3600000);\n const m = Math.floor((diff % 3600000) / 60000);\n const s = Math.floor((diff % 60000) / 1000);\n hEl.textContent = String(h).padStart(2, '0');\n mEl.textContent = String(m).padStart(2, '0');\n sEl.textContent = String(s).padStart(2, '0');\n // Final minute → red accent RING + pulse (readable numerals kept), not a\n // solid-red fill. Once.\n if (diff > 0 && diff <= 60000 && !urgent) {\n urgent = true;\n [hEl, mEl, sEl].forEach((el) => {\n el.style.boxShadow = '0 0 0 2px #ef4444';\n el.style.animation = 'aegisUrgencyPulse 1s ease-in-out infinite';\n });\n }\n if (diff > 0) requestAnimationFrame(tick);\n else if (!expired) {\n expired = true;\n void this.submitWidgetResponse(campaign, 'countdown', { state: 'expired' });\n this._playReaction(card, 'celebrate', 'alarm-clock.json', ic); // time's up → alarm clock\n }\n };\n let expired = false;\n this.addAnimationStyles();\n tick();\n\n if (campaign.body) {\n const desc = document.createElement('div');\n desc.style.cssText = 'font-size: 11px; opacity: 0.8;';\n desc.textContent = campaign.body;\n body.appendChild(desc);\n }\n if (campaign.button_text) {\n const btn = document.createElement('button');\n btn.textContent = campaign.button_text;\n btn.style.cssText = `margin-top: 2px; background: ${text}; color: ${bg}; border: none; padding: 7px 14px; border-radius: ${st.btnRadius ?? 999}px; font-size: 12px; font-weight: 600; cursor: pointer;`;\n btn.addEventListener('click', () => {\n void this.trackEvent(campaign.id, 'clicked');\n void this.submitWidgetResponse(campaign, 'countdown', { state: 'engaged' });\n const url = (campaign as unknown as Record<string, unknown>).action_url as string | undefined;\n if (url) window.open(url, '_blank', 'noopener');\n });\n body.appendChild(btn);\n }\n card.appendChild(body);\n target.appendChild(card);\n return true;\n }\n\n /** Built-in embedded SCRATCH CARD — a canvas foil the customer scratches to\n * reveal the server-picked prize, then submits (records + grants). Confetti\n * on reveal. No AegisMessageRuntime callback dependency (works on the bill). */\n private renderScratchCardSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n ): boolean {\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard('aegis-in-app-scratch-card', campaign.id, bg, text, st.radius);\n if (!card.style.position) card.style.position = 'relative';\n\n // ── Config (all default-safe). `scratch_threshold_pct` is the canonical\n // cross-SDK field (render contract); brush/feel knobs mirror the spin wheel.\n const cfgNum = (k: string, d: number): number => (typeof ic[k] === 'number' ? (ic[k] as number) : d);\n const cfgStr = (k: string): string => (typeof ic[k] === 'string' ? (ic[k] as string) : '');\n const threshold = Math.min(1, Math.max(0.1, cfgNum('scratch_threshold_pct', 0.5)));\n const brush = Math.min(60, Math.max(8, cfgNum('scratch_brush_radius', 22)));\n const idleShimmer = ic.scratch_idle_shimmer !== false;\n const winReveal = cfgStr('scratch_win_reveal') || 'inline';\n const hapticsOn = ic.scratch_haptics_enabled !== false;\n let soundOn = ic.scratch_sound_enabled !== false;\n const revealImg = cfgStr('reveal_image_url');\n const foilImg = cfgStr('scratch_foil_image_url');\n const pool = Array.isArray(ic.prize_pool) ? (ic.prize_pool as Array<Record<string, unknown>>) : [];\n const isUrl = (s: string): boolean => /^https?:\\/\\//i.test(s);\n // Representative prize for preview/offline (no server response) — the first\n // real prize, so the reveal shows a true sample instead of a bare \"You won!\".\n const sampleWin = pool.find(\n (p) => typeof p.prize_type === 'string' && (p.prize_type as string).toLowerCase() !== 'no_prize',\n ) || null;\n\n // One-time keyframes (idle shimmer + reveal pop). Guarded by id.\n if (typeof document !== 'undefined' && !document.getElementById('aegis-scratch-kf')) {\n const kf = document.createElement('style');\n kf.id = 'aegis-scratch-kf';\n kf.textContent =\n '@keyframes aegisScratchSheen{0%{transform:translateX(-140%) skewX(-12deg)}100%{transform:translateX(260%) skewX(-12deg)}}' +\n '@keyframes aegisScratchPop{0%{opacity:0;transform:scale(0.8)}100%{opacity:1;transform:scale(1)}}' +\n '@keyframes aegisScratchDust{0%{opacity:0.9;transform:translate(0,0) scale(1)}100%{opacity:0;transform:translate(var(--dx),var(--dy)) scale(0.4)}}';\n document.head.appendChild(kf);\n }\n\n // ── Lightweight WebAudio (scratch scrape + win chime) + haptics ──\n let audioCtx: AudioContext | null = null;\n const ensureAudio = (): AudioContext | null => {\n if (!soundOn) return null;\n try {\n if (!audioCtx) {\n const Ctx = window.AudioContext\n || (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Ctx) return null;\n audioCtx = new Ctx();\n }\n if (audioCtx.state === 'suspended') void audioCtx.resume();\n return audioCtx;\n } catch { return null; }\n };\n let lastScrape = 0;\n const scrapeFx = (): void => {\n const ac = ensureAudio();\n const now = (typeof performance !== 'undefined' ? performance.now() : Date.now());\n if (ac && now - lastScrape > 45) {\n lastScrape = now;\n // Short filtered white-noise burst = a scratchy scrape.\n const dur = 0.05;\n const buf = ac.createBuffer(1, Math.floor(ac.sampleRate * dur), ac.sampleRate);\n const ch = buf.getChannelData(0);\n for (let i = 0; i < ch.length; i++) ch[i] = (Math.sin(i * 12.9898) * 43758.5453 % 1) * 2 - 1;\n const src = ac.createBufferSource(); src.buffer = buf;\n const hp = ac.createBiquadFilter(); hp.type = 'highpass'; hp.frequency.value = 2200;\n const g = ac.createGain(); g.gain.setValueAtTime(0.05, ac.currentTime);\n g.gain.exponentialRampToValueAtTime(0.0001, ac.currentTime + dur);\n src.connect(hp); hp.connect(g); g.connect(ac.destination); src.start();\n }\n if (hapticsOn) { try { (navigator as unknown as { vibrate?: (x: number | number[]) => boolean }).vibrate?.(4); } catch { /* noop */ } }\n };\n const chordFx = (freqs: number[], gain: number): void => {\n const ac = ensureAudio(); if (!ac) return;\n freqs.forEach((f, i) => window.setTimeout(() => {\n const osc = ac.createOscillator(); const g = ac.createGain();\n osc.type = 'sine'; osc.frequency.value = f;\n g.gain.setValueAtTime(gain, ac.currentTime);\n g.gain.exponentialRampToValueAtTime(0.0001, ac.currentTime + 0.22);\n osc.connect(g); g.connect(ac.destination); osc.start(); osc.stop(ac.currentTime + 0.22);\n }, i * 100));\n };\n const winFx = (): void => { chordFx([523, 659, 784, 1047], 0.07); if (hapticsOn) { try { (navigator as unknown as { vibrate?: (x: number | number[]) => boolean }).vibrate?.([0, 35, 25, 60]); } catch { /* noop */ } } };\n const loseFx = (): void => { chordFx([392, 330], 0.05); if (hapticsOn) { try { (navigator as unknown as { vibrate?: (x: number | number[]) => boolean }).vibrate?.(18); } catch { /* noop */ } } };\n\n const body = document.createElement('div');\n body.style.cssText = `padding: ${st.padY ?? 12}px ${st.padX ?? 12}px; display: flex; flex-direction: column; gap: 8px; align-items: center; text-align: center;`;\n if (campaign.title) {\n const t = document.createElement('div');\n t.style.cssText = `font-size: 13px; font-weight: ${st.weight ?? '700'};`;\n t.textContent = campaign.title;\n body.appendChild(t);\n }\n const hint = document.createElement('div');\n hint.style.cssText = 'font-size: 11px; opacity: 0.7;';\n hint.textContent = cfgStr('scratch_hint') || 'Scratch to reveal your prize';\n body.appendChild(hint);\n\n // Mute toggle (only when sound is configured on).\n if (ic.scratch_sound_enabled !== false) {\n const sb = document.createElement('button');\n sb.type = 'button'; sb.setAttribute('aria-label', 'Toggle sound');\n sb.textContent = soundOn ? '🔊' : '🔇';\n sb.style.cssText = 'position: absolute; top: 10px; left: 12px; background: transparent; border: none; font-size: 15px; cursor: pointer; opacity: 0.65; z-index: 6; line-height: 1;';\n sb.addEventListener('click', () => { soundOn = !soundOn; sb.textContent = soundOn ? '🔊' : '🔇'; });\n card.appendChild(sb);\n }\n\n // Stage holds the prize under a scratch-off foil. Ticket aspect (3:2) reads\n // as a real scratch card, suits the horizontal scratch motion, and shows\n // landscape reveal images without cropping.\n let revealed = false;\n let scratching = false;\n let moves = 0;\n const stage = document.createElement('div');\n stage.style.cssText = 'position: relative; width: 280px; max-width: 100%; aspect-ratio: 3 / 2; border-radius: 16px; overflow: hidden; box-shadow: 0 4px 14px rgba(0,0,0,0.12);';\n const prizeLayer = document.createElement('div');\n // Reveal background = operator image (cover) if set, else a soft tint. This\n // wires `reveal_image_url`, which was a declared-but-unrendered config field.\n prizeLayer.style.cssText =\n `position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; ` +\n `padding: 12px; text-align: center; font-size: 20px; font-weight: 800; color: ${text}; ` +\n (revealImg ? `background: ${text}0f center/cover no-repeat;` : `background: ${text}0f;`);\n if (revealImg) prizeLayer.style.backgroundImage = `url(\"${revealImg.replace(/\"/g, '%22')}\")`;\n const prizeText = document.createElement('div');\n // Print the prize UNDER the foil so scratching reveals it (like a real\n // scratch card), not a bare \"…\". Uses the representative prize; the reveal\n // confirms the server-picked one (a takeover card slides over on a win).\n const _sIco = sampleWin && typeof sampleWin.icon === 'string' ? (sampleWin.icon as string) : '';\n const _sLbl = sampleWin && typeof sampleWin.label === 'string' ? (sampleWin.label as string) : '';\n prizeText.textContent = _sLbl ? (_sIco && !isUrl(_sIco) ? `${_sIco} ${_sLbl}` : _sLbl) : '🎁';\n prizeLayer.appendChild(prizeText);\n stage.appendChild(prizeLayer);\n\n const canvas = document.createElement('canvas');\n canvas.width = 300;\n canvas.height = 200;\n canvas.style.cssText = 'position: absolute; inset: 0; width: 100%; height: 100%; cursor: grab; touch-action: none;';\n stage.appendChild(canvas);\n const ctx = canvas.getContext('2d');\n const CW = canvas.width, CH = canvas.height;\n\n // Foil = brushed metal + EITHER one centred brand logo (dark-tinted so a\n // light logo still reads on the light foil) OR a generated sparkle motif when\n // there's no logo — never both, with the prompt below. Coverage uses the grid\n // below (NOT getImageData), so a cross-origin logo can't taint the canvas.\n const paintFoil = (logo?: HTMLCanvasElement | null): void => {\n if (!ctx) return;\n ctx.globalCompositeOperation = 'source-over';\n const foil = ctx.createLinearGradient(0, 0, CW, CH);\n foil.addColorStop(0, '#d7dbe2'); foil.addColorStop(0.5, '#b4bac4'); foil.addColorStop(1, '#c9cdd6');\n ctx.fillStyle = foil; ctx.fillRect(0, 0, CW, CH);\n ctx.textAlign = 'center'; ctx.textBaseline = 'middle';\n if (logo) {\n ctx.globalAlpha = 0.6;\n ctx.drawImage(logo, (CW - logo.width) / 2, CH * 0.42 - logo.height / 2, logo.width, logo.height);\n ctx.globalAlpha = 1;\n ctx.fillStyle = '#6b7280'; ctx.font = '700 12px system-ui, sans-serif';\n ctx.fillText('SCRATCH HERE', CW / 2, CH * 0.84);\n } else {\n ctx.fillStyle = 'rgba(108,116,128,0.18)'; ctx.font = '12px system-ui, sans-serif';\n for (let gy = 18; gy < CH; gy += 30) {\n const off = (((gy / 30) | 0) % 2) ? 16 : 0;\n for (let gx = 16 + off; gx < CW; gx += 32) ctx.fillText('✦', gx, gy);\n }\n ctx.fillStyle = '#7c828e'; ctx.font = '700 13px system-ui, sans-serif';\n ctx.fillText('SCRATCH HERE', CW / 2, CH / 2);\n }\n ctx.globalCompositeOperation = 'destination-out';\n };\n if (ctx) {\n paintFoil(null);\n if (foilImg) {\n const im = new Image(); im.crossOrigin = 'anonymous';\n im.onload = (): void => {\n if (revealed || !ctx) return;\n // Fit the logo to ~52%×40% of the foil, then RECOLOUR its pixels to a\n // dark grey silhouette (source-in) so a light logo is still visible —\n // grayscale alone left a pale logo invisible on the pale foil.\n const maxW = CW * 0.52, maxH = CH * 0.42;\n const ar = im.width / im.height || 1;\n let lw = maxW, lh = maxW / ar;\n if (lh > maxH) { lh = maxH; lw = maxH * ar; }\n const lc = document.createElement('canvas');\n lc.width = Math.max(1, Math.round(lw)); lc.height = Math.max(1, Math.round(lh));\n const lctx = lc.getContext('2d');\n if (!lctx) return;\n lctx.drawImage(im, 0, 0, lc.width, lc.height);\n lctx.globalCompositeOperation = 'source-in';\n lctx.fillStyle = '#5b626e';\n lctx.fillRect(0, 0, lc.width, lc.height);\n paintFoil(lc);\n };\n im.onerror = (): void => { /* keep the generated foil */ };\n im.src = foilImg;\n }\n }\n\n // Coverage tracker — grid cells flip as the brush passes (taint-free + cheap,\n // replaces a per-move full-canvas getImageData) → auto-reveal past threshold.\n const GX = 30, GY = 20, TOTAL = GX * GY;\n const cells = new Uint8Array(TOTAL);\n let clearedCells = 0;\n const markCleared = (x: number, y: number): void => {\n const cw = CW / GX, ch = CH / GY, r = brush;\n const x0 = Math.max(0, Math.floor((x - r) / cw)), x1 = Math.min(GX - 1, Math.floor((x + r) / cw));\n const y0 = Math.max(0, Math.floor((y - r) / ch)), y1 = Math.min(GY - 1, Math.floor((y + r) / ch));\n for (let cy = y0; cy <= y1; cy++) for (let cx = x0; cx <= x1; cx++) {\n const idx = cy * GX + cx; if (cells[idx]) continue;\n const dx = (cx + 0.5) * cw - x, dy = (cy + 0.5) * ch - y;\n if (dx * dx + dy * dy <= r * r) { cells[idx] = 1; clearedCells++; }\n }\n };\n\n // Idle shimmer sweep over the foil to invite the first scratch (removed once\n // the customer starts).\n let shimmer: HTMLElement | null = null;\n if (idleShimmer) {\n const clip = document.createElement('div');\n clip.style.cssText = 'position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 2;';\n const bar = document.createElement('div');\n bar.style.cssText = 'position: absolute; top: -20%; left: 0; width: 34%; height: 140%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.55), transparent); animation: aegisScratchSheen 2.6s ease-in-out infinite; animation-delay: 0.4s;';\n clip.appendChild(bar);\n shimmer = clip;\n stage.appendChild(clip);\n }\n // Dust layer for scratch flecks.\n const dust = document.createElement('div');\n dust.style.cssText = 'position: absolute; inset: 0; pointer-events: none; z-index: 3;';\n stage.appendChild(dust);\n\n const spawnDust = (cx: number, cy: number): void => {\n const px = (cx / canvas.width) * 100;\n const py = (cy / canvas.height) * 100;\n for (let i = 0; i < 2; i++) {\n const d = document.createElement('div');\n const dx = (((i * 53 + moves * 17) % 30) - 15);\n const dy = (8 + ((moves * 13) % 14));\n d.style.cssText = `position: absolute; left: ${px}%; top: ${py}%; width: 3px; height: 3px; border-radius: 50%; background: #b4bac4; --dx:${dx}px; --dy:${dy}px; animation: aegisScratchDust 0.5s ease-out forwards;`;\n dust.appendChild(d);\n window.setTimeout(() => d.remove(), 520);\n }\n };\n\n const wonConfigFor = (resp: Record<string, unknown> | null): Record<string, unknown> | null => {\n const prize = (resp && (resp.prize as Record<string, unknown> | undefined)) || null;\n const idx = prize && typeof prize.segment_index === 'number' ? (prize.segment_index as number) : -1;\n if (idx >= 0 && pool[idx]) return pool[idx];\n const label = this._extractPrizeLabel(resp);\n return pool.find((p) => p.label === label) || sampleWin || null;\n };\n\n // ONE visible celebration per reveal: the takeover card rains its own confetti;\n // the inline reveal plays the gift. (Previously a gift fired on `body` AND the\n // takeover covered it — a hidden/duplicate animation.)\n const showWin = (label: string, code: string, icoVal: string): void => {\n if (winReveal === 'takeover') {\n const ov = document.createElement('div');\n ov.style.cssText = `position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 22px; text-align: center; background: ${bg}; color: ${text}; border-radius: inherit; animation: aegisScratchPop 0.4s cubic-bezier(0.16,0.86,0.28,1); z-index: 7;`;\n if (icoVal) {\n const ic2 = document.createElement(isUrl(icoVal) ? 'img' : 'div');\n if (isUrl(icoVal)) { (ic2 as HTMLImageElement).src = icoVal; ic2.style.cssText = 'width: 42px; height: 42px; object-fit: contain;'; }\n else { ic2.textContent = icoVal; ic2.style.cssText = 'font-size: 36px; line-height: 1;'; }\n ov.appendChild(ic2);\n }\n const eb = document.createElement('div'); eb.textContent = 'You won'; eb.style.cssText = 'font-size: 12px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; opacity: 0.7;';\n const big = document.createElement('div'); big.textContent = label; big.style.cssText = `font-size: 22px; font-weight: 900; letter-spacing: -0.02em; font-family: 'Inter Tight', Inter, system-ui, sans-serif;`;\n ov.appendChild(eb); ov.appendChild(big);\n if (code) {\n const chip = document.createElement('button'); chip.type = 'button'; chip.textContent = `${code} ⧉`;\n chip.style.cssText = `margin-top: 4px; padding: 8px 14px; border-radius: 999px; border: 1.5px dashed ${text}66; background: transparent; color: ${text}; font-weight: 800; font-size: 13px; letter-spacing: 1px; cursor: pointer;`;\n chip.addEventListener('click', () => { try { void navigator.clipboard?.writeText(code); chip.textContent = 'Copied ✓'; } catch { /* noop */ } });\n ov.appendChild(chip);\n }\n card.appendChild(ov);\n try { this._fireConfetti(ov); } catch { /* noop */ }\n } else {\n prizeText.textContent = (icoVal && !isUrl(icoVal)) ? `${icoVal} ${label}` : label;\n if (code) {\n const chip = document.createElement('div');\n chip.style.cssText = `margin-top: 6px; font-family: ui-monospace, monospace; font-size: 12px; font-weight: 700; padding: 4px 8px; border-radius: 6px; background: ${text}14; color: ${text};`;\n chip.textContent = code;\n body.appendChild(chip);\n }\n this._playReaction(body, 'celebrate', 'gift.json', ic);\n }\n };\n\n const reveal = (): void => {\n if (revealed) return;\n revealed = true;\n try { shimmer?.remove(); } catch { /* noop */ }\n canvas.style.transition = 'opacity 0.4s ease';\n canvas.style.opacity = '0';\n this.addAnimationStyles();\n void this.trackEvent(campaign.id, 'clicked');\n void this.submitWidgetResponse(campaign, 'scratch', { state: 'revealed' }).then((resp) => {\n const won = resp && (resp.won === true || (resp.reward as Record<string, unknown> | undefined)?.granted === true);\n const sampleLabel = sampleWin && typeof sampleWin.label === 'string' ? (sampleWin.label as string) : '';\n const label = this._extractPrizeLabel(resp) || sampleLabel || (ic.scratch_prize_label as string) || 'You won!';\n const code = this._extractCouponCode(resp) || '';\n const wonCfg = wonConfigFor(resp);\n const icoVal = wonCfg && typeof wonCfg.icon === 'string' ? (wonCfg.icon as string) : '';\n const kind = wonCfg && typeof wonCfg.prize_type === 'string' ? (wonCfg.prize_type as string).toLowerCase() : '';\n if (won === false) {\n loseFx();\n prizeText.textContent = 'Better luck next time';\n this._playReaction(body, 'empathize', undefined, ic);\n } else {\n winFx();\n showWin(label, code, icoVal); // owns the single celebration (confetti or gift)\n // Freebie honesty — recorded for manual fulfilment, not auto-redeemed.\n if (!code && kind === 'freebie' && winReveal !== 'takeover') {\n const h = document.createElement('div');\n h.textContent = '🎟️ Show this screen to claim';\n h.style.cssText = 'margin-top: 4px; font-size: 12px; font-weight: 600; opacity: 0.85;';\n body.appendChild(h);\n }\n }\n });\n };\n\n const scratchAt = (x: number, y: number): void => {\n if (revealed) return;\n if (!ctx) return reveal();\n moves += 1;\n ctx.beginPath();\n ctx.arc(x, y, brush, 0, Math.PI * 2);\n ctx.fill();\n markCleared(x, y);\n if (moves % 2 === 0) { scrapeFx(); spawnDust(x, y); }\n if (clearedCells / TOTAL > threshold) reveal();\n };\n const pos = (e: PointerEvent): { x: number; y: number } => {\n const r = canvas.getBoundingClientRect();\n return { x: ((e.clientX - r.left) / r.width) * canvas.width, y: ((e.clientY - r.top) / r.height) * canvas.height };\n };\n canvas.addEventListener('pointerdown', (e: PointerEvent) => { if (revealed) return; scratching = true; try { canvas.setPointerCapture(e.pointerId); } catch { /* noop */ } const p = pos(e); scratchAt(p.x, p.y); });\n canvas.addEventListener('pointermove', (e: PointerEvent) => { if (!scratching) return; const p = pos(e); scratchAt(p.x, p.y); });\n const stop = (): void => { scratching = false; };\n canvas.addEventListener('pointerup', stop);\n canvas.addEventListener('pointercancel', stop);\n canvas.addEventListener('pointerleave', stop);\n\n body.appendChild(stage);\n card.appendChild(body);\n target.appendChild(card);\n return true;\n }\n\n /** Extract a human prize label from a spin/scratch server response. */\n private _extractPrizeLabel(resp: Record<string, unknown> | null): string | null {\n if (!resp) return null;\n const reward = resp.reward as Record<string, unknown> | undefined;\n const cands = [\n resp.prize_label, resp.label, reward?.label,\n (resp.prize as Record<string, unknown> | undefined)?.prize_label,\n ];\n for (const c of cands) if (typeof c === 'string' && c) return c;\n return null;\n }\n\n /** Extract a redeemable coupon code from a spin/scratch server response. */\n private _extractCouponCode(resp: Record<string, unknown> | null): string | null {\n if (!resp) return null;\n const reward = resp.reward as Record<string, unknown> | undefined;\n const cands = [resp.coupon_code, reward?.coupon_code];\n for (const c of cands) if (typeof c === 'string' && c) return c;\n return null;\n }\n\n /**\n * Token-bound submission helper. POSTs the structured response to\n * the per-token submit URL the page handler embedded. Best-effort\n * — failure is logged but doesn't throw (the customer already\n * clicked; we can't undo their interaction).\n */\n private _submitTokenResponse(\n submitUrl: string,\n payload: Record<string, unknown>,\n ): void {\n if (!submitUrl) return;\n // Fire-and-forget; we don't gate the UI on the response.\n fetch(submitUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ response: payload }),\n keepalive: true,\n }).catch((err) => {\n this.log(`token submit failed: ${err}`, 'warn');\n });\n }\n\n // --- Shared body builders (used by both overlay + slot paths) ----------\n //\n // Sizing: `'overlay'` matches the legacy fullscreen-modal scale (24px\n // padding, 18px title, 32px stars). `'slot'` is the embedded card\n // scale (20px padding, 16px title, 28px stars) — proportional, doesn't\n // dwarf merchant page chrome. Adding a new variant means a new tuple\n // here, not a new renderer.\n\n /**\n * Slot styling — the operator's look-&-feel knobs (Style panel) applied to the\n * EMBEDDED render, CLAMPED to boundary-safe ranges so an authored value can\n * never break out of the dynamic block. Unauthored knobs are `undefined` so\n * each renderer keeps its own compact default (no visual regression). Colors\n * default to the current slot defaults. The slot card keeps `width:100%;\n * overflow:hidden` regardless, so the boundary guarantee is independent of\n * these values.\n */\n private _slotStyle(campaign: InAppCampaign): {\n bg: string; text: string; radius: number;\n padX?: number; padY?: number; btnRadius?: number; weight?: string;\n } {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const clampOpt = (v: unknown, lo: number, hi: number): number | undefined => {\n if (v === undefined || v === null || v === '') return undefined;\n const n = Number(v);\n if (!Number.isFinite(n)) return undefined;\n return Math.max(lo, Math.min(hi, n));\n };\n const wRaw = ic.heading_font_weight != null ? String(ic.heading_font_weight) : '';\n const pal = this._surfacePalette(campaign);\n return {\n bg: pal.bg,\n text: pal.text,\n radius: clampOpt(ic.border_radius, 0, 24) ?? 12,\n padX: clampOpt(ic.padding_x, 0, 32),\n padY: clampOpt(ic.padding_y, 0, 24),\n btnRadius: clampOpt(ic.button_radius, 0, 999),\n weight: ['400', '500', '600', '700'].includes(wRaw) ? wRaw : undefined,\n };\n }\n\n private _wrapInSlotCard(\n className: string,\n campaignId: string,\n bg: string,\n text: string,\n radius = 12,\n ): HTMLElement {\n const card = document.createElement('div');\n card.className = className;\n card.setAttribute('data-campaign-id', campaignId);\n // width:100% + overflow:hidden = the boundary guarantee; the authored radius\n // is clamped (0–24) by `_slotStyle` so it can't distort the slot.\n card.style.cssText = `\n width: 100%; border-radius: ${radius}px; overflow: hidden;\n background: ${bg}; color: ${text};\n box-shadow: 0 4px 12px rgba(0,0,0,0.06);\n `;\n return card;\n }\n\n // Optional header/brand image atop a survey-style widget (star / nps).\n private _appendHeaderImage(body: HTMLElement, ic: Record<string, unknown>): void {\n const url = ic.header_image_url as string | undefined;\n if (!url) return;\n const safe = this.sanitizeUrl(url);\n if (!safe) return;\n const img = document.createElement('img');\n img.src = safe;\n img.alt = '';\n img.style.cssText = 'display: block; max-height: 72px; max-width: 60%; margin: 0 auto 14px; object-fit: contain;';\n body.appendChild(img);\n }\n\n private _buildStarRatingBody(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n text: string,\n variant: 'overlay' | 'slot',\n submitUrl?: string,\n slotStyle?: { padX?: number; padY?: number; weight?: string },\n ): HTMLElement {\n const isOverlay = variant === 'overlay';\n // Slot mode honors the authored padding (clamped) when set, else the compact default.\n const padding = isOverlay ? '24px' : `${slotStyle?.padY ?? 20}px ${slotStyle?.padX ?? 20}px`;\n const titleSize = isOverlay ? '18px' : '16px';\n const titleWeight = isOverlay ? '700' : (slotStyle?.weight ?? '600');\n const titleMargin = isOverlay ? '16px' : '12px';\n const starSize = isOverlay ? '32px' : '28px';\n const starsMarginBottom = isOverlay ? '16px' : '0';\n const hoverScale = isOverlay ? '1.2' : '1.15';\n\n const body = document.createElement('div');\n body.style.cssText = `padding: ${padding}; text-align: center;`;\n this._appendHeaderImage(body, ic);\n\n const title = document.createElement('div');\n title.style.cssText =\n `font-size: ${titleSize}; font-weight: ${titleWeight}; margin-bottom: ${titleMargin};`;\n title.textContent = campaign.title || 'Rate your experience';\n body.appendChild(title);\n\n const stars = document.createElement('div');\n stars.style.cssText =\n `display: flex; gap: 8px; justify-content: center;` +\n (starsMarginBottom !== '0' ? ` margin-bottom: ${starsMarginBottom};` : '');\n const maxStars = (ic.rating_scale as number) || 5;\n const GOLD = '#fbbf24';\n // Icon set — classic stars, hearts, or a 1..n emoji-face gradient.\n const iconSet = (ic.rating_icon as string) || 'star';\n const EMOJI = ['😞', '🙁', '😐', '🙂', '😀', '🤩'];\n const emojiFor = (idx: number): string => {\n // Map this position onto the 6-face gradient regardless of scale length.\n const k = maxStars <= 1 ? EMOJI.length - 1 : Math.round((idx / (maxStars - 1)) * (EMOJI.length - 1));\n return EMOJI[Math.max(0, Math.min(EMOJI.length - 1, k))];\n };\n const glyph = (on: boolean, idx: number): string =>\n iconSet === 'emoji' ? emojiFor(idx) : iconSet === 'heart' ? (on ? '♥' : '♡') : (on ? '★' : '☆');\n const labels = Array.isArray(ic.rating_labels) ? (ic.rating_labels as string[]) : null;\n // Caption under the row reflecting the hovered/selected label (declared\n // before paint() which updates it; appended below the stars).\n let caption: HTMLDivElement | null = null;\n if (labels && labels.length > 0) {\n caption = document.createElement('div');\n caption.style.cssText = `font-size: 12px; opacity: 0.7; margin-top: 8px; min-height: 16px; color: ${text || 'inherit'};`;\n }\n const starEls: HTMLSpanElement[] = [];\n let selected = 0;\n // Fill 1..n active, the rest empty — the cascade-on-hover that makes a\n // rating widget feel alive. Emoji mode tints by selection (full opacity to n).\n const paint = (n: number) => {\n starEls.forEach((el, idx) => {\n const on = idx < n;\n el.textContent = glyph(on, idx);\n if (iconSet === 'emoji') {\n el.style.opacity = on || n === 0 ? '1' : '0.3';\n el.style.color = 'inherit';\n } else {\n el.style.color = on ? GOLD : text || 'inherit';\n }\n el.style.transform = on && idx === n - 1 ? `scale(${hoverScale})` : 'scale(1)';\n });\n if (caption && labels) {\n const lbl = n > 0 ? labels[Math.min(n - 1, labels.length - 1)] : '';\n caption.textContent = lbl || '';\n }\n };\n for (let i = 1; i <= maxStars; i++) {\n const star = document.createElement('span');\n star.style.cssText =\n `font-size: ${starSize}; cursor: pointer; transition: transform 0.12s, color 0.12s, opacity 0.12s; user-select: none;` +\n (iconSet !== 'emoji' && text ? ` color: ${text};` : '') +\n (iconSet === 'emoji' ? ' opacity: 0.3;' : '');\n star.setAttribute('role', 'button');\n star.setAttribute('aria-label', `${i} ${iconSet === 'heart' ? 'heart' : 'star'}${i > 1 ? 's' : ''}`);\n star.textContent = glyph(false, i - 1);\n const value = i;\n star.addEventListener('mouseenter', () => paint(value));\n star.addEventListener('mouseleave', () => paint(selected));\n star.addEventListener('click', () => {\n selected = value;\n paint(selected);\n star.style.transform = 'scale(1.28)';\n setTimeout(() => paint(selected), 160);\n this.trackEvent(campaign.id, 'clicked');\n this._onStarRatingPicked(campaign, ic, body, value, maxStars, text, isOverlay, submitUrl);\n });\n starEls.push(star);\n stars.appendChild(star);\n }\n body.appendChild(stars);\n if (caption) body.appendChild(caption);\n return body;\n }\n\n /**\n * Post-rating flow — the Reelo/Plotline \"smart rating\" gate. A happy rater\n * (>= threshold) is invited to leave a PUBLIC review; an unhappy one is given\n * a PRIVATE \"what went wrong?\" comment box so the complaint is captured for\n * the operator instead of landing on a public platform. Exactly ONE response\n * row is written per rating (deferred on the low path until Send/Skip) so the\n * star distribution isn't double-counted.\n */\n private _onStarRatingPicked(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n body: HTMLElement,\n value: number,\n maxStars: number,\n text: string,\n isOverlay: boolean,\n submitUrl?: string,\n ): void {\n // Bill-token slot keeps its existing token submit (unchanged path).\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, { sub_type: 'star_rating', value });\n }\n\n const followupEnabled = isOverlay && ic.rating_followup_enabled !== false;\n const threshold = (ic.rating_followup_threshold as number) || Math.ceil(maxStars * 0.8);\n const isHigh = value >= threshold;\n\n // Slot (embedded bill) keeps the lightweight emotional reaction, no takeover.\n if (!isOverlay) {\n if (isHigh) this._playReaction(body, 'affirm', undefined, ic);\n else if (value <= Math.max(1, Math.floor(maxStars * 0.4))) this._playReaction(body, 'empathize', undefined, ic);\n else this._playReaction(body, 'acknowledge', undefined, ic);\n return;\n }\n\n // Overlay ALWAYS records the rating server-side (the prior bug: it never did).\n if (!followupEnabled) {\n void this.submitWidgetResponse(campaign, 'rating', { stars: value });\n this._renderRatingThankYou(campaign, ic, body, isHigh);\n return;\n }\n\n if (isHigh) {\n void this.submitWidgetResponse(campaign, 'rating', { stars: value });\n this._renderRatingThankYou(campaign, ic, body, true);\n } else {\n this._renderRatingLowFollowup(campaign, ic, body, value, text);\n }\n }\n\n /** Thank-you takeover; happy raters also get a public-review CTA when authored. */\n private _renderRatingThankYou(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n body: HTMLElement,\n isHigh: boolean,\n ): void {\n while (body.firstChild) body.removeChild(body.firstChild);\n // The thank-you copy is short, so the modal collapses to a few rows — which\n // CLIPS the centered ~150px reaction (Lottie/SVG) under the modal's\n // overflow:hidden. Reserve vertical room and let the modal overflow so the\n // badge (and its float-out) can render in full.\n const modalEl = body.parentElement as HTMLElement | null;\n if (modalEl) modalEl.style.overflow = 'visible';\n body.style.position = 'relative';\n body.style.minHeight = '176px';\n body.style.display = 'flex';\n body.style.flexDirection = 'column';\n body.style.alignItems = 'center';\n body.style.justifyContent = 'center';\n const heading = document.createElement('div');\n heading.style.cssText = 'font-size: 16px; font-weight: 700; margin-bottom: 8px;';\n heading.textContent = isHigh\n ? ((ic.rating_high_prompt as string) || 'Thanks — glad you loved it!')\n : ((ic.thank_you_message as string) || 'Thanks for your feedback!');\n body.appendChild(heading);\n\n const reviewUrl = ic.rating_review_url as string | undefined;\n if (isHigh && reviewUrl) {\n const sub = document.createElement('div');\n sub.style.cssText = 'font-size: 13px; opacity: 0.8; margin-bottom: 14px;';\n sub.textContent = 'Would you share that with others?';\n body.appendChild(sub);\n const st = this.inAppStyle(campaign);\n const cta = document.createElement('button');\n cta.type = 'button';\n cta.textContent = campaign.button_text || 'Leave a review';\n cta.style.cssText = `padding: 10px 24px; border-radius: 999px; border: none; background: ${st.btnBg}; color: ${st.btnText}; font-weight: 800; font-size: 13.5px; cursor: pointer;`;\n cta.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked', { meta: { action: 'review_redirect' } });\n const safe = this.sanitizeUrl(reviewUrl);\n if (safe) this.navigateToCampaignAction(campaign, safe);\n });\n body.appendChild(cta);\n } else {\n this._playReaction(body, isHigh ? 'affirm' : 'acknowledge', undefined, ic);\n }\n }\n\n /** Unhappy-path private comment capture; submits {stars, comment} once. */\n private _renderRatingLowFollowup(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n body: HTMLElement,\n value: number,\n text: string,\n ): void {\n this.addAnimationStyles(); // ensure the ::placeholder rule is present\n while (body.firstChild) body.removeChild(body.firstChild);\n const heading = document.createElement('div');\n heading.style.cssText = 'font-size: 15px; font-weight: 700; margin-bottom: 10px;';\n heading.textContent = (ic.rating_low_prompt as string) || 'Sorry to hear that. What went wrong?';\n body.appendChild(heading);\n\n const ta = document.createElement('textarea');\n ta.className = 'aegis-rating-comment';\n ta.rows = 3;\n ta.placeholder = 'Tell us how we can do better…';\n ta.style.cssText = `width: 100%; box-sizing: border-box; padding: 10px; border-radius: 10px; border: 1px solid ${text}33; background: transparent; color: ${text || 'inherit'}; font-size: 13px; resize: vertical; margin-bottom: 12px; font-family: inherit;`;\n body.appendChild(ta);\n\n const st = this.inAppStyle(campaign);\n const row = document.createElement('div');\n row.style.cssText = 'display: flex; gap: 8px; justify-content: center;';\n let done = false;\n const finish = (withComment: boolean) => {\n if (done) return;\n done = true;\n const comment = withComment ? ta.value.trim() : '';\n void this.submitWidgetResponse(campaign, 'rating', comment ? { stars: value, comment } : { stars: value });\n this._renderRatingThankYou(campaign, ic, body, false);\n };\n const send = document.createElement('button');\n send.type = 'button';\n send.textContent = 'Send feedback';\n send.style.cssText = `padding: 9px 20px; border-radius: 999px; border: none; background: ${st.btnBg}; color: ${st.btnText}; font-weight: 800; font-size: 13px; cursor: pointer;`;\n send.addEventListener('click', () => finish(true));\n const skip = document.createElement('button');\n skip.type = 'button';\n skip.textContent = 'Skip';\n skip.style.cssText = `padding: 9px 16px; border-radius: 999px; border: 1px solid ${text}33; background: transparent; color: ${text || 'inherit'}; font-weight: 600; font-size: 13px; cursor: pointer;`;\n skip.addEventListener('click', () => finish(false));\n row.appendChild(send);\n row.appendChild(skip);\n body.appendChild(row);\n ta.focus();\n }\n\n private _buildNPSSurveyBody(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n text: string,\n variant: 'overlay' | 'slot',\n submitUrl?: string,\n slotStyle?: { padX?: number; padY?: number; weight?: string },\n ): HTMLElement {\n const isOverlay = variant === 'overlay';\n const padding = isOverlay ? '24px' : `${slotStyle?.padY ?? 20}px ${slotStyle?.padX ?? 20}px`;\n const titleAlign = isOverlay ? 'center' : 'center';\n\n const body = document.createElement('div');\n body.style.cssText = `padding: ${padding};` +\n (isOverlay ? ' text-align: center;' : '');\n this._appendHeaderImage(body, ic);\n\n const title = document.createElement('div');\n title.style.cssText =\n `font-size: 16px; font-weight: ${isOverlay ? '700' : (slotStyle?.weight ?? '600')}; ` +\n `margin-bottom: ${isOverlay ? '16px' : '12px'}; text-align: ${titleAlign};`;\n title.textContent =\n (ic.nps_question as string) || campaign.title ||\n 'How likely are you to recommend us?';\n body.appendChild(title);\n\n // Color-grade the scale: detractor 0–6 red, passive 7–8 amber, promoter\n // 9–10 green — instantly legible, the CleverTap/standard NPS palette.\n // Shared by BOTH variants so the overlay modal is as interactive + polished\n // as the embedded slot (previously the overlay was flat + did nothing on tap).\n const npsColor = (n: number): string =>\n n <= 6 ? '#ef4444' : n <= 8 ? '#f59e0b' : '#10b981';\n\n // The interactive scale — round pips (overlay) or a bordered grid (slot).\n const scale = document.createElement('div');\n scale.style.cssText = isOverlay\n ? 'display: flex; gap: 4px; justify-content: center; flex-wrap: wrap; margin-bottom: 12px;'\n : 'display: grid; grid-template-columns: repeat(11, 1fr); gap: 4px;';\n\n const onPick = (value: number) => {\n this.trackEvent(campaign.id, 'clicked');\n // Bill-token slot keeps its existing immediate token submit (unchanged).\n if (submitUrl) {\n this._submitTokenResponse(submitUrl, { sub_type: 'nps_survey', value });\n }\n\n // Overlay + follow-up enabled → reason-capture step (wires the per-band\n // nps_follow_up_* prompts that were authored-but-dead). Submit is DEFERRED\n // to that step so exactly ONE response row is written (with the reason).\n const followupEnabled = isOverlay && (ic.nps_followup_enabled as boolean | undefined) !== false;\n if (followupEnabled) {\n this._renderNpsReasonFollowup(campaign, ic, body, value, text);\n return;\n }\n\n // Slot, or overlay with follow-up off: submit now + inline thank-you.\n void this.submitWidgetResponse(campaign, 'nps', { score: value });\n this.addAnimationStyles();\n const thanks = document.createElement('div');\n thanks.style.cssText =\n `font-size: 14px; font-weight: 600; padding: 8px 0; text-align: center; color: ${text};`;\n thanks.textContent = value >= 9\n ? 'Thanks! We are glad you love it.'\n : (value <= 6\n ? 'Thanks for the honest feedback — we will do better.'\n : 'Thank you for your feedback!');\n scale.replaceWith(thanks);\n labels?.remove();\n // Emotional reaction: promoters celebrate, detractors get an empathetic\n // (non-celebratory) response, passives a soft positive.\n if (value >= 9) this._playReaction(body, 'affirm', undefined, ic);\n else if (value <= 6) this._playReaction(body, 'empathize', undefined, ic);\n else this._playReaction(body, 'acknowledge', undefined, ic);\n };\n\n for (let n = 0; n <= 10; n++) {\n const col = npsColor(n);\n const value = n;\n if (isOverlay) {\n const btn = document.createElement('span');\n btn.style.cssText = `\n width: 28px; height: 28px; border-radius: 6px; display: flex;\n align-items: center; justify-content: center; font-size: 12px;\n font-weight: 700; cursor: pointer; background: ${col}; color: #fff;\n opacity: 0.85; transition: transform 0.1s, opacity 0.15s;\n `;\n btn.textContent = String(n);\n btn.addEventListener('mouseenter', () => { btn.style.opacity = '1'; btn.style.transform = 'translateY(-1px)'; });\n btn.addEventListener('mouseleave', () => { btn.style.opacity = '0.85'; btn.style.transform = 'translateY(0)'; });\n btn.addEventListener('click', () => onPick(value));\n scale.appendChild(btn);\n } else {\n const btn = document.createElement('button');\n btn.style.cssText = `\n padding: 8px 0; border-radius: 6px; border: 1px solid ${col}88;\n background: ${col}14; color: ${col}; font-size: 13px; font-weight: 700;\n cursor: pointer; transition: transform 0.12s, background 0.15s;\n `;\n btn.textContent = String(n);\n btn.addEventListener('mouseenter', () => {\n btn.style.background = col; btn.style.color = '#fff'; btn.style.transform = 'translateY(-1px)';\n });\n btn.addEventListener('mouseleave', () => {\n btn.style.background = `${col}14`; btn.style.color = col; btn.style.transform = 'translateY(0)';\n });\n btn.addEventListener('click', () => onPick(value));\n scale.appendChild(btn);\n }\n }\n body.appendChild(scale);\n\n // Not/Very labels under the overlay scale.\n let labels: HTMLElement | null = null;\n if (isOverlay) {\n labels = document.createElement('div');\n labels.style.cssText =\n 'display: flex; justify-content: space-between; font-size: 11px; opacity: 0.6; margin-bottom: 16px;';\n const notLikely = document.createElement('span');\n notLikely.textContent = 'Not likely';\n const veryLikely = document.createElement('span');\n veryLikely.textContent = 'Very likely';\n labels.appendChild(notLikely);\n labels.appendChild(veryLikely);\n body.appendChild(labels);\n }\n return body;\n }\n\n /**\n * NPS reason-capture step (overlay). Wires the per-band `nps_follow_up_*`\n * prompt (promoter / passive / detractor) as the heading and captures an\n * open-text reason (+ optional quick-pick chips). Submits {score, comment}\n * exactly ONCE (deferred from the pick), then shows the thank-you (promoters\n * get an optional review/referral CTA).\n */\n private _renderNpsReasonFollowup(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n body: HTMLElement,\n value: number,\n text: string,\n ): void {\n this.addAnimationStyles();\n const promoterThreshold = (ic.nps_promoter_threshold as number) || 9;\n const prompt = value >= promoterThreshold\n ? ((ic.nps_follow_up_promoter as string) || 'What do you love most about us?')\n : value <= 6\n ? ((ic.nps_follow_up_detractor as string) || 'How can we improve?')\n : ((ic.nps_follow_up_passive as string) || 'What would make us a 10?');\n\n while (body.firstChild) body.removeChild(body.firstChild);\n const heading = document.createElement('div');\n heading.style.cssText = 'font-size: 15px; font-weight: 700; margin-bottom: 10px; text-align: center;';\n heading.textContent = prompt;\n body.appendChild(heading);\n\n // Optional quick-pick chips that fill the textarea.\n const ta = document.createElement('textarea');\n const chips = Array.isArray(ic.nps_reason_chips) ? (ic.nps_reason_chips as string[]) : [];\n if (chips.length) {\n const chipRow = document.createElement('div');\n chipRow.style.cssText = 'display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-bottom: 10px;';\n chips.slice(0, 8).forEach((c) => {\n const chip = document.createElement('button');\n chip.type = 'button';\n chip.textContent = c;\n chip.style.cssText = `padding: 5px 11px; border-radius: 999px; border: 1px solid ${text}33; background: transparent; color: ${text || 'inherit'}; font-size: 12px; cursor: pointer;`;\n chip.addEventListener('click', () => { ta.value = ta.value ? `${ta.value}, ${c}` : c; ta.focus(); });\n chipRow.appendChild(chip);\n });\n body.appendChild(chipRow);\n }\n\n ta.className = 'aegis-rating-comment';\n ta.rows = 3;\n ta.placeholder = 'Share a little more…';\n ta.style.cssText = `width: 100%; box-sizing: border-box; padding: 10px; border-radius: 10px; border: 1px solid ${text}33; background: transparent; color: ${text || 'inherit'}; font-size: 13px; resize: vertical; margin-bottom: 12px; font-family: inherit;`;\n body.appendChild(ta);\n\n const st = this.inAppStyle(campaign);\n const row = document.createElement('div');\n row.style.cssText = 'display: flex; gap: 8px; justify-content: center;';\n let done = false;\n const finish = (withComment: boolean) => {\n if (done) return;\n done = true;\n const comment = withComment ? ta.value.trim() : '';\n void this.submitWidgetResponse(campaign, 'nps', comment ? { score: value, comment } : { score: value });\n this._renderNpsThankYou(campaign, ic, body, value >= promoterThreshold);\n };\n const send = document.createElement('button');\n send.type = 'button';\n send.textContent = 'Send';\n send.style.cssText = `padding: 9px 20px; border-radius: 999px; border: none; background: ${st.btnBg}; color: ${st.btnText}; font-weight: 800; font-size: 13px; cursor: pointer;`;\n send.addEventListener('click', () => finish(true));\n const skip = document.createElement('button');\n skip.type = 'button';\n skip.textContent = 'Skip';\n skip.style.cssText = `padding: 9px 16px; border-radius: 999px; border: 1px solid ${text}33; background: transparent; color: ${text || 'inherit'}; font-weight: 600; font-size: 13px; cursor: pointer;`;\n skip.addEventListener('click', () => finish(false));\n row.appendChild(send);\n row.appendChild(skip);\n body.appendChild(row);\n ta.focus();\n }\n\n /** NPS thank-you takeover; promoters get an optional review/referral CTA. */\n private _renderNpsThankYou(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n body: HTMLElement,\n isPromoter: boolean,\n ): void {\n while (body.firstChild) body.removeChild(body.firstChild);\n // Anti-clip (same as the star thank-you): a short body would otherwise clip\n // the centered reaction under the modal's overflow:hidden.\n const modalEl = body.parentElement as HTMLElement | null;\n if (modalEl) modalEl.style.overflow = 'visible';\n body.style.position = 'relative';\n body.style.minHeight = '176px';\n body.style.display = 'flex';\n body.style.flexDirection = 'column';\n body.style.alignItems = 'center';\n body.style.justifyContent = 'center';\n\n const heading = document.createElement('div');\n heading.style.cssText = 'font-size: 16px; font-weight: 700; margin-bottom: 8px; text-align: center;';\n heading.textContent = (ic.thank_you_message as string)\n || (isPromoter ? 'Thanks — glad you love it!' : 'Thanks for your feedback!');\n body.appendChild(heading);\n\n const reviewUrl = ic.nps_promoter_url as string | undefined;\n if (isPromoter && reviewUrl) {\n const sub = document.createElement('div');\n sub.style.cssText = 'font-size: 13px; opacity: 0.8; margin-bottom: 14px; text-align: center;';\n sub.textContent = 'Would you share that with others?';\n body.appendChild(sub);\n const st = this.inAppStyle(campaign);\n const cta = document.createElement('button');\n cta.type = 'button';\n cta.textContent = campaign.button_text || 'Leave a review';\n cta.style.cssText = `padding: 10px 24px; border-radius: 999px; border: none; background: ${st.btnBg}; color: ${st.btnText}; font-weight: 800; font-size: 13.5px; cursor: pointer;`;\n cta.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked', { meta: { action: 'nps_review_redirect' } });\n const safe = this.sanitizeUrl(reviewUrl);\n if (safe) this.navigateToCampaignAction(campaign, safe);\n });\n body.appendChild(cta);\n } else {\n this._playReaction(body, isPromoter ? 'affirm' : 'acknowledge', undefined, ic);\n }\n }\n\n /**\n * Evaluate the currently armed campaigns against a client-side event\n * and render any that match their `client_trigger`.\n *\n * Called by the host app (e.g., the EcommerceTracker on product_viewed),\n * or by future TriggerEngine bridges. Safe to call repeatedly for the\n * same event — dedup happens via `displayedCampaigns`.\n *\n * Supported trigger types (align with the cell-plane server-side\n * `display_rules.trigger_type`):\n * - `custom_event` : fire when eventName matches config.event\n * - `product_match` : fire on `product_viewed` when eventData.product_id\n * matches config.product_id (string or string[])\n * - `delay` : client-side setTimeout — evaluated at armeng\n * time (kicked off from `displayCampaign`), not here.\n */\n onClientEvent(eventName: string, eventData: Record<string, unknown> = {}): void {\n for (const c of this.campaigns) {\n if (this.displayedCampaigns.has(c.id)) continue;\n if (!c.client_trigger) continue;\n // Conversion-aware suppression: trigger-gated campaigns silenced by\n // a prior notifyConversion() call are skipped until expiry.\n if (this.isSuppressed(c.id)) continue;\n if (this.matchesClientTrigger(c.client_trigger, eventName, eventData)) {\n this.displayCampaign(c);\n }\n }\n }\n\n private matchesClientTrigger(\n trigger: { type: string; config?: Record<string, unknown> },\n eventName: string,\n eventData: Record<string, unknown>,\n ): boolean {\n const cfg = trigger.config || {};\n switch (trigger.type) {\n case 'custom_event':\n return typeof cfg.event === 'string' && cfg.event === eventName;\n case 'product_match': {\n if (eventName !== 'product_viewed' && eventName !== 'product_view') {\n return false;\n }\n const wantedRaw = cfg.product_id;\n const wanted: string[] = Array.isArray(wantedRaw)\n ? (wantedRaw as string[])\n : typeof wantedRaw === 'string'\n ? [wantedRaw]\n : [];\n if (wanted.length === 0) return false;\n const actual = String(\n eventData.product_id ??\n eventData.productId ??\n (eventData.product as Record<string, unknown> | undefined)?.id ??\n '',\n );\n return wanted.includes(actual);\n }\n default:\n // Unknown or server-evaluated — do not auto-fire from the client.\n return false;\n }\n }\n \n private displayCampaign(campaign: InAppCampaign): void {\n // Lifecycle: `campaign-will-show` — CANCELLABLE. Host returns `false` to\n // suppress render (e.g. route-aware blocking, host-side frequency caps,\n // self-handled mode). When suppressed we DO NOT mark the campaign as\n // displayed so a subsequent `tryDisplayNextCampaign` (after the host\n // unblocks) can re-evaluate it.\n const proceed = this.emit('campaign-will-show', campaign);\n if (!proceed) {\n this.log(`campaign ${campaign.id} suppressed by campaign-will-show handler`);\n return;\n }\n\n this.displayedCampaigns.add(campaign.id);\n\n // Sub-type routing: interactive types are handled by dedicated renderers\n const interactiveSubTypes = new Set([\n 'spin_wheel', 'scratch_card', 'nps_survey', 'quiz',\n 'countdown_offer', 'star_rating', 'quick_poll',\n // SDK Demo v4 (W1b/W3): multi-step forms + push primers are in-app\n // render types (Plotline/CleverTap/WebEngage standard), NOT widgets.\n 'multi_step_form', 'push_primer',\n // Games / gamification (the 11 locked mechanics) — interactive widgets.\n ...GAME_SUB_TYPES,\n ]);\n\n if (campaign.sub_type && interactiveSubTypes.has(campaign.sub_type)) {\n this.renderInteractive(campaign);\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n }\n\n switch (campaign.type) {\n case 'custom_html':\n this.renderCustomHtml(campaign);\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'modal':\n this.renderModal(campaign);\n break;\n case 'banner':\n this.renderBanner(campaign);\n break;\n case 'full_screen':\n this.renderFullScreen(campaign);\n break;\n case 'half_interstitial':\n this.renderHalfInterstitial(campaign);\n break;\n case 'alert':\n this.renderAlert(campaign);\n break;\n case 'pip':\n this.renderPIP(campaign);\n break;\n case 'tooltip':\n this.renderTooltip(campaign);\n break;\n // Preload-first display types (2026-04-22). These renderers own their\n // own impression tracking so we don't double-count alongside the\n // trailing `this.trackEvent(... 'impression')` below — return early.\n case 'carousel_cards':\n renderCarouselCards(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'sticky_bar':\n renderStickyBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'progress_bar':\n renderProgressBar(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'coachmark_tour':\n // coachmark_tour fires its own impression/dismiss/click events\n // from within its state machine — don't double-report here.\n renderCoachmarkTour(this.buildRenderContext(campaign));\n this.emit('campaign-shown', campaign);\n return;\n case 'product_recommendation':\n renderProductRecommendation(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'stories':\n // Stories fires its own per-frame impressions; the campaign-level\n // impression is the trailing trackEvent below — keep it (don't return\n // early like the self-tracking coachmark) so served→impression holds.\n renderStories(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'video':\n renderVideo(this.buildRenderContext(campaign));\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n case 'active_web_chat':\n // Persistent chat launcher backed by the AegisChat engine. The bubble\n // is the impression; session_start/session_end/message_sent flow as\n // campaign events from the engine's lifecycle callbacks. SSE is opened\n // only when the customer opens the panel (panel-gated inside AegisChat).\n this.renderActiveWebChatLauncher(campaign);\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n return;\n }\n\n this.trackEvent(campaign.id, 'impression');\n this.emit('campaign-shown', campaign);\n }\n\n /** The single chat launcher on the page (Active Web Chat). Persistent — not\n * re-mounted on SSE/poll refresh; torn down on manager teardown. */\n private activeWebChat?: AegisChat;\n\n /**\n * Mount the Active Web Chat launcher. Idempotent: a repeat delivery of the\n * same (or another) chat campaign is a no-op once one launcher is live — at\n * most one bubble per page, and an open session is never yanked out from\n * under the customer.\n */\n private renderActiveWebChatLauncher(campaign: InAppCampaign): void {\n if (this.activeWebChat) return;\n const chat = renderActiveWebChat(this.buildRenderContext(campaign), {\n writeKey: this.writeKey,\n apiHost: this.apiHost,\n contactId: this.contactId,\n channel: 'web',\n });\n if (chat) this.activeWebChat = chat;\n }\n\n /**\n * Build the shared context passed into the preload-first renderers.\n * Matches the interface in `./renderers/types.ts`. Kept as a private\n * method (rather than inlined at each call-site) so future renderer\n * additions stay consistent and easy to audit.\n */\n private buildRenderContext(campaign: InAppCampaign): RenderContext {\n return {\n campaign,\n getCartState: this.getCartState,\n trackEvent: (id, evt, extra) => {\n void this.trackEvent(id, evt, extra);\n },\n sanitizeUrl: (url: string) => this.sanitizeUrl(url),\n navigate: (url: string, buttonId?: string) =>\n this.navigateToCampaignAction(campaign, url, buttonId),\n submitResponse: (responseType: string, payload: Record<string, unknown>) =>\n this.submitWidgetResponse(campaign, responseType, payload),\n playReaction: (el, intent, lottieFile) =>\n this._playReaction(el, intent, lottieFile, campaign.interactive_config as Record<string, unknown> | undefined),\n haptic: (pattern) => {\n try {\n if (typeof navigator !== 'undefined' && typeof navigator.vibrate === 'function') {\n navigator.vibrate(pattern);\n }\n } catch { /* unsupported — no-op */ }\n },\n sanitizeColor: (color: string) => this.sanitizeColor(color),\n log: (msg: string, level?: 'log' | 'warn' | 'error') => this.log(msg, level),\n addAnimationStyles: () => this.addAnimationStyles(),\n };\n }\n\n /**\n * Renders interactive sub-type campaigns (spin wheel, NPS, quiz, etc.)\n * using DOM-safe rendering. These sub-types use the campaign's\n * interactive_config payload for type-specific behavior.\n */\n private renderInteractive(campaign: InAppCampaign): void {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const { bg, text } = this._surfacePalette(campaign);\n\n // Games / gamification (the 11 locked mechanics) render via the shared\n // games module (centred modal scaffold + per-game body).\n if (campaign.sub_type && renderGame(this.buildRenderContext(campaign), campaign.sub_type)) {\n return;\n }\n\n switch (campaign.sub_type) {\n case 'nps_survey':\n this.renderNPSSurvey(campaign, ic, bg, text);\n break;\n case 'countdown_offer':\n this.renderCountdownOffer(campaign, ic, bg, text);\n break;\n case 'star_rating':\n this.renderStarRating(campaign, ic, bg, text);\n break;\n case 'quick_poll':\n this.renderQuickPoll(campaign, ic, bg, text);\n break;\n case 'quiz':\n this.renderQuiz(campaign, ic, bg, text);\n break;\n case 'multi_step_form':\n this.renderMultiStepForm(campaign, ic, bg, text);\n break;\n case 'push_primer':\n this.renderPushPrimer(campaign, ic, bg, text);\n break;\n case 'spin_wheel':\n case 'scratch_card':\n if (this.onInteractiveCampaign) {\n // A host runtime (AegisMessageRuntime) is wired — let it own the\n // richer gamification UX.\n this.onInteractiveCampaign(campaign);\n } else {\n // No runtime (e.g. dashboard preview, or a host that didn't install\n // the runtime) — render the built-in interactive spin/scratch in an\n // overlay so the widget is never a dead, non-interactive frame.\n this.renderGamificationOverlay(campaign, ic, bg, text);\n }\n break;\n default:\n this.log(`Unknown interactive sub_type: ${campaign.sub_type}`, 'warn');\n this.renderModal(campaign);\n }\n }\n\n /**\n * Built-in overlay for spin_wheel / scratch_card when no host runtime is\n * wired (dashboard preview, runtime-less hosts). Wraps the same interactive\n * slot renderers (`renderSpinWheelSlot` / `renderScratchCardSlot`) in a modal\n * so the gamified widget is fully playable — not a dead frame.\n */\n private renderGamificationOverlay(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n ): void {\n const overlay = this.createOverlay(`aegis-in-app-${campaign.sub_type}-overlay`);\n const modal = document.createElement('div');\n modal.style.cssText = `\n position: relative; max-width: 340px; width: 90%; border-radius: 20px;\n overflow: hidden; background: ${bg}; color: ${text};\n animation: aegisScaleIn 0.3s ease; box-shadow: 0 16px 48px rgba(0,0,0,0.22);\n `;\n if (campaign.sub_type === 'scratch_card') {\n this.renderScratchCardSlot(campaign, ic, bg, text, modal);\n } else {\n this.renderSpinWheelSlot(campaign, ic, bg, text, modal);\n }\n this._addCornerClose(modal, overlay, campaign.id, text);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n /** A circular ✕ close button in the modal's top-right corner. */\n private _addCornerClose(\n modal: HTMLElement,\n overlay: HTMLElement,\n campaignId: string,\n text: string,\n ): void {\n const x = document.createElement('button');\n x.setAttribute('aria-label', 'Close');\n const closeIcon = svgNode(\n '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" ' +\n 'stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>' +\n '<line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>',\n );\n if (closeIcon) x.appendChild(closeIcon); else x.textContent = '✕';\n x.style.cssText = `\n position: absolute; top: 12px; right: 12px; z-index: 4; width: 28px; height: 28px;\n display: flex; align-items: center; justify-content: center; border: none;\n border-radius: 50%; cursor: pointer; color: ${text};\n background: ${text}1f; backdrop-filter: blur(4px); transition: background 0.15s, transform 0.15s;\n `;\n x.addEventListener('mouseenter', () => { x.style.background = `${text}33`; x.style.transform = 'scale(1.08)'; });\n x.addEventListener('mouseleave', () => { x.style.background = `${text}1f`; x.style.transform = 'scale(1)'; });\n x.addEventListener('click', () => {\n this.trackEvent(campaignId, 'dismissed');\n this.removeModal(overlay);\n });\n modal.appendChild(x);\n }\n\n /**\n * Custom HTML type — render operator-authored HTML in a SANDBOXED iframe.\n * The frame runs with `sandbox=\"allow-scripts\"` and NO `allow-same-origin`, so\n * it's an opaque/null origin: no access to the host DOM, cookies, localStorage,\n * the SDK write-key, or same-origin creds. The only channel out is a validated\n * `postMessage` bridge (close / track / cta / resize), exposed to authors as a\n * tiny injected `aegis` shim. See IN_APP_CUSTOM_HTML_TRACKER.md (security model).\n */\n private renderCustomHtml(campaign: InAppCampaign): void {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const overlay = this.createOverlay('aegis-in-app-custom-html-overlay');\n const modal = document.createElement('div');\n modal.style.cssText =\n 'position: relative; max-width: 420px; width: 92%; border-radius: 16px; ' +\n 'overflow: hidden; background: #ffffff; box-shadow: 0 16px 48px rgba(0,0,0,0.22); ' +\n 'animation: aegisScaleIn 0.3s ease;';\n modal.appendChild(this._buildCustomHtmlFrame(campaign, ic, overlay));\n this._addCornerClose(modal, overlay, campaign.id, '#111827');\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n /** Build the sandboxed iframe + the validated message bridge. Reused by the\n * overlay + embedded-slot custom-HTML renderers. */\n private _buildCustomHtmlFrame(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n overlay: HTMLElement,\n ): HTMLIFrameElement {\n const html = typeof ic.html === 'string' ? (ic.html as string) : '';\n const height = typeof ic.html_height === 'number' ? (ic.html_height as number) : 360;\n // Expose the brand palette as CSS variables so authored HTML can be on-brand\n // (var(--aegis-primary) etc.) without hardcoding hexes per campaign.\n const bst = this.inAppStyle(campaign);\n const brandVars =\n `:root{--aegis-bg:${bst.bg};--aegis-text:${bst.text};` +\n `--aegis-primary:${bst.btnBg};--aegis-on-primary:${bst.btnText};}`;\n const iframe = document.createElement('iframe');\n // allow-scripts WITHOUT allow-same-origin → opaque origin, fully isolated.\n iframe.setAttribute('sandbox', 'allow-scripts');\n iframe.setAttribute('referrerpolicy', 'no-referrer');\n // `transform: translateZ(0)` forces the iframe onto its own compositing\n // layer — nested iframes otherwise fail to paint when an ancestor is\n // CSS-scaled (the small editor preview uses `transform: scale()`), which is\n // why custom HTML showed full-screen but not in the small frame.\n iframe.style.cssText =\n `width: 100%; height: ${height}px; border: none; display: block; background: #fff; ` +\n `transform: translateZ(0); backface-visibility: hidden;`;\n iframe.title = campaign.title || 'In-app content';\n\n // Injected author shim — `aegis.close()/track()/cta()/resize()` post tagged\n // messages so authors never hand-write postMessage.\n const shim =\n \"<script>window.aegis={\" +\n \"close:function(){parent.postMessage({__aegis:'close'},'*')},\" +\n \"track:function(e,p){parent.postMessage({__aegis:'track',event:e,payload:p},'*')},\" +\n \"cta:function(u){parent.postMessage({__aegis:'cta',url:u},'*')},\" +\n \"resize:function(h){parent.postMessage({__aegis:'resize',height:h},'*')}\" +\n \"};<\\/script>\";\n iframe.srcdoc =\n '<!DOCTYPE html><html><head><meta charset=\"utf-8\">' +\n '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">' +\n '<style>' + brandVars + 'html,body{margin:0;padding:0;font-family:system-ui,-apple-system,sans-serif;}</style>' +\n shim + '</head><body>' + html + '</body></html>';\n\n // Bridge — only accept messages from THIS frame, only the tagged allow-list.\n const onMsg = (e: MessageEvent) => {\n if (e.source !== iframe.contentWindow) return;\n const d = e.data as { __aegis?: string; event?: unknown; url?: unknown; height?: unknown };\n if (!d || typeof d.__aegis !== 'string') return;\n switch (d.__aegis) {\n case 'close':\n window.removeEventListener('message', onMsg);\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n break;\n case 'track':\n // Author-defined events record as a click (the custom name rides metadata).\n this.trackEvent(campaign.id, 'clicked');\n break;\n case 'cta': {\n this.trackEvent(campaign.id, 'clicked');\n const safe = typeof d.url === 'string' ? this.sanitizeUrl(d.url) : null;\n if (safe) {\n const ev = new CustomEvent('aegis:campaign-click', {\n detail: { campaign, url: safe }, cancelable: true,\n });\n const notPrevented = window.dispatchEvent(ev);\n if (notPrevented) window.open(safe, '_blank', 'noopener');\n }\n break;\n }\n case 'resize':\n if (typeof d.height === 'number' && d.height >= 40 && d.height <= 2000) {\n iframe.style.height = `${d.height}px`;\n }\n break;\n }\n };\n window.addEventListener('message', onMsg);\n return iframe;\n }\n\n /** Embedded-slot custom HTML (e.g. on the bill) — the same sandboxed frame in\n * a slot card instead of an overlay. */\n private renderCustomHtmlSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n ): boolean {\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard('aegis-in-app-custom-html-card', campaign.id, bg, text, st.radius);\n card.appendChild(this._buildCustomHtmlFrame(campaign, ic, card));\n target.appendChild(card);\n return true;\n }\n\n // --- Interactive Renderers ---\n\n private renderNPSSurvey(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-nps-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 360px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 16px 48px rgba(0,0,0,0.22);\n `;\n\n const body = this._buildNPSSurveyBody(campaign, ic, text, 'overlay');\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderCountdownOffer(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-countdown-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 16px 48px rgba(0,0,0,0.22);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 20px; font-weight: 700; margin-bottom: 8px;';\n title.textContent = campaign.title || 'Flash Sale';\n body.appendChild(title);\n\n const label = document.createElement('div');\n label.style.cssText = 'font-size: 13px; opacity: 0.8; margin-bottom: 12px;';\n label.textContent = (ic.countdown_label as string) || 'Sale ends in:';\n body.appendChild(label);\n\n // Start the countdown. With an authored `countdown_target` we run to it;\n // with none (editor preview) a short demo so the timer is visibly ticking.\n const targetStr = ic.countdown_target as string | undefined;\n // No authored target (e.g. editor preview) → a 10-minute demo so the timer\n // is visibly ticking in its NORMAL state (a 10s demo would open already in\n // the final-minute \"urgent\" style, which read as broken).\n const target = targetStr ? new Date(targetStr).getTime() : Date.now() + 600_000;\n\n // Labelled, boxed units (Days/Hrs/Min/Sec) — the standard countdown look\n // (was a bare \"00:00:00\" with no captions + no days, so a multi-day sale\n // showed huge hour counts). Days appear only when the sale is >24h out.\n const includeDays = (target - Date.now()) >= 86_400_000;\n const UNITS: Array<['d' | 'h' | 'm' | 's', string]> = includeDays\n ? [['d', 'Days'], ['h', 'Hrs'], ['m', 'Min'], ['s', 'Sec']]\n : [['h', 'Hrs'], ['m', 'Min'], ['s', 'Sec']];\n const cells: Partial<Record<'d' | 'h' | 'm' | 's', HTMLElement>> = {};\n const digits = document.createElement('div');\n digits.style.cssText = 'display: flex; gap: 10px; justify-content: center; margin-bottom: 16px;';\n for (const [key, cap] of UNITS) {\n const group = document.createElement('div');\n group.style.cssText = 'display: flex; flex-direction: column; align-items: center; gap: 4px;';\n const num = document.createElement('div');\n num.style.cssText = `min-width: 46px; padding: 8px 6px; border-radius: 8px; font-size: 24px; font-weight: 700; font-family: monospace; background: ${text}22; color: ${text}; transition: background 0.2s, color 0.2s;`;\n num.textContent = '00';\n const lbl = document.createElement('div');\n lbl.style.cssText = 'font-size: 10px; opacity: 0.6; text-transform: uppercase; letter-spacing: 0.5px;';\n lbl.textContent = cap;\n group.appendChild(num);\n group.appendChild(lbl);\n cells[key] = num;\n digits.appendChild(group);\n }\n body.appendChild(digits);\n\n const pad = (n: number) => String(n).padStart(2, '0');\n let expired = false;\n let urgent = false;\n const update = () => {\n const diff = Math.max(0, target - Date.now());\n const d = Math.floor(diff / 86_400_000);\n const h = Math.floor((diff % 86_400_000) / 3_600_000);\n const m = Math.floor((diff % 3_600_000) / 60_000);\n const s = Math.floor((diff % 60_000) / 1000);\n if (cells.d) cells.d.textContent = pad(d);\n if (cells.h) cells.h.textContent = pad(includeDays ? h : Math.floor(diff / 3_600_000));\n if (cells.m) cells.m.textContent = pad(m);\n if (cells.s) cells.s.textContent = pad(s);\n // Final-minute urgency: keep the numerals their READABLE colour and signal\n // urgency with a red accent RING + a gentle breathing pulse — NOT red text\n // on a red tint (muddy/unreadable) nor a harsh solid-red fill. Applied once.\n if (!urgent && diff > 0 && diff <= 60000) {\n urgent = true;\n Object.values(cells).forEach((el) => {\n if (el) { el.style.boxShadow = '0 0 0 2px #ef4444'; }\n });\n digits.style.animation = 'aegisCountdownPulse 1.1s ease-in-out infinite';\n }\n if (diff > 0) {\n requestAnimationFrame(update);\n } else if (!expired) {\n expired = true;\n // Time's up — ring the alarm clock.\n void this.submitWidgetResponse(campaign, 'countdown', { state: 'expired' });\n this._playReaction(body, 'celebrate', 'alarm-clock.json', ic); // time's up → alarm clock\n }\n };\n update();\n\n if (campaign.body) {\n const desc = document.createElement('div');\n desc.style.cssText = 'font-size: 14px; opacity: 0.85; margin-bottom: 16px;';\n desc.textContent = campaign.body;\n body.appendChild(desc);\n }\n\n if (campaign.button_text) {\n const btn = this.createCTAButton(campaign, bg, text);\n body.appendChild(btn);\n }\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderStarRating(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-rating-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 16px 48px rgba(0,0,0,0.22);\n `;\n\n const body = this._buildStarRatingBody(campaign, ic, text, 'overlay');\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderQuickPoll(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-poll-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 320px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 16px 48px rgba(0,0,0,0.22);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const title = document.createElement('div');\n title.style.cssText = `font-size: 16px; font-weight: 700; margin-bottom: ${campaign.body ? '6px' : '16px'};`;\n title.textContent = campaign.title || 'Quick question';\n body.appendChild(title);\n\n // Subtitle / body (was never rendered in the overlay).\n if (campaign.body) {\n const sub = document.createElement('div');\n sub.style.cssText = `font-size: 13px; opacity: 0.8; margin-bottom: 16px; color: ${text};`;\n sub.textContent = campaign.body;\n body.appendChild(sub);\n }\n\n const options = (ic.poll_options as string[]) || [];\n const optionsList = document.createElement('div');\n optionsList.style.cssText = 'display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px;';\n const buttons: HTMLButtonElement[] = [];\n options.forEach((opt, i) => {\n // position:relative + overflow so the result fill bar can layer behind.\n const optBtn = document.createElement('button');\n optBtn.style.cssText = `\n position: relative; overflow: hidden;\n padding: 10px 16px; border-radius: 10px; border: 1px solid ${text}33;\n background: transparent; color: ${text}; font-size: 14px; cursor: pointer;\n text-align: left; transition: border-color 0.2s ease;\n `;\n const lbl = document.createElement('span');\n lbl.style.cssText = 'position: relative; z-index: 1; display: flex; justify-content: space-between; gap: 8px;';\n const lblText = document.createElement('span');\n lblText.textContent = opt;\n const lblPct = document.createElement('span');\n lblPct.style.cssText = 'font-weight: 700; opacity: 0; transition: opacity 0.3s ease;';\n lbl.appendChild(lblText);\n lbl.appendChild(lblPct);\n optBtn.appendChild(lbl);\n optBtn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n buttons.forEach((b) => (b.disabled = true));\n // Optimistic confirmation now; upgrade to the real distribution if the\n // server returns one (shared with the embedded slot — no fabrication).\n this._paintPollResult(buttons, options, i, null, text);\n void this.submitWidgetResponse(campaign, 'poll', { option_index: i, option_label: opt })\n .then((resp) => {\n const dist = this._readPollDistribution(resp, options.length);\n if (dist) this._paintPollResult(buttons, options, i, dist, text);\n });\n // Reaction badge (~150px) would clip under the modal's overflow:hidden.\n const modalEl = body.parentElement as HTMLElement | null;\n if (modalEl) modalEl.style.overflow = 'visible';\n this._playReaction(body, 'affirm', 'check.json', ic);\n });\n buttons.push(optBtn);\n optionsList.appendChild(optBtn);\n });\n body.appendChild(optionsList);\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n /**\n * Multi-step form (SDK Demo v4 W1b) — in-app render type matching the\n * Plotline multi-step flow pattern: a progress bar + per-step question with\n * options, Back/Next navigation, Submit on the last step. `ic.steps` is an\n * array of `{ question, options[] }`. DOM-safe (no innerHTML).\n */\n private renderMultiStepForm(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-multistep-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 360px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 16px 48px rgba(0,0,0,0.22);\n `;\n\n // §7.13.I — a profile FORM (field-map) renders as input fields + submit (the\n // SAME body the embedded slot uses), not the question/options stepper.\n const formFields = Array.isArray(ic.form_fields)\n ? (ic.form_fields as Array<Record<string, unknown>>)\n : null;\n if (formFields && formFields.length > 0) {\n const formBody = this._buildFormBody(campaign, formFields, bg, text);\n this.addCloseButton(formBody, overlay, campaign.id);\n modal.appendChild(formBody);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n return;\n }\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px;';\n\n const rawSteps = Array.isArray(ic.steps)\n ? (ic.steps as Array<Record<string, unknown>>)\n : [];\n const steps = rawSteps.length > 0\n ? rawSteps\n : [{ question: campaign.title || 'Tell us more', options: [] }];\n const total = steps.length;\n let current = 0;\n const answers: Array<string | null> = new Array(total).fill(null);\n\n // Progress bar — keeps users motivated to finish (Plotline best practice).\n const progressTrack = document.createElement('div');\n progressTrack.style.cssText = `height: 4px; border-radius: 2px; background: ${text}22; margin-bottom: 16px; overflow: hidden;`;\n const progressFill = document.createElement('div');\n progressFill.style.cssText = `height: 100%; background: ${text}; transition: width 0.2s ease; width: 0%;`;\n progressTrack.appendChild(progressFill);\n body.appendChild(progressTrack);\n\n const stepLabel = document.createElement('div');\n stepLabel.style.cssText = 'font-size: 11px; opacity: 0.7; margin-bottom: 6px;';\n body.appendChild(stepLabel);\n\n const question = document.createElement('div');\n question.style.cssText = 'font-size: 16px; font-weight: 700; margin-bottom: 14px;';\n body.appendChild(question);\n\n const optionsList = document.createElement('div');\n optionsList.style.cssText = 'display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px;';\n body.appendChild(optionsList);\n\n const nav = document.createElement('div');\n nav.style.cssText = 'display: flex; gap: 8px; justify-content: space-between;';\n const backBtn = document.createElement('button');\n backBtn.textContent = 'Back';\n backBtn.style.cssText = `padding: 10px 16px; border-radius: 10px; border: 1px solid ${text}33; background: transparent; color: ${text}; font-size: 14px; cursor: pointer;`;\n const nextBtn = document.createElement('button');\n nextBtn.style.cssText = `padding: 10px 16px; border-radius: 10px; border: none; background: ${text}; color: ${bg}; font-size: 14px; font-weight: 600; cursor: pointer; flex: 1;`;\n nav.appendChild(backBtn);\n nav.appendChild(nextBtn);\n body.appendChild(nav);\n\n const renderStep = () => {\n const step = steps[current] || {};\n const q = (step.question as string) || (step.label as string) || `Step ${current + 1}`;\n const opts = Array.isArray(step.options) ? (step.options as string[]) : [];\n progressFill.style.width = `${Math.round((current / total) * 100)}%`;\n stepLabel.textContent = `Step ${current + 1} of ${total}`;\n question.textContent = q;\n while (optionsList.firstChild) optionsList.removeChild(optionsList.firstChild);\n opts.forEach((opt) => {\n const ob = document.createElement('button');\n ob.textContent = opt;\n const selected = answers[current] === opt;\n ob.style.cssText = `padding: 10px 16px; border-radius: 10px; border: 1px solid ${text}33; background: ${selected ? text + '22' : 'transparent'}; color: ${text}; font-size: 14px; cursor: pointer; text-align: left;`;\n ob.addEventListener('click', () => {\n answers[current] = opt;\n renderStep();\n });\n optionsList.appendChild(ob);\n });\n backBtn.style.visibility = current === 0 ? 'hidden' : 'visible';\n nextBtn.textContent = current === total - 1 ? 'Submit' : 'Next';\n // Gate Next/Submit until the step is answered (was skippable → null\n // answers submitted). A step with no options has nothing to answer.\n const needsAnswer = opts.length > 0 && answers[current] == null;\n nextBtn.disabled = needsAnswer;\n nextBtn.style.opacity = needsAnswer ? '0.5' : '1';\n nextBtn.style.cursor = needsAnswer ? 'not-allowed' : 'pointer';\n };\n\n backBtn.addEventListener('click', () => {\n if (current > 0) {\n current -= 1;\n renderStep();\n }\n });\n nextBtn.addEventListener('click', () => {\n if (current < total - 1) {\n current += 1;\n renderStep();\n } else {\n progressFill.style.width = '100%';\n void this.trackEvent(campaign.id, 'clicked', { meta: { answers } });\n void this.submitWidgetResponse(campaign, 'form', { answers });\n // Completed → green check + confetti, then close once it's been seen.\n this._playReaction(body, 'affirm', 'check.json', ic);\n window.setTimeout(() => { if (overlay.parentNode) document.body.removeChild(overlay); }, 2300);\n }\n });\n\n renderStep();\n\n this.addCloseButton(body, overlay, campaign.id);\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n /**\n * Push primer (SDK Demo v4 W3) — in-app render type that \"soft-asks\" before\n * the OS hard-ask. The Enable CTA calls `Notification.requestPermission()`;\n * we report `permission_granted` / `permission_denied` / `permission_default`\n * so journeys can react. Degrades gracefully where Notification is absent.\n */\n private renderPushPrimer(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-push-primer-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 340px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 16px 48px rgba(0,0,0,0.22);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 24px; text-align: center;';\n\n const icon = document.createElement('div');\n icon.style.cssText = 'font-size: 36px; margin-bottom: 8px;';\n icon.textContent = (ic.icon as string) || '🔔';\n body.appendChild(icon);\n\n const title = document.createElement('div');\n title.style.cssText = 'font-size: 18px; font-weight: 700; margin-bottom: 8px;';\n title.textContent = campaign.title || 'Stay in the loop';\n body.appendChild(title);\n\n const desc = document.createElement('div');\n desc.style.cssText = 'font-size: 14px; opacity: 0.85; margin-bottom: 18px;';\n desc.textContent = campaign.body || 'Enable notifications so you never miss an offer.';\n body.appendChild(desc);\n\n const supported =\n typeof Notification !== 'undefined' &&\n typeof Notification.requestPermission === 'function';\n\n const enableBtn = document.createElement('button');\n enableBtn.textContent = (ic.allow_text as string) || 'Enable notifications';\n enableBtn.style.cssText = `width: 100%; padding: 12px 16px; border-radius: 10px; border: none; background: ${text}; color: ${bg}; font-size: 15px; font-weight: 600; cursor: pointer; margin-bottom: 8px;`;\n enableBtn.addEventListener('click', () => {\n if (!supported) {\n void this.trackEvent(campaign.id, 'dismissed', { meta: { reason: 'unsupported' } });\n if (overlay.parentNode) document.body.removeChild(overlay);\n return;\n }\n // The OS hard-ask. The primer above is the soft-ask that precedes it.\n // The permission OUTCOME is the high-value signal — report it as a click\n // with the resolved permission in meta so journeys can branch on it.\n void Promise.resolve(Notification.requestPermission()).then((perm) => {\n void this.trackEvent(campaign.id, 'clicked', { meta: { permission: perm } });\n if (overlay.parentNode) document.body.removeChild(overlay);\n });\n });\n body.appendChild(enableBtn);\n\n const dismissBtn = document.createElement('button');\n dismissBtn.textContent = (ic.dismiss_text as string) || 'Not now';\n dismissBtn.style.cssText = `width: 100%; padding: 10px 16px; border-radius: 10px; border: none; background: transparent; color: ${text}; opacity: 0.7; font-size: 14px; cursor: pointer;`;\n dismissBtn.addEventListener('click', () => {\n void this.trackEvent(campaign.id, 'dismissed');\n if (overlay.parentNode) document.body.removeChild(overlay);\n });\n body.appendChild(dismissBtn);\n\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderQuiz(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string\n ): void {\n const overlay = this.createOverlay('aegis-in-app-quiz-overlay');\n const modal = document.createElement('div');\n modal.style.cssText = `\n max-width: 360px; width: 90%; border-radius: 16px; overflow: hidden;\n background: ${bg}; color: ${text}; animation: aegisScaleIn 0.3s ease;\n box-shadow: 0 16px 48px rgba(0,0,0,0.22);\n `;\n\n const body = document.createElement('div');\n body.style.cssText = 'padding: 22px; text-align: center;';\n modal.appendChild(body);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n\n this._runQuizFlow(campaign, ic, bg, text, body, overlay);\n }\n\n /**\n * Embedded quiz on a bill/page slot — same question-stepping flow as the\n * overlay, rendered inline with no overlay/close (Open/Closed: both paths\n * share `_runQuizFlow`, so a feature added once lights up both). Returns\n * false when there are no questions so dispatch can fall back to a card.\n */\n private renderQuizSlot(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n target: HTMLElement,\n ): boolean {\n const questions = Array.isArray(ic.questions) ? (ic.questions as unknown[]) : [];\n if (questions.length === 0) return false;\n const st = this._slotStyle(campaign);\n const card = this._wrapInSlotCard('aegis-in-app-quiz-card', campaign.id, bg, text, st.radius);\n const body = document.createElement('div');\n body.style.cssText = `padding: ${st.padY ?? 18}px ${st.padX ?? 18}px; text-align: center;`;\n card.appendChild(body);\n target.appendChild(card);\n this._runQuizFlow(campaign, ic, bg, text, body, null);\n return true;\n }\n\n /**\n * Shared quiz engine — drives the question stepper, scoring (knowledge =\n * correct_index/points, personality = outcome tally), result-band selection,\n * CTA, reaction and the `quiz` response submit. Renders into the provided\n * `body`. `overlay` is the dismiss target for the close button on the overlay\n * path; pass null on the slot path (no close affordance inline).\n */\n private _runQuizFlow(\n campaign: InAppCampaign,\n ic: Record<string, unknown>,\n bg: string,\n text: string,\n body: HTMLElement,\n overlay: HTMLElement | null,\n ): void {\n const isUrl = (s: string): boolean => /^https?:\\/\\//i.test(s);\n const questions = Array.isArray(ic.questions) ? (ic.questions as Array<Record<string, unknown>>) : [];\n const resultMap = Array.isArray(ic.result_mapping) ? (ic.result_mapping as Array<Record<string, unknown>>) : [];\n // knowledge = right/wrong by `correct_index` (+ per-question `points`); personality\n // = each option's index contributes to a score that maps to a result band.\n const knowledge = (ic.quiz_type as string) === 'knowledge';\n const total = questions.length;\n const answers: number[] = [];\n const tally: Record<string, number> = {}; // personality: outcome id → pick count\n const maxPts = knowledge ? questions.reduce((s, q) => s + (typeof q.points === 'number' ? (q.points as number) : 1), 0) : 0;\n let score = 0;\n let cur = 0;\n\n const clear = (): void => { while (body.firstChild) body.removeChild(body.firstChild); };\n const heading = (txt: string, big = false): HTMLElement => {\n const t = document.createElement('div');\n t.style.cssText = `font-size: ${big ? 19 : 14}px; font-weight: ${big ? 800 : 600}; letter-spacing: -0.01em; line-height: 1.3; margin-bottom: ${big ? 6 : 14}px; font-family: 'Inter Tight', Inter, system-ui, -apple-system, sans-serif;`;\n t.textContent = txt;\n return t;\n };\n\n // Final screen: pick the result band the score falls into, show its title/body\n // (+ optional CTA), react, AND submit so the server records it (analytics +\n // completion reward + response-mapping enrichment + the quiz_completed event).\n const showResult = (): void => {\n clear();\n let band: Record<string, unknown> | null = null;\n let outScore = score;\n if (knowledge) {\n band = resultMap.find((r) => {\n const mn = typeof r.min_score === 'number' ? (r.min_score as number) : -Infinity;\n const mx = typeof r.max_score === 'number' ? (r.max_score as number) : Infinity;\n return score >= mn && score <= mx;\n }) || resultMap[resultMap.length - 1] || null;\n } else {\n // Personality: the outcome picked most across all questions wins (ties →\n // the first-authored outcome, by iterating resultMap in order).\n let best = -1;\n for (const r of resultMap) {\n const rid = typeof r.id === 'string' ? (r.id as string) : '';\n const c = rid ? (tally[rid] || 0) : 0;\n if (c > best) { best = c; band = r; }\n }\n outScore = best < 0 ? 0 : best;\n band = band || resultMap[0] || null;\n }\n const rTitle = band && typeof band.title === 'string'\n ? (band.title as string)\n : (knowledge && maxPts ? `You scored ${score} of ${maxPts}` : 'Your result');\n const rBody = band && typeof band.body === 'string'\n ? (band.body as string)\n : (ic.thank_you_message as string) || 'Thanks for completing the quiz!';\n body.appendChild(heading(rTitle, true));\n const sub = document.createElement('div');\n sub.style.cssText = 'font-size: 13.5px; opacity: 0.85; line-height: 1.45; margin: 2px 0 14px;';\n sub.textContent = rBody;\n body.appendChild(sub);\n const actionUrl = band && typeof band.action_url === 'string' ? (band.action_url as string) : '';\n if (actionUrl) {\n const cta = document.createElement('button');\n cta.type = 'button';\n cta.textContent = (campaign as unknown as Record<string, unknown>).button_text as string || 'Continue';\n cta.style.cssText = `padding: 11px 28px; border-radius: 999px; border: none; background: ${text}; color: ${bg}; font-weight: 800; font-size: 14px; cursor: pointer; margin-top: 2px;`;\n cta.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n const safe = this.sanitizeUrl(actionUrl);\n if (safe) this.navigateToCampaignAction(campaign, safe);\n });\n body.appendChild(cta);\n }\n this._playReaction(body, 'affirm', 'check.json', ic);\n if (overlay) this.addCloseButton(body, overlay, campaign.id);\n void this.submitWidgetResponse(campaign, 'quiz', {\n answers,\n score: outScore,\n result_title: rTitle,\n result_id: band && typeof band.id === 'string' ? (band.id as string) : undefined,\n quiz_type: knowledge ? 'knowledge' : 'personality',\n });\n };\n\n const renderQuestion = (): void => {\n if (cur >= total) { showResult(); return; }\n clear();\n const q = questions[cur];\n if (campaign.title) {\n const hd = document.createElement('div');\n hd.style.cssText = 'font-size: 11px; font-weight: 700; letter-spacing: 0.3px; text-transform: uppercase; opacity: 0.55; margin-bottom: 10px;';\n hd.textContent = campaign.title;\n body.appendChild(hd);\n }\n const track = document.createElement('div');\n track.style.cssText = `height: 4px; border-radius: 999px; background: ${text}1f; overflow: hidden; margin-bottom: 8px;`;\n const fill = document.createElement('div');\n fill.style.cssText = `height: 100%; width: ${total ? Math.round((cur / total) * 100) : 0}%; background: ${text}; border-radius: 999px; transition: width 0.3s ease;`;\n track.appendChild(fill); body.appendChild(track);\n const step = document.createElement('div');\n step.style.cssText = 'font-size: 11.5px; opacity: 0.6; margin-bottom: 12px; font-weight: 600;';\n step.textContent = `Question ${cur + 1} of ${total}`;\n body.appendChild(step);\n const imgUrl = q.image_url;\n if (typeof imgUrl === 'string' && isUrl(imgUrl)) {\n const im = document.createElement('img');\n im.src = imgUrl; im.alt = '';\n im.style.cssText = 'width: 100%; max-height: 140px; object-fit: cover; border-radius: 10px; margin-bottom: 12px;';\n body.appendChild(im);\n }\n body.appendChild(heading(typeof q.question === 'string' ? (q.question as string) : ''));\n const opts = Array.isArray(q.options) ? (q.options as unknown[]).filter((o): o is string => typeof o === 'string') : [];\n const correctIdx = typeof q.correct_index === 'number' ? (q.correct_index as number) : -1;\n const pts = typeof q.points === 'number' ? (q.points as number) : 1;\n const wrap = document.createElement('div');\n wrap.style.cssText = 'display: flex; flex-direction: column; gap: 8px;';\n const btns: HTMLButtonElement[] = [];\n opts.forEach((opt, j) => {\n const b = document.createElement('button');\n b.type = 'button';\n b.style.cssText = `padding: 11px 14px; border-radius: 10px; border: 1.5px solid ${text}2e; background: transparent; color: ${text}; font-size: 14px; cursor: pointer; text-align: left; transition: all 0.15s; font-weight: 600;`;\n b.textContent = opt;\n b.addEventListener('click', () => {\n if (b.disabled) return;\n btns.forEach((x) => { x.disabled = true; });\n answers.push(j);\n let delay = 280;\n if (knowledge) {\n if (j === correctIdx) score += pts;\n if (correctIdx >= 0) {\n const good = j === correctIdx;\n b.style.borderColor = good ? '#10b981' : '#ef4444';\n b.style.background = (good ? '#10b981' : '#ef4444') + '22';\n if (!good && btns[correctIdx]) {\n btns[correctIdx].style.borderColor = '#10b981';\n btns[correctIdx].style.background = '#10b98114';\n }\n delay = 680;\n }\n } else {\n // personality: tally the outcome this option maps to (option_results[j]).\n const optRes = Array.isArray(q.option_results) ? (q.option_results as unknown[]) : [];\n const rid = optRes[j];\n if (typeof rid === 'string' && rid) tally[rid] = (tally[rid] || 0) + 1;\n b.style.borderColor = text; b.style.background = `${text}14`;\n }\n window.setTimeout(() => { cur += 1; renderQuestion(); }, delay);\n });\n wrap.appendChild(b); btns.push(b);\n });\n body.appendChild(wrap);\n if (overlay) this.addCloseButton(body, overlay, campaign.id);\n };\n\n renderQuestion();\n }\n\n // --- Shared Rendering Helpers ---\n\n private createOverlay(className: string): HTMLElement {\n const overlay = document.createElement('div');\n overlay.className = className;\n overlay.style.cssText = `\n position: fixed; top: 0; left: 0; right: 0; bottom: 0;\n background: rgba(0,0,0,0.5); display: flex; align-items: center;\n justify-content: center; z-index: 99999; animation: aegisFadeIn 0.3s ease;\n `;\n return overlay;\n }\n\n private createCTAButton(campaign: InAppCampaign, bg: string, text: string): HTMLElement {\n const btn = document.createElement('button');\n btn.className = 'aegis-cta';\n btn.style.cssText = `\n display: inline-block; padding: 10px 28px; border-radius: 999px;\n font-size: 14px; font-weight: 600; cursor: pointer; border: none;\n background: ${text}; color: ${bg}; transition: transform 0.15s;\n `;\n btn.textContent = campaign.button_text || 'OK';\n btn.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (campaign.action_url) {\n const safeUrl = this.sanitizeUrl(campaign.action_url);\n if (safeUrl) this.navigateToCampaignAction(campaign, safeUrl);\n }\n });\n return btn;\n }\n\n private addCloseButton(container: HTMLElement, overlay: HTMLElement, campaignId: string): void {\n const close = document.createElement('div');\n close.style.cssText = 'margin-top: 12px; font-size: 12px; opacity: 0.6; cursor: pointer;';\n close.textContent = 'Close';\n close.addEventListener('click', () => {\n this.trackEvent(campaignId, 'dismissed');\n this.removeModal(overlay);\n });\n container.appendChild(close);\n }\n \n /**\n * Navigate to a campaign CTA URL.\n *\n * Dispatches a cancellable `aegis:campaign-click` CustomEvent so host\n * apps (e.g., the storefront SPA) can intercept and route in-place via\n * their client-side router, avoiding a full page reload that re-runs\n * SSR + re-renders the location picker / banner / cart drawer state.\n *\n * The host calls `event.preventDefault()` to suppress the hard nav and\n * handle the URL itself. If no listener calls preventDefault, the SDK\n * falls through to `window.location.href` so plain HTML pages without a\n * SPA still get the user to the destination.\n *\n * Industry parallel: CleverTap dispatches `clevertap-deeplink-click`,\n * MoEngage dispatches `MoE_inappRedirect`. The pattern lets the same\n * SDK serve both vanilla websites (full nav fallback) and SPAs\n * (in-place state change) without per-host configuration.\n */\n private navigateToCampaignAction(\n campaign: InAppCampaign,\n safeUrl: string,\n buttonId: string = 'cta',\n ): void {\n if (typeof window === 'undefined') return;\n\n // Phase-2 action verbs — `aegis://<verb>` performs an in-app action\n // (dismiss / request push permission / add to cart) instead of navigating.\n if (safeUrl.startsWith('aegis://')) {\n this.runCampaignActionVerb(campaign, safeUrl);\n return;\n }\n\n // Typed lifecycle hook (1.8.0). Mirror the DOM `preventDefault` contract\n // — a handler returning `false` OR mutating `defaultPrevented` via the\n // helper suppresses the SDK's hard-nav. Built first so handlers attached\n // via the typed API see the click before the DOM event fires.\n let typedDefaultPrevented = false;\n const typedEvent: CampaignClickEvent = {\n campaign,\n action_url: safeUrl,\n button_id: buttonId,\n preventDefault: () => {\n typedDefaultPrevented = true;\n typedEvent.defaultPrevented = true;\n },\n defaultPrevented: false,\n };\n const typedProceed = this.emit('campaign-click', typedEvent);\n\n // DOM CustomEvent path — preserved for backward compat (1.7.x consumers\n // already listen for `aegis:campaign-click`) and for advanced patterns\n // (multi-frame embeds, host-app code that runs before the SDK is\n // instantiated, debugging via DevTools event listener panel).\n const domEvent = new CustomEvent('aegis:campaign-click', {\n detail: {\n campaign_id: campaign.id,\n campaign_type: campaign.type,\n action_url: safeUrl,\n button_id: buttonId,\n },\n cancelable: true,\n });\n const domProceed = window.dispatchEvent(domEvent);\n\n // Either path can suppress the hard-nav. We OR the prevent signals so\n // host apps don't have to remember to handle both — registering on\n // either API is enough.\n const suppressed =\n !typedProceed ||\n typedDefaultPrevented ||\n !domProceed ||\n domEvent.defaultPrevented;\n\n if (!suppressed) {\n window.location.href = safeUrl;\n }\n }\n\n /**\n * Phase-2 CTA action verbs (`aegis://<verb>?<params>`). Performs an in-app\n * behaviour instead of navigating. Verbs:\n * dismiss — close the message (tracked as dismissed)\n * request-push — prompt for web-push permission, then close\n * cart-add?sku=X — dispatch `aegis:cart-add` for the storefront to handle;\n * if unhandled, fall back to the product page\n */\n private runCampaignActionVerb(campaign: InAppCampaign, url: string): void {\n const rest = url.slice('aegis://'.length);\n const [verb, qs] = rest.split('?');\n const params = new URLSearchParams(qs || '');\n\n switch (verb) {\n case 'dismiss':\n void this.trackEvent(campaign.id, 'dismissed', { meta: { reason: 'cta' } });\n this.removeCampaignEl(campaign.id);\n break;\n\n case 'request-push':\n void this.trackEvent(campaign.id, 'clicked', { meta: { verb: 'request-push' } });\n if (\n typeof Notification !== 'undefined' &&\n typeof Notification.requestPermission === 'function'\n ) {\n void Promise.resolve(Notification.requestPermission()).then((perm) => {\n void this.trackEvent(campaign.id, 'clicked', { meta: { permission: perm } });\n });\n }\n this.removeCampaignEl(campaign.id);\n break;\n\n case 'cart-add': {\n const sku = params.get('sku') || '';\n void this.trackEvent(campaign.id, 'clicked', { meta: { verb: 'cart-add', sku } });\n const evt = new CustomEvent('aegis:cart-add', {\n detail: { sku, qty: 1, campaign_id: campaign.id },\n cancelable: true,\n });\n const proceed = window.dispatchEvent(evt);\n // Storefront didn't handle it → land on the product page as a fallback.\n if (proceed && !evt.defaultPrevented && sku) {\n window.location.href = `/p/${encodeURIComponent(sku)}`;\n }\n break;\n }\n\n default:\n this.log(`Unknown campaign action verb: ${verb}`, 'warn');\n }\n }\n\n /** Remove a rendered campaign's element(s) from the DOM by campaign id. */\n private removeCampaignEl(campaignId: string): void {\n if (typeof document === 'undefined') return;\n document\n .querySelectorAll(`[data-campaign-id=\"${campaignId}\"]`)\n .forEach((el) => el.parentNode?.removeChild(el));\n }\n\n /**\n * Resolve the operator's colour + style choices into concrete CSS values.\n * Mirrors the studio preview's styleFrom() 1:1 (apps/web/src/app/api/preview/\n * in-app/route.tsx) — same keys, same defaults — so what the operator designs\n * in the editor is what the live SDK renders. The container uses the\n * campaign's background_color/text_color and the CTA button is the inverse\n * (so it pops on the coloured surface), exactly like the preview. Earlier the\n * card renderers hardcoded a white card + dark text and ignored the Style\n * panel entirely, so the live message looked nothing like the preview.\n */\n /** Pick a legible label colour (#fff or near-black) for a solid fill, by\n * relative luminance — so a brand-accent button is always readable. */\n private _contrastText(hex: string): string {\n const m = /^#?([0-9a-fA-F]{6})$/.exec(this.sanitizeColor(hex));\n if (!m) return '#ffffff';\n const n = parseInt(m[1], 16);\n const L = (0.299 * ((n >> 16) & 255) + 0.587 * ((n >> 8) & 255) + 0.114 * (n & 255)) / 255;\n return L > 0.62 ? '#0f172a' : '#ffffff';\n }\n\n /** Central surface palette — the ONE place the brand colour becomes either a\n * surface fill or an accent, so every widget is consistent.\n *\n * `surface_style` (interactive_config), default `clean`:\n * - `clean` → NEUTRAL surface (white) + dark text + the brand colour as the\n * CTA ACCENT. The 60-30-10 / WCAG-safe default: legible copy and\n * a CTA that actually pops (higher CTR than a flat colour card).\n * - `branded`→ brand-colour SURFACE + contrasting text + inverse CTA. For\n * high-impact, low-text moments (flash sale, celebration).\n * `background_color` is the operator's brand colour in BOTH modes — surface\n * fill when branded, CTA accent when clean. */\n private _surfacePalette(campaign: InAppCampaign): {\n bg: string; text: string; btnBg: string; btnText: string; accent: string; branded: boolean;\n } {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const brand = this.sanitizeColor(campaign.background_color || '#4169e1');\n const branded = (ic.surface_style as string) === 'branded';\n if (branded) {\n const bg = brand;\n const text = campaign.text_color ? this.sanitizeColor(campaign.text_color) : '#ffffff';\n return { bg, text, btnBg: text, btnText: bg, accent: text, branded: true };\n }\n return { bg: '#ffffff', text: '#0f172a', btnBg: brand, btnText: this._contrastText(brand), accent: brand, branded: false };\n }\n\n private inAppStyle(campaign: InAppCampaign): {\n bg: string; text: string; btnBg: string; btnText: string; accent: string;\n radius: number; btnRadius: number; padX: number; padY: number;\n weight: string; mediaHeight: number; overlay: number;\n } {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const numOr = (v: unknown, d: number): number => {\n const n = Number(v);\n return Number.isFinite(n) ? n : d;\n };\n const p = this._surfacePalette(campaign);\n return {\n bg: p.bg,\n text: p.text,\n btnBg: p.btnBg,\n btnText: p.btnText,\n accent: p.accent,\n radius: numOr(ic.border_radius, 16),\n btnRadius: numOr(ic.button_radius, 999),\n padX: numOr(ic.padding_x, 24),\n padY: numOr(ic.padding_y, 24),\n weight: String((ic.heading_font_weight as string | number) || '700'),\n mediaHeight: numOr(ic.media_height, 160),\n // 0–100 in the Style panel → 0–1 alpha for the backdrop dim.\n overlay: numOr(ic.overlay_opacity, 50) / 100,\n };\n }\n\n private renderBanner(campaign: InAppCampaign): void {\n const banner = document.createElement('div');\n banner.className = 'aegis-in-app-banner';\n banner.setAttribute('data-campaign-id', campaign.id);\n\n // Honor the studio Style-panel padding so the live strip matches the\n // editor preview. Other knobs (border_radius) are N/A for an edge-to-edge\n // top strip.\n const st = this.inAppStyle(campaign);\n const padY = st.padY;\n const padX = st.padX;\n const ic = (campaign.interactive_config as Record<string, unknown> | undefined) || {};\n const atBottom = (ic.banner_position as string) === 'bottom';\n\n banner.style.cssText = `\n position: fixed;\n ${atBottom ? 'bottom: 0;' : 'top: 0;'}\n left: 0;\n right: 0;\n background: ${st.bg};\n color: ${st.text};\n padding: ${padY}px ${padX}px;\n z-index: 999999;\n box-shadow: 0 ${atBottom ? '-2px' : '2px'} 8px rgba(0,0,0,0.1);\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: ${atBottom ? 'aegisSlideInFromBottom' : 'aegisSlideDown'} 0.3s ease-out;\n `;\n // Tag the anchor so removeBanner can mirror the exit direction (a bottom\n // banner must slide DOWN out, a top banner UP out).\n banner.setAttribute('data-banner-position', atBottom ? 'bottom' : 'top');\n \n const contentContainer = document.createElement('div');\n contentContainer.style.cssText = 'flex: 1; display: flex; align-items: center; gap: 12px;';\n \n if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 40px; height: 40px; border-radius: 4px; object-fit: cover;';\n contentContainer.appendChild(img);\n }\n }\n \n const textContainer = document.createElement('div');\n textContainer.style.cssText = 'flex: 1;';\n \n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = `font-weight: ${st.weight}; font-size: 14px; margin-bottom: 4px;`;\n textContainer.appendChild(title);\n\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 13px; opacity: 0.9;';\n textContainer.appendChild(body);\n\n contentContainer.appendChild(textContainer);\n\n const actionsContainer = document.createElement('div');\n actionsContainer.style.cssText = 'display: flex; align-items: center; gap: 12px; margin-left: 16px;';\n\n // CTA renders whenever it's LABELLED (was hidden unless BOTH set).\n const bannerCtaLabel = campaign.button_text || (campaign.action_url ? 'Learn more' : '');\n if (bannerCtaLabel) {\n const ctaButton = document.createElement('button');\n ctaButton.className = 'aegis-cta';\n ctaButton.textContent = bannerCtaLabel;\n ctaButton.style.cssText = `\n background: ${st.btnBg};\n color: ${st.btnText};\n border: none;\n padding: 8px 16px;\n border-radius: ${st.btnRadius}px;\n font-weight: 600;\n cursor: pointer;\n font-size: 13px;\n white-space: nowrap;\n `;\n\n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (campaign.action_url) {\n const safeUrl = this.sanitizeUrl(campaign.action_url);\n if (safeUrl) this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeBanner(banner);\n });\n\n actionsContainer.appendChild(ctaButton);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n background: transparent;\n border: none;\n color: inherit;\n font-size: 20px;\n cursor: pointer;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n opacity: 0.7;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeBanner(banner);\n });\n \n actionsContainer.appendChild(closeButton);\n \n banner.appendChild(contentContainer);\n banner.appendChild(actionsContainer);\n\n this.addAnimationStyles();\n document.body.appendChild(banner);\n\n // Optional auto-hide after N ms (0 / absent = stays until dismissed).\n const autoMs = Number(ic.banner_auto_dismiss_ms) || 0;\n if (autoMs > 0) {\n window.setTimeout(() => { if (banner.parentNode) this.removeBanner(banner); }, autoMs);\n }\n }\n\n private renderModal(campaign: InAppCampaign): void {\n const st = this.inAppStyle(campaign);\n const ic = (campaign.interactive_config as Record<string, unknown> | undefined) || {};\n const videoUrl = campaign.video_url || (ic.video_url as string | undefined);\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-modal-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, ${st.overlay});\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n\n const modal = document.createElement('div');\n modal.className = 'aegis-in-app-modal';\n modal.style.cssText = `\n background: ${st.bg};\n color: ${st.text};\n border-radius: ${st.radius}px;\n max-width: 500px;\n width: 90%;\n max-height: 80vh;\n overflow: auto;\n box-shadow: 0 16px 48px rgba(0,0,0,0.22);\n animation: aegisScaleIn 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n\n // Hero media — a VIDEO (was authored-but-unrendered: modal ignored video_url)\n // or an image. Both fill the top media band with rounded top corners.\n if (videoUrl) {\n const mediaWrap = document.createElement('div');\n mediaWrap.style.cssText = `position: relative; width: 100%; height: ${st.mediaHeight}px; overflow: hidden; border-radius: ${st.radius}px ${st.radius}px 0 0; background: #000;`;\n this._heroVideo(videoUrl, campaign.image_url, mediaWrap, 'bottom-left');\n modal.appendChild(mediaWrap);\n } else if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = `width: 100%; height: ${st.mediaHeight}px; object-fit: cover; border-radius: ${st.radius}px ${st.radius}px 0 0;`;\n modal.appendChild(img);\n }\n }\n\n const content = document.createElement('div');\n content.style.cssText = `padding: ${st.padY}px ${st.padX}px;`;\n\n const title = document.createElement('h2');\n title.textContent = campaign.title;\n title.style.cssText = `margin: 0 0 12px 0; font-size: 20px; font-weight: ${st.weight}; color: ${st.text};`;\n content.appendChild(title);\n\n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = `margin: 0 0 20px 0; font-size: 15px; line-height: 1.5; color: ${st.text}; opacity: 0.9;`;\n content.appendChild(body);\n\n const actions = document.createElement('div');\n actions.style.cssText = 'display: flex; gap: 12px; justify-content: flex-end; align-items: center;';\n\n // Optional secondary CTA (\"No thanks\") before the primary.\n const secondaryText = ic.modal_secondary_text as string | undefined;\n if (secondaryText) {\n const secondaryUrl = ic.modal_secondary_url as string | undefined;\n const sec = document.createElement('button');\n sec.type = 'button';\n sec.textContent = secondaryText;\n sec.style.cssText = `background: transparent; border: 1px solid ${st.text}55; color: ${st.text}; opacity: 0.8; padding: 10px 24px; border-radius: ${st.btnRadius}px; font-weight: 600; cursor: pointer; font-size: 14px;`;\n sec.addEventListener('click', () => {\n if (secondaryUrl) {\n this.trackEvent(campaign.id, 'clicked', { meta: { action: 'secondary' } });\n const safe = this.sanitizeUrl(secondaryUrl);\n if (safe) { this.navigateToCampaignAction(campaign, safe); this.removeModal(overlay); return; }\n }\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n actions.appendChild(sec);\n }\n\n // Primary CTA — render whenever it's LABELLED (was hidden unless BOTH\n // button_text AND action_url were set). No URL → just dismiss.\n const ctaLabel = campaign.button_text || (campaign.action_url ? 'Continue' : '');\n if (ctaLabel) {\n const ctaButton = document.createElement('button');\n ctaButton.className = 'aegis-cta';\n ctaButton.textContent = ctaLabel;\n ctaButton.style.cssText = `\n background: ${st.btnBg};\n color: ${st.btnText};\n border: none;\n padding: 10px 24px;\n border-radius: ${st.btnRadius}px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n\n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (campaign.action_url) {\n const safeUrl = this.sanitizeUrl(campaign.action_url);\n if (safeUrl) this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n\n actions.appendChild(ctaButton);\n }\n\n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: transparent;\n border: 1px solid ${st.text}55;\n color: ${st.text};\n opacity: 0.8;\n padding: 10px 24px;\n border-radius: ${st.btnRadius}px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n actions.appendChild(closeButton);\n\n content.appendChild(actions);\n modal.appendChild(content);\n overlay.appendChild(modal);\n\n // Dismiss on backdrop click (standard modal UX; default on). A click that\n // lands on the overlay itself — not the modal card — closes it.\n if (ic.modal_dismiss_on_overlay !== false) {\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n }\n });\n }\n\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n // Build a muted-autoplay-loop video with a tap-to-unmute pill (shared by the\n // pip + full-screen heroes). Returns the <video> (or null if no safe URL).\n private _heroVideo(\n url: string,\n poster: string | undefined,\n coverHost: HTMLElement,\n pillCorner: 'top-left' | 'bottom-left',\n ): HTMLVideoElement | null {\n const safe = this.sanitizeUrl(url);\n if (!safe) return null;\n const v = document.createElement('video');\n v.src = safe;\n v.muted = true; v.loop = true; v.autoplay = true; v.playsInline = true;\n v.setAttribute('playsinline', ''); v.setAttribute('webkit-playsinline', '');\n v.controls = false;\n if (poster) { const p = this.sanitizeUrl(poster); if (p) v.poster = p; }\n v.style.cssText = 'position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: #000;';\n coverHost.appendChild(v);\n const pill = document.createElement('button');\n pill.type = 'button';\n const sync = () => {\n pill.replaceChildren();\n const ic = document.createElement('span'); ic.style.fontSize = '13px'; ic.textContent = v.muted ? '🔇' : '🔊';\n pill.appendChild(ic);\n if (v.muted) { const t = document.createElement('span'); t.textContent = 'Tap for sound'; pill.appendChild(t); }\n };\n pill.style.cssText =\n `position: absolute; ${pillCorner === 'top-left' ? 'top: 16px; left: 16px;' : 'bottom: 16px; left: 16px;'} ` +\n 'display: inline-flex; align-items: center; gap: 6px; background: rgba(0,0,0,0.6); color: #fff; border: none; ' +\n 'border-radius: 999px; padding: 6px 11px; font-size: 11.5px; font-weight: 700; cursor: pointer; z-index: 3; backdrop-filter: blur(3px);';\n pill.setAttribute('aria-label', 'Toggle sound');\n pill.addEventListener('click', (e) => { e.stopPropagation(); v.muted = !v.muted; if (!v.muted && v.paused) void v.play().catch(() => {}); sync(); });\n v.addEventListener('volumechange', sync);\n sync();\n coverHost.appendChild(pill);\n void v.play().catch(() => {});\n return v;\n }\n\n private renderFullScreen(campaign: InAppCampaign): void {\n const st = this.inAppStyle(campaign);\n const ic = (campaign.interactive_config as Record<string, unknown> | undefined) || {};\n const videoUrl = campaign.video_url || (ic.video_url as string | undefined);\n const hasMedia = !!(videoUrl || campaign.image_url);\n // Full-bleed background when there's media (the modern takeover look),\n // centered text otherwise. Operator can force either via fullscreen_layout.\n const layout = (ic.fullscreen_layout as string) || (hasMedia ? 'background' : 'centered');\n const isBg = layout === 'background' && hasMedia;\n const contentColor = isBg ? '#ffffff' : st.text;\n\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-fullscreen-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n overlay.style.cssText = `\n position: fixed; inset: 0; background: ${st.bg}; color: ${st.text};\n z-index: 1000001; display: flex; flex-direction: column; align-items: center;\n justify-content: ${isBg ? 'flex-end' : 'center'}; padding: ${isBg ? '0' : '40px 20px'};\n animation: aegisFadeIn 0.3s ease-out; overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n\n if (isBg) {\n // ── Full-bleed media + gradient scrim ──\n const media = document.createElement('div');\n media.style.cssText = 'position: absolute; inset: 0; z-index: 0; background: #000;';\n if (videoUrl) {\n this._heroVideo(videoUrl, campaign.image_url, media, 'top-left');\n } else if (campaign.image_url) {\n const safe = this.sanitizeUrl(campaign.image_url);\n if (safe) {\n const img = document.createElement('img');\n img.src = safe; img.alt = '';\n img.style.cssText = 'position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;';\n media.appendChild(img);\n }\n }\n const scrim = document.createElement('div');\n scrim.style.cssText = 'position: absolute; inset: 0; z-index: 1; background: linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.35) 42%, rgba(0,0,0,0.05) 100%);';\n media.appendChild(scrim);\n overlay.appendChild(media);\n } else if (videoUrl) {\n // Centered layout with a contained video (was authored-but-unrendered).\n const wrap = document.createElement('div');\n wrap.style.cssText = 'position: relative; width: min(100%, 560px); aspect-ratio: 16/9; margin-bottom: 32px; border-radius: 14px; overflow: hidden; background: #000;';\n this._heroVideo(videoUrl, campaign.image_url, wrap, 'bottom-left');\n overlay.appendChild(wrap);\n } else if (campaign.image_url) {\n const safe = this.sanitizeUrl(campaign.image_url);\n if (safe) {\n const img = document.createElement('img');\n img.src = safe; img.alt = '';\n img.style.cssText = 'max-width: 100%; max-height: 40vh; object-fit: contain; margin-bottom: 32px;';\n overlay.appendChild(img);\n }\n }\n\n // ── Content ──\n const contentContainer = document.createElement('div');\n contentContainer.style.cssText = isBg\n ? `position: relative; z-index: 2; max-width: 640px; width: 100%; box-sizing: border-box; text-align: center; padding: 0 24px 52px; color: ${contentColor}; animation: aegisFadeIn 0.45s ease-out 0.1s both;`\n : 'max-width: 600px; text-align: center;';\n\n const title = document.createElement('h1');\n title.textContent = campaign.title;\n title.style.cssText = `margin: 0 0 16px 0; font-size: ${isBg ? '30px' : '32px'}; font-weight: ${st.weight}; color: ${contentColor};` + (isBg ? ' text-shadow: 0 2px 12px rgba(0,0,0,0.4);' : '');\n contentContainer.appendChild(title);\n\n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = `margin: 0 0 28px 0; font-size: ${isBg ? '16px' : '18px'}; line-height: 1.6; opacity: 0.92; color: ${contentColor};`;\n contentContainer.appendChild(body);\n\n // Render the primary CTA whenever it's LABELLED — don't require an\n // action_url (a labelled button with no URL just dismisses). Requiring both\n // silently hid the button, so a takeover with copy but no chosen link showed\n // no CTA at all. Fall back to a sensible label if only the URL is set.\n const fsCtaLabel = campaign.button_text || (campaign.action_url ? 'Continue' : '');\n if (fsCtaLabel) {\n const ctaButton = document.createElement('button');\n ctaButton.className = 'aegis-cta';\n ctaButton.textContent = fsCtaLabel;\n ctaButton.style.cssText = `\n background: ${st.btnBg}; color: ${st.btnText}; border: none;\n padding: 16px 48px; border-radius: ${st.btnRadius}px; font-weight: 700;\n font-size: 18px; cursor: pointer; display: block; margin: 0 auto 12px;\n `;\n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (campaign.action_url) {\n const safeUrl = this.sanitizeUrl(campaign.action_url);\n if (safeUrl) this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n contentContainer.appendChild(ctaButton);\n }\n\n // Secondary CTA / dismiss link — a subtle second action (\"No thanks\").\n const secondaryText = ic.fullscreen_secondary_text as string | undefined;\n if (secondaryText) {\n const secondaryUrl = ic.fullscreen_secondary_url as string | undefined;\n const sec = document.createElement('button');\n sec.type = 'button';\n sec.textContent = secondaryText;\n sec.style.cssText = `background: transparent; border: none; color: ${contentColor}; opacity: 0.75; font-size: 14px; font-weight: 600; cursor: pointer; padding: 8px; display: block; margin: 0 auto; text-decoration: underline;`;\n sec.addEventListener('click', () => {\n if (secondaryUrl) {\n this.trackEvent(campaign.id, 'clicked', { meta: { action: 'secondary' } });\n const safe = this.sanitizeUrl(secondaryUrl);\n if (safe) { this.navigateToCampaignAction(campaign, safe); this.removeModal(overlay); return; }\n }\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n contentContainer.appendChild(sec);\n }\n\n overlay.appendChild(contentContainer);\n\n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute; top: 20px; right: 20px; z-index: 3; background: ${isBg ? 'rgba(0,0,0,0.45)' : 'transparent'};\n border: none; color: ${isBg ? '#fff' : 'inherit'}; font-size: ${isBg ? '20px' : '32px'}; cursor: pointer;\n padding: 0; width: ${isBg ? '36px' : '48px'}; height: ${isBg ? '36px' : '48px'}; border-radius: 50%;\n display: flex; align-items: center; justify-content: center; opacity: ${isBg ? '0.9' : '0.6'};\n `;\n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n overlay.appendChild(closeButton);\n\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n private renderHalfInterstitial(campaign: InAppCampaign): void {\n const st = this.inAppStyle(campaign);\n const ic = (campaign.interactive_config as Record<string, unknown> | undefined) || {};\n const videoUrl = campaign.video_url || (ic.video_url as string | undefined);\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-half-interstitial-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, ${st.overlay});\n z-index: 1000000;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n\n const modal = document.createElement('div');\n modal.className = 'aegis-in-app-half-interstitial';\n modal.style.cssText = `\n background: ${st.bg};\n color: ${st.text};\n border-radius: ${st.radius}px ${st.radius}px 0 0;\n width: 100%;\n max-width: 600px;\n max-height: 60vh;\n overflow: auto;\n box-shadow: 0 -4px 20px rgba(0,0,0,0.2);\n animation: aegisSlideUp 0.3s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n\n // Grabber — the bottom-sheet drag affordance (was missing; sheets read as\n // half-finished without it).\n const grabber = document.createElement('div');\n grabber.style.cssText = `width: 40px; height: 4px; border-radius: 2px; background: ${st.text}33; margin: 10px auto 0;`;\n modal.appendChild(grabber);\n\n // Hero media — a VIDEO (was image-only: video_url was ignored) or an image.\n if (videoUrl) {\n const mediaWrap = document.createElement('div');\n mediaWrap.style.cssText = `position: relative; width: 100%; height: ${st.mediaHeight}px; overflow: hidden; margin-top: 10px; background: #000;`;\n this._heroVideo(videoUrl, campaign.image_url, mediaWrap, 'bottom-left');\n modal.appendChild(mediaWrap);\n } else if (campaign.image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(campaign.image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = `width: 100%; height: ${st.mediaHeight}px; object-fit: cover; margin-top: 10px;`;\n modal.appendChild(img);\n }\n }\n\n const content = document.createElement('div');\n content.style.cssText = `padding: ${st.padY}px ${st.padX}px;`;\n\n const title = document.createElement('h2');\n title.textContent = campaign.title;\n title.style.cssText = `margin: 0 0 12px 0; font-size: 24px; font-weight: ${st.weight}; color: ${st.text};`;\n content.appendChild(title);\n\n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = `margin: 0 0 24px 0; font-size: 16px; line-height: 1.5; color: ${st.text}; opacity: 0.9;`;\n content.appendChild(body);\n\n // Primary CTA — render whenever LABELLED (was hidden unless BOTH set).\n const halfCtaLabel = campaign.button_text || (campaign.action_url ? 'Continue' : '');\n if (halfCtaLabel) {\n const ctaButton = document.createElement('button');\n ctaButton.className = 'aegis-cta';\n ctaButton.textContent = halfCtaLabel;\n ctaButton.style.cssText = `\n background: ${st.btnBg};\n color: ${st.btnText};\n border: none;\n padding: 14px 32px;\n border-radius: ${st.btnRadius}px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n\n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (campaign.action_url) {\n const safeUrl = this.sanitizeUrl(campaign.action_url);\n if (safeUrl) this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n\n content.appendChild(ctaButton);\n }\n\n // Optional secondary CTA / dismiss link.\n const secondaryText = ic.half_secondary_text as string | undefined;\n if (secondaryText) {\n const secondaryUrl = ic.half_secondary_url as string | undefined;\n const sec = document.createElement('button');\n sec.type = 'button';\n sec.textContent = secondaryText;\n sec.style.cssText = `margin-top: 10px; background: transparent; border: none; color: ${st.text}; opacity: 0.75; font-weight: 600; font-size: 14px; cursor: pointer; width: 100%; text-decoration: underline;`;\n sec.addEventListener('click', () => {\n if (secondaryUrl) {\n this.trackEvent(campaign.id, 'clicked', { meta: { action: 'secondary' } });\n const safe = this.sanitizeUrl(secondaryUrl);\n if (safe) { this.navigateToCampaignAction(campaign, safe); this.removeModal(overlay); return; }\n }\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n content.appendChild(sec);\n }\n\n modal.appendChild(content);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: rgba(255,255,255,0.9);\n border: none;\n color: #333;\n font-size: 24px;\n cursor: pointer;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n\n overlay.appendChild(modal);\n\n // Dismiss on backdrop click (default on) — standard bottom-sheet behaviour.\n if (ic.half_dismiss_on_overlay !== false) {\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n }\n });\n }\n\n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n\n private renderAlert(campaign: InAppCampaign): void {\n const st = this.inAppStyle(campaign);\n const overlay = document.createElement('div');\n overlay.className = 'aegis-in-app-alert-overlay';\n overlay.setAttribute('data-campaign-id', campaign.id);\n\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, ${st.overlay});\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.2s ease-out;\n `;\n\n const alert = document.createElement('div');\n alert.className = 'aegis-in-app-alert';\n alert.style.cssText = `\n background: ${st.bg};\n color: ${st.text};\n border-radius: ${st.radius}px;\n max-width: 320px;\n width: 85%;\n box-shadow: 0 16px 48px rgba(0,0,0,0.22);\n animation: aegisScaleIn 0.2s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n overflow: hidden;\n `;\n\n const content = document.createElement('div');\n content.style.cssText = `padding: ${st.padY}px ${st.padX}px; text-align: center;`;\n\n // Tone icon badge — sets the emotional register of the alert at a glance.\n const ic = (campaign.interactive_config as Record<string, unknown> | undefined) || {};\n const variant = (ic.alert_variant as string) || '';\n const VARIANTS: Record<string, { glyph: string; color: string }> = {\n info: { glyph: 'ℹ', color: '#3b82f6' },\n success: { glyph: '✓', color: '#10b981' },\n warning: { glyph: '!', color: '#f59e0b' },\n error: { glyph: '✕', color: '#ef4444' },\n };\n const vspec = VARIANTS[variant];\n if (vspec) {\n const badge = document.createElement('div');\n badge.style.cssText = `width: 48px; height: 48px; border-radius: 50%; margin: 0 auto 12px; display: flex; align-items: center; justify-content: center; font-size: 24px; font-weight: 800; background: ${vspec.color}22; color: ${vspec.color};`;\n badge.textContent = vspec.glyph;\n content.appendChild(badge);\n }\n\n const title = document.createElement('h3');\n title.textContent = campaign.title;\n title.style.cssText = `margin: 0 0 8px 0; font-size: 18px; font-weight: ${st.weight}; color: ${st.text};`;\n content.appendChild(title);\n\n const body = document.createElement('p');\n body.textContent = campaign.body;\n body.style.cssText = `margin: 0; font-size: 14px; line-height: 1.4; color: ${st.text}; opacity: 0.85;`;\n content.appendChild(body);\n\n alert.appendChild(content);\n\n const buttonContainer = document.createElement('div');\n buttonContainer.style.cssText = `display: flex; gap: 8px; justify-content: center; padding: 0 ${st.padX}px ${st.padY}px;`;\n\n const alertCtaLabel = campaign.button_text || (campaign.action_url ? 'OK' : '');\n if (alertCtaLabel) {\n const ctaButton = document.createElement('button');\n ctaButton.className = 'aegis-cta';\n ctaButton.textContent = alertCtaLabel;\n ctaButton.style.cssText = `\n flex: 1;\n background: ${st.btnBg};\n color: ${st.btnText};\n border: none;\n border-radius: ${st.btnRadius}px;\n padding: 12px;\n font-weight: 600;\n font-size: 15px;\n cursor: pointer;\n `;\n\n ctaButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'clicked');\n if (campaign.action_url) {\n const safeUrl = this.sanitizeUrl(campaign.action_url);\n if (safeUrl) this.navigateToCampaignAction(campaign, safeUrl);\n }\n this.removeModal(overlay);\n });\n\n buttonContainer.appendChild(ctaButton);\n }\n\n const cancelButton = document.createElement('button');\n cancelButton.textContent = 'Cancel';\n cancelButton.style.cssText = `\n flex: 1;\n background: transparent;\n border: 1px solid ${st.text}55;\n color: ${st.text};\n opacity: 0.85;\n border-radius: ${st.btnRadius}px;\n padding: 12px;\n font-weight: 600;\n font-size: 15px;\n cursor: pointer;\n `;\n \n cancelButton.addEventListener('click', () => {\n this.trackEvent(campaign.id, 'dismissed');\n this.removeModal(overlay);\n });\n \n buttonContainer.appendChild(cancelButton);\n \n alert.appendChild(buttonContainer);\n overlay.appendChild(alert);\n \n this.addAnimationStyles();\n document.body.appendChild(overlay);\n }\n \n // Corner → fixed-position CSS for the floating PiP card.\n private _pipCornerCss(position: string, gap: number): string {\n switch (position) {\n case 'bottom-left':\n return `bottom: ${gap}px; left: ${gap}px;`;\n case 'top-right':\n return `top: ${gap}px; right: ${gap}px;`;\n case 'top-left':\n return `top: ${gap}px; left: ${gap}px;`;\n case 'bottom-right':\n default:\n return `bottom: ${gap}px; right: ${gap}px;`;\n }\n }\n\n private renderPIP(campaign: InAppCampaign): void {\n const ic = (campaign.interactive_config as Record<string, unknown> | undefined) || {};\n // Authored options — every one is additive; a legacy pip (none set) keeps\n // the old bottom-right, muted-autoplay, looping behaviour.\n const position = (ic.pip_position as string) || 'bottom-right';\n const size = (ic.pip_size as string) || 'standard';\n const autoplay = ic.pip_autoplay !== false; // default ON\n const loop = ic.pip_loop !== false; // default ON\n const startMuted = ic.pip_muted !== false; // default ON (browser autoplay needs it)\n const expandable = ic.pip_expandable !== false; // default ON\n const draggable = ic.pip_draggable === true; // default OFF\n\n const SIZE_W: Record<string, number> = { compact: 250, standard: 320, large: 400 };\n const gap = 20;\n const vw = typeof window !== 'undefined' ? window.innerWidth || 360 : 360;\n const cornerW = Math.min(SIZE_W[size] ?? 320, vw - gap * 2);\n\n const pip = document.createElement('div');\n pip.className = 'aegis-in-app-pip';\n pip.setAttribute('data-campaign-id', campaign.id);\n const cornerCss = this._pipCornerCss(position, gap);\n const slideAnim = position.startsWith('top') ? 'aegisSlideDown' : 'aegisSlideUp';\n pip.style.cssText = `\n position: fixed; ${cornerCss} width: ${cornerW}px; max-width: calc(100vw - ${gap * 2}px);\n background: #000; border-radius: 14px; overflow: hidden;\n box-shadow: 0 10px 30px rgba(0,0,0,0.38); z-index: 999999;\n animation: ${slideAnim} 0.3s ease-out; transition: width 0.25s ease, border-radius 0.25s ease;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n\n // ── Media (16:9) ──────────────────────────────────────────────────────\n const mediaWrap = document.createElement('div');\n mediaWrap.style.cssText = 'position: relative; width: 100%; background: #000; line-height: 0; aspect-ratio: 16 / 9;';\n\n const videoUrl =\n campaign.video_url || (ic.video_url as string | undefined);\n let video: HTMLVideoElement | null = null;\n let hasMedia = false;\n\n if (videoUrl) {\n const safe = this.sanitizeUrl(videoUrl);\n if (safe) {\n video = document.createElement('video');\n video.src = safe;\n video.muted = startMuted;\n video.loop = loop;\n video.autoplay = autoplay;\n video.playsInline = true;\n video.setAttribute('playsinline', '');\n video.setAttribute('webkit-playsinline', '');\n video.controls = false;\n if (campaign.image_url) {\n const poster = this.sanitizeUrl(campaign.image_url);\n if (poster) video.poster = poster;\n }\n video.style.cssText = 'width: 100%; height: 100%; display: block; object-fit: cover; background: #000;';\n mediaWrap.appendChild(video);\n hasMedia = true;\n }\n } else if (campaign.image_url) {\n const safe = this.sanitizeUrl(campaign.image_url);\n if (safe) {\n const img = document.createElement('img');\n img.src = safe;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 100%; display: block; object-fit: cover;';\n mediaWrap.appendChild(img);\n hasMedia = true;\n }\n }\n\n if (!hasMedia) {\n const placeholder = document.createElement('div');\n placeholder.style.cssText =\n 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #1f2937, #0f172a); color: rgba(255,255,255,0.35); font-size: 34px;';\n placeholder.textContent = '▶';\n mediaWrap.appendChild(placeholder);\n }\n pip.appendChild(mediaWrap);\n\n // ── Video controls: tap-to-play/pause + unmute pill ───────────────────\n if (video) {\n const v = video;\n // Center play/pause glyph that fades after each toggle.\n const playGlyph = document.createElement('button');\n playGlyph.type = 'button';\n playGlyph.setAttribute('aria-label', 'Play or pause');\n playGlyph.style.cssText =\n 'position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 52px; height: 52px; border-radius: 50%; border: none; background: rgba(0,0,0,0.45); color: #fff; font-size: 22px; cursor: pointer; display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.25s ease; backdrop-filter: blur(2px);';\n const syncGlyph = () => {\n playGlyph.textContent = v.paused ? '▶' : '❚❚';\n playGlyph.style.opacity = v.paused ? '1' : '0';\n };\n const togglePlay = () => {\n if (v.paused) void v.play().catch(() => {});\n else v.pause();\n };\n playGlyph.addEventListener('click', (e) => { e.stopPropagation(); togglePlay(); });\n mediaWrap.addEventListener('click', togglePlay);\n v.addEventListener('play', () => { syncGlyph(); setTimeout(() => { if (!v.paused) playGlyph.style.opacity = '0'; }, 600); });\n v.addEventListener('pause', syncGlyph);\n mediaWrap.appendChild(playGlyph);\n\n // Unmute pill — autoplay must start muted, so the sound affordance is the\n // single most important PiP interaction. Prominent when muted.\n const mutePill = document.createElement('button');\n mutePill.type = 'button';\n const syncMute = () => {\n mutePill.replaceChildren();\n const ic = document.createElement('span'); ic.style.fontSize = '13px'; ic.textContent = v.muted ? '🔇' : '🔊';\n mutePill.appendChild(ic);\n if (v.muted) { const t = document.createElement('span'); t.textContent = 'Tap for sound'; mutePill.appendChild(t); }\n mutePill.style.padding = v.muted ? '6px 11px' : '6px 9px';\n };\n mutePill.style.cssText =\n 'position: absolute; left: 10px; bottom: 10px; display: inline-flex; align-items: center; gap: 6px; background: rgba(0,0,0,0.6); color: #fff; border: none; border-radius: 999px; font-size: 11.5px; font-weight: 700; cursor: pointer; z-index: 3; backdrop-filter: blur(3px);';\n mutePill.setAttribute('aria-label', 'Toggle sound');\n mutePill.addEventListener('click', (e) => {\n e.stopPropagation();\n v.muted = !v.muted;\n if (!v.muted && v.paused) void v.play().catch(() => {});\n syncMute();\n });\n v.addEventListener('volumechange', syncMute);\n syncMute();\n mediaWrap.appendChild(mutePill);\n\n if (autoplay) void v.play().catch(() => {});\n }\n\n // ── Text + CTA overlay ────────────────────────────────────────────────\n const st = this.inAppStyle(campaign);\n const accent = st.btnBg;\n const accentText = st.btnText;\n const overlay = document.createElement('div');\n overlay.style.cssText =\n 'position: absolute; bottom: 0; left: 0; right: 0; background: linear-gradient(to top, rgba(0,0,0,0.92), rgba(0,0,0,0.2) 70%, transparent); padding: 36px 14px 13px; color: #fff; pointer-events: none;';\n\n if (campaign.title) {\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-size: 14px; font-weight: 700; margin-bottom: 3px; line-height: 1.25;';\n overlay.appendChild(title);\n }\n if (campaign.body) {\n const body = document.createElement('div');\n body.textContent = campaign.body;\n body.style.cssText = 'font-size: 12px; opacity: 0.9; line-height: 1.35;';\n overlay.appendChild(body);\n }\n\n // Real CTA button (was a whole-card click → easy mis-tap on the close X).\n if (campaign.action_url && campaign.button_text) {\n const cta = document.createElement('button');\n cta.type = 'button';\n cta.textContent = campaign.button_text;\n cta.style.cssText = `pointer-events: auto; margin-top: 10px; padding: 8px 18px; border-radius: 999px; border: none; background: ${accent}; color: ${accentText}; font-weight: 800; font-size: 12.5px; cursor: pointer;`;\n cta.addEventListener('click', (e) => {\n e.stopPropagation();\n this.trackEvent(campaign.id, 'clicked');\n const safe = this.sanitizeUrl(campaign.action_url!);\n if (safe) this.navigateToCampaignAction(campaign, safe);\n });\n overlay.appendChild(cta);\n }\n pip.appendChild(overlay);\n\n // ── Top-right controls: expand + close ────────────────────────────────\n const controls = document.createElement('div');\n controls.style.cssText = 'position: absolute; top: 8px; right: 8px; display: flex; gap: 6px; z-index: 4;';\n\n const ctrlBtnCss =\n 'background: rgba(0,0,0,0.6); border: none; color: #fff; font-size: 14px; cursor: pointer; width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; backdrop-filter: blur(3px);';\n\n let expanded = false;\n let backdrop: HTMLElement | null = null;\n let expandBtn: HTMLButtonElement | null = null;\n const collapse = () => {\n expanded = false;\n if (backdrop) { backdrop.remove(); backdrop = null; }\n pip.style.position = 'fixed';\n pip.style.cssText = `\n position: fixed; ${cornerCss} width: ${cornerW}px; max-width: calc(100vw - ${gap * 2}px);\n background: #000; border-radius: 14px; overflow: hidden;\n box-shadow: 0 10px 30px rgba(0,0,0,0.38); z-index: 999999; transition: none;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n if (expandBtn) { expandBtn.textContent = '⤢'; expandBtn.setAttribute('aria-label', 'Expand'); }\n };\n const expand = () => {\n expanded = true;\n this.trackEvent(campaign.id, 'impression', { meta: { action: 'pip_expand' } });\n backdrop = document.createElement('div');\n backdrop.style.cssText = 'position: fixed; inset: 0; background: rgba(0,0,0,0.72); z-index: 999998; animation: aegisFadeIn 0.2s ease-out;';\n backdrop.addEventListener('click', collapse);\n document.body.appendChild(backdrop);\n const theaterW = Math.min(760, vw - gap * 2);\n pip.style.cssText = `\n position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);\n width: ${theaterW}px; max-width: calc(100vw - ${gap * 2}px);\n background: #000; border-radius: 16px; overflow: hidden;\n box-shadow: 0 24px 60px rgba(0,0,0,0.55); z-index: 999999; transition: none;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n if (expandBtn) { expandBtn.textContent = '✕'; expandBtn.setAttribute('aria-label', 'Minimize'); }\n if (video && video.muted) { video.muted = false; video.dispatchEvent(new Event('volumechange')); }\n };\n\n if (expandable && hasMedia) {\n expandBtn = document.createElement('button');\n expandBtn.type = 'button';\n expandBtn.textContent = '⤢';\n expandBtn.setAttribute('aria-label', 'Expand');\n expandBtn.style.cssText = ctrlBtnCss;\n expandBtn.addEventListener('click', (e) => { e.stopPropagation(); if (expanded) collapse(); else expand(); });\n controls.appendChild(expandBtn);\n }\n\n const closeButton = document.createElement('button');\n closeButton.type = 'button';\n closeButton.textContent = '✕';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = ctrlBtnCss;\n closeButton.addEventListener('click', (e) => {\n e.stopPropagation();\n this.trackEvent(campaign.id, 'dismissed');\n if (backdrop) backdrop.remove();\n pip.style.animation = `${slideAnim === 'aegisSlideDown' ? 'aegisSlideUp' : 'aegisSlideDown'} 0.3s ease-out`;\n setTimeout(() => { if (pip.parentNode) pip.parentNode.removeChild(pip); }, 300);\n });\n controls.appendChild(closeButton);\n pip.appendChild(controls);\n\n // ── Optional drag-to-reposition (default off) ─────────────────────────\n if (draggable) {\n let dragging = false;\n let sx = 0, sy = 0, ox = 0, oy = 0;\n const onDown = (e: PointerEvent) => {\n if (expanded) return;\n const tgt = e.target as HTMLElement;\n if (tgt.closest('button')) return; // don't hijack control taps\n dragging = true;\n const rect = pip.getBoundingClientRect();\n ox = rect.left; oy = rect.top; sx = e.clientX; sy = e.clientY;\n pip.style.bottom = 'auto'; pip.style.right = 'auto';\n pip.style.left = `${ox}px`; pip.style.top = `${oy}px`;\n pip.setPointerCapture(e.pointerId);\n };\n const onMove = (e: PointerEvent) => {\n if (!dragging) return;\n const nx = Math.max(4, Math.min(vw - pip.offsetWidth - 4, ox + (e.clientX - sx)));\n const ny = Math.max(4, Math.min((window.innerHeight || 800) - pip.offsetHeight - 4, oy + (e.clientY - sy)));\n pip.style.left = `${nx}px`; pip.style.top = `${ny}px`;\n };\n const onUp = () => { dragging = false; };\n pip.addEventListener('pointerdown', onDown);\n pip.addEventListener('pointermove', onMove);\n pip.addEventListener('pointerup', onUp);\n pip.style.touchAction = 'none';\n }\n\n this.addAnimationStyles();\n document.body.appendChild(pip);\n this.trackEvent(campaign.id, 'impression');\n }\n \n private removeBanner(banner: HTMLElement): void {\n // Exit mirrors the entrance: bottom banner slides DOWN out, top banner UP.\n const atBottom = banner.getAttribute('data-banner-position') === 'bottom';\n banner.style.animation = `${atBottom ? 'aegisSlideOutToBottom' : 'aegisSlideUp'} 0.3s ease-out`;\n setTimeout(() => {\n if (banner.parentNode) {\n banner.parentNode.removeChild(banner);\n }\n }, 300);\n }\n \n private removeModal(overlay: HTMLElement): void {\n overlay.style.animation = 'aegisFadeOut 0.3s ease-out';\n setTimeout(() => {\n if (overlay.parentNode) {\n overlay.parentNode.removeChild(overlay);\n }\n }, 300);\n }\n \n /**\n * Spotlight backdrop colour → a dim of the chosen base at `dim` opacity.\n * `dark` (slate, default) · `brand` (the campaign brand colour) · `black` ·\n * `custom` (a picked hex). Encoded as 8-digit hex alpha; falls back to slate\n * rgba when the base isn't a 6-digit hex (e.g. an rgb() brand colour).\n */\n private _spotlightDimColor(ic: Record<string, unknown>, brand: string, dim: number): string {\n const mode = (ic.spotlight_dim_color as string) || 'dark';\n const base =\n mode === 'black' ? '#000000'\n : mode === 'brand' ? brand\n : mode === 'custom' ? this.sanitizeColor((ic.spotlight_dim_custom as string) || '#0f172a')\n : '#0f172a';\n const alpha = Math.round(Math.max(0, Math.min(1, dim)) * 255).toString(16).padStart(2, '0');\n return /^#[0-9a-fA-F]{6}$/.test(base) ? `${base}${alpha}` : `rgba(15,23,42,${dim})`;\n }\n\n private renderTooltip(campaign: InAppCampaign): void {\n const ic = (campaign.interactive_config || {}) as Record<string, unknown>;\n const anchorSelector = (ic.tooltip_anchor_selector as string) || '[data-aegis-tooltip]';\n const preferredPosition = (ic.tooltip_position as string) || 'auto'; // auto | top | bottom | left | right\n const highlightOn = ic.tooltip_highlight !== false; // default ON — ring the target\n\n let anchor = document.querySelector(anchorSelector);\n if (!anchor) {\n // Silent-anchor footgun: the tooltip's target isn't on this surface, so\n // nothing renders. Without a signal the operator sees zero impressions\n // and assumes the campaign simply didn't fire. Emit an always-on dev\n // warning + a dedicated `anchor_unresolved` event so the dashboard can\n // flag the misconfiguration. (Mobile anchors are registered keys, so the\n // same selector can resolve on web yet be unregistered on a native app —\n // see registerInAppAnchor.)\n console.warn(\n `[AegisInApp] Tooltip anchor \"${anchorSelector}\" not found on this surface — tooltip not shown. ` +\n `On native apps this must be a key registered via registerInAppAnchor(); adding a new anchor needs an app release.`,\n );\n void this.trackEvent(campaign.id, 'anchor_unresolved', {\n meta: { anchor_resolved: false, anchor_selector: anchorSelector, widget_type: 'tooltip' },\n });\n return;\n }\n\n const bg = this.sanitizeColor(campaign.background_color || '#1a1a1a');\n const textColor = this.sanitizeColor(campaign.text_color || '#ffffff');\n\n // Tooltip container (positioned absolute to body)\n const tooltip = document.createElement('div');\n tooltip.className = 'aegis-in-app-tooltip';\n tooltip.setAttribute('data-campaign-id', campaign.id);\n tooltip.style.cssText = `\n position: absolute; z-index: 1000001; max-width: 280px; width: max-content;\n background: ${bg}; color: ${textColor}; border-radius: 10px; padding: 14px 16px;\n box-shadow: 0 8px 24px rgba(0,0,0,0.18); font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.2s ease-out; pointer-events: auto;\n `;\n\n // Arrow\n const arrow = document.createElement('div');\n arrow.className = 'aegis-tooltip-arrow';\n arrow.style.cssText = `\n position: absolute; width: 10px; height: 10px; background: ${bg};\n transform: rotate(45deg);\n `;\n\n let highlightEl: HTMLElement | null = null;\n let outsideHandler: ((e: MouseEvent) => void) | null = null;\n // P5 — live re-resolution: scroll/resize listeners + observers are detached\n // here so a dismissed tooltip leaves nothing behind.\n let cleanupReflow: (() => void) | null = null;\n const dismiss = () => {\n tooltip.style.animation = 'aegisFadeOut 0.2s ease-out';\n if (highlightEl) { highlightEl.remove(); highlightEl = null; }\n if (outsideHandler) { document.removeEventListener('click', outsideHandler); outsideHandler = null; }\n if (cleanupReflow) { cleanupReflow(); cleanupReflow = null; }\n setTimeout(() => { tooltip.parentNode?.removeChild(tooltip); }, 200);\n this.trackEvent(campaign.id, 'dismissed');\n };\n\n // Close button \\u2014 a real hit area (was a ~9px glyph that was easy to miss).\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.textContent = '\\u00d7';\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.style.cssText = `\n position: absolute; top: 4px; right: 4px; z-index: 1; background: none; border: none;\n color: ${textColor}; opacity: 0.7; font-size: 16px; line-height: 1; cursor: pointer;\n width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; padding: 0;\n `;\n closeBtn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); dismiss(); });\n\n // Title\n if (campaign.title) {\n const title = document.createElement('div');\n title.textContent = campaign.title;\n title.style.cssText = 'font-size: 13px; font-weight: 700; margin-bottom: 4px; padding-right: 18px;';\n tooltip.appendChild(title);\n }\n\n // Body \\u2014 never blank (a tooltip with no copy reads as broken).\n const body = document.createElement('div');\n body.textContent = campaign.body || 'Here\\u2019s a quick tip.';\n body.style.cssText = 'font-size: 12px; line-height: 1.4; opacity: 0.9; padding-right: 18px;';\n tooltip.appendChild(body);\n\n // CTA button\n if (campaign.button_text && campaign.action_url) {\n const cta = document.createElement('a');\n cta.textContent = campaign.button_text;\n cta.href = campaign.action_url;\n cta.style.cssText = `\n display: inline-block; margin-top: 8px; font-size: 12px; font-weight: 600;\n color: ${textColor}; text-decoration: underline; cursor: pointer;\n `;\n cta.addEventListener('click', () => { this.trackEvent(campaign.id, 'clicked'); });\n tooltip.appendChild(cta);\n }\n\n tooltip.appendChild(closeBtn);\n tooltip.appendChild(arrow);\n document.body.appendChild(tooltip);\n\n // Highlight the target — a soft pulsing ring (the point of a tooltip is to\n // draw the eye to a specific element). Created once; repositioned live.\n // Spotlight (masked cutout) vs the legacy light ring. Spotlight dims the\n // whole screen except a transparent hole around the anchor.\n const spotlight = (ic.highlight_style as string) === 'spotlight';\n const spotPad = typeof ic.spotlight_padding === 'number' ? (ic.spotlight_padding as number) : (spotlight ? 6 : 4);\n const spotRadius = (ic.spotlight_shape as string) === 'circle' ? '50%' : '12px';\n const spotDim = typeof ic.spotlight_dim === 'number' ? Math.max(0, Math.min(95, ic.spotlight_dim as number)) / 100 : 0.64;\n // Backdrop colour: dark slate (default) · brand accent (the tooltip bg) ·\n // black · custom hex. Applied at the dim opacity via an 8-digit hex alpha.\n const dimColor = this._spotlightDimColor(ic, bg, spotDim);\n if (highlightOn) {\n highlightEl = document.createElement('div');\n highlightEl.className = 'aegis-tooltip-highlight';\n const shadow = spotlight\n ? `box-shadow: 0 0 0 3px rgba(255,255,255,0.92), 0 0 0 6px ${bg}66, 0 0 0 9999px ${dimColor};`\n : `box-shadow: 0 0 0 3px ${bg}55, 0 0 0 9999px rgba(0,0,0,0.04);`;\n // The opacity pulse is fine for the faint RING, but it would make the\n // spotlight's strong dim flicker/halve (it reads as broken) — so the\n // spotlight gets a STEADY dim (standard for masked spotlights).\n const anim = spotlight ? '' : 'animation: aegisTooltipPulse 1.6s ease-in-out infinite;';\n highlightEl.style.cssText =\n `position: absolute; z-index: 1000000; pointer-events: none; border-radius: ${spotlight ? spotRadius : '8px'}; ` +\n `${shadow} ${anim}`;\n document.body.appendChild(highlightEl);\n }\n\n // P5 — extra gap from interactive_config (`tooltip_offset`).\n const gap = 10 + (typeof ic.tooltip_offset === 'number' ? (ic.tooltip_offset as number) : 0);\n const OPP: Record<string, string> = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };\n\n // P5 — position relative to the (live) anchor. Re-run on scroll / resize /\n // layout shifts so the tooltip tracks the element instead of going stale.\n const reposition = (): void => {\n if (!anchor) return;\n const anchorRect = anchor.getBoundingClientRect();\n const tooltipRect = tooltip.getBoundingClientRect();\n const scrollX = window.scrollX, scrollY = window.scrollY;\n const vw = window.innerWidth, vh = window.innerHeight;\n if (highlightEl) {\n highlightEl.style.top = `${anchorRect.top + scrollY - spotPad}px`;\n highlightEl.style.left = `${anchorRect.left + scrollX - spotPad}px`;\n highlightEl.style.width = `${anchorRect.width + spotPad * 2}px`;\n highlightEl.style.height = `${anchorRect.height + spotPad * 2}px`;\n }\n const room = { bottom: vh - anchorRect.bottom, top: anchorRect.top, right: vw - anchorRect.right, left: anchorRect.left };\n const needV = tooltipRect.height + gap, needH = tooltipRect.width + gap;\n const fits = (s: string): boolean =>\n s === 'top' ? room.top >= needV : s === 'bottom' ? room.bottom >= needV\n : s === 'left' ? room.left >= needH : room.right >= needH;\n let side = preferredPosition;\n if (side === 'auto') {\n side = room.bottom >= needV ? 'bottom'\n : room.top >= needV ? 'top'\n : room.right >= needH ? 'right'\n : room.left >= needH ? 'left'\n : (room.bottom >= room.top ? 'bottom' : 'top');\n } else if (!fits(side) && fits(OPP[side])) {\n side = OPP[side];\n }\n let top = 0, left = 0;\n let arrowTop = '', arrowLeft = '', arrowBottom = '', arrowRight = '';\n switch (side) {\n case 'top':\n top = anchorRect.top + scrollY - tooltipRect.height - gap;\n left = anchorRect.left + scrollX + (anchorRect.width - tooltipRect.width) / 2;\n arrowBottom = '-5px'; arrowLeft = `${tooltipRect.width / 2 - 5}px`;\n break;\n case 'left':\n top = anchorRect.top + scrollY + (anchorRect.height - tooltipRect.height) / 2;\n left = anchorRect.left + scrollX - tooltipRect.width - gap;\n arrowRight = '-5px'; arrowTop = `${tooltipRect.height / 2 - 5}px`;\n break;\n case 'right':\n top = anchorRect.top + scrollY + (anchorRect.height - tooltipRect.height) / 2;\n left = anchorRect.right + scrollX + gap;\n arrowLeft = '-5px'; arrowTop = `${tooltipRect.height / 2 - 5}px`;\n break;\n default: // bottom\n top = anchorRect.bottom + scrollY + gap;\n left = anchorRect.left + scrollX + (anchorRect.width - tooltipRect.width) / 2;\n arrowTop = '-5px'; arrowLeft = `${tooltipRect.width / 2 - 5}px`;\n break;\n }\n left = Math.max(8, Math.min(left, vw + scrollX - tooltipRect.width - 8));\n top = Math.max(8 + scrollY, Math.min(top, vh + scrollY - tooltipRect.height - 8));\n tooltip.style.top = `${top}px`;\n tooltip.style.left = `${left}px`;\n arrow.style.top = arrowTop || '';\n arrow.style.left = arrowLeft || '';\n arrow.style.bottom = arrowBottom || '';\n arrow.style.right = arrowRight || '';\n };\n\n // P5 — runtime re-resolution: if the anchor leaves the DOM (SPA re-render),\n // re-query the selector; if it's truly gone, signal `anchor_unresolved` and\n // dismiss instead of leaving a tooltip pointing at nothing.\n const ensureAnchor = (): boolean => {\n if (anchor && anchor.isConnected) return true;\n const next = document.querySelector(anchorSelector);\n if (next) { anchor = next; return true; }\n void this.trackEvent(campaign.id, 'anchor_unresolved', {\n meta: { anchor_resolved: false, anchor_selector: anchorSelector, widget_type: 'tooltip', phase: 'runtime' },\n });\n dismiss();\n return false;\n };\n\n // rAF-debounced so a burst of mutations/scroll events coalesces to one paint.\n let rafId = 0;\n const onReflow = (): void => {\n if (rafId) return;\n rafId = window.requestAnimationFrame(() => {\n rafId = 0;\n if (ensureAnchor()) reposition();\n });\n };\n\n reposition();\n window.addEventListener('scroll', onReflow, { passive: true, capture: true });\n window.addEventListener('resize', onReflow, { passive: true });\n let ro: ResizeObserver | null = null;\n let mo: MutationObserver | null = null;\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(onReflow);\n if (anchor) ro.observe(anchor);\n ro.observe(document.documentElement);\n }\n if (typeof MutationObserver !== 'undefined') {\n mo = new MutationObserver(onReflow);\n mo.observe(document.body, { childList: true, subtree: true, attributes: true });\n }\n cleanupReflow = () => {\n if (rafId) { window.cancelAnimationFrame(rafId); rafId = 0; }\n window.removeEventListener('scroll', onReflow, { capture: true } as EventListenerOptions);\n window.removeEventListener('resize', onReflow);\n if (ro) { ro.disconnect(); ro = null; }\n if (mo) { mo.disconnect(); mo = null; }\n };\n\n // Dismiss on outside click (handler tracked so `dismiss()` can detach it too).\n outsideHandler = (e: MouseEvent) => {\n if (!tooltip.contains(e.target as Node) && !(anchor && anchor.contains(e.target as Node))) {\n dismiss();\n }\n };\n setTimeout(() => { if (outsideHandler) document.addEventListener('click', outsideHandler); }, 100);\n }\n\n /** Fire a short confetti burst from the top of an anchor element. Vanilla\n * (no deps) — mirrors the cashier-portal confetti. Respects\n * prefers-reduced-motion. Used on positive moments (high rating, won prize,\n * form complete). */\n private _fireConfetti(anchor?: HTMLElement): void {\n try {\n if (typeof window === 'undefined' || typeof document === 'undefined') return;\n if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\n return;\n }\n this.addAnimationStyles();\n const host = document.createElement('div');\n host.className = 'aegis-in-app-confetti';\n host.style.cssText =\n 'position: fixed; left: 0; right: 0; top: 0; height: 0; z-index: 2147483647; pointer-events: none;';\n const colors = ['#fbbf24', '#10b981', '#4169e1', '#ef4444', '#a855f7'];\n const n = 80;\n for (let i = 0; i < n; i++) {\n const p = document.createElement('span');\n const left = Math.round((i / n) * 100);\n const dx = Math.round((Math.random() - 0.5) * 240) + 'px';\n const r = Math.round(Math.random() * 1080) + 'deg';\n const delay = (Math.random() * 0.2).toFixed(2);\n const dur = (1.6 + Math.random() * 1.2).toFixed(2);\n const c = colors[i % colors.length];\n const size = 6 + Math.round(Math.random() * 6);\n p.style.cssText =\n `position: absolute; top: 0; left: ${left}%; width: ${size}px; height: ${size}px; ` +\n `background: ${c}; border-radius: 2px; --dx: ${dx}; --r: ${r}; ` +\n `animation: aegisConfetti ${dur}s cubic-bezier(.2,.6,.3,1) ${delay}s forwards;`;\n host.appendChild(p);\n }\n (anchor?.ownerDocument?.body || document.body).appendChild(host);\n window.setTimeout(() => host.remove(), 3200);\n } catch {\n /* confetti is decorative — never throw */\n }\n }\n\n /**\n * Emotional reaction layer (CEP parity — CleverTap exposes configurable\n * outcome animation; MoEngage sets distinct win/lose icons). Three CONTEXT-\n * AWARE intents drive a premium Lottie animation (with an instant SVG\n * placeholder + graceful fallback):\n *\n * - `celebrate` → a real WIN in a game (spin/scratch prize). Trophy Lottie,\n * gold rings, confetti. The big, earned moment.\n * - `affirm` → positive FEEDBACK (high rating, NPS promoter, quiz/form\n * done). An animated success check — friendly, NOT a trophy\n * (a survey isn't a contest).\n * - `empathize` → a negative outcome (low rating, NPS detractor, no-prize /\n * \"Try again\"). A soft breathing heart — supportive, NO\n * confetti, NO rings.\n *\n * Honors prefers-reduced-motion (static badge, no motion).\n */\n private _playReaction(\n host: HTMLElement | undefined,\n intent: 'celebrate' | 'affirm' | 'acknowledge' | 'empathize',\n lottieFile?: string,\n ic?: Record<string, unknown>,\n ): void {\n try {\n if (typeof document === 'undefined') return;\n this.addAnimationStyles();\n const reduce =\n typeof window !== 'undefined' &&\n window.matchMedia &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n const anchor = host || document.body;\n const prevPos = anchor.style.position;\n if (!prevPos || prevPos === 'static') anchor.style.position = 'relative';\n\n const layer = document.createElement('div');\n layer.className = 'aegis-in-app-reaction';\n layer.style.cssText =\n 'position: absolute; inset: 0; z-index: 2147483646; pointer-events: none; overflow: visible;';\n\n // intent → (Lottie file, SVG fallback variant, ring color, festive?).\n // `festive` = rings + confetti (an earned/delight moment). `acknowledge`\n // is the calm neutral band (NPS 7–8 / mid-★): a green tick, no fanfare.\n const SPEC = {\n celebrate: { file: 'trophy.json', svg: 'gift', ring: '#fbbf24', festive: true },\n affirm: { file: 'affirm.json', svg: 'star', ring: '#fbbf24', festive: true },\n acknowledge: { file: 'check.json', svg: 'check', ring: '#34d399', festive: false },\n empathize: { file: 'empathize.json', svg: 'heart', ring: '', festive: false },\n } as const;\n const spec = SPEC[intent];\n const festive = spec.festive;\n\n if (festive && !reduce) {\n for (let i = 0; i < 3; i++) {\n const ring = document.createElement('div');\n ring.style.cssText =\n `position: absolute; left: 50%; top: 50%; width: 60px; height: 60px; ` +\n `border-radius: 50%; border: 3px solid ${spec.ring}; ` +\n `animation: aegisRing 1.1s ease-out ${i * 0.18}s forwards;`;\n layer.appendChild(ring);\n }\n }\n\n const g = document.createElement('div');\n const reactionIcon = svgNode(this._reactionSvg(spec.svg)); // SDK-constant SVG\n if (reactionIcon) g.appendChild(reactionIcon);\n const motion = reduce\n ? ''\n : intent !== 'empathize'\n ? 'animation: aegisReactionPop 0.7s cubic-bezier(.2,.9,.3,1.2) forwards, aegisReactionFloatOut 0.7s ease-in 1.9s forwards;'\n : 'animation: aegisReactionSoft 0.9s ease-out forwards;';\n const px = festive ? 150 : intent === 'acknowledge' ? 92 : 124;\n g.style.cssText =\n `position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); ` +\n `width: ${px}px; height: ${px}px; ` +\n `display: flex; align-items: center; justify-content: center; ` +\n `line-height: 0; filter: drop-shadow(0 8px 16px rgba(0,0,0,0.30)); ${motion}`;\n layer.appendChild(g);\n anchor.appendChild(layer);\n\n // Confetti only on festive (earned/delight) moments — not the calm tick.\n if (festive && !reduce) this._fireConfetti(host);\n\n // Upgrade EVERY intent's badge to its premium Lottie (trophy for a win, an\n // animated check for feedback, a beating heart for empathy). The instant\n // SVG stays as the graceful fallback. The empathetic heart loops gently.\n // Resolution: operator's no-code custom animation (per intent) wins, then\n // the per-call default (e.g. scratch → gift), then the intent default.\n // A custom value is a full URL; the bundled defaults resolve under /sdk/lottie/.\n const ra = ic && typeof ic === 'object'\n ? (ic.reaction_animations as Record<string, string> | undefined)\n : undefined;\n const custom = ra && typeof ra[intent] === 'string' ? ra[intent] : undefined;\n const file = custom || lottieFile || spec.file;\n if (!reduce && file) {\n const base = this._assetBase();\n const loop = intent === 'empathize';\n const path = /^https?:\\/\\//.test(file) ? file : `${base}lottie/${file}`;\n this._loadLottie()\n .then((lot) => {\n if (!lot || !g.isConnected) return;\n g.replaceChildren();\n (lot as { loadAnimation: (o: Record<string, unknown>) => void }).loadAnimation({\n container: g,\n renderer: 'svg',\n loop,\n autoplay: true,\n path,\n });\n })\n .catch(() => { /* keep the SVG fallback */ });\n }\n\n window.setTimeout(\n () => {\n layer.remove();\n if (anchor.style.position !== prevPos) anchor.style.position = prevPos;\n },\n intent === 'acknowledge' ? 1800 : festive ? 2700 : 2200,\n );\n } catch {\n /* reactions are decorative — never throw */\n }\n }\n\n /** Hand-built, brand-neutral animated SVG badges for the reaction layer — a\n * premium alternative to system emoji (consistent across browsers, no Lottie\n * dependency). The check strokes itself in; the heart breathes gently. */\n private _reactionSvg(variant: string): string {\n switch (variant) {\n case 'star':\n return (\n '<svg width=\"74\" height=\"74\" viewBox=\"0 0 74 74\" fill=\"none\">' +\n '<circle cx=\"37\" cy=\"37\" r=\"31\" fill=\"#fbbf24\"/>' +\n '<circle cx=\"37\" cy=\"37\" r=\"31\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2\" opacity=\"0.6\"/>' +\n '<path d=\"M37 19 l5.6 11.8 13 1.7 -9.5 9 2.4 12.8 -11.5 -6.2 -11.5 6.2 2.4 -12.8 -9.5 -9 13 -1.7 Z\" ' +\n 'fill=\"#fff\"/></svg>'\n );\n case 'gift':\n return (\n '<svg width=\"74\" height=\"74\" viewBox=\"0 0 74 74\" fill=\"none\">' +\n '<circle cx=\"37\" cy=\"37\" r=\"31\" fill=\"#eef2ff\"/>' +\n '<rect x=\"20\" y=\"35\" width=\"34\" height=\"22\" rx=\"3\" fill=\"#6366f1\"/>' +\n '<rect x=\"17\" y=\"28\" width=\"40\" height=\"10\" rx=\"3\" fill=\"#4f46e5\"/>' +\n '<rect x=\"34\" y=\"28\" width=\"6\" height=\"29\" fill=\"#fbbf24\"/>' +\n '<path d=\"M34 28 C28 20 20 24 24 28 Z\" fill=\"#fbbf24\"/>' +\n '<path d=\"M40 28 C46 20 54 24 50 28 Z\" fill=\"#fbbf24\"/></svg>'\n );\n case 'heart':\n return (\n '<svg width=\"66\" height=\"66\" viewBox=\"0 0 66 66\" fill=\"none\" ' +\n 'style=\"animation: aegisBreathe 1.6s ease-in-out infinite; transform-origin: center;\">' +\n '<circle cx=\"33\" cy=\"33\" r=\"30\" fill=\"#f1f5f9\"/>' +\n '<path d=\"M33 49 C16 38 19 23 28 23 C32 23 33 27 33 27 C33 27 34 23 38 23 C47 23 50 38 33 49 Z\" ' +\n 'fill=\"rgba(244,114,182,0.18)\" stroke=\"#f472b6\" stroke-width=\"2.5\" stroke-linejoin=\"round\"/></svg>'\n );\n case 'check':\n default:\n return (\n '<svg width=\"74\" height=\"74\" viewBox=\"0 0 74 74\" fill=\"none\">' +\n '<circle cx=\"37\" cy=\"37\" r=\"31\" fill=\"#10b981\"/>' +\n '<circle cx=\"37\" cy=\"37\" r=\"31\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2\" opacity=\"0.6\"/>' +\n '<path d=\"M24 38 l9 9 l18 -21\" stroke=\"#fff\" stroke-width=\"6\" stroke-linecap=\"round\" ' +\n 'stroke-linejoin=\"round\" pathLength=\"100\" stroke-dasharray=\"100\" stroke-dashoffset=\"100\" ' +\n 'style=\"animation: aegisDraw 0.45s 0.25s ease forwards\"/></svg>'\n );\n }\n }\n\n /** Resolve the base URL the SDK assets are served from (so Lottie JSON +\n * player load from the same origin/path as the SDK bundle — works in the\n * dashboard preview and same-origin installs; cross-origin CDN installs fall\n * back to the inline SVG when the asset 404s). */\n private _assetBase(): string {\n try {\n const scripts = Array.from(document.getElementsByTagName('script'));\n const s = scripts.find((x) => /\\/(?:aegis|lottie)\\.min\\.js/.test(x.src));\n if (s && s.src) return s.src.replace(/[^/]*(?:\\?.*)?$/, '');\n } catch {\n /* fall through */\n }\n return '/sdk/';\n }\n\n /** Lazy-load the Lottie player once (cached on window). Resolves to the\n * global `lottie`, or rejects if it can't be fetched (→ SVG fallback). */\n private _loadLottie(): Promise<unknown> {\n const w = window as unknown as { lottie?: unknown; __aegisLottieP?: Promise<unknown> };\n if (w.lottie) return Promise.resolve(w.lottie);\n if (w.__aegisLottieP) return w.__aegisLottieP;\n w.__aegisLottieP = new Promise<unknown>((resolve, reject) => {\n try {\n const s = document.createElement('script');\n s.src = `${this._assetBase()}lottie.min.js`;\n s.async = true;\n s.onload = () => resolve((window as unknown as { lottie?: unknown }).lottie);\n s.onerror = () => reject(new Error('lottie player failed to load'));\n document.head.appendChild(s);\n } catch (e) {\n reject(e instanceof Error ? e : new Error('lottie load error'));\n }\n });\n return w.__aegisLottieP;\n }\n\n private addAnimationStyles(): void {\n if (document.getElementById('aegis-in-app-styles')) {\n return;\n }\n \n const style = document.createElement('style');\n style.id = 'aegis-in-app-styles';\n style.textContent = `\n @keyframes aegisSlideDown {\n from { transform: translateY(-100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes aegisSlideUp {\n from { transform: translateY(0); opacity: 1; }\n to { transform: translateY(-100%); opacity: 0; }\n }\n \n @keyframes aegisFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n \n @keyframes aegisFadeOut {\n from { opacity: 1; }\n to { opacity: 0; }\n }\n \n @keyframes aegisScaleIn {\n from { transform: scale(0.9); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n }\n\n /* Bottom-anchored slide IN (opposite of aegisSlideUp which slides OUT).\n Used by the preload-first renderers: sticky_bar (bottom),\n progress_bar, carousel_cards, product_recommendation. */\n @keyframes aegisSlideInFromBottom {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n\n /* Bottom-anchored slide OUT (mirror of aegisSlideInFromBottom). A\n bottom banner must exit DOWNWARD, not up through the viewport. */\n @keyframes aegisSlideOutToBottom {\n from { transform: translateY(0); opacity: 1; }\n to { transform: translateY(100%); opacity: 0; }\n }\n\n /* Celebration confetti (ported from the cashier-portal aegis-confetti\n keyframe) — fired on positive moments: high star rating, won spin/\n scratch prize, completed form. Empathetic (no confetti) on negatives. */\n @keyframes aegisConfetti {\n 0% { transform: translate3d(0,0,0) rotate(0); opacity: 1; }\n 100% { transform: translate3d(var(--dx), 112vh, 0) rotate(var(--r)); opacity: 0; }\n }\n\n /* Poll result bar — fills to its share once a vote lands. */\n @keyframes aegisPollFill {\n from { width: 0%; }\n to { width: var(--pct, 0%); }\n }\n\n /* Countdown urgency — pulse the digits red in the final stretch (<60s). */\n @keyframes aegisUrgencyPulse {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.08); }\n }\n\n /* Emotional reaction (success) — the hero glyph springs in with an\n overshoot, gives a happy wiggle, then gently settles + floats out. */\n @keyframes aegisReactionPop {\n 0% { transform: translate(-50%, -40%) scale(0.2) rotate(-12deg); opacity: 0; }\n 45% { transform: translate(-50%, -52%) scale(1.18) rotate(6deg); opacity: 1; }\n 62% { transform: translate(-50%, -50%) scale(0.94) rotate(-3deg); }\n 78% { transform: translate(-50%, -50%) scale(1.05) rotate(1deg); }\n 100% { transform: translate(-50%, -50%) scale(1) rotate(0); opacity: 1; }\n }\n @keyframes aegisReactionFloatOut {\n 0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }\n 100% { transform: translate(-50%, -150%) scale(0.9); opacity: 0; }\n }\n /* Empathetic reaction — soft fade-in + gentle sway, NO celebration. */\n @keyframes aegisReactionSoft {\n 0% { transform: translate(-50%, -45%) scale(0.7); opacity: 0; }\n 25% { transform: translate(-50%, -50%) scale(1); opacity: 1; }\n 50% { transform: translate(-52%, -50%) scale(1) rotate(-4deg); }\n 75% { transform: translate(-48%, -50%) scale(1) rotate(4deg); }\n 100% { transform: translate(-50%, -50%) scale(1) rotate(0); opacity: 1; }\n }\n /* Radiating celebration rings behind the success glyph. */\n @keyframes aegisRing {\n 0% { transform: translate(-50%, -50%) scale(0.3); opacity: 0.55; }\n 100% { transform: translate(-50%, -50%) scale(2.4); opacity: 0; }\n }\n /* Self-drawing stroke (the check / outline draws itself in). */\n @keyframes aegisDraw {\n from { stroke-dashoffset: 100; }\n to { stroke-dashoffset: 0; }\n }\n /* Gentle breathing for the empathetic heart. */\n @keyframes aegisBreathe {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.08); }\n }\n /* Comment-box placeholder — inherit the modal's text color (not the\n browser default near-black, which is invisible on a dark/accent modal). */\n .aegis-rating-comment::placeholder, .aegis-field::placeholder { color: currentColor; opacity: 0.55; }\n /* Tooltip target highlight — a soft pulsing ring drawing the eye. */\n @keyframes aegisTooltipPulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n /* Countdown final-minute urgency — a gentle breathing pulse (NOT a harsh\n solid-red fill). */\n @keyframes aegisCountdownPulse {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.04); }\n }\n /* Shared CTA micro-interaction — one consistent hover-lift + press across\n every widget's primary button, so they feel like one system. */\n .aegis-cta { transition: transform 0.12s ease, box-shadow 0.12s ease, filter 0.12s ease; }\n .aegis-cta:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(0,0,0,0.18); filter: brightness(1.04); }\n .aegis-cta:active { transform: translateY(0); box-shadow: 0 2px 6px rgba(0,0,0,0.15); filter: brightness(0.98); }\n @media (prefers-reduced-motion: reduce) { .aegis-cta { transition: none; } .aegis-cta:hover { transform: none; } }\n `;\n\n document.head.appendChild(style);\n }\n \n private sanitizeUrl(url: string): string | null {\n try {\n const parsedUrl = new URL(url, window.location.origin);\n \n if (parsedUrl.protocol === 'javascript:' || parsedUrl.protocol === 'data:') {\n this.log(`Blocked unsafe URL: ${url}`, 'error');\n return null;\n }\n \n return parsedUrl.href;\n } catch (error) {\n this.log(`Invalid URL: ${url}`, 'error');\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n if (/^#[0-9A-Fa-f]{3,6}$/.test(color)) {\n return color;\n }\n \n if (/^rgb\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*\\)$/.test(color)) {\n return color;\n }\n \n if (/^rgba\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*[\\d.]+\\s*\\)$/.test(color)) {\n return color;\n }\n \n const namedColors = ['white', 'black', 'red', 'green', 'blue', 'yellow', 'orange', 'purple', 'pink', 'gray', 'transparent'];\n if (namedColors.includes(color.toLowerCase())) {\n return color;\n }\n \n return '#000000';\n }\n \n /**\n * Track in-app event via the standard Event Ingress pipeline.\n *\n * Events flow: SDK → Event Ingress → Kafka → Governance Consumer\n * → Event Engine → ClickHouse (in_app_events + events_with_ttl)\n *\n * The event_type uses the canonical prefix `in_app.` so the event\n * switchboard maps it to the correct canonical form:\n * in_app.impression → engagement.view\n * in_app.clicked → engagement.click\n * in_app.dismissed → engagement.dismiss\n */\n private async trackEvent(\n campaignId: string,\n eventType: 'served' | 'impression' | 'clicked' | 'dismissed' | 'anchor_unresolved',\n extra?: { stepId?: string; meta?: Record<string, unknown> },\n ): Promise<void> {\n // Lifecycle: `campaign-dismiss` — fire from this single chokepoint so\n // every renderer (8 sites today + future ones) emits consistently.\n // Source granularity (close_button / overlay / esc / auto_timeout) can\n // be refined in a future minor by passing source through to trackEvent;\n // for 1.8.0 we surface the event itself since that's the high-value\n // signal host apps need (inbox state updates, dismiss analytics).\n // Resolve the served campaign once — its attribution context (echoed from\n // the in-app serve for queued journey/campaign messages; NULL for catalog)\n // is forwarded on the engagement event so the switchboard lands\n // journey/template/outlet on the delivery_event.\n const trackedCampaign = this.campaigns.find((c) => c.id === campaignId) as\n | (InAppCampaign & {\n journey_execution_id?: string;\n lifecycle_fork_id?: string;\n location_id?: string;\n })\n | undefined;\n\n if (eventType === 'dismissed') {\n if (trackedCampaign) {\n this.emit('campaign-dismiss', {\n campaign: trackedCampaign,\n source: 'close_button',\n });\n }\n }\n\n try {\n // Use the public SDK scheme (/v1/in_app/events) — the gateway has an\n // explicit handler that auths via X-Aegis-Write-Key and forwards to\n // event-switchboard. Direct POST to /api/v1/events bypasses the SDK\n // auth model and hits the JWT preHandler → 401.\n // See docs/architecture/API_ROUTING.md §5.\n const url = `${this.apiHost}/v1/in_app/events`;\n const externalEventId = `inapp_${campaignId}_${eventType}_${Date.now()}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey,\n };\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n\n // Plumb the same workspace cascade the main analytics SDK uses\n // (config → ?ws= → URL path slug → setWorkspace runtime → session\n // storage). Without this, in-app engagement events arrive at\n // event-ingress unscoped and fall back to the org's primary\n // workspace — see PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n const workspaceId = this.getWorkspaceId?.();\n\n const body = {\n campaign_id: campaignId,\n event_type: eventType,\n user_id: this.userId,\n contact_id: this.contactId,\n anonymous_id: this.userId,\n platform: 'web',\n workspace_id: workspaceId,\n // Per-surface traffic (PROPERTY_IN_APP_TAB_SURFACE_BREAKDOWN_TRACKER\n // Phase B): the canonical screen this campaign actually rendered on,\n // as last declared by the host via aegis.page()/screen(). Null when\n // the host page didn't declare a surface. The gateway forwards this\n // to in_app_events.surface so the property By-screen breakdown can\n // show real per-screen impressions/CTR.\n current_surface: this.currentSurface ?? undefined,\n // P3 — optional step_id surfaces multi-step granularity\n // (WEB_SDK_DLR_ENHANCEMENT_TRACKER P3). Server validator + CH\n // schema accept null/empty as the single-step default.\n step_id: extra?.stepId,\n // Attribution echoed from the served message (queued journey/campaign\n // in-app); NULL for catalog campaigns. Lets the switchboard land\n // journey/template/outlet on the engagement delivery_event.\n journey_execution_id: trackedCampaign?.journey_execution_id,\n lifecycle_fork_id: trackedCampaign?.lifecycle_fork_id,\n location_id: trackedCampaign?.location_id,\n metadata: {\n property_id: this.propertyId,\n variant_id: this.getVariantId(campaignId) ?? undefined,\n lifecycle_fork_id: trackedCampaign?.lifecycle_fork_id,\n location_id: trackedCampaign?.location_id,\n // Renderer-supplied metadata (e.g. anchor_resolved/anchor_selector on\n // an anchor_unresolved event). The gateway spreads payload.metadata\n // into the canonical event so these land in in_app_events.metadata.\n ...(extra?.meta ?? {}),\n },\n idempotency_key: externalEventId,\n };\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n credentials: 'include',\n }).catch(error => {\n this.log(`Error tracking event: ${error}`, 'error');\n });\n\n this.log(`Tracked ${eventType} event for campaign ${campaignId}`);\n } catch (error) {\n this.log(`Error tracking event: ${error}`, 'error');\n }\n }\n \n private log(message: string, level: 'log' | 'warn' | 'error' = 'log'): void {\n if (this.debugMode) {\n console[level](`[AegisInApp] ${message}`);\n }\n }\n \n destroy(options?: { clearABState?: boolean }): void {\n this.disconnectSSE();\n\n // Tear down the Active Web Chat launcher (its own SSE is already panel-gated,\n // but destroy() removes the bubble + any open panel + listeners).\n disposeActiveWebChat();\n this.activeWebChat = undefined;\n\n // P1 — clear any pending qualifying-event refresh so a destroy() during\n // the debounce window doesn't fire a stray fetch after the manager is gone.\n if (this.refreshDebounceTimer) {\n clearTimeout(this.refreshDebounceTimer);\n this.refreshDebounceTimer = undefined;\n }\n\n if (typeof document !== 'undefined') {\n document.querySelectorAll(\n '.aegis-in-app-banner, .aegis-in-app-modal-overlay, .aegis-in-app-fullscreen-overlay, ' +\n '.aegis-in-app-half-interstitial-overlay, .aegis-in-app-alert-overlay, .aegis-in-app-pip, ' +\n '.aegis-in-app-nps-overlay, .aegis-in-app-countdown-overlay, .aegis-in-app-rating-overlay, ' +\n '.aegis-in-app-poll-overlay, .aegis-in-app-quiz-overlay, ' +\n // F2/F3 / U8 — slot-rendered card classes\n '.aegis-in-app-rating-card, .aegis-in-app-nps-card'\n ).forEach(el => {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n });\n\n const styles = document.getElementById('aegis-in-app-styles');\n if (styles && styles.parentNode) {\n styles.parentNode.removeChild(styles);\n }\n }\n\n // Optionally clear A/B assignment state\n if (options?.clearABState && typeof localStorage !== 'undefined') {\n localStorage.removeItem('aegis_ab_assignments');\n }\n\n this.isInitialized = false;\n this.log('AegisInApp destroyed');\n }\n}\n","/**\n * renderPreview — Static Preview Renderer for Dashboard iframe (Critical Fix A)\n *\n * Used exclusively by the sandboxed iframe preview route\n * (`/api/preview/in-app/route.tsx`). Renders a single campaign into the\n * current document body using the same rendering logic as the production SDK.\n *\n * Data flow:\n * editor-sidebar.tsx → onChange → formState → postMessage({type:'preview_update', config})\n * → iframe receives message → calls renderPreview(config)\n *\n * This ensures 100% fidelity between the dashboard editor preview and\n * production rendering — both use the same SDK code.\n */\n\nimport type { InAppCampaign } from './AegisInAppManager';\nimport { AegisInAppManager } from './AegisInAppManager';\nimport { renderStoriesRings, type RenderContext } from './renderers';\n\n/**\n * Renders a single in-app campaign into the current document for preview.\n *\n * Creates a temporary AegisInAppManager with preview-only config (no tracking,\n * no SSE, no network requests). Calls the same rendering pipeline as production.\n */\nexport function renderPreview(config: InAppCampaign & { interactive_config?: Record<string, unknown> }): void {\n // Clear previous preview\n document.querySelectorAll(\n '[class^=\"aegis-in-app-\"]'\n ).forEach((el) => {\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n });\n\n // Reset any per-contact \"already seen / completed\" persistence so the\n // preview always renders fresh. Without this, clicking through a\n // coachmark tour (which writes `aegis_coachmark_progress:<resume_key>` to\n // localStorage on completion) would make every subsequent preview render\n // return early — the tour would vanish and never reappear. The preview is\n // a design surface, not a real session, so it must never \"remember\" state.\n try {\n if (typeof localStorage !== 'undefined') {\n for (let i = localStorage.length - 1; i >= 0; i--) {\n const key = localStorage.key(i);\n if (\n key &&\n (key.startsWith('aegis_coachmark_progress:') ||\n key.startsWith('aegis_sticky_dismissed:'))\n ) {\n localStorage.removeItem(key);\n }\n }\n }\n } catch {\n // localStorage blocked — nothing to reset.\n }\n\n if (!config) return;\n\n // Create a lightweight preview-only manager\n const manager = new AegisInAppManager({\n writeKey: 'preview-mode',\n apiHost: '',\n debugMode: false,\n enableSSE: false,\n });\n\n // Override trackEvent to be a no-op in preview mode\n // Access private via any cast — preview only, not production code\n const m = manager as unknown as {\n displayCampaign: (campaign: InAppCampaign) => void;\n trackEvent: (campaignId: string, eventType: string) => Promise<void>;\n addAnimationStyles: () => void;\n buildRenderContext: (campaign: InAppCampaign) => RenderContext;\n };\n\n // No-op tracking for preview\n m.trackEvent = async () => {};\n\n // Ensure animation styles are injected\n m.addAnimationStyles();\n\n // Stories' canonical surface is the INLINE launcher tray (the embedded\n // widget), not the full-screen takeover player. Pin the tray to the TOP of the\n // preview — that's where a real stories rail lives (Instagram/app home), and a\n // centered tray floating mid-screen read as \"random\". Full-width row so it\n // adapts to both the narrow mobile frame and the wide desktop frame; the tray\n // itself scrolls horizontally when the cards overflow.\n if (config.type === 'stories' || config.sub_type === 'stories') {\n const host = document.createElement('div');\n host.className = 'aegis-in-app-stories-host';\n host.style.cssText =\n 'position: fixed; left: 0; right: 0; top: 0; z-index: 99998; padding-top: 4px;' +\n // Subtle tray surface so the row reads as a real stories rail in the\n // preview (branded trays paint their own background over this).\n 'background: rgba(255,255,255,0.94); backdrop-filter: blur(8px);' +\n 'box-shadow: 0 2px 12px rgba(0,0,0,0.06);';\n document.body.appendChild(host);\n renderStoriesRings(m.buildRenderContext(config), host);\n return;\n }\n\n // Render the campaign\n m.displayCampaign(config);\n}\n","/**\n * Aegis device pairing — WEB client (Surface Canvas P6).\n *\n * Pairs a web property to the dashboard canvas so an operator can anchor in-app\n * overlays to REAL page elements. Flow:\n * 1. operator opens a session in the dashboard → short pairing code\n * 2. `pairWebDevice(apiHost, code)` claims it, then captures the current\n * screen: the page's addressable element tree (stable CSS selectors +\n * bounds + roles) + viewport, and POSTs it to the backend.\n * 3. re-captures on navigation (SPA route changes) so the canvas tracks the\n * live page.\n *\n * This is the web sibling of the native (Flutter/Android/iOS/RN) pairing clients\n * — they stream the native view hierarchy; this walks the DOM. Same backend\n * contract (`/v1/device-pairing/...`).\n */\n\nexport interface PairingElementNode {\n /** A stable CSS selector the SDK can re-resolve at runtime (id > data-* > path). */\n selector: string;\n role: string;\n text?: string;\n bounds: { x: number; y: number; w: number; h: number };\n}\n\nexport interface CapturedWebScreen {\n screen_name: string;\n view_tree: PairingElementNode[];\n viewport: { w: number; h: number; scale: number };\n platform: 'web';\n}\n\nexport interface PairWebOptions {\n /** Override the screen name (defaults to location.pathname). */\n screenName?: string;\n deviceLabel?: string;\n /** Keep re-capturing on SPA navigation + a slow heartbeat. Default true. */\n live?: boolean;\n}\n\nconst MAX_NODES = 400; // bound the payload — anchor candidates, not the whole DOM\n\n/** Build a stable-ish CSS selector for an element: prefer #id, then a unique\n * [data-*] attribute, else a nth-of-type path from the nearest id'd ancestor. */\nfunction selectorFor(el: Element): string {\n if (el.id) return `#${CSS.escape(el.id)}`;\n for (const attr of ['data-testid', 'data-test', 'data-aegis-anchor', 'data-qa', 'name']) {\n const v = el.getAttribute(attr);\n if (v) {\n const sel = `${el.tagName.toLowerCase()}[${attr}=\"${CSS.escape(v)}\"]`;\n if (document.querySelectorAll(sel).length === 1) return sel;\n }\n }\n // Path from nearest id'd ancestor, using nth-of-type for stability.\n const parts: string[] = [];\n let node: Element | null = el;\n while (node && node !== document.body && parts.length < 6) {\n if (node.id) { parts.unshift(`#${CSS.escape(node.id)}`); break; }\n const tag = node.tagName.toLowerCase();\n const parentEl: Element | null = node.parentElement;\n if (!parentEl) { parts.unshift(tag); break; }\n const sibs = Array.from(parentEl.children).filter((c) => c.tagName === node!.tagName);\n const idx = sibs.indexOf(node) + 1;\n parts.unshift(sibs.length > 1 ? `${tag}:nth-of-type(${idx})` : tag);\n node = parentEl;\n }\n return parts.join(' > ');\n}\n\n/** Walk the DOM for addressable anchor candidates (interactive + labelled\n * elements that are visible), with bounds + a re-resolvable selector. */\nexport function captureWebScreen(screenName?: string): CapturedWebScreen {\n const nodes: PairingElementNode[] = [];\n const candidates = document.querySelectorAll(\n 'a,button,input,select,textarea,[role],[data-aegis-anchor],[data-testid],h1,h2,h3,img,[data-aegis-slot]',\n );\n for (const el of Array.from(candidates)) {\n if (nodes.length >= MAX_NODES) break;\n const rect = el.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) continue; // skip hidden/zero-size\n // Flag built-in slots so the dashboard canvas highlights them as the\n // recommended targets (\"the value-bar slot\") rather than generic elements.\n const slotKey = el.getAttribute('data-aegis-slot');\n const role = slotKey\n ? `slot:${slotKey}`\n : el.getAttribute('role') || el.tagName.toLowerCase();\n const text = (el.textContent || el.getAttribute('aria-label') || '').trim().slice(0, 80);\n nodes.push({\n selector: selectorFor(el),\n role,\n ...(text ? { text } : {}),\n bounds: {\n x: Math.round(rect.left + window.scrollX),\n y: Math.round(rect.top + window.scrollY),\n w: Math.round(rect.width),\n h: Math.round(rect.height),\n },\n });\n }\n return {\n screen_name: screenName || window.location.pathname || '/',\n view_tree: nodes,\n viewport: { w: window.innerWidth, h: window.innerHeight, scale: window.devicePixelRatio || 1 },\n platform: 'web',\n };\n}\n\n/** Claim a pairing code + stream this web page as a captured screen. Returns a\n * stop() to end live re-capture. */\nexport async function pairWebDevice(\n apiHost: string,\n code: string,\n opts: PairWebOptions = {},\n): Promise<{ ok: boolean; stop: () => void; error?: string }> {\n const base = `${apiHost.replace(/\\/$/, '')}/v1/device-pairing`;\n const noop = () => {};\n try {\n const claim = await fetch(`${base}/${encodeURIComponent(code)}/claim`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ platform: 'web', device_label: opts.deviceLabel || 'Web browser' }),\n });\n if (!claim.ok) return { ok: false, stop: noop, error: `claim failed (${claim.status})` };\n\n const push = async (): Promise<void> => {\n try {\n const screen = captureWebScreen(opts.screenName);\n await fetch(`${base}/${encodeURIComponent(code)}/screens`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(screen),\n });\n } catch {\n /* transient — the next capture retries */\n }\n };\n\n await push();\n\n if (opts.live === false) return { ok: true, stop: noop };\n\n // Live re-capture: SPA route changes + a slow heartbeat for late layout.\n let timer: ReturnType<typeof setInterval> | null = null;\n const onNav = () => { void push(); };\n window.addEventListener('popstate', onNav);\n window.addEventListener('hashchange', onNav);\n timer = setInterval(() => { void push(); }, 4000);\n const stop = () => {\n window.removeEventListener('popstate', onNav);\n window.removeEventListener('hashchange', onNav);\n if (timer) { clearInterval(timer); timer = null; }\n };\n return { ok: true, stop };\n } catch (e) {\n return { ok: false, stop: noop, error: e instanceof Error ? e.message : 'pairing error' };\n }\n}\n\nlet _pairingStarted = false;\n\n/**\n * Read `?aegis_pair=CODE` from the URL and enter pairing — ONCE per page load.\n *\n * Shared entry point so pairing fires the SAME way for BOTH distribution styles:\n * - npm package consumers — the PREFERRED path: the Active Commerce Store AND\n * external websites that `npm i @active-reach/web-sdk` + `new AegisMessageRuntime(...)`\n * → called from `AegisMessageRuntime.initialize()`.\n * - CDN bundle (`aegis.min.js`) — only for platforms that can't consume npm\n * (Shopify / Magento / WooCommerce) → called from `cdn.ts` on bundle boot.\n * The module-level guard dedupes when both paths exist in one bundle. This is\n * what makes the storefront a true testbed: it pairs exactly like any external\n * npm-SDK site — no per-integration divergence.\n */\nexport function maybeStartPairing(apiHost?: string): void {\n if (_pairingStarted || typeof window === 'undefined') return;\n try {\n const code = new URLSearchParams(window.location.search).get('aegis_pair');\n if (!code) return;\n _pairingStarted = true;\n void pairWebDevice(apiHost || 'https://api.active-reach.ai', code, { live: true });\n } catch {\n /* pairing is best-effort — never block SDK boot */\n }\n}\n","/**\n * Micro-Intent Engine — compound rule evaluator (P1 Task 4).\n *\n * Pure, side-effect-free evaluation of an IntentRule predicate tree against\n * a current snapshot of Layer-1 (identity) + Layer-2 (session) signal values.\n *\n * Why a separate class from TriggerEngine\n * ----------------------------------------\n * TriggerEngine.ts owns signal CAPTURE (scroll, time-on-page, exit-intent,\n * etc.) and emits named events like `scroll_depth_50`. IntentRuleEvaluator\n * owns rule EVALUATION — given a compound predicate and the current state\n * of all known signals, return whether the rule fires now. The two\n * concerns separate cleanly: capture is global per-page (one engine\n * instance), evaluation is per-rule (the manager re-runs every armed\n * rule when a `fire_on` signal fires).\n *\n * Type strategy\n * -------------\n * Types are declared LOCALLY in this file rather than imported from\n * `@aegis/shared-types`. The SDK is published standalone on npm and\n * cannot pull in workspace packages at runtime. A drift-check test\n * (`libs/web-sdk/tests/intent-evaluator-shared-types-drift.test.ts`)\n * parses both files and asserts the local types and the canonical\n * `libs/shared-types/src/intent.ts` declare the same set of signal /\n * comparator values.\n *\n * Plan reference: docs/architecture/MICRO_INTENT_ENGINE.md §\"Schemas\"\n */\n\n// ───────────────────────────────────────────────────────────────────────────\n// Types — local mirror of libs/shared-types/src/intent.ts\n// ───────────────────────────────────────────────────────────────────────────\n\nexport type IntentSignal =\n // Layer-2 session\n | 'scroll_depth'\n | 'time_on_page'\n | 'exit_intent'\n | 'back_button'\n | 'scroll_velocity'\n | 'inactivity'\n | 'visibility_change'\n | 'rage_click'\n | 'price_hover_ms'\n | 'cta_hover_ms'\n | 'cum_dwell_sku'\n | 'session_count_sku'\n | 'cart_value'\n | 'converted_in_session'\n // Layer-1 identity scores\n | 'rfm_segment'\n | 'rfm_score'\n | 'lifecycle_stage'\n | 'purchase_intent_score'\n | 'purchase_intent_tier'\n | 'churn_risk_score'\n | 'churn_risk_tier'\n | 'predicted_ltv'\n | 'predicted_ltv_tier'\n | 'uninstall_risk_tier'\n | 'engagement_level'\n | 'price_tier'\n | 'price_sensitivity_score'\n | 'top_category'\n | 'avg_cart_value'\n | 'scoring_tier';\n\nexport type Comparator = 'gte' | 'lte' | 'gt' | 'lt' | 'eq' | 'neq' | 'in' | 'nin';\n\nexport type IntentLeafValue =\n | number\n | string\n | boolean\n | ReadonlyArray<number | string | boolean>;\n\nexport interface IntentLeaf {\n /** Canonical enum signal (Layer-1/2). Mutually exclusive with `path`. */\n signal?: IntentSignal;\n /** Dot-path into the updateContext namespaces (cart.total / user.tier /\n * session.idle_s). Mutually exclusive with `signal`. */\n path?: string;\n op: Comparator;\n value: IntentLeafValue;\n}\n\n/** A value/node in the generic reactive context (fed via updateContext). */\nexport type ContextValue = string | number | boolean | null | ContextNode | ReadonlyArray<ContextValue>;\nexport interface ContextNode {\n [key: string]: ContextValue;\n}\n/** Named namespaces: { cart: {...}, user: {...}, session: {...}, custom: {...} }. */\nexport type ContextNamespaces = Record<string, ContextNode>;\n\nexport interface IntentNode {\n op: 'AND' | 'OR' | 'NOT';\n operands: ReadonlyArray<IntentExpr>;\n}\n\nexport type IntentExpr = IntentNode | IntentLeaf;\n\nexport interface IntentRule {\n fire_on: ReadonlyArray<IntentSignal>;\n when: IntentExpr;\n priority: number;\n suppress_competing: boolean;\n}\n\n/** A scalar a signal can hold in the snapshot. null = signal not (yet)\n * populated — happens for Layer-1 scores on anonymous sessions and for\n * Layer-2 signals before the user triggers them. */\nexport type SignalValue = number | string | boolean | null;\n\n/** Current state of every known signal. Missing keys are treated the\n * same as `null`. */\nexport type IntentSnapshot = Partial<Record<IntentSignal, SignalValue>>;\n\n// ───────────────────────────────────────────────────────────────────────────\n// Type guards\n// ───────────────────────────────────────────────────────────────────────────\n\nexport function isIntentLeaf(expr: IntentExpr): expr is IntentLeaf {\n // A leaf is anything WITHOUT `operands` (it may carry `signal` or `path`).\n return !('operands' in expr);\n}\n\n/** Resolve a dot-path (`cart.total`) against the context namespaces.\n * Returns undefined on any miss → tri-state null in evaluateLeaf (same as a\n * missing signal). Never throws. */\nexport function getValueByPath(\n namespaces: ContextNamespaces | undefined,\n path: string,\n): ContextValue | undefined {\n if (!namespaces || !path) return undefined;\n let cur: ContextValue | undefined = namespaces as unknown as ContextValue;\n for (const part of path.split('.')) {\n if (cur === null || typeof cur !== 'object' || Array.isArray(cur)) return undefined;\n cur = (cur as ContextNode)[part];\n }\n return cur;\n}\n\nexport function isIntentNode(expr: IntentExpr): expr is IntentNode {\n return 'operands' in expr;\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Pure leaf evaluator\n// ───────────────────────────────────────────────────────────────────────────\n\n/**\n * Evaluate a single leaf comparison against a snapshot.\n *\n * Missing-signal semantics (per the plan's \"Graceful degradation rules\"):\n * - The CALLER (evaluateExpr) decides AND/OR semantics on missing\n * operands; this function answers strictly for THIS leaf.\n * - When the signal is missing from the snapshot, the leaf is\n * \"unknown\" → return null so the parent node can interpret it.\n *\n * Comparator semantics:\n * - gte/lte/gt/lt: numeric only; comparing strings/bools returns false.\n * - eq/neq: any type; strict equality.\n * - in/nin: leaf value must be a list; membership test on the snapshot\n * value. `nin` returns true for missing snapshot values (the\n * contact's RFM segment is \"not in\" the forbidden list if we don't\n * know it yet — conservative).\n */\nexport function evaluateLeaf(\n leaf: IntentLeaf,\n snapshot: IntentSnapshot,\n namespaces?: ContextNamespaces,\n): boolean | null {\n // Resolve from a dot-path (generic context) when present, else the enum\n // signal snapshot. Both share the SAME tri-state (missing → null) + operator\n // semantics — one evaluator, not two.\n const actual = leaf.path !== undefined\n ? getValueByPath(namespaces, leaf.path)\n : (leaf.signal !== undefined ? snapshot[leaf.signal] : undefined);\n if (actual === undefined || actual === null) {\n // Missing signal/path — let the parent decide.\n return null;\n }\n\n const want = leaf.value;\n\n switch (leaf.op) {\n case 'gte':\n case 'lte':\n case 'gt':\n case 'lt': {\n if (typeof actual !== 'number' || typeof want !== 'number') return false;\n if (leaf.op === 'gte') return actual >= want;\n if (leaf.op === 'lte') return actual <= want;\n if (leaf.op === 'gt') return actual > want;\n return actual < want; // lt\n }\n case 'eq':\n return actual === want;\n case 'neq':\n return actual !== want;\n case 'in':\n case 'nin': {\n if (!Array.isArray(want)) return false;\n const isMember = want.some((v) => v === actual);\n return leaf.op === 'in' ? isMember : !isMember;\n }\n default: {\n // Exhaustiveness check — TS will flag a new Comparator that doesn't\n // have a case here, but the runtime fallback returns false.\n const _exhaustive: never = leaf.op;\n void _exhaustive;\n return false;\n }\n }\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Pure tree evaluator\n// ───────────────────────────────────────────────────────────────────────────\n\n/**\n * Evaluate the full predicate tree.\n *\n * AND/OR/NOT semantics with missing-value handling (per plan §\"Graceful\n * degradation rules\"):\n *\n * AND(a, b, c) where any operand is null → false (conservative; the\n * rule doesn't fire when we can't prove all conditions).\n * OR(a, b, c) where some operands are null → if any non-null operand\n * is true, returns true. If all operands are null OR all are\n * false, returns false.\n * NOT(a) where a is null → null (parent decides). When this propagates\n * to the top-level evaluateExpr, the rule does NOT fire.\n *\n * The \"AND treats missing as unmet\" + \"OR treats missing as inert\" rule\n * from the plan maps exactly onto this implementation: AND short-circuits\n * to false on any null operand; OR ignores nulls and looks at the rest.\n *\n * Top-level: a null result from the root expression means the rule\n * cannot be evaluated yet — do NOT fire.\n */\nexport function evaluateExpr(\n expr: IntentExpr,\n snapshot: IntentSnapshot,\n namespaces?: ContextNamespaces,\n): boolean | null {\n if (isIntentLeaf(expr)) {\n return evaluateLeaf(expr, snapshot, namespaces);\n }\n\n switch (expr.op) {\n case 'AND': {\n // AND requires ALL operands true. Any null = unprovable = false.\n for (const operand of expr.operands) {\n const v = evaluateExpr(operand, snapshot, namespaces);\n if (v === null) return false;\n if (!v) return false;\n }\n return true;\n }\n case 'OR': {\n // OR is satisfied by any true operand. Nulls are skipped (inert).\n let allNull = true;\n for (const operand of expr.operands) {\n const v = evaluateExpr(operand, snapshot, namespaces);\n if (v === true) return true;\n if (v !== null) allNull = false;\n }\n // If every operand was null, propagate null upward — caller decides.\n // Otherwise all operands evaluated false.\n return allNull ? null : false;\n }\n case 'NOT': {\n // Validator at write time guarantees operands.length === 1; the\n // evaluator trusts that and reads operands[0].\n const v = evaluateExpr(expr.operands[0], snapshot, namespaces);\n if (v === null) return null;\n return !v;\n }\n default: {\n // Exhaustiveness check — if a new op is added to IntentExpr and\n // not handled above, TypeScript narrows `expr` to `never` here\n // and assigning it to a non-`never` would fail at compile time.\n // The earlier draft did `expr.op` which itself dereferences\n // `never` and explodes; assign `expr` directly instead.\n const _exhaustive: never = expr;\n void _exhaustive;\n return false;\n }\n }\n}\n\n/** Top-level \"does the rule fire right now?\" check. Treats a null\n * evaluation result as \"do not fire\" (we can't prove the rule's\n * conditions are met). */\nexport function evaluateRule(\n rule: IntentRule,\n snapshot: IntentSnapshot,\n namespaces?: ContextNamespaces,\n): boolean {\n const result = evaluateExpr(rule.when, snapshot, namespaces);\n return result === true;\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Stateful evaluator class — what AegisInAppManager talks to\n// ───────────────────────────────────────────────────────────────────────────\n\n/** A campaign carrying a compound rule, in the SDK's runtime shape.\n * Mirrors the cell-plane payload at /v1/in-app/active when\n * client_trigger.type === 'micro_intent'. */\nexport interface ArmedCampaign {\n id: string;\n rule: IntentRule;\n}\n\n/** The decision the evaluator returns when a signal fires.\n *\n * fire : caller should display this campaign now.\n * suppress : caller should silence the listed competing campaign IDs\n * for the rest of the session (the bouncing-researcher\n * pattern — a rule whose only job is to silence others).\n * none : no rule matched, do nothing.\n */\nexport interface EvaluationDecision {\n kind: 'fire' | 'suppress' | 'none';\n campaignId?: string;\n suppressIds?: ReadonlyArray<string>;\n}\n\nexport class IntentRuleEvaluator {\n /** All campaigns currently armed on this page. Caller (the\n * AegisInAppManager) replaces this on every refresh. */\n private armed: ArmedCampaign[] = [];\n\n /** Latest signal values. Caller pushes updates via updateSignal /\n * updateSnapshot whenever TriggerEngine emits a state change or\n * contact-scores fetch completes. */\n private snapshot: IntentSnapshot = {};\n\n /** Generic reactive context namespaces fed via updateContext() — the SINGLE\n * store path-leaves resolve against (no parallel state elsewhere). */\n private namespaces: ContextNamespaces = {};\n\n /** Campaigns that have already fired this session — never re-fire. */\n private firedThisSession = new Set<string>();\n\n /** Campaigns silenced by a prior `suppress_competing` win. The set\n * resets on session boundary (new tab / new pageview after timeout).\n * The AegisInAppManager owns durability semantics; this set is\n * in-memory only. */\n private silencedThisSession = new Set<string>();\n\n // ─── snapshot management ───\n\n updateSignal(signal: IntentSignal, value: SignalValue): void {\n this.snapshot[signal] = value;\n }\n\n updateSnapshot(partial: IntentSnapshot): void {\n Object.assign(this.snapshot, partial);\n }\n\n getSnapshot(): Readonly<IntentSnapshot> {\n return this.snapshot;\n }\n\n // ─── generic reactive context (updateContext) ───\n\n /** Merge a namespace's data (shallow). Path-leaves (`cart.total`) resolve\n * against this. The runtime's updateContext() delegates here so there is ONE\n * context store, then bridges well-known paths to enum signals. */\n updateContext(namespace: string, data: ContextNode): void {\n if (!namespace || !data) return;\n this.namespaces[namespace] = { ...this.namespaces[namespace], ...data };\n }\n\n getNamespaces(): Readonly<ContextNamespaces> {\n return this.namespaces;\n }\n\n /** Resolve a dot-path against the live context (for previews / debugging). */\n getValueByPath(path: string): ContextValue | undefined {\n return getValueByPath(this.namespaces, path);\n }\n\n // ─── armed-campaign management ───\n\n setArmed(campaigns: ArmedCampaign[]): void {\n this.armed = [...campaigns];\n }\n\n getArmed(): ReadonlyArray<ArmedCampaign> {\n return this.armed;\n }\n\n markFired(campaignId: string): void {\n this.firedThisSession.add(campaignId);\n }\n\n /** Clear all per-session state. Caller invokes on logout or explicit\n * session reset. */\n reset(): void {\n this.firedThisSession.clear();\n this.silencedThisSession.clear();\n }\n\n // ─── the main dispatch ───\n\n /**\n * Called every time a signal value changes meaningfully (e.g. a\n * TriggerEngine `exit_intent` event, or a `scroll_depth_50` crossing\n * threshold, or the Layer-1 fetch finishing). Returns the decision the\n * caller should act on.\n *\n * Algorithm:\n * 1. Filter armed campaigns to those whose `fire_on` includes the\n * signal that just changed.\n * 2. Drop already-fired and silenced campaigns.\n * 3. Sort the remainder by priority DESC, tie-broken by campaign id\n * lexicographic (per plan §\"Pattern ordering rules\").\n * 4. Walk the sorted list:\n * - If a suppress_competing rule matches, emit a 'suppress'\n * decision listing every lower-priority armed campaign id.\n * Mark those as silenced internally too.\n * - Otherwise the first matching rule emits 'fire'.\n * 5. If nothing matches, return 'none'.\n */\n onSignalChanged(signal: IntentSignal): EvaluationDecision {\n const candidates = this.armed\n .filter((c) => c.rule.fire_on.includes(signal))\n .filter((c) => !this.firedThisSession.has(c.id))\n .filter((c) => !this.silencedThisSession.has(c.id))\n .sort((a, b) => {\n if (b.rule.priority !== a.rule.priority) {\n return b.rule.priority - a.rule.priority;\n }\n // Tie-break: lexicographic on id, ascending.\n return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;\n });\n\n for (let i = 0; i < candidates.length; i++) {\n const c = candidates[i];\n if (!evaluateRule(c.rule, this.snapshot, this.namespaces)) continue;\n\n if (c.rule.suppress_competing) {\n // Silence every other armed campaign for the rest of session.\n // Specifically: every armed campaign EXCEPT this one. We don't\n // restrict to \"lower priority\" because suppress_competing is\n // explicitly a bouncing-researcher / margin-protection signal —\n // it means \"if this matches, don't show ANYTHING\".\n const suppressIds = this.armed\n .filter((other) => other.id !== c.id)\n .map((other) => other.id);\n suppressIds.forEach((id) => this.silencedThisSession.add(id));\n return {\n kind: 'suppress',\n campaignId: c.id,\n suppressIds,\n };\n }\n\n return { kind: 'fire', campaignId: c.id };\n }\n\n return { kind: 'none' };\n }\n}\n\n// Re-export pure helpers so tests can reach them without instantiating\n// the class.\nexport const MAX_RULE_DEPTH = 3 as const;\n","/**\n * Micro-Intent Engine — contact-scores fetcher (P4a bridge).\n *\n * Bridges `GET /v1/sdk/contact-scores` into the SDK's\n * `IntentRuleEvaluator` snapshot. Without this, identified-contact\n * micro-intent patterns (VIP Whisper, Win-back At-Risk, Price-Sensitive\n * Nudge, etc.) cannot fire because their AND-compound rules evaluate\n * `rfm_segment` / `lifecycle_stage` / `churn_risk_tier` /\n * `predicted_ltv_tier` / `price_sensitivity_score` against an empty\n * snapshot and always return false.\n *\n * Lifecycle\n * ---------\n * AegisMessageRuntime.initialize() → fetch if contactId known\n * AegisMessageRuntime.updateContactId → fetch for the new contact\n *\n * The fetcher is session-deduped: a second `fetchForContact(sameId)`\n * call within `dedupWindowMs` is a no-op. This stops a hot navigation\n * loop from hammering the endpoint when SPA route changes re-call\n * identify() with the same id.\n *\n * Empty state\n * -----------\n * The endpoint returns 204 for unknown contacts AND for contacts whose\n * `scoring_tier='none'`. Either way the fetcher leaves the snapshot\n * unchanged — the evaluator's leaf eval treats absent Layer-1 keys as\n * null, which fail-closes any AND clause involving them. Anonymous\n * patterns continue to work normally.\n *\n * Privacy posture\n * ---------------\n * The endpoint's default response is the tiered form (`predicted_ltv_tier`).\n * Tenants who opt into raw `predicted_ltv` via\n * `organizations.settings.score_serving_raw_ltv = true` will see the\n * float on the snapshot too. Both are valid IntentSignals; rule\n * authors pick whichever matches their tenant config.\n *\n * Plan reference: docs/architecture/MICRO_INTENT_ENGINE.md §P4a.\n */\n\nimport type { IntentRuleEvaluator, IntentSnapshot } from './IntentRuleEvaluator';\n\n/** Shape of the Layer-1 score response from /v1/sdk/contact-scores. */\nexport interface ContactScoresResponse {\n rfm_segment?: string;\n lifecycle_stage?: string;\n churn_risk_tier?: 'low' | 'medium' | 'high';\n predicted_ltv_tier?: 'low' | 'medium' | 'high';\n predicted_ltv?: number;\n price_sensitivity_score?: number;\n scoring_tier?: string;\n scores_updated_at?: string | null;\n /** Governed contact context — namespaced { user: { custom: {…} }, loyalty:\n * { points, tier } } from contacts.attributes + the loyalty record (the SAME\n * source segments + {{custom.x}} merge fields use). Pushed into the rule\n * engine's namespaces so `user.custom.<attr>` / `loyalty.points` path-leaves\n * resolve client-side off one catalog. */\n context?: Record<string, Record<string, unknown>>;\n}\n\nexport interface ContactScoresFetcherConfig {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n /** Optional. When provided, the fetcher pushes the response into the\n * evaluator's snapshot automatically on every successful fetch. */\n evaluator?: IntentRuleEvaluator;\n /** Minimum time between repeat fetches for the same contactId.\n * Default 60 seconds. */\n dedupWindowMs?: number;\n /** Override for tests / non-browser environments. */\n fetchImpl?: typeof fetch;\n /** Console.warn channel. */\n onError?: (err: unknown, contactId: string) => void;\n}\n\nexport class ContactScoresFetcher {\n private readonly apiHost: string;\n private readonly writeKey: string;\n private organizationId?: string;\n private readonly evaluator?: IntentRuleEvaluator;\n private readonly dedupWindowMs: number;\n private readonly fetchImpl: typeof fetch;\n private readonly onError?: (err: unknown, contactId: string) => void;\n\n private lastFetchedContactId?: string;\n private lastFetchedAt = 0;\n private latestSnapshot: ContactScoresResponse | null = null;\n\n constructor(cfg: ContactScoresFetcherConfig) {\n this.apiHost = cfg.apiHost.replace(/\\/$/, '');\n this.writeKey = cfg.writeKey;\n this.organizationId = cfg.organizationId;\n this.evaluator = cfg.evaluator;\n this.dedupWindowMs = cfg.dedupWindowMs ?? 60_000;\n this.fetchImpl = cfg.fetchImpl ?? (typeof fetch !== 'undefined' ? fetch.bind(globalThis) : (() => Promise.reject(new Error('fetch unavailable'))) as typeof fetch);\n this.onError = cfg.onError;\n }\n\n /** Update the org so subsequent fetches scope correctly (e.g. when\n * the SDK resolves an org id after init). */\n updateOrganizationId(organizationId: string | undefined): void {\n this.organizationId = organizationId;\n }\n\n /** Most recent successful response. `null` when no fetch has succeeded\n * yet, OR when the endpoint returned 204 (unscored). Consumers can\n * poll this for diagnostic UIs; campaign evaluation does not need to\n * read it directly because the evaluator (if configured) already has\n * the snapshot applied. */\n getSnapshot(): Readonly<ContactScoresResponse> | null {\n return this.latestSnapshot;\n }\n\n /** Fetch scores for `contactId` and apply to the configured evaluator\n * (if any). Returns the response on success, null on 204 / error.\n *\n * Session-dedup: repeat calls for the same contactId within\n * `dedupWindowMs` are no-ops. Pass `force: true` to override. */\n async fetchForContact(\n contactId: string,\n opts: { force?: boolean } = {},\n ): Promise<ContactScoresResponse | null> {\n if (!contactId) return null;\n\n const now = Date.now();\n if (\n !opts.force &&\n this.lastFetchedContactId === contactId &&\n now - this.lastFetchedAt < this.dedupWindowMs\n ) {\n return this.latestSnapshot;\n }\n\n this.lastFetchedContactId = contactId;\n this.lastFetchedAt = now;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Contact-ID': contactId,\n 'X-User-ID': contactId,\n };\n if (this.organizationId) {\n headers['X-Organization-ID'] = this.organizationId;\n }\n\n try {\n const resp = await this.fetchImpl(\n `${this.apiHost}/v1/sdk/contact-scores`,\n {\n method: 'GET',\n headers,\n credentials: 'include',\n },\n );\n if (resp.status === 204) {\n this.latestSnapshot = null;\n return null;\n }\n if (!resp.ok) {\n this.latestSnapshot = null;\n return null;\n }\n const payload = (await resp.json()) as ContactScoresResponse;\n this.latestSnapshot = payload;\n if (this.evaluator) {\n this.evaluator.updateSnapshot(toIntentSnapshot(payload));\n // Bridge the governed contact context into the rule engine's namespaces\n // — the SAME source as segments + merge fields, so client path-rules\n // (user.custom.<attr> / loyalty.points) resolve off one catalog. Any\n // product enriching contacts.attributes or the loyalty record flows here.\n if (payload.context && typeof payload.context === 'object') {\n for (const [ns, data] of Object.entries(payload.context)) {\n if (data && typeof data === 'object') {\n this.evaluator.updateContext(ns, data as Record<string, never>);\n }\n }\n }\n }\n return payload;\n } catch (err) {\n // Network errors / aborted fetches must not block in-app rendering.\n // Anonymous patterns keep working; identified-contact patterns\n // simply don't fire this session.\n this.onError?.(err, contactId);\n return null;\n }\n }\n}\n\n/** Project the wire response onto the evaluator's IntentSnapshot shape.\n * Strings (rfm_segment / lifecycle_stage / *_tier) map straight across;\n * numerics (price_sensitivity_score / predicted_ltv) are passed through\n * as numbers. Missing keys are omitted so the evaluator's leaf eval\n * treats them as null (per IntentRuleEvaluator semantics).\n *\n * Exported for the smoke test — drift guard pins the mapping. */\nexport function toIntentSnapshot(r: ContactScoresResponse): IntentSnapshot {\n const snap: IntentSnapshot = {};\n if (r.rfm_segment) snap.rfm_segment = r.rfm_segment;\n if (r.lifecycle_stage) snap.lifecycle_stage = r.lifecycle_stage;\n if (r.churn_risk_tier) snap.churn_risk_tier = r.churn_risk_tier;\n if (r.predicted_ltv_tier) snap.predicted_ltv_tier = r.predicted_ltv_tier;\n if (typeof r.predicted_ltv === 'number') snap.predicted_ltv = r.predicted_ltv;\n if (typeof r.price_sensitivity_score === 'number') {\n snap.price_sensitivity_score = r.price_sensitivity_score;\n }\n if (r.scoring_tier) snap.scoring_tier = r.scoring_tier;\n return snap;\n}\n","/**\n * SDK Config Poller\n *\n * Fetches non-sensitive SDK configuration from GET /v1/sdk/config\n * with ETag/If-None-Match support for 304 responses.\n *\n * Polls every 5 minutes by default. Config changes are applied\n * to push/in-app managers without re-initialization.\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface SdkConfig {\n version: string;\n push: {\n enabled: boolean;\n vapid_public_key: string | null;\n platforms: string[];\n };\n in_app: {\n enabled: boolean;\n };\n consent: {\n channels_requiring_opt_in: string[];\n };\n}\n\nexport interface SdkConfigPollerOptions {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n pollIntervalMs?: number;\n}\n\nexport type ConfigChangeCallback = (config: SdkConfig) => void;\n\nexport class SdkConfigPoller {\n private options: Required<Omit<SdkConfigPollerOptions, 'organizationId'>> & { organizationId?: string };\n private currentETag: string | null = null;\n private currentConfig: SdkConfig | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private listeners: ConfigChangeCallback[] = [];\n\n constructor(options: SdkConfigPollerOptions) {\n this.options = {\n pollIntervalMs: 300_000, // 5 minutes\n ...options,\n };\n }\n\n /**\n * Fetch config once (on init) and start polling.\n */\n async start(): Promise<SdkConfig | null> {\n const config = await this.fetchConfig();\n\n this.pollTimer = setInterval(() => {\n this.fetchConfig().catch((err) => {\n logger.warn('SDK config poll failed:', err);\n });\n }, this.options.pollIntervalMs);\n\n return config;\n }\n\n /**\n * Stop polling.\n */\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n /**\n * Register a callback for config changes.\n */\n onChange(callback: ConfigChangeCallback): () => void {\n this.listeners.push(callback);\n return () => {\n const idx = this.listeners.indexOf(callback);\n if (idx >= 0) this.listeners.splice(idx, 1);\n };\n }\n\n /**\n * Get current cached config.\n */\n getConfig(): SdkConfig | null {\n return this.currentConfig;\n }\n\n /**\n * Fetch config with ETag/304 support.\n */\n private async fetchConfig(): Promise<SdkConfig | null> {\n try {\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.options.writeKey,\n 'Accept': 'application/json',\n };\n\n if (this.options.organizationId) {\n headers['X-Organization-ID'] = this.options.organizationId;\n }\n\n if (this.currentETag) {\n headers['If-None-Match'] = this.currentETag;\n }\n\n const response = await fetch(`${this.options.apiHost}/v1/sdk/config`, {\n method: 'GET',\n headers,\n });\n\n // 304 Not Modified — config unchanged\n if (response.status === 304) {\n return this.currentConfig;\n }\n\n if (!response.ok) {\n logger.warn(`SDK config fetch failed: HTTP ${response.status}`);\n return this.currentConfig;\n }\n\n const config: SdkConfig = await response.json();\n const newETag = response.headers.get('ETag');\n\n if (newETag) {\n this.currentETag = newETag;\n }\n\n // Detect changes\n const changed = !this.currentConfig ||\n JSON.stringify(this.currentConfig) !== JSON.stringify(config);\n\n this.currentConfig = config;\n\n if (changed) {\n for (const listener of this.listeners) {\n try {\n listener(config);\n } catch (err) {\n logger.warn('SDK config change listener error:', err);\n }\n }\n }\n\n return config;\n } catch (err) {\n logger.warn('SDK config fetch error:', err);\n return this.currentConfig;\n }\n }\n}\n","/**\n * PrefetchBundleClient — unified init-time resolver for in-app state.\n *\n * Fetches /v1/sdk/prefetch-bundle at SDK init and on a 5-minute ETag\n * refresh cadence. The bundle payload carries:\n * • `campaigns[]` — eligible, property-scoped, A/B-assigned campaigns\n * armed for this contact. EVERY in-app type is in\n * here (modal, banner, spin_wheel, carousel_cards,\n * sticky_bar, progress_bar, coachmark_tour, etc.).\n * • `inbox` — first page + unread count for the notification\n * drawer; lets AegisInbox hydrate without a second\n * round-trip.\n * • `etag` — content-hashed, stable when state is unchanged;\n * 304 responses cost ~50ms and consume no body.\n * • `invalidation_topic` — SSE channel name the cell-plane publishes\n * to when a playbook arms a campaign mid-session.\n * The SDK does NOT open SSE on that topic today —\n * we rely on the 5-minute poll + an explicit\n * `refresh()` hook that app code (AegisInAppManager,\n * AegisInbox) call on relevant user actions.\n *\n * This is the cornerstone of the preload-first contract from\n * docs/architecture/IN_APP_MESSAGES_EXPANSION_PLAN.md §1. The render\n * path must NEVER hit the network at trigger time — the bundle is\n * populated at init, and everything renders from memory.\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface PrefetchBundleCampaign {\n id: string;\n type: string;\n sub_type?: string;\n title: string;\n body: string;\n image_url?: string;\n action_url?: string;\n button_text?: string;\n background_color?: string;\n text_color?: string;\n priority: number;\n expires_at?: string | null;\n frequency?: {\n max_impressions?: number;\n max_impressions_per_day?: number;\n cooldown_seconds?: number;\n };\n interactive_config?: Record<string, unknown>;\n client_trigger?: {\n type: string;\n config?: Record<string, unknown>;\n };\n assigned_variant_id?: string;\n inbox_enabled?: boolean;\n}\n\nexport interface PrefetchBundleInboxEntry {\n id: string;\n source: string;\n campaign_id: string | null;\n title: string;\n body: string;\n media_url: string | null;\n cta_url: string | null;\n metadata: Record<string, unknown> | null;\n read: boolean;\n read_at: string | null;\n created_at: string | null;\n expires_at: string | null;\n}\n\nexport interface PrefetchBundleInbox {\n unread_count: number;\n page: PrefetchBundleInboxEntry[];\n cursor: string | null;\n}\n\nexport interface PrefetchBundle {\n etag: string;\n generated_at: string;\n ttl_seconds: number;\n invalidation_topic: string;\n campaigns: PrefetchBundleCampaign[];\n inbox: PrefetchBundleInbox;\n}\n\nexport interface PrefetchBundleContext {\n device_type?: string;\n page_url?: string;\n geo?: string;\n is_new_user?: boolean;\n}\n\nexport interface PrefetchBundleClientOptions {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n contactId?: string;\n userId?: string;\n propertyId?: string;\n /** Cached AB assignments from localStorage, base64-json. */\n abAssignments?: Record<string, string>;\n /** Polling cadence; defaults to the bundle's own `ttl_seconds` (300s). */\n pollIntervalMs?: number;\n /** Factory for client context — re-evaluated on each fetch so device/page\n * state stays fresh without forcing callers to re-instantiate the client. */\n contextProvider?: () => PrefetchBundleContext;\n}\n\nexport type PrefetchBundleListener = (bundle: PrefetchBundle) => void;\n\nconst DEFAULT_POLL_MS = 300_000; // 5 minutes — aligns with cell-plane TTL\n\nexport class PrefetchBundleClient {\n private apiHost: string;\n private writeKey: string;\n private organizationId?: string;\n private contactId?: string;\n private userId?: string;\n private propertyId?: string;\n private abAssignments: Record<string, string>;\n private pollIntervalMs: number;\n private contextProvider: () => PrefetchBundleContext;\n\n private currentETag: string | null = null;\n private currentBundle: PrefetchBundle | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private listeners: PrefetchBundleListener[] = [];\n private inflightRefetch: Promise<PrefetchBundle | null> | null = null;\n\n constructor(options: PrefetchBundleClientOptions) {\n this.apiHost = options.apiHost;\n this.writeKey = options.writeKey;\n this.organizationId = options.organizationId;\n this.contactId = options.contactId;\n this.userId = options.userId;\n this.propertyId = options.propertyId;\n this.abAssignments = options.abAssignments ?? {};\n this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_MS;\n this.contextProvider = options.contextProvider ?? (() => ({}));\n }\n\n /**\n * Initial fetch + start the background ETag poll. Resolves to the bundle\n * (or `null` if the first fetch failed — callers should fall back to an\n * empty campaign list, not abort SDK init).\n */\n async start(): Promise<PrefetchBundle | null> {\n const bundle = await this.fetch();\n this.pollTimer = setInterval(() => {\n this.fetch().catch((err) => logger.warn('prefetch-bundle poll failed:', err));\n }, this.pollIntervalMs);\n return bundle;\n }\n\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n getBundle(): PrefetchBundle | null {\n return this.currentBundle;\n }\n\n getCampaigns(): PrefetchBundleCampaign[] {\n return this.currentBundle?.campaigns ?? [];\n }\n\n getInbox(): PrefetchBundleInbox {\n return this.currentBundle?.inbox ?? { unread_count: 0, page: [], cursor: null };\n }\n\n /** Force a refresh (dedupes concurrent calls). Exposed so inbox mutations\n * and campaign-activation SSE messages can trigger a refetch on demand. */\n async refresh(): Promise<PrefetchBundle | null> {\n if (this.inflightRefetch) return this.inflightRefetch;\n this.inflightRefetch = this.fetch();\n try {\n return await this.inflightRefetch;\n } finally {\n this.inflightRefetch = null;\n }\n }\n\n /** Subscribe to bundle changes (emits on first fetch + on any content\n * change — ETag 304 does NOT fire the listener). Returns an unsubscribe. */\n onChange(listener: PrefetchBundleListener): () => void {\n this.listeners.push(listener);\n return () => {\n const idx = this.listeners.indexOf(listener);\n if (idx >= 0) this.listeners.splice(idx, 1);\n };\n }\n\n /**\n * Update the identity tuple — called by AegisInAppManager when the host\n * app resolves a contactId post-init (e.g., after login). Triggers an\n * immediate refresh since the eligible campaigns + inbox will differ.\n */\n updateIdentity(partial: {\n contactId?: string;\n userId?: string;\n organizationId?: string;\n propertyId?: string;\n }): void {\n let changed = false;\n if (partial.contactId !== undefined && partial.contactId !== this.contactId) {\n this.contactId = partial.contactId;\n changed = true;\n }\n if (partial.userId !== undefined && partial.userId !== this.userId) {\n this.userId = partial.userId;\n changed = true;\n }\n if (\n partial.organizationId !== undefined &&\n partial.organizationId !== this.organizationId\n ) {\n this.organizationId = partial.organizationId;\n changed = true;\n }\n if (partial.propertyId !== undefined && partial.propertyId !== this.propertyId) {\n this.propertyId = partial.propertyId;\n changed = true;\n }\n if (changed) {\n // Identity change invalidates ETag — drop the cached tag so the next\n // fetch gets a fresh payload instead of a 304 bound to the old identity.\n this.currentETag = null;\n this.refresh().catch((err) =>\n logger.warn('prefetch-bundle identity-refresh failed:', err),\n );\n }\n }\n\n /** Update cached AB assignments. Called by downstream renderers after\n * they display a variant. Persisted to localStorage by higher layers. */\n setAbAssignments(assignments: Record<string, string>): void {\n this.abAssignments = { ...assignments };\n }\n\n /**\n * Wire an already-open realtime subscriber (from `aegis.realtime.subscribe`\n * or a caller-provided EventSource) so the prefetch bundle refreshes\n * instantly when the cell-plane signals `bundle.invalidate` — covering\n * the window between an event (cart abandon, inbox write) and the\n * 5-min ETag poll.\n *\n * `subscriber.onMessage(handler)` must fire with parsed message bodies\n * from the contact's SSE stream. The handler filters for\n * `type === 'bundle.invalidate'` and calls `refresh()`. Returns an\n * unsubscribe function.\n *\n * Degrades gracefully: if the subscriber is missing or throws, the\n * 5-min poll still keeps state converging.\n */\n subscribeInvalidations(subscriber: {\n onMessage: (handler: (msg: { type?: string; [k: string]: unknown }) => void) => () => void;\n }): () => void {\n try {\n const unsub = subscriber.onMessage((msg) => {\n if (msg && msg.type === 'bundle.invalidate') {\n this.refresh().catch((err) =>\n logger.warn('prefetch-bundle invalidate-refresh failed:', err),\n );\n }\n });\n return unsub;\n } catch (err) {\n logger.warn('prefetch-bundle subscribeInvalidations failed — relying on poll:', err);\n return () => {};\n }\n }\n\n // ── internals ──────────────────────────────────────────────────────────\n\n private async fetch(): Promise<PrefetchBundle | null> {\n const ctx = this.contextProvider();\n const qs = new URLSearchParams();\n if (ctx.device_type) qs.set('device_type', ctx.device_type);\n if (ctx.page_url) qs.set('page_url', ctx.page_url);\n if (ctx.geo) qs.set('geo', ctx.geo);\n qs.set('is_new_user', ctx.is_new_user ? 'true' : 'false');\n\n const url = `${this.apiHost}/v1/sdk/prefetch-bundle?${qs.toString()}`;\n\n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n Accept: 'application/json',\n };\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.propertyId) headers['X-Property-Id'] = this.propertyId;\n if (this.currentETag) headers['If-None-Match'] = this.currentETag;\n if (Object.keys(this.abAssignments).length > 0) {\n try {\n headers['X-AB-Assignments'] = btoa(JSON.stringify(this.abAssignments));\n } catch {\n // base64 on non-ASCII campaign IDs — skip rather than 400 the request\n }\n }\n\n let response: Response;\n try {\n response = await fetch(url, { method: 'GET', headers });\n } catch (err) {\n logger.warn('prefetch-bundle fetch network error:', err);\n return this.currentBundle;\n }\n\n // 304 — same bundle; listeners are intentionally NOT fired.\n if (response.status === 304) {\n return this.currentBundle;\n }\n\n if (!response.ok) {\n logger.warn(`prefetch-bundle fetch failed: HTTP ${response.status}`);\n return this.currentBundle;\n }\n\n const etag = response.headers.get('ETag');\n let bundle: PrefetchBundle;\n try {\n bundle = (await response.json()) as PrefetchBundle;\n } catch (err) {\n logger.warn('prefetch-bundle invalid JSON:', err);\n return this.currentBundle;\n }\n\n if (etag) this.currentETag = etag;\n this.currentBundle = bundle;\n\n for (const l of this.listeners) {\n try {\n l(bundle);\n } catch (err) {\n logger.warn('prefetch-bundle listener threw:', err);\n }\n }\n\n return bundle;\n }\n}\n","/**\n * AegisInbox — client-side App Inbox (Message Center).\n *\n * Backs the notification drawer on actii.me WebView and every tenant\n * storefront that embeds the Web SDK. Operates against cell-plane's\n * /v1/in-app/inbox family of endpoints (list, unread-count, read,\n * dismiss, read-all).\n *\n * Design choices:\n * • Hydrate from the prefetch bundle at init — no extra HTTP on first\n * paint. PrefetchBundleClient seeds us; we then own the live copy.\n * • Mutations are optimistic + beacon-backed. Read / dismiss writes to\n * local state immediately, then POSTs with `keepalive: true` so an\n * in-flight dismiss survives page unload.\n * • Badge polling uses the tiny `/unread-count` endpoint on a 60-second\n * cadence — matches the `inbox_poll_interval_ms` from sdk_config's\n * TransportConfig.hybrid mode.\n * • No external dependencies; IndexedDB is optional (we gracefully fall\n * back to in-memory when unavailable, e.g., in private browsing).\n */\n\nimport type { PrefetchBundleClient } from '../core/prefetch-bundle-client';\nimport { logger } from '../utils/logger';\n\nexport interface AegisInboxEntry {\n id: string;\n source: string;\n campaign_id: string | null;\n title: string;\n body: string;\n media_url: string | null;\n cta_url: string | null;\n metadata: Record<string, unknown> | null;\n read: boolean;\n read_at: string | null;\n dismissed_at?: string | null;\n created_at: string | null;\n expires_at: string | null;\n}\n\nexport interface AegisInboxConfig {\n apiHost: string;\n writeKey: string;\n organizationId?: string;\n contactId?: string;\n propertyId?: string;\n bundleClient?: PrefetchBundleClient;\n unreadPollIntervalMs?: number;\n}\n\nexport type InboxListener = (state: { entries: AegisInboxEntry[]; unreadCount: number }) => void;\n\nconst DEFAULT_UNREAD_POLL = 60_000;\n\n/** IndexedDB schema version + constants. Offline cache is a nice-to-have,\n * so we never break the app if IDB operations fail. */\nconst IDB_NAME = 'aegis-inbox';\nconst IDB_STORE = 'messages';\nconst IDB_VERSION = 1;\n\nexport class AegisInbox {\n private apiHost: string;\n private writeKey: string;\n private organizationId?: string;\n private contactId?: string;\n private propertyId?: string;\n private bundleClient?: PrefetchBundleClient;\n private unreadPollIntervalMs: number;\n\n private entries: AegisInboxEntry[] = [];\n private unreadCount = 0;\n private cursor: string | null = null;\n private listeners: InboxListener[] = [];\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private bundleUnsub: (() => void) | null = null;\n\n constructor(config: AegisInboxConfig) {\n this.apiHost = config.apiHost;\n this.writeKey = config.writeKey;\n this.organizationId = config.organizationId;\n this.contactId = config.contactId;\n this.propertyId = config.propertyId;\n this.bundleClient = config.bundleClient;\n this.unreadPollIntervalMs = config.unreadPollIntervalMs ?? DEFAULT_UNREAD_POLL;\n }\n\n /** Hydrate from bundle (if available), restore the IDB cache (if any),\n * then start the background unread-count poll. */\n async initialize(): Promise<void> {\n // Inbox is contact-scoped — if the host app hasn't resolved a contact\n // yet, stay dormant. The host will call setIdentity() later.\n if (!this.contactId || !this.propertyId) {\n logger.warn('AegisInbox: no contact/property yet — staying dormant');\n return;\n }\n\n // Try IDB cache for instant paint on cold start.\n const cached = await this.readCache();\n if (cached.length > 0) {\n this.entries = cached;\n this.recomputeUnread();\n this.emit();\n }\n\n // Hydrate from prefetch bundle if we have one — this is the preload\n // path, no additional network round-trip.\n if (this.bundleClient) {\n const inbox = this.bundleClient.getInbox();\n this.seedFromBundle(inbox.page, inbox.unread_count);\n // Keep following bundle changes — when the bundle-poller refreshes,\n // the inbox slice refreshes too.\n this.bundleUnsub = this.bundleClient.onChange((bundle) => {\n this.seedFromBundle(bundle.inbox.page, bundle.inbox.unread_count);\n });\n } else {\n // No bundle client — do one list call to prime.\n await this.refreshList();\n }\n\n this.pollTimer = setInterval(() => {\n this.refreshUnreadCount().catch((err) =>\n logger.warn('inbox unread-count poll failed:', err),\n );\n }, this.unreadPollIntervalMs);\n }\n\n stop(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n if (this.bundleUnsub) {\n this.bundleUnsub();\n this.bundleUnsub = null;\n }\n }\n\n /** Update identity after login / property switch. Clears the local\n * inbox since it's intrinsically contact+property scoped. */\n setIdentity(partial: { contactId?: string; propertyId?: string; organizationId?: string }): void {\n let changed = false;\n if (partial.contactId !== undefined && partial.contactId !== this.contactId) {\n this.contactId = partial.contactId;\n changed = true;\n }\n if (partial.propertyId !== undefined && partial.propertyId !== this.propertyId) {\n this.propertyId = partial.propertyId;\n changed = true;\n }\n if (partial.organizationId !== undefined && partial.organizationId !== this.organizationId) {\n this.organizationId = partial.organizationId;\n changed = true;\n }\n if (changed) {\n this.entries = [];\n this.unreadCount = 0;\n this.cursor = null;\n this.emit();\n void this.clearCache();\n void this.refreshList();\n }\n }\n\n // ── Read-side API ────────────────────────────────────────────────────\n\n getEntries(): AegisInboxEntry[] {\n return this.entries;\n }\n\n getUnreadCount(): number {\n return this.unreadCount;\n }\n\n /** Pagination cursor (ISO-8601 timestamp of the oldest entry currently\n * held). Pass it back via `loadMore()` to fetch older history. */\n getCursor(): string | null {\n return this.cursor;\n }\n\n /** Append one more page of older entries using the current cursor. */\n async loadMore(): Promise<void> {\n if (!this.contactId || !this.propertyId || !this.cursor) return;\n try {\n const url = `${this.apiHost}/v1/in-app/inbox?limit=20&cursor=${encodeURIComponent(this.cursor)}`;\n const resp = await fetch(url, { headers: this.headers() });\n if (!resp.ok) return;\n const body = (await resp.json()) as {\n entries: AegisInboxEntry[];\n unread_count: number;\n cursor: string | null;\n };\n const byId = new Set(this.entries.map((e) => e.id));\n for (const e of body.entries) {\n if (!byId.has(e.id)) this.entries.push(e);\n }\n this.cursor = body.cursor;\n void this.writeCache();\n this.emit();\n } catch (err) {\n logger.warn('inbox loadMore failed:', err);\n }\n }\n\n onChange(l: InboxListener): () => void {\n this.listeners.push(l);\n return () => {\n const i = this.listeners.indexOf(l);\n if (i >= 0) this.listeners.splice(i, 1);\n };\n }\n\n async refreshList(): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n const resp = await fetch(\n `${this.apiHost}/v1/in-app/inbox?limit=20`,\n { headers: this.headers() },\n );\n if (!resp.ok) {\n logger.warn(`inbox list fetch failed: HTTP ${resp.status}`);\n return;\n }\n const body = (await resp.json()) as {\n entries: AegisInboxEntry[];\n unread_count: number;\n cursor: string | null;\n };\n this.entries = body.entries;\n this.unreadCount = body.unread_count;\n this.cursor = body.cursor;\n void this.writeCache();\n this.emit();\n } catch (err) {\n logger.warn('inbox list fetch error:', err);\n }\n }\n\n async refreshUnreadCount(): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n const resp = await fetch(\n `${this.apiHost}/v1/in-app/inbox/unread-count`,\n { headers: this.headers() },\n );\n if (!resp.ok) return;\n const body = (await resp.json()) as { unread_count: number };\n if (body.unread_count !== this.unreadCount) {\n this.unreadCount = body.unread_count;\n this.emit();\n // New messages detected — do a list refresh to get them.\n if (this.unreadCount > 0) {\n void this.refreshList();\n }\n }\n } catch {\n /* swallow — transient network */\n }\n }\n\n // ── Mutations (optimistic + beacon) ──────────────────────────────────\n\n async markRead(messageId: string): Promise<void> {\n const entry = this.entries.find((e) => e.id === messageId);\n if (!entry || entry.read) return;\n entry.read = true;\n entry.read_at = new Date().toISOString();\n this.recomputeUnread();\n void this.writeCache();\n this.emit();\n await this.postBeacon(`/v1/in-app/inbox/${messageId}/read`);\n }\n\n async dismiss(messageId: string): Promise<void> {\n const idx = this.entries.findIndex((e) => e.id === messageId);\n if (idx < 0) return;\n const [entry] = this.entries.splice(idx, 1);\n if (entry && !entry.read) {\n this.recomputeUnread();\n }\n void this.writeCache();\n this.emit();\n await this.postBeacon(`/v1/in-app/inbox/${messageId}/dismiss`);\n }\n\n async markAllRead(): Promise<void> {\n const now = new Date().toISOString();\n for (const e of this.entries) {\n if (!e.read) {\n e.read = true;\n e.read_at = now;\n }\n }\n this.unreadCount = 0;\n void this.writeCache();\n this.emit();\n await this.postBeacon('/v1/in-app/inbox/read-all');\n }\n\n // ── Internals ────────────────────────────────────────────────────────\n\n private seedFromBundle(page: AegisInboxEntry[], unreadCount: number): void {\n // Merge rather than overwrite — an entry we already marked read\n // locally should stay read even if the bundle is slightly stale.\n const byId = new Map(this.entries.map((e) => [e.id, e] as const));\n const merged = page.map((incoming) => {\n const existing = byId.get(incoming.id);\n if (existing && existing.read && !incoming.read) {\n return { ...incoming, read: true, read_at: existing.read_at };\n }\n return incoming;\n });\n // Preserve any locally-cached entries that aren't in this bundle page\n // (e.g., older history not included in the first slice).\n for (const [id, e] of byId) {\n if (!merged.find((m) => m.id === id)) merged.push(e);\n }\n merged.sort((a, b) => (b.created_at || '').localeCompare(a.created_at || ''));\n this.entries = merged;\n this.unreadCount = unreadCount;\n void this.writeCache();\n this.emit();\n }\n\n private recomputeUnread(): void {\n this.unreadCount = this.entries.filter((e) => !e.read).length;\n }\n\n private emit(): void {\n const snapshot = { entries: [...this.entries], unreadCount: this.unreadCount };\n for (const l of this.listeners) {\n try {\n l(snapshot);\n } catch (err) {\n logger.warn('inbox listener threw:', err);\n }\n }\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n Accept: 'application/json',\n };\n if (this.organizationId) h['X-Organization-ID'] = this.organizationId;\n if (this.contactId) h['X-Contact-ID'] = this.contactId;\n if (this.propertyId) h['X-Property-Id'] = this.propertyId;\n return h;\n }\n\n /** Best-effort beacon-style POST. Uses `keepalive: true` so it survives\n * a navigation away from the current page (e.g., user taps the CTA\n * which takes them to another URL right after dismiss). */\n private async postBeacon(path: string): Promise<void> {\n if (!this.contactId || !this.propertyId) return;\n try {\n await fetch(`${this.apiHost}${path}`, {\n method: 'POST',\n headers: this.headers(),\n keepalive: true,\n });\n } catch (err) {\n // The mutation is already applied locally; failed delivery will be\n // reconciled on the next refreshList().\n logger.warn(`inbox mutation POST ${path} failed:`, err);\n }\n }\n\n // ── IndexedDB cache (non-critical) ───────────────────────────────────\n\n private async openDb(): Promise<IDBDatabase | null> {\n if (typeof indexedDB === 'undefined') return null;\n return new Promise((resolve) => {\n try {\n const req = indexedDB.open(IDB_NAME, IDB_VERSION);\n req.onerror = () => resolve(null);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(IDB_STORE)) {\n db.createObjectStore(IDB_STORE);\n }\n };\n req.onsuccess = () => resolve(req.result);\n } catch {\n resolve(null);\n }\n });\n }\n\n private cacheKey(): string | null {\n if (!this.contactId || !this.propertyId) return null;\n return `${this.organizationId || 'default'}:${this.propertyId}:${this.contactId}`;\n }\n\n private async writeCache(): Promise<void> {\n const key = this.cacheKey();\n if (!key) return;\n const db = await this.openDb();\n if (!db) return;\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).put(this.entries, key);\n await new Promise<void>((res, rej) => {\n tx.oncomplete = () => res();\n tx.onerror = () => rej(tx.error);\n });\n } catch {\n /* noop */\n } finally {\n db.close();\n }\n }\n\n private async readCache(): Promise<AegisInboxEntry[]> {\n const key = this.cacheKey();\n if (!key) return [];\n const db = await this.openDb();\n if (!db) return [];\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const req = tx.objectStore(IDB_STORE).get(key);\n return await new Promise<AegisInboxEntry[]>((res) => {\n req.onsuccess = () => res((req.result as AegisInboxEntry[]) || []);\n req.onerror = () => res([]);\n });\n } catch {\n return [];\n } finally {\n db.close();\n }\n }\n\n private async clearCache(): Promise<void> {\n const key = this.cacheKey();\n if (!key) return;\n const db = await this.openDb();\n if (!db) return;\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).delete(key);\n await new Promise<void>((res) => {\n tx.oncomplete = () => res();\n tx.onerror = () => res();\n });\n } catch {\n /* noop */\n } finally {\n db.close();\n }\n }\n}\n","/**\n * AegisWidgetManager - Web SDK Widget Module\n * \n * Smart Pull architecture for persistent web widgets.\n * \n * Features:\n * - Gamification (spin wheel, scratch card) with server-side prize generation\n * - Chat bubbles (WhatsApp, support)\n * - Social proof toasts (real-time purchase notifications)\n * - Feedback forms (NPS, surveys)\n * \n * Security:\n * - XSS Protection: Uses DOM APIs instead of innerHTML\n * - Server-side prize generation prevents client manipulation\n * - URL validation prevents javascript: protocol injection\n * \n * Architecture:\n * - Fetches widget configs from /v1/widgets/config on page load\n * - Integrates with TriggerEngine for behavioral triggers\n * - Tracks widget events (show, click, dismiss, submit)\n * - Server-side prize generation for gamification\n */\n\nimport { TriggerEngine } from '../triggers/TriggerEngine';\nimport { Storage } from '../utils/storage';\n\n// Read the SDK's persisted anonymous_id from localStorage/cookie if available.\n// Returns undefined when called server-side or when no id has been minted yet.\n// See AegisInAppManager for the same pattern + canonical contract in\n// docs/architecture/API_ROUTING.md §3.\nfunction readAnonIdFromStorage(): string | undefined {\n if (typeof document === 'undefined') return undefined;\n try {\n const storage = new Storage();\n return storage.get('anon_id') ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport interface WidgetConfig {\n widget_id: string;\n widget_type: 'chat_bubble' | 'spin_wheel' | 'scratch_card' | 'toast' | 'feedback_form' | 'exit_intent_popup';\n name: string;\n config: Record<string, any>;\n position?: string;\n priority: number;\n trigger_rules?: {\n type: 'exit_intent' | 'scroll_depth' | 'time_on_page' | 'immediate';\n config?: Record<string, any>;\n };\n}\n\nexport interface GamificationPrize {\n prize_label: string;\n prize_value?: string;\n coupon_code?: string;\n play_id: string;\n}\n\nexport interface AegisWidgetConfig {\n writeKey: string;\n apiHost?: string;\n userId?: string;\n contactId?: string;\n organizationId?: string;\n debugMode?: boolean;\n triggerEngine?: TriggerEngine;\n /** If true, WidgetManager takes ownership of the TriggerEngine and\n * will call `triggerEngine.stop()` on destroy(). Leave false when\n * the caller shares the engine across managers (e.g. the facade). */\n ownsTriggerEngine?: boolean;\n enablePrefetch?: boolean;\n cssCustomization?: WidgetCSSCustomization;\n onEvent?: (eventType: string, data: any) => void;\n /** Source platform passed as X-Source-Platform header so the API\n * can filter campaigns whose display_rules.sources restricts them\n * to specific integrations (e.g. 'shopify', 'woocommerce'). */\n sourcePlatform?: 'web' | 'shopify' | 'woocommerce' | 'mobile_sdk';\n /**\n * Workspace cascade reader. Host SDK sets this to\n * `() => aegis.getEffectiveWorkspaceId()` so widget interaction events\n * (impressions, clicks, spin/scratch plays, feedback submissions)\n * arrive at the gateway with the same workspace context the main\n * analytics SDK uses. See PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n */\n getWorkspaceId?: () => string | undefined;\n}\n\nexport interface WidgetCSSCustomization {\n exitIntent?: {\n backgroundColor?: string;\n textColor?: string;\n accentColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n overlayOpacity?: number;\n };\n spinWheel?: {\n backgroundColor?: string;\n textColor?: string;\n accentColor?: string;\n borderRadius?: string;\n fontFamily?: string;\n wheelColors?: string[];\n buttonColor?: string;\n };\n chatBubble?: {\n backgroundColor?: string;\n textColor?: string;\n position?: 'bottom_right' | 'bottom_left' | 'top_right' | 'top_left';\n size?: 'small' | 'medium' | 'large';\n };\n}\n\nexport interface PrefetchWidgetConfig {\n exit_intent?: {\n enabled: boolean;\n type: 'cart_recovery' | 'lead_gen';\n tier?: string;\n title?: string;\n message?: string;\n discount_code?: string;\n discount_percentage?: number;\n cta_text?: string;\n cta_url?: string;\n background_color?: string;\n text_color?: string;\n accent_color?: string;\n show_cart_items?: boolean;\n show_timer?: boolean;\n timer_minutes?: number;\n priority: number;\n mobile_triggers?: {\n scroll_velocity?: boolean;\n scroll_threshold?: number;\n scroll_min_position?: number;\n scroll_cooldown?: number;\n idle_timer?: boolean;\n idle_seconds?: number;\n visibility_change?: boolean;\n back_button?: boolean;\n };\n };\n spin_wheel?: {\n enabled: boolean;\n type: 'lead_gen' | 'cart_recovery';\n title?: string;\n prizes?: any[];\n priority: number;\n };\n}\n\nexport interface CartData {\n cart_id: string;\n cart_total: number;\n cart_currency: string;\n cart_items: Array<{\n product_id: string;\n product_name?: string;\n quantity: number;\n price?: number;\n }>;\n}\n\nexport class AegisWidgetManager {\n private writeKey: string;\n private apiHost: string;\n private userId?: string;\n private contactId?: string;\n private organizationId?: string;\n private debugMode: boolean;\n private triggerEngine?: TriggerEngine;\n private enablePrefetch: boolean;\n private cssCustomization: WidgetCSSCustomization;\n private onEvent?: (eventType: string, data: any) => void;\n private sourcePlatform?: string;\n private getWorkspaceId?: () => string | undefined;\n\n private widgets: WidgetConfig[] = [];\n private renderedWidgets = new Set<string>();\n private isInitialized = false;\n private isDestroyed = false;\n private ownsTriggerEngine: boolean;\n\n private prefetchWidgetConfigs: PrefetchWidgetConfig = {};\n private cartData?: CartData;\n \n constructor(config: AegisWidgetConfig) {\n this.writeKey = config.writeKey;\n this.apiHost = config.apiHost || 'https://api.aegis.ai';\n // Fall back to the SDK's persisted anonymous_id when callers don't pass\n // userId explicitly. Without this, /v1/widgets/config requests omit\n // X-User-ID and the cell-plane buckets the call into \"anonymous\", which\n // misses any user-targeted widget configs. Mirror in AegisInAppManager.\n this.userId = config.userId ?? readAnonIdFromStorage();\n this.contactId = config.contactId;\n this.organizationId = config.organizationId;\n this.debugMode = config.debugMode || false;\n this.triggerEngine = config.triggerEngine;\n this.ownsTriggerEngine = config.ownsTriggerEngine === true;\n this.enablePrefetch = config.enablePrefetch !== false;\n this.cssCustomization = config.cssCustomization || {};\n this.onEvent = config.onEvent;\n this.sourcePlatform = config.sourcePlatform;\n this.getWorkspaceId = config.getWorkspaceId;\n }\n \n updateCSSCustomization(customization: WidgetCSSCustomization): void {\n this.cssCustomization = { ...this.cssCustomization, ...customization };\n this.log('CSS customization updated');\n }\n\n /**\n * Swap the identity that outgoing widget requests are attributed to.\n * Safe to call at any time; if prefetch is enabled and the manager\n * has already initialised, this will re-fetch the per-contact widget\n * configs so subsequent renders target the new identity. Does NOT\n * re-render already-visible widgets — a full teardown requires destroy().\n */\n async updateContactId(contactId: string | undefined): Promise<void> {\n if (this.contactId === contactId) return;\n this.contactId = contactId;\n this.log(`Contact ID updated → ${contactId ?? '(cleared)'}`);\n if (this.isInitialized && !this.isDestroyed && this.enablePrefetch && contactId) {\n await this.fetchPrefetchConfigs();\n this.preloadWidgetAssets();\n }\n }\n\n /**\n * Render an in-app campaign whose sub_type routes it to the\n * gamification-widget code path (spin_wheel / scratch_card).\n * InAppCampaign is adapted to the minimal WidgetConfig shape that\n * the internal renderers already understand — no rewrite needed.\n *\n * AegisMessageRuntime wires this method as AegisInAppManager's\n * `onInteractiveCampaign` callback so impressions from the inbox\n * prefetch bundle actually land on screen.\n */\n renderInteractiveCampaign(campaign: {\n id: string;\n title: string;\n sub_type?: string;\n priority?: number;\n interactive_config?: Record<string, unknown>;\n }): void {\n if (this.isDestroyed) return;\n if (typeof document === 'undefined') return;\n const subType = campaign.sub_type;\n if (subType !== 'spin_wheel' && subType !== 'scratch_card') {\n this.log(`renderInteractiveCampaign: unsupported sub_type \"${subType}\"`, true);\n return;\n }\n const widget: WidgetConfig = {\n widget_id: campaign.id,\n widget_type: subType,\n name: campaign.title,\n config: (campaign.interactive_config ?? {}) as Record<string, any>,\n priority: campaign.priority ?? 0,\n };\n if (this.renderedWidgets.has(widget.widget_id)) return;\n this.renderedWidgets.add(widget.widget_id);\n if (subType === 'spin_wheel') {\n this.renderSpinWheel(widget);\n } else {\n this.renderScratchCard(widget);\n }\n }\n\n /**\n * Tear down everything the manager installed: trigger listeners (if\n * we own the TriggerEngine), injected style sheets, and any rendered\n * widget roots. Further render attempts from in-flight triggers are\n * short-circuited by the `isDestroyed` flag.\n */\n destroy(): void {\n if (this.isDestroyed) return;\n this.isDestroyed = true;\n\n if (this.triggerEngine && this.ownsTriggerEngine) {\n this.triggerEngine.stop();\n }\n\n if (typeof document !== 'undefined') {\n const animationStyle = document.getElementById('aegis-widget-animations');\n animationStyle?.remove();\n document.querySelectorAll('[data-aegis-widget-root]').forEach((node) => {\n node.remove();\n });\n }\n\n this.renderedWidgets.clear();\n this.widgets = [];\n this.isInitialized = false;\n this.log('AegisWidgets destroyed');\n this.emitEvent('destroyed', {});\n }\n\n /**\n * Fire a lifecycle event to the consumer-supplied callback. Public-API\n * hook configured via `AegisWidgetConfig.onEvent`. Currently only used\n * by external callers passing their own logger; internal widget lifecycle\n * events get wired through here as they're added.\n */\n private emitEvent(eventType: string, data: unknown): void {\n if (this.onEvent) {\n try {\n this.onEvent(eventType, data);\n } catch (error) {\n this.log(`Error in event callback: ${error}`, true);\n }\n }\n }\n\n async initialize(): Promise<void> {\n if (this.isInitialized) {\n this.log('AegisWidgets already initialized');\n return;\n }\n \n if (this.enablePrefetch && this.contactId) {\n await this.fetchPrefetchConfigs();\n this.preloadWidgetAssets();\n }\n \n await this.fetchWidgets();\n \n this.renderImmediateWidgets();\n \n this.setupTriggerListeners();\n \n this.setupExitIntentWithPrefetch();\n \n this.isInitialized = true;\n this.log('AegisWidgets initialized successfully');\n }\n \n setCartData(cartData: CartData): void {\n this.cartData = cartData;\n this.log(`Cart data updated: ${cartData.cart_items.length} items, total: ${cartData.cart_currency} ${cartData.cart_total}`);\n }\n \n private detectPlatformCart(): CartData | null {\n const shopifyCart = this.normalizeShopifyCart();\n if (shopifyCart) {\n this.log('Detected Shopify cart via browser globals');\n return shopifyCart;\n }\n \n const wooCart = this.normalizeWooCart();\n if (wooCart) {\n this.log('Detected WooCommerce cart via injected data');\n return wooCart;\n }\n \n const magentoCart = this.normalizeMagentoCart();\n if (magentoCart) {\n this.log('Detected Magento cart via localStorage');\n return magentoCart;\n }\n \n if (this.cartData) {\n this.log('Using manually set cart data');\n return this.cartData;\n }\n \n return null;\n }\n \n private normalizeShopifyCart(): CartData | null {\n try {\n if (typeof window === 'undefined') return null;\n \n const win = window as any;\n \n if (win.Shopify?.checkout) {\n const checkout = win.Shopify.checkout;\n return {\n cart_id: checkout.token || `shopify_${Date.now()}`,\n cart_total: parseFloat(checkout.total_price) || 0,\n cart_currency: checkout.currency || 'USD',\n cart_items: (checkout.line_items || []).map((item: any) => ({\n product_id: String(item.product_id || item.id),\n product_name: item.title || item.product_title,\n quantity: item.quantity || 1,\n price: parseFloat(item.price) || 0\n }))\n };\n }\n \n const cartJsonEl = document.getElementById('cart-json');\n if (cartJsonEl?.textContent) {\n const cart = JSON.parse(cartJsonEl.textContent);\n return {\n cart_id: cart.token || `shopify_${Date.now()}`,\n cart_total: (cart.total_price || 0) / 100,\n cart_currency: cart.currency || 'USD',\n cart_items: (cart.items || []).map((item: any) => ({\n product_id: String(item.product_id || item.id),\n product_name: item.product_title || item.title,\n quantity: item.quantity || 1,\n price: (item.price || 0) / 100\n }))\n };\n }\n \n return null;\n } catch (error) {\n this.log(`Error detecting Shopify cart: ${error}`, true);\n return null;\n }\n }\n \n private normalizeWooCart(): CartData | null {\n try {\n if (typeof window === 'undefined') return null;\n \n const win = window as any;\n \n if (win.aegis_cart) {\n const cart = win.aegis_cart;\n return {\n cart_id: cart.cart_id || `woo_${Date.now()}`,\n cart_total: parseFloat(cart.cart_total) || 0,\n cart_currency: cart.cart_currency || 'USD',\n cart_items: (cart.cart_items || []).map((item: any) => ({\n product_id: String(item.product_id),\n product_name: item.product_name,\n quantity: item.quantity || 1,\n price: parseFloat(item.price) || 0\n }))\n };\n }\n \n return null;\n } catch (error) {\n this.log(`Error detecting WooCommerce cart: ${error}`, true);\n return null;\n }\n }\n \n private normalizeMagentoCart(): CartData | null {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return null;\n \n const mageCacheStr = localStorage.getItem('mage-cache-storage');\n if (!mageCacheStr) return null;\n \n const mageCache = JSON.parse(mageCacheStr);\n if (!mageCache?.cart) return null;\n \n const cart = mageCache.cart;\n \n return {\n cart_id: cart.quote_id || cart.id || `magento_${Date.now()}`,\n cart_total: parseFloat(cart.subtotalAmount || cart.subtotal || 0),\n cart_currency: cart.currencyCode || 'USD',\n cart_items: (cart.items || []).map((item: any) => ({\n product_id: String(item.item_id || item.product_id),\n product_name: item.product_name || item.name,\n quantity: item.qty || 1,\n price: parseFloat(item.product_price_value || item.price || 0)\n }))\n };\n } catch (error) {\n this.log(`Error detecting Magento cart: ${error}`, true);\n return null;\n }\n }\n \n private preloadWidgetAssets(): void {\n try {\n const exitIntentConfig = this.prefetchWidgetConfigs.exit_intent;\n if (exitIntentConfig?.enabled) {\n const imageUrl = (exitIntentConfig as any).image_url;\n if (imageUrl) {\n const img = new Image();\n img.src = imageUrl;\n this.log(`Preloading exit intent image: ${imageUrl}`);\n }\n }\n \n const spinWheelConfig = this.prefetchWidgetConfigs.spin_wheel;\n if (spinWheelConfig?.enabled) {\n const imageUrl = (spinWheelConfig as any).image_url;\n if (imageUrl) {\n const img = new Image();\n img.src = imageUrl;\n this.log(`Preloading spin wheel image: ${imageUrl}`);\n }\n }\n } catch (error) {\n this.log(`Error preloading widget assets: ${error}`, true);\n }\n }\n \n private async fetchPrefetchConfigs(): Promise<void> {\n try {\n const startTime = performance.now();\n const url = `${this.apiHost}/v1/widgets/config/prefetch`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n };\n \n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, { headers, credentials: 'include' });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch prefetch configs: ${response.status}`);\n }\n \n this.prefetchWidgetConfigs = await response.json();\n \n const elapsed = performance.now() - startTime;\n this.log(`Fetched prefetch widget configs in ${elapsed.toFixed(2)}ms`);\n \n } catch (error) {\n this.log(`Error fetching prefetch configs: ${error}`, true);\n }\n }\n \n private async fetchWidgets(): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/widgets/config`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'X-Device-Platform': 'web',\n 'X-Device-Type': this.getDeviceType()\n };\n\n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n if (this.sourcePlatform) headers['X-Source-Platform'] = this.sourcePlatform;\n \n const response = await fetch(url, { headers, credentials: 'include' });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch widgets: ${response.status}`);\n }\n \n this.widgets = await response.json();\n \n this.log(`Fetched ${this.widgets.length} widgets`);\n \n } catch (error) {\n this.log(`Error fetching widgets: ${error}`, true);\n }\n }\n \n private renderImmediateWidgets(): void {\n const immediateWidgets = this.widgets.filter(w => \n !w.trigger_rules || w.trigger_rules.type === 'immediate'\n );\n \n immediateWidgets.forEach(widget => this.renderWidget(widget));\n }\n \n private setupTriggerListeners(): void {\n if (!this.triggerEngine) {\n this.log('TriggerEngine not provided, skipping trigger-based widgets');\n return;\n }\n \n this.widgets.forEach(widget => {\n if (!widget.trigger_rules) return;\n \n const { type, config } = widget.trigger_rules;\n \n switch (type) {\n case 'exit_intent':\n this.triggerEngine!.registerExitIntent();\n this.triggerEngine!.on('exit_intent', () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n \n case 'scroll_depth':\n const depthPercent = (config as any)?.depth_percent || 50;\n this.triggerEngine!.registerScrollDepth(depthPercent);\n this.triggerEngine!.on(`scroll_depth_${depthPercent}`, () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n \n case 'time_on_page':\n const seconds = (config as any)?.seconds || 30;\n this.triggerEngine!.registerTimeOnPage(seconds);\n this.triggerEngine!.on(`time_on_page_${seconds}`, () => {\n if (!this.renderedWidgets.has(widget.widget_id)) {\n this.renderWidget(widget);\n }\n });\n break;\n }\n });\n }\n \n private setupExitIntentWithPrefetch(): void {\n if (!this.enablePrefetch || !this.triggerEngine) {\n return;\n }\n \n const spinWheelConfig = this.prefetchWidgetConfigs.spin_wheel;\n const exitIntentConfig = this.prefetchWidgetConfigs.exit_intent;\n \n if (spinWheelConfig && spinWheelConfig.enabled) {\n const isMobile = this.isMobileDevice();\n const mobileConfig = exitIntentConfig?.mobile_triggers || {};\n \n const handleSpinWheelIntent = () => {\n const widgetId = `prefetch_spin_wheel_${Date.now()}`;\n \n if (this.renderedWidgets.has(widgetId)) {\n return;\n }\n \n this.renderedWidgets.add(widgetId);\n \n const detectedCart = this.detectPlatformCart();\n \n if (spinWheelConfig.type === 'cart_recovery' && detectedCart) {\n this.cartData = detectedCart;\n this.renderSpinWheelWidget(widgetId, spinWheelConfig);\n this.sendCartAbandonmentBeacon();\n } else if (spinWheelConfig.type === 'lead_gen') {\n this.renderSpinWheelWidget(widgetId, spinWheelConfig);\n }\n };\n \n if (isMobile) {\n const scrollVelocityEnabled = mobileConfig.scroll_velocity !== false;\n if (scrollVelocityEnabled) {\n this.triggerEngine.registerScrollVelocity({\n threshold: mobileConfig.scroll_threshold || 0.5,\n minScrollPosition: mobileConfig.scroll_min_position || 100,\n cooldown: mobileConfig.scroll_cooldown || 5000\n });\n this.triggerEngine.on('mobile_exit_intent', handleSpinWheelIntent);\n this.log('Registered mobile scroll velocity trigger for spin wheel');\n }\n \n const idleTimerEnabled = mobileConfig.idle_timer !== false;\n if (idleTimerEnabled) {\n const idleSeconds = mobileConfig.idle_seconds || 15;\n this.triggerEngine.registerInactivity(idleSeconds);\n this.triggerEngine.on(`inactivity_${idleSeconds}`, handleSpinWheelIntent);\n this.log(`Registered mobile idle timer trigger for spin wheel: ${idleSeconds}s`);\n }\n \n const visibilityChangeEnabled = mobileConfig.visibility_change !== false;\n if (visibilityChangeEnabled) {\n const detectedCart = this.detectPlatformCart();\n if (detectedCart && detectedCart.cart_items && detectedCart.cart_items.length > 0) {\n this.triggerEngine.registerVisibilityChange();\n this.triggerEngine.on('visibility_hidden', handleSpinWheelIntent);\n this.log('Registered mobile visibility change trigger for spin wheel (cart detected)');\n }\n }\n \n const backButtonEnabled = mobileConfig.back_button === true;\n if (backButtonEnabled) {\n this.triggerEngine.registerBackButton();\n this.triggerEngine.on('back_button', handleSpinWheelIntent);\n this.log('Registered mobile back button trigger for spin wheel');\n }\n \n this.log(`Setup mobile spin wheel: type=${spinWheelConfig.type}, priority=${spinWheelConfig.priority}`);\n } else {\n this.triggerEngine.registerExitIntent();\n this.triggerEngine.on('exit_intent', handleSpinWheelIntent);\n this.log(`Setup desktop spin wheel exit intent: type=${spinWheelConfig.type}, priority=${spinWheelConfig.priority}`);\n }\n \n return;\n }\n \n if (!exitIntentConfig || !exitIntentConfig.enabled) {\n this.log('No exit intent config found in prefetch');\n return;\n }\n \n const isMobile = this.isMobileDevice();\n const mobileConfig = exitIntentConfig.mobile_triggers || {};\n \n const handleExitIntent = () => {\n const widgetId = `prefetch_exit_intent_${Date.now()}`;\n \n if (this.renderedWidgets.has(widgetId)) {\n return;\n }\n \n this.renderedWidgets.add(widgetId);\n \n const detectedCart = this.detectPlatformCart();\n \n if (exitIntentConfig.type === 'cart_recovery' && detectedCart) {\n this.cartData = detectedCart;\n this.renderCartRecoveryPopup(widgetId, exitIntentConfig);\n this.sendCartAbandonmentBeacon();\n } else if (exitIntentConfig.type === 'lead_gen') {\n this.renderLeadGenPopup(widgetId, exitIntentConfig);\n } else {\n this.log('Unknown exit intent type or missing cart data');\n }\n };\n \n if (isMobile) {\n const scrollVelocityEnabled = mobileConfig.scroll_velocity !== false;\n if (scrollVelocityEnabled) {\n this.triggerEngine.registerScrollVelocity({\n threshold: mobileConfig.scroll_threshold || 0.5,\n minScrollPosition: mobileConfig.scroll_min_position || 100,\n cooldown: mobileConfig.scroll_cooldown || 5000\n });\n this.triggerEngine.on('mobile_exit_intent', handleExitIntent);\n this.log('Registered mobile scroll velocity trigger');\n }\n \n const idleTimerEnabled = mobileConfig.idle_timer !== false;\n if (idleTimerEnabled) {\n const idleSeconds = mobileConfig.idle_seconds || 15;\n this.triggerEngine.registerInactivity(idleSeconds);\n this.triggerEngine.on(`inactivity_${idleSeconds}`, handleExitIntent);\n this.log(`Registered mobile idle timer trigger: ${idleSeconds}s`);\n }\n \n const visibilityChangeEnabled = mobileConfig.visibility_change !== false;\n if (visibilityChangeEnabled) {\n const detectedCart = this.detectPlatformCart();\n if (detectedCart && detectedCart.cart_items && detectedCart.cart_items.length > 0) {\n this.triggerEngine.registerVisibilityChange();\n this.triggerEngine.on('visibility_hidden', handleExitIntent);\n this.log('Registered mobile visibility change trigger (cart detected)');\n } else {\n this.log('Skipped visibility change trigger (no cart items)');\n }\n }\n \n const backButtonEnabled = mobileConfig.back_button === true;\n if (backButtonEnabled) {\n this.triggerEngine.registerBackButton();\n this.triggerEngine.on('back_button', handleExitIntent);\n this.log('Registered mobile back button trigger (aggressive mode)');\n }\n \n this.log(`Setup mobile exit intent: type=${exitIntentConfig.type}, priority=${exitIntentConfig.priority}`);\n } else {\n this.triggerEngine.registerExitIntent();\n this.triggerEngine.on('exit_intent', handleExitIntent);\n this.log(`Setup desktop exit intent: type=${exitIntentConfig.type}, priority=${exitIntentConfig.priority}`);\n }\n }\n \n private sendCartAbandonmentBeacon(): void {\n if (!this.cartData) {\n this.log('No cart data available for beacon', true);\n return;\n }\n \n const beaconData = {\n organization_id: this.organizationId || 'default',\n contact_id: this.contactId,\n cart_id: this.cartData.cart_id,\n cart_total: this.cartData.cart_total,\n cart_currency: this.cartData.cart_currency,\n cart_items: this.cartData.cart_items,\n user_email: this.userId,\n abandoned_at: new Date().toISOString(),\n page_url: window.location.href,\n referrer: document.referrer\n };\n \n const beaconUrl = `${this.apiHost}/v1/widgets/beacon/cart-abandoned`;\n \n if (navigator.sendBeacon) {\n const blob = new Blob([JSON.stringify(beaconData)], { type: 'application/json' });\n const sent = navigator.sendBeacon(beaconUrl, blob);\n \n if (sent) {\n this.log('Cart abandonment beacon sent successfully');\n } else {\n this.log('Failed to send cart abandonment beacon', true);\n }\n } else {\n fetch(beaconUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Aegis-Write-Key': this.writeKey\n },\n body: JSON.stringify(beaconData),\n keepalive: true,\n credentials: 'include',\n }).catch(err => {\n this.log(`Error sending cart abandonment via fetch: ${err}`, true);\n });\n }\n }\n \n private renderWidget(widget: WidgetConfig): void {\n if (this.isDestroyed) return;\n if (this.renderedWidgets.has(widget.widget_id)) {\n return;\n }\n\n this.renderedWidgets.add(widget.widget_id);\n \n switch (widget.widget_type) {\n case 'chat_bubble':\n this.renderChatBubble(widget);\n break;\n case 'spin_wheel':\n this.renderSpinWheel(widget);\n break;\n case 'scratch_card':\n this.renderScratchCard(widget);\n break;\n case 'toast':\n this.renderToast(widget);\n break;\n case 'feedback_form':\n this.renderFeedbackForm(widget);\n break;\n case 'exit_intent_popup':\n this.renderExitIntentPopup(widget);\n break;\n default:\n this.log(`Unknown widget type: ${widget.widget_type}`, true);\n }\n \n this.trackEvent(widget.widget_id, 'show');\n }\n \n private renderChatBubble(widget: WidgetConfig): void {\n const { text, icon_url, link_url, background_color, text_color } = widget.config;\n const position = widget.position || 'bottom_right';\n \n const bubble = document.createElement('div');\n bubble.className = 'aegis-chat-bubble';\n bubble.setAttribute('data-widget-id', widget.widget_id);\n \n const positionStyles: Record<string, string> = {\n bottom_right: 'bottom: 20px; right: 20px;',\n bottom_left: 'bottom: 20px; left: 20px;',\n top_right: 'top: 20px; right: 20px;',\n top_left: 'top: 20px; left: 20px;'\n };\n \n bubble.style.cssText = `\n position: fixed;\n ${positionStyles[position] || positionStyles.bottom_right}\n background: ${this.sanitizeColor(background_color || '#25D366')};\n color: ${this.sanitizeColor(text_color || '#ffffff')};\n padding: 16px 24px;\n border-radius: 50px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n cursor: pointer;\n z-index: 999999;\n display: flex;\n align-items: center;\n gap: 12px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n font-weight: 600;\n font-size: 14px;\n animation: aegisBubbleIn 0.3s ease-out;\n `;\n \n if (icon_url) {\n const icon = document.createElement('img');\n const safeUrl = this.sanitizeUrl(icon_url);\n if (safeUrl) {\n icon.src = safeUrl;\n icon.alt = '';\n icon.style.cssText = 'width: 24px; height: 24px;';\n bubble.appendChild(icon);\n }\n }\n \n const textEl = document.createElement('span');\n textEl.textContent = text || 'Chat with us';\n bubble.appendChild(textEl);\n \n bubble.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'click');\n const safeUrl = this.sanitizeUrl(link_url);\n if (safeUrl) {\n window.open(safeUrl, '_blank');\n }\n });\n \n this.addAnimationStyles();\n bubble.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(bubble);\n }\n \n private renderSpinWheel(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-gamification-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-spin-wheel-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'Spin to Win!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Try your luck and win exclusive prizes!';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n modal.appendChild(description);\n \n // Draw an SVG wheel that honours the tenant's configured segments.\n // Each segment's `color` + `label` is painted as a pie slice; falls\n // back to a 4-color placeholder if no segments are provided.\n const segments: Array<{ label: string; color?: string }> = Array.isArray(\n (widget.config as any).segments,\n )\n ? (widget.config as any).segments\n : [\n { label: 'Prize 1', color: '#ff6b6b' },\n { label: 'Prize 2', color: '#feca57' },\n { label: 'Prize 3', color: '#48dbfb' },\n { label: 'Prize 4', color: '#ff6348' },\n ];\n\n const SVG_NS = 'http://www.w3.org/2000/svg';\n const wheel = document.createElementNS(SVG_NS, 'svg');\n wheel.setAttribute('viewBox', '-160 -160 320 320');\n wheel.setAttribute('width', '300');\n wheel.setAttribute('height', '300');\n wheel.style.cssText = 'margin: 0 auto 24px; display: block;';\n\n const n = segments.length;\n const anglePer = (2 * Math.PI) / n;\n const radius = 140;\n for (let i = 0; i < n; i++) {\n const start = i * anglePer - Math.PI / 2;\n const end = start + anglePer;\n const x1 = Math.cos(start) * radius;\n const y1 = Math.sin(start) * radius;\n const x2 = Math.cos(end) * radius;\n const y2 = Math.sin(end) * radius;\n const largeArc = anglePer > Math.PI ? 1 : 0;\n const path = document.createElementNS(SVG_NS, 'path');\n path.setAttribute(\n 'd',\n `M 0 0 L ${x1.toFixed(2)} ${y1.toFixed(2)} A ${radius} ${radius} 0 ${largeArc} 1 ${x2.toFixed(2)} ${y2.toFixed(2)} Z`,\n );\n path.setAttribute('fill', this.sanitizeColor(segments[i].color || '#cccccc'));\n path.setAttribute('stroke', '#ffffff');\n path.setAttribute('stroke-width', '2');\n wheel.appendChild(path);\n\n const labelAngle = start + anglePer / 2;\n const lx = Math.cos(labelAngle) * radius * 0.65;\n const ly = Math.sin(labelAngle) * radius * 0.65;\n const text = document.createElementNS(SVG_NS, 'text');\n text.setAttribute('x', lx.toFixed(2));\n text.setAttribute('y', ly.toFixed(2));\n text.setAttribute('fill', '#ffffff');\n text.setAttribute('font-size', '13');\n text.setAttribute('font-weight', '600');\n text.setAttribute('text-anchor', 'middle');\n text.setAttribute('dominant-baseline', 'middle');\n text.textContent = segments[i].label || `#${i + 1}`;\n wheel.appendChild(text);\n }\n modal.appendChild(wheel);\n \n const spinButton = document.createElement('button');\n spinButton.textContent = 'SPIN NOW!';\n spinButton.style.cssText = `\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n margin-bottom: 16px;\n `;\n \n spinButton.addEventListener('click', async () => {\n spinButton.disabled = true;\n spinButton.textContent = 'SPINNING...';\n \n try {\n const prize = await this.generatePrize(widget.config.config_id);\n\n wheel.style.animation = 'aegisSpin 2s ease-out';\n\n setTimeout(() => {\n this.showPrizeResult(modal, prize);\n }, 2000);\n \n } catch (error) {\n this.log(`Error generating prize: ${error}`, true);\n spinButton.disabled = false;\n spinButton.textContent = 'TRY AGAIN';\n }\n });\n \n modal.appendChild(spinButton);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderSpinWheelWidget(widgetId: string, config: NonNullable<PrefetchWidgetConfig['spin_wheel']>): void {\n if (this.isDestroyed) return;\n const cart = this.detectPlatformCart();\n \n if (config.type === 'cart_recovery' && !cart) {\n this.log('Spin wheel requires cart, but none detected');\n return;\n }\n \n if (cart) {\n this.cartData = cart;\n }\n \n const customization = this.cssCustomization.spinWheel || {};\n const accentColor = customization.accentColor || (config as any).accent_color || '#FF6B6B';\n const backgroundColor = customization.backgroundColor || (config as any).background_color || '#FFFFFF';\n const textColor = customization.textColor || (config as any).text_color || '#333333';\n const buttonColor = customization.buttonColor || (config as any).button_color || accentColor;\n const wheelColors = customization.wheelColors || ['#FF6B6B', '#4ECDC4', '#FFE66D', '#95E1D3'];\n \n const overlay = document.createElement('div');\n overlay.className = 'aegis-spin-wheel-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.7);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 999999;\n animation: aegisFadeIn 0.3s ease;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-spin-wheel-modal';\n modal.style.cssText = `\n background: ${this.sanitizeColor(backgroundColor)};\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n position: relative;\n animation: aegisScaleIn 0.4s ease;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n `;\n \n const closeBtn = document.createElement('button');\n closeBtn.innerHTML = '✕';\n closeBtn.className = 'aegis-spin-wheel-close';\n closeBtn.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #999;\n `;\n closeBtn.onclick = () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'spin_wheel' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n };\n modal.appendChild(closeBtn);\n \n const title = document.createElement('h2');\n title.textContent = this.interpolateCartVariables((config as any).title || 'Spin to Win!');\n title.style.cssText = `\n margin: 0 0 16px 0;\n font-size: 28px;\n font-weight: bold;\n text-align: center;\n color: ${this.sanitizeColor(textColor)};\n `;\n modal.appendChild(title);\n \n if (cart) {\n const subtitle = document.createElement('p');\n subtitle.textContent = `Complete your ${cart.cart_currency} ${cart.cart_total.toFixed(2)} order and save!`;\n subtitle.style.cssText = `\n margin: 0 0 24px 0;\n font-size: 16px;\n text-align: center;\n color: #666;\n `;\n modal.appendChild(subtitle);\n }\n \n const wheelContainer = document.createElement('div');\n wheelContainer.className = 'aegis-wheel-container';\n wheelContainer.style.cssText = `\n width: 300px;\n height: 300px;\n margin: 0 auto 24px auto;\n background: conic-gradient(\n from 0deg,\n ${wheelColors[0]} 0deg 90deg,\n ${wheelColors[1]} 90deg 180deg,\n ${wheelColors[2]} 180deg 270deg,\n ${wheelColors[3]} 270deg 360deg\n );\n border-radius: 50%;\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n \n const form = document.createElement('form');\n form.className = 'aegis-spin-form';\n form.style.cssText = 'display: block;';\n \n const phoneInput = document.createElement('input');\n phoneInput.type = 'tel';\n phoneInput.placeholder = 'Enter your phone number';\n phoneInput.required = true;\n phoneInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(phoneInput);\n \n const emailInput = document.createElement('input');\n emailInput.type = 'email';\n emailInput.placeholder = 'Enter your email (optional)';\n emailInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(emailInput);\n \n const nameInput = document.createElement('input');\n nameInput.type = 'text';\n nameInput.placeholder = 'Enter your name (optional)';\n nameInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 12px;\n box-sizing: border-box;\n `;\n form.appendChild(nameInput);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Spin the Wheel!';\n submitButton.style.cssText = `\n width: 100%;\n padding: 14px;\n background: ${this.sanitizeColor(buttonColor)};\n color: white;\n border: none;\n border-radius: 8px;\n font-size: 16px;\n font-weight: 700;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n const errorMessage = document.createElement('div');\n errorMessage.className = 'aegis-spin-error';\n errorMessage.style.cssText = `\n color: #d32f2f;\n font-size: 14px;\n margin-top: 12px;\n text-align: center;\n display: none;\n `;\n form.appendChild(errorMessage);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n const phone = phoneInput.value.trim();\n const email = emailInput.value.trim();\n const name = nameInput.value.trim();\n \n if (!this.validatePhone(phone)) {\n errorMessage.textContent = 'Please enter a valid phone number (e.g., +1234567890)';\n errorMessage.style.display = 'block';\n return;\n }\n \n if (email && !this.validateEmail(email)) {\n errorMessage.textContent = 'Please enter a valid email address';\n errorMessage.style.display = 'block';\n return;\n }\n \n errorMessage.style.display = 'none';\n submitButton.disabled = true;\n submitButton.textContent = 'Spinning...';\n \n wheelContainer.style.animation = 'aegisSpin 2s ease-out';\n \n setTimeout(async () => {\n try {\n const prize = await this.submitSpinWheel({\n phone,\n email,\n name,\n cart,\n widgetId\n });\n \n this.showSpinWheelPrize(modal, prize);\n this.trackEvent(widgetId, 'submit', {\n type: 'spin_wheel',\n prize_label: prize.prize_label,\n has_email: !!email\n });\n \n } catch (error) {\n this.log(`Error submitting spin wheel: ${error}`, true);\n errorMessage.textContent = 'Failed to submit. Please try again.';\n errorMessage.style.display = 'block';\n submitButton.disabled = false;\n submitButton.textContent = 'Spin the Wheel!';\n wheelContainer.style.animation = '';\n }\n }, 2000);\n });\n \n modal.appendChild(wheelContainer);\n modal.appendChild(form);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'spin_wheel' });\n }\n \n private validatePhone(phone: string): boolean {\n const e164Regex = /^\\+?[1-9]\\d{1,14}$/;\n return e164Regex.test(phone.replace(/[\\s()-]/g, ''));\n }\n \n private validateEmail(email: string): boolean {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n }\n \n private async submitSpinWheel(data: {\n phone: string;\n email: string;\n name: string;\n cart: CartData | null;\n widgetId: string;\n }): Promise<GamificationPrize> {\n const url = `${this.apiHost}/v1/widgets/spin-wheel/submit`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const geoRegion = this.detectGeoRegion();\n const deviceType = this.getDeviceType();\n const utmParams = this.getUTMParams();\n \n const body: any = {\n phone: data.phone.replace(/[\\s()-]/g, ''),\n email: data.email || undefined,\n name: data.name || undefined,\n cart_id: data.cart?.cart_id || `web_${Date.now()}`,\n cart_token: data.cart?.cart_id,\n cart_total: data.cart?.cart_total || 0,\n cart_currency: data.cart?.cart_currency || 'USD',\n cart_items: data.cart?.cart_items || [],\n cart_url: window.location.href,\n platform: 'web',\n geo_region: geoRegion,\n device_type: deviceType,\n session_id: this.getSessionId() || undefined,\n anonymous_id: this.getAnonymousId() || undefined,\n utm_source: utmParams.utm_source,\n utm_medium: utmParams.utm_medium,\n utm_campaign: utmParams.utm_campaign\n };\n \n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n credentials: 'include',\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to submit spin wheel: ${response.status} - ${errorText}`);\n }\n \n return await response.json();\n }\n \n private showSpinWheelPrize(modal: HTMLElement, prize: GamificationPrize): void {\n modal.innerHTML = '';\n \n const resultContainer = document.createElement('div');\n resultContainer.style.cssText = 'text-align: center; padding: 40px 20px;';\n \n const emoji = document.createElement('div');\n emoji.textContent = '🎉';\n emoji.style.cssText = 'font-size: 60px; margin-bottom: 20px;';\n resultContainer.appendChild(emoji);\n \n const title = document.createElement('h2');\n title.textContent = 'Congratulations!';\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 28px; font-weight: 700; color: #1a73e8;';\n resultContainer.appendChild(title);\n \n const prizeLabel = document.createElement('p');\n prizeLabel.textContent = prize.prize_label;\n prizeLabel.style.cssText = 'margin: 0 0 20px 0; font-size: 20px; font-weight: 600; color: #333;';\n resultContainer.appendChild(prizeLabel);\n \n if (prize.coupon_code) {\n const couponContainer = document.createElement('div');\n couponContainer.style.cssText = `\n background: #f5f5f5;\n padding: 16px;\n border-radius: 8px;\n margin-bottom: 20px;\n border: 2px dashed #1a73e8;\n `;\n \n const couponLabel = document.createElement('div');\n couponLabel.textContent = 'Your coupon code:';\n couponLabel.style.cssText = 'font-size: 12px; color: #666; margin-bottom: 8px;';\n couponContainer.appendChild(couponLabel);\n \n const couponCode = document.createElement('div');\n couponCode.textContent = prize.coupon_code;\n couponCode.style.cssText = 'font-size: 24px; font-weight: 700; color: #1a73e8; letter-spacing: 2px;';\n couponContainer.appendChild(couponCode);\n \n resultContainer.appendChild(couponContainer);\n }\n \n const message = document.createElement('p');\n message.textContent = 'Check your WhatsApp/SMS for your discount code and cart link!';\n message.style.cssText = 'margin: 0 0 20px 0; font-size: 14px; color: #666;';\n resultContainer.appendChild(message);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n \n closeButton.addEventListener('click', () => {\n const overlay = modal.parentElement;\n if (overlay && document.body.contains(overlay)) {\n document.body.removeChild(overlay);\n }\n });\n \n resultContainer.appendChild(closeButton);\n modal.appendChild(resultContainer);\n }\n \n private detectGeoRegion(): string {\n const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n \n if (timezone.includes('America')) return 'north_america';\n if (timezone.includes('Europe')) return 'europe';\n if (timezone.includes('Asia/Kolkata') || timezone.includes('Asia/Calcutta')) return 'india';\n if (timezone.includes('Asia/Singapore') || timezone.includes('Asia/Bangkok') || timezone.includes('Asia/Jakarta')) return 'southeast_asia';\n if (timezone.includes('Asia/Dubai') || timezone.includes('Asia/Riyadh')) return 'middle_east';\n if (timezone.includes('America') && (timezone.includes('Sao_Paulo') || timezone.includes('Buenos_Aires'))) return 'latin_america';\n if (timezone.includes('Australia') || timezone.includes('Pacific/Auckland')) return 'oceania';\n \n return 'north_america';\n }\n \n private getUTMParams(): { utm_source?: string; utm_medium?: string; utm_campaign?: string } {\n const params = new URLSearchParams(window.location.search);\n return {\n utm_source: params.get('utm_source') || undefined,\n utm_medium: params.get('utm_medium') || undefined,\n utm_campaign: params.get('utm_campaign') || undefined\n };\n }\n \n private getSessionId(): string | null {\n return sessionStorage.getItem('aegis_session_id');\n }\n \n private getAnonymousId(): string | null {\n return localStorage.getItem('aegis_anonymous_id');\n }\n \n private renderScratchCard(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-gamification-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-scratch-card-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n padding: 32px;\n max-width: 500px;\n width: 90%;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'Scratch & Win!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 24px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Scratch to reveal your prize!';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n modal.appendChild(description);\n \n const canvas = document.createElement('canvas');\n canvas.width = 300;\n canvas.height = 200;\n canvas.style.cssText = `\n border-radius: 8px;\n cursor: pointer;\n margin: 0 auto 24px;\n display: block;\n box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n `;\n modal.appendChild(canvas);\n \n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.fillStyle = '#c0c0c0';\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.fillStyle = '#888';\n ctx.font = '20px Arial';\n ctx.textAlign = 'center';\n ctx.fillText('Scratch here!', canvas.width / 2, canvas.height / 2);\n \n let isScratching = false;\n \n const scratch = (x: number, y: number) => {\n ctx.globalCompositeOperation = 'destination-out';\n ctx.beginPath();\n ctx.arc(x, y, 20, 0, Math.PI * 2);\n ctx.fill();\n };\n \n canvas.addEventListener('mousedown', () => { isScratching = true; });\n canvas.addEventListener('mouseup', () => { isScratching = false; });\n canvas.addEventListener('mousemove', (e) => {\n if (isScratching) {\n const rect = canvas.getBoundingClientRect();\n scratch(e.clientX - rect.left, e.clientY - rect.top);\n }\n });\n }\n \n const scratchButton = document.createElement('button');\n scratchButton.textContent = 'REVEAL PRIZE';\n scratchButton.style.cssText = `\n background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);\n color: white;\n border: none;\n padding: 16px 48px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n `;\n \n scratchButton.addEventListener('click', async () => {\n scratchButton.disabled = true;\n scratchButton.textContent = 'REVEALING...';\n \n try {\n const prize = await this.generatePrize(widget.config.config_id);\n this.showPrizeResult(modal, prize);\n } catch (error) {\n this.log(`Error generating prize: ${error}`, true);\n scratchButton.disabled = false;\n scratchButton.textContent = 'TRY AGAIN';\n }\n });\n \n modal.appendChild(scratchButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderToast(widget: WidgetConfig): void {\n const { message, icon, duration } = widget.config;\n const position = widget.position || 'bottom_left';\n \n const toast = document.createElement('div');\n toast.className = 'aegis-toast';\n toast.setAttribute('data-widget-id', widget.widget_id);\n \n const positionStyles: Record<string, string> = {\n bottom_left: 'bottom: 20px; left: 20px;',\n bottom_right: 'bottom: 20px; right: 20px;',\n top_left: 'top: 20px; left: 20px;',\n top_right: 'top: 20px; right: 20px;'\n };\n \n toast.style.cssText = `\n position: fixed;\n ${positionStyles[position] || positionStyles.bottom_left}\n background: white;\n padding: 16px 20px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n z-index: 999998;\n display: flex;\n align-items: center;\n gap: 12px;\n max-width: 350px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisToastIn 0.3s ease-out;\n `;\n \n if (icon) {\n const iconEl = document.createElement('div');\n iconEl.textContent = icon;\n iconEl.style.cssText = 'font-size: 20px;';\n toast.appendChild(iconEl);\n }\n \n const messageEl = document.createElement('div');\n messageEl.textContent = message || 'Someone just made a purchase!';\n messageEl.style.cssText = 'flex: 1; font-size: 13px; color: #333;';\n toast.appendChild(messageEl);\n \n this.addAnimationStyles();\n toast.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(toast);\n \n setTimeout(() => {\n toast.style.animation = 'aegisToastOut 0.3s ease-out';\n setTimeout(() => {\n if (document.body.contains(toast)) {\n document.body.removeChild(toast);\n }\n this.renderedWidgets.delete(widget.widget_id);\n }, 300);\n }, duration || 5000);\n }\n \n private renderFeedbackForm(widget: WidgetConfig): void {\n const overlay = document.createElement('div');\n overlay.className = 'aegis-feedback-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 400px;\n background: white;\n box-shadow: -4px 0 20px rgba(0,0,0,0.15);\n z-index: 1000000;\n padding: 32px;\n overflow-y: auto;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisSlideInRight 0.3s ease-out;\n `;\n \n const title = document.createElement('h2');\n title.textContent = widget.config.title || 'We value your feedback!';\n title.style.cssText = 'margin: 0 0 8px 0; font-size: 20px; font-weight: 600; color: #1a1a1a;';\n overlay.appendChild(title);\n \n const description = document.createElement('p');\n description.textContent = widget.config.description || 'Help us improve your experience.';\n description.style.cssText = 'margin: 0 0 24px 0; font-size: 14px; color: #666;';\n overlay.appendChild(description);\n \n const form = document.createElement('form');\n \n const label = document.createElement('label');\n label.textContent = 'How likely are you to recommend us? (0-10)';\n label.style.cssText = 'display: block; font-size: 14px; font-weight: 600; margin-bottom: 8px; color: #333;';\n form.appendChild(label);\n \n const input = document.createElement('input');\n input.type = 'number';\n input.min = '0';\n input.max = '10';\n input.style.cssText = `\n width: 100%;\n padding: 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-size: 14px;\n margin-bottom: 16px;\n `;\n form.appendChild(input);\n \n const textareaLabel = document.createElement('label');\n textareaLabel.textContent = 'Tell us more (optional)';\n textareaLabel.style.cssText = 'display: block; font-size: 14px; font-weight: 600; margin-bottom: 8px; color: #333;';\n form.appendChild(textareaLabel);\n \n const textarea = document.createElement('textarea');\n textarea.rows = 4;\n textarea.style.cssText = `\n width: 100%;\n padding: 12px;\n border: 1px solid #ddd;\n border-radius: 6px;\n font-size: 14px;\n resize: vertical;\n margin-bottom: 16px;\n font-family: inherit;\n `;\n form.appendChild(textarea);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Submit Feedback';\n submitButton.style.cssText = `\n width: 100%;\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px;\n border-radius: 6px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n submitButton.disabled = true;\n submitButton.textContent = 'Submitting...';\n \n try {\n await this.submitFeedback(widget.widget_id, {\n score: parseInt(input.value),\n comment: textarea.value\n });\n \n overlay.innerHTML = '<div style=\"text-align: center; padding: 60px 20px;\"><h3 style=\"margin: 0 0 12px 0; color: #1a73e8;\">Thank you!</h3><p style=\"margin: 0; color: #666;\">Your feedback helps us improve.</p></div>';\n \n setTimeout(() => {\n document.body.removeChild(overlay);\n }, 2000);\n \n } catch (error) {\n this.log(`Error submitting feedback: ${error}`, true);\n submitButton.disabled = false;\n submitButton.textContent = 'Submit Feedback';\n }\n });\n \n overlay.appendChild(form);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n overlay.appendChild(closeButton);\n \n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private renderExitIntentPopup(widget: WidgetConfig): void {\n const { title, description, cta_text, cta_url, image_url } = widget.config;\n \n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widget.widget_id);\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-exit-popup-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n max-width: 600px;\n width: 90%;\n overflow: hidden;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n `;\n \n if (image_url) {\n const img = document.createElement('img');\n const safeUrl = this.sanitizeUrl(image_url);\n if (safeUrl) {\n img.src = safeUrl;\n img.alt = '';\n img.style.cssText = 'width: 100%; height: 250px; object-fit: cover;';\n modal.appendChild(img);\n }\n }\n \n const content = document.createElement('div');\n content.style.cssText = 'padding: 32px;';\n \n const titleEl = document.createElement('h2');\n titleEl.textContent = title || 'Wait! Don\\'t leave yet!';\n titleEl.style.cssText = 'margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: #1a1a1a;';\n content.appendChild(titleEl);\n \n const descEl = document.createElement('p');\n descEl.textContent = description || 'Get 10% off your first order!';\n descEl.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; color: #666; line-height: 1.5;';\n content.appendChild(descEl);\n \n if (cta_text && cta_url) {\n const ctaButton = document.createElement('button');\n ctaButton.textContent = cta_text;\n ctaButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'click');\n const safeUrl = this.sanitizeUrl(cta_url);\n if (safeUrl) {\n window.location.href = safeUrl;\n }\n });\n \n content.appendChild(ctaButton);\n }\n \n modal.appendChild(content);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: white;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #666;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widget.widget_id, 'dismiss');\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widget.widget_id);\n });\n \n modal.style.position = 'relative';\n modal.appendChild(closeButton);\n \n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n }\n \n private async generatePrize(configId: string): Promise<GamificationPrize> {\n const url = `${this.apiHost}/v1/widgets/gamification/generate-prize`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({ config_id: configId }),\n credentials: 'include',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to generate prize: ${response.status}`);\n }\n \n return await response.json();\n }\n \n private showPrizeResult(modal: HTMLElement, prize: GamificationPrize): void {\n modal.innerHTML = '';\n \n const resultContainer = document.createElement('div');\n resultContainer.style.cssText = 'text-align: center; padding: 40px 20px;';\n \n const emoji = document.createElement('div');\n emoji.textContent = '🎉';\n emoji.style.cssText = 'font-size: 60px; margin-bottom: 20px;';\n resultContainer.appendChild(emoji);\n \n const title = document.createElement('h2');\n title.textContent = 'Congratulations!';\n title.style.cssText = 'margin: 0 0 12px 0; font-size: 28px; font-weight: 700; color: #1a73e8;';\n resultContainer.appendChild(title);\n \n const prizeLabel = document.createElement('p');\n prizeLabel.textContent = prize.prize_label;\n prizeLabel.style.cssText = 'margin: 0 0 20px 0; font-size: 20px; font-weight: 600; color: #333;';\n resultContainer.appendChild(prizeLabel);\n \n if (prize.coupon_code) {\n const couponContainer = document.createElement('div');\n couponContainer.style.cssText = `\n background: #f5f5f5;\n padding: 16px;\n border-radius: 8px;\n margin-bottom: 20px;\n border: 2px dashed #1a73e8;\n `;\n \n const couponLabel = document.createElement('div');\n couponLabel.textContent = 'Your coupon code:';\n couponLabel.style.cssText = 'font-size: 12px; color: #666; margin-bottom: 8px;';\n couponContainer.appendChild(couponLabel);\n \n const couponCode = document.createElement('div');\n couponCode.textContent = prize.coupon_code;\n couponCode.style.cssText = 'font-size: 24px; font-weight: 700; color: #1a73e8; letter-spacing: 2px;';\n couponContainer.appendChild(couponCode);\n \n resultContainer.appendChild(couponContainer);\n }\n \n const closeButton = document.createElement('button');\n closeButton.textContent = 'Close';\n closeButton.style.cssText = `\n background: #1a73e8;\n color: white;\n border: none;\n padding: 12px 32px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n cursor: pointer;\n `;\n \n closeButton.addEventListener('click', () => {\n const overlay = modal.parentElement;\n if (overlay && document.body.contains(overlay)) {\n document.body.removeChild(overlay);\n }\n });\n \n resultContainer.appendChild(closeButton);\n modal.appendChild(resultContainer);\n }\n \n private async submitFeedback(widgetId: string, data: Record<string, any>): Promise<void> {\n const url = `${this.apiHost}/v1/widgets/track-event`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n \n // Plumb workspace cascade so feedback submissions are attributed to\n // the same outlet the customer was viewing. See\n // PLUGIN_HANDSHAKE_AUTOMATION_TRACKER.md §P1.b.\n const workspaceId = this.getWorkspaceId?.();\n\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n widget_id: widgetId,\n event_type: 'submit',\n event_data: data,\n workspace_id: workspaceId,\n }),\n credentials: 'include',\n });\n \n if (!response.ok) {\n throw new Error(`Failed to submit feedback: ${response.status}`);\n }\n }\n \n private async trackEvent(widgetId: string, eventType: string, metadata?: Record<string, any>): Promise<void> {\n try {\n const url = `${this.apiHost}/v1/widgets/track-event`;\n \n const headers: Record<string, string> = {\n 'X-Aegis-Write-Key': this.writeKey,\n 'Content-Type': 'application/json'\n };\n \n if (this.userId) headers['X-User-ID'] = this.userId;\n if (this.contactId) headers['X-Contact-ID'] = this.contactId;\n if (this.organizationId) headers['X-Organization-ID'] = this.organizationId;\n\n const workspaceId = this.getWorkspaceId?.();\n\n await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n widget_id: widgetId,\n event_type: eventType,\n event_data: metadata || {},\n workspace_id: workspaceId,\n }),\n credentials: 'include',\n });\n\n } catch (error) {\n this.log(`Error tracking widget event: ${error}`, true);\n }\n }\n \n private sanitizeUrl(url?: string): string | null {\n if (!url) return null;\n \n try {\n const parsed = new URL(url, window.location.href);\n if (parsed.protocol === 'javascript:' || parsed.protocol === 'data:') {\n this.log(`Blocked dangerous URL: ${url}`, true);\n return null;\n }\n return parsed.href;\n } catch {\n this.log(`Invalid URL: ${url}`, true);\n return null;\n }\n }\n \n private sanitizeColor(color: string): string {\n if (/^#[0-9A-F]{3,8}$/i.test(color)) {\n return color;\n }\n \n if (/^rgb\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*\\)$/i.test(color)) {\n return color;\n }\n \n if (/^rgba\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*[\\d.]+\\s*\\)$/i.test(color)) {\n return color;\n }\n \n return '#1a73e8';\n }\n \n private getDeviceType(): string {\n const ua = navigator.userAgent;\n if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {\n return 'tablet';\n }\n if (/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(ua)) {\n return 'mobile';\n }\n return 'desktop';\n }\n \n private isMobileDevice(): boolean {\n const deviceType = this.getDeviceType();\n return deviceType === 'mobile' || deviceType === 'tablet';\n }\n \n private addAnimationStyles(): void {\n if (document.getElementById('aegis-widget-animations')) {\n return;\n }\n \n const style = document.createElement('style');\n style.id = 'aegis-widget-animations';\n style.textContent = `\n @keyframes aegisFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n \n @keyframes aegisScaleIn {\n from { transform: scale(0.8); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n }\n \n @keyframes aegisBubbleIn {\n from { transform: translateY(20px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes aegisToastIn {\n from { transform: translateX(-100%); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n }\n \n @keyframes aegisToastOut {\n from { transform: translateX(0); opacity: 1; }\n to { transform: translateX(-100%); opacity: 0; }\n }\n \n @keyframes aegisSlideInRight {\n from { transform: translateX(100%); }\n to { transform: translateX(0); }\n }\n \n @keyframes aegisSpin {\n from { transform: rotate(0deg); }\n to { transform: rotate(1440deg); }\n }\n `;\n document.head.appendChild(style);\n }\n \n private renderCartRecoveryPopup(widgetId: string, config: NonNullable<PrefetchWidgetConfig['exit_intent']>): void {\n if (this.isDestroyed) return;\n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n overlay.setAttribute('data-aegis-widget-root', '');\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-cart-recovery-modal';\n modal.style.cssText = `\n background: ${this.sanitizeColor(config.background_color || '#FFFFFF')};\n color: ${this.sanitizeColor(config.text_color || '#333333')};\n border-radius: 16px;\n max-width: 600px;\n width: 90%;\n padding: 40px;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n position: relative;\n `;\n \n const title = document.createElement('h2');\n const titleText = this.interpolateCartVariables(config.title || 'Complete Your Order');\n title.textContent = titleText;\n title.style.cssText = `margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: ${this.sanitizeColor(config.accent_color || '#FF6B00')};`;\n modal.appendChild(title);\n \n const message = document.createElement('p');\n const messageText = this.interpolateCartVariables(config.message || 'Your cart is waiting for you!');\n message.textContent = messageText;\n message.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; line-height: 1.5;';\n modal.appendChild(message);\n \n if (config.show_cart_items && this.cartData) {\n const cartItems = document.createElement('div');\n cartItems.style.cssText = 'margin: 0 0 24px 0; padding: 16px; background: rgba(0,0,0,0.05); border-radius: 8px;';\n \n const cartTitle = document.createElement('div');\n cartTitle.textContent = `${this.cartData.cart_items.length} items in your cart`;\n cartTitle.style.cssText = 'font-weight: 600; margin-bottom: 12px;';\n cartItems.appendChild(cartTitle);\n \n this.cartData.cart_items.slice(0, 3).forEach(item => {\n const itemDiv = document.createElement('div');\n itemDiv.textContent = `${item.quantity}× ${item.product_name || item.product_id}`;\n itemDiv.style.cssText = 'font-size: 14px; margin-bottom: 4px;';\n cartItems.appendChild(itemDiv);\n });\n \n modal.appendChild(cartItems);\n }\n \n if (config.discount_code) {\n const discountBox = document.createElement('div');\n discountBox.style.cssText = `\n margin: 0 0 24px 0;\n padding: 16px;\n background: ${this.sanitizeColor(config.accent_color || '#FF6B00')};\n color: white;\n border-radius: 8px;\n text-align: center;\n font-weight: 700;\n font-size: 18px;\n `;\n discountBox.textContent = `Use code: ${config.discount_code} for ${config.discount_percentage || 10}% off!`;\n modal.appendChild(discountBox);\n }\n \n if (config.show_timer && config.timer_minutes) {\n const timer = document.createElement('div');\n timer.style.cssText = 'margin: 0 0 24px 0; text-align: center; font-size: 14px; color: #999;';\n timer.textContent = `⏰ Offer expires in ${config.timer_minutes} minutes`;\n modal.appendChild(timer);\n }\n \n const ctaButton = document.createElement('button');\n ctaButton.textContent = config.cta_text || 'Complete Checkout';\n ctaButton.style.cssText = `\n background: ${this.sanitizeColor(config.accent_color || '#FF6B00')};\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n width: 100%;\n `;\n \n ctaButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'click', { type: 'cart_recovery' });\n const checkoutUrl = this.sanitizeUrl(config.cta_url || '/checkout');\n if (checkoutUrl) {\n window.location.href = checkoutUrl;\n }\n });\n \n modal.appendChild(ctaButton);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'cart_recovery' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n });\n \n modal.appendChild(closeButton);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'cart_recovery', tier: config.tier });\n }\n \n private renderLeadGenPopup(widgetId: string, config: NonNullable<PrefetchWidgetConfig['exit_intent']>): void {\n if (this.isDestroyed) return;\n const overlay = document.createElement('div');\n overlay.className = 'aegis-exit-popup-overlay';\n overlay.setAttribute('data-widget-id', widgetId);\n overlay.setAttribute('data-aegis-widget-root', '');\n \n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 1000000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: aegisFadeIn 0.3s ease-out;\n `;\n \n const modal = document.createElement('div');\n modal.className = 'aegis-leadgen-modal';\n modal.style.cssText = `\n background: white;\n border-radius: 16px;\n max-width: 500px;\n width: 90%;\n padding: 40px;\n box-shadow: 0 10px 40px rgba(0,0,0,0.3);\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n animation: aegisScaleIn 0.3s ease-out;\n position: relative;\n `;\n \n const title = document.createElement('h2');\n title.textContent = config.title || 'Get 10% Off Your First Order!';\n title.style.cssText = 'margin: 0 0 16px 0; font-size: 28px; font-weight: 700; color: #1a1a1a;';\n modal.appendChild(title);\n \n const message = document.createElement('p');\n message.textContent = config.message || 'Subscribe to our newsletter and get an exclusive discount code.';\n message.style.cssText = 'margin: 0 0 24px 0; font-size: 16px; color: #666;';\n modal.appendChild(message);\n \n const form = document.createElement('form');\n \n const emailInput = document.createElement('input');\n emailInput.type = 'email';\n emailInput.placeholder = 'Enter your email';\n emailInput.required = true;\n emailInput.style.cssText = `\n width: 100%;\n padding: 14px;\n border: 2px solid #ddd;\n border-radius: 8px;\n font-size: 16px;\n margin-bottom: 16px;\n box-sizing: border-box;\n `;\n form.appendChild(emailInput);\n \n const submitButton = document.createElement('button');\n submitButton.type = 'submit';\n submitButton.textContent = 'Get My Discount';\n submitButton.style.cssText = `\n width: 100%;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border: none;\n padding: 16px 32px;\n border-radius: 8px;\n font-weight: 700;\n font-size: 16px;\n cursor: pointer;\n `;\n form.appendChild(submitButton);\n \n form.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n submitButton.disabled = true;\n submitButton.textContent = 'Submitting...';\n \n try {\n await this.trackEvent(widgetId, 'submit', { \n type: 'lead_gen',\n email: emailInput.value \n });\n \n modal.innerHTML = `\n <div style=\"text-align: center; padding: 20px;\">\n <div style=\"font-size: 48px; margin-bottom: 16px;\">✅</div>\n <h3 style=\"margin: 0 0 12px 0; color: #1a73e8;\">Thank You!</h3>\n <p style=\"margin: 0; color: #666;\">Check your email for your discount code!</p>\n </div>\n `;\n \n setTimeout(() => {\n document.body.removeChild(overlay);\n }, 2500);\n \n } catch (error) {\n this.log(`Error submitting lead gen form: ${error}`, true);\n submitButton.disabled = false;\n submitButton.textContent = 'Get My Discount';\n }\n });\n \n modal.appendChild(form);\n \n const closeButton = document.createElement('button');\n closeButton.textContent = '×';\n closeButton.setAttribute('aria-label', 'Close');\n closeButton.style.cssText = `\n position: absolute;\n top: 16px;\n right: 16px;\n background: transparent;\n border: none;\n font-size: 28px;\n cursor: pointer;\n color: #999;\n `;\n \n closeButton.addEventListener('click', () => {\n this.trackEvent(widgetId, 'dismiss', { type: 'lead_gen' });\n document.body.removeChild(overlay);\n this.renderedWidgets.delete(widgetId);\n });\n \n modal.appendChild(closeButton);\n overlay.appendChild(modal);\n this.addAnimationStyles();\n overlay.setAttribute('data-aegis-widget-root', '');\n document.body.appendChild(overlay);\n \n this.trackEvent(widgetId, 'show', { type: 'lead_gen' });\n }\n \n private interpolateCartVariables(template: string): string {\n if (!this.cartData) return template;\n \n return template\n .replace(/\\{\\{cart_total\\}\\}/g, `${this.cartData.cart_currency} ${this.cartData.cart_total.toFixed(2)}`)\n .replace(/\\{\\{cart_currency\\}\\}/g, this.cartData.cart_currency)\n .replace(/\\{\\{cart_items_count\\}\\}/g, this.cartData.cart_items.length.toString());\n }\n \n private log(message: string, isError: boolean = false): void {\n if (this.debugMode || isError) {\n const method = isError ? 'error' : 'log';\n console[method](`[AegisWidgets] ${message}`);\n }\n }\n}\n","/**\n * AegisLoyaltyManager — public SDK surface for the closed-loop store\n * credit + gift cards feature.\n *\n * Phase 7 of the Active Loyalty — Store Credit + Gift Cards rollout.\n * Tracker: docs/architecture/ACTIVE_LOYALTY_STORE_CREDIT_GIFT_CARDS_TRACKER.md\n *\n * Public API (call via `runtime.loyalty.storeCredit.*` / `runtime.loyalty.giftCards.*`):\n *\n * await runtime.loyalty.storeCredit.listActive(phone)\n * await runtime.loyalty.storeCredit.startReload({ phone, workspaceId, amountPaise })\n * await runtime.loyalty.giftCards.startPurchase({ ... })\n * await runtime.loyalty.giftCards.claim({ giftCardId, phone })\n * await runtime.loyalty.giftCards.listReceived(phone)\n *\n * Closed-loop constraints surfaced through the API:\n * - workspaceId is required on every reload / gift card purchase\n * (C1 — single-workspace redemption).\n * - listActive returns ONE row per workspace; clients render one\n * card per workspace, never pooled.\n * - claim() requires the recipient phone to authenticate as the\n * directed recipient (C3 — no bearer codes).\n *\n * Network shape — all calls hit the storefront-facing commerce router\n * via the configured apiHost / same-origin.\n */\n\nexport interface StoreCreditBalance {\n workspaceId: string;\n balancePaise: number;\n expiresAt: string | null;\n lastActivityAt: string | null;\n}\n\nexport interface ReloadCheckoutResult {\n contactId: string;\n checkoutUrl: string;\n provider: string;\n paymentLinkId: string;\n amountPaise: number;\n}\n\nexport interface GiftCardPurchaseResult {\n senderContactId: string;\n giftCardId: string;\n checkoutUrl: string;\n provider: string;\n paymentLinkId: string;\n amountPaise: number;\n}\n\nexport interface GiftCard {\n id: string;\n workspaceId: string;\n senderContactId: string;\n amountPaise: number;\n status: string;\n personalMessage: string | null;\n deliveredAt: string | null;\n claimedAt: string | null;\n expiresAt: string | null;\n createdAt: string | null;\n}\n\nexport interface GiftCardClaimResult {\n recipientContactId: string;\n giftCardId: string;\n amountCreditedPaise: number;\n newBalancePaise: number;\n}\n\nexport interface AegisLoyaltyManagerConfig {\n /** Storefront slug — `{slug}.actii.me/...` */\n slug: string;\n /** Optional explicit API host. When null, uses same-origin. */\n apiHost?: string;\n /** When true, attaches credentials so cookies flow (anon-id, csrf). */\n credentials?: 'include' | 'same-origin' | 'omit';\n /** Optional debug logger. */\n debugMode?: boolean;\n}\n\ninterface ListActiveResponse {\n balances: Array<{\n workspace_id: string;\n balance_paise: number;\n expires_at: string | null;\n last_activity_at: string | null;\n }>;\n}\n\ninterface StartReloadResponse {\n contact_id: string;\n checkout_url: string;\n provider: string;\n payment_link_id: string;\n amount_paise: number;\n}\n\ninterface GiftCardPurchaseResponse {\n sender_contact_id: string;\n gift_card_id: string;\n checkout_url: string;\n provider: string;\n payment_link_id: string;\n amount_paise: number;\n}\n\ninterface GiftCardClaimResponse {\n recipient_contact_id: string;\n gift_card_id: string;\n amount_credited_paise: number;\n new_balance_paise: number;\n}\n\ninterface GiftCardListReceivedResponse {\n gift_cards: Array<{\n id: string;\n workspace_id: string;\n sender_contact_id: string;\n amount_paise: number;\n status: string;\n personal_message: string | null;\n delivered_at: string | null;\n claimed_at: string | null;\n expires_at: string | null;\n created_at: string | null;\n }>;\n}\n\nclass HttpClient {\n constructor(private config: AegisLoyaltyManagerConfig) {}\n\n private url(path: string) {\n const host = (this.config.apiHost ?? '').replace(/\\/$/, '');\n return `${host}/api/v1/commerce/store/${encodeURIComponent(this.config.slug)}${path}`;\n }\n\n async get<T>(path: string): Promise<T> {\n const res = await fetch(this.url(path), {\n method: 'GET',\n credentials: this.config.credentials ?? 'include',\n headers: { 'content-type': 'application/json' },\n });\n if (!res.ok) {\n const body = await res.text();\n throw new Error(`GET ${path} failed (${res.status}): ${body}`);\n }\n return res.json() as Promise<T>;\n }\n\n async post<T>(path: string, body: Record<string, unknown>): Promise<T> {\n const res = await fetch(this.url(path), {\n method: 'POST',\n credentials: this.config.credentials ?? 'include',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const errBody = await res.text();\n let detail = errBody;\n try {\n detail = JSON.parse(errBody).detail ?? errBody;\n } catch {\n // not JSON\n }\n throw new Error(`POST ${path} failed (${res.status}): ${detail}`);\n }\n return res.json() as Promise<T>;\n }\n}\n\nclass StoreCreditClient {\n constructor(private http: HttpClient) {}\n\n async listActive(phone: string): Promise<StoreCreditBalance[]> {\n const body = await this.http.get<ListActiveResponse>(\n `/store-credit/list-active?phone=${encodeURIComponent(phone)}`,\n );\n return (body.balances ?? []).map((b) => ({\n workspaceId: b.workspace_id,\n balancePaise: b.balance_paise,\n expiresAt: b.expires_at,\n lastActivityAt: b.last_activity_at,\n }));\n }\n\n async startReload(opts: {\n phone: string;\n workspaceId: string;\n amountPaise: number;\n firstName?: string;\n email?: string;\n callbackUrl?: string;\n }): Promise<ReloadCheckoutResult> {\n if (!opts.workspaceId) {\n throw new Error('workspaceId is required for store credit reload (closed-loop C1)');\n }\n const body = await this.http.post<StartReloadResponse>(\n '/store-credit/reload',\n {\n phone: opts.phone,\n workspace_id: opts.workspaceId,\n amount_paise: opts.amountPaise,\n first_name: opts.firstName,\n email: opts.email,\n callback_url: opts.callbackUrl,\n },\n );\n return {\n contactId: body.contact_id,\n checkoutUrl: body.checkout_url,\n provider: body.provider,\n paymentLinkId: body.payment_link_id,\n amountPaise: body.amount_paise,\n };\n }\n}\n\nclass GiftCardsClient {\n constructor(private http: HttpClient) {}\n\n async startPurchase(opts: {\n senderPhone: string;\n workspaceId: string;\n recipientPhone: string;\n recipientName?: string;\n amountPaise: number;\n personalMessage?: string;\n callbackUrl?: string;\n }): Promise<GiftCardPurchaseResult> {\n if (!opts.workspaceId) {\n throw new Error('workspaceId is required for gift card purchase (closed-loop C1)');\n }\n if (!opts.recipientPhone) {\n throw new Error('recipientPhone is required (no bearer cards — C3)');\n }\n const body = await this.http.post<GiftCardPurchaseResponse>(\n '/gift-cards/purchase',\n {\n sender_phone: opts.senderPhone,\n workspace_id: opts.workspaceId,\n recipient_phone: opts.recipientPhone,\n recipient_name: opts.recipientName,\n amount_paise: opts.amountPaise,\n personal_message: opts.personalMessage,\n callback_url: opts.callbackUrl,\n },\n );\n return {\n senderContactId: body.sender_contact_id,\n giftCardId: body.gift_card_id,\n checkoutUrl: body.checkout_url,\n provider: body.provider,\n paymentLinkId: body.payment_link_id,\n amountPaise: body.amount_paise,\n };\n }\n\n async claim(opts: { giftCardId: string; phone: string }): Promise<GiftCardClaimResult> {\n const body = await this.http.post<GiftCardClaimResponse>('/gift-cards/claim', {\n gift_card_id: opts.giftCardId,\n phone: opts.phone,\n });\n return {\n recipientContactId: body.recipient_contact_id,\n giftCardId: body.gift_card_id,\n amountCreditedPaise: body.amount_credited_paise,\n newBalancePaise: body.new_balance_paise,\n };\n }\n\n async listReceived(phone: string): Promise<GiftCard[]> {\n const body = await this.http.get<GiftCardListReceivedResponse>(\n `/gift-cards/received?phone=${encodeURIComponent(phone)}`,\n );\n return (body.gift_cards ?? []).map((g) => ({\n id: g.id,\n workspaceId: g.workspace_id,\n senderContactId: g.sender_contact_id,\n amountPaise: g.amount_paise,\n status: g.status,\n personalMessage: g.personal_message,\n deliveredAt: g.delivered_at,\n claimedAt: g.claimed_at,\n expiresAt: g.expires_at,\n createdAt: g.created_at,\n }));\n }\n}\n\nexport class AegisLoyaltyManager {\n readonly storeCredit: StoreCreditClient;\n readonly giftCards: GiftCardsClient;\n\n constructor(config: AegisLoyaltyManagerConfig) {\n if (!config.slug) {\n throw new Error('AegisLoyaltyManager requires a slug');\n }\n const http = new HttpClient(config);\n this.storeCredit = new StoreCreditClient(http);\n this.giftCards = new GiftCardsClient(http);\n }\n}\n","/**\n * AegisMessageRuntime — unified facade for in-app messaging.\n *\n * The sole public entry point for all 20 in-app types (announce +\n * collect + assist buckets) plus the legacy gamification surface\n * (chat_bubble / toast / exit_intent_popup configured via\n * /v1/widgets/config). Under the hood it composes an\n * `AegisInAppManager` + `AegisWidgetManager`; callers never touch them\n * directly.\n *\n * Public API:\n * new AegisMessageRuntime({ writeKey, apiHost, ... })\n * await runtime.initialize()\n * await runtime.updateContactId(id)\n * runtime.onClientEvent(eventName, data)\n * runtime.destroy()\n *\n * Internal wiring: spin_wheel + scratch_card campaigns land in the\n * inbox prefetch bundle but need DOM renderers that live in\n * WidgetManager. The facade passes an `onInteractiveCampaign` callback\n * into the InAppManager constructor; the callback forwards to\n * `widgets.renderInteractiveCampaign(campaign)` — no CustomEvent bus,\n * no listeners, no registration-order bugs.\n */\n\nimport { AegisInAppManager, maybeStartPairing, type AegisInAppConfig, type InAppCampaign, type CartState } from '../inapp';\nimport { AegisWidgetManager, type AegisWidgetConfig } from '../widgets';\nimport { TriggerEngine } from '../triggers/TriggerEngine';\nimport { IntentRuleEvaluator } from '../triggers/IntentRuleEvaluator';\nimport { ContactScoresFetcher } from '../triggers/ContactScoresFetcher';\nimport { AegisLoyaltyManager } from '../loyalty';\nimport { AegisChat, type AegisChatConfig } from '../chat';\n\nexport interface AegisMessageRuntimeConfig extends AegisInAppConfig {\n /** If set, a `TriggerEngine` from the SDK is wired to the WidgetManager\n * for its exit-intent / scroll-velocity / inactivity handlers. Leave\n * undefined to have the runtime construct one internally. */\n triggerEngine?: AegisWidgetConfig['triggerEngine'];\n /** WidgetManager prefetch toggle. Defaults to true — matches the\n * existing behaviour where spin_wheel / scratch_card prefetch their\n * configs from `/v1/widgets/config/prefetch`. */\n enableWidgetPrefetch?: boolean;\n /** Source platform for gamification attribution (shopify / woocommerce\n * / magento / mobile_sdk / web). Passed through to WidgetManager. */\n sourcePlatform?: AegisWidgetConfig['sourcePlatform'];\n /** Storefront slug for the loyalty subsystem — needed when the host\n * app calls `runtime.loyalty.storeCredit.*` / `runtime.loyalty.giftCards.*`.\n * When omitted, the loyalty manager is constructed but every call\n * will throw until configure() is invoked. */\n storefrontSlug?: string;\n /** Mount the customer chat launcher (\"Shopping Assistant\") — a floating\n * bubble that talks to the channel-neutral chat agent (Track A). Off by\n * default; opt in per host page. */\n enableChat?: boolean;\n /** Presentation overrides for the chat launcher (title / greeting / accent),\n * plus proactive auto-open. writeKey / apiHost / org / contact are inherited\n * from the runtime. */\n chat?: Pick<AegisChatConfig, 'title' | 'greeting' | 'accentColor' | 'channel' | 'icon' | 'logoUrl' | 'position'> & {\n /** Client-side TriggerEngine events that auto-open the launcher (e.g.\n * ['exit_intent', 'inactivity_90']). The trigger ONLY opens the panel —\n * it never creates an offer. The proactive *opener* is owned server-side\n * by the journey→warm-offer-queue bridge (Track B B4); the bot surfaces it\n * on the customer's first turn. This keeps a single offer source — no\n * parallel client-side offer infra. */\n proactiveTriggers?: string[];\n };\n}\n\n/**\n * One runtime, all in-app types. Consumers should prefer this over\n * importing AegisInAppManager / AegisWidgetManager directly. Those two\n * classes remain exported for a deprecation window — see `./deprecated.ts`.\n */\nexport class AegisMessageRuntime {\n readonly inApp: AegisInAppManager;\n readonly widgets: AegisWidgetManager;\n /** Shared IntentRuleEvaluator for identified-contact micro-intent\n * patterns. The ContactScoresFetcher writes Layer-1 signals into its\n * snapshot; IntentSnapshotCollector (if wired by the consumer) writes\n * Layer-2 signals. Exposed so apps that pre-existed P4a can swap in\n * their own evaluator if they need to. */\n readonly intentRuleEvaluator: IntentRuleEvaluator;\n /** Bridges GET /v1/sdk/contact-scores into the evaluator snapshot.\n * Triggered automatically on initialize() and updateContactId(). */\n readonly contactScores: ContactScoresFetcher;\n /** Closed-loop store credit + directed gift cards (Phase 7).\n * Usage:\n * await runtime.loyalty.storeCredit.listActive(phone)\n * await runtime.loyalty.storeCredit.startReload({ phone, workspaceId, amountPaise })\n * await runtime.loyalty.giftCards.startPurchase({ ... })\n * await runtime.loyalty.giftCards.claim({ giftCardId, phone })\n * Tracker: docs/architecture/ACTIVE_LOYALTY_STORE_CREDIT_GIFT_CARDS_TRACKER.md */\n readonly loyalty: AegisLoyaltyManager;\n /** Customer chat launcher (\"Shopping Assistant\"). Constructed only when\n * `enableChat` is set; undefined otherwise. (Track A) */\n readonly chat?: AegisChat;\n private contactId?: string;\n private initialized = false;\n /** apiHost captured for the device-pairing entry (`?aegis_pair=CODE`). */\n private readonly pairingApiHost: string;\n // Context is held in ONE place — `intentRuleEvaluator.namespaces` (fed via\n // updateContext). The renderer cart reader + the cart_value signal are DERIVED\n // from it; there is no parallel cart/context store on the runtime.\n\n constructor(config: AegisMessageRuntimeConfig) {\n const triggerEngine = config.triggerEngine ?? new TriggerEngine();\n const ownsTriggerEngine = !config.triggerEngine;\n this.contactId = config.contactId;\n this.pairingApiHost = config.apiHost ?? '';\n // Ownership of the engine is tracked downstream by WidgetManager\n // (which is the only consumer that needs to call lifecycle methods\n // on it). The facade itself only forwards.\n\n this.widgets = new AegisWidgetManager({\n writeKey: config.writeKey,\n apiHost: config.apiHost,\n userId: config.userId,\n contactId: config.contactId,\n organizationId: config.organizationId,\n debugMode: config.debugMode,\n triggerEngine,\n ownsTriggerEngine,\n enablePrefetch: config.enableWidgetPrefetch !== false,\n sourcePlatform: config.sourcePlatform,\n getWorkspaceId: config.getWorkspaceId,\n });\n\n this.inApp = new AegisInAppManager({\n writeKey: config.writeKey,\n apiHost: config.apiHost,\n userId: config.userId,\n contactId: config.contactId,\n organizationId: config.organizationId,\n propertyId: config.propertyId,\n debugMode: config.debugMode,\n enableSSE: config.enableSSE,\n // Route gamification sub_types straight to the widget renderer —\n // replaces the old CustomEvent('aegis:render-widget') bridge which\n // had no listener and silently dropped impressions.\n onInteractiveCampaign: (campaign) => {\n this.widgets.renderInteractiveCampaign(campaign);\n },\n getWorkspaceId: config.getWorkspaceId,\n // First-party cart reader — renderers (progress-bar) read live cart\n // state from here instead of `window.*` cart globals. See setCartState().\n getCartState: () => this.deriveCartState(),\n });\n\n this.intentRuleEvaluator = new IntentRuleEvaluator();\n this.contactScores = new ContactScoresFetcher({\n // Falls back to same-origin when no apiHost configured (storefront\n // typical case) — matches WidgetManager/InAppManager handling\n // where `config.apiHost` is also `string | undefined`.\n apiHost: config.apiHost ?? '',\n writeKey: config.writeKey,\n organizationId: config.organizationId,\n evaluator: this.intentRuleEvaluator,\n });\n\n // Loyalty subsystem — closed-loop store credit + gift cards.\n // Constructed even when no slug is provided so the readonly prop\n // is stable; calls throw until configured.\n this.loyalty = new AegisLoyaltyManager({\n slug: config.storefrontSlug ?? '__unconfigured__',\n apiHost: config.apiHost,\n debugMode: config.debugMode,\n });\n\n // Customer chat launcher (Track A) — opt-in, only mounted when enabled so\n // non-chat tenants pay nothing. Inherits identity/transport from the runtime.\n if (config.enableChat) {\n this.chat = new AegisChat({\n writeKey: config.writeKey,\n apiHost: config.apiHost,\n organizationId: config.organizationId,\n contactId: config.contactId,\n debugMode: config.debugMode,\n ...config.chat,\n });\n\n // Proactive auto-open: subscribe the configured client triggers (cart-\n // stall surfaces as `inactivity_*`, exit-intent as `exit_intent`). The\n // trigger ONLY opens the panel — the warm-offer opener itself is enqueued\n // server-side (journey→warm-offer-queue bridge) and surfaced by the bot\n // on the first turn. No parallel client-side offer infra.\n const proactive = config.chat?.proactiveTriggers ?? [];\n for (const evt of proactive) {\n triggerEngine.on(evt, () => this.chat?.openPanel());\n }\n }\n }\n\n /**\n * Boots both managers in parallel. Safe to call multiple times — the\n * second + subsequent calls are no-ops.\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n this.initialized = true;\n // Surface-Canvas pairing entry — `?aegis_pair=CODE`. Works for EVERY runtime\n // consumer (the Active Commerce Store + any external site that npm-installs\n // the SDK — the preferred distribution), so the first-party storefront pairs\n // exactly like an external npm-SDK site. Idempotent (shared module guard with\n // the cdn.ts / Shopify-Magento-Woo path); no-op when the param is absent.\n maybeStartPairing(this.pairingApiHost);\n await Promise.all([\n this.inApp.initialize(),\n this.widgets.initialize(),\n ]);\n // Mount the chat launcher bubble (DOM only — no network until opened).\n this.chat?.initialize();\n // Fire-and-forget the Layer-1 score fetch when we already know the\n // contact at init. Identified-contact micro-intent patterns need\n // this snapshot — without it their AND-compound rules eval to\n // false. Anonymous patterns are unaffected.\n if (this.contactId) {\n void this.contactScores.fetchForContact(this.contactId);\n }\n }\n\n /**\n * Both managers carry contactId. Updates both so the server-side\n * targeting pipeline sees the identity for campaign eligibility AND\n * the widget prefetch includes per-contact segment configs. The\n * widgets call is async (may re-fetch prefetch configs) but we don't\n * wait — callers that care about the fetched state await on the\n * returned promise.\n */\n async updateContactId(contactId: string): Promise<void> {\n this.contactId = contactId;\n this.inApp.updateContactId?.(contactId);\n this.chat?.updateContactId(contactId);\n await this.widgets.updateContactId(contactId);\n // Re-fetch Layer-1 scores for the new identity. Session-dedup in\n // the fetcher means a repeat call with the same contactId is a\n // no-op, so SPA navigation that re-calls identify() is cheap.\n void this.contactScores.fetchForContact(contactId);\n }\n\n /**\n * Forward a client-side event (product_viewed, cart_idle_90s, etc.)\n * to the in-app manager's client-trigger evaluator. The WidgetManager\n * has its own TriggerEngine wiring (exit-intent, scroll-velocity) so\n * we don't forward there — events it cares about arrive through that\n * channel already.\n */\n onClientEvent(eventName: string, eventData: Record<string, unknown> = {}): void {\n this.inApp.onClientEvent?.(eventName, eventData);\n }\n\n /**\n * Unified reactive context — the GENERAL imperative state API (Plotline-style\n * \"global context state engine\"). The host app feeds named namespaces:\n * runtime.updateContext('cart', { total: 540, items: 3, currency: 'INR' })\n * runtime.updateContext('user', { tier: 'gold', lifecycle: 'active' })\n * runtime.updateContext('session', { idle_s: 60 })\n *\n * Held in PRIVATE runtime state (no `window` pollution). Merged shallowly per\n * namespace and evaluated entirely client-side — no round-trip. This supersedes\n * the single-purpose `setCartState` (kept as a thin wrapper for back-compat).\n *\n * Design note (vs the proposed rewrite): we DELIBERATELY do NOT introduce a\n * parallel rule schema. Our canonical `IntentRule` (shared with the cell-plane\n * Pydantic schema + the editor + seeded campaigns) stays the source of truth.\n * `updateContext` BRIDGES known paths into the existing enum-keyed\n * `IntentSnapshot` (e.g. cart.total → the `cart_value` signal) so today's rules\n * keep firing — fed by the generic API. Arbitrary dot-path leaves\n * (`cart.foo`) are a forward-compatible follow-up that adds an optional `path`\n * to the canonical `IntentLeaf` (schema-mirrored + drift-guarded), NOT a second\n * evaluator. Tri-state (null = unprovable) evaluation is preserved — we do not\n * regress missing paths to `false`.\n */\n updateContext(namespace: string, data: Record<string, unknown>): void {\n if (!namespace || typeof namespace !== 'string' || !data) return;\n // ONE store — the evaluator's namespaces. Path-leaves (cart.total) resolve\n // against this directly; no copy on the runtime.\n this.intentRuleEvaluator.updateContext(namespace, data as Record<string, never>);\n this.bridgeContextToSignals(namespace);\n // Re-arm context-gated campaigns (debounced manager-side).\n this.inApp.refreshOnEvent('context_updated');\n }\n\n /** Read the current client-side context snapshot (for the editor scrubber /\n * preview bridge to mirror live values). Read-only view of the ONE store. */\n getContext(): Readonly<Record<string, Readonly<Record<string, unknown>>>> {\n return this.intentRuleEvaluator.getNamespaces() as Readonly<\n Record<string, Readonly<Record<string, unknown>>>\n >;\n }\n\n /**\n * Bridge well-known context paths into the canonical enum-keyed IntentSnapshot,\n * so existing signal-based rules (cart_value) keep firing off the generic\n * `updateContext`. Reads from the ONE store (the evaluator). Extend here as new\n * signals map to context paths — no parallel engine.\n */\n private bridgeContextToSignals(namespace: string): void {\n if (namespace === 'cart') {\n const total = Number(this.intentRuleEvaluator.getValueByPath('cart.total')\n ?? this.intentRuleEvaluator.getValueByPath('cart.cart_value'));\n if (Number.isFinite(total)) {\n this.intentRuleEvaluator.updateSignal('cart_value', total);\n }\n }\n }\n\n /** Derive the typed cart snapshot for the progress-bar renderer reader from\n * the ONE context store (the `cart` namespace). No separate cart field. */\n private deriveCartState(): CartState | undefined {\n const total = Number(this.intentRuleEvaluator.getValueByPath('cart.total'));\n if (!Number.isFinite(total)) return undefined;\n const items = Number(\n this.intentRuleEvaluator.getValueByPath('cart.items')\n ?? this.intentRuleEvaluator.getValueByPath('cart.itemCount'),\n );\n const currency = this.intentRuleEvaluator.getValueByPath('cart.currency');\n return {\n total,\n itemCount: Number.isFinite(items) ? items : 0,\n currency: typeof currency === 'string' ? currency : 'INR',\n };\n }\n\n /**\n * Back-compat wrapper over `updateContext('cart', …)`. The single-purpose cart\n * feed for headless storefronts; prefer `updateContext` for new code.\n */\n setCartState(state: CartState): void {\n this.updateContext('cart', {\n total: state.total,\n items: state.itemCount,\n currency: state.currency,\n });\n }\n\n // --- Qualifying-event refresh facade (DLR Tracker 1 / P1, 2026-05-28) ---\n //\n // `track`, `page`, and `screen` here are thin trigger taps for the\n // in-app subsystem — they tell `AegisInAppManager.refreshOnEvent` that\n // a host-app event happened, and the debounced refresh re-fetches\n // `/v1/in-app/active` so newly armed campaigns become visible without\n // waiting for the next identity flip. They are NOT a substitute for\n // the main analytics SDK (`Aegis` in `core/analytics.ts`) — those\n // methods own the canonical capture path (batch uplink, governance,\n // workspace resolution, etc.). Integrations that already call\n // `aegis.track(...)` should also call `runtime.track(...)` to drive\n // the in-app refresh. A future P-phase will bridge the two so a single\n // call on the public analytics surface drives both behaviors.\n\n /**\n * Notify the in-app subsystem that a tracked event occurred. Schedules\n * a debounced refresh of armed campaigns so newly eligible in-app\n * messages (e.g., trigger-gated on `cart_item_added`) become visible\n * within ~300ms — bursts coalesce. See\n * `AegisInAppManager.refreshOnEvent` for debounce semantics and why\n * this matters under storefront polling.\n */\n track(eventName: string): void {\n if (!eventName) return;\n this.inApp.refreshOnEvent(eventName);\n }\n\n /**\n * Notify the in-app subsystem that a URL-bound page view occurred.\n * Mirrors `aegis.page()` semantics — fires `'page_view'` as the\n * qualifying event so the trailing debounce covers SPA route bursts\n * (history.pushState rapid-fire) without spamming the endpoint.\n */\n page(name?: string): void {\n // isScreenDeclaration=true → the in-app manager captures the raw name as\n // `currentScreen` for free-form targeting (Dynamic Screens P2). The\n // 'page_view' default sentinel is filtered out manager-side.\n this.inApp.refreshOnEvent(name ?? 'page_view', true);\n }\n\n /**\n * Notify the in-app subsystem that a SPA-logical screen view occurred\n * (cart drawer open, checkout step transition — anywhere `aegis.screen()`\n * is called). Refresh-on-screen lets per-screen-targeted campaigns\n * arm without a URL change.\n */\n screen(name: string): void {\n if (!name) return;\n // isScreenDeclaration=true → captured as the raw `currentScreen` for\n // free-form screen targeting (Dynamic Screens P2).\n this.inApp.refreshOnEvent(name, true);\n }\n\n /**\n * Conversion-aware suppression — call when the host app observes a\n * goal event (purchase / order_completed / checkout_completed / custom).\n *\n * Forwards to AegisInAppManager.notifyConversion() which:\n * - Persists the conversion in sessionStorage so subsequent page loads\n * in the same tab keep armed campaigns silenced.\n * - For every armed campaign whose\n * `frequency.suppress_after_conversion_seconds` is set, computes an\n * expiry epoch_ms and silences it until then.\n *\n * Storefronts integrate via the React provider's useCommerceEvents\n * helper which calls this after `ecom.orderCompleted(...)`. Direct SDK\n * users call it themselves.\n *\n * Added by Micro-Intent Engine P0a Task 6 (2026-04-30).\n */\n notifyConversion(goalName: string): void {\n this.inApp.notifyConversion?.(goalName);\n }\n\n /**\n * Tear down both managers. Used by React component unmounts + during\n * identity switches where we want a full reset. If the facade created\n * its own TriggerEngine, WidgetManager.destroy() will stop it;\n * caller-supplied engines are left alone.\n */\n destroy(): void {\n this.inApp.destroy?.();\n this.widgets.destroy();\n this.chat?.destroy();\n this.initialized = false;\n }\n\n /**\n * Current armed campaigns visible to the InAppManager. Accessible for\n * the Prefetch Inspector and for debugging. WidgetManager's prefetched\n * spin_wheel / scratch_card configs are NOT in this list — they live\n * in `this.widgets` and have their own lifecycle.\n */\n getCampaigns(): InAppCampaign[] {\n // AegisInAppManager keeps `campaigns` as a private field. Expose it\n // via bracket access; the field is stable as of SDK 1.5.0. Once\n // Phase 7c unifies render paths this becomes a first-class getter.\n return ((this.inApp as unknown as { campaigns?: InAppCampaign[] }).campaigns) ?? [];\n }\n}\n","/**\n * SDK Bootstrap\n *\n * Strict origin-assertion handshake against the control-plane. Called once\n * at SDK init — resolves writeKey → propertyId, asserts origin, and returns\n * the VAPID public key + first-party cookie id the SDK needs for the rest\n * of the session.\n *\n * A failed bootstrap (401/403) aborts SDK init — the SDK refuses to emit\n * events or request push permission against an origin it cannot prove it\n * owns.\n *\n * See docs/architecture/SUBSCRIPTION_PROPERTY_ARCHITECTURE.md §5.\n */\n\nconst COOKIE_NAME = 'aegis_fpc';\nconst COOKIE_MAX_AGE_DAYS = 365 * 2;\n\nexport interface BootstrapRequest {\n writeKey: string;\n currentOrigin?: string;\n firstPartyCookieId?: string;\n attestationToken?: string;\n userAgent?: string;\n}\n\nimport type { EventGovernanceHint } from '../governance';\n\nexport interface BootstrapResult {\n propertyId: string;\n organizationId: string;\n workspaceId: string;\n propertyType: 'shopify_store' | 'hosted_commerce' | 'custom_website' | 'mobile_app';\n vapidPublicKey: string | null;\n allowedOrigins: string[];\n pushEnabled: boolean;\n inAppEnabled: boolean;\n transportMode: string;\n firstPartyCookieId: string;\n /**\n * Event-governance hint for SDK-side unique-event-name cap enforcement.\n * Null = Enterprise plan / CP outage / org has no cap. Safe to pass\n * directly to `aegis.ingestGovernanceHint()`.\n */\n eventGovernance: EventGovernanceHint | null;\n /**\n * @deprecated since P15.1 (2026-05-26) — use `locationCodes` instead.\n * Pre-2026-05-26 the path segment after the brand subdomain was a\n * workspace_code; the canonical hierarchy reversal made it a\n * location_code (outlet under a brand). Field name retained for\n * backward compat with SDK consumers that haven't migrated; new\n * consumers MUST read `locationCodes`. Server still populates BOTH\n * with the same array during the deprecation window so a stale\n * SDK keeps working.\n */\n workspaceCodes: string[];\n /**\n * P15.1 — outlet-code allowlist for SDK path-segment detection.\n * Empty array = no outlet codes registered for this org (single-\n * outlet tenant). SDK uses this set to decide whether\n * `location.pathname.split('/')[1]` is a valid outlet code vs a\n * generic route (`/products`, `/collections`). Pass to\n * `aegis.ingestLocationCodes()` after bootstrap completes.\n *\n * Same array contents as `workspaceCodes` during the deprecation\n * window — renaming the field gives semantic clarity (these ARE\n * location codes under the new hierarchy) without breaking\n * existing consumers.\n */\n locationCodes: string[];\n}\n\nexport class BootstrapError extends Error {\n constructor(public readonly status: number, message: string) {\n super(message);\n this.name = 'BootstrapError';\n }\n}\n\n/**\n * Read the first-party cookie id from document.cookie. Returns null if\n * unset — caller should pass undefined so the server issues a fresh one.\n */\nexport function readFirstPartyCookie(): string | null {\n if (typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${COOKIE_NAME}=([^;]+)`));\n return match ? decodeURIComponent(match[1]) : null;\n}\n\n/**\n * Persist the first-party cookie id returned by the server. Stored as a\n * first-party cookie (readable by JS — it's not a secret, it's a device\n * id) so that the same browser hitting a second origin on the same\n * registrable domain gets the same cookie back.\n */\nexport function writeFirstPartyCookie(cookieId: string): void {\n if (typeof document === 'undefined') return;\n const expires = new Date();\n expires.setDate(expires.getDate() + COOKIE_MAX_AGE_DAYS);\n // Derive the registrable-domain boundary where possible so the cookie is\n // shared across subdomains (e.g., shop.sweettruths.com + www.sweettruths.com).\n // We conservatively use the current host without a leading dot —\n // browsers scope the cookie to that host. For cross-registrable-domain\n // siblings (Shopify myshopify.com + actii.me), each domain gets its own\n // cookie, which is the expected per-origin behavior.\n document.cookie =\n `${COOKIE_NAME}=${encodeURIComponent(cookieId)};` +\n `expires=${expires.toUTCString()};` +\n `path=/;SameSite=Lax`;\n // Also mirror into localStorage so the SDK can read it synchronously at\n // init time even in environments where document.cookie is delayed.\n try {\n window.localStorage.setItem(COOKIE_NAME, cookieId);\n } catch {\n // private mode / storage disabled — cookie alone is sufficient\n }\n}\n\n/**\n * Perform the bootstrap handshake.\n *\n * @throws BootstrapError on 4xx — the SDK should stop init and surface the\n * error to the console. 5xx are retried once.\n */\nexport async function bootstrap(\n apiHost: string,\n req: BootstrapRequest\n): Promise<BootstrapResult> {\n const body: Record<string, unknown> = { writeKey: req.writeKey };\n if (req.currentOrigin) body.currentOrigin = req.currentOrigin;\n if (req.firstPartyCookieId) body.firstPartyCookieId = req.firstPartyCookieId;\n if (req.attestationToken) body.attestationToken = req.attestationToken;\n if (req.userAgent) body.userAgent = req.userAgent;\n\n const url = `${apiHost.replace(/\\/$/, '')}/v1/sdk/bootstrap`;\n\n const doFetch = async (): Promise<Response> =>\n fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n credentials: 'omit',\n });\n\n let resp = await doFetch();\n if (resp.status >= 500) {\n await new Promise((r) => setTimeout(r, 750));\n resp = await doFetch();\n }\n\n if (resp.status === 401) {\n throw new BootstrapError(401, 'writeKey not recognized or revoked');\n }\n if (resp.status === 403) {\n throw new BootstrapError(403, 'Origin validation failed — this writeKey is bound to a different property');\n }\n if (!resp.ok) {\n throw new BootstrapError(resp.status, `Bootstrap failed: HTTP ${resp.status}`);\n }\n\n const json = (await resp.json()) as BootstrapResult;\n writeFirstPartyCookie(json.firstPartyCookieId);\n return json;\n}\n\n/**\n * Derive a deterministic device fingerprint from the first-party cookie id\n * and a few stable UA parts. This is the value sent on every push-subscribe\n * call — its stability lets the backend UPSERT on (property_id, fingerprint)\n * across re-subscribes and VAPID rotations.\n */\nexport async function deriveDeviceFingerprint(firstPartyCookieId: string): Promise<string> {\n const ua = typeof navigator !== 'undefined' ? navigator.userAgent : '';\n const platform = typeof navigator !== 'undefined' ? (navigator.platform || '') : '';\n const language = typeof navigator !== 'undefined' ? (navigator.language || '') : '';\n const input = `${firstPartyCookieId}|${ua}|${platform}|${language}`;\n\n // Prefer subtle.crypto — available in all push-capable browsers.\n if (typeof crypto !== 'undefined' && crypto.subtle) {\n const bytes = new TextEncoder().encode(input);\n const hash = await crypto.subtle.digest('SHA-256', bytes);\n const hex = Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n return hex;\n }\n\n // Last-resort fallback — basic 32-bit FNV hash (non-cryptographic but\n // stable). Push-capable browsers always have subtle.crypto so this path\n // is practically unreachable; included only for completeness.\n let h = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n }\n return `fnv-${h.toString(16)}`;\n}\n","import { Aegis } from './core/analytics';\n\nconst aegis = new Aegis();\n\nexport default aegis;\n\nexport { Aegis } from './core/analytics';\nexport type { AegisConfig, CellEndpoint, CellRegion } from './types/config';\nexport type {\n AegisEvent,\n TrackEvent,\n IdentifyEvent,\n PageEvent,\n ScreenEvent,\n GroupEvent,\n AliasEvent,\n EventContext,\n BatchPayload,\n BatchResponse,\n} from './types/events';\nexport { UserNamespace } from './core/user-namespace';\nexport type { OptInChannel } from './core/user-namespace';\nexport type { Plugin, PluginRegistry } from './types/plugin';\nexport { debounce, throttle } from './utils/debounce';\nexport type {\n ConsentPreferences,\n ConsentCategory,\n ConsentStatus,\n} from './utils/consent';\n// In-app + widget types are re-exported for callers that configure\n// AegisMessageRuntime or read campaign objects. The underlying manager\n// classes are intentionally NOT exported — use AegisMessageRuntime.\nexport type {\n InAppCampaign,\n AegisInAppConfig,\n CartState,\n CampaignClickEvent,\n CampaignDismissEvent,\n AegisErrorEvent,\n InAppLifecycleEventMap,\n} from './inapp';\nexport { renderPreview } from './inapp';\n\nexport type {\n WidgetConfig,\n GamificationPrize,\n AegisWidgetConfig,\n} from './widgets';\n\nexport { TriggerEngine } from './triggers';\nexport type {\n TriggerRule,\n ScrollDepthConfig,\n TimeOnPageConfig,\n ExitIntentConfig,\n InactivityConfig,\n TriggerEvent,\n} from './triggers';\n\nexport { SdkConfigPoller } from './core/sdk-config-poller';\nexport type { SdkConfig, SdkConfigPollerOptions, ConfigChangeCallback } from './core/sdk-config-poller';\n\n// Preload-first bundle (2026-04-22) — fetches armed campaigns + inbox\n// slice once at init; everything renders from memory on trigger.\nexport { PrefetchBundleClient } from './core/prefetch-bundle-client';\nexport type {\n PrefetchBundle,\n PrefetchBundleCampaign,\n PrefetchBundleInbox,\n PrefetchBundleInboxEntry,\n PrefetchBundleClientOptions,\n PrefetchBundleContext,\n PrefetchBundleListener,\n} from './core/prefetch-bundle-client';\n\n// App Inbox — persistent message-center client.\nexport { AegisInbox } from './inbox';\nexport type { AegisInboxConfig, AegisInboxEntry, InboxListener } from './inbox';\n\n// Unified message runtime — the single entry point for in-app + widgets.\n// All 20 in-app types (modal/banner/tooltip/full_screen/spin_wheel/\n// scratch_card/nps_survey/quiz/countdown_offer/star_rating/...) flow\n// through this one class. The underlying AegisInAppManager +\n// AegisWidgetManager implementations are internal to the package.\nexport { AegisMessageRuntime } from './runtime';\nexport type { AegisMessageRuntimeConfig } from './runtime';\n\n// Customer chat launcher (\"Shopping Assistant\") — Track A. Usually mounted via\n// `new AegisMessageRuntime({ enableChat: true })`; exported for standalone use.\nexport { AegisChat } from './chat';\nexport type { AegisChatConfig } from './chat';\n\n// Loyalty subsystem — closed-loop store credit + directed gift cards.\n// Reachable as `runtime.loyalty.storeCredit.*` / `runtime.loyalty.giftCards.*`.\n// Tracker: docs/architecture/ACTIVE_LOYALTY_STORE_CREDIT_GIFT_CARDS_TRACKER.md\nexport { AegisLoyaltyManager } from './loyalty';\nexport type {\n AegisLoyaltyManagerConfig,\n StoreCreditBalance,\n ReloadCheckoutResult,\n GiftCard,\n GiftCardPurchaseResult,\n GiftCardClaimResult,\n} from './loyalty';\n\nexport { AegisWebPush } from './push/AegisWebPush';\nexport type {\n AegisWebPushConfig,\n AegisAPIClient,\n ContactIdentity,\n PushEventTracker,\n} from './push/AegisWebPush';\n\nexport {\n bootstrap,\n readFirstPartyCookie,\n writeFirstPartyCookie,\n deriveDeviceFingerprint,\n BootstrapError,\n} from './core/bootstrap';\nexport type { BootstrapRequest, BootstrapResult } from './core/bootstrap';\n\nexport { RateLimiter } from './core/rate-limiter';\nexport type { RateLimiterOptions } from './core/rate-limiter';\n\n// Event-governance — SDK-side cap enforcement. The NameGovernor is wired\n// into `Aegis.captureEvent()` automatically; callers only interact with it\n// via `aegis.ingestGovernanceHint(bootstrapResult.eventGovernance)`.\nexport { NameGovernor, BloomFilter, murmurhash3_x86_32 } from './governance';\nexport type { EventGovernanceHint, DropReport, BloomFilterParams } from './governance';\n\n// NOTE: SSE-based realtime subscription is intentionally NOT exported from the\n// public SDK surface. The Aegis Web SDK uses HTTP batch uplink + HTTP polling\n// downstream (via AegisInAppManager) + Web Push (via AegisWebPush). Tenant\n// dashboards that need SSE open it directly via their own Next.js API routes,\n// not through this SDK. See RFC 2026-04-16 §A.\n\nexport { EcommerceTracker } from './ecommerce';\nexport type {\n EcommerceProduct,\n EcommerceCart,\n EcommerceCheckout,\n EcommerceOrder,\n EcommerceCoupon,\n EcommerceSearch,\n EcommerceProductList,\n EcommerceWishlist,\n EcommerceWaitlist,\n EcommercePromotion,\n} from './ecommerce';\n"],"names":["goto","str","_a","_b","readAnonIdFromStorage","arr","target","m","caption","num","ic","isMobile","mobileConfig"],"mappings":"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"}