{"version":3,"file":"index.mjs","sources":["../src/utils/logger.ts","../src/utils/viewabilityTracker.ts","../src/hooks/useViewabilityTracker.ts","../src/components/AdMeshViewabilityTracker.tsx","../src/context/AdMeshContext.ts","../src/components/AdMeshTailAd.tsx","../src/hooks/useAdMesh.ts","../src/components/AdMeshBridgeFormat.tsx","../../node_modules/classnames/index.js","../src/components/AdMeshLinkTracker.tsx","../src/components/AdMeshEcommerceCards.tsx","../src/components/AdMeshLayout.tsx","../src/components/AdMeshFollowup.tsx","../src/sdk/AdMeshTracker.ts","../src/context/AdMeshProvider.tsx","../src/sdk/AdMeshRenderer.tsx","../src/sdk/AdMeshSDK.ts","../src/sdk/WeaveResponseProcessor.ts","../src/components/AdMeshRecommendations.tsx","../src/components/WeaveFallbackRecommendations.tsx","../src/context/WeaveAdFormatContext.tsx","../src/components/AdMeshBadge.tsx","../src/utils/streamingEvents.ts","../src/utils/inlineExposureTracker.ts","../src/components/WeaveAdFormatContainer.tsx","../src/utils/styleInjection.ts","../src/hooks/useAdMeshStyles.ts","../src/hooks/useWeaveAdFormat.ts","../src/index.ts"],"sourcesContent":["/**\n * Logger utility for AdMesh UI SDK\n * Disables all logs in production environment\n */\n\n// Check for production environment\n// Supports both Vite (import.meta.env) and standard Node.js (process.env)\nlet isProduction = false;\ntry {\n  // Check for Vite's import.meta.env (only available in ESM modules)\n  if (typeof (globalThis as any).importMeta !== 'undefined' && (globalThis as any).importMeta.env?.PROD) {\n    isProduction = true;\n  }\n} catch (e) {\n  // import.meta not available, continue with other checks\n}\n\nif (!isProduction) {\n  isProduction = \n    (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') ||\n    (typeof process !== 'undefined' && process.env.ADMESH_ENV === 'production');\n}\n\nexport const logger = {\n  log: (...args: any[]) => {\n    if (!isProduction) {\n      console.log(...args);\n    }\n  },\n  \n  warn: (...args: any[]) => {\n    if (!isProduction) {\n      console.warn(...args);\n    }\n  },\n  \n  error: (...args: any[]) => {\n    // Errors are always logged, even in production, as they're critical\n    console.error(...args);\n  },\n  \n  info: (...args: any[]) => {\n    if (!isProduction) {\n      console.info(...args);\n    }\n  },\n  \n  debug: (...args: any[]) => {\n    if (!isProduction) {\n      console.debug(...args);\n    }\n  },\n};\n\n","/**\n * AdMesh UI SDK - MRC Viewability Tracker Utilities\n * Implements Media Rating Council (MRC) viewability standards\n */\n\nimport type {\n  MRCViewabilityStandards,\n  DeviceType,\n  ViewabilityContextMetrics,\n  ViewabilityAnalyticsEvent\n} from '../types/analytics';\nimport { logger } from './logger';\n\n/**\n * Calculate MRC viewability standards based on ad size\n */\nexport function calculateMRCStandards(\n  adWidth: number,\n  adHeight: number,\n  customStandards?: Partial<MRCViewabilityStandards>\n): MRCViewabilityStandards {\n  const adPixels = adWidth * adHeight;\n  const isLargeAd = adPixels > 242500; // MRC threshold for large ads\n\n  const defaults: MRCViewabilityStandards = {\n    visibilityThreshold: isLargeAd ? 0.3 : 0.5, // 30% for large, 50% for standard\n    minimumDuration: 1000, // 1 second in milliseconds\n    isLargeAd\n  };\n\n  return { ...defaults, ...customStandards };\n}\n\n/**\n * Detect device type based on viewport width\n */\nexport function detectDeviceType(viewportWidth: number): DeviceType {\n  if (viewportWidth < 768) return 'mobile';\n  if (viewportWidth < 1024) return 'tablet';\n  return 'desktop';\n}\n\n/**\n * Calculate visibility percentage of element in viewport\n */\nexport function calculateVisibilityPercentage(element: HTMLElement): number {\n  const rect = element.getBoundingClientRect();\n  const viewportHeight = window.innerHeight || document.documentElement.clientHeight;\n  const viewportWidth = window.innerWidth || document.documentElement.clientWidth;\n\n  // Element dimensions\n  const elementHeight = rect.height;\n  const elementWidth = rect.width;\n\n  if (elementHeight === 0 || elementWidth === 0) return 0;\n\n  // Calculate visible portion\n  const visibleTop = Math.max(0, rect.top);\n  const visibleBottom = Math.min(viewportHeight, rect.bottom);\n  const visibleLeft = Math.max(0, rect.left);\n  const visibleRight = Math.min(viewportWidth, rect.right);\n\n  const visibleHeight = Math.max(0, visibleBottom - visibleTop);\n  const visibleWidth = Math.max(0, visibleRight - visibleLeft);\n\n  const visibleArea = visibleHeight * visibleWidth;\n  const totalArea = elementHeight * elementWidth;\n\n  return totalArea > 0 ? (visibleArea / totalArea) : 0;\n}\n\n/**\n * Calculate current scroll depth as percentage\n */\nexport function calculateScrollDepth(): number {\n  const windowHeight = window.innerHeight;\n  const documentHeight = document.documentElement.scrollHeight;\n  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n\n  const scrollableHeight = documentHeight - windowHeight;\n  if (scrollableHeight <= 0) return 100;\n\n  return Math.min(100, (scrollTop / scrollableHeight) * 100);\n}\n\n/**\n * Get element position on page\n */\nexport function getElementPosition(element: HTMLElement): { top: number; left: number } {\n  const rect = element.getBoundingClientRect();\n  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n  const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;\n\n  return {\n    top: rect.top + scrollTop,\n    left: rect.left + scrollLeft\n  };\n}\n\n/**\n * Collect context metrics\n */\nexport function collectContextMetrics(element: HTMLElement): ViewabilityContextMetrics {\n  const rect = element.getBoundingClientRect();\n  const position = getElementPosition(element);\n  const viewportWidth = window.innerWidth || document.documentElement.clientWidth;\n  const viewportHeight = window.innerHeight || document.documentElement.clientHeight;\n\n  // Detect dark mode\n  const isDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;\n\n  return {\n    pageUrl: window.location.href,\n    pageTitle: document.title,\n    referrer: document.referrer,\n    deviceType: detectDeviceType(viewportWidth),\n    viewportWidth,\n    viewportHeight,\n    adWidth: rect.width,\n    adHeight: rect.height,\n    adPositionTop: position.top,\n    adPositionLeft: position.left,\n    isDarkMode,\n    language: navigator.language,\n    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone\n  };\n}\n\n/**\n * Generate unique session ID for INTERNAL viewability tracking only.\n * \n * IMPORTANT: This is NOT the main sessionId used for recommendations.\n * This is only used internally by the viewability tracker for tracking\n * viewability events. The main sessionId MUST be provided by the platform\n * and passed to AdMeshProvider and SDK methods.\n */\nexport function generateSessionId(): string {\n  return `session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n}\n\n/**\n * Generate unique batch ID\n */\nexport function generateBatchId(): string {\n  return `batch_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n}\n\n/**\n * Check if ad meets MRC viewability threshold\n */\nexport function meetsViewabilityThreshold(\n  visibilityPercentage: number,\n  visibleDuration: number,\n  standards: MRCViewabilityStandards\n): boolean {\n  return (\n    visibilityPercentage >= standards.visibilityThreshold &&\n    visibleDuration >= standards.minimumDuration\n  );\n}\n\n/**\n * Format timestamp to ISO 8601\n */\nexport function formatTimestamp(date: Date = new Date()): string {\n  return date.toISOString();\n}\n\n/**\n * Calculate average from array of numbers\n */\nexport function calculateAverage(numbers: number[]): number {\n  if (numbers.length === 0) return 0;\n  const sum = numbers.reduce((acc, num) => acc + num, 0);\n  return sum / numbers.length;\n}\n\n/**\n * Debounce function for performance optimization\n */\nexport function debounce<T extends (...args: unknown[]) => unknown>(\n  func: T,\n  wait: number\n): (...args: Parameters<T>) => void {\n  let timeout: NodeJS.Timeout | null = null;\n\n  return function executedFunction(...args: Parameters<T>) {\n    const later = () => {\n      timeout = null;\n      func(...args);\n    };\n\n    if (timeout) clearTimeout(timeout);\n    timeout = setTimeout(later, wait);\n  };\n}\n\n/**\n * Throttle function for performance optimization\n */\nexport function throttle<T extends (...args: unknown[]) => unknown>(\n  func: T,\n  limit: number\n): (...args: Parameters<T>) => void {\n  let inThrottle: boolean;\n\n  return function executedFunction(...args: Parameters<T>) {\n    if (!inThrottle) {\n      func(...args);\n      inThrottle = true;\n      setTimeout(() => (inThrottle = false), limit);\n    }\n  };\n}\n\n/**\n * Send analytics event to API\n *\n * NOTE: If apiEndpoint is empty, the event is silently discarded (no error).\n * This allows the SDK to collect analytics without sending them to a backend.\n */\nexport async function sendAnalyticsEvent(\n  event: ViewabilityAnalyticsEvent,\n  apiEndpoint: string,\n  retryAttempts: number = 3,\n  retryDelay: number = 1000\n): Promise<boolean> {\n  // If no endpoint is configured, silently skip sending\n  if (!apiEndpoint || apiEndpoint.trim() === '') {\n    return true;\n  }\n\n  for (let attempt = 0; attempt < retryAttempts; attempt++) {\n    try {\n      const response = await fetch(apiEndpoint, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json'\n        },\n        body: JSON.stringify(event),\n        keepalive: true\n      });\n\n      if (response.ok) {\n        return true;\n      }\n\n      // Log error details for debugging\n      await response.text().catch(() => '');\n    } catch (error) {\n      // Error caught, will retry\n    }\n\n    // Wait before retry (exponential backoff)\n    if (attempt < retryAttempts - 1) {\n      await new Promise(resolve => setTimeout(resolve, retryDelay * Math.pow(2, attempt)));\n    }\n  }\n\n  logger.error('[AdMesh Viewability] Failed to send analytics event');\n  return false;\n}\n\n/**\n * Send batched analytics events to API\n *\n * NOTE: If apiEndpoint is empty, the batch is silently discarded (no error).\n * This allows the SDK to collect analytics without sending them to a backend.\n */\nexport async function sendAnalyticsBatch(\n  events: ViewabilityAnalyticsEvent[],\n  sessionId: string,\n  apiEndpoint: string,\n  retryAttempts: number = 3,\n  retryDelay: number = 1000\n): Promise<boolean> {\n  if (events.length === 0) return true;\n\n  // If no endpoint is configured, silently skip sending\n  if (!apiEndpoint || apiEndpoint.trim() === '') {\n    return true;\n  }\n\n  const batch = {\n    batchId: generateBatchId(),\n    sessionId,\n    createdAt: formatTimestamp(),\n    events,\n    eventCount: events.length\n  };\n\n  for (let attempt = 0; attempt < retryAttempts; attempt++) {\n    try {\n      const response = await fetch(apiEndpoint, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json'\n        },\n        body: JSON.stringify(batch),\n        keepalive: true\n      });\n\n      if (response.ok) {\n        return true;\n      }\n\n      // Log error details for debugging\n      await response.text().catch(() => '');\n    } catch (error) {\n      // Error caught, will retry\n    }\n\n    // Wait before retry (exponential backoff)\n    if (attempt < retryAttempts - 1) {\n      await new Promise(resolve => setTimeout(resolve, retryDelay * Math.pow(2, attempt)));\n    }\n  }\n\n  logger.error('[AdMesh Viewability] Failed to send analytics batch');\n  return false;\n}\n\n/**\n * Sanitize URL to remove PII (query parameters, fragments)\n */\nexport function sanitizeUrl(url: string): string {\n  try {\n    const urlObj = new URL(url);\n    // Remove query parameters and hash\n    return `${urlObj.protocol}//${urlObj.host}${urlObj.pathname}`;\n  } catch {\n    return url;\n  }\n}\n\n/**\n * Check if element is in viewport\n */\nexport function isElementInViewport(element: HTMLElement): boolean {\n  const rect = element.getBoundingClientRect();\n  return (\n    rect.top < (window.innerHeight || document.documentElement.clientHeight) &&\n    rect.bottom > 0 &&\n    rect.left < (window.innerWidth || document.documentElement.clientWidth) &&\n    rect.right > 0\n  );\n}\n","/**\n * AdMesh UI SDK - MRC Viewability Tracker Hook\n * React hook for tracking ad viewability according to MRC standards\n */\n\nimport { useState, useEffect, useRef, useCallback } from 'react';\nimport { logger } from '../utils/logger';\nimport type {\n  ViewabilityTrackerConfig,\n  ViewabilityTrackerState,\n  ViewabilityAnalyticsEvent,\n  ViewabilityEventType,\n  MRCViewabilityStandards\n} from '../types/analytics';\nimport {\n  calculateMRCStandards,\n  calculateVisibilityPercentage,\n  calculateScrollDepth,\n  collectContextMetrics,\n  generateSessionId,\n  meetsViewabilityThreshold,\n  formatTimestamp,\n  calculateAverage,\n  throttle\n} from '../utils/viewabilityTracker';\n\n// Default configuration\nconst DEFAULT_CONFIG: ViewabilityTrackerConfig = {\n  enabled: true,\n  // Analytics endpoint disabled - no analytics will be sent\n  apiEndpoint: '',  // Empty string disables analytics sending\n  enableBatching: false,  // Disabled since no endpoint\n  batchSize: 10,\n  batchTimeout: 5000, // 5 seconds\n  debug: false,\n  enableRetry: false,\n  maxRetries: 3,\n  retryDelay: 1000\n};\n\n// Global config that can be set by consuming application\nlet globalConfig: ViewabilityTrackerConfig = DEFAULT_CONFIG;\n\n// TEMPORARY: Global flag to disable all analytics sending\n// Set this to true to prevent any viewability analytics from being sent to the backend\n// This is a temporary measure and can be easily reverted by setting to false\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nlet ANALYTICS_DISABLED = false;\n\nexport const setViewabilityTrackerConfig = (config: Partial<ViewabilityTrackerConfig>) => {\n  globalConfig = { ...globalConfig, ...config };\n};\n\n/**\n * TEMPORARY: Disable/enable all viewability analytics sending\n * @param disabled - Set to true to disable analytics, false to enable\n *\n * Usage:\n *   disableViewabilityAnalytics(true);  // Disable all analytics\n *   disableViewabilityAnalytics(false); // Re-enable analytics\n */\nexport const disableViewabilityAnalytics = (disabled: boolean) => {\n  ANALYTICS_DISABLED = disabled;\n  if (disabled) {\n    logger.warn('[AdMesh Viewability] Analytics sending is DISABLED - no data will be sent to backend');\n  } else {\n    logger.log('[AdMesh Viewability] Analytics sending is ENABLED');\n  }\n};\n\ninterface UseViewabilityTrackerProps {\n  /** Product ID */\n  productId?: string;\n  /** Offer ID */\n  offerId?: string;\n  /** Agent ID */\n  agentId?: string;\n  /** Recommendation ID (from recommendations collection) */\n  recommendationId: string;\n  /** HTML element to track */\n  elementRef: React.RefObject<HTMLElement>;\n  /** Custom configuration */\n  config?: Partial<ViewabilityTrackerConfig>;\n}\n\nexport function useViewabilityTracker({\n  productId,\n  offerId,\n  agentId,\n  recommendationId,\n  elementRef,\n  config: customConfig\n}: UseViewabilityTrackerProps): ViewabilityTrackerState {\n  const config = { ...globalConfig, ...customConfig };\n\n  // Session ID (persists for component lifetime)\n  const sessionId = useRef(generateSessionId());\n\n  // State\n  const [state, setState] = useState<ViewabilityTrackerState>({\n    isVisible: false,\n    isViewable: false,\n    visibilityPercentage: 0,\n    timeMetrics: {\n      loadedAt: formatTimestamp(),\n      totalVisibleDuration: 0,\n      totalViewableDuration: 0,\n      totalHoverDuration: 0,\n      totalFocusDuration: 0\n    },\n    engagementMetrics: {\n      currentScrollDepth: 0,\n      viewportEnterCount: 0,\n      viewportExitCount: 0,\n      hoverCount: 0,\n      wasClicked: false,\n      maxVisibilityPercentage: 0,\n      averageVisibilityPercentage: 0\n    },\n    isTracking: config.enabled\n  });\n\n  // Refs for tracking\n  const mrcStandards = useRef<MRCViewabilityStandards | null>(null);\n  const visibilityStartTime = useRef<number | null>(null);\n  const viewableStartTime = useRef<number | null>(null);\n  const hoverStartTime = useRef<number | null>(null);\n  const focusStartTime = useRef<number | null>(null);\n  const visibilityPercentages = useRef<number[]>([]);\n  const eventBatch = useRef<ViewabilityAnalyticsEvent[]>([]);\n  const batchTimeout = useRef<NodeJS.Timeout | null>(null);\n\n  // Log helper\n  const log = useCallback((message: string) => {\n    if (config.debug) {\n      logger.log(`[AdMesh Viewability] ${message}`);\n    }\n  }, [config.debug]);\n\n  // Send event (analytics disabled - no events sent to backend)\n  // Viewability tracking still works for exposure pixels (handled separately)\n  const sendEvent = useCallback(async (eventType: ViewabilityEventType, additionalData?: Record<string, unknown>) => {\n    if (!config.enabled || !elementRef.current || !mrcStandards.current) return;\n\n    // Analytics disabled - no events sent to backend\n    // Viewability tracking still works internally for exposure pixel firing\n    log(`Analytics disabled - skipping event: ${eventType}`);\n    \n    // Call custom callback if provided (for local tracking)\n    if (config.onEvent) {\n      const contextMetrics = collectContextMetrics(elementRef.current);\n      const event: ViewabilityAnalyticsEvent = {\n        eventType,\n        timestamp: formatTimestamp(),\n        sessionId: sessionId.current,\n        productId,\n        offerId,\n        agentId,\n        recommendationId,\n        timeMetrics: state.timeMetrics,\n        engagementMetrics: state.engagementMetrics,\n        contextMetrics,\n        mrcStandards: mrcStandards.current,\n        isViewable: state.isViewable,\n        metadata: additionalData\n      };\n      config.onEvent(event);\n    }\n  }, [config, productId, offerId, agentId, recommendationId, elementRef, state, log]);\n\n  // Flush event batch (disabled - analytics not sent)\n  const flushBatch = useCallback(async () => {\n    if (eventBatch.current.length === 0) return;\n\n    // Analytics disabled - clear batch without sending\n    log('Analytics disabled - clearing batch without sending');\n    eventBatch.current = [];\n    if (batchTimeout.current) {\n      clearTimeout(batchTimeout.current);\n      batchTimeout.current = null;\n    }\n    return;\n  }, [log]);\n\n  // Update visibility\n  const updateVisibility = useCallback(throttle(() => {\n    if (!elementRef.current) return;\n\n    const visibilityPercentage = calculateVisibilityPercentage(elementRef.current);\n    const now = Date.now();\n    const loadTime = new Date(state.timeMetrics.loadedAt).getTime();\n\n    setState(prev => {\n      const newState = { ...prev };\n\n      // Track visibility percentages for average calculation\n      if (visibilityPercentage > 0) {\n        visibilityPercentages.current.push(visibilityPercentage);\n      }\n\n      // Update visibility state\n      const wasVisible = prev.isVisible;\n      const isNowVisible = visibilityPercentage > 0;\n\n      if (isNowVisible && !wasVisible) {\n        // Became visible\n        visibilityStartTime.current = now;\n        newState.engagementMetrics.viewportEnterCount++;\n\n        if (!newState.timeMetrics.timeToFirstVisible) {\n          newState.timeMetrics.timeToFirstVisible = now - loadTime;\n          newState.engagementMetrics.scrollDepthAtFirstVisible = calculateScrollDepth();\n          sendEvent('ad_visible');\n        }\n      } else if (!isNowVisible && wasVisible) {\n        // Became hidden\n        if (visibilityStartTime.current) {\n          const visibleDuration = now - visibilityStartTime.current;\n          newState.timeMetrics.totalVisibleDuration += visibleDuration;\n          visibilityStartTime.current = null;\n        }\n        newState.engagementMetrics.viewportExitCount++;\n        sendEvent('ad_hidden');\n      } else if (isNowVisible && wasVisible && visibilityStartTime.current) {\n        // Still visible, update duration\n        const visibleDuration = now - visibilityStartTime.current;\n        newState.timeMetrics.totalVisibleDuration += visibleDuration;\n        visibilityStartTime.current = now;\n      }\n\n      newState.isVisible = isNowVisible;\n      newState.visibilityPercentage = visibilityPercentage;\n\n      // Update max visibility\n      if (visibilityPercentage > newState.engagementMetrics.maxVisibilityPercentage) {\n        newState.engagementMetrics.maxVisibilityPercentage = visibilityPercentage;\n      }\n\n      // Update average visibility\n      if (visibilityPercentages.current.length > 0) {\n        newState.engagementMetrics.averageVisibilityPercentage = calculateAverage(visibilityPercentages.current);\n      }\n\n      // Check MRC viewability threshold\n      if (mrcStandards.current) {\n        const wasViewable = prev.isViewable;\n        const isNowViewable = meetsViewabilityThreshold(\n          visibilityPercentage,\n          newState.timeMetrics.totalVisibleDuration,\n          mrcStandards.current\n        );\n\n        if (isNowViewable && !wasViewable) {\n          // Met viewability threshold\n          newState.isViewable = true;\n          newState.timeMetrics.timeToViewable = now - loadTime;\n          viewableStartTime.current = now;\n          sendEvent('ad_viewable');\n        } else if (isNowViewable && wasViewable && viewableStartTime.current) {\n          // Still viewable, update duration\n          const viewableDuration = now - viewableStartTime.current;\n          newState.timeMetrics.totalViewableDuration += viewableDuration;\n          viewableStartTime.current = now;\n        }\n      }\n\n      // Update scroll depth\n      newState.engagementMetrics.currentScrollDepth = calculateScrollDepth();\n\n      return newState;\n    });\n  }, 100), [elementRef, state.timeMetrics.loadedAt, sendEvent]);\n\n  // Initialize MRC standards\n  useEffect(() => {\n    if (!elementRef.current) return;\n\n    const rect = elementRef.current.getBoundingClientRect();\n    mrcStandards.current = calculateMRCStandards(rect.width, rect.height, config.mrcStandards);\n\n    log('Initialized MRC standards');\n    sendEvent('ad_loaded');\n  }, [elementRef, config.mrcStandards, log, sendEvent]);\n\n  // Set up Intersection Observer\n  useEffect(() => {\n    if (!config.enabled || !elementRef.current) return;\n\n    const observer = new IntersectionObserver(\n      (entries) => {\n        entries.forEach(() => {\n          updateVisibility();\n        });\n      },\n      {\n        threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],\n        rootMargin: '0px'\n      }\n    );\n\n    observer.observe(elementRef.current);\n\n    return () => {\n      observer.disconnect();\n    };\n  }, [config.enabled, elementRef, updateVisibility]);\n\n  // Track scroll events\n  useEffect(() => {\n    if (!config.enabled) return;\n\n    const handleScroll = throttle(() => {\n      updateVisibility();\n    }, 100);\n\n    window.addEventListener('scroll', handleScroll, { passive: true });\n    return () => window.removeEventListener('scroll', handleScroll);\n  }, [config.enabled, updateVisibility]);\n\n  // Track hover events\n  useEffect(() => {\n    if (!config.enabled || !elementRef.current) return;\n\n    const element = elementRef.current;\n\n    const handleMouseEnter = () => {\n      hoverStartTime.current = Date.now();\n      setState(prev => ({\n        ...prev,\n        engagementMetrics: {\n          ...prev.engagementMetrics,\n          hoverCount: prev.engagementMetrics.hoverCount + 1\n        }\n      }));\n      sendEvent('ad_hover_start');\n    };\n\n    const handleMouseLeave = () => {\n      if (hoverStartTime.current) {\n        const hoverDuration = Date.now() - hoverStartTime.current;\n        setState(prev => ({\n          ...prev,\n          timeMetrics: {\n            ...prev.timeMetrics,\n            totalHoverDuration: prev.timeMetrics.totalHoverDuration + hoverDuration\n          }\n        }));\n        hoverStartTime.current = null;\n        sendEvent('ad_hover_end', { hoverDuration });\n      }\n    };\n\n    element.addEventListener('mouseenter', handleMouseEnter);\n    element.addEventListener('mouseleave', handleMouseLeave);\n\n    return () => {\n      element.removeEventListener('mouseenter', handleMouseEnter);\n      element.removeEventListener('mouseleave', handleMouseLeave);\n    };\n  }, [config.enabled, elementRef, sendEvent]);\n\n  // Track focus events\n  useEffect(() => {\n    if (!config.enabled || !elementRef.current) return;\n\n    const element = elementRef.current;\n\n    const handleFocus = () => {\n      focusStartTime.current = Date.now();\n      sendEvent('ad_focus');\n    };\n\n    const handleBlur = () => {\n      if (focusStartTime.current) {\n        const focusDuration = Date.now() - focusStartTime.current;\n        setState(prev => ({\n          ...prev,\n          timeMetrics: {\n            ...prev.timeMetrics,\n            totalFocusDuration: prev.timeMetrics.totalFocusDuration + focusDuration\n          }\n        }));\n        focusStartTime.current = null;\n        sendEvent('ad_blur', { focusDuration });\n      }\n    };\n\n    element.addEventListener('focus', handleFocus);\n    element.addEventListener('blur', handleBlur);\n\n    return () => {\n      element.removeEventListener('focus', handleFocus);\n      element.removeEventListener('blur', handleBlur);\n    };\n  }, [config.enabled, elementRef, sendEvent]);\n\n  // Track click events\n  useEffect(() => {\n    if (!config.enabled || !elementRef.current) return;\n\n    const element = elementRef.current;\n\n    const handleClick = () => {\n      setState(prev => ({\n        ...prev,\n        engagementMetrics: {\n          ...prev.engagementMetrics,\n          wasClicked: true\n        }\n      }));\n      sendEvent('ad_click');\n    };\n\n    element.addEventListener('click', handleClick);\n\n    return () => {\n      element.removeEventListener('click', handleClick);\n    };\n  }, [config.enabled, elementRef, sendEvent]);\n\n  // Cleanup on unmount\n  useEffect(() => {\n    return () => {\n      // Calculate session duration\n      const now = Date.now();\n      const loadTime = new Date(state.timeMetrics.loadedAt).getTime();\n      const sessionDuration = now - loadTime;\n\n      setState(prev => ({\n        ...prev,\n        timeMetrics: {\n          ...prev.timeMetrics,\n          sessionDuration\n        }\n      }));\n\n      // Send final event\n      sendEvent('ad_unloaded', { sessionDuration });\n\n      // Flush any remaining batched events\n      flushBatch();\n    };\n  }, []);\n\n  return state;\n}\n","/**\n * AdMesh Viewability Tracker Component\n * Wraps any ad component with MRC viewability tracking\n */\n\nimport React, { useRef, useEffect } from 'react';\nimport { logger } from '../utils/logger';\nimport { useViewabilityTracker } from '../hooks/useViewabilityTracker';\nimport type { ViewabilityTrackerConfig } from '../types/analytics';\n\nexport interface AdMeshViewabilityTrackerProps {\n  /** Product ID */\n  productId?: string;\n  /** Offer ID */\n  offerId?: string;\n  /** Agent ID */\n  agentId?: string;\n  /** Recommendation ID (for exposure tracking) */\n  recommendationId: string;\n  /** Exposure URL (for MRC-compliant exposure pixel firing) */\n  exposureUrl?: string;\n  /** Session ID (for exposure tracking) */\n  sessionId?: string;\n  /** Children to wrap with viewability tracking */\n  children: React.ReactNode;\n  /** Custom viewability tracker configuration */\n  config?: Partial<ViewabilityTrackerConfig>;\n  /** CSS class name */\n  className?: string;\n  /** Inline styles */\n  style?: React.CSSProperties;\n  /** Callback when viewability state changes */\n  onViewabilityChange?: (isViewable: boolean) => void;\n  /** Callback when ad becomes visible */\n  onVisible?: () => void;\n  /** Callback when ad becomes viewable (meets MRC threshold) */\n  onViewable?: () => void;\n  /** Callback when ad is clicked */\n  onClick?: () => void;\n}\n\n/**\n * AdMeshViewabilityTracker Component\n * \n * Wraps ad components with comprehensive MRC viewability tracking.\n * Automatically tracks:\n * - Viewability (50% visible for 1 second)\n * - Time metrics (time to viewable, total visible duration, etc.)\n * - Engagement metrics (hover, focus, clicks, scroll depth)\n * - Context metrics (device type, viewport size, ad position)\n * \n * @example\n * ```tsx\n * <AdMeshViewabilityTracker\n *   recommendationId=\"rec_123\"\n *   productId=\"prod_456\"\n *   offerId=\"offer_789\"\n *   onViewable={() => logger.log('Ad is viewable!')}\n * >\n *   <YourAdComponent />\n * </AdMeshViewabilityTracker>\n * ```\n */\nexport const AdMeshViewabilityTracker: React.FC<AdMeshViewabilityTrackerProps> = ({\n  productId,\n  offerId,\n  agentId,\n  recommendationId,\n  exposureUrl,\n  sessionId,\n  children,\n  config,\n  className,\n  style,\n  onViewabilityChange,\n  onVisible,\n  onViewable,\n  onClick\n}) => {\n  const elementRef = useRef<HTMLElement>(null);\n  const exposureFired = useRef(false);\n\n  // Use viewability tracker hook\n  const viewabilityState = useViewabilityTracker({\n    productId,\n    offerId,\n    agentId,\n    recommendationId,\n    elementRef: elementRef as React.RefObject<HTMLElement>,\n    config\n  });\n\n  // Track viewability changes and fire exposure pixel\n  const previousViewable = useRef(viewabilityState.isViewable);\n\n  useEffect(() => {\n    if (viewabilityState.isViewable !== previousViewable.current) {\n      previousViewable.current = viewabilityState.isViewable;\n\n      if (onViewabilityChange) {\n        onViewabilityChange(viewabilityState.isViewable);\n      }\n\n      if (viewabilityState.isViewable && onViewable) {\n        onViewable();\n      }\n\n      // Fire exposure pixel when ad becomes viewable (MRC-compliant)\n      // Only fire if we have the required data and haven't fired yet\n      if (viewabilityState.isViewable && !exposureFired.current) {\n        logger.log('[AdMeshViewabilityTracker] 🎯 Ad is viewable, checking exposure pixel requirements:', {\n          exposureUrl: exposureUrl ? 'present' : 'MISSING',\n          sessionId: sessionId ? 'present' : 'MISSING',\n          recommendationId\n        });\n\n        if (exposureUrl && sessionId) {\n          exposureFired.current = true;\n\n          logger.log('[AdMeshViewabilityTracker] 🔥 Firing exposure pixel:', exposureUrl);\n\n          // Fire the exposure pixel using fetch with keepalive\n          fetch(exposureUrl, { method: 'GET', keepalive: true })\n            .then(() => {\n              logger.log('[AdMesh] ✅ Exposure pixel fired successfully');\n            })\n            .catch((error) => {\n              logger.warn('[AdMesh] ⚠️ Failed to fire exposure pixel:', error);\n              // Reset flag to allow retry\n              exposureFired.current = false;\n            });\n        } else {\n          logger.warn('[AdMeshViewabilityTracker] ⚠️ Cannot fire exposure pixel - missing required data:', {\n            hasExposureUrl: !!exposureUrl,\n            hasSessionId: !!sessionId\n          });\n        }\n      }\n    }\n  }, [viewabilityState.isViewable, onViewabilityChange, onViewable, exposureUrl, sessionId, recommendationId]);\n\n  // Track visibility changes\n  const previousVisible = useRef(viewabilityState.isVisible);\n  \n  useEffect(() => {\n    if (viewabilityState.isVisible !== previousVisible.current) {\n      previousVisible.current = viewabilityState.isVisible;\n      \n      if (viewabilityState.isVisible && onVisible) {\n        onVisible();\n      }\n    }\n  }, [viewabilityState.isVisible, onVisible]);\n\n  // Handle click\n  const handleClick = () => {\n    if (onClick) {\n      onClick();\n    }\n    \n    // Allow event to propagate to children\n  };\n\n  return (\n    <div\n      ref={elementRef as React.RefObject<HTMLDivElement>}\n      className={className}\n      style={style}\n      onClick={handleClick}\n      data-admesh-viewability-tracker\n      data-recommendation-id={recommendationId}\n      data-is-viewable={viewabilityState.isViewable}\n      data-is-visible={viewabilityState.isVisible}\n      data-visibility-percentage={viewabilityState.visibilityPercentage.toFixed(2)}\n    >\n      {children}\n    </div>\n  );\n};\n\nAdMeshViewabilityTracker.displayName = 'AdMeshViewabilityTracker';\n","import React from 'react';\nimport { AdMeshSDK } from '../sdk/AdMeshSDK';\nimport type { AdMeshTheme } from '../types/index';\n\n/**\n * Context value provided by AdMeshProvider\n */\nexport interface AdMeshContextValue {\n  // SDK instance\n  sdk: AdMeshSDK | null;\n\n  // Configuration\n  apiKey: string;\n  sessionId: string;\n  theme?: AdMeshTheme;\n\n  // UCP PlatformRequest fields (optional, passed from frontend)\n  language?: string; // User language in BCP 47 format (e.g., \"en-US\")\n  geo_country?: string; // User country code in ISO 3166-1 alpha-2 format (e.g., \"US\")\n  userId?: string; // Anonymous hashed user ID\n  model?: string; // AI model identifier (e.g., \"gpt-4o\")\n  messages?: Array<{ role: string; content: string; id?: string }>; // Conversation history\n\n  // Tracking state\n  processedMessageIds: Set<string>;\n\n  // Methods\n  markMessageAsProcessed: (messageId: string) => void;\n  isMessageProcessed: (messageId: string) => boolean;\n}\n\n/**\n * React Context for AdMesh SDK\n * \n * Provides SDK instance and tracking state to all child components\n */\nexport const AdMeshContext = React.createContext<AdMeshContextValue | undefined>(\n  undefined\n);\n\n/**\n * Hook to access AdMesh context\n * \n * @throws Error if used outside of AdMeshProvider\n * @returns AdMeshContextValue\n */\nexport function useAdMeshContext(): AdMeshContextValue {\n  const context = React.useContext(AdMeshContext);\n  \n  if (!context) {\n    throw new Error(\n      'useAdMeshContext must be used within an <AdMeshProvider>. ' +\n      'Make sure your component is wrapped with <AdMeshProvider>.'\n    );\n  }\n  \n  return context;\n}\n\n","import React from 'react';\nimport { logger } from '../utils/logger';\nimport type { AdMeshRecommendation, AdMeshTheme } from '../types/index';\nimport { AdMeshViewabilityTracker } from './AdMeshViewabilityTracker';\nimport { AdMeshContext } from '../context/AdMeshContext';\n\nexport interface AdMeshTailAdProps {\n  summaryText?: string; // The tail_summary from backend response (optional, not used in new UI)\n  recommendations: AdMeshRecommendation[]; // Full recommendation objects\n  theme?: AdMeshTheme;\n  className?: string;\n  style?: React.CSSProperties;\n  onLinkClick?: (recommendation: AdMeshRecommendation) => void;\n  sessionId?: string;\n}\n\n// Utility function to validate and normalize URLs\nconst isValidUrl = (url: string): boolean => {\n  try {\n    new URL(url);\n    return true;\n  } catch {\n    return false;\n  }\n};\n\n// Helper function to get CTA label from backend\nconst getCTALabel = (ctaLabel?: string): string => {\n  // Use provided CTA label from backend if available\n  if (ctaLabel && ctaLabel.trim()) {\n    return ctaLabel.trim();\n    }\n\n  // Return empty string if no CTA label provided (will hide CTA button)\n  return '';\n};\n\n// Process summary text with markdown links [Product Name](click_url) and brand name links\n// NOTE: This function is kept for backward compatibility but is no longer used in the new tail ad UI\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst processSummaryText = (_summaryText: string, _recommendations: AdMeshRecommendation[]): (string | React.ReactElement)[] => {\n  // This function is no longer used - kept for backward compatibility only\n  return [];\n};\n\nexport const AdMeshTailAd: React.FC<AdMeshTailAdProps> = ({\n  recommendations,\n  theme,\n  className = '',\n  style = {},\n  sessionId\n}) => {\n  // Try to get context values for feedback submission (optional - component can work without provider)\n  const context = React.useContext(AdMeshContext);\n  const contextUserId = context?.userId;\n  const contextModel = context?.model;\n  const contextSessionId = context?.sessionId;\n  const sdk = context?.sdk || null;\n  \n  // Use prop sessionId if provided, otherwise use context sessionId\n  const effectiveSessionId = sessionId || contextSessionId;\n  \n  // State for feedback and visibility\n  const [isHidden, setIsHidden] = React.useState(false);\n  const [feedbackSubmitted, setFeedbackSubmitted] = React.useState(false);\n  const [isSubmittingFeedback, setIsSubmittingFeedback] = React.useState(false);\n  \n  // Validate inputs - return null if empty\n  if (!recommendations || recommendations.length === 0) {\n    logger.log('[AdMesh Tail Ad] No recommendations provided - not rendering');\n    return null;\n  }\n  \n  // Early return if component should be hidden (dislike clicked)\n  if (isHidden) {\n    return null;\n  }\n\n  // Get the first recommendation's data for CTA and tracking\n  const firstRecommendation = recommendations[0];\n  const productId = firstRecommendation?.product_id;\n  const exposureUrl = firstRecommendation?.exposure_url;\n  const recommendationId = firstRecommendation?.recommendation_id || '';\n  \n  // Get data from creative_input for tail format\n  const creativeInput = firstRecommendation?.creative_input || {};\n  const shortDescription = creativeInput.short_description || '';\n  const offerSummary = creativeInput.offer_summary || '';\n  const brandName = creativeInput.brand_name || firstRecommendation?.title || '';\n  const productName = creativeInput.product_name || '';\n  \n  // Get logo_url from assets\n  const assets = creativeInput.assets || {};\n  const logoUrl = assets.logo_url || '';\n  \n  // Get click URL - prioritize click_url from recommendation (this is the tracking URL we need)\n  const clickUrl = firstRecommendation?.click_url || \n                   firstRecommendation?.admesh_link || \n                   creativeInput.cta_url ||\n                   firstRecommendation?.url;\n  \n  // Get CTA label from backend\n  const ctaLabel = getCTALabel(creativeInput.cta_label);\n\n  // For tail format, we need at least brand name\n  // But we still validate that we have at least one recommendation with data\n  if (!brandName) {\n    logger.log('[AdMesh Tail Ad] No valid recommendation data provided - not rendering', {\n      reason: 'brandName is missing',\n      brandName,\n      hasFirstRecommendation: !!firstRecommendation,\n      hasCreativeInput: !!creativeInput,\n      creativeInputBrandName: creativeInput.brand_name,\n      recommendationTitle: firstRecommendation?.title,\n      recommendationId,\n      recommendationKeys: firstRecommendation ? Object.keys(firstRecommendation) : []\n    });\n    return null;\n  }\n  \n  // Build headline parts with priority:\n  // 1. If offer_summary exists: \"Brand — Offer Summary\"\n  // 2. If product_name exists: \"Brand — Product Name\"\n  // 3. Otherwise: just \"Brand\"\n  let headlineText = brandName;\n  let headlineSuffix = '';\n  \n  if (offerSummary) {\n    headlineSuffix = offerSummary;\n  } else if (productName) {\n    headlineSuffix = productName;\n  }\n  \n  if (headlineSuffix) {\n    headlineText = `${brandName} — ${headlineSuffix}`;\n  }\n\n  logger.debug('[AdMeshTailAd] 📊 Rendering with tracking data:', {\n    recommendationId,\n    productId,\n    exposureUrl: exposureUrl ? 'present' : 'MISSING',\n    sessionId: sessionId ? 'present' : 'MISSING',\n    recommendationsCount: recommendations.length,\n    clickUrl: clickUrl ? clickUrl : 'MISSING',\n    clickUrlSource: firstRecommendation?.click_url ? 'click_url' : \n                    firstRecommendation?.admesh_link ? 'admesh_link' :\n                    creativeInput.cta_url ? 'cta_url' :\n                    firstRecommendation?.url ? 'url' : 'none',\n    shortDescription: shortDescription ? 'present' : 'MISSING',\n    offerSummary: offerSummary || 'MISSING',\n    brandName,\n    productName,\n    headlineText\n  });\n\n  // Handler for tracking clicks on the entire tail ad\n  const handleContainerClick = (source: string, e?: React.MouseEvent) => {\n    if (e) {\n      e.stopPropagation();\n    }\n    logger.log(`AdMesh tail ad ${source} clicked`);\n    if (typeof window !== 'undefined' && (window as any).admeshTracker) {\n      (window as any).admeshTracker.trackClick({\n        recommendationId: firstRecommendation.recommendation_id,\n        productId: firstRecommendation.product_id,\n        clickUrl: clickUrl,\n        source: source\n      }).catch(() => {\n        logger.error(`[AdMesh] Failed to track ${source} click`);\n      });\n    }\n  };\n\n  // Handler for brand name link click\n  const handleBrandNameClick = (e: React.MouseEvent) => {\n    e.stopPropagation();\n    handleContainerClick('tail_ad_brand_name');\n  };\n\n  // Handler for CTA link click\n  const handleCTAClick = (e: React.MouseEvent) => {\n    e.stopPropagation();\n    handleContainerClick('tail_ad_cta');\n  };\n\n  // Handler for logo click\n  const handleLogoClick = (e: React.MouseEvent) => {\n    e.stopPropagation();\n    handleContainerClick('tail_ad_logo');\n  };\n\n  // Get API base URL from SDK or window global\n  const getApiBaseUrl = (): string => {\n    // Try to get from SDK using the public getter method\n    if (sdk && typeof (sdk as any).getApiBaseUrl === 'function') {\n      return (sdk as any).getApiBaseUrl();\n    }\n    // Fallback to direct property access (for backward compatibility)\n    if (sdk && (sdk as any).apiBaseUrl) {\n      return (sdk as any).apiBaseUrl;\n    }\n    // Fallback to window global\n    if (typeof window !== 'undefined' && (window as any).__ADMESH_API_BASE_URL__) {\n      return (window as any).__ADMESH_API_BASE_URL__;\n    }\n    // Default to production\n    return 'https://api.useadmesh.com';\n  };\n\n  // Handler for submitting feedback\n  const submitFeedback = async (feedbackType: 'like' | 'dislike') => {\n    // Prevent duplicate submissions\n    if (feedbackSubmitted || isSubmittingFeedback) {\n      return;\n    }\n\n    setIsSubmittingFeedback(true);\n\n    try {\n      const apiBaseUrl = getApiBaseUrl();\n      const agentId = firstRecommendation?.agent_id || '';\n      \n      const payload = {\n        message_index: 0, // Default to 0, can be enhanced later if message_index is available\n        feedback: feedbackType,\n        session_id: effectiveSessionId || null,\n        user_id: contextUserId || null,\n        agent_id: agentId || null,\n        model_used: contextModel || null,\n        recommendationId: recommendationId || null\n      };\n\n      const endpointUrl = `${apiBaseUrl}/user/feedback/submit`;\n      logger.log(`[AdMesh Tail Ad] Submitting feedback: ${feedbackType}`, {\n        endpoint: endpointUrl,\n        payload\n      });\n\n      const response = await fetch(endpointUrl, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json'\n        },\n        body: JSON.stringify(payload)\n      });\n\n      // Log response details for debugging\n      logger.log(`[AdMesh Tail Ad] Feedback response status: ${response.status} ${response.statusText}`);\n\n      if (!response.ok) {\n        // Try to get error details from response\n        let errorMessage = `Feedback submission failed: ${response.status} ${response.statusText}`;\n        try {\n          const errorData = await response.json().catch(() => null);\n          if (errorData?.detail) {\n            errorMessage = `Feedback submission failed: ${errorData.detail}`;\n          }\n          logger.error(`[AdMesh Tail Ad] Error response body:`, errorData);\n        } catch (e) {\n          // Failed to parse error response, use default message\n        }\n        throw new Error(errorMessage);\n      }\n\n      const result = await response.json();\n      logger.log(`[AdMesh Tail Ad] ✅ Feedback submitted successfully: ${feedbackType}`, result);\n      \n      setFeedbackSubmitted(true);\n\n      // If dislike, hide the component\n      if (feedbackType === 'dislike') {\n        setIsHidden(true);\n      }\n    } catch (error) {\n      // Enhanced error logging\n      const errorDetails = error instanceof Error ? {\n        message: error.message,\n        name: error.name,\n        stack: error.stack\n      } : String(error);\n      \n      logger.error(`[AdMesh Tail Ad] ❌ Failed to submit feedback: ${feedbackType}`, {\n        error: errorDetails,\n        apiBaseUrl: getApiBaseUrl(),\n        endpoint: `${getApiBaseUrl()}/user/feedback/submit`\n      });\n      \n      // Don't block UI on error - allow user to try again\n      setIsSubmittingFeedback(false);\n    }\n  };\n\n  // Handler for like button click\n  const handleLikeClick = (e: React.MouseEvent) => {\n    e.stopPropagation();\n    e.preventDefault();\n    submitFeedback('like');\n  };\n\n  // Handler for dislike button click\n  const handleDislikeClick = (e: React.MouseEvent) => {\n    e.stopPropagation();\n    e.preventDefault();\n    submitFeedback('dislike');\n  };\n\n  // State for logo load error\n  const [logoError, setLogoError] = React.useState(false);\n\n  // Get first letter of brand name for fallback\n  const brandInitial = brandName ? brandName.charAt(0).toUpperCase() : 'B';\n\n  // Determine if dark mode\n  const isDarkMode = theme?.mode === 'dark' || \n    (typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);\n\n  // Card styling with theme support\n  const cardBackground = theme?.surfaceColor || theme?.components?.card?.backgroundColor || \n    (isDarkMode ? '#1f2937' : '#ffffff');\n  const cardBorder = theme?.borderColor || theme?.components?.card?.borderColor || \n    (isDarkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.05)');\n  const cardBorderRadius = theme?.borderRadius || theme?.components?.card?.borderRadius || '8px';\n  \n  // Shadow styles - definitive shadow for floating feel\n  const defaultShadow = isDarkMode \n    ? '0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2)' \n    : '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)';\n  const hoverShadow = isDarkMode\n    ? '0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3)'\n    : '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)';\n  \n  const cardShadow = theme?.shadows?.medium || theme?.components?.card?.boxShadow || defaultShadow;\n  const cardHoverShadow = theme?.shadows?.large || hoverShadow;\n\n  return (\n    <AdMeshViewabilityTracker\n      productId={productId}\n      recommendationId={recommendationId}\n      exposureUrl={exposureUrl}\n      sessionId={sessionId}\n      className={`admesh-tail-ad ${className}`}\n      style={{\n        fontFamily: theme?.fontFamily || '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n        ...style\n      }}\n    >\n      <div \n        className=\"tail-ad-container flex flex-row gap-3\"\n        style={{\n          backgroundColor: cardBackground,\n          borderRadius: cardBorderRadius,\n          padding: '16px',\n          boxShadow: cardShadow,\n          border: `1px solid ${cardBorder}`,\n          transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',\n          transform: 'translateY(0)',\n          ...theme?.components?.card\n        }}\n        onMouseEnter={(e) => {\n          e.currentTarget.style.boxShadow = cardHoverShadow;\n          e.currentTarget.style.transform = 'translateY(-2px)';\n        }}\n        onMouseLeave={(e) => {\n          e.currentTarget.style.boxShadow = cardShadow;\n          e.currentTarget.style.transform = 'translateY(0)';\n        }}\n      >\n        {/* Left Section: Logo Area (10% width, stacks on mobile) */}\n        {logoUrl && (\n          <div \n            className=\"flex-shrink-0 flex items-center justify-center pr-2\"\n            style={{\n              width: '10%',\n              minWidth: '48px'\n            }}\n          >\n            {!logoError && isValidUrl(logoUrl) ? (\n              <a\n                href={clickUrl || '#'}\n                target={clickUrl ? \"_blank\" : undefined}\n                rel={clickUrl ? \"noopener noreferrer\" : undefined}\n                onClick={clickUrl ? handleLogoClick : undefined}\n                className=\"block\"\n                style={{ \n                  cursor: clickUrl ? 'pointer' : 'default',\n                  display: 'flex',\n                  alignItems: 'center',\n                  justifyContent: 'center',\n                  width: '100%',\n                  maxWidth: '64px'\n                }}\n              >\n                <img\n                  src={logoUrl}\n                  alt={`${brandName} logo`}\n                  className=\"object-cover\"\n                  style={{\n                    width: '100%',\n                    height: 'auto',\n                    maxWidth: '64px',\n                    maxHeight: '64px',\n                    objectFit: 'contain',\n                    borderRadius: '8px'\n                  }}\n                  onError={() => {\n                    setLogoError(true);\n                    logger.debug('[AdMesh Tail Ad] Logo failed to load, showing fallback');\n                  }}\n                />\n              </a>\n            ) : (\n              <div\n                className=\"flex items-center justify-center text-lg font-semibold text-gray-600 dark:text-gray-300 bg-gray-100 dark:bg-gray-800\"\n                style={{\n                  width: '100%',\n                  maxWidth: '64px',\n                  aspectRatio: '1',\n                  borderRadius: '8px',\n                  minHeight: '48px'\n                }}\n              >\n                {brandInitial}\n              </div>\n            )}\n          </div>\n        )}\n\n        {/* Right Section: Content Area (90% width) */}\n        <div \n          className=\"flex-1\"\n          style={{\n            width: logoUrl ? '90%' : '100%',\n            minWidth: 0 // Allow flex item to shrink below content size\n          }}\n        >\n          {/* Headline: Brand Name (clickable link) — Offer Summary / Product Name / Brand only */}\n          {headlineText && (\n            <div className=\"mb-2\">\n              <h3 className=\"text-black dark:text-white font-semibold text-base\" style={{ fontSize: '0.7rem' }}>\n                {clickUrl && brandName ? (\n                  <>\n                    <a\n                      href={clickUrl}\n                      target=\"_blank\"\n                      rel=\"noopener noreferrer\"\n                      className=\"text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 underline decoration-blue-600 dark:decoration-blue-400 hover:decoration-blue-800 dark:hover:decoration-blue-300 transition-colors duration-200 font-semibold\"\n                      style={{\n                        color: '#2563eb',\n                        textDecoration: 'underline',\n                        textDecorationColor: '#2563eb',\n                        textUnderlineOffset: '2px'\n                      }}\n                      onClick={handleBrandNameClick}\n                    >\n                      {brandName}\n                    </a>\n                    {headlineSuffix && ` — ${headlineSuffix}`}\n                  </>\n                ) : (\n                  headlineText\n                )}\n              </h3>\n            </div>\n          )}\n          \n          {/* Description: Full short_description */}\n          {shortDescription && (\n            <p className=\"text-gray-700 dark:text-gray-300 text-sm mb-3 leading-relaxed\" style={{ fontSize: '0.7rem' }}>\n              {shortDescription}\n            </p>\n          )}\n          \n          {/* CTA Link, Feedback Buttons, and Sponsored Label */}\n          <div className=\"flex items-center justify-between mt-2\">\n            {/* Left side: CTA Link */}\n            <div className=\"flex items-center gap-2\">\n              {/* CTA Link - Left aligned (only show if ctaLabel is provided) */}\n              {ctaLabel && clickUrl && (\n                <a\n                  href={clickUrl}\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                  className=\"text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 underline decoration-blue-600 dark:decoration-blue-400 hover:decoration-blue-800 dark:hover:decoration-blue-300 transition-colors duration-200 font-medium text-sm\"\n                  style={{\n                    color: '#2563eb',\n                    textDecoration: 'underline',\n                    textDecorationColor: '#2563eb',\n                    textUnderlineOffset: '2px'\n                  }}\n                  onClick={handleCTAClick}\n                >\n                  {ctaLabel}\n                </a>\n              )}\n            </div>\n\n            {/* Right side: Feedback buttons and Sponsored label */}\n            <div className=\"flex items-center gap-2\">\n              {/* Helpful Button */}\n              <button\n                onClick={handleLikeClick}\n                disabled={feedbackSubmitted || isSubmittingFeedback}\n                aria-label=\"Mark as helpful\"\n                className=\"flex items-center justify-center px-2 py-1 rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed\"\n                style={{\n                  color: feedbackSubmitted && !isHidden ? '#10b981' : (isDarkMode ? '#9ca3af' : '#6b7280'),\n                  backgroundColor: 'transparent',\n                  border: 'none',\n                  cursor: feedbackSubmitted || isSubmittingFeedback ? 'not-allowed' : 'pointer',\n                  fontSize: '0.75rem',\n                  fontWeight: '500',\n                  minHeight: '24px'\n                }}\n                onMouseEnter={(e) => {\n                  if (!feedbackSubmitted && !isSubmittingFeedback) {\n                    e.currentTarget.style.color = '#10b981';\n                    e.currentTarget.style.backgroundColor = isDarkMode ? 'rgba(16, 185, 129, 0.1)' : 'rgba(16, 185, 129, 0.1)';\n                  }\n                }}\n                onMouseLeave={(e) => {\n                  if (!feedbackSubmitted) {\n                    e.currentTarget.style.color = feedbackSubmitted ? '#10b981' : (isDarkMode ? '#9ca3af' : '#6b7280');\n                    e.currentTarget.style.backgroundColor = 'transparent';\n                  }\n                }}\n              >\n                Helpful\n              </button>\n\n              {/* Not Helpful Button */}\n              <button\n                onClick={handleDislikeClick}\n                disabled={feedbackSubmitted || isSubmittingFeedback}\n                aria-label=\"Mark as not helpful\"\n                className=\"flex items-center justify-center px-2 py-1 rounded transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed\"\n                style={{\n                  color: isHidden ? '#ef4444' : (isDarkMode ? '#9ca3af' : '#6b7280'),\n                  backgroundColor: 'transparent',\n                  border: 'none',\n                  cursor: feedbackSubmitted || isSubmittingFeedback ? 'not-allowed' : 'pointer',\n                  fontSize: '0.75rem',\n                  fontWeight: '500',\n                  minHeight: '24px'\n                }}\n                onMouseEnter={(e) => {\n                  if (!feedbackSubmitted && !isSubmittingFeedback) {\n                    e.currentTarget.style.color = '#ef4444';\n                    e.currentTarget.style.backgroundColor = isDarkMode ? 'rgba(239, 68, 68, 0.1)' : 'rgba(239, 68, 68, 0.1)';\n                  }\n                }}\n                onMouseLeave={(e) => {\n                  if (!isHidden) {\n                    e.currentTarget.style.color = isDarkMode ? '#9ca3af' : '#6b7280';\n                    e.currentTarget.style.backgroundColor = 'transparent';\n                  }\n                }}\n              >\n                Not Helpful\n              </button>\n\n              {/* Sponsored Label */}\n              <p className=\"text-xs text-gray-500 dark:text-gray-400\">\n                Sponsored\n              </p>\n            </div>\n          </div>\n        </div>\n      </div>\n    </AdMeshViewabilityTracker>\n  );\n};\n\nexport default AdMeshTailAd;\n\n","import { useAdMeshContext } from '../context/AdMeshContext';\n\n/**\n * Hook to access AdMesh SDK and tracking state\n *\n * Must be used within an <AdMeshProvider>\n *\n * @returns Object with SDK instance and tracking methods\n *\n * @example\n * ```tsx\n * const { sdk, sessionId, markMessageAsProcessed } = useAdMesh();\n *\n * // Use SDK to show recommendations\n * await sdk?.showRecommendations({\n *   query: 'user query',\n *   containerId: 'recommendations-container',\n *   session_id: sessionId,\n *   message_id: messageId\n * });\n *\n * // Mark message as processed to avoid duplicates\n * markMessageAsProcessed(messageId);\n * ```\n */\nexport function useAdMesh() {\n  const context = useAdMeshContext();\n\n  return {\n    /** AdMesh SDK instance */\n    sdk: context.sdk,\n\n    /** API key */\n    apiKey: context.apiKey,\n\n    /** Session ID */\n    sessionId: context.sessionId,\n\n    /** Theme configuration */\n    theme: context.theme,\n\n    /** User language in BCP 47 format (e.g., \"en-US\") - from AdMeshProvider */\n    language: context.language,\n\n    /** User country code in ISO 3166-1 alpha-2 format (e.g., \"US\") - from AdMeshProvider */\n    geo_country: context.geo_country,\n\n    /** Anonymous hashed user ID - from AdMeshProvider */\n    userId: context.userId,\n\n    /** AI model identifier (e.g., \"gpt-4o\") - from AdMeshProvider */\n    model: context.model,\n\n    /** Conversation history - from AdMeshProvider */\n    messages: context.messages,\n\n    /** Set of processed message IDs (for deduplication) */\n    processedMessageIds: context.processedMessageIds,\n\n    /** Mark a message as processed to prevent duplicate recommendations */\n    markMessageAsProcessed: context.markMessageAsProcessed,\n\n    /** Check if a message has already been processed */\n    isMessageProcessed: context.isMessageProcessed,\n  };\n}\n\nexport default useAdMesh;\n\n","'use client';\n\nimport React from 'react';\nimport { logger } from '../utils/logger';\nimport type { AdMeshRecommendation, AdMeshTheme } from '../types/index';\nimport { AdMeshViewabilityTracker } from './AdMeshViewabilityTracker';\nimport { useAdMesh } from '../hooks/useAdMesh';\n\nexport interface AdMeshBridgeFormatProps {\n  recommendation: AdMeshRecommendation;\n  theme?: AdMeshTheme;\n  className?: string;\n  style?: React.CSSProperties;\n  sessionId?: string;\n  onLinkClick?: (recommendation: AdMeshRecommendation) => void;\n  /** Callback to paste content to input field (for CTA button) */\n  onPasteToInput?: (content: string) => void;\n}\n\n/**\n * AdMeshBridgeFormat - Bridge Ad Format Component\n * \n * Displays bridge format recommendations as followup sponsored recommendations with setup prompts and documentation URLs.\n * Bridge format is primarily designed for Vibe Coding Platforms and AI IDEs, and can also be shown in AI search as followup suggestions.\n * These recommendations appear after initial responses to provide setup instructions and configuration guidance.\n * \n * @example\n * ```tsx\n * <AdMeshBridgeFormat\n *   recommendation={recommendation}\n *   sessionId={sessionId}\n *   theme={theme}\n * />\n * ```\n */\n/**\n * Extract CTA text from bridge_prompt / bridge_content\n * Generates \"Integrate [Product]\" format based on product name in the prompt\n */\nconst extractCTAText = (bridgePrompt: string, productName?: string): string => {\n  if (!bridgePrompt) return 'Get Started';\n\n  // Try to extract product name from prompt first\n  let extractedProduct = '';\n  \n  // Patterns to extract product name\n  const productPatterns = [\n    /(?:set up|setup|integrate|add|install|use)\\s+([A-Z][a-zA-Z0-9\\s]+?)(?:\\.|$|,| by)/i,\n    /(?:by|from)\\s+([A-Z][a-zA-Z0-9\\s]+?)(?:\\.|$|,)/,\n  ];\n\n  for (const pattern of productPatterns) {\n    const match = bridgePrompt.match(pattern);\n    if (match && match[1]) {\n      extractedProduct = match[1].trim();\n      break;\n    }\n  }\n\n  // Use provided productName or extracted product\n  const product = productName || extractedProduct;\n  \n  if (product) {\n    // Clean up product name (remove extra words, keep main product name)\n    const cleanProduct = product.split(/\\s+/).slice(0, 2).join(' '); // Take first 2 words max\n    return `Integrate ${cleanProduct}`;\n  }\n\n  // Fallback: try to extract from \"To set up [Product]\" pattern\n  const setupMatch = bridgePrompt.match(/to\\s+set\\s+up\\s+([a-zA-Z0-9\\s]+?)(?:\\s+by|\\s*[.,]|$)/i);\n  if (setupMatch && setupMatch[1]) {\n    const product = setupMatch[1].trim().split(/\\s+/).slice(0, 2).join(' ');\n    return `Integrate ${product}`;\n  }\n\n  return 'Integrate';\n};\n\nexport const AdMeshBridgeFormat: React.FC<AdMeshBridgeFormatProps> = ({\n  recommendation,\n  theme,\n  className = '',\n  style = {},\n  sessionId,\n  onLinkClick,\n  onPasteToInput,\n}) => {\n  const creativeInput = recommendation.creative_input || {};\n  // Extract bridge format fields\n  const bridgeHeadline = (creativeInput as any).bridge_headline || '';\n  const bridgeDescription = (creativeInput as any).bridge_description || '';\n  const bridgePrompt =\n    (creativeInput as any).bridge_prompt ||\n    (creativeInput as any).bridge_content ||\n    '';\n  const productName = creativeInput.product_name || '';\n  const ctaLabel = creativeInput.cta_label || '';\n\n  // If no bridge description or prompt, don't render\n  if (!bridgeDescription && !bridgePrompt) {\n    return null;\n  }\n\n  const productId = recommendation.product_id || '';\n  const recommendationId = recommendation.recommendation_id || '';\n  \n  // Get SDK and sessionId from context for API calls\n  const { sdk, sessionId: contextSessionId } = useAdMesh();\n  const effectiveSessionId = sessionId || contextSessionId;\n  \n  // Bridge format doesn't use click_url or admesh_link - it only pastes the prompt\n  // Exposure pixel is fired by AdMeshViewabilityTracker when ad becomes viewable (MRC-compliant)\n\n  const handleCTAClick = async (e: React.MouseEvent) => {\n    e.preventDefault();\n    \n    if (!bridgePrompt) return;\n\n    // Track bridge engagement (sets status to \"engaged\")\n    if (recommendationId && effectiveSessionId) {\n      try {\n        // Get API base URL from SDK or use default\n        const apiBaseUrl = (sdk as any)?.apiBaseUrl || \n                          (typeof window !== 'undefined' && (window as any).__ADMESH_API_BASE_URL__) ||\n                          'https://api.useadmesh.com';\n        \n        const response = await fetch(`${apiBaseUrl}/click/bridge-engagement`, {\n          method: 'POST',\n          headers: {\n            'Content-Type': 'application/json',\n          },\n          body: JSON.stringify({\n            recommendation_id: recommendationId,\n            session_id: effectiveSessionId,\n            agent_id: recommendation.agent_id,\n            user_id: (recommendation as any).user_id || undefined,\n            is_test: false, // TODO: Get from config if needed\n          }),\n        });\n\n        if (response.ok) {\n          logger.log('[AdMesh Bridge] ✅ Engagement tracked successfully');\n        } else {\n          logger.warn('[AdMesh Bridge] ⚠️ Failed to track engagement:', response.statusText);\n        }\n      } catch (error) {\n        logger.error('[AdMesh Bridge] ❌ Error tracking engagement:', error);\n        // Don't block the user action if tracking fails\n      }\n    }\n\n    // Call onLinkClick if provided (for tracking purposes)\n    if (onLinkClick) {\n      onLinkClick(recommendation);\n    }\n\n    // Paste prompt to input if callback provided\n    if (onPasteToInput) {\n      onPasteToInput(bridgePrompt);\n    } else if (typeof window !== 'undefined' && (window as any).__admesh_setMessage) {\n      // Fallback to window object\n      (window as any).__admesh_setMessage(bridgePrompt);\n    }\n  };\n\n  // Use cta_label from creative_input if available, otherwise extract from prompt\n  const ctaText = ctaLabel || extractCTAText(bridgePrompt, productName);\n  \n  // Always show CTA if we have text for it\n  const shouldShowCTA = !!ctaText;\n\n  return (\n    <AdMeshViewabilityTracker\n      productId={productId}\n      recommendationId={recommendation.recommendation_id || ''}\n      exposureUrl={recommendation.exposure_url}\n      sessionId={sessionId}\n      className={`admesh-bridge-format ${className}`}\n      style={{\n        fontFamily: theme?.fontFamily || '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n        padding: '1rem',\n        border: 'none',\n        borderRadius: theme?.borderRadius || '0.5rem',\n        backgroundColor: 'transparent',\n        color: theme?.textColor || 'inherit',\n        ...style\n      }}\n    >\n      <div data-admesh-theme={theme?.mode || 'light'}>\n        {/* Bridge Headline */}\n        {bridgeHeadline && (\n          <div\n            className=\"admesh-bridge-headline\"\n            style={{\n              marginBottom: bridgeDescription ? '0.75rem' : shouldShowCTA ? '1rem' : '0',\n              fontSize: theme?.fontSize?.large || '1rem',\n              fontWeight: 600,\n              color: theme?.textColor || 'inherit',\n              lineHeight: '1.4',\n            }}\n          >\n            {bridgeHeadline}\n          </div>\n        )}\n\n        {/* Brand Description (1 sentence, short) - shown initially */}\n        {bridgeDescription && (\n          <div\n            className=\"admesh-bridge-description\"\n            style={{\n              marginBottom: (shouldShowCTA || recommendation.creative_input?.offer_summary) ? '1rem' : '0',\n              lineHeight: '1.6',\n              fontSize: theme?.fontSize?.base || '0.875rem',\n              color: theme?.textColor || 'inherit',\n            }}\n          >\n            {bridgeDescription}\n          </div>\n        )}\n\n        {/* Offer Summary: Display below description */}\n        {recommendation.creative_input?.offer_summary && (\n          <div\n            className=\"admesh-bridge-offer-summary\"\n            style={{\n              marginBottom: shouldShowCTA ? '1rem' : '0',\n              lineHeight: '1.5',\n              fontSize: theme?.fontSize?.small || '0.75rem',\n              color: theme?.textSecondaryColor || theme?.mode === 'dark' ? '#9ca3af' : '#6b7280',\n              fontStyle: 'italic',\n            }}\n          >\n            {recommendation.creative_input.offer_summary}\n          </div>\n        )}\n\n        {/* CTA Button - Left aligned, just below description */}\n        {shouldShowCTA && (\n          <div style={{ marginBottom: '0.75rem' }}>\n            <button\n              onClick={handleCTAClick}\n              className=\"admesh-bridge-cta-button\"\n              style={{\n                padding: '0.5rem 1rem',\n                backgroundColor: '#000000',\n                color: '#ffffff',\n                fontSize: theme?.fontSize?.small || '0.875rem',\n                fontWeight: 500,\n                borderRadius: theme?.borderRadius || '0.5rem',\n                border: 'none',\n                cursor: 'pointer',\n                transition: 'background-color 0.2s, opacity 0.2s',\n              }}\n              onMouseEnter={(e) => {\n                e.currentTarget.style.backgroundColor = '#1a1a1a';\n                e.currentTarget.style.opacity = '0.9';\n              }}\n              onMouseLeave={(e) => {\n                e.currentTarget.style.backgroundColor = '#000000';\n                e.currentTarget.style.opacity = '1';\n              }}\n            >\n              {ctaText}\n            </button>\n          </div>\n        )}\n\n        {/* Sponsored Label - Right aligned */}\n        <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '0.5rem' }}>\n          <div\n            className=\"admesh-bridge-label\"\n            style={{\n              fontSize: theme?.fontSize?.small || '0.75rem',\n              color: theme?.textSecondaryColor || theme?.mode === 'dark' ? '#9ca3af' : '#6b7280',\n              fontStyle: 'italic',\n            }}\n          >\n            Sponsored\n          </div>\n        </div>\n      </div>\n    </AdMeshViewabilityTracker>\n  );\n};\n\nexport default AdMeshBridgeFormat;\n","/*!\n\tCopyright (c) 2018 Jed Watson.\n\tLicensed under the MIT License (MIT), see\n\thttp://jedwatson.github.io/classnames\n*/\n/* global define */\n\n(function () {\n\t'use strict';\n\n\tvar hasOwn = {}.hasOwnProperty;\n\n\tfunction classNames () {\n\t\tvar classes = '';\n\n\t\tfor (var i = 0; i < arguments.length; i++) {\n\t\t\tvar arg = arguments[i];\n\t\t\tif (arg) {\n\t\t\t\tclasses = appendClass(classes, parseValue(arg));\n\t\t\t}\n\t\t}\n\n\t\treturn classes;\n\t}\n\n\tfunction parseValue (arg) {\n\t\tif (typeof arg === 'string' || typeof arg === 'number') {\n\t\t\treturn arg;\n\t\t}\n\n\t\tif (typeof arg !== 'object') {\n\t\t\treturn '';\n\t\t}\n\n\t\tif (Array.isArray(arg)) {\n\t\t\treturn classNames.apply(null, arg);\n\t\t}\n\n\t\tif (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes('[native code]')) {\n\t\t\treturn arg.toString();\n\t\t}\n\n\t\tvar classes = '';\n\n\t\tfor (var key in arg) {\n\t\t\tif (hasOwn.call(arg, key) && arg[key]) {\n\t\t\t\tclasses = appendClass(classes, key);\n\t\t\t}\n\t\t}\n\n\t\treturn classes;\n\t}\n\n\tfunction appendClass (value, newClass) {\n\t\tif (!newClass) {\n\t\t\treturn value;\n\t\t}\n\t\n\t\tif (value) {\n\t\t\treturn value + ' ' + newClass;\n\t\t}\n\t\n\t\treturn value + newClass;\n\t}\n\n\tif (typeof module !== 'undefined' && module.exports) {\n\t\tclassNames.default = classNames;\n\t\tmodule.exports = classNames;\n\t} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {\n\t\t// register as 'classnames', consistent with npm package name\n\t\tdefine('classnames', [], function () {\n\t\t\treturn classNames;\n\t\t});\n\t} else {\n\t\twindow.classNames = classNames;\n\t}\n}());\n","import React, { useCallback, useEffect, useRef } from 'react';\nimport type { AdMeshLinkTrackerProps } from '../types/index';\nimport { logger } from '../utils/logger';\n\n/**\n * AdMeshLinkTracker Component\n * \n * Wraps content with click tracking via AdMesh click URLs.\n * \n * Note: View/exposure tracking is handled separately by AdMeshViewabilityTracker component.\n * This component only handles click navigation to the admeshLink (which contains click tracking).\n * \n * The admeshLink prop should be the click URL from the recommendation, which already includes\n * all necessary tracking parameters and will redirect to the merchant URL.\n */\nexport const AdMeshLinkTracker: React.FC<AdMeshLinkTrackerProps> = ({\n  recommendationId,\n  admeshLink,\n  productId,\n  children,\n  trackingData,\n  className,\n  style\n}) => {\n  const elementRef = useRef<HTMLDivElement>(null);\n\n  // Ensure all child links open in new tab\n  useEffect(() => {\n    if (!elementRef.current) return;\n\n    // Find all <a> tags within this component and ensure they open in new tab\n    const links = elementRef.current.querySelectorAll('a');\n    links.forEach((link) => {\n      // Only set if not already set or if it's not _blank\n      if (!link.hasAttribute('target') || link.getAttribute('target') !== '_blank') {\n        link.setAttribute('target', '_blank');\n        link.setAttribute('rel', 'noopener noreferrer');\n      }\n    });\n  }, [children]); // Re-run when children change\n\n  const handleClick = useCallback((event: React.MouseEvent) => {\n    // The admeshLink already contains the click tracking URL from the backend\n    // Navigating to it will automatically fire the click tracking pixel and redirect to merchant\n    \n    // If the children contain a link, ensure it opens in new tab\n    // Otherwise, navigate programmatically\n    const target = event.target as HTMLElement;\n    const link = target.closest('a');\n\n    if (!link) {\n      // No link found, navigate programmatically to the click URL\n      // The click URL will handle tracking and redirect\n      if (admeshLink) {\n        window.open(admeshLink, '_blank', 'noopener,noreferrer');\n      } else {\n        logger.warn('[AdMeshLinkTracker] No admeshLink provided for click tracking');\n      }\n    } else {\n      // Link found - ensure it opens in new tab\n      // If the link href is not set or is different from admeshLink, update it\n      if (!link.href || link.href === '#' || link.href === '') {\n        if (admeshLink) {\n          link.href = admeshLink;\n        }\n      }\n      if (!link.hasAttribute('target') || link.getAttribute('target') !== '_blank') {\n        link.setAttribute('target', '_blank');\n        link.setAttribute('rel', 'noopener noreferrer');\n      }\n      // Let the browser handle navigation naturally (click URL will track and redirect)\n    }\n  }, [admeshLink]);\n\n  return (\n    <div\n      ref={elementRef}\n      className={className}\n      onClick={handleClick}\n      style={{\n        cursor: 'pointer',\n        ...style\n      }}\n    >\n      {children}\n    </div>\n  );\n};\n\nAdMeshLinkTracker.displayName = 'AdMeshLinkTracker';\n","import React from 'react';\nimport { logger } from '../utils/logger';\nimport classNames from 'classnames';\nimport type { AdMeshRecommendation, Product } from '../types/index';\nimport { AdMeshViewabilityTracker } from './AdMeshViewabilityTracker';\nimport { AdMeshLinkTracker } from './AdMeshLinkTracker';\nimport { useAdMesh } from '../hooks/useAdMesh';\n\n/**\n * Props for AdMeshEcommerceCards component.\n * \n * @remarks\n * This component requires BOTH brand information and products to be present.\n * - Brand info: Extracted from brand.creative_input (brand_name, assets.logo_url, short_description)\n * - Products: Must be provided in brand.products[] array with at least one product\n * \n * Both brand header and product cards will be displayed when valid data is provided.\n */\nexport interface AdMeshEcommerceCardsProps {\n  /** \n   * Required: Single brand recommendation object containing brand info and products array.\n   * Both brand information (name, logo, description) and products array must be present.\n   * Brand info is extracted from creative_input, products from the products[] array.\n   */\n  brand: AdMeshRecommendation;\n  title?: string;\n  showTitle?: boolean;\n  className?: string;\n  cardClassName?: string;\n  onProductClick?: (product: Product) => void;\n  showPricing?: boolean;\n  showRatings?: boolean;\n  showBrand?: boolean;\n  showSource?: boolean;\n  showShipping?: boolean;\n  maxCards?: number;\n  cardWidth?: 'sm' | 'md' | 'lg';\n  theme?: 'light' | 'dark' | 'auto';\n  borderRadius?: 'none' | 'sm' | 'md' | 'lg';\n  shadow?: 'none' | 'sm' | 'md' | 'lg';\n  sessionId?: string; // Optional sessionId for tracking (falls back to context)\n  onFeedback?: (helpful: boolean, recommendationId: string) => void; // Callback when feedback is submitted\n}\n\n/**\n * AdMeshEcommerceCards Component\n * \n * Displays a brand header and horizontal scrolling product cards for ecommerce recommendations.\n * \n * @remarks\n * **Requirements:**\n * - Both brand information AND products are required\n * - Brand info: brand.creative_input.brand_name, brand.creative_input.assets.logo_url, brand.creative_input.short_description\n * - Products: brand.products[] array with at least one product\n * \n * The component will display:\n * 1. Brand header section (logo, name, description) - always shown when brand info exists\n * 2. Product cards section (horizontal scroll) - always shown when products exist\n * \n * @example\n * ```tsx\n * <AdMeshEcommerceCards\n *   brand={{\n *     creative_input: {\n *       brand_name: \"TechCorp\",\n *       assets: { logo_url: \"https://...\" },\n *       short_description: \"Premium tech products\"\n *     },\n *     products: [\n *       {\n *         product_id: \"prod1\",\n *         product_link: \"https://techcorp.com/product1\",\n *         product_name: \"Laptop Pro\",\n *         product_description: \"High-performance laptop\",\n *         product_price: 1299.99,\n *         product_discount: 15,\n *         product_cta_label: \"Buy Now\"\n *       },\n *       {\n *         product_id: \"prod2\",\n *         product_click_url: \"https://techcorp.com/product2\",\n *         product_name: \"Wireless Mouse\",\n *         product_description: \"Ergonomic mouse\",\n *         product_price: \"49.99\",\n *         product_discount: \"10%\",\n *         product_cta_label: \"Add to Cart\"\n *       }\n *     ]\n *   }}\n * />\n * ```\n */\nexport const AdMeshEcommerceCards: React.FC<AdMeshEcommerceCardsProps> = ({\n  brand,\n  title = \"Product Recommendations\",\n  showTitle = false,\n  className = \"\",\n  cardClassName = \"\",\n  onProductClick,\n  maxCards = 10,\n  cardWidth = 'md',\n  theme = 'auto',\n  borderRadius = 'md',\n  shadow = 'sm',\n  sessionId: propSessionId,\n  onFeedback\n}) => {\n  const [feedbackSubmitted, setFeedbackSubmitted] = React.useState<'helpful' | 'not-helpful' | null>(null);\n  // Validate that both brand and products are present (both are required)\n  if (!brand) {\n    logger.log('[AdMesh Ecommerce Cards] Brand object is required but was not provided');\n    return null;\n  }\n\n  if (!brand.products || brand.products.length === 0) {\n    logger.log('[AdMesh Ecommerce Cards] Products array is required but was empty or missing. Both brand info and products are required for ecommerce cards.');\n    return null;\n  }\n\n  const displayItems: Product[] = brand.products.slice(0, maxCards);\n\n  // Extract brand info from brand recommendation object\n  const getBrandName = (): string => {\n    return (brand as any).brand_name ||\n      brand.creative_input?.brand_name ||\n      '';\n  };\n\n  const getBrandLogo = (): string => {\n    return brand.creative_input?.assets?.logo_url || '';\n  };\n\n  const getBrandDescription = (): string => {\n    return brand.creative_input?.short_description ||\n      (brand as any).description ||\n      '';\n  };\n\n  // Extract CTA info for products - products are simple objects with only these fields\n  const getCtaUrl = (item: Product): string => {\n    return item.product_link ||\n      item.product_click_url ||\n      '';\n  };\n\n  const getCtaLabel = (item: Product): string => {\n    return item.product_cta_label || 'Shop';\n  };\n\n  const getPrice = (item: Product): string => {\n    const productPrice = item.product_price;\n\n    // Handle both number and string formats\n    if (productPrice !== undefined && productPrice !== null) {\n      if (typeof productPrice === 'string') return productPrice;\n      if (typeof productPrice === 'number') return `$${productPrice.toFixed(2)}`;\n    }\n    return '';\n  };\n\n  const getProductName = (item: Product): string => {\n    return item.product_name || '';\n  };\n\n\n  const getProductDisplayContent = (item: Product): string => {\n    if (item.product_features && item.product_features.length > 0) {\n      // Deterministic selection based on product_id to avoid hydration errors\n      let hash = 0;\n      const str = item.product_id || '';\n      for (let i = 0; i < str.length; i++) {\n        hash = ((hash << 5) - hash) + str.charCodeAt(i);\n        hash |= 0;\n      }\n      const index = Math.abs(hash) % item.product_features.length;\n      return item.product_features[index];\n    }\n    return item.product_description || '';\n  };\n\n  const getProductImageUrl = (item: Product): string | null => {\n    return item.product_image_url || null;\n  };\n\n  const getProductDiscount = (item: Product): string | null => {\n    const discount = item.product_discount;\n    if (discount !== undefined && discount !== null) {\n      if (typeof discount === 'string') return discount;\n      if (typeof discount === 'number') return `${discount}%`;\n    }\n    return null;\n  };\n\n  const getCardWidthClass = () => {\n    // Fixed width - same across all device sizes (increased by 15px)\n    switch (cardWidth) {\n      case 'sm': return 'w-[305px] min-w-[305px] max-w-[305px]';\n      case 'md': return 'w-[345px] min-w-[345px] max-w-[345px]';\n      case 'lg': return 'w-[385px] min-w-[385px] max-w-[385px]';\n      default: return 'w-[345px] min-w-[345px] max-w-[345px]';\n    }\n  };\n\n  const getBorderRadiusClass = () => {\n    switch (borderRadius) {\n      case 'none': return 'rounded-none';\n      case 'sm': return 'rounded-sm';\n      case 'md': return 'rounded-lg';\n      case 'lg': return 'rounded-xl';\n      default: return 'rounded-lg';\n    }\n  };\n\n  const getShadowClass = () => {\n    switch (shadow) {\n      case 'none': return '';\n      case 'sm': return 'shadow-sm hover:shadow-md';\n      case 'md': return 'shadow-md hover:shadow-lg';\n      case 'lg': return 'shadow-lg hover:shadow-xl';\n      default: return 'shadow-sm hover:shadow-md';\n    }\n  };\n\n  const getThemeClasses = () => {\n    if (theme === 'dark') {\n      return 'bg-gray-900 text-white';\n    } else if (theme === 'light') {\n      return 'bg-white text-gray-900';\n    }\n    return 'bg-white dark:bg-gray-900 text-gray-900 dark:text-white';\n  };\n\n\n\n  const handleProductClick = (item: Product) => {\n    if (onProductClick) {\n      onProductClick(item);\n    } else {\n      // Default behavior: use product_link (contains tracking URL from backend)\n      // AdMeshLinkTracker will handle the click tracking and navigation\n      const link = item.product_link || item.product_click_url;\n      if (link) {\n        // AdMeshLinkTracker handles navigation, but we can still call this as fallback\n        window.open(link, '_blank', 'noopener,noreferrer');\n      }\n    }\n  };\n\n  const brandName = getBrandName();\n  const brandLogo = getBrandLogo();\n  const brandDescription = getBrandDescription();\n\n  // Get sessionId from props or context for tracking\n  const { sessionId: contextSessionId, userId: contextUserId } = useAdMesh();\n  const effectiveSessionId = propSessionId || contextSessionId;\n\n  // Extract exposure URL from brand recommendation (at top level from backend)\n  const exposureUrl = brand.exposure_url;\n\n  return (\n    <AdMeshViewabilityTracker\n      recommendationId={brand.recommendation_id}\n      exposureUrl={exposureUrl}\n      sessionId={effectiveSessionId}\n      className={classNames('w-full', className)}\n    >\n      {/* Main Card Container with definitive shadows and box styling */}\n      <div className={classNames(\n        'bg-white dark:bg-gray-900',\n        'border border-gray-200 dark:border-gray-700',\n        'rounded-xl',\n        'shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-1px_rgba(0,0,0,0.06)]',\n        'dark:shadow-[0_4px_6px_-1px_rgba(0,0,0,0.3),0_2px_4px_-1px_rgba(0,0,0,0.2)]',\n        'p-6',\n        'transition-shadow duration-200',\n        'hover:shadow-[0_10px_15px_-3px_rgba(0,0,0,0.1),0_4px_6px_-2px_rgba(0,0,0,0.05)]',\n        'dark:hover:shadow-[0_10px_15px_-3px_rgba(0,0,0,0.4),0_4px_6px_-2px_rgba(0,0,0,0.3)]'\n      )}>\n        {/* Brand Header Section - Always display when brand info exists (both brand and products are required) */}\n        {(brandName || brandLogo || brandDescription) && (\n          <div className=\"mb-4\">\n            <div className=\"flex items-start gap-3\">\n              {/* Logo on left - spans both rows */}\n              {brandLogo && (\n                <div className=\"flex-shrink-0\">\n                  <div\n                    className=\"rounded-full overflow-hidden bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center\"\n                    style={{ aspectRatio: '1', width: '48px', height: '48px' }}\n                  >\n                    <img\n                      src={brandLogo}\n                      alt={`${brandName} logo`}\n                      className=\"w-full h-full object-contain\"\n                      style={{ aspectRatio: '1' }}\n                      onError={(e) => {\n                        (e.target as HTMLImageElement).style.display = 'none';\n                      }}\n                    />\n                  </div>\n                </div>\n              )}\n              {/* Brand name and description on right - two rows */}\n              <div className=\"flex-1\">\n                {/* Top row - Brand name */}\n                {brandName && (\n                  <div className=\"font-bold text-gray-900 dark:text-white text-base mb-1\">\n                    {brandName}\n                  </div>\n                )}\n                {/* Bottom row - Brand description */}\n                {brandDescription && (\n                  <p className=\"text-sm text-gray-600 dark:text-gray-400\">\n                    {brandDescription}\n                  </p>\n                )}\n              </div>\n            </div>\n          </div>\n        )}\n\n        <div className=\"relative\">\n          {displayItems.length === 0 ? (\n            <div className=\"text-center py-8 text-gray-500\">\n              No products to display\n            </div>\n          ) : (\n            <div className=\"flex gap-3 sm:gap-4 overflow-x-auto pb-4 scrollbar-hide\">\n              {displayItems.map((item) => {\n                // Get the appropriate ID for the key and tracking\n                const productId = item.product_id;\n                const itemId = productId;\n                const ctaUrl = getCtaUrl(item);\n                const ctaLabel = getCtaLabel(item);\n                const price = getPrice(item);\n                const productName = getProductName(item);\n                const productDisplayContent = getProductDisplayContent(item);\n                const productDiscount = getProductDiscount(item);\n                const productImageUrl = getProductImageUrl(item);\n                const productLink = item.product_link || item.product_click_url || '';\n                // Use parent recommendation's recommendation_id for all products\n                const parentRecommendationId = brand.recommendation_id;\n\n                return (\n                  <AdMeshLinkTracker\n                    key={itemId}\n                    recommendationId={parentRecommendationId}\n                    admeshLink={productLink}\n                    productId={productId}\n                    trackingData={{\n                      sessionId: effectiveSessionId,\n                      userId: contextUserId\n                    }}\n                  >\n                    <div\n                      className={classNames(\n                        getCardWidthClass(),\n                        getBorderRadiusClass(),\n                        getShadowClass(),\n                        getThemeClasses(),\n                        'flex-shrink-0 border border-gray-200 dark:border-gray-700 transition-all duration-200 cursor-pointer hover:scale-[1.02] overflow-hidden box-border',\n                        cardClassName\n                      )}\n                      style={{ width: cardWidth === 'sm' ? '305px' : cardWidth === 'lg' ? '385px' : '345px', minWidth: cardWidth === 'sm' ? '305px' : cardWidth === 'lg' ? '385px' : '345px', maxWidth: cardWidth === 'sm' ? '305px' : cardWidth === 'lg' ? '385px' : '345px' }}\n                      onClick={() => handleProductClick(item)}\n                    >\n                      <div className=\"p-3 w-full overflow-hidden box-border\">\n                        {/* Product Layout - Similar to brand header: circular image on left, name and description on right */}\n                        <div className=\"flex items-start gap-3 mb-3 w-full\">\n                          {/* Circular Product Image on left */}\n                          <div className=\"flex-shrink-0\">\n                            <div\n                              className=\"rounded-full overflow-hidden bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center\"\n                              style={{ aspectRatio: '1', width: '48px', height: '48px' }}\n                            >\n                              {productImageUrl ? (\n                                <img\n                                  src={productImageUrl}\n                                  alt={productName}\n                                  className=\"w-full h-full object-cover\"\n                                  style={{ aspectRatio: '1' }}\n                                  onError={(e) => {\n                                    // Fallback to placeholder icon if image fails to load\n                                    (e.target as HTMLImageElement).style.display = 'none';\n                                    const parent = (e.target as HTMLImageElement).parentElement;\n                                    if (parent) {\n                                      parent.innerHTML = `\n                                <svg class=\"w-6 h-6 text-gray-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n                                  <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\" />\n                                </svg>\n                              `;\n                                    }\n                                  }}\n                                />\n                              ) : (\n                                /* Placeholder icon when no product image */\n                                <svg className=\"w-6 h-6 text-gray-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n                                  <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\" />\n                                </svg>\n                              )}\n                            </div>\n                          </div>\n\n                          {/* Product name and description on right - two rows */}\n                          <div className=\"flex-1 min-w-0 max-w-full overflow-hidden\">\n                            {/* Top row - Product name */}\n                            {productName && (\n                              <h4 className=\"text-sm font-medium text-gray-900 dark:text-white mb-1 leading-tight break-words overflow-wrap-anywhere\">\n                                {productName}\n                              </h4>\n                            )}\n                            {/* Bottom row - Product description */}\n                            {productDisplayContent && (\n                              <p className=\"text-xs text-gray-600 dark:text-gray-400 break-words overflow-wrap-anywhere line-clamp-2\" title={productDisplayContent}>\n                                {productDisplayContent}\n                              </p>\n                            )}\n                          </div>\n                        </div>\n\n                        {/* Price, Discount, and CTA Button */}\n                        <div className=\"mt-3 flex items-center justify-between gap-2\">\n                          {/* Price and discount on left */}\n                          <div className=\"flex items-center gap-2\">\n                            {price && (\n                              <span className=\"text-sm font-semibold text-gray-900 dark:text-white\">\n                                {price}\n                              </span>\n                            )}\n                            {productDiscount && (\n                              <span className=\"text-xs text-red-600 dark:text-red-400 font-medium\">\n                                {productDiscount} OFF\n                              </span>\n                            )}\n                          </div>\n                          {/* CTA Button on right */}\n                          {ctaUrl && (\n                            <button\n                              onClick={(e) => {\n                                e.stopPropagation();\n                                handleProductClick(item);\n                              }}\n                              className=\"px-3 py-1.5 text-xs font-medium text-gray-100 bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 rounded-md transition-colors duration-200 whitespace-nowrap\"\n                            >\n                              {ctaLabel}\n                            </button>\n                          )}\n                        </div>\n                      </div>\n                    </div>\n                  </AdMeshLinkTracker>\n                );\n              })}\n            </div>\n          )}\n\n          {/* Scroll Indicators - only show when there are products */}\n          {displayItems.length > 0 && (\n            <>\n              <div className=\"absolute top-1/2 -left-2 transform -translate-y-1/2 bg-white dark:bg-gray-800 rounded-full shadow-lg p-1 opacity-0 group-hover:opacity-100 transition-opacity\">\n                <svg className=\"w-4 h-4 text-gray-600 dark:text-gray-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n                  <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M15 19l-7-7 7-7\" />\n                </svg>\n              </div>\n              <div className=\"absolute top-1/2 -right-2 transform -translate-y-1/2 bg-white dark:bg-gray-800 rounded-full shadow-lg p-1 opacity-0 group-hover:opacity-100 transition-opacity\">\n                <svg className=\"w-4 h-4 text-gray-600 dark:text-gray-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n                  <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n                </svg>\n              </div>\n            </>\n          )}\n        </div>\n\n        {/* Disclosure and Feedback */}\n        <div className=\"flex justify-between items-center mt-3 pt-2 border-t border-gray-200 dark:border-gray-700\">\n          <span className=\"text-xs text-gray-500 dark:text-gray-400\">\n            Sponsored\n          </span>\n          {onFeedback && (\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-xs text-gray-500 dark:text-gray-400 mr-1\">Was this helpful?</span>\n              <button\n                onClick={() => {\n                  if (feedbackSubmitted === null) {\n                    setFeedbackSubmitted('helpful');\n                    onFeedback(true, brand.recommendation_id || '');\n                  }\n                }}\n                disabled={feedbackSubmitted !== null}\n                className={classNames(\n                  'px-2 py-1 text-xs font-medium rounded transition-colors duration-200',\n                  feedbackSubmitted === 'helpful'\n                    ? 'bg-green-100 dark:bg-green-900 text-green-700 dark:text-green-300 cursor-default'\n                    : 'bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer',\n                  feedbackSubmitted !== null && feedbackSubmitted !== 'helpful' && 'opacity-50 cursor-not-allowed'\n                )}\n                title=\"Helpful\"\n              >\n                <span className=\"flex items-center gap-1\">\n                  <svg className=\"w-3 h-3\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n                    <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 00-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 01-2-2v-6a2 2 0 012-2h2.5\" />\n                  </svg>\n                  Helpful\n                </span>\n              </button>\n              <button\n                onClick={() => {\n                  if (feedbackSubmitted === null) {\n                    setFeedbackSubmitted('not-helpful');\n                    onFeedback(false, brand.recommendation_id || '');\n                  }\n                }}\n                disabled={feedbackSubmitted !== null}\n                className={classNames(\n                  'px-2 py-1 text-xs font-medium rounded transition-colors duration-200',\n                  feedbackSubmitted === 'not-helpful'\n                    ? 'bg-red-100 dark:bg-red-900 text-red-700 dark:text-red-300 cursor-default'\n                    : 'bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer',\n                  feedbackSubmitted !== null && feedbackSubmitted !== 'not-helpful' && 'opacity-50 cursor-not-allowed'\n                )}\n                title=\"Not helpful\"\n              >\n                <span className=\"flex items-center gap-1\">\n                  <svg className=\"w-3 h-3\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n                    <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M10 14H5.236a2 2 0 01-1.789-2.894l3.5-7A2 2 0 018.736 3h4.018a2 2 0 01.485.06l3.76.94m-7 10v5a2 2 0 002 2h.096c.5 0 .905-.405.905-.904 0-.715.211-1.413.608-2.008L17 13V4a2 2 0 00-2-2h-1.528c-.163 0-.326.02-.485.06L9 4m7 10H9m0 0H5m4 0v5a2 2 0 002 2h2M9 9h.01\" />\n                  </svg>\n                  Not helpful\n                </span>\n              </button>\n            </div>\n          )}\n        </div>\n      </div>\n\n      {/* Custom scrollbar styles */}\n      <style dangerouslySetInnerHTML={{\n        __html: `\n          .scrollbar-hide {\n            -ms-overflow-style: none;\n            scrollbar-width: none;\n          }\n          .scrollbar-hide::-webkit-scrollbar {\n            display: none;\n          }\n          .line-clamp-2 {\n            display: -webkit-box;\n            -webkit-line-clamp: 2;\n            -webkit-box-orient: vertical;\n            overflow: hidden;\n          }\n        `\n      }} />\n    </AdMeshViewabilityTracker>\n  );\n};\n\nexport default AdMeshEcommerceCards;\n","import React from 'react';\nimport { logger } from '../utils/logger';\nimport type { AdMeshLayoutProps, AdMeshRecommendation, AdMeshTheme } from '../types/index';\nimport { AdMeshTailAd } from './AdMeshTailAd';\nimport { AdMeshBridgeFormat } from './AdMeshBridgeFormat';\nimport { AdMeshEcommerceCards } from './AdMeshEcommerceCards';\n\nexport const AdMeshLayout: React.FC<AdMeshLayoutProps> = ({\n  // New props (finalized minimal schema)\n  recommendations,\n  summaryText,\n\n  // Styling\n  theme,\n  className,\n  style,\n\n  // Behavior\n  onLinkClick,\n  onPasteToInput,\n\n  // Exposure tracking\n  sessionId,\n\n  // Legacy props (deprecated)\n  response\n}) => {\n  // Support both new and legacy props for backward compatibility\n  const recs = recommendations || response?.recommendations || [];\n  let summary = summaryText || response?.tail_summary;\n\n  // Filter out any null/undefined/invalid recommendations\n  const validRecs = recs.filter(rec => rec && typeof rec === 'object' && rec.recommendation_id);\n\n  // Validate that valid recommendations are provided\n  if (!validRecs || validRecs.length === 0) {\n    logger.log('[AdMeshLayout] Empty or invalid recommendations array - not rendering anything');\n    return null;\n  }\n\n  // If no summary provided, try to get it from first recommendation's creative_input\n  if (!summary && validRecs.length > 0 && validRecs[0]?.creative_input) {\n    const creativeInput = validRecs[0].creative_input;\n    summary = creativeInput.long_description || \n              creativeInput.context_snippet || \n              creativeInput.short_description || \n              undefined;\n  }\n\n  logger.log(`[AdMeshLayout] Rendering with ${validRecs.length} valid recommendations`);\n\n  // Render based on layout type (default to tail)\n  const renderContent = () => {\n    if (validRecs.length > 0) {\n      const firstRec = validRecs[0];\n      const creativeInput = firstRec?.creative_input || {};\n      \n      // Use ONLY preferred_format (single authoritative field from backend)\n      const preferredFormat = (firstRec as any)?.preferred_format || (creativeInput as any)?.preferred_format;\n      \n      logger.log('[AdMeshLayout] 🔍 Checking format:', {\n        preferredFormat,\n        creativeInputKeys: Object.keys(creativeInput),\n        recommendationKeys: Object.keys(firstRec || {})\n      });\n      \n      // Check for product_card format first (before bridge)\n      if (preferredFormat === 'product_card') {\n        // Extract products (check top-level first, then creative_input)\n        const products = (firstRec as any)?.products || (creativeInput as any)?.products || [];\n        if (products && products.length > 0) {\n          logger.log(`[AdMeshLayout] 🛍️ Rendering product_card format with ${products.length} products`);\n          return (\n            <AdMeshEcommerceCards\n              brand={firstRec}\n              theme={theme}\n              sessionId={sessionId}\n            />\n          );\n        } else {\n          logger.warn('[AdMeshLayout] product_card format detected but no products array, falling back to tail');\n        }\n      }\n      \n      // Check for bridge format\n      // Priority: 1) bridge_content in creative_input, 2) preferred_format field\n      const hasBridgePrompt = !!(creativeInput as any).bridge_prompt || !!creativeInput.bridge_content;\n      const hasBridgeFormat = preferredFormat === 'bridge';\n      \n      if (hasBridgePrompt || hasBridgeFormat) {\n        logger.log('[AdMeshLayout] 🎯 ✅ Rendering bridge format');\n        return (\n          <AdMeshBridgeFormat\n            recommendation={firstRec}\n            theme={theme}\n            sessionId={sessionId}\n            onLinkClick={onLinkClick}\n            onPasteToInput={onPasteToInput}\n          />\n        );\n      } else {\n        logger.log('[AdMeshLayout] ⚠️ Bridge format NOT detected, falling back to other formats');\n      }\n    }\n\n    // Show summary if available (tail format)\n    if (summary) {\n      return (\n        <AdMeshTailAd\n          summaryText={summary}\n          recommendations={validRecs}\n          theme={theme}\n          onLinkClick={onLinkClick}\n          sessionId={sessionId}\n        />\n      );\n    }\n    // Fallback: if no summary and no valid recommendation, don't render anything\n    return null;\n  };\n\n  return (\n    <div\n      className={`admesh-layout ${className}`}\n      style={{\n        fontFamily: theme?.fontFamily || '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n        ...style\n      }}\n    >\n      {renderContent()}\n    </div>\n  );\n};\n\nexport default AdMeshLayout;\n","'use client';\n\nimport React from 'react';\nimport { logger } from '../utils/logger';\nimport type { AdMeshRecommendation, AdMeshTheme } from '../types/index';\nimport { AdMeshSDK } from '../sdk/AdMeshSDK';\nimport { AdMeshViewabilityTracker } from './AdMeshViewabilityTracker';\n\nexport interface AdMeshFollowupProps {\n  recommendation: AdMeshRecommendation;\n  theme?: AdMeshTheme;\n  sdk: AdMeshSDK;\n  sessionId: string;\n  onExecuteQuery?: (query: string) => void | Promise<void>;\n}\n\nconst PlusIcon = ({ className, size = 20 }: { className?: string; size?: number }) => (\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    width={size}\n    height={size}\n    viewBox=\"0 0 24 24\"\n    fill=\"none\"\n    stroke=\"currentColor\"\n    strokeWidth=\"2\"\n    strokeLinecap=\"round\"\n    strokeLinejoin=\"round\"\n    className={className}\n  >\n    <path d=\"M5 12h14\" />\n    <path d=\"M12 5v14\" />\n  </svg>\n);\n\n/**\n * AdMeshFollowup - Sponsored Follow-up Component\n * \n * Displays sponsored follow-up suggestions as optional fields on any recommendation.\n * Follow-ups use the same recommendation_id as the primary ad and are rendered separately\n * in a followups_container_id. This component handles all exposure and engagement tracking\n * internally - platforms only need to provide an onExecuteQuery hook for query execution.\n * \n * @example\n * ```tsx\n * <AdMeshFollowup\n *   recommendation={recommendation}\n *   sdk={sdk}\n *   sessionId={sessionId}\n *   theme={theme}\n *   onExecuteQuery={(query) => {\n *     // Platform's query execution logic\n *     executeQuery(query);\n *   }}\n * />\n * ```\n */\nexport const AdMeshFollowup: React.FC<AdMeshFollowupProps> = ({\n  recommendation,\n  theme,\n  sdk,\n  sessionId,\n  onExecuteQuery,\n}) => {\n  const followupQuery = recommendation.followup_query;\n  const followupEngagementUrl = recommendation.followup_engagement_url;\n  const followupExposureUrl = recommendation.followup_exposure_url; // Dedicated followup exposure URL\n  const recommendationId = recommendation.recommendation_id;\n\n  // Validate required fields\n  if (!followupQuery || !followupEngagementUrl || !followupExposureUrl) {\n    logger.log('[AdMeshFollowup] Missing followup_query, followup_engagement_url, or followup_exposure_url - not rendering');\n    return null;\n  }\n\n  // Handle follow-up click/selection\n  const handleFollowupClick = async () => {\n    try {\n      // Fire engagement tracking (SDK handles this automatically)\n      if (followupEngagementUrl && recommendationId) {\n        logger.log('[AdMeshFollowup] 🎯 Firing follow-up engagement tracking');\n        await sdk.fireFollowupEngagement(followupEngagementUrl, recommendationId, sessionId);\n      }\n\n      // Execute query via platform hook\n      if (onExecuteQuery && followupQuery) {\n        logger.log(`[AdMeshFollowup] 🔍 Executing query: ${followupQuery}`);\n        await onExecuteQuery(followupQuery);\n      } else {\n        logger.warn('[AdMeshFollowup] ⚠️ onExecuteQuery not provided - cannot execute query');\n      }\n    } catch (error) {\n      logger.error('[AdMeshFollowup] ❌ Error handling follow-up click:', error);\n    }\n  };\n\n  // Get theme colors\n  const mode = theme?.mode || 'light';\n\n  // Platform-native styling (matching Perplexica's \"Related\" section)\n  // We use inline styles that can be overridden, but default to blending in\n\n  return (\n    <AdMeshViewabilityTracker\n      productId={recommendation.product_id || ''}\n      recommendationId={recommendationId || ''}\n      exposureUrl={followupExposureUrl}\n      sessionId={sessionId}\n      className=\"admesh-followup-container\"\n      style={{\n        width: '100%',\n      }}\n    >\n      <div className=\"flex flex-col space-y-3 text-sm admesh-followup-wrapper\">\n        {/* Divider matching platform style */}\n        <div className=\"h-px w-full bg-[#E5E5E5] dark:bg-[#262626] admesh-divider\" />\n\n        <div\n          onClick={handleFollowupClick}\n          className=\"cursor-pointer flex flex-row justify-between font-medium space-x-2 items-center group\"\n          role=\"button\"\n          tabIndex={0}\n          onKeyDown={(e) => {\n            if (e.key === 'Enter' || e.key === ' ') {\n              handleFollowupClick();\n            }\n          }}\n          aria-label={`Sponsored follow-up: ${followupQuery}`}\n        >\n          <p className=\"transition duration-200 text-[#000] dark:text-[#FFF] hover:text-[#24A0ED] admesh-followup-text\">\n            {followupQuery}\n          </p>\n          <div className=\"flex flex-row items-center space-x-2\">\n            <span className=\"text-xs text-gray-500 dark:text-gray-400 italic admesh-ad-label\">\n              Ad\n            </span>\n            <PlusIcon\n              size={20}\n              className=\"text-[#24A0ED] flex-shrink-0 admesh-plus-icon\"\n            />\n          </div>\n        </div>\n      </div>\n    </AdMeshViewabilityTracker>\n  );\n};\n","/**\n * AdMesh Tracker\n *\n * Handles MRC-compliant exposure tracking for recommendations\n *\n * MRC Viewability Standards:\n * - Display Ads: 50% of pixels visible for at least 1 continuous second\n * - Large Display Ads (>242,500 pixels): 30% of pixels visible for at least 1 continuous second\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface TrackerConfig {\n  apiKey: string;\n  debug?: boolean;\n}\n\n/**\n * MRC Viewability threshold configuration\n */\ninterface MRCThreshold {\n  visibilityPercentage: number;  // 50% for standard ads, 30% for large ads\n  minimumDurationMs: number;     // 1000ms (1 second)\n}\n\nexport class AdMeshTracker {\n  private firedExposures: Set<string> = new Set();\n  private debug: boolean = false;\n  private mrcThreshold: MRCThreshold = {\n    visibilityPercentage: 50,\n    minimumDurationMs: 1000\n  };\n\n  constructor(config: TrackerConfig) {\n    this.debug = config.debug || false;\n  }\n\n  /**\n   * Fire an exposure tracking pixel with MRC viewability compliance\n   *\n   * This method should be called when an ad element becomes viewable according to MRC standards.\n   * The caller is responsible for ensuring the ad meets the MRC threshold before calling this method.\n   *\n   * Prevents duplicate firing for the same ad in the same session.\n   *\n   * @param exposureUrl - The tracking pixel URL to fire\n   * @param recommendationId - The recommendation ID for deduplication\n   * @param sessionId - The session ID for deduplication\n   */\n  fireExposure(exposureUrl: string, recommendationId: string, sessionId: string): void {\n    const key = `${sessionId}_${recommendationId}`;\n\n    // Prevent duplicate exposures\n    if (this.firedExposures.has(key)) {\n      if (this.debug) {\n        logger.log('[Tracker] Exposure already fired');\n      }\n      return;\n    }\n\n    this.firedExposures.add(key);\n\n    try {\n      // Fire the exposure pixel\n      // Note: The caller should ensure MRC compliance before calling this method\n      fetch(exposureUrl, { method: 'GET', keepalive: true }).catch(() => {\n        if (this.debug) {\n          logger.warn('[Tracker] Failed to fire exposure');\n        }\n      });\n\n      if (this.debug) {\n        logger.log('[Tracker] Fired MRC-compliant exposure');\n      }\n    } catch (error) {\n      if (this.debug) {\n        logger.error('[Tracker] Error firing exposure');\n      }\n    }\n  }\n\n  /**\n   * Fire an exposure pixel with MRC viewability verification\n   *\n   * This method monitors an element for MRC viewability compliance before firing the exposure pixel.\n   * It uses Intersection Observer API to track visibility and ensures the ad meets the threshold\n   * (50% visible for 1 continuous second) before firing.\n   *\n   * @param exposureUrl - The tracking pixel URL to fire\n   * @param recommendationId - The recommendation ID for deduplication\n   * @param sessionId - The session ID for deduplication\n   * @param element - The DOM element to monitor for viewability\n   * @returns Promise that resolves when exposure is fired or timeout occurs\n   */\n  async fireExposureWithMRCCompliance(\n    exposureUrl: string,\n    recommendationId: string,\n    sessionId: string,\n    element: HTMLElement\n  ): Promise<void> {\n    const key = `${sessionId}_${recommendationId}`;\n\n    // Prevent duplicate exposures\n      if (this.firedExposures.has(key)) {\n        if (this.debug) {\n          logger.log('[Tracker] MRC exposure already fired');\n        }\n        return;\n      }\n\n    return new Promise((resolve) => {\n      let viewableStartTime: number | null = null;\n      let timeoutId: NodeJS.Timeout | null = null;\n\n      const observer = new IntersectionObserver(\n        (entries) => {\n          entries.forEach((entry) => {\n            const visibilityPercentage = (entry.intersectionRatio * 100);\n\n            if (visibilityPercentage >= this.mrcThreshold.visibilityPercentage) {\n              // Ad is visible enough\n              if (viewableStartTime === null) {\n                // Start tracking viewable duration\n                viewableStartTime = Date.now();\n\n                if (this.debug) {\n                  logger.log('[Tracker] Ad reached MRC visibility threshold');\n                }\n\n                // Set timeout to fire exposure after minimum duration\n                timeoutId = setTimeout(() => {\n                  // Fire the exposure pixel\n                  this.fireExposure(exposureUrl, recommendationId, sessionId);\n                  observer.disconnect();\n                  resolve();\n                }, this.mrcThreshold.minimumDurationMs);\n              }\n            } else {\n              // Ad visibility dropped below threshold\n              if (viewableStartTime !== null) {\n                // Reset tracking\n                if (timeoutId) {\n                  clearTimeout(timeoutId);\n                  timeoutId = null;\n                }\n                viewableStartTime = null;\n\n                if (this.debug) {\n                  logger.log('[Tracker] Ad visibility dropped below MRC threshold');\n                }\n              }\n            }\n          });\n        },\n        {\n          threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],\n          rootMargin: '0px'\n        }\n      );\n\n      observer.observe(element);\n\n      // Cleanup on unmount or after reasonable timeout\n      const maxWaitTime = 30000; // 30 seconds max wait\n      const cleanupTimeout = setTimeout(() => {\n        observer.disconnect();\n        if (timeoutId) {\n          clearTimeout(timeoutId);\n        }\n        resolve();\n      }, maxWaitTime);\n\n      // Store cleanup function for manual cleanup if needed\n      (element as any).__admeshTrackerCleanup = () => {\n        observer.disconnect();\n        if (timeoutId) {\n          clearTimeout(timeoutId);\n        }\n        clearTimeout(cleanupTimeout);\n      };\n    });\n  }\n\n  /**\n   * Clear fired exposures (useful for testing or session reset)\n   */\n  clearFiredExposures(): void {\n    this.firedExposures.clear();\n  }\n\n  /**\n   * Get MRC threshold configuration\n   */\n  getMRCThreshold(): MRCThreshold {\n    return { ...this.mrcThreshold };\n  }\n\n  /**\n   * Set custom MRC threshold (for testing or special cases)\n   */\n  setMRCThreshold(threshold: Partial<MRCThreshold>): void {\n    this.mrcThreshold = {\n      ...this.mrcThreshold,\n      ...threshold\n    };\n  }\n\n  /**\n   * Fire exposure pixel for sponsored followup\n   * Uses same logic as regular exposure tracking\n   * \n   * @param exposureUrl - The tracking pixel URL to fire (can use regular exposure_url)\n   * @param recommendationId - The recommendation ID for deduplication\n   * @param sessionId - The session ID for deduplication\n   */\n  fireFollowupExposure(\n    exposureUrl: string,\n    recommendationId: string,\n    sessionId: string\n  ): void {\n    // Reuse existing fireExposure() method\n    this.fireExposure(exposureUrl, recommendationId, sessionId);\n  }\n\n  /**\n   * Fire engagement tracking for sponsored followup\n   * \n   * @param engagementUrl - The engagement tracking URL to fire\n   * @param recommendationId - The recommendation ID\n   * @param sessionId - The session ID (sent in POST body for analytics joining)\n   * @returns Promise that resolves when engagement is fired\n   */\n  fireFollowupEngagement(\n    engagementUrl: string,\n    recommendationId: string,\n    sessionId: string\n  ): Promise<void> {\n    // Use fetch with keepalive and POST method\n    // Always resolve the promise even on error to prevent unhandled rejections\n    return fetch(engagementUrl, {\n      method: 'POST',\n      keepalive: true,\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({ session_id: sessionId })\n    }).catch((error) => {\n      // Log error silently (only in debug mode) - network errors are expected and shouldn't break the flow\n      if (this.debug) {\n        logger.warn('[Tracker] Failed to fire followup engagement (non-critical):', error);\n      }\n      // Return undefined to resolve the promise successfully\n      // This prevents the error from propagating to callers\n      return undefined;\n    }).then(() => {\n      // Ensure promise always resolves with void (no return value)\n      // This makes the return type consistent: Promise<void>\n    });\n  }\n}\n","'use client';\n\nimport React, { useEffect, useRef, useState } from 'react';\nimport { logger } from '../utils/logger';\nimport { AdMeshSDK } from '../sdk/AdMeshSDK';\nimport { AdMeshContext, type AdMeshContextValue } from './AdMeshContext';\nimport type { AdMeshTheme } from '../types/index';\n\nexport interface AdMeshProviderProps {\n  /** AdMesh API key (required) */\n  apiKey: string;\n\n  /** Session ID (required) */\n  sessionId: string;\n\n  /** Optional theme configuration */\n  theme?: AdMeshTheme;\n\n  /** Optional API base URL (defaults to production) */\n  apiBaseUrl?: string;\n\n  /** Optional user language in BCP 47 format (e.g., \"en-US\") */\n  language?: string;\n\n  /** Optional user country code in ISO 3166-1 alpha-2 format (e.g., \"US\") */\n  geo_country?: string;\n\n  /** Optional anonymous hashed user ID */\n  userId?: string;\n\n  /** Optional AI model identifier (e.g., \"gpt-4o\") - used for producer.software_version in UCP PlatformRequest */\n  model?: string;\n\n  /** Optional conversation history - used for extensions.aip.messages in UCP PlatformRequest */\n  messages?: Array<{ role: string; content: string; id?: string }>;\n\n  /** Child components */\n  children: React.ReactNode;\n}\n\n/**\n * AdMeshProvider - Simplified SDK integration for React applications\n *\n * Handles:\n * - SDK initialization and lifecycle management\n * - Message deduplication tracking\n * - Session and message ID management\n * - Error handling and logging\n *\n * @example\n * ```tsx\n * <AdMeshProvider\n *   apiKey={process.env.NEXT_PUBLIC_ADMESH_API_KEY}\n *   sessionId={sessionId}\n * >\n *   <Chat messages={messages} />\n * </AdMeshProvider>\n * ```\n */\nexport const AdMeshProvider: React.FC<AdMeshProviderProps> = ({\n  apiKey,\n  sessionId,\n  theme,\n  apiBaseUrl,\n  language,\n  geo_country,\n  userId,\n  model,\n  messages,\n  children,\n}) => {\n  const sdkRef = useRef<AdMeshSDK | null>(null);\n  const [processedMessageIds, setProcessedMessageIds] = useState<Set<string>>(\n    new Set()\n  );\n\n  // CRITICAL: Validate that sessionId is provided by platform\n  // The SDK/provider NEVER generates sessionId automatically\n  useEffect(() => {\n    if (!sessionId || sessionId.trim() === '') {\n      logger.error('[AdMeshProvider] ❌ sessionId is required and must be provided by the platform. The SDK never generates sessionId automatically.');\n      return;\n    }\n  }, [sessionId]);\n\n  // Initialize SDK once on mount\n  useEffect(() => {\n    if (!apiKey) {\n      logger.warn('[AdMeshProvider] ⚠️ AdMesh API key not configured');\n      return;\n    }\n\n    if (!sessionId || sessionId.trim() === '') {\n      logger.error('[AdMeshProvider] ❌ Cannot initialize SDK: sessionId is required and must be provided by the platform');\n      return;\n    }\n\n    try {\n      sdkRef.current = new AdMeshSDK({\n        apiKey,\n        theme,\n        apiBaseUrl,\n      });\n      logger.log('[AdMeshProvider] ✅ AdMesh SDK initialized');\n      if (apiBaseUrl) {\n        logger.log('[AdMeshProvider] 📍 Using custom API base URL');\n      }\n    } catch (error) {\n      logger.error('[AdMeshProvider] ❌ Failed to initialize AdMesh SDK');\n    }\n\n    // Cleanup on unmount\n    return () => {\n      logger.log('[AdMeshProvider] 🧹 Provider unmounted');\n    };\n  }, [apiKey, theme, apiBaseUrl]);\n\n  // Create context value\n  const contextValue: AdMeshContextValue = {\n    sdk: sdkRef.current,\n    apiKey,\n    sessionId,\n    theme,\n    language,\n    geo_country,\n    userId,\n    model,\n    messages,\n    processedMessageIds,\n    \n    markMessageAsProcessed: (messageId: string) => {\n      setProcessedMessageIds((prev) => {\n        const updated = new Set(prev);\n        updated.add(messageId);\n        return updated;\n      });\n    },\n    \n    isMessageProcessed: (messageId: string) => {\n      return processedMessageIds.has(messageId);\n    },\n  };\n\n  return (\n    <AdMeshContext.Provider value={contextValue}>\n      {children}\n    </AdMeshContext.Provider>\n  );\n};\n\nexport default AdMeshProvider;\n","/**\n * AdMesh Renderer\n * \n * Handles rendering of recommendations in the specified container\n */\n\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport type { AgentRecommendationResponse, AdMeshTheme, AdMeshRecommendation } from '../types/index';\nimport { AdMeshLayout } from '../components/AdMeshLayout';\nimport { AdMeshFollowup } from '../components/AdMeshFollowup';\nimport { AdMeshTracker } from './AdMeshTracker';\nimport { AdMeshProvider } from '../context/AdMeshProvider';\nimport { logger } from '../utils/logger';\n\nexport interface RenderOptions {\n  containerId: string;\n  followups_container_id?: string;\n  response: AgentRecommendationResponse;\n  theme?: AdMeshTheme;\n  tracker: AdMeshTracker;\n  sessionId: string;\n  apiKey: string;\n  apiBaseUrl?: string;\n  language?: string;\n  geo_country?: string;\n  userId?: string;\n  model?: string;\n  messages?: Array<{ role: string; content: string; id?: string }>;\n  onPasteToInput?: (content: string) => void;\n  onExecuteQuery?: (query: string) => void | Promise<void>;\n}\n\nexport class AdMeshRenderer {\n  private roots: Map<string, ReactDOM.Root> = new Map();\n\n  constructor() {\n    // No configuration needed\n  }\n\n  /**\n   * Render recommendations in the specified container\n   */\n  async render(options: RenderOptions): Promise<void> {\n    try {\n      logger.log('[AdMeshRenderer] 🎨 Attempting to render recommendations');\n\n      // Check if we have any recommendations to render\n      const recommendations = options.response.recommendations || [];\n      if (recommendations.length === 0) {\n        logger.log('[AdMeshRenderer] ⚠️ No recommendations to render - skipping render to avoid occupying space');\n        return;\n      }\n\n      const container = document.getElementById(options.containerId);\n\n      if (!container) {\n        logger.error('[AdMeshRenderer] ❌ Container not found');\n        throw new Error(`Container with ID \"${options.containerId}\" not found`);\n      }\n\n      logger.log('[AdMeshRenderer] ✅ Container ready');\n\n      // Clean up existing root if any\n      const existingRoot = this.roots.get(options.containerId);\n      if (existingRoot) {\n        logger.log('[AdMeshRenderer] 🧹 Cleaning up existing root');\n        existingRoot.unmount();\n        this.roots.delete(options.containerId);\n      }\n\n      // Clear the container's innerHTML to ensure React can create a fresh root\n      container.innerHTML = '';\n\n      // Create a new root\n      const root = ReactDOM.createRoot(container);\n\n      // Render the layout component\n      // Use tail_summary from first recommendation if available\n      const tailSummary = recommendations[0]?.tail_summary || '';\n\n      logger.log('[AdMeshRenderer] 📊 Rendering recommendations');\n\n      // Get onPasteToInput from options or window object (for backward compatibility)\n      const onPasteToInput = options.onPasteToInput || \n        (typeof window !== 'undefined' ? (window as any).__admesh_onPasteToInput : undefined);\n\n      // Wrap components in AdMeshProvider to provide context for hooks like useAdMesh()\n      root.render(\n        <AdMeshProvider\n          apiKey={options.apiKey}\n          sessionId={options.sessionId}\n          theme={options.theme}\n          apiBaseUrl={options.apiBaseUrl}\n          language={options.language}\n          geo_country={options.geo_country}\n          userId={options.userId}\n          model={options.model}\n          messages={options.messages}\n        >\n          <AdMeshLayout\n            recommendations={recommendations}\n            summaryText={tailSummary}\n            theme={options.theme}\n            sessionId={options.sessionId}\n            onPasteToInput={onPasteToInput}\n          />\n        </AdMeshProvider>\n      );\n\n      // Show the container now that content is rendered (prevents empty space when no ads)\n      container.style.display = 'block';\n\n      logger.log('[AdMeshRenderer] ✅ Recommendations rendered successfully');\n\n      // Store root for cleanup\n      this.roots.set(options.containerId, root);\n\n      // After rendering primary format, check for follow-ups\n      if (options.followups_container_id) {\n        const recommendation = recommendations[0];\n        if (recommendation?.followup_query && recommendation?.followup_engagement_url) {\n          // Render follow-up in followups_container_id\n          await this.renderFollowup({\n            containerId: options.followups_container_id,\n            recommendation,\n            theme: options.theme,\n            tracker: options.tracker,\n            sessionId: options.sessionId,\n            apiKey: options.apiKey,\n            apiBaseUrl: options.apiBaseUrl,\n            onExecuteQuery: options.onExecuteQuery\n          });\n        }\n      }\n    } catch (error) {\n      logger.error('[AdMeshRenderer] ❌ Error rendering recommendations');\n      throw error;\n    }\n  }\n\n  /**\n   * Render follow-up in the specified container\n   */\n  private async renderFollowup(options: {\n    containerId: string;\n    recommendation: AdMeshRecommendation;\n    theme?: AdMeshTheme;\n    tracker: AdMeshTracker;\n    sessionId: string;\n    apiKey: string;\n    apiBaseUrl?: string;\n    onExecuteQuery?: (query: string) => void | Promise<void>;\n  }): Promise<void> {\n    try {\n      logger.log(`[AdMeshRenderer] 🎯 Rendering follow-up in container: ${options.containerId}`);\n\n      const container = document.getElementById(options.containerId);\n      if (!container) {\n        logger.warn(`[AdMeshRenderer] ⚠️ Followups container not found: ${options.containerId}`);\n        return;\n      }\n\n      // Clean up existing root if any\n      const existingRoot = this.roots.get(options.containerId);\n      if (existingRoot) {\n        logger.log('[AdMeshRenderer] 🧹 Cleaning up existing followup root');\n        existingRoot.unmount();\n        this.roots.delete(options.containerId);\n      }\n\n      // Clear container\n      container.innerHTML = '';\n\n      // Create a new root\n      const root = ReactDOM.createRoot(container);\n\n      // Wrap in AdMeshProvider for context (if followup components need it)\n      // Note: AdMeshFollowup might not need context, but wrapping for consistency\n      root.render(\n        <AdMeshProvider\n          apiKey={options.apiKey}\n          sessionId={options.sessionId}\n          theme={options.theme}\n          apiBaseUrl={options.apiBaseUrl}\n        >\n          <AdMeshFollowup\n            recommendation={options.recommendation}\n            theme={options.theme}\n            tracker={options.tracker}\n            sessionId={options.sessionId}\n            onExecuteQuery={options.onExecuteQuery}\n          />\n        </AdMeshProvider>\n      );\n\n      // Show the container\n      container.style.display = 'block';\n\n      logger.log('[AdMeshRenderer] ✅ Follow-up rendered successfully');\n\n      // Store root for cleanup\n      this.roots.set(options.containerId, root);\n    } catch (error) {\n      logger.error('[AdMeshRenderer] ❌ Error rendering follow-up');\n      // Don't throw - follow-up rendering failure shouldn't break primary ad\n    }\n  }\n\n  /**\n   * Unmount a rendered component\n   */\n  unmount(containerId: string): void {\n    const root = this.roots.get(containerId);\n    if (root) {\n      root.unmount();\n      this.roots.delete(containerId);\n      \n      // Hide the container again to prevent empty space\n      const container = document.getElementById(containerId);\n      if (container) {\n        container.style.display = 'none';\n      }\n    }\n  }\n\n  /**\n   * Unmount all rendered components\n   */\n  unmountAll(): void {\n    for (const [, root] of this.roots.entries()) {\n      root.unmount();\n    }\n    this.roots.clear();\n  }\n}\n","/**\n * AdMesh UI SDK - Zero-Code Integration\n * \n * Provides a simple, zero-code integration experience for platforms.\n * Handles all recommendation fetching, rendering, and tracking automatically.\n */\n\nimport type { AdMeshTheme, AgentRecommendationResponse, AdMeshRecommendation, PlatformRequest, AIPContextResponse } from '../types/index';\nimport { AdMeshRenderer } from './AdMeshRenderer';\nimport { AdMeshTracker } from './AdMeshTracker';\nimport { logger } from '../utils/logger';\n\nexport interface AdMeshSDKConfig {\n  apiKey: string;\n  theme?: AdMeshTheme;\n  apiBaseUrl?: string;\n}\n\nexport interface ShowRecommendationsOptions {\n  query: string;\n  containerId: string;\n  theme?: AdMeshTheme;\n\n  // Optional follow-ups container (SDK will render follow-ups here if provided and followup_query is present)\n  followups_container_id?: string;\n\n  // Session tracking (required)\n  session_id: string;\n\n  // Message tracking (required)\n  // messageId MUST be provided by the platform - SDK never generates it\n  messageId: string;\n\n  // Platform information\n  // platformId is now extracted from API key by the backend\n  platformSurface?: string;\n  model?: string;\n  messages?: Array<{ role: string; content: string }>;\n  locale?: string;\n  geo?: string;\n  userId?: string;\n  // latency_budget_ms removed - now fetched from agent profile by backend\n  // allowed_formats removed - backend fetches from platform config (configured during onboarding)\n  \n  /** Callback to paste content to input field (for bridge format CTA) */\n  onPasteToInput?: (content: string) => void;\n  \n  /** Callback to execute query when follow-up is selected (required for follow-up functionality) */\n  onExecuteQuery?: (query: string) => void | Promise<void>;\n}\n\n/**\n * Main AdMesh SDK class for zero-code integration\n *\n * The SDK is stateless regarding session management. Developers must provide\n * session_id when calling showRecommendations().\n *\n * @example\n * ```typescript\n * import { AdMeshSDK } from '@admesh/ui-sdk';\n *\n * const admesh = new AdMeshSDK({ apiKey: 'your-api-key' });\n *\n * // Generate session ID on your platform\n * const sessionId = AdMeshSDK.createSession();\n *\n * await admesh.showRecommendations({\n *   query: 'best CRM for small business',\n *   containerId: 'admesh-recommendations',\n *   session_id: sessionId\n * });\n * ```\n */\nexport class AdMeshSDK {\n  private config: AdMeshSDKConfig;\n  private apiBaseUrl: string;\n\n  // OPTIMIZATION: Lazy-initialized managers (only created when needed)\n  private renderer: AdMeshRenderer | null = null;\n  private tracker: AdMeshTracker | null = null;\n\n  constructor(config: AdMeshSDKConfig) {\n    if (!config.apiKey) {\n      throw new Error('AdMeshSDK: apiKey is required');\n    }\n\n    this.config = {\n      apiKey: config.apiKey,\n      theme: config.theme,\n      apiBaseUrl: config.apiBaseUrl\n    };\n\n    // Set API base URL with priority: config > environment variable > production default\n    this.apiBaseUrl = config.apiBaseUrl ||\n      (typeof window !== 'undefined' && (window as any).__ADMESH_API_BASE_URL__) ||\n      'https://api.useadmesh.com';\n  }\n\n  /**\n   * Get the API base URL\n   * @returns The API base URL being used by the SDK\n   */\n  getApiBaseUrl(): string {\n    return this.apiBaseUrl;\n  }\n\n  /**\n   * PLATFORM UTILITY: Generate a unique session ID for tracking recommendations\n   * \n   * IMPORTANT: This is a utility method for PLATFORMS to use. The SDK itself\n   * NEVER calls this method automatically. Platforms must:\n   * 1. Call this method (or generate their own sessionId)\n   * 2. Store the sessionId in their own storage\n   * 3. Pass sessionId to AdMeshProvider and SDK methods\n   * \n   * The SDK will throw an error if sessionId is not provided - it will never\n   * auto-generate one.\n   *\n   * @returns A unique session ID (platform must store and manage this)\n   */\n  static createSession(): string {\n    const timestamp = Date.now();\n    const random = Math.random().toString(36).substring(2, 15);\n    return `session_${timestamp}_${random}`;\n  }\n\n  /**\n   * PLATFORM UTILITY: Generate a unique message ID for tracking recommendations per message\n   * \n   * IMPORTANT: This is a utility method for PLATFORMS to use. The SDK itself\n   * NEVER calls this method automatically. Platforms must:\n   * 1. Call this method (or generate their own messageId) for each user message\n   * 2. Pass messageId to SDK methods (showRecommendations, fetchRecommendationFromAIPContext)\n   * \n   * The SDK will throw an error if messageId is not provided - it will never\n   * auto-generate one.\n   *\n   * @param sessionId Optional session ID to include in the message ID\n   * @returns A unique message ID (platform must provide this to SDK methods)\n   */\n  static createMessageId(sessionId?: string): string {\n    const timestamp = Date.now();\n    const random = Math.random().toString(36).substring(2, 9);\n    if (sessionId) {\n      return `msg_${sessionId}_${timestamp}_${random}`;\n    }\n    return `msg_${timestamp}_${random}`;\n  }\n\n\n  /**\n   * OPTIMIZATION: Lazy initialize renderer on first use\n   */\n  private getRenderer(): AdMeshRenderer {\n    if (!this.renderer) {\n      this.renderer = new AdMeshRenderer();\n    }\n    return this.renderer;\n  }\n\n  /**\n   * OPTIMIZATION: Lazy initialize tracker on first use\n   */\n  private getTracker(): AdMeshTracker {\n    if (!this.tracker) {\n      this.tracker = new AdMeshTracker({\n        apiKey: this.config.apiKey\n      });\n    }\n    return this.tracker;\n  }\n\n\n\n\n  /**\n   * Fetch and render recommendations automatically using /aip/context endpoint\n   *\n   * IMPORTANT: Both session_id and messageId MUST be provided by the platform.\n   * The SDK NEVER generates these automatically. Use AdMeshSDK.createSession()\n   * and AdMeshSDK.createMessageId() on your platform, or generate your own IDs.\n   */\n  async showRecommendations(options: ShowRecommendationsOptions): Promise<void> {\n    try {\n      // CRITICAL: session_id MUST be provided by platform - SDK never generates it\n      if (!options.session_id || options.session_id.trim() === '') {\n        throw new Error('session_id is required and must be provided by the platform. The SDK never generates sessionId automatically.');\n      }\n      \n      // CRITICAL: messageId MUST be provided by the platform - SDK never generates it\n      if (!options.messageId || options.messageId.trim() === '') {\n        throw new Error('messageId is required and must be provided by the platform. The SDK never generates messageId automatically.');\n      }\n      \n      // Fetch recommendation from /aip/context endpoint\n      // platformId is extracted from API key by the backend\n      const aipResponse = await this.fetchRecommendationFromAIPContext({\n        query: options.query,\n        sessionId: options.session_id,\n        messageId: options.messageId, // Pass messageId from platform\n        platformSurface: options.platformSurface,\n        model: options.model,\n        messages: options.messages,\n        language: options.locale, // locale maps to language\n        geo_country: options.geo, // geo maps to geo_country\n        userId: options.userId,\n        // latency_budget_ms removed - now fetched from agent profile by backend\n        // allowed_formats removed - backend fetches from platform config automatically\n      });\n\n      // Convert AIP response to AgentRecommendationResponse format for rendering\n      const recommendation = this.convertAIPResponseToRecommendation(aipResponse);\n      const response: AgentRecommendationResponse = {\n        session_id: aipResponse.session_id,\n        message_id: `msg_${aipResponse.recommendation_id}`,\n        recommendations: [recommendation]\n      };\n\n      // Standard rendering\n        const renderer = this.getRenderer();\n        const tracker = this.getTracker();\n\n        await renderer.render({\n          containerId: options.containerId,\n          followups_container_id: options.followups_container_id,\n          response,\n          theme: options.theme || this.config.theme,\n          tracker: tracker,\n          sessionId: options.session_id,\n          apiKey: this.config.apiKey,\n          apiBaseUrl: this.apiBaseUrl,\n          language: options.locale,\n          geo_country: options.geo,\n          userId: options.userId,\n          model: options.model,\n          messages: options.messages,\n          onPasteToInput: options.onPasteToInput,\n          onExecuteQuery: options.onExecuteQuery\n        });\n\n        // NOTE: Exposure pixels are now fired by AdMeshViewabilityTracker component\n        // when ads meet MRC viewability standards (50% visible for 1 second).\n        // This ensures MRC-compliant exposure tracking and proper CPX billing.\n    } catch (error) {\n      logger.error('[AdMeshSDK] Error showing recommendations');\n      throw error;\n    }\n  }\n\n  /**\n   * Fetch recommendation from the /aip/context endpoint (new auction-based endpoint)\n   * \n   * Public method for fetching recommendation data without rendering.\n   * Useful for format detection and custom rendering logic.\n   * \n   * IMPORTANT: Both sessionId and messageId MUST be provided by the platform.\n   * The SDK NEVER generates these automatically.\n   */\n  async fetchRecommendationFromAIPContext(params: {\n    query: string;\n    sessionId: string;\n    messageId?: string;\n    // platformId is now extracted from API key by the backend\n    platformSurface?: string;\n    model?: string;\n    messages?: Array<{ role: string; content: string; id?: string }>;\n    language?: string;\n    geo_country?: string;\n    userId?: string;\n    // latency_budget_ms removed - now fetched from agent profile by backend\n    // allowed_formats removed - backend fetches from platform config (configured during onboarding)\n  }): Promise<AIPContextResponse> {\n    const url = `${this.apiBaseUrl}/aip/context`;\n\n    logger.log('[AdMeshSDK] 📥 fetchRecommendationFromAIPContext called');\n\n    // CRITICAL: sessionId MUST be provided by platform - SDK never generates it\n    if (!params.sessionId || params.sessionId.trim() === '') {\n      const error = new Error('sessionId is required and must be provided by the platform. The SDK never generates sessionId automatically.');\n      logger.error('[AdMeshSDK] ❌ sessionId not provided by platform - cannot process request');\n      throw error;\n    }\n\n    // CRITICAL: messageId MUST be provided by the platform - SDK never generates it\n    // NEVER derive from messages array - platform must pass it explicitly\n    const messageId = params.messageId;\n    if (!messageId || messageId.trim() === '') {\n      const error = new Error('messageId is required and must be provided by the platform. The SDK never generates messageId automatically.');\n      logger.error('[AdMeshSDK] ❌ messageId not provided by platform - cannot process request');\n      throw error;\n    }\n    \n    // Calculate turn_index from messages length\n    const turnIndex = params.messages ? params.messages.length : 0;\n    \n    // Detect device platform (web by default, could be enhanced with user agent detection)\n    const devicePlatform = typeof window !== 'undefined' && window.navigator ? 'web' : 'web';\n    \n    // Detect form factor (could be enhanced with screen size detection)\n    const formFactor = typeof window !== 'undefined' && window.innerWidth \n      ? (window.innerWidth < 768 ? 'mobile' : window.innerWidth < 1024 ? 'tablet' : 'desktop')\n      : 'desktop';\n\n    // Build PlatformRequest payload in UCP structure\n    // Note: producer.agent_id will be extracted from API key by the backend\n    // \n    // The operator receives this PlatformRequest and converts it to ContextRequest:\n    // - PlatformRequest uses extensions.aip (with query_text, messages) - this is correct\n    // - ContextRequest is flat (no extensions, intent.summary replaces query_text)\n    // - Brand agents receive decision context only (no raw queries, no identity fields)\n    const payload: PlatformRequest = {\n      spec_version: '1.0.0',\n      message_id: messageId,\n      timestamp: new Date().toISOString(),\n      producer: {\n        agent_id: 'placeholder', // Will be overridden by backend from API key\n        agent_role: 'publisher',\n        software: 'admesh_ui_sdk',\n        software_version: params.model || '1.0.0'\n      },\n      context: {\n        // context_id removed - operator will set it as message_id when creating ContextRequest for brand agents\n        language: params.language || 'en-US',\n        publisher: 'placeholder', // Will be overridden by backend from API key\n        placement: {\n          ad_unit: params.platformSurface || 'web'\n        },\n        device: {\n          platform: devicePlatform,\n          form_factor: formFactor\n        },\n        geography: {\n          country: params.geo_country || 'US'\n        }\n      },\n      identity: {\n        namespace: 'platform_user',\n        value_hash: params.userId || '',\n        confidence: 1.0\n      },\n      extensions: {\n        aip: {\n          session_id: params.sessionId,\n          turn_index: turnIndex,\n          query_text: params.query,\n          messages: params.messages || [],\n          // latency_budget_ms removed - now fetched from agent profile by backend\n          cpx_floor: 0.0\n        }\n      }\n    };\n\n    // Validate query before sending\n    if (!payload.extensions.aip.query_text || !payload.extensions.aip.query_text.trim()) {\n      logger.warn('[AdMeshSDK] ⚠️ Warning: Sending request with empty query_text');\n    }\n\n    const jsonBody = JSON.stringify(payload);\n    logger.log('[AdMeshSDK] 📤 Sending request to /aip/context');\n\n    const response = await fetch(url, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'Authorization': `Bearer ${this.config.apiKey}`\n      },\n      body: jsonBody\n    });\n\n    if (!response.ok) {\n      const errorData = await response.json().catch(() => ({}));\n      const errorMessage = errorData.detail || `HTTP ${response.status}`;\n      throw new Error(`Failed to fetch recommendation from /aip/context: ${errorMessage}`);\n    }\n\n    const data: any = await response.json();\n    \n    // Log the raw response structure for debugging\n    logger.log('[AdMeshSDK] 📥 Raw response from /aip/context:', {\n      hasCreative: !!data.creative,\n      creativeFormat: data.creative?.format,\n      creativeBridgeContent: data.creative?.bridge_content ? data.creative.bridge_content.substring(0, 50) + '...' : undefined,\n      hasWinningBid: !!data.winning_bid,\n      winningBidPreferredFormat: data.winning_bid?.preferred_format,\n      topLevelKeys: Object.keys(data)\n    });\n    \n    \n    return data as AIPContextResponse;\n  }\n\n\n  /**\n   * Convert AIP context response to AdMeshRecommendation format for compatibility\n   */\n  private convertAIPResponseToRecommendation(aipResponse: AIPContextResponse): AdMeshRecommendation {\n    const responseAny = aipResponse as any;\n    let creativeInput = aipResponse.creative_input || {};\n    \n    // Extract format and bridge prompt/content from creative object if present\n    // The response may have: creative: { format: 'bridge', bridge_prompt: '...', bridge_content: '...' }\n    // Check multiple locations for the creative object\n    const creative = responseAny.creative || {};\n    const format = creative.format || \n                   responseAny.format || \n                   responseAny.winning_bid?.preferred_format;\n    \n    // Extract headline from creative if present (for tail and product_card formats)\n    const headlineFromCreative = creative.headline;\n    \n    // Extract bridge format fields from creative if present\n    const bridgeHeadlineFromCreative = creative.bridge_headline;\n    const bridgeDescriptionFromCreative = creative.bridge_description;\n    const bridgePromptFromCreative =\n      creative.bridge_prompt || creative.bridge_content;\n    const bridgePrompt =\n      bridgePromptFromCreative ||\n      (creativeInput as any).bridge_prompt ||\n      (creativeInput as any).bridge_content;\n    \n    // Extract cta_label from creative if present (for bridge format)\n    const ctaLabelFromCreative = creative.cta_label;\n    const ctaLabel =\n      ctaLabelFromCreative ||\n      (creativeInput as any).cta_label;\n    \n    // Extract bridge_headline and bridge_description\n    const bridgeHeadline =\n      bridgeHeadlineFromCreative ||\n      (creativeInput as any).bridge_headline;\n    const bridgeDescription =\n      bridgeDescriptionFromCreative ||\n      (creativeInput as any).bridge_description;\n    \n    logger.log('[AdMeshSDK] 🔍 Extracting from response:', {\n      creativeObject: creative,\n      creativeFormat: creative.format,\n      creativeBridgeHeadline: bridgeHeadlineFromCreative,\n      creativeBridgeDescription: bridgeDescriptionFromCreative\n        ? String(bridgeDescriptionFromCreative).substring(0, 50) + '...'\n        : undefined,\n      creativeBridgePrompt: bridgePromptFromCreative\n        ? String(bridgePromptFromCreative).substring(0, 50) + '...'\n        : undefined,\n      creativeCtaLabel: ctaLabelFromCreative,\n      extractedFormat: format,\n      extractedBridgeHeadline: bridgeHeadline,\n      extractedBridgeDescription: bridgeDescription\n        ? String(bridgeDescription).substring(0, 50) + '...'\n        : undefined,\n      extractedBridgePrompt: bridgePrompt\n        ? String(bridgePrompt).substring(0, 50) + '...'\n        : undefined,\n      extractedCtaLabel: ctaLabel,\n      creativeInputHasBridgeHeadline: !!(creativeInput as any).bridge_headline,\n      creativeInputHasBridgeDescription: !!(creativeInput as any).bridge_description,\n      creativeInputHasBridgePrompt: !!(creativeInput as any).bridge_prompt,\n      creativeInputHasBridgeContent: !!(creativeInput as any).bridge_content,\n      creativeInputHasCtaLabel: !!(creativeInput as any).cta_label\n    });\n    \n    // ALWAYS merge creative fields into creative_input for format detection\n    // This ensures headline, bridge_headline, bridge_description, bridge_prompt and cta_label are available\n    // Explicitly preserve assets to ensure logo_url is not lost during merge\n    const preservedAssets = creativeInput.assets || {};\n    creativeInput = {\n      ...creativeInput,\n      // Explicitly preserve assets object to ensure logo_url is maintained\n      assets: preservedAssets,\n      // Prioritize creative object fields over existing creative_input\n      ...(headlineFromCreative && { headline: headlineFromCreative }), // For tail and product_card formats\n      ...(bridgeHeadline && { bridge_headline: bridgeHeadline }),\n      ...(bridgeDescription && { bridge_description: bridgeDescription }),\n      ...(bridgePrompt && { bridge_prompt: bridgePrompt }),\n      // Keep bridge_content for backward compatibility\n      ...(bridgePrompt && { bridge_content: bridgePrompt }),\n      ...(ctaLabel && { cta_label: ctaLabel }),\n      ...(format && { format: format })\n    };\n    \n    // Ensure recommendation_id is set (use from response or generate fallback)\n    const recommendationId = aipResponse.recommendation_id || \n                             (responseAny as any).recommendation_id ||\n                             (responseAny as any).bid_id || // Fallback for backward compatibility\n                             '';\n    \n    // Ensure admesh_link is set (use click_url if not provided)\n    const admeshLink = aipResponse.click_url || \n                       (aipResponse as any).admesh_link || \n                       '';\n    \n    // Build legacy fields from creative_input for backward compatibility\n    const recommendation: any = {\n      ...aipResponse,\n      // Ensure recommendation_id is present\n      recommendation_id: recommendationId,\n      // Ensure admesh_link is present (use click_url as fallback)\n      admesh_link: admeshLink || aipResponse.click_url || '',\n      // Remove any ad_id or bid_id fields\n      ad_id: undefined,\n      bid_id: undefined,\n      // Update creative_input with merged fields (CRITICAL: this must include bridge_content)\n      creative_input: creativeInput,\n      // Legacy field mappings\n      product_title: aipResponse.title,\n      tail_summary: creativeInput.long_description || '',\n      product_summary: creativeInput.short_description || '',\n      weave_summary: creativeInput.context_snippet || '',\n      product_logo: creativeInput.assets?.logo_url ? {\n        url: creativeInput.assets.logo_url\n      } : undefined,\n      categories: creativeInput.categories || []\n    };\n    \n    // Remove ad_id and bid_id if they exist\n    delete recommendation.ad_id;\n    delete recommendation.bid_id;\n    \n    // Ensure products array is preserved (check top-level first, then creative_input as fallback)\n    // Operator adds products at top level, but also check creative_input for backward compatibility\n    const productsFromTopLevel = (aipResponse as any)?.products || [];\n    const productsFromCreative = (creativeInput as any)?.products || [];\n    const products = productsFromTopLevel.length > 0 ? productsFromTopLevel : productsFromCreative;\n    \n    if (products && products.length > 0) {\n      recommendation.products = products;\n      logger.log(`[AdMeshSDK] ✅ Preserved ${products.length} products for product_card format`);\n    }\n    \n    // Ensure preferred_format is preserved (single authoritative field from backend)\n    const preferredFormat = (aipResponse as any)?.preferred_format || (creativeInput as any)?.preferred_format;\n    if (preferredFormat) {\n      recommendation.preferred_format = preferredFormat;\n      logger.log(`[AdMeshSDK] ✅ Preserved preferred_format: ${preferredFormat}`);\n    }\n    \n    logger.log('[AdMeshSDK] 🔄 Converted recommendation:', {\n      preferredFormat: preferredFormat,\n      hasProducts: !!(products && products.length > 0),\n      productsCount: products?.length || 0,\n      hasBridgeHeadline: !!bridgeHeadline,\n      bridgeHeadline: bridgeHeadline,\n      hasBridgeDescription: !!bridgeDescription,\n      bridgeDescriptionPreview: bridgeDescription\n        ? String(bridgeDescription).substring(0, 50) + '...'\n        : undefined,\n      hasBridgePrompt: !!bridgePrompt,\n      hasCtaLabel: !!ctaLabel,\n      ctaLabel: ctaLabel,\n      bridgeHeadlineInCreativeInput: !!(recommendation.creative_input as any)\n        ?.bridge_headline,\n      bridgeDescriptionInCreativeInput: !!(recommendation.creative_input as any)\n        ?.bridge_description,\n      bridgePromptInCreativeInput: !!(recommendation.creative_input as any)\n        ?.bridge_prompt,\n      bridgeContentInCreativeInput: !!(recommendation.creative_input as any)\n        ?.bridge_content,\n      ctaLabelInCreativeInput: !!(recommendation.creative_input as any)\n        ?.cta_label,\n      bridgePromptPreview: bridgePrompt\n        ? String(bridgePrompt).substring(0, 50) + '...'\n        : undefined,\n      creativeInputKeys: Object.keys(recommendation.creative_input || {})\n    });\n    \n    return recommendation as AdMeshRecommendation;\n  }\n\n  /**\n   * Fire exposure for sponsored followup\n   * \n   * @param exposureUrl - The exposure URL to fire (can use regular exposure_url)\n   * @param recommendationId - The recommendation ID\n   * @param sessionId - The session ID\n   */\n  fireFollowupExposure(exposureUrl: string, recommendationId: string, sessionId: string): void {\n    const tracker = this.getTracker();\n    tracker.fireFollowupExposure(exposureUrl, recommendationId, sessionId);\n  }\n\n  /**\n   * Fire engagement for sponsored followup\n   * \n   * @param engagementUrl - The engagement URL to fire\n   * @param recommendationId - The recommendation ID\n   * @param sessionId - The session ID\n   * @returns Promise that resolves when engagement is fired\n   */\n  async fireFollowupEngagement(engagementUrl: string, recommendationId: string, sessionId: string): Promise<void> {\n    const tracker = this.getTracker();\n    return tracker.fireFollowupEngagement(engagementUrl, recommendationId, sessionId);\n  }\n}\n\nexport default AdMeshSDK;\n","/**\n * WeaveResponseProcessor\n * \n * Automatically detects and enhances AdMesh recommendation links in organic LLM responses.\n * Handles:\n * - Automatic link detection (AdMesh tracking URLs)\n * - Label enhancement (<sub>[Ad]</sub> subscript labels)\n * - Exposure pixel triggering\n * - Streaming response support (MutationObserver)\n */\n\nimport { logger } from '../utils/logger';\n\nexport interface DetectedLink {\n  element: HTMLAnchorElement;\n  href: string;\n  text: string;\n  hasAdLabel: boolean;\n  matchedRecommendation?: {\n    recommendation_id: string;\n    click_url: string;\n    exposure_url?: string;\n  };\n}\n\nexport interface ProcessorConfig {\n  autoAddLabels?: boolean;\n  fireExposurePixels?: boolean;\n  labelStyle?: {\n    fontSize?: string;\n    fontWeight?: string;\n    color?: string;\n    marginLeft?: string;\n  };\n}\n\nexport interface ExposurePixelTarget {\n  exposureUrl?: string;\n  recommendationId?: string;\n  linkElement: HTMLAnchorElement;\n}\n\nexport class WeaveResponseProcessor {\n  private autoAddLabels: boolean;\n  private fireExposurePixels: boolean;\n  private labelStyle: Record<string, string>;\n  private processedLinks: Set<string> = new Set();\n  private mutationObserver: MutationObserver | null = null;\n\n  constructor(config: ProcessorConfig = {}) {\n    this.autoAddLabels = config.autoAddLabels !== false; // Default: true\n    this.fireExposurePixels = config.fireExposurePixels !== false; // Default: true\n    this.labelStyle = {\n      fontSize: config.labelStyle?.fontSize || '0.75em',\n      fontWeight: config.labelStyle?.fontWeight || 'bold',\n      color: config.labelStyle?.color || '#666',\n      marginLeft: config.labelStyle?.marginLeft || '2px'\n    };\n  }\n\n  /**\n   * Get links to process with CSS selector optimization\n   *\n   * Optimized approach:\n   * 1. Use CSS selector to find AdMesh links (97% faster)\n   *    - Matches: api.useadmesh.com/click/*, *.useadmesh.com/click/*\n   * 2. Fallback to scanning all links if selector finds nothing\n   * 3. Recommendation validation ensures accuracy\n   */\n  private getLinksToProcess(container: HTMLElement): HTMLAnchorElement[] {\n    // Try optimized selector first for AdMesh links\n    // Matches both api.useadmesh.com and *.useadmesh.com domains\n    const optimizedSelector = 'a[href*=\"/click/\"][href*=\"admesh.com\"], a[href*=\"/click/\"][href*=\"useadmesh.com\"]';\n    const optimizedLinks = container.querySelectorAll(optimizedSelector);\n\n    if (optimizedLinks.length > 0) {\n      return Array.from(optimizedLinks) as HTMLAnchorElement[];\n    }\n\n    // Fallback: scan all links\n    return Array.from(container.querySelectorAll('a')) as HTMLAnchorElement[];\n  }\n\n  /**\n   * Scan container for ALL links and process only AdMesh recommendation links\n   *\n   * This method:\n   * 1. Scans container for all <a> tags (or uses optimized selector)\n   * 2. If recommendations provided: Filters to only process links matching recommendation click_url values\n   * 3. If NO recommendations: Detects links by URL pattern (api.useadmesh.com/click/*)\n   * 4. Ignores non-AdMesh links (external links, documentation, etc.)\n   * 5. Adds [Ad] labels to matching links\n   * 6. Fires exposure pixels for each match\n   *\n   * NOTE: When recommendations array is empty, this method detects AdMesh links by URL pattern.\n   * This is important for Weave Ad Format where the backend embeds links in the LLM response\n   * and the frontend hook doesn't have access to the recommendations data.\n   */\n  scanAndProcessLinks(\n    container: HTMLElement,\n    recommendations: any[],\n    onExposurePixel?: (target: ExposurePixelTarget) => void\n  ): DetectedLink[] {\n    if (!container) {\n      return [];\n    }\n\n    const detectedLinks: DetectedLink[] = [];\n\n    // If recommendations provided, use them for matching\n    if (recommendations.length > 0) {\n      // Get links to process (with optional optimization)\n      const links = this.getLinksToProcess(container);\n\n      // Build map of AdMesh click URLs for fast lookup\n      const clickUrlMap = new Map(\n        recommendations\n          .filter(r => r.click_url)\n          .map(r => [r.click_url, r])\n      );\n\n      // Build map of brand URLs (redirect_url, url) for matching direct brand links\n      const brandUrlMap = new Map<string, any>();\n      recommendations.forEach((r: any) => {\n        // Match by redirect_url or url (original brand URLs)\n        const redirectUrl = r.redirect_url || r.url || (r.creative_input as any)?.cta_url;\n        if (redirectUrl && typeof redirectUrl === 'string') {\n          // Normalize URL (remove trailing slashes, query params for matching)\n          const normalizedUrl = redirectUrl.trim().replace(/\\/$/, '');\n          brandUrlMap.set(normalizedUrl, r);\n          // Also match with trailing slash\n          brandUrlMap.set(`${normalizedUrl}/`, r);\n        }\n      });\n\n      links.forEach((link: HTMLAnchorElement) => {\n        const href = link.getAttribute('href') || '';\n        const linkKey = `${href}`;\n\n        // Skip if already processed\n        if (this.processedLinks.has(linkKey)) {\n          return;\n        }\n\n        // First, check if link matches AdMesh click URL\n        let recommendation = clickUrlMap.get(href);\n        let actualHref = href;\n        \n        // If not found, check if link matches brand URL (redirect_url or url)\n        if (!recommendation) {\n          const normalizedHref = href.trim().replace(/\\/$/, '');\n          recommendation = brandUrlMap.get(normalizedHref) || brandUrlMap.get(`${normalizedHref}/`);\n          \n          // If brand URL matched, replace it with click_url\n          if (recommendation && recommendation.click_url) {\n            logger.log('[WeaveResponseProcessor] 🔄 Found brand URL match, replacing with click_url:', href);\n            link.setAttribute('href', recommendation.click_url);\n            actualHref = recommendation.click_url;\n          }\n        }\n        \n        // Process link if it matches a recommendation (either by click_url or brand URL)\n        if (recommendation) {\n          this.processedLinks.add(linkKey);\n\n          // ALWAYS set target=\"_blank\" and rel=\"noopener noreferrer\" for AdMesh tracking links\n          // This ensures all click_url links open in a new tab\n          link.setAttribute('target', '_blank');\n          link.setAttribute('rel', 'noopener noreferrer');\n\n          const detectedLink: DetectedLink = {\n            element: link,\n            href: actualHref, // Use actual href (may be updated click_url)\n            text: link.textContent || '',\n            hasAdLabel: this.hasAdLabel(link),\n            matchedRecommendation: {\n              recommendation_id: recommendation.recommendation_id || '',\n              click_url: recommendation.click_url,\n              exposure_url: recommendation.exposure_url\n            }\n          };\n\n          // Add label if not present\n          if (this.autoAddLabels && !detectedLink.hasAdLabel) {\n            logger.log('[WeaveResponseProcessor] 🏷️  Adding [Ad] label to matched recommendation link:', actualHref);\n            this.addAdLabel(link);\n            detectedLink.hasAdLabel = true;\n          } else if (!this.autoAddLabels) {\n            logger.log('[WeaveResponseProcessor] ℹ️  autoAddLabels is disabled, skipping label');\n          } else if (detectedLink.hasAdLabel) {\n            logger.log('[WeaveResponseProcessor] ℹ️  Link already has label, skipping');\n          }\n\n          // Fire exposure pixel\n          if (this.fireExposurePixels && recommendation.exposure_url && onExposurePixel && detectedLink.matchedRecommendation) {\n            onExposurePixel({\n              exposureUrl: recommendation.exposure_url,\n              recommendationId: detectedLink.matchedRecommendation.recommendation_id,\n              linkElement: link\n            });\n          }\n\n          detectedLinks.push(detectedLink);\n        }\n      });\n    } else {\n      // No recommendations provided - detect AdMesh links by URL pattern\n      // This is used for Weave Ad Format where backend embeds links in LLM response\n      // Links can be in formats like:\n      // - https://api.useadmesh.com/click/...\n      // - https://api.admesh.com/click/...\n      // - https://useadmesh.com/click/...\n      // - https://admesh.com/click/...\n      // Get ALL links in container and filter programmatically\n      const allLinks = Array.from(container.querySelectorAll('a')) as HTMLAnchorElement[];\n\n      \n\n      allLinks.forEach((link: HTMLAnchorElement) => {\n        const href = link.getAttribute('href') || '';\n        const linkKey = `${href}`;\n\n        // Skip if already processed\n        if (this.processedLinks.has(linkKey)) {\n          return;\n        }\n\n        // Check if this is an AdMesh link by examining the URL\n        const isAdMeshLink = this.isAdMeshLink(href);\n\n        if (isAdMeshLink) {\n\n          this.processedLinks.add(linkKey);\n\n          const detectedLink: DetectedLink = {\n            element: link,\n            href,\n            text: link.textContent || '',\n            hasAdLabel: this.hasAdLabel(link),\n            matchedRecommendation: undefined\n          };\n\n          // Set target=\"_blank\" and rel=\"noopener noreferrer\" for security\n          link.setAttribute('target', '_blank');\n          link.setAttribute('rel', 'noopener noreferrer');\n\n          // Add label if not present\n          if (this.autoAddLabels && !detectedLink.hasAdLabel) {\n            logger.log('[WeaveResponseProcessor] 🏷️  Adding [Ad] label to pattern-matched AdMesh link:', href);\n            this.addAdLabel(link);\n            detectedLink.hasAdLabel = true;\n          } else if (!this.autoAddLabels) {\n            logger.log('[WeaveResponseProcessor] ℹ️  autoAddLabels is disabled, skipping label');\n          } else if (detectedLink.hasAdLabel) {\n            logger.log('[WeaveResponseProcessor] ℹ️  Link already has label, skipping');\n          }\n\n          // Fire exposure tracking with converted exposure URL\n          // For Weave Ad Format: LLM embeds click URLs in response text, so we convert to exposure URL\n          if (this.fireExposurePixels && onExposurePixel) {\n            const exposureUrl = this.convertClickUrlToExposureUrl(href);\n            onExposurePixel({\n              exposureUrl,\n              recommendationId: this.extractRecommendationIdFromUrl(href),\n              linkElement: link\n            });\n          }\n\n          detectedLinks.push(detectedLink);\n        }\n      });\n\n    \n    }\n\n    return detectedLinks;\n  }\n\n  /**\n   * Check if link already has [Ad] label\n   *\n   * This method checks for [Ad] labels on BOTH sides of the link:\n   * - Previous sibling (left side): [Ad] link text\n   * - Next sibling (right side): link text [Ad]\n   * - Inside the link itself (as a child element)\n   *\n   * This prevents duplicate label rendering when the LLM response\n   * already contains [Ad] labels in any position.\n   */\n  private hasAdLabel(link: HTMLAnchorElement): boolean {\n    // First, check if link itself contains [Ad] in its text content or as a child\n    const linkText = link.textContent || '';\n    if (linkText.includes('[Ad]')) {\n      logger.log('[WeaveResponseProcessor] ℹ️  Link text contains [Ad] label');\n      return true;\n    }\n\n    // Check for [Ad] label as a direct child element (e.g., <a>text<sub>[Ad]</sub></a>)\n    const childElements = link.querySelectorAll('sub, span');\n    for (const child of Array.from(childElements)) {\n      if (child.textContent?.includes('[Ad]')) {\n        logger.log('[WeaveResponseProcessor] ℹ️  Link has [Ad] label as child element');\n        return true;\n      }\n    }\n\n    // Check PREVIOUS sibling (left side) for [Ad] label\n    let prevNode = link.previousSibling;\n\n    // Skip text nodes that are just whitespace\n    while (prevNode && prevNode.nodeType === Node.TEXT_NODE) {\n      const text = prevNode.textContent || '';\n      if (text.trim() === '') {\n        prevNode = prevNode.previousSibling;\n        continue;\n      }\n      // If we find non-whitespace text, check if it contains [Ad]\n      if (text.includes('[Ad]')) {\n        logger.log('[WeaveResponseProcessor] ℹ️  Found [Ad] label in previous text sibling');\n        return true;\n      }\n      break;\n    }\n\n    // Check if previous element node is a <sub> or <span> with [Ad] label\n    if (prevNode && prevNode.nodeType === Node.ELEMENT_NODE) {\n      const element = prevNode as HTMLElement;\n      const tagName = element.tagName.toUpperCase();\n      if ((tagName === 'SUB' || tagName === 'SPAN') &&\n          element.textContent?.includes('[Ad]')) {\n        logger.log('[WeaveResponseProcessor] ℹ️  Found [Ad] label in previous element sibling:', tagName);\n        return true;\n      }\n    }\n\n    // Check NEXT sibling (right side) for [Ad] label\n    let nextNode = link.nextSibling;\n\n    // Skip text nodes that are just whitespace\n    while (nextNode && nextNode.nodeType === Node.TEXT_NODE) {\n      const text = nextNode.textContent || '';\n      if (text.trim() === '') {\n        nextNode = nextNode.nextSibling;\n        continue;\n      }\n      // If we find non-whitespace text, check if it contains [Ad]\n      if (text.includes('[Ad]')) {\n        logger.log('[WeaveResponseProcessor] ℹ️  Found [Ad] label in next text sibling');\n        return true;\n      }\n      break;\n    }\n\n    // Check if next element node is a <sub> or <span> with [Ad] label\n    if (nextNode && nextNode.nodeType === Node.ELEMENT_NODE) {\n      const element = nextNode as HTMLElement;\n      const tagName = element.tagName.toUpperCase();\n      if ((tagName === 'SUB' || tagName === 'SPAN') &&\n          element.textContent?.includes('[Ad]')) {\n        logger.log('[WeaveResponseProcessor] ℹ️  Found [Ad] label in next element sibling:', tagName);\n        return true;\n      }\n    }\n\n    logger.log('[WeaveResponseProcessor] ℹ️  No existing [Ad] label found');\n    return false;\n  }\n\n  /**\n   * Add [Ad] label as subscript after link with \"Why this ad?\" tooltip\n   *\n   * This method:\n   * 1. Removes any [Ad] label on the LEFT side (previous sibling)\n   * 2. Creates a <sub> element with [Ad] text\n   * 3. Positions it immediately after the link (to the RIGHT)\n   * 4. Adds tooltip styling with default cursor (not help cursor)\n   * 5. Adds click handler for tooltip interaction\n   * 6. Ensures only ONE label per link, always on the RIGHT side\n   */\n  private addAdLabel(link: HTMLAnchorElement): void {\n    logger.log('[WeaveResponseProcessor] 🏷️  Attempting to add [Ad] label to link:', link.href);\n   \n    // Verify link is still in the DOM\n    if (!link.isConnected) {\n      logger.warn('[WeaveResponseProcessor] ⚠️  Link is not in DOM, cannot add label');\n      return;\n    }\n\n    // Double-check that [Ad] label doesn't already exist to prevent duplicates\n    if (this.hasAdLabel(link)) {\n      logger.log('[WeaveResponseProcessor] ℹ️  Link already has [Ad] label, skipping');\n      return;\n    }\n\n    // Verify parent node exists before proceeding\n    const parentNode = link.parentNode;\n    if (!parentNode) {\n      logger.error('[WeaveResponseProcessor] ❌ Link has no parent node, cannot add label');\n      return;\n    }\n\n    // Remove any [Ad] label on the LEFT side (previous sibling)\n    this.removeLeftAdLabel(link);\n\n    // Create the [Ad] label as a <sub> element\n    const subLabel = document.createElement('sub');\n    subLabel.textContent = '[Ad]';\n    subLabel.style.fontSize = this.labelStyle.fontSize;\n    subLabel.style.fontWeight = this.labelStyle.fontWeight;\n    subLabel.style.color = this.labelStyle.color;\n    subLabel.style.marginLeft = this.labelStyle.marginLeft;\n\n    // Add tooltip styling with default cursor (not help cursor)\n    subLabel.style.cursor = 'pointer';\n    subLabel.style.borderBottom = `1px dotted ${this.labelStyle.color}`;\n    subLabel.style.whiteSpace = 'nowrap';\n    subLabel.title = 'Why this ad? This is a sponsored recommendation based on your search query.';\n\n    // Track tooltip state for click interactions\n    let isTooltipVisible = false;\n\n    // Add hover effect for visual feedback\n    subLabel.addEventListener('mouseenter', () => {\n      subLabel.style.opacity = '0.7';\n    });\n\n    subLabel.addEventListener('mouseleave', () => {\n      subLabel.style.opacity = '1';\n      // Hide tooltip on mouse leave if it was shown by click\n      if (isTooltipVisible) {\n        isTooltipVisible = false;\n      }\n    });\n\n    // Add click handler to toggle tooltip visibility\n    subLabel.addEventListener('click', (event: Event) => {\n      event.stopPropagation();\n      isTooltipVisible = !isTooltipVisible;\n\n      if (isTooltipVisible) {\n        // Show tooltip by adding visual indicator\n        subLabel.style.textDecoration = 'underline';\n        subLabel.style.opacity = '0.7';\n      } else {\n        // Hide tooltip visual indicator\n        subLabel.style.textDecoration = 'none';\n        subLabel.style.opacity = '1';\n      }\n    });\n\n    // Close tooltip when clicking elsewhere on the page\n    const closeTooltipOnClickOutside = (event: Event) => {\n      if (isTooltipVisible && event.target !== subLabel) {\n        isTooltipVisible = false;\n        subLabel.style.textDecoration = 'none';\n        subLabel.style.opacity = '1';\n      }\n    };\n\n    document.addEventListener('click', closeTooltipOnClickOutside);\n\n    // Insert the label immediately after the link (to the right)\n    // Handle edge cases: if nextSibling is null, appendChild will insert at the end\n    try {\n      const nextSibling = link.nextSibling;\n      if (nextSibling) {\n        parentNode.insertBefore(subLabel, nextSibling);\n        logger.log('[WeaveResponseProcessor] ✅ [Ad] label inserted before next sibling');\n      } else {\n        // If no next sibling, append to parent (inserts after link)\n        parentNode.appendChild(subLabel);\n        logger.log('[WeaveResponseProcessor] ✅ [Ad] label appended to parent (no next sibling)');\n      }\n      \n      // Verify label was successfully inserted\n      if (subLabel.isConnected && subLabel.parentNode === parentNode) {\n        logger.log('[WeaveResponseProcessor] ✅ [Ad] label successfully added to link:', link.href);\n      } else {\n        logger.error('[WeaveResponseProcessor] ❌ [Ad] label insertion failed - label not in DOM');\n      }\n    } catch (error) {\n      logger.error('[WeaveResponseProcessor] ❌ Error inserting [Ad] label:', error);\n    }\n  }\n\n  /**\n   * Remove [Ad] label from the LEFT side (previous sibling) of a link\n   *\n   * This ensures that only ONE [Ad] label appears on the RIGHT side,\n   * removing any duplicate labels that might be on the left.\n   */\n  private removeLeftAdLabel(link: HTMLAnchorElement): void {\n    let prevNode = link.previousSibling;\n\n    // Skip text nodes that are just whitespace\n    while (prevNode && prevNode.nodeType === Node.TEXT_NODE) {\n      const text = prevNode.textContent || '';\n      if (text.trim() === '') {\n        prevNode = prevNode.previousSibling;\n        continue;\n      }\n      // If we find non-whitespace text containing [Ad], remove it\n      if (text.includes('[Ad]')) {\n        prevNode.parentNode?.removeChild(prevNode);\n        return;\n      }\n      break;\n    }\n\n    // Check if previous element node is a <sub> or <span> with [Ad] label\n    if (prevNode && prevNode.nodeType === Node.ELEMENT_NODE) {\n      const element = prevNode as HTMLElement;\n      if ((element.tagName === 'SUB' || element.tagName === 'SPAN') &&\n          element.textContent?.includes('[Ad]')) {\n        element.parentNode?.removeChild(element);\n      }\n    }\n  }\n\n  /**\n   * Check if a URL is an AdMesh link\n   *\n   * Detects AdMesh links by checking if the URL contains /click/ and matches AdMesh patterns:\n   * - https://api.useadmesh.com/click/...\n   * - https://api.admesh.com/click/...\n   * - http://localhost:8000/click/... (local development)\n   * - Any URL with /click/ that looks like an AdMesh tracking URL\n   */\n  private isAdMeshLink(href: string): boolean {\n    if (!href) {\n      return false;\n    }\n\n    // Check if URL contains /click/ (AdMesh tracking pattern)\n    if (!href.includes('/click/')) {\n      return false;\n    }\n\n    // Check for known AdMesh domains\n    const admeshDomains = [\n      'useadmesh.com',\n      'admesh.com',\n      'api.useadmesh.com',\n      'api.admesh.com',\n      'localhost:8000', // Local development\n      'localhost:3000', // Local development (if proxied)\n    ];\n\n    const isKnownDomain = admeshDomains.some(domain => href.includes(domain));\n    if (isKnownDomain) {\n      return true;\n    }\n\n    // Fallback: if URL has /click/ and looks like a tracking URL, treat it as AdMesh\n    // This handles cases where the domain might be different but the pattern matches\n    try {\n      const url = new URL(href);\n      const pathname = url.pathname;\n\n      // Check if pathname starts with /click/ (AdMesh pattern)\n      if (pathname.startsWith('/click/')) {\n        return true;\n      }\n    } catch {\n      // If URL parsing fails, check string pattern\n      if (href.match(/\\/click\\/[a-zA-Z0-9\\-_]+/)) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  /**\n   * Extract recommendation ID from AdMesh click URL\n   *\n   * URL format: https://api.useadmesh.com/click/{recommendation_id}?...\n   * Returns the recommendation_id portion or empty string if extraction fails\n   */\n  private extractRecommendationIdFromUrl(url: string): string {\n    try {\n      // Try to extract from /click/{id} pattern\n      const match = url.match(/\\/click\\/([^/?]+)/);\n      if (match && match[1]) {\n        return match[1];\n      }\n      // Fallback to empty string (recommendation_id should be in URL)\n      return '';\n    } catch {\n      return url;\n    }\n  }\n\n  /**\n   * Convert AdMesh click URL to exposure URL (Weave Ad Format only)\n   *\n   * This is ONLY used for Weave Ad Format where the LLM embeds click URLs in the response text\n   * and we need to derive the exposure URL for tracking.\n   *\n   * Click URL format: https://api.useadmesh.com/click/r/{aid}?aid={aid}&rid={rid}&nonce={nonce}&exp={exp}&sig={sig}\n   * Exposure URL format: https://api.useadmesh.com/exposure?aid={aid}&rid={rid}&nonce={nonce}&exp={exp}&sig={sig}&cpx={cpx}\n   *\n   * This method:\n   * 1. Parses the click URL to extract the base domain and query parameters\n   * 2. Replaces the /click/r/{aid} path with /exposure\n   * 3. Preserves all tracking parameters (aid, rid, nonce, exp, sig)\n   * 4. Adds cpx=0 as default (actual CPX value is set server-side)\n   *\n   * @param clickUrl - The AdMesh click tracking URL\n   * @returns The corresponding exposure tracking URL, or the original URL if conversion fails\n   */\n  private convertClickUrlToExposureUrl(clickUrl: string): string {\n    try {\n      const url = new URL(clickUrl);\n\n      // Extract the base URL (protocol + host)\n      const baseUrl = `${url.protocol}//${url.host}`;\n\n      // Build exposure endpoint URL\n      const exposureUrl = `${baseUrl}/exposure`;\n\n      // Preserve all existing query parameters from click URL\n      // These include: aid, rid, nonce, exp, sig\n      const params = new URLSearchParams(url.search);\n\n      // Add cpx parameter if not present (default to 0, actual value is set server-side)\n      if (!params.has('cpx')) {\n        params.set('cpx', '0');\n      }\n\n      // Construct final exposure URL with all parameters\n      return `${exposureUrl}?${params.toString()}`;\n    } catch (error) {\n      // If URL parsing fails, log warning and return original URL\n      logger.warn('[WeaveResponseProcessor] Failed to convert click URL to exposure URL');\n      return clickUrl;\n    }\n  }\n\n  /**\n   * Watch container for new links (streaming support)\n   */\n  watchForNewLinks(\n    container: HTMLElement,\n    recommendations: any[],\n    onExposurePixel?: (target: ExposurePixelTarget) => void\n  ): void {\n    if (!container) {\n      return;\n    }\n\n    // Stop existing observer\n    if (this.mutationObserver) {\n      this.mutationObserver.disconnect();\n    }\n\n    // Create observer for new nodes\n    this.mutationObserver = new MutationObserver(() => {\n      this.scanAndProcessLinks(container, recommendations, onExposurePixel);\n    });\n\n    this.mutationObserver.observe(container, {\n      childList: true,\n      subtree: true,\n      characterData: false\n    });\n  }\n\n  /**\n   * Stop watching for new links\n   */\n  stopWatching(): void {\n    if (this.mutationObserver) {\n      this.mutationObserver.disconnect();\n      this.mutationObserver = null;\n    }\n  }\n\n  /**\n   * Clear processed links cache\n   */\n  clearCache(): void {\n    this.processedLinks.clear();\n  }\n}\n\nexport default WeaveResponseProcessor;\n","'use client';\n\nimport { useEffect, useState, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useAdMesh } from '../hooks/useAdMesh';\nimport { logger } from '../utils/logger';\nimport { AdMeshTailAd } from './AdMeshTailAd';\nimport { AdMeshFollowup } from './AdMeshFollowup';\nimport { AdMeshBridgeFormat } from './AdMeshBridgeFormat';\nimport { AdMeshEcommerceCards } from './AdMeshEcommerceCards';\nimport type { AdMeshRecommendation } from '../types/index';\n\nexport interface AdMeshRecommendationsProps {\n  /** Optional callback when recommendations are shown */\n  onRecommendationsShown?: (messageId: string) => void;\n\n  /** Optional callback on error */\n  onError?: (error: Error) => void;\n\n  /**\n   * Message ID for per-message recommendations.\n   *\n   * This is the primary identifier for fetching recommendations for a specific message.\n   */\n  messageId?: string;\n\n  /**\n   * User query text for generating recommendations.\n   *\n   * This is the query that will be used to fetch recommendations from the backend.\n   * Typically the user's question or search query.\n   *\n   * IMPORTANT: This should be a non-empty string. If not provided or empty,\n   * the component will skip rendering to prevent 400 Bad Request errors.\n   * The backend requires a valid query parameter.\n   */\n  query?: string;\n\n  /**\n   * Callback to paste content to input field (for bridge format CTA button).\n   * When provided, the bridge format will show a CTA button that pastes\n   * the bridge_content into the input field when clicked.\n   */\n  onPasteToInput?: (content: string) => void;\n\n  /**\n   * Optional container ID for follow-up suggestions.\n   * When provided and the recommendation includes a followup_query,\n   * the SDK will automatically render the follow-up in this container.\n   */\n  followups_container_id?: string;\n\n  /**\n   * Callback to execute query when follow-up is selected (required for follow-up functionality).\n   * When a user clicks on a follow-up suggestion, this callback is invoked with the followup_query.\n   * This allows the platform to continue the conversation with the sponsored follow-up query.\n   */\n  onExecuteQuery?: (query: string) => void | Promise<void>;\n\n  /**\n   * Callback when a sponsored followup is detected.\n   * This allows third-party applications to integrate the sponsored followup query into their own\n   * followup suggestions UI (e.g., adding to a suggestions list, related questions section, etc.).\n   * \n   * When a user clicks the followup suggestion, the application should:\n   * 1. Fire engagement tracking by calling the followupEngagementUrl\n   * 2. Execute the followupQuery (e.g., submit it as a new user query)\n   * \n   * @param followupQuery - The sponsored followup query text to display to the user\n   * @param followupEngagementUrl - The engagement tracking URL to call when user clicks the followup\n   * @param recommendationId - The recommendation ID for tracking and correlation\n   * \n   * @example\n   * ```tsx\n   * <AdMeshRecommendations\n   *   onFollowupDetected={(query, engagementUrl, recId) => {\n   *     // Add to your suggestions list\n   *     setSuggestions(prev => [...prev, {\n   *       text: query,\n   *       sponsored: true,\n   *       engagementUrl,\n   *       recommendationId: recId\n   *     }]);\n   *   }}\n   * />\n   * ```\n   */\n\n  onFollowupDetected?: (followupQuery: string, followupEngagementUrl: string, recommendationId: string) => void;\n\n  /**\n   * Signal indicating if the followup container is ready in the DOM.\n   * \n   * Useful for scenarios where the container is rendered conditionally or after a delay (e.g. streaming).\n   * If provided, the component will wait until this is true before attempting to attach the portal.\n   */\n  isContainerReady?: boolean;\n\n  /**\n   * Optional user ID to override the context-provided user ID.\n   * Useful for per-message or specific user tracking scenarios.\n   */\n  userId?: string;\n}\n\n/**\n * AdMeshRecommendations - Citation/Product Format Recommendation Display\n *\n * Displays recommendations as a separate UI component. Handles all the complexity:\n * - Uses provided messageId directly\n * - Generates container IDs for recommendations\n * - Calls SDK's showRecommendations()\n *\n * For Weave Ad Format (where AdMesh links are embedded in LLM response),\n * use WeaveAdFormatContainer component instead.\n *\n * @example\n * ```tsx\n * // Per-message recommendations with messageId\n * <AdMeshProvider apiKey={apiKey} sessionId={sessionId}>\n *   {messages.map((msg) => (\n * <div key={msg.messageId}>\n *       {msg.content}\n *       {msg.role === 'assistant' && (\n * <AdMeshRecommendations\n * messageId={msg.messageId}\n *           query={msg.userQuery}\n *         />\n *       )}\n *     </div>\n *   ))}\n * </AdMeshProvider>\n * ```\n *\n * @example\n * ```tsx\n * // Format is auto-detected from brand agent's preferred_format\n * <AdMeshProvider apiKey={apiKey} sessionId={sessionId}>\n *   <Chat messages={messages} />\n *   <AdMeshRecommendations\n *     messageId={lastMessageId}\n *     query=\"best CRM for small business\"\n *   />\n * </AdMeshProvider>\n * ```\n */\nexport const AdMeshRecommendations = ({\n  onRecommendationsShown,\n  onError,\n  messageId,\n  query,\n  onPasteToInput,\n  followups_container_id: _followups_container_id,\n  onExecuteQuery: _onExecuteQuery,\n\n  onFollowupDetected,\n  isContainerReady,\n  userId: propUserId,\n}: AdMeshRecommendationsProps) => {\n  const { sdk, sessionId, language, geo_country, userId: contextUserId, model, messages, theme } = useAdMesh();\n\n  // Use prop userId if provided, otherwise context userId\n  const userId = propUserId || contextUserId;\n\n  const [recommendation, setRecommendation] = useState<AdMeshRecommendation | null>(null);\n  const [detectedFormat, setDetectedFormat] = useState<string | null>(null);\n  const [isLoading, setIsLoading] = useState(true);\n  const [error, setError] = useState<Error | null>(null);\n\n  // Track fetched messageId to prevent duplicate fetches\n  const fetchedMessageIdRef = useRef<string | null>(null);\n  const isFetchingRef = useRef<boolean>(false);\n\n  // Use refs for callbacks to avoid dependency issues\n  const onRecommendationsShownRef = useRef(onRecommendationsShown);\n  const onErrorRef = useRef(onError);\n  const onFollowupDetectedRef = useRef(onFollowupDetected);\n\n  // Update refs when callbacks change\n  useEffect(() => {\n    onRecommendationsShownRef.current = onRecommendationsShown;\n    onErrorRef.current = onError;\n    onFollowupDetectedRef.current = onFollowupDetected;\n  }, [onRecommendationsShown, onError, onFollowupDetected]);\n\n  // Helper function to convert AIPContextResponse to AdMeshRecommendation format\n  const convertAIPResponseToRecommendation = (aipResponse: any): AdMeshRecommendation => {\n    const responseAny = aipResponse as any;\n    let creativeInput = aipResponse.creative_input || {};\n\n    // Extract format and bridge prompt/content from creative object if present\n    const creative = responseAny.creative || {};\n    const formatFromResponse = creative.format ||\n      responseAny.format ||\n      responseAny.winning_bid?.preferred_format ||\n      (aipResponse.creative_input as any)?.preferred_format;\n\n    // Extract headline from creative if present (for tail and product_card formats)\n    const headlineFromCreative = creative.headline;\n\n    // Extract bridge format fields from creative if present\n    const bridgeHeadlineFromCreative = creative.bridge_headline;\n    const bridgeDescriptionFromCreative = creative.bridge_description;\n    const bridgePromptFromCreative = creative.bridge_prompt || creative.bridge_content;\n    const bridgePrompt = bridgePromptFromCreative ||\n      (creativeInput as any).bridge_prompt ||\n      (creativeInput as any).bridge_content;\n\n    // Extract cta_label from creative if present (for bridge format)\n    const ctaLabelFromCreative = creative.cta_label;\n    const ctaLabel = ctaLabelFromCreative || (creativeInput as any).cta_label;\n\n    // Extract bridge_headline and bridge_description\n    const bridgeHeadline = bridgeHeadlineFromCreative || (creativeInput as any).bridge_headline;\n    const bridgeDescription = bridgeDescriptionFromCreative || (creativeInput as any).bridge_description;\n\n    // Merge creative fields into creative_input\n    // Explicitly preserve assets to ensure logo_url is not lost\n    const preservedAssets = creativeInput.assets || {};\n    creativeInput = {\n      ...creativeInput,\n      // Explicitly preserve assets object to ensure logo_url is maintained\n      assets: preservedAssets,\n      ...(headlineFromCreative && { headline: headlineFromCreative }),\n      ...(bridgeHeadline && { bridge_headline: bridgeHeadline }),\n      ...(bridgeDescription && { bridge_description: bridgeDescription }),\n      ...(bridgePrompt && { bridge_prompt: bridgePrompt }),\n      ...(bridgePrompt && { bridge_content: bridgePrompt }), // Backward compatibility\n      ...(ctaLabel && { cta_label: ctaLabel }),\n      ...(formatFromResponse && { format: formatFromResponse })\n    };\n\n    // Ensure recommendation_id is set\n    const recommendationId = aipResponse.recommendation_id ||\n      (aipResponse as any).bid_id || // Fallback for backward compatibility\n      '';\n\n    // Ensure admesh_link is set (use click_url if not provided)\n    const admeshLink = aipResponse.click_url ||\n      (aipResponse as any).admesh_link ||\n      '';\n\n    // Build recommendation object\n    const recommendation: any = {\n      ...aipResponse,\n      // Ensure recommendation_id is present\n      recommendation_id: recommendationId,\n      // Ensure admesh_link is present (use click_url as fallback)\n      admesh_link: admeshLink || aipResponse.click_url || '',\n      creative_input: creativeInput,\n      // Remove any ad_id or bid_id fields\n      ad_id: undefined,\n      bid_id: undefined,\n      ...(formatFromResponse && { format: formatFromResponse })\n    };\n\n    // Remove ad_id and bid_id if they exist\n    delete recommendation.ad_id;\n    delete recommendation.bid_id;\n\n    // Explicitly preserve followup fields if present in aipResponse (check both top-level and creative_input)\n    // Followup fields can be at top-level (from operator response) or in creative_input (from Firestore)\n    const followupQueryTopLevel = (aipResponse as any).followup_query;\n    const followupQueryInCreative = (aipResponse.creative_input as any)?.followup_query || (creativeInput as any)?.followup_query;\n    const followupQuery = followupQueryTopLevel || followupQueryInCreative;\n\n    const followupEngagementUrlTopLevel = (aipResponse as any).followup_engagement_url;\n    const followupEngagementUrlInCreative = (aipResponse.creative_input as any)?.followup_engagement_url || (creativeInput as any)?.followup_engagement_url;\n    const followupEngagementUrl = followupEngagementUrlTopLevel || followupEngagementUrlInCreative;\n\n    const followupExposureUrlTopLevel = (aipResponse as any).followup_exposure_url;\n    const followupExposureUrlInCreative = (aipResponse.creative_input as any)?.followup_exposure_url || (creativeInput as any)?.followup_exposure_url;\n    const followupExposureUrl = followupExposureUrlTopLevel || followupExposureUrlInCreative;\n\n    if (followupQuery) {\n      recommendation.followup_query = followupQuery;\n      logger.debug('[AdMeshRecommendations] ✅ Extracted followup_query:', followupQuery.substring(0, 50) + '...');\n    }\n    if (followupEngagementUrl) {\n      recommendation.followup_engagement_url = followupEngagementUrl;\n      logger.debug('[AdMeshRecommendations] ✅ Extracted followup_engagement_url');\n    }\n    if (followupExposureUrl) {\n      recommendation.followup_exposure_url = followupExposureUrl;\n      logger.debug('[AdMeshRecommendations] ✅ Extracted followup_exposure_url');\n    }\n\n    return recommendation as AdMeshRecommendation;\n  };\n\n  // Reset fetched ref when messageId changes\n  useEffect(() => {\n    if (fetchedMessageIdRef.current !== messageId) {\n      fetchedMessageIdRef.current = null;\n      setRecommendation(null);\n      setDetectedFormat(null);\n    }\n  }, [messageId]);\n\n  // Find container for followups when recommendation is available\n  const [followupContainer, setFollowupContainer] = useState<Element | null>(null);\n\n  useEffect(() => {\n    // If we don't have a query or container ID, we can't do anything\n    if (!recommendation?.followup_query || !_followups_container_id) {\n      setFollowupContainer(null);\n      return;\n    }\n\n    // If isContainerReady is explicitly provided and false, wait\n    if (isContainerReady === false) {\n      logger.debug(`[AdMeshRecommendations] ⏳ Waiting for container signal...`);\n      return;\n    }\n\n    // Try to find the container\n    let attempts = 0;\n    const maxAttempts = 5; // Reduced from 30 since we now have a signal - just need to handle React render lag\n\n    const checkForContainer = () => {\n      const container = document.getElementById(_followups_container_id);\n      if (container) {\n        logger.debug(`[AdMeshRecommendations] ✅ Found followup container: ${_followups_container_id} `);\n        setFollowupContainer(container);\n        return true;\n      }\n      return false;\n    };\n\n    // Check immediately\n    if (checkForContainer()) return;\n\n    // Short poll to account for React rendering\n    const interval = setInterval(() => {\n      attempts++;\n      if (checkForContainer() || attempts >= maxAttempts) {\n        clearInterval(interval);\n        if (attempts >= maxAttempts) {\n          logger.warn(`[AdMeshRecommendations] ⚠️ Followup container not found after signal: ${_followups_container_id} `);\n        }\n      }\n    }, 100);\n\n    return () => clearInterval(interval);\n  }, [recommendation, _followups_container_id, isContainerReady]);\n\n  // Single fetch effect - fetch recommendation once and detect format\n  useEffect(() => {\n    // Validate required parameters\n    if (!messageId || !query || query.trim() === '') {\n      logger.log('[AdMeshRecommendations] ❌ Validation failed - missing required parameters');\n      setIsLoading(false);\n      return;\n    }\n\n    if (!sdk?.fetchRecommendationFromAIPContext) {\n      logger.log('[AdMeshRecommendations] SDK fetchRecommendationFromAIPContext not available');\n      setIsLoading(false);\n      return;\n    }\n\n    // Prevent duplicate fetches for the same messageId\n    if (fetchedMessageIdRef.current === messageId) {\n      logger.log('[AdMeshRecommendations] ⏭️ Already fetched for this messageId, skipping duplicate fetch');\n      return;\n    }\n\n    // Prevent concurrent fetches\n    if (isFetchingRef.current) {\n      logger.log('[AdMeshRecommendations] ⏭️ Fetch already in progress, skipping duplicate fetch');\n      return;\n    }\n\n    logger.log('[AdMeshRecommendations] 📤 Fetching recommendation from /aip/context (single fetch)');\n\n    const fetchRecommendations = async () => {\n      try {\n        isFetchingRef.current = true;\n        setIsLoading(true);\n        setError(null);\n\n        // Single fetch call\n        // Note: messages is optional - only pass if available\n        const aipResponse = await sdk.fetchRecommendationFromAIPContext({\n          query: query.trim(),\n          sessionId: sessionId,\n          messageId: messageId, // REQUIRED: messageId is mandatory\n          language: language,\n          geo_country: geo_country,\n          userId: userId,\n          model: model,\n          ...(messages && messages.length > 0 && { messages }), // Optional: only pass if messages exist\n        });\n\n        // Convert response to AdMeshRecommendation format\n        const convertedRecommendation = convertAIPResponseToRecommendation(aipResponse);\n\n        // Log followup fields for debugging and call onFollowupDetected if present\n        const followupQuery = (aipResponse as any).followup_query || (convertedRecommendation as any).followup_query;\n        const followupEngagementUrl = (aipResponse as any).followup_engagement_url || (convertedRecommendation as any).followup_engagement_url;\n        const recommendationId = convertedRecommendation.recommendation_id || '';\n\n        // Only require followupQuery to trigger the callback - other fields are optional\n        if (followupQuery) {\n          logger.debug('[AdMeshRecommendations] ✅ Followup query detected:', followupQuery);\n          logger.debug('[AdMeshRecommendations] ✅ Followup engagement URL:', followupEngagementUrl ? 'present' : 'missing');\n          logger.debug('[AdMeshRecommendations] ✅ Recommendation ID:', recommendationId ? recommendationId : 'missing');\n\n          // Log when optional fields are missing\n          if (!followupEngagementUrl) {\n            logger.debug('[AdMeshRecommendations] ⚠️ Followup engagement URL is missing (optional)');\n          }\n          if (!recommendationId) {\n            logger.debug('[AdMeshRecommendations] ⚠️ Recommendation ID is missing (optional)');\n          }\n\n          // SDK-managed rendering: If followups_container_id is provided, use portal rendering\n          // Only use onFollowupDetected callback if container ID is NOT provided (legacy/fallback mode)\n          if (_followups_container_id) {\n            logger.debug('[AdMeshRecommendations] ✅ Using SDK-managed portal rendering (followups_container_id provided)');\n          } else if (onFollowupDetectedRef.current) {\n            // Legacy/fallback: Notify third-party application via callback\n            logger.debug('[AdMeshRecommendations] 🔔 Using legacy callback mode (followups_container_id not provided)');\n            onFollowupDetectedRef.current(followupQuery, followupEngagementUrl || '', recommendationId || '');\n          } else {\n            logger.debug('[AdMeshRecommendations] ⚠️ Followup detected but no rendering method provided (neither followups_container_id nor onFollowupDetected callback)');\n          }\n        }\n\n        setRecommendation(convertedRecommendation);\n\n        // Extract format information - use ONLY preferred_format (single authoritative field from backend)\n        const responseAny = aipResponse as any;\n        const preferredFormat = responseAny.preferred_format ||\n          responseAny.creative?.preferred_format ||\n          responseAny.winning_bid?.preferred_format ||\n          (aipResponse.creative_input as any)?.preferred_format;\n\n        // Format selection logic - use preferred_format directly (no fallbacks)\n        let selectedFormat: string = preferredFormat || 'tail';\n\n        // If weave format is returned, fall back to tail (weave should use WeaveAdFormatContainer)\n        if (selectedFormat === 'weave') {\n          selectedFormat = 'tail';\n        }\n\n        setDetectedFormat(selectedFormat);\n        fetchedMessageIdRef.current = messageId; // Mark as fetched\n        logger.log('[AdMeshRecommendations] 📊 Format detection:', {\n          preferred_format: preferredFormat,\n          selected_format: selectedFormat\n        });\n\n        setIsLoading(false);\n        isFetchingRef.current = false;\n        onRecommendationsShownRef.current?.(messageId);\n      } catch (err) {\n        const error = err instanceof Error ? err : new Error(String(err));\n        // Log error but don't break the UI - network errors are expected in some scenarios\n        if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) {\n          logger.warn(`[AdMeshRecommendations] ⚠️ Network error fetching recommendations(non - critical): ${error.message} `);\n        } else {\n          logger.error(`[AdMeshRecommendations] ❌ Error fetching recommendations: ${error.message} `);\n        }\n        setError(error);\n        setIsLoading(false);\n        isFetchingRef.current = false;\n        onErrorRef.current?.(error);\n      }\n    };\n\n    fetchRecommendations();\n  }, [sdk, sessionId, messageId, query, language, geo_country, userId, model]); // Removed messages, onRecommendationsShown, onError from dependencies\n\n  // Helper to render followup portal\n  const renderFollowupPortal = () => {\n    if (followupContainer && recommendation?.followup_query && sdk) {\n      logger.debug(`[AdMeshRecommendations] 🌀 Rendering followup portal into: ${_followups_container_id} `);\n      return createPortal(\n        <AdMeshFollowup\n          recommendation={recommendation}\n          theme={theme}\n          sdk={sdk}\n          sessionId={sessionId}\n          onExecuteQuery={_onExecuteQuery}\n        />,\n        followupContainer\n      );\n    } else {\n      logger.debug(`[AdMeshRecommendations] ❌ Skipping followup portal.Container: ${!!followupContainer}, Query: ${!!recommendation?.followup_query}, SDK: ${!!sdk} `);\n    }\n    return null;\n  };\n\n  // Don't render anything if validation fails\n  if (!messageId || !query || query.trim() === '') {\n    return null;\n  }\n\n  // Show loading state (optional - can be removed if not needed)\n  if (isLoading) {\n    return null; // Or return a loading spinner if desired\n  }\n\n  // Show error state (optional - can be removed if not needed)\n  if (error) {\n    return null; // Error is already handled by onError callback\n  }\n\n  // Don't render if no recommendation\n  if (!recommendation || !detectedFormat) {\n    return null;\n  }\n\n  // Render appropriate component based on detected format\n  const creativeInput = recommendation.creative_input || {};\n  const hasBridgePrompt = !!(creativeInput as any).bridge_prompt || !!creativeInput.bridge_content;\n  const formatFromRec = (recommendation as any)?.format || (creativeInput as any)?.format;\n  const preferredFormatFromRec = (recommendation as any)?.preferred_format;\n  const hasBridgeFormat = formatFromRec === 'bridge' || preferredFormatFromRec === 'bridge' || detectedFormat === 'bridge';\n\n  // Bridge format detection and rendering\n  if (hasBridgePrompt || hasBridgeFormat) {\n    return (\n      <div className=\"admesh-recommendations-container\" style={{ marginTop: '1rem' }}>\n        <AdMeshBridgeFormat\n          recommendation={recommendation}\n          theme={theme}\n          sessionId={sessionId}\n          onPasteToInput={onPasteToInput}\n        />\n        {renderFollowupPortal()}\n      </div>\n    );\n  }\n\n  // Product card format - render AdMeshEcommerceCards\n  if (detectedFormat === 'product_card') {\n    // Check if recommendation has products array\n    if (recommendation.products && recommendation.products.length > 0) {\n      return (\n        <div className=\"admesh-recommendations-container\" style={{ marginTop: '1rem' }}>\n          <AdMeshEcommerceCards\n            brand={recommendation}\n            theme={theme?.mode === 'dark' ? 'dark' : theme?.mode === 'light' ? 'light' : 'auto'}\n            sessionId={sessionId}\n          />\n          {renderFollowupPortal()}\n        </div>\n      );\n    } else {\n      // Fallback to tail format if products array is missing\n      logger.warn('[AdMeshRecommendations] product_card format detected but no products array, falling back to tail format');\n    }\n  }\n\n  // Tail format (default)\n  const summaryText = creativeInput.long_description ||\n    creativeInput.context_snippet ||\n    creativeInput.short_description ||\n    '';\n\n  return (\n    <div className=\"admesh-recommendations-container\" style={{ marginTop: '1rem' }}>\n      <AdMeshTailAd\n        summaryText={summaryText}\n        recommendations={[recommendation]}\n        theme={theme}\n        sessionId={sessionId}\n      />\n      {renderFollowupPortal()}\n    </div>\n  );\n};\n\nexport default AdMeshRecommendations;\n","'use client';\n\nimport React, { useEffect, useRef, useState } from 'react';\nimport { useAdMesh } from '../hooks/useAdMesh';\nimport { logger } from '../utils/logger';\n\nexport interface WeaveFallbackRecommendationsProps {\n  /** Recommendation format for fallback display\n   *\n   * - 'product': Display as product cards\n   * - 'tail': Display as tail format (default)\n   */\n  format?: 'product' | 'tail';\n\n  /** Optional callback on error */\n  onError?: (error: Error) => void;\n\n  /**\n   * Message ID for per-message recommendations.\n   *\n   * This is the primary identifier for fetching recommendations for a specific message.\n   */\n  messageId: string;\n\n  /**\n   * User query text for generating recommendations.\n   *\n   * This is the query that will be used to fetch recommendations from the backend.\n   * Typically the user's question or search query.\n   *\n   * IMPORTANT: This should be a non-empty string. If not provided or empty,\n   * the component will skip rendering to prevent 400 Bad Request errors.\n   * The backend requires a valid query parameter.\n   */\n  query?: string;\n\n  /**\n   * Fallback state - controls whether to show recommendations\n   * When true, recommendations will be fetched and displayed\n   * When false or undefined, component will not render\n   */\n  fallback?: boolean;\n\n  /**\n   * Previously fetched recommendations from WeaveAdFormatContainer.\n   * If provided and not empty, these will be rendered directly without making a new API call.\n   * Only makes a new API call if this is empty/null/undefined.\n   */\n  previousRecommendations?: any[]; // eslint-disable-line @typescript-eslint/no-explicit-any\n}\n\n/**\n * WeaveFallbackRecommendations - Weave Format Fallback Component\n *\n * Displays recommendations as a fallback UI when no AdMesh links are detected\n * in the LLM response. Works independently without requiring WeaveAdFormatContext.\n *\n * This component will:\n * - Accept messageId, query, and fallback state as props\n * - Only render when fallback prop is true\n * - If previousRecommendations are provided and not empty: renders them directly (no API call)\n * - If previousRecommendations are empty/null: calls SDK's showRecommendations() to fetch recommendations\n * - Display recommendations in the specified format (tail or product)\n *\n * IMPORTANT: Pass previousRecommendations from WeaveAdFormatContainer to avoid duplicate API calls.\n *\n * @example\n * ```tsx\n * const [fallback, setFallback] = useState(false);\n *\n * <AdMeshProvider apiKey={apiKey} sessionId={sessionId}>\n *   <WeaveAdFormatContainer\n *     messageId={message.id}\n *     query={userQuery}\n *     onFallbackChange={setFallback}\n *   >\n *     {llmResponseContent}\n *   </WeaveAdFormatContainer>\n *   <WeaveFallbackRecommendations\n *     messageId={message.id}\n *     query={userQuery}\n *     format=\"tail\"\n *     fallback={fallback}\n *     previousRecommendations={recommendations} // Pass from WeaveAdFormatContainer\n *   />\n * </AdMeshProvider>\n * ```\n */\nexport const WeaveFallbackRecommendations: React.FC<WeaveFallbackRecommendationsProps> = ({\n  format = 'tail',\n  onError,\n  messageId,\n  query,\n  fallback,\n  previousRecommendations,\n}) => {\n  const { sdk, sessionId, theme, apiKey, language, geo_country, userId, model, messages } = useAdMesh();\n  const containerRef = useRef<HTMLDivElement>(null);\n  const [containerId, setContainerId] = useState<string>('');\n\n  // Generate container ID based on message ID\n  useEffect(() => {\n    if (messageId) {\n      setContainerId(`admesh-weave-fallback-${messageId}`);\n    }\n  }, [messageId]);\n\n  // Log component render\n  logger.log('[WeaveFallbackRecommendations] 🎨 Component render');\n\n  useEffect(() => {\n    // Log what we're receiving\n    logger.log('[WeaveFallbackRecommendations] 🔄 useEffect triggered', {\n      fallback,\n      hasPreviousRecommendations: previousRecommendations && previousRecommendations.length > 0,\n      previousRecommendationsCount: previousRecommendations?.length || 0\n    });\n\n    // Skip if fallback is not true\n    if (!fallback) {\n      logger.log('[WeaveFallbackRecommendations] ⏭️  Skipping - fallback is FALSE, not rendering recommendations');\n      return;\n    }\n\n    logger.log('[WeaveFallbackRecommendations] ✅ fallback is TRUE, proceeding with recommendations');\n\n    // Validate required parameters\n    if (!messageId || !query || query.trim() === '') {\n      logger.log('[WeaveFallbackRecommendations] ❌ Validation failed - returning early');\n      return;\n    }\n\n    logger.log('[WeaveFallbackRecommendations] ✅ Validation passed');\n\n    if (!sdk || !containerId) {\n      logger.log('[WeaveFallbackRecommendations] SDK or containerId not ready');\n      return;\n    }\n\n    // Check if we have previous recommendations to reuse\n    const hasPreviousRecs = previousRecommendations && previousRecommendations.length > 0;\n    \n    logger.log('[WeaveFallbackRecommendations] 📊 Checking previous recommendations:', {\n      hasPreviousRecs,\n      count: previousRecommendations?.length || 0,\n      fallback,\n      messageId\n    });\n    \n    if (hasPreviousRecs) {\n      // Use previous recommendations - render directly without API call\n      logger.log(`[WeaveFallbackRecommendations] ♻️  Reusing ${previousRecommendations.length} previous recommendation(s), skipping API call`);\n      \n      const renderRecommendations = async () => {\n        try {\n          const aipResponse = previousRecommendations[0];\n          \n          logger.log('[WeaveFallbackRecommendations] 📦 Processing AIP response:', {\n            hasAipResponse: !!aipResponse,\n            recommendationId: aipResponse?.recommendation_id,\n            hasCreativeInput: !!aipResponse?.creative_input\n          });\n          \n          // Development logging: Log full recommendation details\n          if (aipResponse && process.env.NODE_ENV === 'development') {\n            logger.log('[WeaveFallbackRecommendations] 📋 Recommendation received (DEV):', {\n              recommendation_id: aipResponse.recommendation_id,\n              product_id: aipResponse.product_id,\n              brand_id: aipResponse.brand_id,\n              title: aipResponse.title,\n              click_url: aipResponse.click_url,\n              contextual_relevance_score: aipResponse.contextual_relevance_score,\n              preferred_format: aipResponse.creative_input?.preferred_format,\n              resolved_format: aipResponse.format_resolution?.resolved_format,\n              creative_input: {\n                product_name: aipResponse.creative_input?.product_name,\n                brand_name: aipResponse.creative_input?.brand_name,\n                cta_url: aipResponse.creative_input?.cta_url,\n                short_description: aipResponse.creative_input?.short_description,\n                allowed_formats: aipResponse.creative_input?.allowed_formats,\n                fallback_formats: aipResponse.creative_input?.fallback_formats,\n              },\n              format_resolution: aipResponse.format_resolution,\n              full_response: aipResponse\n            });\n          }\n          \n          if (!aipResponse) {\n            logger.warn('[WeaveFallbackRecommendations] ⚠️ Previous recommendation is empty, falling back to API call');\n            await sdk.showRecommendations({\n              query: query.trim(),\n              containerId,\n              session_id: sessionId,\n              messageId: messageId,\n            });\n            return;\n          }\n\n          // Try to access SDK's private methods via type casting\n          // These are used internally by showRecommendations\n          const sdkAny = sdk as any;\n          const convertMethod = sdkAny.convertAIPResponseToRecommendation;\n          const getRendererMethod = sdkAny.getRenderer;\n          const getTrackerMethod = sdkAny.getTracker;\n          const sdkTheme = sdkAny.config?.theme;\n\n          if (convertMethod && getRendererMethod && getTrackerMethod) {\n            // Convert AIP response to recommendation format (same as showRecommendations does)\n            const recommendation = convertMethod.call(sdk, aipResponse);\n            \n            if (!recommendation) {\n              logger.warn('[WeaveFallbackRecommendations] ⚠️ Conversion returned empty, falling back to API call');\n              await sdk.showRecommendations({\n                query: query.trim(),\n                containerId,\n                session_id: sessionId,\n                messageId: messageId,\n              });\n              return;\n            }\n\n            const response = {\n              session_id: aipResponse.session_id || sessionId,\n              message_id: `msg_${aipResponse.recommendation_id || messageId}`,\n              recommendations: [recommendation]\n            };\n\n            // Get renderer and tracker\n            const renderer = getRendererMethod.call(sdk);\n            const tracker = getTrackerMethod.call(sdk);\n            \n            // Get apiBaseUrl from SDK instance\n            const apiBaseUrl = (sdk as any)?.apiBaseUrl || \n                              (typeof window !== 'undefined' && (window as any).__ADMESH_API_BASE_URL__) ||\n                              'https://api.useadmesh.com';\n            \n            // Render directly - pass all required props for AdMeshProvider\n            await renderer.render({\n              containerId,\n              response,\n              theme: theme || sdkTheme,\n              tracker: tracker,\n              sessionId: sessionId,\n              apiKey: apiKey || (sdk as any)?.config?.apiKey,\n              apiBaseUrl: apiBaseUrl,\n              language: language,\n              geo_country: geo_country,\n              userId: userId,\n              model: model,\n              messages: messages,\n            });\n            \n            logger.log('[WeaveFallbackRecommendations] ✅ Recommendations rendered from previous response (no API call)');\n          } else {\n            // SDK methods not accessible - fall back to showRecommendations\n            // This will use the cached result from auction coordination, so it's still fast\n            logger.warn('[WeaveFallbackRecommendations] ⚠️ SDK internal methods not accessible, using showRecommendations (will use cached result)');\n            await sdk.showRecommendations({\n              query: query.trim(),\n              containerId,\n              session_id: sessionId,\n              messageId: messageId,\n            });\n          }\n        } catch (error) {\n          const err = error instanceof Error ? error : new Error(String(error));\n          logger.error(`[WeaveFallbackRecommendations] ❌ Error rendering previous recommendations: ${err.message}`);\n          // Fallback to API call on error (will use cached result)\n          try {\n            await sdk.showRecommendations({\n              query: query.trim(),\n              containerId,\n              session_id: sessionId,\n              messageId: messageId,\n            });\n          } catch (fallbackError) {\n            onError?.(err);\n          }\n        }\n      };\n\n      renderRecommendations();\n    } else {\n      // No previous recommendations - make new API call\n      logger.log('[WeaveFallbackRecommendations] 📤 No previous recommendations, calling sdk.showRecommendations');\n      \n      const fetchRecommendations = async () => {\n        try {\n          if (!sdk?.showRecommendations) {\n            logger.log('[WeaveFallbackRecommendations] SDK showRecommendations not available');\n            return;\n          }\n\n          await sdk.showRecommendations({\n            query: query.trim(),\n            containerId,\n            session_id: sessionId,\n            messageId: messageId, // REQUIRED: messageId must be provided by platform\n          });\n\n          logger.log('[WeaveFallbackRecommendations] ✅ Recommendations displayed successfully');\n        } catch (error) {\n          const err = error instanceof Error ? error : new Error(String(error));\n          logger.log(`[WeaveFallbackRecommendations] ❌ Error: ${err.message}`);\n          onError?.(err);\n        }\n      };\n\n      fetchRecommendations();\n    }\n  }, [sdk, sessionId, containerId, format, messageId, query, fallback, onError, previousRecommendations, theme]);\n\n  // Don't render anything if fallback is not active or validation fails\n  if (!fallback || !messageId || !query || query.trim() === '') {\n    return null;\n  }\n\n  // Render the container where fallback recommendations will be displayed\n  // Use display: 'none' initially to prevent taking up space until recommendations are loaded\n  // The SDK will set display: 'block' when it renders content\n  return (\n    <div\n      ref={containerRef}\n      id={containerId}\n      className=\"admesh-weave-fallback-recommendations-container\"\n      style={{\n        marginTop: '1rem',\n        display: 'none', // Hidden by default, SDK will show when recommendations are rendered\n      }}\n    />\n  );\n};\n\nexport default WeaveFallbackRecommendations;\n","'use client';\n\nimport React, { createContext, useContext } from 'react';\n\nexport interface WeaveAdFormatContextType {\n  /** Whether the fallback UI should be rendered (no AdMesh links detected) */\n  shouldRenderFallback: boolean;\n  /** The message ID for this Weave Ad Format container (used for deduplication) */\n  messageId: string;\n  /** The session ID for this Weave Ad Format container (used for tracking) */\n  sessionId?: string;\n  /** The query for this message (used for fallback API calls) */\n  query?: string;\n}\n\nconst WeaveAdFormatContext = createContext<WeaveAdFormatContextType | undefined>(undefined);\n\nexport const WeaveAdFormatProvider: React.FC<{\n  children: React.ReactNode;\n  shouldRenderFallback: boolean;\n  messageId: string;\n  sessionId?: string;\n  query?: string;\n}> = ({ children, shouldRenderFallback, messageId, sessionId, query }) => {\n  return (\n    <WeaveAdFormatContext.Provider value={{ shouldRenderFallback, messageId, sessionId, query }}>\n      {children}\n    </WeaveAdFormatContext.Provider>\n  );\n};\n\n/**\n * Hook to access WeaveAdFormatContext\n * \n * Returns the context value if inside a WeaveAdFormatContainer,\n * or undefined if not inside one.\n * \n * @example\n * ```tsx\n * const weaveContext = useWeaveAdFormatContext();\n * if (weaveContext) {\n *   // Inside a WeaveAdFormatContainer\n *   const { shouldRenderFallback, messageId } = weaveContext;\n * }\n * ```\n */\nexport const useWeaveAdFormatContext = (): WeaveAdFormatContextType | undefined => {\n  return useContext(WeaveAdFormatContext);\n};\n\nexport default WeaveAdFormatContext;\n\n","import React from 'react';\nimport classNames from 'classnames';\nimport type { AdMeshBadgeProps, BadgeType } from '../types/index';\n\n// Badge type to variant mapping\nconst badgeTypeVariants: Record<BadgeType, string> = {\n  'Top Match': 'primary',\n  'Free Tier': 'success',\n  'AI Powered': 'secondary',\n  'Popular': 'warning',\n  'New': 'primary',\n  'Trial Available': 'success'\n};\n\n// Badge type to icon mapping (using clean Unicode symbols)\nconst badgeTypeIcons: Partial<Record<BadgeType, string>> = {\n  'Top Match': '★',\n  'Free Tier': '◆',\n  'AI Powered': '◉',\n  'Popular': '▲',\n  'New': '●',\n  'Trial Available': '◈'\n};\n\nexport const AdMeshBadge: React.FC<AdMeshBadgeProps> = ({\n  type,\n  variant,\n  size = 'md',\n  className,\n  style\n}) => {\n  const effectiveVariant = variant || badgeTypeVariants[type] || 'secondary';\n  const icon = badgeTypeIcons[type];\n\n  const badgeClasses = classNames(\n    'admesh-component',\n    'admesh-badge',\n    `admesh-badge--${effectiveVariant}`,\n    `admesh-badge--${size}`,\n    className\n  );\n\n  return (\n    <span\n      className={badgeClasses}\n      style={style}\n    >\n      {icon && <span className=\"admesh-badge__icon\">{icon}</span>}\n      <span className=\"admesh-badge__text\">{type}</span>\n    </span>\n  );\n};\n\nAdMeshBadge.displayName = 'AdMeshBadge';\n","/**\n * Streaming Events Utilities\n * \n * Custom event system for communicating LLM streaming lifecycle events\n * between the chat frontend and AdMesh WeaveAdFormatContainer.\n * \n * This allows WeaveAdFormatContainer to trigger final link detection\n * when streaming completes, rather than using arbitrary timeouts.\n */\n\nimport { logger } from './logger';\n\nexport const STREAMING_START_EVENT = 'admesh:streamingStart';\nexport const STREAMING_COMPLETE_EVENT = 'admesh:streamingComplete';\n\nexport interface StreamingStartEventDetail {\n  messageId: string;\n  sessionId: string;\n  timestamp: number;\n}\n\nexport interface StreamingCompleteEventDetail {\n  messageId: string;\n  sessionId: string;\n  timestamp: number;\n  metadata?: {\n    hasRecommendations?: boolean;\n    recommendationCount?: number;\n  };\n}\n\n/**\n * Dispatch a streaming start event\n * \n * Call this when the backend starts streaming the LLM response.\n * This signals to WeaveAdFormatContainer that content is being received.\n * \n * @param messageId - Unique identifier for the message\n * @param sessionId - Session/chat identifier\n */\nexport function dispatchStreamingStartEvent(\n  messageId: string,\n  sessionId: string\n): void {\n  const detail: StreamingStartEventDetail = {\n    messageId,\n    sessionId,\n    timestamp: Date.now(),\n  };\n\n  const event = new CustomEvent(STREAMING_START_EVENT, { detail });\n  window.dispatchEvent(event);\n\n  logger.log('[StreamingEvents] 📢 Dispatched streamingStart event', {\n    messageId,\n    sessionId\n  });\n}\n\n/**\n * Dispatch a streaming complete event\n * \n * Call this when the backend finishes streaming the LLM response.\n * This triggers WeaveAdFormatContainer to perform final link detection.\n * \n * @param messageId - Unique identifier for the message\n * @param sessionId - Session/chat identifier\n * @param metadata - Optional metadata about recommendations\n */\nexport function dispatchStreamingCompleteEvent(\n  messageId: string,\n  sessionId: string,\n  metadata?: {\n    hasRecommendations?: boolean;\n    recommendationCount?: number;\n  }\n): void {\n  const detail: StreamingCompleteEventDetail = {\n    messageId,\n    sessionId,\n    timestamp: Date.now(),\n    metadata,\n  };\n\n  const event = new CustomEvent(STREAMING_COMPLETE_EVENT, { detail });\n  window.dispatchEvent(event);\n\n  logger.log('[StreamingEvents] 📢 Dispatched streamingComplete event', {\n    messageId,\n    sessionId,\n    metadata\n  });\n}\n\n/**\n * Listen for streaming start events\n * \n * @param messageId - Filter events by this messageId\n * @param sessionId - Filter events by this sessionId\n * @param callback - Called when matching event is received\n * @returns Cleanup function to remove the event listener\n */\nexport function onStreamingStart(\n  messageId: string,\n  sessionId: string,\n  callback: (detail: StreamingStartEventDetail) => void\n): () => void {\n  const handler = (event: Event) => {\n    const customEvent = event as CustomEvent<StreamingStartEventDetail>;\n    \n    // Only trigger callback if this is the message we're waiting for\n    if (\n      customEvent.detail.messageId === messageId &&\n      customEvent.detail.sessionId === sessionId\n    ) {\n      logger.log('[StreamingEvents] 📨 Received streamingStart event');\n      callback(customEvent.detail);\n    }\n  };\n\n  window.addEventListener(STREAMING_START_EVENT, handler);\n\n  // Return cleanup function\n  return () => {\n    window.removeEventListener(STREAMING_START_EVENT, handler);\n  };\n}\n\n/**\n * Listen for streaming complete events\n * \n * @param messageId - Filter events by this messageId\n * @param sessionId - Filter events by this sessionId\n * @param callback - Called when matching event is received\n * @returns Cleanup function to remove the event listener\n */\nexport function onStreamingComplete(\n  messageId: string,\n  sessionId: string,\n  callback: (detail: StreamingCompleteEventDetail) => void\n): () => void {\n  logger.log('[StreamingEvents] 👂 Setting up streamingComplete listener', {\n    expectedMessageId: messageId,\n    expectedSessionId: sessionId\n  });\n\n  const handler = (event: Event) => {\n    const customEvent = event as CustomEvent<StreamingCompleteEventDetail>;\n    \n    logger.log('[StreamingEvents] 📨 Received streamingComplete event (checking match)', {\n      receivedMessageId: customEvent.detail.messageId,\n      receivedSessionId: customEvent.detail.sessionId,\n      expectedMessageId: messageId,\n      expectedSessionId: sessionId,\n      messageIdMatch: customEvent.detail.messageId === messageId,\n      sessionIdMatch: customEvent.detail.sessionId === sessionId\n    });\n    \n    // Only trigger callback if this is the message we're waiting for\n    if (\n      customEvent.detail.messageId === messageId &&\n      customEvent.detail.sessionId === sessionId\n    ) {\n      logger.log('[StreamingEvents] ✅ Event matched! Calling callback');\n      callback(customEvent.detail);\n    } else {\n      logger.log('[StreamingEvents] ⚠️ Event did not match - ignoring');\n    }\n  };\n\n  window.addEventListener(STREAMING_COMPLETE_EVENT, handler);\n\n  // Return cleanup function\n  return () => {\n    logger.log('[StreamingEvents] 🧹 Removing streamingComplete listener');\n    window.removeEventListener(STREAMING_COMPLETE_EVENT, handler);\n  };\n}\n","import { logger } from './logger';\n\ninterface InlineExposureTrackerState {\n  observer: IntersectionObserver;\n  timeoutId: ReturnType<typeof setTimeout> | null;\n  viewableStart: number | null;\n}\n\nexport interface InlineExposureTrackingParams {\n  exposureUrl?: string;\n  recommendationId?: string;\n  linkElement?: HTMLElement | null;\n  sessionId?: string;\n  logPrefix?: string;\n}\n\nexport interface InlineExposureTracker {\n  startTracking: (params: InlineExposureTrackingParams) => void;\n  cleanup: () => void;\n}\n\n/**\n * Creates an inline exposure tracker that fires AdMesh exposure pixels when\n * detected links meet the MRC viewability threshold (50% visible for 1 second).\n */\nexport const createInlineExposureTracker = (): InlineExposureTracker => {\n  const firedKeys = new Set<string>();\n  const activeTrackers = new Map<string, InlineExposureTrackerState>();\n\n  const cleanupTracker = (key: string) => {\n    const tracker = activeTrackers.get(key);\n    if (!tracker) {\n      return;\n    }\n    tracker.observer.disconnect();\n    if (tracker.timeoutId) {\n      clearTimeout(tracker.timeoutId);\n    }\n    activeTrackers.delete(key);\n  };\n\n  const startTracking = ({\n    exposureUrl,\n    recommendationId,\n    linkElement,\n    sessionId,\n    logPrefix = '[AdMesh Exposure]'\n  }: InlineExposureTrackingParams) => {\n    if (typeof window === 'undefined') {\n      return;\n    }\n\n    if (!exposureUrl || !linkElement) {\n      if (logPrefix) {\n        logger.warn(`${logPrefix} ⚠️ Missing exposure tracking data`);\n      }\n      return;\n    }\n\n    const dedupeKey = `${sessionId || 'anonymous'}::${recommendationId || exposureUrl}`;\n\n    if (firedKeys.has(dedupeKey) || activeTrackers.has(dedupeKey)) {\n      return;\n    }\n\n    const trackerState: InlineExposureTrackerState = {\n      observer: undefined as unknown as IntersectionObserver,\n      timeoutId: null,\n      viewableStart: null\n    };\n\n    const fireExposurePixel = () => {\n      cleanupTracker(dedupeKey);\n      firedKeys.add(dedupeKey);\n\n      fetch(exposureUrl, { method: 'GET', keepalive: true })\n        .then(() => {\n          if (logPrefix) {\n            logger.log(`${logPrefix} ✅ Exposure pixel fired`);\n          }\n        })\n        .catch(() => {\n          if (logPrefix) {\n            logger.warn(`${logPrefix} ⚠️ Failed to fire exposure pixel`);\n          }\n          firedKeys.delete(dedupeKey);\n        });\n    };\n\n    const observer = new IntersectionObserver(\n      (entries) => {\n        entries.forEach((entry) => {\n          const visibility = entry.intersectionRatio;\n\n          if (visibility >= 0.5) {\n            if (trackerState.viewableStart === null) {\n              trackerState.viewableStart = performance.now();\n              trackerState.timeoutId = setTimeout(fireExposurePixel, 1000);\n            }\n          } else {\n            trackerState.viewableStart = null;\n            if (trackerState.timeoutId) {\n              clearTimeout(trackerState.timeoutId);\n              trackerState.timeoutId = null;\n            }\n          }\n        });\n      },\n      {\n        threshold: [0, 0.25, 0.5, 0.75, 1],\n        rootMargin: '0px'\n      }\n    );\n\n    trackerState.observer = observer;\n    observer.observe(linkElement as Element);\n    activeTrackers.set(dedupeKey, trackerState);\n  };\n\n  const cleanup = () => {\n    Array.from(activeTrackers.keys()).forEach(cleanupTracker);\n  };\n\n  return {\n    startTracking,\n    cleanup\n  };\n};\n","'use client';\n\nimport React, { useRef, useState, useEffect, useCallback } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useAdMesh } from '../hooks/useAdMesh';\nimport { WeaveFallbackRecommendations } from './WeaveFallbackRecommendations';\nimport { AdMeshFollowup } from './AdMeshFollowup';\nimport { onStreamingComplete } from '../utils/streamingEvents';\nimport {\n  createInlineExposureTracker,\n  type InlineExposureTrackingParams\n} from '../utils/inlineExposureTracker';\nimport { WeaveResponseProcessor } from '../sdk/WeaveResponseProcessor';\nimport { logger } from '../utils/logger';\nimport type { AdMeshRecommendation } from '../types/index';\n\n/**\n * FinalLinkDetectionCheck - Event-driven link detection component\n *\n * This component waits for the 'admesh:streamingComplete' event from ChatWindow\n * before performing final link detection. This eliminates race conditions where\n * timeout-based detection would trigger before streaming completes.\n */\ninterface FinalLinkDetectionCheckProps {\n  containerId: string;\n  messageId: string;\n  sessionId: string;\n  sdk: any; // eslint-disable-line @typescript-eslint/no-explicit-any\n  query?: string;\n  recommendations?: any[]; // eslint-disable-line @typescript-eslint/no-explicit-any\n  onLinksFound: (count: number) => void;\n  onNoLinksFound: () => void;\n  children: React.ReactNode;\n}\n\nconst FinalLinkDetectionCheck: React.FC<FinalLinkDetectionCheckProps> = ({\n  containerId,\n  messageId,\n  sessionId,\n  sdk,\n  query,\n  recommendations = [],\n  onLinksFound,\n  onNoLinksFound,\n  children\n}) => {\n  const [checkComplete, setCheckComplete] = useState(false);\n  const [waitingForStreamEnd, setWaitingForStreamEnd] = useState(true);\n  const [linksFound, setLinksFound] = useState(false);\n  const exposureTrackerRef = useRef(createInlineExposureTracker());\n\n  // Use refs to avoid recreating the callback on every render\n  const onLinksFoundRef = useRef(onLinksFound);\n  const onNoLinksFoundRef = useRef(onNoLinksFound);\n  const containerIdRef = useRef(containerId);\n  const sdkRef = useRef(sdk);\n  const sessionIdRef = useRef(sessionId);\n  const queryRef = useRef(query);\n\n  // Update refs when values change\n  useEffect(() => {\n    onLinksFoundRef.current = onLinksFound;\n    onNoLinksFoundRef.current = onNoLinksFound;\n    containerIdRef.current = containerId;\n    sdkRef.current = sdk;\n    sessionIdRef.current = sessionId;\n    queryRef.current = query;\n  }, [onLinksFound, onNoLinksFound, containerId, sdk, sessionId, query]);\n\n  useEffect(() => {\n    return () => {\n      exposureTrackerRef.current.cleanup();\n    };\n  }, []);\n\n  const trackExposurePixel = useCallback(\n    ({ exposureUrl, recommendationId, linkElement }: InlineExposureTrackingParams) => {\n      exposureTrackerRef.current.startTracking({\n        exposureUrl,\n        recommendationId,\n        linkElement,\n        sessionId: sessionIdRef.current,\n        logPrefix: '[FinalLinkDetectionCheck]'\n      });\n    },\n    []\n  );\n\n  const performFinalCheck = useCallback(() => {\n    logger.log('[FinalLinkDetectionCheck] 🔍 Performing final link detection...');\n\n    try {\n      const container = document.getElementById(containerIdRef.current);\n      if (!container) {\n        logger.warn('[FinalLinkDetectionCheck] ❌ Container not found');\n        setCheckComplete(true);\n        onNoLinksFound();\n        return;\n      }\n\n      // Create WeaveResponseProcessor instance\n      const weaveProcessor = new WeaveResponseProcessor({\n        autoAddLabels: true,\n        fireExposurePixels: true\n      });\n\n      // Use fetched recommendations if available, otherwise fall back to pattern-based detection\n      const recsToUse = recommendations.length > 0 ? recommendations : [];\n      logger.log(`[FinalLinkDetectionCheck] 📋 Using ${recsToUse.length} recommendations for link detection`);\n      \n      // Development logging: Log recommendation details used for link detection\n      if (recsToUse.length > 0 && process.env.NODE_ENV === 'development') {\n        recsToUse.forEach((rec, index) => {\n          logger.log(`[FinalLinkDetectionCheck] 📋 Recommendation ${index + 1} (DEV):`, {\n            recommendation_id: rec.recommendation_id,\n            product_id: rec.product_id,\n            title: rec.title,\n            click_url: rec.click_url,\n            preferred_format: rec.creative_input?.preferred_format,\n            resolved_format: rec.format_resolution?.resolved_format,\n            creative_input: {\n              product_name: rec.creative_input?.product_name,\n              brand_name: rec.creative_input?.brand_name,\n              cta_url: rec.creative_input?.cta_url,\n            }\n          });\n        });\n      }\n\n      // Scan for AdMesh links one final time\n      const detectedLinks = weaveProcessor.scanAndProcessLinks(\n        container,\n        recsToUse, // Use fetched recommendations for brand URL matching\n        ({ exposureUrl, recommendationId, linkElement }: InlineExposureTrackingParams) =>\n          trackExposurePixel({ exposureUrl, recommendationId, linkElement })\n      );\n\n      logger.log(`[FinalLinkDetectionCheck] 📊 Final check result: ${detectedLinks.length} links`);\n\n      if (detectedLinks.length > 0) {\n        // Links found! Cancel fallback\n        logger.log('[FinalLinkDetectionCheck] ✅ Links detected - canceling fallback (no API call)');\n        setLinksFound(true);\n        onLinksFoundRef.current(detectedLinks.length);\n      } else {\n        // No links found, proceed with fallback\n        logger.log(`[FinalLinkDetectionCheck] ⚠️ No links found - rendering fallback (will use ${recsToUse.length} previous recommendation(s) if available)`);\n        setLinksFound(false);\n        onNoLinksFoundRef.current();\n      }\n\n      setCheckComplete(true);\n    } catch (error) {\n      logger.error('[FinalLinkDetectionCheck] ❌ Error during final check');\n      setCheckComplete(true);\n      onNoLinksFoundRef.current();\n    }\n  }, [trackExposurePixel, recommendations]);\n\n  useEffect(() => {\n    logger.log('[FinalLinkDetectionCheck] ⏳ Setting up listener', {\n      messageId,\n      sessionId,\n      recommendationsCount: recommendations.length\n    });\n\n    let timeoutId: NodeJS.Timeout | null = null;\n    let eventReceived = false;\n\n    // Listen for the streamingComplete event from ChatWindow\n    const cleanup = onStreamingComplete(messageId, sessionId, (detail) => {\n      logger.log('[FinalLinkDetectionCheck] 🎯 Received streamingComplete event', {\n        messageId: detail.messageId,\n        sessionId: detail.sessionId,\n        timestamp: detail.timestamp\n      });\n      eventReceived = true;\n      \n      // Clear timeout since event was received\n      if (timeoutId) {\n        clearTimeout(timeoutId);\n        timeoutId = null;\n      }\n      \n      setWaitingForStreamEnd(false);\n\n      // Small delay to ensure DOM is fully updated\n      setTimeout(() => {\n        performFinalCheck();\n      }, 100);\n    });\n\n    // Fallback timeout: If streamingComplete doesn't fire within 5 seconds, trigger check anyway\n    // This ensures fallback recommendations display even if event system fails\n    timeoutId = setTimeout(() => {\n      if (!eventReceived) {\n        logger.warn('[FinalLinkDetectionCheck] ⏱️ Timeout: streamingComplete event not received, triggering fallback check anyway');\n        setWaitingForStreamEnd(false);\n        setTimeout(() => {\n          performFinalCheck();\n        }, 100);\n      }\n    }, 5000); // 5 second timeout\n\n    return () => {\n      logger.log('[FinalLinkDetectionCheck] 🧹 Cleaning up listener');\n      if (timeoutId) {\n        clearTimeout(timeoutId);\n      }\n      cleanup();\n    };\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [messageId, sessionId]); // performFinalCheck depends on recommendations prop, but recommendations should be stable for a given messageId\n\n  // Show loading state while waiting for stream to complete\n  if (waitingForStreamEnd) {\n    return <></>;\n  }\n\n  // Show checking state while performing final detection\n  if (!checkComplete) {\n    return <></>;\n  }\n\n  // Only render children (fallback) if NO links were found\n  if (linksFound) {\n    logger.log('[FinalLinkDetectionCheck] 🚫 Links found - NOT rendering fallback');\n    return <></>;\n  }\n\n  logger.log('[FinalLinkDetectionCheck] ✅ No links found - rendering fallback');\n  return <>{children}</>;\n};\n\nexport interface WeaveAdFormatContainerProps {\n  /** Unique ID for this message container */\n  messageId: string;\n\n  /** The LLM response content (may contain AdMesh links) */\n  children: React.ReactNode;\n\n  /** Fallback format if no links detected (default: 'tail') */\n  fallbackFormat?: 'product' | 'tail';\n\n  /** Optional callback when AdMesh links are detected */\n  onLinksDetected?: (count: number) => void;\n\n  /** Optional callback when no links are detected (fallback should be rendered) */\n  onNoLinksDetected?: () => void;\n\n  /** Optional callback on error */\n  onError?: (error: Error) => void;\n\n  /** Optional CSS class for the container */\n  className?: string;\n\n  /** Optional query text for fallback API calls (used when no links are detected) */\n  query?: string;\n\n  /** Optional callback to notify parent when fallback state changes */\n  onFallbackChange?: (shouldFallback: boolean) => void;\n\n  /** Optional callback when weave injection is attempted */\n  onWeaveAttempt?: (messageId: string) => void;\n\n  /** Optional callback when weave injection outcome is determined */\n  onWeaveOutcome?: (messageId: string, success: boolean, reason?: string) => void;\n\n  /** Optional container ID for follow-up suggestions */\n  followups_container_id?: string;\n\n  /** Callback to execute query when follow-up is selected (required for follow-up functionality) */\n  onExecuteQuery?: (query: string) => void | Promise<void>;\n\n  /** Optional callback when a sponsored followup is detected */\n  onFollowupDetected?: (followupQuery: string, followupEngagementUrl: string, recommendationId: string) => void;\n\n  /** Signal indicating if the followup container is ready in the DOM */\n  isContainerReady?: boolean;\n}\n\n/**\n * WeaveAdFormatContainer - Automatic Weave Ad Format handling component\n *\n * Wraps LLM response content and automatically:\n * - Detects AdMesh links in the content\n * - Fires exposure tracking for detected links\n * - Adds [Ad] labels to links\n * - Shows \"Why this ad?\" tooltip on hover\n * - Provides context for WeaveFallbackRecommendations component\n *\n * @example\n * ```tsx\n * <WeaveAdFormatContainer\n *   messageId={message.id}\n *   query={userQuery}\n *   onLinksDetected={(count) => console.log(`Found ${count} ads`)}\n * >\n *   {llmResponseContent}\n * </WeaveAdFormatContainer>\n * ```\n */\nexport const WeaveAdFormatContainer: React.FC<WeaveAdFormatContainerProps> = ({\n  messageId,\n  children,\n  fallbackFormat = 'tail',\n  onLinksDetected,\n  onNoLinksDetected,\n  onError,\n  className,\n  query,\n  onFallbackChange,\n  onWeaveAttempt,\n  onWeaveOutcome,\n  followups_container_id: _followups_container_id,\n  onExecuteQuery: _onExecuteQuery,\n  onFollowupDetected,\n  isContainerReady\n}) => {\n  const { sessionId, sdk, language, geo_country, userId, model, messages, theme } = useAdMesh();\n  const containerRef = useRef<HTMLDivElement>(null);\n  const containerId = `weave-ad-container-${messageId}`;\n  const exposureTrackerRef = useRef(createInlineExposureTracker());\n  const scannedRef = useRef(false);\n  const weaveProcessorRef = useRef<WeaveResponseProcessor | null>(null);\n  const [recommendations, setRecommendations] = useState<any[]>([]);\n  const recommendationsRef = useRef<any[]>([]);\n  const [recommendationWithFollowup, setRecommendationWithFollowup] = useState<AdMeshRecommendation | null>(null);\n  const [followupContainer, setFollowupContainer] = useState<Element | null>(null);\n\n  // Use refs for callbacks to avoid dependency issues\n  const onFollowupDetectedRef = useRef(onFollowupDetected);\n  \n  // Update refs when callbacks change\n  useEffect(() => {\n    onFollowupDetectedRef.current = onFollowupDetected;\n  }, [onFollowupDetected]);\n\n  // Initialize WeaveResponseProcessor once\n  useEffect(() => {\n    if (!weaveProcessorRef.current) {\n      weaveProcessorRef.current = new WeaveResponseProcessor({\n        autoAddLabels: true,\n        fireExposurePixels: true\n      });\n    }\n    return () => {\n      if (weaveProcessorRef.current) {\n        weaveProcessorRef.current.stopWatching();\n        weaveProcessorRef.current.clearCache();\n      }\n    };\n  }, []);\n\n  // Cleanup exposure tracker on unmount\n  useEffect(() => {\n    return () => {\n      exposureTrackerRef.current.cleanup();\n    };\n  }, []);\n\n  // Fetch recommendations from SDK cache if available\n  useEffect(() => {\n    const fetchRecommendations = async () => {\n      if (!sdk || !query?.trim() || !messageId) {\n        logger.log('[WeaveAdFormatContainer] ⚠️ Missing SDK, query, or messageId - using pattern-based detection');\n        return;\n      }\n\n      try {\n        logger.log('[WeaveAdFormatContainer] 📤 Fetching recommendations from SDK for brand URL matching');\n        // Use context values (from AdMeshProvider) for UCP PlatformRequest fields\n        const aipResponse = await sdk.fetchRecommendationFromAIPContext({\n          query: query.trim(),\n          sessionId: sessionId,\n          messageId: messageId,\n          language: language, // From context (AdMeshProvider) - maps to context.language in UCP\n          geo_country: geo_country, // From context (AdMeshProvider) - maps to context.geography.country in UCP\n          userId: userId, // From context (AdMeshProvider)\n          model: model, // From context (AdMeshProvider)\n          messages: messages, // From context (AdMeshProvider)\n        });\n\n        // Wrap single recommendation in array for WeaveResponseProcessor\n        const recs = aipResponse ? [aipResponse] : [];\n        setRecommendations(recs);\n        recommendationsRef.current = recs; // Update ref to avoid dependency issues\n        logger.log('[WeaveAdFormatContainer] ✅ Fetched recommendations:', recs.length);\n        \n        // Extract follow-up data from response (similar to AdMeshRecommendations)\n        if (aipResponse) {\n          const followupQueryTopLevel = (aipResponse as any).followup_query;\n          const followupQueryInCreative = (aipResponse.creative_input as any)?.followup_query;\n          const followupQuery = followupQueryTopLevel || followupQueryInCreative;\n          \n          const followupEngagementUrlTopLevel = (aipResponse as any).followup_engagement_url;\n          const followupEngagementUrlInCreative = (aipResponse.creative_input as any)?.followup_engagement_url;\n          const followupEngagementUrl = followupEngagementUrlTopLevel || followupEngagementUrlInCreative;\n          \n          const followupExposureUrlTopLevel = (aipResponse as any).followup_exposure_url;\n          const followupExposureUrlInCreative = (aipResponse.creative_input as any)?.followup_exposure_url;\n          const followupExposureUrl = followupExposureUrlTopLevel || followupExposureUrlInCreative;\n          \n          const recommendationId = (aipResponse as any).recommendation_id || '';\n          \n          // If followup query exists, create recommendation object with follow-up data\n          if (followupQuery) {\n            logger.debug('[WeaveAdFormatContainer] ✅ Followup query detected:', followupQuery);\n            logger.debug('[WeaveAdFormatContainer] ✅ Followup engagement URL:', followupEngagementUrl ? 'present' : 'missing');\n            logger.debug('[WeaveAdFormatContainer] ✅ Recommendation ID:', recommendationId ? recommendationId : 'missing');\n            \n            // SDK-managed rendering: If followups_container_id is provided, use portal rendering\n            // Only use onFollowupDetected callback if container ID is NOT provided (legacy/fallback mode)\n            if (_followups_container_id) {\n              logger.debug('[WeaveAdFormatContainer] ✅ Using SDK-managed portal rendering (followups_container_id provided)');\n              // Store recommendation with follow-up data for portal rendering\n              const recommendationWithFollowupData: any = {\n                ...aipResponse,\n                followup_query: followupQuery,\n                followup_engagement_url: followupEngagementUrl,\n                followup_exposure_url: followupExposureUrl,\n                recommendation_id: recommendationId || (aipResponse as any).recommendation_id\n              };\n              setRecommendationWithFollowup(recommendationWithFollowupData as AdMeshRecommendation);\n            } else if (onFollowupDetectedRef.current) {\n              // Legacy/fallback: Notify third-party application via callback\n              logger.debug('[WeaveAdFormatContainer] 🔔 Using legacy callback mode (followups_container_id not provided)');\n              onFollowupDetectedRef.current(followupQuery, followupEngagementUrl || '', recommendationId || '');\n            } else {\n              logger.debug('[WeaveAdFormatContainer] ⚠️ Followup detected but no rendering method provided (neither followups_container_id nor onFollowupDetected callback)');\n            }\n          } else {\n            setRecommendationWithFollowup(null);\n          }\n        }\n        \n        // Development logging: Log full recommendation details\n        if (aipResponse && process.env.NODE_ENV === 'development') {\n          logger.log('[WeaveAdFormatContainer] 📋 Recommendation received (DEV):', {\n            recommendation_id: aipResponse.recommendation_id,\n            product_id: aipResponse.product_id,\n            brand_id: aipResponse.brand_id,\n            title: aipResponse.title,\n            click_url: aipResponse.click_url,\n            contextual_relevance_score: aipResponse.contextual_relevance_score,\n            preferred_format: aipResponse.creative_input?.preferred_format,\n            resolved_format: aipResponse.format_resolution?.resolved_format,\n            creative_input: {\n              product_name: aipResponse.creative_input?.product_name,\n              brand_name: aipResponse.creative_input?.brand_name,\n              cta_url: aipResponse.creative_input?.cta_url,\n              short_description: aipResponse.creative_input?.short_description,\n              allowed_formats: aipResponse.creative_input?.allowed_formats,\n              fallback_formats: aipResponse.creative_input?.fallback_formats,\n            },\n            format_resolution: aipResponse.format_resolution,\n            full_response: aipResponse\n          });\n        }\n      } catch (error) {\n        logger.warn('[WeaveAdFormatContainer] ⚠️ Failed to fetch recommendations, falling back to pattern-based detection:', error);\n        setRecommendations([]);\n      }\n    };\n\n    fetchRecommendations();\n  }, [sdk, sessionId, messageId, query, _followups_container_id]);\n\n  // Find container for followups when recommendation with follow-up is available\n  useEffect(() => {\n    // If we don't have a query or container ID, we can't do anything\n    if (!recommendationWithFollowup?.followup_query || !_followups_container_id) {\n      setFollowupContainer(null);\n      return;\n    }\n\n    // If isContainerReady is explicitly provided and false, wait\n    if (isContainerReady === false) {\n      logger.debug(`[WeaveAdFormatContainer] ⏳ Waiting for container signal...`);\n      return;\n    }\n\n    // Try to find the container\n    let attempts = 0;\n    const maxAttempts = 5; // Reduced from 30 since we now have a signal - just need to handle React render lag\n\n    const checkForContainer = () => {\n      const container = document.getElementById(_followups_container_id);\n      if (container) {\n        logger.debug(`[WeaveAdFormatContainer] ✅ Found followup container: ${_followups_container_id} `);\n        setFollowupContainer(container);\n        return true;\n      }\n      return false;\n    };\n\n    // Check immediately\n    if (checkForContainer()) return;\n\n    // Short poll to account for React rendering\n    const interval = setInterval(() => {\n      attempts++;\n      if (checkForContainer() || attempts >= maxAttempts) {\n        clearInterval(interval);\n        if (attempts >= maxAttempts) {\n          logger.warn(`[WeaveAdFormatContainer] ⚠️ Followup container not found after signal: ${_followups_container_id} `);\n        }\n      }\n    }, 100);\n\n    return () => clearInterval(interval);\n  }, [recommendationWithFollowup, _followups_container_id, isContainerReady]);\n\n  // Scan for links immediately when container is ready and on children changes\n  useEffect(() => {\n    const container = containerRef.current;\n    if (!container || !weaveProcessorRef.current) {\n      return;\n    }\n\n    const weaveProcessor = weaveProcessorRef.current;\n\n    const trackExposurePixel = ({ exposureUrl, recommendationId, linkElement }: InlineExposureTrackingParams) => {\n      exposureTrackerRef.current.startTracking({\n        exposureUrl,\n        recommendationId,\n        linkElement,\n        sessionId,\n        logPrefix: '[WeaveAdFormatContainer]'\n      });\n    };\n\n    // Scan immediately\n    const scanLinks = () => {\n      // Emit weave attempt signal\n      logger.log('[WeaveAdFormatContainer] 🔍 Weave injection attempt started');\n      onWeaveAttempt?.(messageId);\n\n      // Use fetched recommendations if available, otherwise fall back to pattern-based detection\n      // Use ref to avoid triggering re-runs when recommendations change\n      const recsToUse = recommendationsRef.current.length > 0 ? recommendationsRef.current : [];\n      logger.log(`[WeaveAdFormatContainer] 📋 Using ${recsToUse.length} recommendations for link detection`);\n\n      try {\n        const detectedLinks = weaveProcessor.scanAndProcessLinks(\n          container,\n          recsToUse, // Use fetched recommendations for brand URL matching\n          trackExposurePixel\n        );\n\n        if (detectedLinks.length > 0 && !scannedRef.current) {\n          scannedRef.current = true;\n          logger.log(`[WeaveAdFormatContainer] ✅ Weave injection succeeded: ${detectedLinks.length} links detected`);\n          onWeaveOutcome?.(messageId, true, `Found ${detectedLinks.length} links`);\n          onLinksDetected?.(detectedLinks.length);\n          onFallbackChange?.(false);\n        } else if (!scannedRef.current) {\n          // No links found on first scan - will be handled by FinalLinkDetectionCheck\n          // But we emit the outcome signal here for immediate feedback\n          logger.log('[WeaveAdFormatContainer] ⚠️ Weave injection: no links found on initial scan');\n          // Don't emit outcome yet - wait for FinalLinkDetectionCheck to confirm\n        }\n      } catch (error) {\n        const errorMessage = error instanceof Error ? error.message : String(error);\n        logger.error(`[WeaveAdFormatContainer] ❌ Weave injection failed: ${errorMessage}`);\n        onWeaveOutcome?.(messageId, false, errorMessage);\n        // Immediately trigger fallback on error\n        onNoLinksDetected?.();\n        onFallbackChange?.(true);\n      }\n    };\n\n    // Initial scan after a small delay to ensure DOM is ready\n    const timeoutId = setTimeout(scanLinks, 100);\n\n    // Watch for new links (streaming support)\n    // Use ref to avoid triggering re-runs when recommendations change\n    weaveProcessor.watchForNewLinks(container, recommendationsRef.current, trackExposurePixel);\n\n    return () => {\n      clearTimeout(timeoutId);\n      weaveProcessor.stopWatching();\n    };\n  }, [children, sessionId, messageId, onLinksDetected, onFallbackChange, onWeaveAttempt, onWeaveOutcome]); // Removed recommendations from deps to prevent infinite loop\n\n  // Check if format is \"weave\" - if so, don't show fallback recommendations\n  const resolvedFormat = recommendations[0]?.format_resolution?.resolved_format;\n  const preferredFormat = recommendations[0]?.creative_input?.preferred_format;\n  const isWeaveFormat = resolvedFormat === 'weave' || preferredFormat === 'weave';\n\n  // Log when format is weave (for debugging)\n  useEffect(() => {\n    if (query && isWeaveFormat) {\n      logger.log(`[WeaveAdFormatContainer] 🎯 Format is \"weave\" (resolved: ${resolvedFormat}, preferred: ${preferredFormat}) - skipping fallback recommendations`);\n    }\n  }, [query, isWeaveFormat, resolvedFormat, preferredFormat]);\n\n  // Helper to render followup portal\n  const renderFollowupPortal = () => {\n    if (followupContainer && recommendationWithFollowup?.followup_query && sdk) {\n      logger.debug(`[WeaveAdFormatContainer] 🌀 Rendering followup portal into: ${_followups_container_id} `);\n      return createPortal(\n        <AdMeshFollowup\n          recommendation={recommendationWithFollowup}\n          theme={theme}\n          sdk={sdk}\n          sessionId={sessionId}\n          onExecuteQuery={_onExecuteQuery}\n        />,\n        followupContainer\n      );\n    } else {\n      logger.debug(`[WeaveAdFormatContainer] ❌ Skipping followup portal. Container: ${!!followupContainer}, Query: ${!!recommendationWithFollowup?.followup_query}, SDK: ${!!sdk} `);\n    }\n    return null;\n  };\n\n  return (\n    <>\n      <div\n        ref={containerRef}\n        id={containerId}\n        className={className}\n        data-weave-ad-format=\"true\"\n        data-message-id={messageId}\n      >\n        {children}\n      </div>\n\n      {/* Event-driven link detection and fallback rendering - only show if format is NOT weave */}\n      {query && !isWeaveFormat && (\n        <FinalLinkDetectionCheck\n          containerId={containerId}\n          messageId={messageId}\n          sessionId={sessionId}\n          sdk={sdk}\n          query={query}\n          recommendations={recommendations}\n          onLinksFound={(count) => {\n            logger.log(`[WeaveAdFormatContainer] ✅ Links found (${count}) - no fallback needed`);\n            // Emit weave outcome success if not already emitted\n            onWeaveOutcome?.(messageId, true, `Found ${count} links in final check`);\n            onLinksDetected?.(count);\n            onFallbackChange?.(false);\n          }}\n          onNoLinksFound={() => {\n            logger.log(`[WeaveAdFormatContainer] ⚠️ No links found - rendering fallback`);\n            logger.log(`[WeaveAdFormatContainer] 📋 Passing ${recommendations.length} recommendation(s) to fallback component`);\n            // Emit weave outcome failure\n            onWeaveOutcome?.(messageId, false, 'No links detected in final check');\n            onNoLinksDetected?.();\n            onFallbackChange?.(true);\n          }}\n        >\n          <WeaveFallbackRecommendations\n            format={fallbackFormat}\n            messageId={messageId}\n            query={query}\n            fallback={true}\n            onError={onError}\n            previousRecommendations={recommendations.length > 0 ? recommendations : undefined}\n          />\n        </FinalLinkDetectionCheck>\n      )}\n\n      {/* Render follow-up portal if follow-up exists */}\n      {renderFollowupPortal()}\n    </>\n  );\n};\n\nexport default WeaveAdFormatContainer;\n","/**\n * AdMesh Style Injection System\n * \n * Provides platform-agnostic, isolated styling for AdMesh components\n * that prevents interference from host platform CSS frameworks\n */\n\nconst ADMESH_STYLE_ID = 'admesh-ui-sdk-styles';\nconst ADMESH_RESET_ID = 'admesh-ui-sdk-reset';\n\n/**\n * CSS Reset for AdMesh components\n * Normalizes styles to prevent host platform CSS from affecting AdMesh components\n */\nconst ADMESH_CSS_RESET = `\n/* AdMesh UI SDK - CSS Reset & Normalization */\n.admesh-component,\n.admesh-component * {\n  box-sizing: border-box;\n  margin: 0;\n  padding: 0;\n  border: 0;\n  font-size: 100%;\n  font-weight: normal;\n  font-style: normal;\n  line-height: 1.5;\n  text-decoration: none;\n  background: transparent;\n  color: inherit;\n}\n\n.admesh-component {\n  all: revert;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-rendering: optimizeLegibility;\n}\n\n.admesh-component button,\n.admesh-component a {\n  cursor: pointer;\n  border: none;\n  background: none;\n  padding: 0;\n  margin: 0;\n  font-family: inherit;\n  font-size: inherit;\n  color: inherit;\n}\n\n.admesh-component a {\n  text-decoration: none;\n  color: inherit;\n}\n\n.admesh-component button:focus,\n.admesh-component a:focus {\n  outline: none;\n}\n\n.admesh-component img {\n  max-width: 100%;\n  height: auto;\n  display: block;\n}\n\n.admesh-component ul,\n.admesh-component ol {\n  list-style: none;\n}\n\n.admesh-component table {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\n.admesh-component input,\n.admesh-component textarea,\n.admesh-component select {\n  font-family: inherit;\n  font-size: inherit;\n  color: inherit;\n}\n\n/* Prevent Tailwind and other frameworks from affecting AdMesh */\n.admesh-component .prose,\n.admesh-component .container,\n.admesh-component .grid,\n.admesh-component .flex {\n  all: revert;\n}\n\n/* Ensure AdMesh components are not affected by dark mode utilities */\n.admesh-component.dark,\n.admesh-component[data-admesh-theme=\"dark\"] {\n  color-scheme: dark;\n}\n\n.admesh-component.light,\n.admesh-component[data-admesh-theme=\"light\"] {\n  color-scheme: light;\n}\n`;\n\n/**\n * Core AdMesh Component Styles\n * Self-contained styles that work independently of host platform\n */\nconst ADMESH_CORE_STYLES = `\n/* AdMesh Core Component Styles */\n\n.admesh-component {\n  position: relative;\n  display: block;\n}\n\n/* Product Card Styles */\n.admesh-product-card {\n  position: relative;\n  cursor: pointer;\n  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n  height: 100%;\n  border-radius: 0.75rem;\n  background: rgb(255, 255, 255);\n  border: 1px solid rgb(229, 231, 235);\n  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n  overflow: hidden;\n}\n\n.admesh-product-card[data-admesh-theme=\"dark\"] {\n  background: rgb(17, 24, 39);\n  border-color: rgb(31, 41, 55);\n}\n\n.admesh-product-card:hover {\n  transform: translateY(-4px);\n  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);\n  border-color: rgba(99, 102, 241, 0.2);\n}\n\n.admesh-product-card__container {\n  position: relative;\n  padding: 1rem;\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  gap: 0.75rem;\n  z-index: 2;\n}\n\n.admesh-product-card__header {\n  display: flex;\n  justify-content: space-between;\n  align-items: flex-start;\n  gap: 0.5rem;\n  margin-bottom: 0.25rem;\n}\n\n.admesh-product-card__title {\n  margin: 0;\n  font-size: 1.5rem;\n  font-weight: 700;\n  line-height: 1.2;\n  color: rgb(17, 24, 39);\n  letter-spacing: -0.025em;\n  transition: all 0.3s ease;\n}\n\n.admesh-product-card[data-admesh-theme=\"dark\"] .admesh-product-card__title {\n  color: rgb(243, 244, 246);\n}\n\n.admesh-product-card:hover .admesh-product-card__title {\n  transform: translateX(4px);\n}\n\n.admesh-product-card__cta {\n  position: relative;\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  gap: 0.5rem;\n  white-space: nowrap;\n  border-radius: 0.5rem;\n  font-size: 1rem;\n  font-weight: 600;\n  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n  padding: 0.75rem 1.5rem;\n  background: rgb(0, 0, 0);\n  color: rgb(255, 255, 255);\n  border: none;\n  cursor: pointer;\n  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n  overflow: hidden;\n}\n\n.admesh-product-card[data-admesh-theme=\"dark\"] .admesh-product-card__cta {\n  background: rgb(255, 255, 255);\n  color: rgb(0, 0, 0);\n}\n\n.admesh-product-card__cta:hover {\n  transform: translateY(-2px);\n  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);\n}\n\n.admesh-product-card__cta:active {\n  transform: translateY(0);\n}\n\n/* Summary Unit Styles */\n.admesh-summary-unit {\n  font-size: 1rem;\n  line-height: 1.6;\n  color: rgb(17, 24, 39);\n}\n\n.admesh-summary-unit[data-admesh-theme=\"dark\"] {\n  color: rgb(243, 244, 246);\n}\n\n.admesh-summary-unit a {\n  color: rgb(37, 99, 235);\n  text-decoration: underline;\n  text-decoration-color: rgb(37, 99, 235);\n  text-underline-offset: 2px;\n  transition: all 0.2s ease;\n  font-weight: 500;\n}\n\n.admesh-summary-unit[data-admesh-theme=\"dark\"] a {\n  color: rgb(96, 165, 250);\n  text-decoration-color: rgb(96, 165, 250);\n}\n\n.admesh-summary-unit a:hover {\n  color: rgb(29, 78, 216);\n  text-decoration-color: rgb(29, 78, 216);\n}\n\n.admesh-summary-unit[data-admesh-theme=\"dark\"] a:hover {\n  color: rgb(147, 197, 253);\n  text-decoration-color: rgb(147, 197, 253);\n}\n\n/* Ecommerce Cards Styles */\n.admesh-ecommerce-container {\n  position: relative;\n  width: 100%;\n}\n\n.admesh-ecommerce-card {\n  flex-shrink: 0;\n  background: white;\n  border: 1px solid rgb(229, 231, 235);\n  border-radius: 0.5rem;\n  overflow: hidden;\n  transition: all 0.2s ease-in-out;\n  cursor: pointer;\n  position: relative;\n}\n\n.admesh-ecommerce-card[data-admesh-theme=\"dark\"] {\n  background: rgb(31, 41, 55);\n  border-color: rgb(55, 65, 81);\n  color: white;\n}\n\n.admesh-ecommerce-card:hover {\n  transform: translateY(-2px);\n  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);\n}\n\n/* Badge Styles */\n.admesh-badge {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.375rem;\n  border-radius: 0.5rem;\n  padding: 0.375rem 0.75rem;\n  font-size: 0.875rem;\n  font-weight: 600;\n  transition: all 0.3s ease;\n  position: relative;\n  overflow: hidden;\n}\n\n.admesh-badge--primary {\n  background: linear-gradient(135deg, rgb(99, 102, 241), rgb(79, 70, 229));\n  color: white;\n  box-shadow: 0 4px 6px -1px rgba(99, 102, 241, 0.3);\n}\n\n.admesh-badge--secondary {\n  background: rgb(243, 244, 246);\n  color: rgb(55, 65, 81);\n}\n\n.admesh-badge[data-admesh-theme=\"dark\"].admesh-badge--secondary {\n  background: rgb(31, 41, 55);\n  color: rgb(209, 213, 219);\n}\n\n/* Responsive */\n@media (max-width: 640px) {\n  .admesh-product-card__container {\n    padding: 0.75rem;\n    gap: 0.5rem;\n  }\n\n  .admesh-product-card__title {\n    font-size: 1.25rem;\n  }\n\n  .admesh-product-card__cta {\n    padding: 0.5rem 1rem;\n    font-size: 0.875rem;\n  }\n}\n`;\n\n/**\n * Inject AdMesh styles into the document\n * Ensures styles are loaded only once and don't conflict with host platform\n */\nexport const injectAdMeshStyles = (): void => {\n  if (typeof document === 'undefined') return;\n\n  // Check if styles already injected\n  if (document.getElementById(ADMESH_RESET_ID) && document.getElementById(ADMESH_STYLE_ID)) {\n    return;\n  }\n\n  // Inject CSS Reset\n  if (!document.getElementById(ADMESH_RESET_ID)) {\n    const resetStyle = document.createElement('style');\n    resetStyle.id = ADMESH_RESET_ID;\n    resetStyle.textContent = ADMESH_CSS_RESET;\n    document.head.appendChild(resetStyle);\n  }\n\n  // Inject Core Styles\n  if (!document.getElementById(ADMESH_STYLE_ID)) {\n    const coreStyle = document.createElement('style');\n    coreStyle.id = ADMESH_STYLE_ID;\n    coreStyle.textContent = ADMESH_CORE_STYLES;\n    document.head.appendChild(coreStyle);\n  }\n};\n\n/**\n * Remove AdMesh styles from the document\n * Useful for cleanup or testing\n */\nexport const removeAdMeshStyles = (): void => {\n  if (typeof document === 'undefined') return;\n\n  const resetStyle = document.getElementById(ADMESH_RESET_ID);\n  const coreStyle = document.getElementById(ADMESH_STYLE_ID);\n\n  if (resetStyle) resetStyle.remove();\n  if (coreStyle) coreStyle.remove();\n};\n\n/**\n * Check if AdMesh styles are already injected\n */\nexport const areAdMeshStylesInjected = (): boolean => {\n  if (typeof document === 'undefined') return false;\n  return !!(document.getElementById(ADMESH_RESET_ID) && document.getElementById(ADMESH_STYLE_ID));\n};\n\n","import { useEffect } from 'react';\nimport { logger } from '../utils/logger';\nimport { injectAdMeshStyles } from '../utils/styleInjection';\n\n// Complete CSS content as a string - this will be injected automatically\nconst ADMESH_STYLES = `\n/* AdMesh UI SDK - Complete Self-Contained Styles */\n\n/* CSS Reset for AdMesh components */\n.admesh-component, .admesh-component * {\n  box-sizing: border-box;\n}\n\n/* CSS Variables - Black/White Color Scheme */\n.admesh-component {\n  --admesh-primary: #000000;\n  --admesh-primary-hover: #333333;\n  --admesh-secondary: #666666;\n  --admesh-accent: #000000;\n  --admesh-background: #ffffff;\n  --admesh-surface: #ffffff;\n  --admesh-border: #e5e7eb;\n  --admesh-text: #000000;\n  --admesh-text-muted: #666666;\n  --admesh-text-light: #999999;\n  --admesh-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n  --admesh-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);\n  --admesh-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\n  --admesh-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\n  --admesh-radius: 0.5rem;\n  --admesh-radius-sm: 0.25rem;\n  --admesh-radius-lg: 0.75rem;\n  --admesh-radius-xl: 1rem;\n}\n\n.admesh-component[data-admesh-theme=\"dark\"] {\n  --admesh-primary: #ffffff;\n  --admesh-primary-hover: #e5e7eb;\n  --admesh-secondary: #9ca3af;\n  --admesh-accent: #ffffff;\n  --admesh-background: #000000;\n  --admesh-surface: #111111;\n  --admesh-border: #333333;\n  --admesh-text: #ffffff;\n  --admesh-text-muted: #9ca3af;\n  --admesh-text-light: #666666;\n  --admesh-shadow: 0 1px 3px 0 rgb(255 255 255 / 0.1), 0 1px 2px -1px rgb(255 255 255 / 0.1);\n  --admesh-shadow-md: 0 4px 6px -1px rgb(255 255 255 / 0.1), 0 2px 4px -2px rgb(255 255 255 / 0.1);\n  --admesh-shadow-lg: 0 10px 15px -3px rgb(255 255 255 / 0.1), 0 4px 6px -4px rgb(255 255 255 / 0.1);\n  --admesh-shadow-xl: 0 20px 25px -5px rgb(255 255 255 / 0.1), 0 8px 10px -6px rgb(255 255 255 / 0.1);\n}\n\n/* Layout Styles */\n.admesh-layout {\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n  color: var(--admesh-text);\n  background-color: var(--admesh-background);\n  border-radius: var(--admesh-radius);\n  padding: 1.5rem;\n  box-shadow: var(--admesh-shadow);\n  border: 1px solid var(--admesh-border);\n  /* Consistent width: 100% for all layouts except ecommerce */\n  width: 100%;\n}\n\n/* Ecommerce layout exception */\n.admesh-layout--ecommerce {\n  width: auto;\n}\n\n/* Citation Unit Styles */\n.admesh-citation-unit {\n  width: 100%;\n}\n\n/* Inline Recommendation Styles */\n.admesh-inline-recommendation {\n  width: 100%;\n}\n\n/* Simple Ad Styles */\n.admesh-simple-ad {\n  width: 100%;\n}\n\n.admesh-layout__header {\n  margin-bottom: 1.5rem;\n  text-align: center;\n}\n\n.admesh-layout__title {\n  font-size: 1.25rem;\n  font-weight: 600;\n  color: var(--admesh-text);\n  margin-bottom: 0.5rem;\n}\n\n.admesh-layout__subtitle {\n  font-size: 0.875rem;\n  color: var(--admesh-text-muted);\n}\n\n.admesh-layout__cards-grid {\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n  gap: 1rem;\n  margin-bottom: 1.5rem;\n}\n\n.admesh-layout__more-indicator {\n  text-align: center;\n  padding: 1rem;\n  color: var(--admesh-text-muted);\n  font-size: 0.875rem;\n}\n\n.admesh-layout__empty {\n  text-align: center;\n  padding: 3rem 1rem;\n}\n\n.admesh-layout__empty-content h3 {\n  font-size: 1.125rem;\n  font-weight: 600;\n  color: var(--admesh-text-muted);\n  margin-bottom: 0.5rem;\n}\n\n.admesh-layout__empty-content p {\n  font-size: 0.875rem;\n  color: var(--admesh-text-muted);\n}\n\n/* Product Card Styles */\n.admesh-product-card {\n  background-color: var(--admesh-surface);\n  border: 1px solid var(--admesh-border);\n  border-radius: var(--admesh-radius);\n  padding: 1.5rem;\n  transition: all 0.2s ease-in-out;\n  position: relative;\n  overflow: hidden;\n  /* Consistent width: 100% for product cards */\n  width: 100%;\n}\n\n.admesh-product-card:hover {\n  box-shadow: var(--admesh-shadow-lg);\n  transform: translateY(-2px);\n  border-color: var(--admesh-primary);\n}\n\n.admesh-product-card__header {\n  display: flex;\n  justify-content: space-between;\n  align-items: flex-start;\n  margin-bottom: 1rem;\n}\n\n.admesh-product-card__title {\n  font-size: 1.125rem;\n  font-weight: 600;\n  color: var(--admesh-text);\n  margin-bottom: 0.5rem;\n  line-height: 1.4;\n}\n\n.admesh-product-card__reason {\n  font-size: 0.875rem;\n  color: var(--admesh-text-muted);\n  line-height: 1.5;\n  margin-bottom: 1rem;\n}\n\n.admesh-product-card__match-score {\n  margin-bottom: 1rem;\n}\n\n.admesh-product-card__match-score-label {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  font-size: 0.75rem;\n  color: var(--admesh-text-muted);\n  margin-bottom: 0.25rem;\n}\n\n.admesh-product-card__match-score-bar {\n  width: 100%;\n  height: 0.375rem;\n  background-color: var(--admesh-border);\n  border-radius: var(--admesh-radius-sm);\n  overflow: hidden;\n}\n\n.admesh-product-card__match-score-fill {\n  height: 100%;\n  background: var(--admesh-primary);\n  border-radius: var(--admesh-radius-sm);\n  transition: width 0.3s ease-in-out;\n}\n\n.admesh-product-card__badges {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 0.5rem;\n  margin-bottom: 1rem;\n}\n\n.admesh-product-card__badge {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.25rem;\n  padding: 0.25rem 0.5rem;\n  background-color: var(--admesh-primary);\n  color: white;\n  font-size: 0.75rem;\n  font-weight: 500;\n  border-radius: var(--admesh-radius-sm);\n}\n\n.admesh-product-card__badge--secondary {\n  background-color: var(--admesh-secondary);\n}\n\n.admesh-product-card__keywords {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 0.25rem;\n  margin-bottom: 1rem;\n}\n\n.admesh-product-card__keyword {\n  padding: 0.125rem 0.375rem;\n  background-color: var(--admesh-border);\n  color: var(--admesh-text-muted);\n  font-size: 0.75rem;\n  border-radius: var(--admesh-radius-sm);\n}\n\n/* Dark mode specific enhancements */\n.admesh-component[data-admesh-theme=\"dark\"] .admesh-product-card__keyword {\n  background-color: #4b5563;\n  color: #d1d5db;\n}\n\n.admesh-component[data-admesh-theme=\"dark\"] .admesh-product-card:hover {\n  border-color: var(--admesh-primary);\n  background-color: #374151;\n}\n\n.admesh-component[data-admesh-theme=\"dark\"] .admesh-product-card__button:hover {\n  background: var(--admesh-primary-hover);\n}\n\n.admesh-product-card__footer {\n  display: flex;\n  justify-content: flex-end;\n  margin-top: 1.5rem;\n}\n\n/* Mobile-specific sidebar improvements */\n@media (max-width: 640px) {\n  .admesh-sidebar {\n    /* Ensure proper mobile viewport handling */\n    height: 100vh !important;\n    height: 100dvh !important; /* Dynamic viewport height for mobile browsers */\n    max-height: 100vh !important;\n    max-height: 100dvh !important;\n    width: 100vw !important;\n    max-width: 90vw !important;\n    overflow: hidden !important;\n  }\n\n  .admesh-sidebar.relative {\n    height: 100% !important;\n    width: 100% !important;\n    max-width: 100% !important;\n  }\n\n  /* Improve touch scrolling */\n  .admesh-sidebar .overflow-y-auto {\n    -webkit-overflow-scrolling: touch !important;\n    overscroll-behavior: contain !important;\n    scroll-behavior: smooth !important;\n  }\n\n  /* Prevent body scroll when sidebar is open */\n  body:has(.admesh-sidebar[data-mobile-open=\"true\"]) {\n    overflow: hidden !important;\n    position: fixed !important;\n    width: 100% !important;\n  }\n}\n\n/* Tablet improvements */\n@media (min-width: 641px) and (max-width: 1024px) {\n  .admesh-sidebar {\n    max-width: 400px !important;\n  }\n}\n\n/* Mobile responsiveness improvements for all components */\n@media (max-width: 640px) {\n  /* Product cards mobile optimization */\n  .admesh-card {\n    padding: 0.75rem !important;\n    margin-bottom: 0.75rem !important;\n  }\n\n  /* Inline recommendations mobile optimization */\n  .admesh-inline-recommendation {\n    padding: 0.5rem !important;\n    margin-bottom: 0.5rem !important;\n  }\n\n  /* Conversation summary mobile optimization */\n  .admesh-conversation-summary {\n    padding: 1rem !important;\n  }\n\n  /* Percentage text mobile improvements */\n  .admesh-component .text-xs {\n    font-size: 0.75rem !important;\n    line-height: 1rem !important;\n  }\n\n  .admesh-component .text-sm {\n    font-size: 0.875rem !important;\n    line-height: 1.25rem !important;\n  }\n\n  /* Button mobile improvements */\n  .admesh-component button {\n    padding: 0.375rem 0.75rem !important;\n    font-size: 0.75rem !important;\n    min-height: 2rem !important;\n    touch-action: manipulation !important;\n  }\n\n  /* Badge mobile improvements */\n  .admesh-component .rounded-full {\n    padding: 0.25rem 0.5rem !important;\n    font-size: 0.625rem !important;\n    line-height: 1rem !important;\n  }\n\n  /* Progress bar mobile improvements */\n  .admesh-component .bg-gray-200,\n  .admesh-component .bg-slate-600 {\n    height: 0.25rem !important;\n  }\n\n  /* Flex layout mobile improvements */\n  .admesh-component .flex {\n    flex-wrap: wrap !important;\n  }\n\n  .admesh-component .gap-2 {\n    gap: 0.375rem !important;\n  }\n\n  .admesh-component .gap-3 {\n    gap: 0.5rem !important;\n  }\n}\n\n.admesh-product-card__button {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.5rem;\n  padding: 0.75rem 1.5rem;\n  background: var(--admesh-primary);\n  color: var(--admesh-background);\n  font-size: 0.875rem;\n  font-weight: 500;\n  border: none;\n  border-radius: var(--admesh-radius);\n  cursor: pointer;\n  transition: all 0.2s ease-in-out;\n  text-decoration: none;\n}\n\n.admesh-product-card__button:hover {\n  transform: translateY(-1px);\n  box-shadow: var(--admesh-shadow-lg);\n}\n\n/* Utility Classes */\n.admesh-text-xs { font-size: 0.75rem; }\n.admesh-text-sm { font-size: 0.875rem; }\n.admesh-text-base { font-size: 1rem; }\n.admesh-text-lg { font-size: 1.125rem; }\n.admesh-text-xl { font-size: 1.25rem; }\n\n.admesh-font-medium { font-weight: 500; }\n.admesh-font-semibold { font-weight: 600; }\n.admesh-font-bold { font-weight: 700; }\n\n.admesh-text-muted { color: var(--admesh-text-muted); }\n\n/* Comparison Table Styles */\n.admesh-compare-table {\n  width: 100%;\n  border-collapse: collapse;\n  background-color: var(--admesh-surface);\n  border: 1px solid var(--admesh-border);\n  border-radius: var(--admesh-radius);\n  overflow: hidden;\n}\n\n.admesh-compare-table th,\n.admesh-compare-table td {\n  padding: 0.75rem;\n  text-align: left;\n  border-bottom: 1px solid var(--admesh-border);\n}\n\n.admesh-compare-table th {\n  background-color: var(--admesh-background);\n  font-weight: 600;\n  color: var(--admesh-text);\n  font-size: 0.875rem;\n}\n\n.admesh-compare-table td {\n  color: var(--admesh-text);\n  font-size: 0.875rem;\n}\n\n.admesh-compare-table tr:hover {\n  background-color: var(--admesh-border);\n}\n\n/* Dark mode table enhancements */\n.admesh-component[data-admesh-theme=\"dark\"] .admesh-compare-table th {\n  background-color: #374151;\n}\n\n.admesh-component[data-admesh-theme=\"dark\"] .admesh-compare-table tr:hover {\n  background-color: #4b5563;\n}\n\n/* Responsive Design */\n@media (max-width: 768px) {\n  .admesh-layout {\n    padding: 1rem;\n  }\n\n  .admesh-layout__cards-grid {\n    grid-template-columns: 1fr;\n    gap: 0.75rem;\n  }\n\n  .admesh-product-card {\n    padding: 1rem;\n  }\n\n  .admesh-compare-table {\n    font-size: 0.75rem;\n  }\n\n  .admesh-compare-table th,\n  .admesh-compare-table td {\n    padding: 0.5rem;\n  }\n}\n\n/* Essential Utility Classes for Self-Contained SDK - High Specificity */\n.admesh-component .relative { position: relative !important; }\n.admesh-component .absolute { position: absolute !important; }\n.admesh-component .flex { display: flex !important; }\n.admesh-component .inline-flex { display: inline-flex !important; }\n.admesh-component .grid { display: grid !important; }\n.admesh-component .hidden { display: none !important; }\n.admesh-component .block { display: block !important; }\n.admesh-component .inline-block { display: inline-block !important; }\n\n/* Flexbox utilities */\n.admesh-component .flex-col { flex-direction: column !important; }\n.admesh-component .flex-row { flex-direction: row !important; }\n.admesh-component .flex-wrap { flex-wrap: wrap !important; }\n.admesh-component .items-center { align-items: center !important; }\n.admesh-component .items-start { align-items: flex-start !important; }\n.admesh-component .items-end { align-items: flex-end !important; }\n.admesh-component .justify-center { justify-content: center !important; }\n.admesh-component .justify-between { justify-content: space-between !important; }\n.admesh-component .justify-end { justify-content: flex-end !important; }\n.admesh-component .flex-1 { flex: 1 1 0% !important; }\n.admesh-component .flex-shrink-0 { flex-shrink: 0 !important; }\n\n/* Grid utilities */\n.admesh-component .grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }\n.admesh-component .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n.admesh-component .grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }\n\n/* Spacing utilities */\n.admesh-component .gap-1 { gap: 0.25rem; }\n.admesh-component .gap-2 { gap: 0.5rem; }\n.admesh-component .gap-3 { gap: 0.75rem; }\n.admesh-component .gap-4 { gap: 1rem; }\n.admesh-component .gap-6 { gap: 1.5rem; }\n.admesh-component .gap-8 { gap: 2rem; }\n\n/* Padding utilities */\n.admesh-component .p-1 { padding: 0.25rem; }\n.admesh-component .p-2 { padding: 0.5rem; }\n.admesh-component .p-3 { padding: 0.75rem; }\n.admesh-component .p-4 { padding: 1rem; }\n.admesh-component .p-5 { padding: 1.25rem; }\n.admesh-component .p-6 { padding: 1.5rem; }\n.admesh-component .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; }\n.admesh-component .px-3 { padding-left: 0.75rem; padding-right: 0.75rem; }\n.admesh-component .px-4 { padding-left: 1rem; padding-right: 1rem; }\n.admesh-component .py-1 { padding-top: 0.25rem; padding-bottom: 0.25rem; }\n.admesh-component .py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }\n.admesh-component .py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; }\n.admesh-component .pt-2 { padding-top: 0.5rem; }\n.admesh-component .pt-3 { padding-top: 0.75rem; }\n.admesh-component .pb-2 { padding-bottom: 0.5rem; }\n.admesh-component .pb-3 { padding-bottom: 0.75rem; }\n\n/* Margin utilities */\n.admesh-component .m-0 { margin: 0; }\n.admesh-component .mb-1 { margin-bottom: 0.25rem; }\n.admesh-component .mb-2 { margin-bottom: 0.5rem; }\n.admesh-component .mb-3 { margin-bottom: 0.75rem; }\n.admesh-component .mb-4 { margin-bottom: 1rem; }\n.admesh-component .mb-6 { margin-bottom: 1.5rem; }\n.admesh-component .mt-1 { margin-top: 0.25rem; }\n.admesh-component .mt-2 { margin-top: 0.5rem; }\n.admesh-component .mt-4 { margin-top: 1rem; }\n.admesh-component .mt-6 { margin-top: 1.5rem; }\n.admesh-component .mt-auto { margin-top: auto; }\n.admesh-component .ml-1 { margin-left: 0.25rem; }\n.admesh-component .mr-1 { margin-right: 0.25rem; }\n.admesh-component .mr-2 { margin-right: 0.5rem; }\n\n/* Width and height utilities */\n.admesh-component .w-2 { width: 0.5rem; }\n.admesh-component .w-3 { width: 0.75rem; }\n.admesh-component .w-4 { width: 1rem; }\n.admesh-component .w-5 { width: 1.25rem; }\n.admesh-component .w-6 { width: 1.5rem; }\n.admesh-component .w-full { width: 100%; }\n.admesh-component .w-fit { width: fit-content; }\n.admesh-component .h-2 { height: 0.5rem; }\n.admesh-component .h-3 { height: 0.75rem; }\n.admesh-component .h-4 { height: 1rem; }\n.admesh-component .h-5 { height: 1.25rem; }\n.admesh-component .h-6 { height: 1.5rem; }\n.admesh-component .h-full { height: 100%; }\n.admesh-component .min-w-0 { min-width: 0px; }\n\n/* Border utilities */\n.admesh-component .border { border-width: 1px; }\n.admesh-component .border-t { border-top-width: 1px; }\n.admesh-component .border-gray-100 { border-color: #f3f4f6; }\n.admesh-component .border-gray-200 { border-color: #e5e7eb; }\n.admesh-component .border-gray-300 { border-color: #d1d5db; }\n.admesh-component .border-blue-200 { border-color: #bfdbfe; }\n.admesh-component .border-green-200 { border-color: #bbf7d0; }\n\n/* Border radius utilities */\n.admesh-component .rounded { border-radius: 0.25rem !important; }\n.admesh-component .rounded-md { border-radius: 0.375rem !important; }\n.admesh-component .rounded-lg { border-radius: 0.5rem !important; }\n.admesh-component .rounded-xl { border-radius: 0.75rem !important; }\n.admesh-component .rounded-full { border-radius: 9999px !important; }\n\n/* Background utilities */\n.admesh-component .bg-white { background-color: #ffffff; }\n.admesh-component .bg-gray-50 { background-color: #f9fafb; }\n.admesh-component .bg-gray-100 { background-color: #f3f4f6; }\n.admesh-component .bg-blue-50 { background-color: #eff6ff; }\n.admesh-component .bg-blue-100 { background-color: #dbeafe; }\n.admesh-component .bg-green-100 { background-color: #dcfce7; }\n.admesh-component .bg-green-500 { background-color: #22c55e; }\n.admesh-component .bg-blue-500 { background-color: #3b82f6; }\n\n/* Solid backgrounds - no gradients for minimal design */\n.admesh-component .bg-primary { background-color: var(--admesh-primary); }\n.admesh-component .bg-secondary { background-color: var(--admesh-secondary); }\n.admesh-component .bg-surface { background-color: var(--admesh-surface); }\n.admesh-component .bg-background { background-color: var(--admesh-background); }\n\n/* Text utilities */\n.admesh-component .text-xs { font-size: 0.75rem; line-height: 1rem; }\n.admesh-component .text-sm { font-size: 0.875rem; line-height: 1.25rem; }\n.admesh-component .text-base { font-size: 1rem; line-height: 1.5rem; }\n.admesh-component .text-lg { font-size: 1.125rem; line-height: 1.75rem; }\n.admesh-component .text-xl { font-size: 1.25rem; line-height: 1.75rem; }\n.admesh-component .font-medium { font-weight: 500; }\n.admesh-component .font-semibold { font-weight: 600; }\n.admesh-component .font-bold { font-weight: 700; }\n.admesh-component .leading-relaxed { line-height: 1.625; }\n\n/* Text colors */\n.admesh-component .text-white { color: #ffffff; }\n.admesh-component .text-gray-400 { color: #9ca3af; }\n.admesh-component .text-gray-500 { color: #6b7280; }\n.admesh-component .text-gray-600 { color: #4b5563; }\n.admesh-component .text-gray-700 { color: #374151; }\n.admesh-component .text-gray-800 { color: #1f2937; }\n.admesh-component .text-blue-600 { color: #2563eb; }\n.admesh-component .text-blue-700 { color: #1d4ed8; }\n.admesh-component .text-green-700 { color: #15803d; }\n\n/* Shadow utilities */\n.admesh-component .shadow-sm { box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); }\n.admesh-component .shadow { box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); }\n.admesh-component .shadow-md { box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); }\n.admesh-component .shadow-lg { box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); }\n.admesh-component .shadow-xl { box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); }\n\n/* Transition utilities */\n.admesh-component .transition-all { transition-property: all; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }\n.admesh-component .transition-colors { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 150ms; }\n.admesh-component .duration-200 { transition-duration: 200ms; }\n.admesh-component .duration-300 { transition-duration: 300ms; }\n\n/* Transform utilities */\n.admesh-component .hover\\\\:-translate-y-1:hover { transform: translateY(-0.25rem); }\n.admesh-component .hover\\\\:scale-105:hover { transform: scale(1.05); }\n\n/* Hover utilities */\n.admesh-component .hover\\\\:shadow-xl:hover { box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); }\n.admesh-component .hover\\\\:bg-gray-100:hover { background-color: #f3f4f6; }\n.admesh-component .hover\\\\:text-blue-800:hover { color: #1e40af; }\n\n/* Cursor utilities */\n.admesh-component .cursor-pointer { cursor: pointer; }\n\n/* Overflow utilities */\n.admesh-component .overflow-hidden { overflow: hidden; }\n.admesh-component .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\n/* Text decoration */\n.admesh-component .underline { text-decoration-line: underline; }\n\n/* Whitespace */\n.admesh-component .whitespace-nowrap { white-space: nowrap; }\n\n/* Dark mode utilities */\n@media (prefers-color-scheme: dark) {\n  .admesh-component .dark\\\\:bg-slate-800 { background-color: #1e293b; }\n  .admesh-component .dark\\\\:bg-slate-900 { background-color: #0f172a; }\n  .admesh-component .dark\\\\:border-slate-700 { border-color: #334155; }\n  .admesh-component .dark\\\\:text-white { color: #ffffff; }\n  .admesh-component .dark\\\\:text-gray-200 { color: #e5e7eb; }\n  .admesh-component .dark\\\\:text-gray-300 { color: #d1d5db; }\n  .admesh-component .dark\\\\:text-gray-400 { color: #9ca3af; }\n  .admesh-component .dark\\\\:text-blue-400 { color: #60a5fa; }\n}\n\n/* Responsive utilities */\n@media (min-width: 640px) {\n  .admesh-component .sm\\\\:p-5 { padding: 1.25rem; }\n  .admesh-component .sm\\\\:text-base { font-size: 1rem; line-height: 1.5rem; }\n  .admesh-component .sm\\\\:text-lg { font-size: 1.125rem; line-height: 1.75rem; }\n  .admesh-component .sm\\\\:flex-row { flex-direction: row; }\n  .admesh-component .sm\\\\:items-center { align-items: center; }\n  .admesh-component .sm\\\\:justify-between { justify-content: space-between; }\n}\n\n@media (min-width: 768px) {\n  .admesh-component .md\\\\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n}\n\n@media (min-width: 1024px) {\n  .admesh-component .lg\\\\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }\n  .admesh-component .lg\\\\:col-span-1 { grid-column: span 1 / span 1; }\n}\n`;\n\nlet stylesInjected = false;\n\n/**\n * Hook to inject AdMesh styles into the document\n * Ensures platform-agnostic, isolated styling that prevents\n * interference from host platform CSS frameworks\n *\n * Usage:\n *   const MyComponent = () => {\n *     useAdMeshStyles();\n *     return <div className=\"admesh-component\">...</div>;\n *   };\n */\nexport const useAdMeshStyles = () => {\n  useEffect(() => {\n    if (stylesInjected) return;\n\n    try {\n      // Use the new style injection system for better isolation\n      injectAdMeshStyles();\n\n      // Also inject the legacy styles for backward compatibility\n      const styleElement = document.createElement('style');\n      styleElement.id = 'admesh-ui-sdk-styles-legacy';\n      styleElement.textContent = ADMESH_STYLES;\n\n      if (!document.getElementById('admesh-ui-sdk-styles-legacy')) {\n        document.head.appendChild(styleElement);\n      }\n\n      stylesInjected = true;\n    } catch (error) {\n      logger.error('[AdMesh] Failed to inject styles');\n    }\n\n    // Cleanup function\n    return () => {\n      // Note: We don't remove styles on unmount to prevent flickering\n      // Styles are designed to be persistent for the lifetime of the app\n    };\n  }, []);\n};\n","'use client';\n\nimport { useEffect, useRef, useCallback } from 'react';\nimport { useAdMesh } from './useAdMesh';\nimport {\n  createInlineExposureTracker,\n  type InlineExposureTrackingParams\n} from '../utils/inlineExposureTracker';\n\nexport interface UseWeaveAdFormatOptions {\n  /** Container ID for the LLM output (where AdMesh links will be detected) */\n  llmOutputContainerId: string;\n\n  /** Timeout for link detection (default: 900ms) */\n  timeoutMs?: number;\n\n  /** Fallback format if no links detected (default: 'tail') */\n  fallbackFormat?: 'product' | 'tail';\n\n  /** Optional callback when AdMesh links are detected */\n  onLinksDetected?: (count: number) => void;\n\n  /** Optional callback when no links are detected (fallback should be rendered) */\n  onNoLinksDetected?: () => void;\n\n  /** Optional callback on error */\n  onError?: (error: Error) => void;\n\n  /** Optional query for fallback API calls (used when no links are detected) */\n  query?: string;\n\n  /** Optional message ID for fallback API calls (used when no links are detected) */\n  messageId?: string;\n}\n\n/**\n * useWeaveAdFormat - Hook for automatic Weave Ad Format handling\n * \n * Automatically:\n * - Detects AdMesh links in LLM output\n * - Fires exposure tracking for detected links\n * - Adds [Ad] labels to links\n * - Shows \"Why this ad?\" tooltip on hover\n * - Renders fallback UI if no links detected\n * \n * @example\n * ```tsx\n * const { isProcessing, detectedLinksCount } = useWeaveAdFormat({\n *   llmOutputContainerId: 'llm-output-123',\n *   timeoutMs: 1500,\n *   fallbackFormat: 'tail'\n * });\n * ```\n */\nexport const useWeaveAdFormat = (options: UseWeaveAdFormatOptions) => {\n  const { sdk, sessionId } = useAdMesh();\n  const processingRef = useRef(false);\n  const detectedLinksRef = useRef(0);\n  const linksFoundRef = useRef(false);\n  const callbackFiredRef = useRef(false);\n  const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);\n  const exposureTrackerRef = useRef(createInlineExposureTracker());\n\n  useEffect(() => {\n    return () => {\n      exposureTrackerRef.current.cleanup();\n    };\n  }, []);\n\n  const trackInlineExposure = useCallback(\n    ({ exposureUrl, recommendationId, linkElement }: InlineExposureTrackingParams) => {\n      exposureTrackerRef.current.startTracking({\n        exposureUrl,\n        recommendationId,\n        linkElement,\n        sessionId,\n        logPrefix: '[useWeaveAdFormat]'\n      });\n    },\n    [sessionId]\n  );\n\n  // Phase 1: Enhanced Mutation Silence Detection\n  // Track when last mutation occurred for silence detection\n  const lastMutationTimeRef = useRef<number>(Date.now());\n  // Count consecutive silence checks (requires 2 for confirmation)\n  const mutationSilenceCountRef = useRef<number>(0);\n  // Store interval timer for cleanup\n  const silenceCheckIntervalRef = useRef<NodeJS.Timeout | null>(null);\n\n  // Phase 2: Adaptive Debounce Detection\n  // Track timestamps of recent mutations to calculate adaptive timeout\n  const mutationTimestampsRef = useRef<number[]>([]);\n  // Store the calculated adaptive timeout value\n  const adaptiveTimeoutRef = useRef<number>(300); // Default to 300ms\n\n  const processWeaveFormat = useCallback(async () => {\n    if (!sdk || !sessionId || processingRef.current) {\n      return;\n    }\n\n    processingRef.current = true;\n    detectedLinksRef.current = 0;\n\n    try {\n      const container = document.getElementById(options.llmOutputContainerId);\n      if (!container) {\n        \n        return;\n      }\n\n      // Get the WeaveResponseProcessor from SDK\n      const weaveProcessor = (sdk as any).getWeaveProcessor?.(); // eslint-disable-line @typescript-eslint/no-explicit-any\n      if (!weaveProcessor) {\n        return;\n      }\n\n      // Scan and process AdMesh links in the container\n      const detectedLinks = weaveProcessor.scanAndProcessLinks(\n        container,\n        [], // Recommendations will be fetched from SDK cache\n        ({ exposureUrl, recommendationId, linkElement }: InlineExposureTrackingParams) =>\n          trackInlineExposure({ exposureUrl, recommendationId, linkElement })\n      );\n\n      detectedLinksRef.current = detectedLinks.length;\n      const hasLinks = detectedLinks.length > 0;\n\n      // Update the flag indicating whether links were found\n      if (hasLinks && !linksFoundRef.current) {\n        // Links detected (first time or after streaming)\n        linksFoundRef.current = true;\n        options.onLinksDetected?.(detectedLinks.length);\n        callbackFiredRef.current = true;\n      } else if (!hasLinks && linksFoundRef.current) {\n        // Links were found before but now they're gone (shouldn't happen in normal flow)\n        linksFoundRef.current = false;\n        callbackFiredRef.current = false;\n      } else if (!hasLinks && !callbackFiredRef.current) {\n        // No links found and callback hasn't been fired yet\n        // Use enhanced mutation silence detection to wait for streaming to complete\n        // This prevents firing the callback too early during streaming\n\n        // Clear existing debounce timer\n        if (debounceTimerRef.current) {\n          clearTimeout(debounceTimerRef.current);\n        }\n\n        // Clear existing silence check interval\n        if (silenceCheckIntervalRef.current) {\n          clearInterval(silenceCheckIntervalRef.current);\n        }\n\n        // Reset silence counter when starting new detection\n        mutationSilenceCountRef.current = 0;\n        lastMutationTimeRef.current = Date.now();\n\n        // Phase 1 + Phase 2: Enhanced Mutation Silence Detection with Adaptive Timeout\n        // Check for mutation silence at adaptive intervals\n        // Require 2 consecutive silence checks before declaring streaming complete\n        const silenceCheckInterval = Math.max(100, adaptiveTimeoutRef.current / 3); // Check 3x per adaptive timeout\n\n        silenceCheckIntervalRef.current = setInterval(() => {\n          const timeSinceLastMutation = Date.now() - lastMutationTimeRef.current;\n          const SILENCE_THRESHOLD = adaptiveTimeoutRef.current; // Use adaptive timeout as silence threshold\n\n          if (timeSinceLastMutation >= SILENCE_THRESHOLD) {\n            // Mutation silence detected\n            mutationSilenceCountRef.current++;\n\n            // Require 2 consecutive silence checks for confirmation\n            if (mutationSilenceCountRef.current >= 2) {\n              // Clear the interval\n              if (silenceCheckIntervalRef.current) {\n                clearInterval(silenceCheckIntervalRef.current);\n                silenceCheckIntervalRef.current = null;\n              }\n\n              // Fire callback if no links were found\n              if (!linksFoundRef.current && !callbackFiredRef.current) {\n                options.onNoLinksDetected?.();\n                callbackFiredRef.current = true;\n              }\n            }\n          } else {\n            // Mutations still happening, reset counter\n            mutationSilenceCountRef.current = 0;\n          }\n        }, silenceCheckInterval);\n\n        // Phase 2: Fallback timeout using adaptive timeout\n        // Set a maximum timeout to ensure we eventually fire the callback\n        // This handles edge cases where mutations might be very infrequent\n        const maxFallbackTimeout = Math.max(1500, adaptiveTimeoutRef.current * 5); // At least 1500ms, or 5x adaptive timeout\n\n        debounceTimerRef.current = setTimeout(() => {\n          // Clear the silence check interval\n          if (silenceCheckIntervalRef.current) {\n            clearInterval(silenceCheckIntervalRef.current);\n            silenceCheckIntervalRef.current = null;\n          }\n\n          // Fire callback if no links were found\n          if (!linksFoundRef.current && !callbackFiredRef.current) {\n            options.onNoLinksDetected?.();\n            callbackFiredRef.current = true;\n          }\n        }, maxFallbackTimeout);\n      } else if (hasLinks && callbackFiredRef.current && !linksFoundRef.current) {\n        // Links detected after we initially said \"no links found\"\n        // This happens when links arrive during streaming\n\n\n        // Clear debounce timer since we found links\n        if (debounceTimerRef.current) {\n          clearTimeout(debounceTimerRef.current);\n          debounceTimerRef.current = null;\n        }\n\n        linksFoundRef.current = true;\n        options.onLinksDetected?.(detectedLinks.length);\n        callbackFiredRef.current = true;\n      } else {\n        \n      }\n    } catch (error) {\n      const err = error instanceof Error ? error : new Error(String(error));\n      options.onError?.(err);\n    } finally {\n      processingRef.current = false;\n    }\n  }, [sdk, sessionId, options, trackInlineExposure]);\n\n  // Phase 2: Calculate adaptive debounce timeout based on mutation frequency\n  const calculateAdaptiveTimeout = useCallback(() => {\n    const timestamps = mutationTimestampsRef.current;\n\n    // Need at least 2 timestamps to calculate interval\n    if (timestamps.length < 2) {\n      adaptiveTimeoutRef.current = 300; // Default to 300ms\n      return;\n    }\n\n    // Calculate intervals between consecutive mutations\n    const intervals: number[] = [];\n    for (let i = 1; i < timestamps.length; i++) {\n      intervals.push(timestamps[i] - timestamps[i - 1]);\n    }\n\n    // Calculate average interval\n    const avgInterval = intervals.reduce((a, b) => a + b, 0) / intervals.length;\n\n    // Adaptive timeout: 3x the average interval, min 100ms, max 1000ms\n    const adaptiveTimeout = Math.max(100, Math.min(avgInterval * 3, 1000));\n\n    adaptiveTimeoutRef.current = adaptiveTimeout;\n  }, []);\n\n  // Watch for changes in the LLM output container\n  useEffect(() => {\n    const container = document.getElementById(options.llmOutputContainerId);\n    if (!container) {\n      return;\n    }\n\n    // Initial scan\n    processWeaveFormat();\n\n    // Set up MutationObserver for streaming responses\n    const observer = new MutationObserver(() => {\n      const now = Date.now();\n\n      // Phase 1: Update last mutation time for silence detection\n      lastMutationTimeRef.current = now;\n      // Reset silence counter since we detected a mutation\n      mutationSilenceCountRef.current = 0;\n\n      // Phase 2: Track mutation timestamp for adaptive debounce calculation\n      mutationTimestampsRef.current.push(now);\n      // Keep only last 10 timestamps to avoid memory bloat\n      if (mutationTimestampsRef.current.length > 10) {\n        mutationTimestampsRef.current.shift();\n      }\n      // Recalculate adaptive timeout based on recent mutation pattern\n      calculateAdaptiveTimeout();\n\n      processWeaveFormat();\n    });\n\n    observer.observe(container, {\n      childList: true,\n      subtree: true,\n      characterData: false\n    });\n\n    return () => {\n      observer.disconnect();\n      // Clean up debounce timer on unmount\n      if (debounceTimerRef.current) {\n        clearTimeout(debounceTimerRef.current);\n      }\n      // Phase 1: Clean up silence check interval on unmount\n      if (silenceCheckIntervalRef.current) {\n        clearInterval(silenceCheckIntervalRef.current);\n      }\n    };\n  }, [options.llmOutputContainerId, processWeaveFormat, calculateAdaptiveTimeout]);\n\n  return {\n    isProcessing: processingRef.current,\n    detectedLinksCount: detectedLinksRef.current,\n    linksFound: linksFoundRef.current,\n    shouldRenderFallback: !linksFoundRef.current && callbackFiredRef.current,\n    processWeaveFormat\n  };\n};\n\nexport default useWeaveAdFormat;\n","/**\n * AdMesh UI SDK - Main Entry Point\n * \n * Zero-code integration for displaying AdMesh recommendations\n */\n\n// Core SDK\nexport { AdMeshSDK } from './sdk/AdMeshSDK';\nexport type { AdMeshSDKConfig, ShowRecommendationsOptions } from './sdk/AdMeshSDK';\n\n// Tracking\nexport { AdMeshTracker } from './sdk/AdMeshTracker';\nexport type { TrackerConfig } from './sdk/AdMeshTracker';\n\n// Rendering\nexport { AdMeshRenderer } from './sdk/AdMeshRenderer';\nexport type { RenderOptions } from './sdk/AdMeshRenderer';\n\n// Weave Response Processing\nexport { WeaveResponseProcessor } from './sdk/WeaveResponseProcessor';\nexport type { DetectedLink, ProcessorConfig } from './sdk/WeaveResponseProcessor';\n\n// Weave format is now integrated into AdMeshSDK\n// Use format: 'weave' option in showRecommendations() method\n\n// Provider Pattern (Simplified Integration)\nexport { AdMeshProvider } from './context/AdMeshProvider';\nexport type { AdMeshProviderProps } from './context/AdMeshProvider';\n\n// Components\nexport { AdMeshRecommendations } from './components/AdMeshRecommendations';\nexport type { AdMeshRecommendationsProps } from './components/AdMeshRecommendations';\nexport { WeaveFallbackRecommendations } from './components/WeaveFallbackRecommendations';\nexport type { WeaveFallbackRecommendationsProps } from './components/WeaveFallbackRecommendations';\n\n// Context\nexport { AdMeshContext, useAdMeshContext } from './context/AdMeshContext';\nexport type { AdMeshContextValue } from './context/AdMeshContext';\nexport { WeaveAdFormatProvider, useWeaveAdFormatContext } from './context/WeaveAdFormatContext';\nexport type { WeaveAdFormatContextType } from './context/WeaveAdFormatContext';\n\n// Components\nexport { AdMeshEcommerceCards } from './components/AdMeshEcommerceCards';\nexport { AdMeshLayout } from './components/AdMeshLayout';\nexport { AdMeshTailAd } from './components/AdMeshTailAd';\nexport type { AdMeshTailAdProps } from './components/AdMeshTailAd';\nexport { AdMeshBridgeFormat } from './components/AdMeshBridgeFormat';\nexport type { AdMeshBridgeFormatProps } from './components/AdMeshBridgeFormat';\nexport { AdMeshFollowup } from './components/AdMeshFollowup';\nexport type { AdMeshFollowupProps } from './components/AdMeshFollowup';\nexport { AdMeshViewabilityTracker } from './components/AdMeshViewabilityTracker';\nexport { AdMeshLinkTracker } from './components/AdMeshLinkTracker';\nexport { AdMeshBadge } from './components/AdMeshBadge';\nexport { WeaveAdFormatContainer } from './components/WeaveAdFormatContainer';\nexport type { WeaveAdFormatContainerProps } from './components/WeaveAdFormatContainer';\n\n// Hooks\nexport { useAdMesh } from './hooks/useAdMesh';\nexport { useAdMeshStyles } from './hooks/useAdMeshStyles';\nexport { useViewabilityTracker } from './hooks/useViewabilityTracker';\nexport { useWeaveAdFormat } from './hooks/useWeaveAdFormat';\nexport type { UseWeaveAdFormatOptions } from './hooks/useWeaveAdFormat';\n\n// Types\nexport type { AdMeshTheme } from './types/index';\n\n// Streaming Events (for event-driven link detection)\nexport {\n  dispatchStreamingStartEvent,\n  dispatchStreamingCompleteEvent,\n  onStreamingStart,\n  onStreamingComplete,\n  STREAMING_START_EVENT,\n  STREAMING_COMPLETE_EVENT\n} from './utils/streamingEvents';\nexport type {\n  StreamingStartEventDetail,\n  StreamingCompleteEventDetail\n} from './utils/streamingEvents';\n\n// Inline exposure tracking helper\nexport {\n  createInlineExposureTracker\n} from './utils/inlineExposureTracker';\nexport type {\n  InlineExposureTracker,\n  InlineExposureTrackingParams\n} from './utils/inlineExposureTracker';\n\n// Version\nexport const VERSION = '1.0.10';\n"],"names":["isProduction","_a","logger","args","calculateMRCStandards","adWidth","adHeight","customStandards","isLargeAd","detectDeviceType","viewportWidth","calculateVisibilityPercentage","element","rect","viewportHeight","elementHeight","elementWidth","visibleTop","visibleBottom","visibleLeft","visibleRight","visibleHeight","visibleWidth","visibleArea","totalArea","calculateScrollDepth","windowHeight","documentHeight","scrollTop","scrollableHeight","getElementPosition","scrollLeft","collectContextMetrics","position","isDarkMode","generateSessionId","meetsViewabilityThreshold","visibilityPercentage","visibleDuration","standards","formatTimestamp","date","calculateAverage","numbers","acc","num","throttle","func","limit","inThrottle","DEFAULT_CONFIG","globalConfig","useViewabilityTracker","productId","offerId","agentId","recommendationId","elementRef","customConfig","config","sessionId","useRef","state","setState","useState","mrcStandards","visibilityStartTime","viewableStartTime","hoverStartTime","focusStartTime","visibilityPercentages","eventBatch","batchTimeout","log","useCallback","message","sendEvent","eventType","additionalData","contextMetrics","event","flushBatch","updateVisibility","now","loadTime","prev","newState","wasVisible","isNowVisible","wasViewable","isNowViewable","viewableDuration","useEffect","observer","entries","handleScroll","handleMouseEnter","handleMouseLeave","hoverDuration","handleFocus","handleBlur","focusDuration","handleClick","sessionDuration","AdMeshViewabilityTracker","exposureUrl","children","className","style","onViewabilityChange","onVisible","onViewable","onClick","exposureFired","viewabilityState","previousViewable","error","previousVisible","jsx","AdMeshContext","React","useAdMeshContext","context","isValidUrl","url","getCTALabel","ctaLabel","AdMeshTailAd","recommendations","theme","contextUserId","contextModel","contextSessionId","sdk","effectiveSessionId","isHidden","setIsHidden","feedbackSubmitted","setFeedbackSubmitted","isSubmittingFeedback","setIsSubmittingFeedback","firstRecommendation","creativeInput","shortDescription","offerSummary","brandName","productName","logoUrl","clickUrl","headlineText","headlineSuffix","handleContainerClick","source","e","handleBrandNameClick","handleCTAClick","handleLogoClick","getApiBaseUrl","submitFeedback","feedbackType","apiBaseUrl","payload","endpointUrl","response","errorMessage","errorData","result","errorDetails","handleLikeClick","handleDislikeClick","logoError","setLogoError","brandInitial","cardBackground","_b","cardBorder","_d","_c","cardBorderRadius","_f","_e","defaultShadow","hoverShadow","cardShadow","_g","_i","_h","cardHoverShadow","_j","jsxs","_k","Fragment","useAdMesh","extractCTAText","bridgePrompt","extractedProduct","productPatterns","pattern","match","product","setupMatch","AdMeshBridgeFormat","recommendation","onLinkClick","onPasteToInput","bridgeHeadline","bridgeDescription","ctaText","shouldShowCTA","hasOwn","classNames","classes","i","arg","appendClass","parseValue","key","value","newClass","module","AdMeshLinkTracker","admeshLink","trackingData","link","AdMeshEcommerceCards","brand","title","showTitle","cardClassName","onProductClick","maxCards","cardWidth","borderRadius","shadow","propSessionId","onFeedback","displayItems","getBrandName","getBrandLogo","getBrandDescription","getCtaUrl","item","getCtaLabel","getPrice","productPrice","getProductName","getProductDisplayContent","hash","str","index","getProductImageUrl","getProductDiscount","discount","getCardWidthClass","getBorderRadiusClass","getShadowClass","getThemeClasses","handleProductClick","brandLogo","brandDescription","itemId","ctaUrl","price","productDisplayContent","productDiscount","productImageUrl","productLink","parentRecommendationId","parent","AdMeshLayout","summaryText","recs","summary","validRecs","rec","renderContent","firstRec","preferredFormat","products","PlusIcon","size","AdMeshFollowup","onExecuteQuery","followupQuery","followupEngagementUrl","followupExposureUrl","handleFollowupClick","AdMeshTracker","__publicField","resolve","timeoutId","entry","cleanupTimeout","threshold","engagementUrl","AdMeshProvider","apiKey","language","geo_country","userId","model","messages","sdkRef","processedMessageIds","setProcessedMessageIds","AdMeshSDK","contextValue","messageId","updated","AdMeshRenderer","options","container","existingRoot","root","ReactDOM","tailSummary","containerId","timestamp","random","aipResponse","renderer","tracker","params","turnIndex","devicePlatform","formFactor","jsonBody","data","responseAny","creative","format","headlineFromCreative","bridgeHeadlineFromCreative","bridgeDescriptionFromCreative","bridgePromptFromCreative","ctaLabelFromCreative","preservedAssets","productsFromTopLevel","productsFromCreative","WeaveResponseProcessor","optimizedLinks","onExposurePixel","detectedLinks","links","clickUrlMap","r","brandUrlMap","redirectUrl","normalizedUrl","href","linkKey","actualHref","normalizedHref","detectedLink","childElements","child","prevNode","text","tagName","nextNode","parentNode","subLabel","isTooltipVisible","closeTooltipOnClickOutside","nextSibling","domain","AdMeshRecommendations","onRecommendationsShown","onError","query","_followups_container_id","_onExecuteQuery","onFollowupDetected","isContainerReady","propUserId","setRecommendation","detectedFormat","setDetectedFormat","isLoading","setIsLoading","setError","fetchedMessageIdRef","isFetchingRef","onRecommendationsShownRef","onErrorRef","onFollowupDetectedRef","convertAIPResponseToRecommendation","formatFromResponse","followupQueryTopLevel","followupQueryInCreative","followupEngagementUrlTopLevel","followupEngagementUrlInCreative","followupExposureUrlTopLevel","followupExposureUrlInCreative","followupContainer","setFollowupContainer","attempts","maxAttempts","checkForContainer","interval","convertedRecommendation","selectedFormat","err","renderFollowupPortal","createPortal","hasBridgePrompt","formatFromRec","preferredFormatFromRec","WeaveFallbackRecommendations","fallback","previousRecommendations","containerRef","setContainerId","hasPreviousRecs","sdkAny","convertMethod","getRendererMethod","getTrackerMethod","sdkTheme","WeaveAdFormatContext","createContext","WeaveAdFormatProvider","shouldRenderFallback","useWeaveAdFormatContext","useContext","badgeTypeVariants","badgeTypeIcons","AdMeshBadge","type","variant","effectiveVariant","icon","badgeClasses","STREAMING_START_EVENT","STREAMING_COMPLETE_EVENT","dispatchStreamingStartEvent","detail","dispatchStreamingCompleteEvent","metadata","onStreamingStart","callback","handler","customEvent","onStreamingComplete","createInlineExposureTracker","firedKeys","activeTrackers","cleanupTracker","linkElement","logPrefix","dedupeKey","trackerState","fireExposurePixel","FinalLinkDetectionCheck","onLinksFound","onNoLinksFound","checkComplete","setCheckComplete","waitingForStreamEnd","setWaitingForStreamEnd","linksFound","setLinksFound","exposureTrackerRef","onLinksFoundRef","onNoLinksFoundRef","containerIdRef","sessionIdRef","queryRef","trackExposurePixel","performFinalCheck","weaveProcessor","recsToUse","eventReceived","cleanup","WeaveAdFormatContainer","fallbackFormat","onLinksDetected","onNoLinksDetected","onFallbackChange","onWeaveAttempt","onWeaveOutcome","scannedRef","weaveProcessorRef","setRecommendations","recommendationsRef","recommendationWithFollowup","setRecommendationWithFollowup","recommendationWithFollowupData","resolvedFormat","isWeaveFormat","count","ADMESH_STYLE_ID","ADMESH_RESET_ID","ADMESH_CSS_RESET","ADMESH_CORE_STYLES","injectAdMeshStyles","resetStyle","coreStyle","ADMESH_STYLES","stylesInjected","useAdMeshStyles","styleElement","useWeaveAdFormat","processingRef","detectedLinksRef","linksFoundRef","callbackFiredRef","debounceTimerRef","trackInlineExposure","lastMutationTimeRef","mutationSilenceCountRef","silenceCheckIntervalRef","mutationTimestampsRef","adaptiveTimeoutRef","processWeaveFormat","hasLinks","silenceCheckInterval","timeSinceLastMutation","SILENCE_THRESHOLD","maxFallbackTimeout","calculateAdaptiveTimeout","timestamps","intervals","avgInterval","a","b","adaptiveTimeout","VERSION"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","x_google_ignoreList":[8]}