{"version":3,"file":"qaid.umd.cjs","sources":["../src/icons.ts","../src/styles.ts","../src/element-selector.ts","../src/modal-positioning.ts","../src/console-capture.ts","../src/network-capture.ts","../src/video-capture.ts","../src/dom-utils.ts","../src/screenshot.ts","../src/screenshot-dom.ts","../src/embed.ts","../src/index.ts"],"sourcesContent":["/**\n * SVG icon strings for thumbs up/down buttons\n */\n\nexport const THUMBS_UP_ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n  <path stroke-linecap=\"round\" stroke-linejoin=\"round\" 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\nexport const THUMBS_DOWN_ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n  <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M10 14H5.236a2 2 0 01-1.789-2.894l3.5-7A2 2 0 018.737 3h4.018a2 2 0 01.485.06l3.76.94m-7 10v5a2 2 0 002 2h.095c.5 0 .905-.405.905-.905 0-.714.211-1.412.608-2.006L17 13V4m-7 10h2m5-10h2a2 2 0 012 2v6a2 2 0 01-2 2h-2.5\"/>\n</svg>`;\n\nexport const RECORD_ICON = `<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n  <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 10.5l4.72-4.72a.75.75 0 011.28.53v11.38a.75.75 0 01-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25h-9A2.25 2.25 0 002.25 7.5v9a2.25 2.25 0 002.25 2.25z\"/>\n</svg>`;\n","/**\n * CSS styles for the feedback embed\n * Uses .qaid- prefix to avoid conflicts\n */\n\n// Import CSS as strings (vite handles minification in production)\nimport shadowStyles from \"./styles-shadow.css?inline\";\nimport lightStyles from \"./styles-light.css?inline\";\n\nlet instanceCount = 0;\n\n/** Default button styles included in shadow root */\nconst DEFAULT_BUTTON_STYLES = `button.qaid-btn{width:var(--qaid-btn-size);height:var(--qaid-btn-size);border-radius:50%;border:none;background:#f3f4f6;color:#374151;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);transition:background-color .2s,color .2s,transform .2s;-webkit-appearance:none;appearance:none;--qaid-hover-up-bg:var(--qaid-positive);--qaid-hover-up-color:#fff;--qaid-hover-down-bg:var(--qaid-negative);--qaid-hover-down-color:#fff}button.qaid-btn:hover{transform:scale(1.05)}button.qaid-btn-up:hover{background:var(--qaid-hover-up-bg);color:var(--qaid-hover-up-color)}button.qaid-btn-down:hover{background:var(--qaid-hover-down-bg);color:var(--qaid-hover-down-color)}button.qaid-btn svg{width:var(--qaid-icon-size);height:var(--qaid-icon-size)}`;\n\nexport interface BuildCssVarsOptions {\n  positiveColor?: string;\n  negativeColor?: string;\n  /** Color for selected element marker */\n  markerColor?: string;\n  /** Button size: small (36px), medium (48px), large (64px) */\n  buttonSize?: \"small\" | \"medium\" | \"large\";\n  /** Modal width in pixels */\n  modalWidth?: number;\n  /** Backdrop opacity (0-1) */\n  backdropOpacity?: number;\n  /** Font family */\n  fontFamily?: string;\n  /** Base font size in pixels */\n  fontSize?: number;\n}\n\nconst BUTTON_SIZES = {\n  small: 36,\n  medium: 48,\n  large: 64,\n} as const;\n\nconst ICON_SIZES = {\n  small: 18,\n  medium: 24,\n  large: 32,\n} as const;\n\n/**\n * Calculate relative luminance of a color\n * Returns value between 0 (black) and 1 (white)\n */\nfunction getLuminance(r: number, g: number, b: number): number {\n  const [rs, gs, bs] = [r, g, b].map((c) => {\n    c = c / 255;\n    return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n  });\n  return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n}\n\n/**\n * Parse a color string (hex or rgb) and return RGB values\n */\nfunction parseColor(color: string): { r: number; g: number; b: number } | null {\n  // Hex format\n  if (color.startsWith(\"#\")) {\n    const hex = color.slice(1);\n    const fullHex = hex.length === 3\n      ? hex.split(\"\").map((c) => c + c).join(\"\")\n      : hex;\n    const num = parseInt(fullHex, 16);\n    return {\n      r: (num >> 16) & 255,\n      g: (num >> 8) & 255,\n      b: num & 255,\n    };\n  }\n  // RGB format\n  const match = color.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);\n  if (match) {\n    return {\n      r: parseInt(match[1]),\n      g: parseInt(match[2]),\n      b: parseInt(match[3]),\n    };\n  }\n  return null;\n}\n\n/**\n * Get the best contrasting text color (black or white) for a background\n */\nfunction getContrastTextColor(bgColor: string): string {\n  const rgb = parseColor(bgColor);\n  if (!rgb) return \"white\";\n  const luminance = getLuminance(rgb.r, rgb.g, rgb.b);\n  // Use white text on dark backgrounds, black on light\n  return luminance > 0.4 ? \"black\" : \"white\";\n}\n\n/**\n * Build a map of CSS variable names to values for per-instance scoping\n */\nexport function buildCssVars(options: BuildCssVarsOptions = {}): Record<string, string> {\n  const {\n    positiveColor = \"rgb(0, 200, 83)\",\n    negativeColor = \"rgb(255, 0, 0)\",\n    markerColor = \"#6366f1\",\n    buttonSize = \"medium\",\n    modalWidth = 400,\n    backdropOpacity = 0.3,\n    fontFamily = \"system-ui, -apple-system, sans-serif\",\n    fontSize = 16,\n  } = options;\n\n  const btnSize = BUTTON_SIZES[buttonSize];\n  const iconSize = ICON_SIZES[buttonSize];\n  const markerTextColor = getContrastTextColor(markerColor);\n\n  return {\n    \"--qaid-positive\": positiveColor,\n    \"--qaid-negative\": negativeColor,\n    \"--qaid-marker\": markerColor,\n    \"--qaid-marker-text\": markerTextColor,\n    \"--qaid-btn-size\": `${btnSize}px`,\n    \"--qaid-icon-size\": `${iconSize}px`,\n    \"--qaid-modal-width\": `${modalWidth}px`,\n    \"--qaid-backdrop-opacity\": String(backdropOpacity),\n    \"--qaid-font-family\": fontFamily,\n    \"--qaid-font-size\": `${fontSize}px`,\n  };\n}\n\n/**\n * Apply CSS variables to an element via inline style properties\n */\nexport function applyCssVars(el: HTMLElement, vars: Record<string, string>): void {\n  for (const [name, value] of Object.entries(vars)) {\n    el.style.setProperty(name, value);\n  }\n}\n\n/**\n * Get the CSS string to inject into a shadow root\n * Includes base shadow styles + default button styles\n */\nexport function getEmbedStyles(): string {\n  return shadowStyles + DEFAULT_BUTTON_STYLES;\n}\n\n/**\n * Inject light DOM styles (cursor override + highlight)\n * Reference-counted across instances\n */\nexport function injectStyles(): void {\n  instanceCount++;\n  if (instanceCount > 1) return;\n\n  const style = document.createElement(\"style\");\n  style.id = \"qaid-styles\";\n  style.textContent = lightStyles;\n  document.head.appendChild(style);\n}\n\n/**\n * Remove light DOM styles when last instance is destroyed\n */\nexport function removeStyles(): void {\n  if (instanceCount <= 0) return;\n  instanceCount--;\n  if (instanceCount === 0) {\n    const style = document.getElementById(\"qaid-styles\");\n    if (style) {\n      style.remove();\n    }\n  }\n}\n\n/** Reset internal state — for tests only */\nexport function _resetStylesState(): void {\n  instanceCount = 0;\n  const style = document.getElementById(\"qaid-styles\");\n  if (style) {\n    style.remove();\n  }\n}\n","/**\n * Element selector generation utilities\n */\n\n/** Data attributes to look for (in priority order) */\nexport const DATA_ATTRS = [\"data-comp\", \"data-qa\", \"data-testid\", \"data-id\"];\n\nexport interface ElementInfo {\n  selector: string;\n  text: string;\n  dataAttr: string | null;\n}\n\n/**\n * Find the first matching data attribute on an element or its ancestors\n */\nexport function findDataAttribute(\n  element: Element,\n  stopAt: Element = document.body\n): string | null {\n  let current: Element | null = element;\n\n  while (current && current !== stopAt) {\n    for (const attr of DATA_ATTRS) {\n      const value = current.getAttribute(attr);\n      if (value) {\n        return `${attr}=\"${value}\"`;\n      }\n    }\n    current = current.parentElement;\n  }\n\n  return null;\n}\n\n/**\n * Get truncated text content from an element\n */\nexport function getTruncatedText(element: Element, maxLength = 100): string {\n  const textContent = element.textContent?.trim().slice(0, maxLength) || \"\";\n  return textContent.length === maxLength ? textContent + \"...\" : textContent;\n}\n\n/**\n * Get the nth-child index of an element among its siblings\n */\nfunction getNthChildIndex(element: Element): number {\n  let index = 1;\n  let sibling = element.previousElementSibling;\n  while (sibling) {\n    index++;\n    sibling = sibling.previousElementSibling;\n  }\n  return index;\n}\n\n/**\n * Generate an nth-child path from body to the element\n * This is always a valid CSS selector and uniquely identifies the element\n * Exported for testing\n */\nexport function generateNthChildPath(element: Element): string {\n  const path: string[] = [];\n  let current: Element | null = element;\n\n  while (current && current !== document.body && current !== document.documentElement) {\n    const tag = current.tagName.toLowerCase();\n    const index = getNthChildIndex(current);\n    path.unshift(`${tag}:nth-child(${index})`);\n    current = current.parentElement;\n  }\n\n  return path.length > 0 ? `body > ${path.join(\" > \")}` : \"body\";\n}\n\n/**\n * Escape special CSS characters in a string (for IDs with special chars)\n */\nfunction escapeCSSIdentifier(str: string): string {\n  return str.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, \"\\\\$1\");\n}\n\n/**\n * Generate a selector string for an element\n * Priority: data attribute > ID > nth-child path\n */\nexport function generateSelector(element: Element): string {\n  // Try data attribute first (on element or ancestors) - most stable\n  const dataAttr = findDataAttribute(element);\n  if (dataAttr) {\n    return `[${dataAttr}]`;\n  }\n\n  // Try ID (escaped for special characters)\n  if (element.id) {\n    return `#${escapeCSSIdentifier(element.id)}`;\n  }\n\n  // Fall back to nth-child path - always valid and unique\n  return generateNthChildPath(element);\n}\n\n/**\n * Generate complete element info for feedback\n */\nexport function generateElementInfo(element: Element): ElementInfo {\n  const text = getTruncatedText(element);\n  const dataAttr = findDataAttribute(element);\n  const selector = generateSelector(element);\n\n  return { selector, text, dataAttr };\n}\n","/**\n * Modal positioning utilities\n */\n\nimport type { SelectedBounds } from \"./types\";\n\nexport interface ModalPosition {\n  top: number;\n  left: number;\n  position: \"above\" | \"below\";\n}\n\nexport interface ArrowPosition {\n  left: number;\n}\n\nexport interface ModalDimensions {\n  width: number;\n  height: number;\n  arrowHeight: number;\n  gap: number;\n  viewportPadding: number;\n}\n\nconst DEFAULT_DIMENSIONS: ModalDimensions = {\n  width: 400,\n  height: 280,\n  arrowHeight: 12,\n  gap: 8,\n  viewportPadding: 16,\n};\n\n/**\n * Calculate whether modal should go above or below the target element\n */\nexport function calculateVerticalPosition(\n  bounds: SelectedBounds,\n  viewportHeight: number,\n  totalHeight: number,\n  gap: number,\n  viewportPadding: number\n): { top: number; position: \"above\" | \"below\" } {\n  const spaceAbove = bounds.y;\n  const spaceBelow = viewportHeight - (bounds.y + bounds.height);\n\n  // Prefer below if there's enough space\n  if (spaceBelow >= totalHeight + gap) {\n    return {\n      top: bounds.y + bounds.height + gap,\n      position: \"below\",\n    };\n  }\n\n  // Try above if there's enough space\n  if (spaceAbove >= totalHeight + gap) {\n    return {\n      top: bounds.y - totalHeight - gap,\n      position: \"above\",\n    };\n  }\n\n  // Neither fits perfectly - clamp to viewport\n  const position = spaceBelow > spaceAbove ? \"below\" : \"above\";\n  let top: number;\n\n  if (position === \"below\") {\n    top = Math.min(\n      bounds.y + bounds.height + gap,\n      viewportHeight - totalHeight - viewportPadding\n    );\n  } else {\n    top = Math.max(viewportPadding, bounds.y - totalHeight - gap);\n  }\n\n  return { top, position };\n}\n\n/**\n * Calculate horizontal position of modal, clamped to viewport\n */\nexport function calculateHorizontalPosition(\n  bounds: SelectedBounds,\n  viewportWidth: number,\n  modalWidth: number,\n  viewportPadding: number\n): number {\n  const centerX = bounds.x + bounds.width / 2;\n  let left = centerX - modalWidth / 2;\n\n  // Clamp to viewport\n  left = Math.max(viewportPadding, Math.min(left, viewportWidth - modalWidth - viewportPadding));\n\n  return left;\n}\n\n/**\n * Calculate arrow position relative to modal\n * Points at the click position, not the element center\n */\nexport function calculateArrowPosition(\n  bounds: SelectedBounds,\n  modalLeft: number,\n  modalWidth: number,\n  minOffset = 24,\n  arrowWidth = 24\n): number {\n  // Use click position for arrow, not element center\n  const targetX = bounds.clickX;\n  // Subtract half the arrow width to center it on the target\n  const arrowLeft = targetX - modalLeft - arrowWidth / 2;\n\n  // Clamp arrow to stay within modal bounds\n  return Math.max(minOffset, Math.min(arrowLeft, modalWidth - minOffset - arrowWidth / 2));\n}\n\n/**\n * Calculate complete modal position based on selected element bounds\n */\nexport function calculateModalPosition(\n  bounds: SelectedBounds,\n  viewportWidth: number,\n  viewportHeight: number,\n  dimensions: ModalDimensions = DEFAULT_DIMENSIONS\n): ModalPosition {\n  const totalHeight = dimensions.height + dimensions.arrowHeight;\n\n  const vertical = calculateVerticalPosition(\n    bounds,\n    viewportHeight,\n    totalHeight,\n    dimensions.gap,\n    dimensions.viewportPadding\n  );\n\n  const left = calculateHorizontalPosition(\n    bounds,\n    viewportWidth,\n    dimensions.width,\n    dimensions.viewportPadding\n  );\n\n  return {\n    top: vertical.top,\n    left,\n    position: vertical.position,\n  };\n}\n\n/**\n * Calculate both modal and arrow positions\n */\nexport function calculateModalAndArrowPosition(\n  bounds: SelectedBounds,\n  viewportWidth: number,\n  viewportHeight: number,\n  dimensions: ModalDimensions = DEFAULT_DIMENSIONS\n): { modal: ModalPosition; arrow: ArrowPosition } {\n  const modal = calculateModalPosition(bounds, viewportWidth, viewportHeight, dimensions);\n\n  const arrowLeft = calculateArrowPosition(\n    bounds,\n    modal.left,\n    dimensions.width\n  );\n\n  return {\n    modal,\n    arrow: { left: arrowLeft },\n  };\n}\n","/**\n * Console capture utilities\n */\n\nimport type { ConsoleError } from \"./types\";\n\nconst MAX_MESSAGES = 20;\n\nexport interface ConsoleCapture {\n  errors: ConsoleError[];\n  restore: () => void;\n}\n\ntype ConsoleLevel = \"error\" | \"warn\" | \"log\";\n\n/**\n * Wrap console methods to capture messages\n */\nexport function captureConsoleErrors(\n  onError?: (error: ConsoleError) => void\n): ConsoleCapture {\n  const errors: ConsoleError[] = [];\n  const originalError = console.error;\n  const originalWarn = console.warn;\n  const originalLog = console.log;\n\n  const capture = (level: ConsoleLevel, args: unknown[]) => {\n    const error: ConsoleError = {\n      message: args.map((arg) => String(arg)).join(\" \"),\n      timestamp: Date.now(),\n      level,\n    };\n\n    // Keep max messages\n    if (errors.length >= MAX_MESSAGES) {\n      errors.shift();\n    }\n    errors.push(error);\n\n    // Call callback if provided\n    if (onError) {\n      onError(error);\n    }\n  };\n\n  console.error = function (...args: unknown[]) {\n    capture(\"error\", args);\n    originalError.apply(console, args);\n  };\n\n  console.warn = function (...args: unknown[]) {\n    capture(\"warn\", args);\n    originalWarn.apply(console, args);\n  };\n\n  console.log = function (...args: unknown[]) {\n    capture(\"log\", args);\n    originalLog.apply(console, args);\n  };\n\n  return {\n    errors,\n    restore: () => {\n      console.error = originalError;\n      console.warn = originalWarn;\n      console.log = originalLog;\n    },\n  };\n}\n\n/**\n * Add an error to the captured errors array\n */\nexport function addError(errors: ConsoleError[], error: ConsoleError): void {\n  if (errors.length >= MAX_MESSAGES) {\n    errors.shift();\n  }\n  errors.push(error);\n}\n\n/**\n * Format console error for display\n */\nexport function formatError(error: ConsoleError): string {\n  const date = new Date(error.timestamp);\n  const time = date.toLocaleTimeString();\n  const levelPrefix = error.level === \"error\" ? \"ERR\" : error.level === \"warn\" ? \"WRN\" : \"LOG\";\n  return `[${time}] [${levelPrefix}] ${error.message}`;\n}\n","/**\n * Network capture utilities\n * Intercepts fetch() and XMLHttpRequest to capture 4xx/5xx errors\n */\n\nimport type { NetworkError } from \"./types\";\n\nconst MAX_ENTRIES = 20;\nconst MAX_BODY_SIZE = 4096; // 4KB\n\nexport interface NetworkCapture {\n  errors: NetworkError[];\n  restore: () => void;\n}\n\n/**\n * Truncate a body to max size\n */\nfunction truncateBody(body: unknown): string | undefined {\n  if (body === null || body === undefined) return undefined;\n  const str = typeof body === \"string\" ? body : JSON.stringify(body);\n  if (str.length > MAX_BODY_SIZE) {\n    return str.slice(0, MAX_BODY_SIZE) + \"…[truncated]\";\n  }\n  return str;\n}\n\n/**\n * Add an error to the buffer, evicting oldest if at capacity\n */\nfunction addEntry(errors: NetworkError[], entry: NetworkError): void {\n  if (errors.length >= MAX_ENTRIES) {\n    errors.shift();\n  }\n  errors.push(entry);\n}\n\n/**\n * Read response body as text, with size limit\n */\nasync function safeReadBody(response: Response): Promise<string | undefined> {\n  try {\n    const text = await response.clone().text();\n    return truncateBody(text);\n  } catch {\n    return undefined;\n  }\n}\n\n/**\n * Intercept fetch() and XMLHttpRequest to capture network errors (4xx/5xx)\n */\nexport function captureNetworkErrors(): NetworkCapture {\n  const errors: NetworkError[] = [];\n  const originalFetch = window.fetch;\n\n  // Monkey-patch fetch\n  window.fetch = async function (input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n    const url = typeof input === \"string\" ? input : input instanceof URL ? input.toString() : input.url;\n    const method = init?.method ?? (typeof input === \"object\" && \"method\" in input ? input.method : \"GET\");\n    let requestBody: string | undefined;\n    if (init?.body) {\n      requestBody = truncateBody(init.body);\n    }\n\n    const response = await originalFetch.apply(window, [input, init]);\n\n    if (response.status >= 400) {\n      const responseBody = await safeReadBody(response);\n      addEntry(errors, {\n        url,\n        method: method.toUpperCase(),\n        status: response.status,\n        statusText: response.statusText,\n        requestBody,\n        responseBody,\n        timestamp: Date.now(),\n      });\n    }\n\n    return response;\n  };\n\n  // Monkey-patch XMLHttpRequest\n  const originalXHROpen = XMLHttpRequest.prototype.open;\n  const originalXHRSend = XMLHttpRequest.prototype.send;\n\n  XMLHttpRequest.prototype.open = function (method: string, url: string | URL, ...rest: unknown[]) {\n    (this as XMLHttpRequest & { _qaid_method: string; _qaid_url: string })._qaid_method = method;\n    (this as XMLHttpRequest & { _qaid_url: string })._qaid_url = typeof url === \"string\" ? url : url.toString();\n    return originalXHROpen.apply(this, [method, url, ...rest] as Parameters<typeof originalXHROpen>);\n  };\n\n  XMLHttpRequest.prototype.send = function (body?: Document | XMLHttpRequestBodyInit | null) {\n    const xhr = this as XMLHttpRequest & { _qaid_method: string; _qaid_url: string };\n    const requestBody = body ? truncateBody(body) : undefined;\n\n    xhr.addEventListener(\"load\", function () {\n      if (xhr.status >= 400) {\n        addEntry(errors, {\n          url: xhr._qaid_url,\n          method: xhr._qaid_method.toUpperCase(),\n          status: xhr.status,\n          statusText: xhr.statusText,\n          requestBody,\n          responseBody: truncateBody(xhr.responseText),\n          timestamp: Date.now(),\n        });\n      }\n    });\n\n    return originalXHRSend.apply(this, [body]);\n  };\n\n  return {\n    errors,\n    restore: () => {\n      window.fetch = originalFetch;\n      XMLHttpRequest.prototype.open = originalXHROpen;\n      XMLHttpRequest.prototype.send = originalXHRSend;\n    },\n  };\n}\n","/**\n * Video capture utilities\n * Uses getDisplayMedia + MediaRecorder for screen recording\n */\n\nexport interface VideoRecorderOptions {\n  /** Max recording duration in seconds. Default: 15 */\n  maxDuration?: number;\n  /** Video bitrate in bps. Default: 800000 (800kbps) */\n  videoBitsPerSecond?: number;\n}\n\nexport interface VideoRecorder {\n  /** Start recording. Requests getDisplayMedia if not already started. */\n  start(): Promise<void>;\n  /** Stop recording and return the video blob. */\n  stop(): Promise<Blob>;\n  /** Register a callback for each second tick (receives seconds elapsed). */\n  onTick(callback: (elapsed: number) => void): void;\n  /** Register a callback for when recording stops (e.g., browser stop button, max duration). */\n  onStop(callback: (blob: Blob | null) => void): void;\n  /** Clean up all resources. */\n  destroy(): void;\n}\n\n/**\n * Check if video recording is supported in this browser\n */\nexport function isVideoRecordingSupported(): boolean {\n  return (\n    typeof navigator !== \"undefined\" &&\n    !!navigator.mediaDevices &&\n    typeof navigator.mediaDevices.getDisplayMedia === \"function\" &&\n    typeof MediaRecorder !== \"undefined\"\n  );\n}\n\n/**\n * Detect the best supported MIME type for recording\n */\nexport function getSupportedMimeType(): string {\n  if (typeof MediaRecorder === \"undefined\") return \"\";\n\n  const candidates = [\n    \"video/webm;codecs=vp9\",\n    \"video/webm;codecs=vp8\",\n    \"video/webm\",\n    \"video/mp4\",\n  ];\n\n  for (const type of candidates) {\n    if (MediaRecorder.isTypeSupported(type)) {\n      return type;\n    }\n  }\n\n  return \"\";\n}\n\n/**\n * Create a video recorder that captures the screen\n */\nexport function createVideoRecorder(options: VideoRecorderOptions = {}): VideoRecorder {\n  const maxDuration = options.maxDuration ?? 15;\n  const videoBitsPerSecond = options.videoBitsPerSecond ?? 800_000;\n\n  let stream: MediaStream | null = null;\n  let recorder: MediaRecorder | null = null;\n  let chunks: Blob[] = [];\n  let tickCallback: ((elapsed: number) => void) | null = null;\n  let stopCallback: ((blob: Blob | null) => void) | null = null;\n  let tickInterval: ReturnType<typeof setInterval> | null = null;\n  let startTime = 0;\n  let resolveStop: ((blob: Blob) => void) | null = null;\n  let rejectStop: ((err: Error) => void) | null = null;\n  let stopped = false;\n  let autoStopTimeout: ReturnType<typeof setTimeout> | null = null;\n\n  function cleanup(): void {\n    if (tickInterval !== null) {\n      clearInterval(tickInterval);\n      tickInterval = null;\n    }\n    if (autoStopTimeout !== null) {\n      clearTimeout(autoStopTimeout);\n      autoStopTimeout = null;\n    }\n    if (stream) {\n      stream.getTracks().forEach((t) => t.stop());\n      stream = null;\n    }\n    recorder = null;\n    chunks = [];\n    tickCallback = null;\n    stopCallback = null;\n    resolveStop = null;\n    rejectStop = null;\n  }\n\n  function finishRecording(): void {\n    if (stopped) return;\n    stopped = true;\n\n    if (recorder && recorder.state !== \"inactive\") {\n      recorder.stop();\n    }\n  }\n\n  return {\n    async start(): Promise<void> {\n      stopped = false;\n      chunks = [];\n\n      const mimeType = getSupportedMimeType();\n      if (!mimeType) {\n        throw new Error(\"No supported video MIME type found\");\n      }\n\n      // Request screen capture\n      stream = await navigator.mediaDevices.getDisplayMedia({\n        video: {\n          frameRate: 15,\n        },\n        audio: false,\n        // @ts-expect-error preferCurrentTab is not in the TS types yet\n        preferCurrentTab: true,\n      });\n\n      // Handle browser \"Stop sharing\" button\n      const videoTrack = stream.getVideoTracks()[0];\n      if (videoTrack) {\n        videoTrack.addEventListener(\"ended\", () => {\n          finishRecording();\n        });\n      }\n\n      recorder = new MediaRecorder(stream, {\n        mimeType,\n        videoBitsPerSecond,\n      });\n\n      recorder.ondataavailable = (e: BlobEvent) => {\n        if (e.data.size > 0) {\n          chunks.push(e.data);\n        }\n      };\n\n      recorder.onstop = () => {\n        const blob = new Blob(chunks, { type: mimeType });\n        if (resolveStop) {\n          resolveStop(blob);\n        }\n        // Notify via callback (for unexpected stops like browser stop button)\n        if (stopCallback) {\n          stopCallback(blob);\n        }\n        // Stop stream tracks\n        if (stream) {\n          stream.getTracks().forEach((t) => t.stop());\n        }\n      };\n\n      recorder.onerror = () => {\n        if (rejectStop) {\n          rejectStop(new Error(\"MediaRecorder error\"));\n        }\n      };\n\n      recorder.start(1000); // collect data every second\n      startTime = Date.now();\n\n      // Start tick interval\n      tickInterval = setInterval(() => {\n        const elapsed = Math.floor((Date.now() - startTime) / 1000);\n        if (tickCallback) {\n          tickCallback(elapsed);\n        }\n      }, 1000);\n\n      // Auto-stop at max duration\n      autoStopTimeout = setTimeout(() => {\n        finishRecording();\n      }, maxDuration * 1000);\n    },\n\n    stop(): Promise<Blob> {\n      return new Promise<Blob>((resolve, reject) => {\n        resolveStop = resolve;\n        rejectStop = reject;\n        finishRecording();\n      });\n    },\n\n    onTick(callback: (elapsed: number) => void): void {\n      tickCallback = callback;\n    },\n\n    onStop(callback: (blob: Blob | null) => void): void {\n      stopCallback = callback;\n    },\n\n    destroy(): void {\n      finishRecording();\n      cleanup();\n    },\n  };\n}\n","/**\n * DOM utility functions\n */\n\n/**\n * Create an element with attributes and optional children\n */\nexport function createElement<K extends keyof HTMLElementTagNameMap>(\n  tag: K,\n  attrs?: Record<string, string>,\n  children?: (Node | string)[]\n): HTMLElementTagNameMap[K] {\n  const el = document.createElement(tag);\n\n  if (attrs) {\n    for (const [key, value] of Object.entries(attrs)) {\n      if (key === \"className\") {\n        el.className = value;\n      } else {\n        el.setAttribute(key, value);\n      }\n    }\n  }\n\n  if (children) {\n    for (const child of children) {\n      if (typeof child === \"string\") {\n        el.appendChild(document.createTextNode(child));\n      } else {\n        el.appendChild(child);\n      }\n    }\n  }\n\n  return el;\n}\n\n/**\n * Check if viewport width indicates mobile device\n */\nexport function isMobileViewport(breakpoint = 640): boolean {\n  return typeof window !== \"undefined\" && window.innerWidth < breakpoint;\n}\n\n/**\n * Get element at point, temporarily hiding shadow hosts so elementFromPoint\n * sees through to the page elements underneath.\n * Uses visibility:hidden which skips the element in elementFromPoint without\n * triggering reflow.\n */\nexport function getElementAtPointUnderOverlay(\n  x: number,\n  y: number,\n  hosts: HTMLElement[]\n): Element | null {\n  const saved = hosts.map((h) => h.style.visibility);\n  hosts.forEach((h) => (h.style.visibility = \"hidden\"));\n  const element = document.elementFromPoint(x, y);\n  hosts.forEach((h, i) => (h.style.visibility = saved[i]));\n  return element;\n}\n\n/**\n * Check if an element is part of the feedback embed\n * With shadow DOM, embed elements are inside shadow hosts marked with\n * data-qaid-embed or data-qaid-embed-overlay\n */\nexport function isEmbedElement(element: Element | null): boolean {\n  if (!element) return false;\n  // Check if the element itself is a shadow host\n  if (element.hasAttribute(\"data-qaid-embed\") || element.hasAttribute(\"data-qaid-embed-overlay\")) return true;\n  // Check ancestors for shadow host\n  return !!element.closest(\"[data-qaid-embed], [data-qaid-embed-overlay]\");\n}\n\n/**\n * Get element bounds with optional padding\n */\nexport function getElementBounds(\n  element: Element,\n  padding = 0\n): { x: number; y: number; width: number; height: number } {\n  const rect = element.getBoundingClientRect();\n  return {\n    x: rect.left - padding,\n    y: rect.top - padding,\n    width: rect.width + padding * 2,\n    height: rect.height + padding * 2,\n  };\n}\n\n/**\n * Remove all elements with a specific class\n */\nexport function removeAllByClass(className: string): void {\n  document.querySelectorAll(`.${className}`).forEach((el) => {\n    el.classList.remove(className);\n  });\n}\n","/**\n * Screenshot capture utility using native Screen Capture API\n */\n\nexport interface ScreenshotOptions {\n  /** Quality of WebP compression (0-1). Default: 1.0 */\n  quality?: number;\n  /** Max width of the screenshot. Default: 1280 */\n  maxWidth?: number;\n  /** Max height of the screenshot. Default: 800 */\n  maxHeight?: number;\n}\n\n/**\n * Captures a screenshot using the native Screen Capture API\n * Requires user permission but produces accurate results\n * Returns a base64-encoded WebP data URL\n */\nexport async function captureScreenshot(\n  options: ScreenshotOptions = {}\n): Promise<string | null> {\n  const { quality = 1.0, maxWidth = 1280, maxHeight = 800 } = options;\n\n  try {\n    // Check if API is available\n    if (!navigator.mediaDevices?.getDisplayMedia) {\n      console.warn('Screen Capture API not available');\n      return null;\n    }\n\n    // Request screen capture - preferCurrentTab auto-selects current tab in supported browsers\n    const stream = await navigator.mediaDevices.getDisplayMedia({\n      preferCurrentTab: true,\n      video: {\n        displaySurface: 'browser',\n      },\n    } as DisplayMediaStreamOptions);\n\n    // Get video track\n    const track = stream.getVideoTracks()[0];\n    const settings = track.getSettings();\n\n    // Create video element\n    const video = document.createElement('video');\n    video.srcObject = stream;\n    video.muted = true;\n\n    await new Promise<void>((resolve) => {\n      video.onloadedmetadata = () => {\n        video.play();\n        resolve();\n      };\n    });\n\n    // Wait for video to have actual frame data\n    await new Promise<void>((resolve) => {\n      const checkFrame = () => {\n        if (video.readyState >= 2) {\n          resolve();\n        } else {\n          requestAnimationFrame(checkFrame);\n        }\n      };\n      checkFrame();\n    });\n\n    // Extra delay to ensure frame is rendered\n    await new Promise((resolve) => setTimeout(resolve, 100));\n\n    // Calculate dimensions\n    const srcWidth = settings.width || video.videoWidth;\n    const srcHeight = settings.height || video.videoHeight;\n    const scale = Math.min(maxWidth / srcWidth, maxHeight / srcHeight, 1);\n    const width = Math.round(srcWidth * scale);\n    const height = Math.round(srcHeight * scale);\n\n    // Draw to canvas\n    const canvas = document.createElement('canvas');\n    canvas.width = width;\n    canvas.height = height;\n\n    const ctx = canvas.getContext('2d');\n    if (!ctx) {\n      track.stop();\n      return null;\n    }\n\n    ctx.drawImage(video, 0, 0, width, height);\n\n    // Stop the stream\n    track.stop();\n\n    return canvas.toDataURL('image/webp', quality);\n  } catch (error) {\n    console.warn('Screenshot capture failed:', error);\n    return null;\n  }\n}\n","/**\n * DOM-based screenshot capture using html2canvas\n * No browser permission dialog required - reconstructs the page from the DOM\n */\n\nexport interface DomScreenshotOptions {\n  /** Quality of WebP compression (0-1). Default: 0.8 */\n  quality?: number;\n  /** Max width of the screenshot. Default: 1280 */\n  maxWidth?: number;\n  /** Max height of the screenshot. Default: 800 */\n  maxHeight?: number;\n}\n\ndeclare global {\n  interface Window {\n    html2canvas?: (\n      element: HTMLElement,\n      options?: Record<string, unknown>\n    ) => Promise<HTMLCanvasElement>;\n  }\n}\n\nconst SCRIPT_URL = \"https://qaid.dev/lib/html2canvas.min.js\";\nconst LOAD_TIMEOUT = 10_000;\nconst POLL_INTERVAL = 50;\n\nlet loadPromise: Promise<boolean> | null = null;\n\n/**\n * Check if DOM screenshot capture is supported\n * Requires canvas and basic DOM APIs\n */\nexport function isDomScreenshotSupported(): boolean {\n  if (typeof document === \"undefined\" || typeof window === \"undefined\") {\n    return false;\n  }\n  // Check canvas support\n  const canvas = document.createElement(\"canvas\");\n  return typeof canvas.getContext === \"function\" && !!canvas.getContext(\"2d\");\n}\n\n/**\n * Load html2canvas script if not already loaded\n */\nfunction loadHtml2Canvas(): Promise<boolean> {\n  if (window.html2canvas) return Promise.resolve(true);\n\n  if (loadPromise) return loadPromise;\n\n  loadPromise = new Promise<boolean>((resolve) => {\n    // Check if script tag already exists\n    const existing = document.querySelector(\n      `script[src=\"${SCRIPT_URL}\"]`\n    ) as HTMLScriptElement | null;\n\n    if (!existing) {\n      const script = document.createElement(\"script\");\n      script.src = SCRIPT_URL;\n      script.async = true;\n      document.head.appendChild(script);\n    }\n\n    // Poll for window.html2canvas availability\n    const start = Date.now();\n    const poll = () => {\n      if (window.html2canvas) {\n        resolve(true);\n        return;\n      }\n      if (Date.now() - start > LOAD_TIMEOUT) {\n        loadPromise = null;\n        resolve(false);\n        return;\n      }\n      setTimeout(poll, POLL_INTERVAL);\n    };\n    poll();\n  });\n\n  return loadPromise;\n}\n\n/**\n * Capture a screenshot of the current page using html2canvas\n * Returns a base64-encoded WebP data URL, or null on failure\n */\nexport async function captureDomScreenshot(\n  options: DomScreenshotOptions = {}\n): Promise<string | null> {\n  const { quality = 0.8, maxWidth = 1280, maxHeight = 800 } = options;\n\n  try {\n    const loaded = await loadHtml2Canvas();\n    if (!loaded || !window.html2canvas) {\n      console.warn(\"html2canvas failed to load\");\n      return null;\n    }\n\n    const canvas = await window.html2canvas(document.body, {\n      useCORS: true,\n      allowTaint: false,\n      logging: false,\n      windowWidth: document.documentElement.clientWidth,\n      windowHeight: document.documentElement.clientHeight,\n      width: document.documentElement.clientWidth,\n      height: document.documentElement.clientHeight,\n      x: window.scrollX,\n      y: window.scrollY,\n      ignoreElements: (el: Element) => {\n        // Hide all qaid elements from the screenshot\n        if (el instanceof HTMLElement) {\n          return (\n            el.classList.contains(\"qaid-buttons\") ||\n            el.classList.contains(\"qaid-targeting-overlay\") ||\n            el.classList.contains(\"qaid-modal-container\") ||\n            el.classList.contains(\"qaid-bottom-sheet\") ||\n            el.classList.contains(\"qaid-backdrop\") ||\n            el.classList.contains(\"qaid-selected-marker\") ||\n            el.classList.contains(\"qaid-tooltip-text\") ||\n            el.classList.contains(\"qaid-recording-indicator\") ||\n            el.classList.contains(\"qaid-video-preview\") ||\n            el.className?.toString().startsWith?.(\"qaid-\")\n          );\n        }\n        return false;\n      },\n    });\n\n    // Scale down if needed\n    const srcWidth = canvas.width;\n    const srcHeight = canvas.height;\n    const scale = Math.min(maxWidth / srcWidth, maxHeight / srcHeight, 1);\n\n    if (scale < 1) {\n      const scaledWidth = Math.round(srcWidth * scale);\n      const scaledHeight = Math.round(srcHeight * scale);\n\n      const scaledCanvas = document.createElement(\"canvas\");\n      scaledCanvas.width = scaledWidth;\n      scaledCanvas.height = scaledHeight;\n\n      const ctx = scaledCanvas.getContext(\"2d\");\n      if (!ctx) return null;\n\n      ctx.drawImage(canvas, 0, 0, scaledWidth, scaledHeight);\n      return scaledCanvas.toDataURL(\"image/webp\", quality);\n    }\n\n    return canvas.toDataURL(\"image/webp\", quality);\n  } catch (error) {\n    console.warn(\"DOM screenshot capture failed:\", error);\n    return null;\n  }\n}\n","import type {\n  FeedbackConfig,\n  ResolvedFeedbackConfig,\n  FeedbackData,\n  SelectedBounds,\n  EmbedState,\n  FeedbackPayload,\n  FeedbackResponse,\n} from \"./types\";\nimport { THUMBS_UP_ICON, THUMBS_DOWN_ICON, RECORD_ICON } from \"./icons\";\nimport { injectStyles, removeStyles, buildCssVars, applyCssVars, getEmbedStyles } from \"./styles\";\nimport { generateElementInfo } from \"./element-selector\";\nimport { calculateModalAndArrowPosition } from \"./modal-positioning\";\nimport { captureConsoleErrors, type ConsoleCapture } from \"./console-capture\";\nimport { captureNetworkErrors, type NetworkCapture } from \"./network-capture\";\nimport {\n  createVideoRecorder,\n  isVideoRecordingSupported,\n  type VideoRecorder,\n} from \"./video-capture\";\nimport {\n  getElementAtPointUnderOverlay,\n  isEmbedElement,\n  getElementBounds,\n  isMobileViewport,\n} from \"./dom-utils\";\nimport { captureScreenshot } from \"./screenshot\";\nimport { captureDomScreenshot } from \"./screenshot-dom\";\n\nconst VISITOR_ID_KEY = \"qaid_visitor_id\";\n\n/**\n * Get or create a visitor ID stored in localStorage\n */\nfunction getOrCreateVisitorId(): string {\n  try {\n    let visitorId = localStorage.getItem(VISITOR_ID_KEY);\n    if (!visitorId) {\n      visitorId = crypto.randomUUID();\n      localStorage.setItem(VISITOR_ID_KEY, visitorId);\n    }\n    return visitorId;\n  } catch {\n    // localStorage not available, generate a session-only ID\n    return crypto.randomUUID();\n  }\n}\n\n/**\n * QaidFeedback - Standalone feedback collection embed\n */\nexport class QaidFeedback {\n  private config: ResolvedFeedbackConfig;\n  private state: EmbedState = \"IDLE\";\n  private feedbackData: FeedbackData = {\n    feedbackType: null,\n    elementSelector: null,\n    elementText: null,\n    consoleErrors: [],\n  };\n  private selectedBounds: SelectedBounds = {\n    x: 0,\n    y: 0,\n    width: 0,\n    height: 0,\n    clickX: 0,\n    clickY: 0,\n    visible: false,\n  };\n  private feedbackId: number | null = null;\n  private mousePos = { x: 0, y: 0 };\n  private isMobile = false;\n  private visitorId: string;\n\n  // Console capture\n  private consoleCapture: ConsoleCapture | null = null;\n\n  // Video recording\n  private videoRecorder: VideoRecorder | null = null;\n  private networkCapture: NetworkCapture | null = null;\n  private recordedBlob: Blob | null = null;\n  private recordingIndicator: HTMLDivElement | null = null;\n  private videoPreview: HTMLDivElement | null = null;\n  private isRecording = false;\n  private isSendingVideo = false;\n\n  // Shadow DOM\n  private shadowHost: HTMLDivElement | null = null;\n  private shadowRoot: ShadowRoot | null = null;\n\n  // Overlay shadow DOM (always on document.body for full-page coverage)\n  private overlayShadowHost: HTMLDivElement | null = null;\n  private overlayShadowRoot: ShadowRoot | null = null;\n\n  // DOM elements (inside shadow root)\n  private buttonsContainer: HTMLDivElement | null = null;\n  private isUserProvidedContainer = false;\n  private overlayContainer: HTMLDivElement | null = null;\n  private captureLayer: HTMLDivElement | null = null;\n  private crosshairH: HTMLDivElement | null = null;\n  private crosshairV: HTMLDivElement | null = null;\n  private scope: HTMLDivElement | null = null;\n  private highlightBox: HTMLDivElement | null = null;\n  private marker: HTMLDivElement | null = null;\n  private modalContainer: HTMLDivElement | null = null;\n  private backdrop: HTMLDivElement | null = null;\n\n  // Per-instance CSS variables\n  private cssVars: Record<string, string> = {};\n\n  // Bound event handlers\n  private boundKeyDown: (e: KeyboardEvent) => void;\n  private boundMouseMove: (e: MouseEvent) => void;\n  private boundClick: (e: MouseEvent) => void;\n  private boundResize: () => void;\n\n  constructor(config: FeedbackConfig) {\n    this.config = {\n      endpoint: config.endpoint,\n      apiKey: config.apiKey ?? \"\",\n      container: config.container ?? \"\",\n      buttonClass: config.buttonClass ?? \"\",\n      direction: config.direction ?? \"horizontal\",\n      position: config.position ?? \"bottom-right\",\n      offset: {\n        x: config.offset?.x ?? 16,\n        y: config.offset?.y ?? 16,\n      },\n      zIndex: config.zIndex ?? 50,\n      skipTargeting: config.skipTargeting ?? false,\n      colors: {\n        positive: config.colors?.positive ?? \"rgb(0, 200, 83)\",\n        negative: config.colors?.negative ?? \"rgb(255, 0, 0)\",\n        marker: config.colors?.marker ?? \"#6366f1\",\n      },\n      buttonSize: config.buttonSize ?? \"medium\",\n      text: {\n        tooltip: config.text?.tooltip ?? \"\",\n        modalTitle: config.text?.modalTitle ?? \"Thank you for your feedback!\",\n        modalSubtitle: config.text?.modalSubtitle ?? \"Would you like to add a message to help us understand your feedback better?\",\n        placeholder: config.text?.placeholder ?? \"Optional: Tell us more about your experience...\",\n        submitButton: config.text?.submitButton ?? \"Submit\",\n        skipButton: config.text?.skipButton ?? \"Skip\",\n      },\n      modalWidth: config.modalWidth ?? 400,\n      backdropOpacity: config.backdropOpacity ?? 0.3,\n      fontFamily: config.fontFamily ?? \"system-ui, -apple-system, sans-serif\",\n      fontSize: config.fontSize ?? 16,\n      captureScreenshot: config.captureScreenshot ?? false,\n      screenshotMethod: config.screenshotMethod ?? \"permission\",\n      screenshotOptions: {\n        quality: config.screenshotOptions?.quality ?? 0.8,\n        maxWidth: config.screenshotOptions?.maxWidth ?? 1280,\n        maxHeight: config.screenshotOptions?.maxHeight ?? 800,\n      },\n      incognito: config.incognito ?? false,\n      positiveIcon: config.positiveIcon ?? \"\",\n      negativeIcon: config.negativeIcon ?? \"\",\n      hideThumbs: config.hideThumbs ?? false,\n      css: config.css ?? \"\",\n      captureVideo: config.captureVideo ?? false,\n      videoOptions: {\n        maxDuration: config.videoOptions?.maxDuration ?? 15,\n      },\n      recordIcon: config.recordIcon ?? \"\",\n    };\n\n    // Bind event handlers\n    this.boundKeyDown = this.handleKeyDown.bind(this);\n    this.boundMouseMove = this.handleMouseMove.bind(this);\n    this.boundClick = this.handleClick.bind(this);\n    this.boundResize = this.handleResize.bind(this);\n\n    // Get or create visitor ID for anonymous feedback tracking\n    this.visitorId = getOrCreateVisitorId();\n\n    this.init();\n  }\n\n  private applyVars(el: HTMLElement): void {\n    applyCssVars(el, this.cssVars);\n  }\n\n  private init(): void {\n    // Inject shared light DOM styles (cursor + highlight, reference counted)\n    injectStyles();\n\n    // Build per-instance CSS variables\n    this.cssVars = buildCssVars({\n      positiveColor: this.config.colors.positive,\n      negativeColor: this.config.colors.negative,\n      markerColor: this.config.colors.marker,\n      buttonSize: this.config.buttonSize,\n      modalWidth: this.config.modalWidth,\n      backdropOpacity: this.config.backdropOpacity,\n      fontFamily: this.config.fontFamily,\n      fontSize: this.config.fontSize,\n    });\n\n    // Check mobile\n    this.checkMobile();\n    window.addEventListener(\"resize\", this.boundResize);\n\n    // Create shadow host and embed\n    this.createEmbed();\n\n    // Capture console errors\n    this.consoleCapture = captureConsoleErrors((_error) => {\n      this.feedbackData.consoleErrors = this.consoleCapture?.errors ?? [];\n    });\n    this.feedbackData.consoleErrors = this.consoleCapture.errors;\n  }\n\n  private checkMobile(): void {\n    this.isMobile = isMobileViewport();\n  }\n\n  private handleResize(): void {\n    this.checkMobile();\n  }\n\n  private createEmbed(): void {\n    // Create the shadow host element\n    this.shadowHost = document.createElement(\"div\");\n    this.shadowHost.setAttribute(\"data-qaid-embed\", \"\");\n    this.shadowHost.style.position = \"static\";\n    this.shadowHost.style.display = \"contents\";\n\n    // Check if user provided a container selector\n    let userContainer: HTMLElement | null = null;\n    if (this.config.container) {\n      userContainer = document.querySelector(this.config.container);\n    }\n\n    if (userContainer) {\n      userContainer.appendChild(this.shadowHost);\n      this.isUserProvidedContainer = true;\n    } else {\n      // Set shadow host to fixed positioning for auto-created containers\n      this.shadowHost.style.position = \"fixed\";\n      this.shadowHost.style.display = \"block\";\n      this.shadowHost.style.inset = \"0\";\n      this.shadowHost.style.pointerEvents = \"none\";\n      this.shadowHost.style.zIndex = String(this.config.zIndex);\n      document.body.appendChild(this.shadowHost);\n    }\n\n    // Attach shadow root\n    this.shadowRoot = this.shadowHost.attachShadow({ mode: \"open\" });\n\n    // Inject base styles into shadow root\n    const baseStyle = document.createElement(\"style\");\n    baseStyle.textContent = getEmbedStyles();\n    this.shadowRoot.appendChild(baseStyle);\n\n    // Inject theme CSS if provided\n    if (this.config.css) {\n      const themeStyle = document.createElement(\"style\");\n      themeStyle.textContent = this.config.css;\n      this.shadowRoot.appendChild(themeStyle);\n    }\n\n    // Create buttons container inside shadow root\n    const dirClass = this.config.direction === \"vertical\" ? \"qaid-vertical\" : \"\";\n    if (this.isUserProvidedContainer) {\n      this.buttonsContainer = document.createElement(\"div\");\n      this.buttonsContainer.className = `qaid-buttons qaid-${this.config.position} ${dirClass}`.trim();\n      if (this.config.incognito) {\n        this.buttonsContainer.classList.add(\"qaid-incognito\");\n      }\n    } else {\n      this.buttonsContainer = document.createElement(\"div\");\n      this.buttonsContainer.className = `qaid-buttons qaid-auto-container qaid-${this.config.position} ${dirClass}${this.config.incognito ? \" qaid-incognito\" : \"\"}`.trim();\n      this.buttonsContainer.style.pointerEvents = \"auto\";\n      // Apply custom offset\n      const { x: offsetX, y: offsetY } = this.config.offset;\n      if (this.config.position.includes(\"right\")) {\n        this.buttonsContainer.style.right = `${offsetX}px`;\n      } else {\n        this.buttonsContainer.style.left = `${offsetX}px`;\n      }\n      if (this.config.position.includes(\"bottom\")) {\n        this.buttonsContainer.style.bottom = `${offsetY}px`;\n      } else {\n        this.buttonsContainer.style.top = `${offsetY}px`;\n      }\n    }\n\n    // Apply per-instance CSS variables to buttons container\n    this.applyVars(this.buttonsContainer);\n    this.shadowRoot.appendChild(this.buttonsContainer);\n\n    // Determine button classes\n    const useCustomClass = !!this.config.buttonClass;\n    const btnBaseClass = useCustomClass\n      ? `qaid-btn-structural ${this.config.buttonClass}`\n      : \"qaid-btn\";\n\n    // Determine tooltip text\n    const defaultTooltip = \"Feedback for us?\";\n    const tooltipText = this.config.text.tooltip || defaultTooltip;\n\n    // Create shared tooltip element (inside shadow root)\n    const tooltip = document.createElement(\"div\");\n    tooltip.className = \"qaid-tooltip-text\";\n    tooltip.textContent = tooltipText;\n    this.applyVars(tooltip);\n    this.shadowRoot.appendChild(tooltip);\n    this.tooltipElement = tooltip;\n\n    // Thumbs up/down buttons (unless hidden)\n    if (!this.config.hideThumbs) {\n      // Thumbs up button\n      const upWrapper = document.createElement(\"div\");\n      upWrapper.className = \"qaid-tooltip-wrapper\";\n\n      const upBtn = document.createElement(\"button\");\n      upBtn.type = \"button\";\n      upBtn.className = useCustomClass ? `${btnBaseClass} qaid-btn-up` : \"qaid-btn qaid-btn-up\";\n      upBtn.innerHTML = this.config.positiveIcon || THUMBS_UP_ICON;\n      upBtn.addEventListener(\"click\", (e) => this.handleThumbClick(\"up\", e.currentTarget as HTMLElement, e));\n      upBtn.addEventListener(\"mouseenter\", () => this.showTooltip(upBtn));\n      upBtn.addEventListener(\"mouseleave\", () => this.hideTooltip());\n      upWrapper.appendChild(upBtn);\n\n      // Thumbs down button\n      const downWrapper = document.createElement(\"div\");\n      downWrapper.className = \"qaid-tooltip-wrapper\";\n\n      const downBtn = document.createElement(\"button\");\n      downBtn.type = \"button\";\n      downBtn.className = useCustomClass ? `${btnBaseClass} qaid-btn-down` : \"qaid-btn qaid-btn-down\";\n      downBtn.innerHTML = this.config.negativeIcon || THUMBS_DOWN_ICON;\n      downBtn.addEventListener(\"click\", (e) => this.handleThumbClick(\"down\", e.currentTarget as HTMLElement, e));\n      downBtn.addEventListener(\"mouseenter\", () => this.showTooltip(downBtn));\n      downBtn.addEventListener(\"mouseleave\", () => this.hideTooltip());\n      downWrapper.appendChild(downBtn);\n\n      this.buttonsContainer.appendChild(upWrapper);\n      this.buttonsContainer.appendChild(downWrapper);\n    }\n\n    // Record button (only when captureVideo is true and browser supports it)\n    if (this.config.captureVideo && isVideoRecordingSupported()) {\n      const recordWrapper = document.createElement(\"div\");\n      recordWrapper.className = \"qaid-tooltip-wrapper\";\n\n      const recordBtn = document.createElement(\"button\");\n      recordBtn.type = \"button\";\n      recordBtn.className = useCustomClass ? `${btnBaseClass} qaid-btn-record` : \"qaid-btn qaid-btn-record\";\n      recordBtn.innerHTML = this.config.recordIcon || RECORD_ICON;\n      recordBtn.addEventListener(\"click\", () => this.startRecording());\n      recordBtn.addEventListener(\"mouseenter\", () => this.showTooltip(recordBtn));\n      recordBtn.addEventListener(\"mouseleave\", () => this.hideTooltip());\n      recordWrapper.appendChild(recordBtn);\n\n      this.buttonsContainer.appendChild(recordWrapper);\n    }\n  }\n\n  /**\n   * Lazily create a separate overlay shadow host on document.body.\n   * This host contains all full-page elements (targeting overlay, marker,\n   * backdrop, modal, recording indicator, video preview) so they escape\n   * clip-path / transform containing blocks in user containers.\n   */\n  private ensureOverlayHost(): ShadowRoot {\n    if (this.overlayShadowRoot) return this.overlayShadowRoot;\n\n    this.overlayShadowHost = document.createElement(\"div\");\n    this.overlayShadowHost.setAttribute(\"data-qaid-embed-overlay\", \"\");\n    this.overlayShadowHost.style.position = \"fixed\";\n    this.overlayShadowHost.style.inset = \"0\";\n    this.overlayShadowHost.style.pointerEvents = \"none\";\n    this.overlayShadowHost.style.zIndex = String(this.config.zIndex);\n    document.body.appendChild(this.overlayShadowHost);\n\n    this.overlayShadowRoot = this.overlayShadowHost.attachShadow({ mode: \"open\" });\n\n    // Inject base styles into overlay shadow root\n    const baseStyle = document.createElement(\"style\");\n    baseStyle.textContent = getEmbedStyles();\n    this.overlayShadowRoot.appendChild(baseStyle);\n\n    // Inject theme CSS if provided\n    if (this.config.css) {\n      const themeStyle = document.createElement(\"style\");\n      themeStyle.textContent = this.config.css;\n      this.overlayShadowRoot.appendChild(themeStyle);\n    }\n\n    return this.overlayShadowRoot;\n  }\n\n  private tooltipElement: HTMLElement | null = null;\n\n  private showTooltip(anchor: HTMLElement): void {\n    if (!this.tooltipElement) return;\n\n    const tooltip = this.tooltipElement;\n    const gap = 8;\n\n    // Make visible to measure\n    tooltip.style.visibility = \"hidden\";\n    tooltip.classList.add(\"qaid-tooltip-visible\");\n\n    const anchorRect = anchor.getBoundingClientRect();\n    const tooltipRect = tooltip.getBoundingClientRect();\n    const viewportWidth = window.innerWidth;\n    const viewportHeight = window.innerHeight;\n\n    let top: number;\n    let left: number;\n\n    // Always position below the button\n    top = anchorRect.bottom + gap;\n\n    // If below would overflow viewport, try above\n    if (top + tooltipRect.height > viewportHeight - gap) {\n      top = anchorRect.top - tooltipRect.height - gap;\n    }\n\n    // Align to left edge of anchor\n    left = anchorRect.left;\n\n    // Clamp to viewport horizontally\n    if (left < gap) {\n      left = gap;\n    } else if (left + tooltipRect.width > viewportWidth - gap) {\n      left = viewportWidth - tooltipRect.width - gap;\n    }\n\n    // Clamp to viewport vertically\n    if (top < gap) {\n      top = gap;\n    } else if (top + tooltipRect.height > viewportHeight - gap) {\n      top = viewportHeight - tooltipRect.height - gap;\n    }\n\n    tooltip.style.top = `${top}px`;\n    tooltip.style.left = `${left}px`;\n    tooltip.style.visibility = \"visible\";\n  }\n\n  private hideTooltip(): void {\n    if (this.tooltipElement) {\n      this.tooltipElement.classList.remove(\"qaid-tooltip-visible\");\n    }\n  }\n\n  private handleThumbClick(type: \"up\" | \"down\", buttonEl: HTMLElement, e: MouseEvent): void {\n    if (this.config.skipTargeting) {\n      this.submitDirectFeedback(type, buttonEl);\n    } else {\n      this.startTargeting(type, e);\n    }\n  }\n\n  private submitDirectFeedback(type: \"up\" | \"down\", buttonEl: HTMLElement): void {\n    this.feedbackData.feedbackType = type;\n    this.feedbackData.elementSelector = null;\n    this.feedbackData.elementText = null;\n\n    // Use the button's position for modal placement\n    const rect = buttonEl.getBoundingClientRect();\n    this.selectedBounds = {\n      x: rect.left,\n      y: rect.top,\n      width: rect.width,\n      height: rect.height,\n      clickX: rect.left + rect.width / 2,\n      clickY: rect.top + rect.height / 2,\n      visible: false,\n    };\n    this.submitFeedback();\n  }\n\n  private startTargeting(type: \"up\" | \"down\", e: MouseEvent): void {\n    this.state = \"TARGETING\";\n    this.feedbackData.feedbackType = type;\n    this.feedbackData.elementSelector = null;\n    this.feedbackData.elementText = null;\n    this.selectedBounds.visible = false;\n\n    // Track initial mouse position from the click event\n    this.mousePos.x = e.clientX;\n    this.mousePos.y = e.clientY;\n\n    // Add class to body (light DOM — for cursor override)\n    document.body.classList.add(\"qaid-targeting\");\n    if (type === \"up\") {\n      document.body.classList.add(\"qaid-type-up\");\n    } else {\n      document.body.classList.remove(\"qaid-type-up\");\n    }\n\n    // Set targeting colors on body so .qaid-highlight rules can resolve them\n    document.body.style.setProperty(\"--qaid-positive\", this.cssVars[\"--qaid-positive\"]);\n    document.body.style.setProperty(\"--qaid-negative\", this.cssVars[\"--qaid-negative\"]);\n\n    // Create targeting overlay (in overlay shadow host)\n    this.createTargetingOverlay();\n\n    // Add event listeners on document — overlay is pointer-events:none so scroll works naturally\n    document.addEventListener(\"keydown\", this.boundKeyDown);\n    document.addEventListener(\"mousemove\", this.boundMouseMove);\n    document.addEventListener(\"click\", this.boundClick, true);\n  }\n\n  private createTargetingOverlay(): void {\n    const root = this.ensureOverlayHost();\n\n    this.overlayContainer = document.createElement(\"div\");\n    this.overlayContainer.className = `qaid-targeting-overlay qaid-type-${this.feedbackData.feedbackType}`;\n\n    // Capture layer (pointer-events:none — scroll passes through naturally)\n    this.captureLayer = document.createElement(\"div\");\n    this.captureLayer.className = \"qaid-capture-layer\";\n\n    // Vignette\n    const vignette = document.createElement(\"div\");\n    vignette.className = \"qaid-vignette\";\n\n    // Crosshairs\n    this.crosshairH = document.createElement(\"div\");\n    this.crosshairH.className = \"qaid-crosshair-h\";\n\n    this.crosshairV = document.createElement(\"div\");\n    this.crosshairV.className = \"qaid-crosshair-v\";\n\n    // Scope\n    this.scope = document.createElement(\"div\");\n    this.scope.className = \"qaid-scope\";\n    this.scope.innerHTML = `\n      <div class=\"qaid-scope-ring\"></div>\n      <div class=\"qaid-scope-ring-inner\"></div>\n      <div class=\"qaid-scope-dot\"></div>\n    `;\n\n    // Highlight box overlay (positioned over hovered elements)\n    this.highlightBox = document.createElement(\"div\");\n    this.highlightBox.className = \"qaid-highlight-box\";\n\n    this.overlayContainer.appendChild(this.captureLayer);\n    this.overlayContainer.appendChild(vignette);\n    this.overlayContainer.appendChild(this.highlightBox);\n    this.overlayContainer.appendChild(this.crosshairH);\n    this.overlayContainer.appendChild(this.crosshairV);\n    this.overlayContainer.appendChild(this.scope);\n\n    // Position crosshairs immediately at current mouse position\n    this.crosshairH.style.top = `${this.mousePos.y}px`;\n    this.crosshairV.style.left = `${this.mousePos.x}px`;\n    this.scope.style.left = `${this.mousePos.x}px`;\n    this.scope.style.top = `${this.mousePos.y}px`;\n\n    this.applyVars(this.overlayContainer);\n    root.appendChild(this.overlayContainer);\n  }\n\n  private handleKeyDown(e: KeyboardEvent): void {\n    if (e.key === \"Escape\") {\n      if (this.isRecording) {\n        this.stopRecording();\n      } else if (this.videoPreview) {\n        this.cancelRecordingPreview();\n      } else if (this.state === \"TARGETING\") {\n        this.cancelTargeting();\n      } else if (this.state === \"MODAL_OPEN\") {\n        this.closeModal();\n      }\n    }\n  }\n\n  private handleMouseMove(e: MouseEvent): void {\n    this.mousePos.x = e.clientX;\n    this.mousePos.y = e.clientY;\n\n    // Update crosshairs and scope\n    if (this.crosshairH) {\n      this.crosshairH.style.top = `${e.clientY}px`;\n    }\n    if (this.crosshairV) {\n      this.crosshairV.style.left = `${e.clientX}px`;\n    }\n    if (this.scope) {\n      this.scope.style.left = `${e.clientX}px`;\n      this.scope.style.top = `${e.clientY}px`;\n    }\n\n    // Find element underneath — hide both shadow hosts\n    if (this.captureLayer && this.shadowHost) {\n      const hosts = [this.shadowHost, this.overlayShadowHost].filter(Boolean) as HTMLElement[];\n      const elementUnder = getElementAtPointUnderOverlay(\n        e.clientX,\n        e.clientY,\n        hosts\n      );\n\n      if (elementUnder && !isEmbedElement(elementUnder)) {\n        if (this.highlightBox) {\n          const rect = elementUnder.getBoundingClientRect();\n          this.highlightBox.style.transform = `translate(${rect.left}px, ${rect.top}px)`;\n          this.highlightBox.style.width = `${rect.width}px`;\n          this.highlightBox.style.height = `${rect.height}px`;\n          this.highlightBox.style.display = \"block\";\n        }\n      } else {\n        if (this.highlightBox) {\n          this.highlightBox.style.display = \"none\";\n        }\n      }\n    }\n  }\n\n  private handleClick(e: MouseEvent): void {\n    if (this.state !== \"TARGETING\" || !this.shadowHost) return;\n    e.preventDefault();\n    e.stopPropagation();\n\n    // Find element underneath — hide both shadow hosts\n    const hosts = [this.shadowHost, this.overlayShadowHost].filter(Boolean) as HTMLElement[];\n    const target = getElementAtPointUnderOverlay(\n      e.clientX,\n      e.clientY,\n      hosts\n    );\n\n    if (!target || isEmbedElement(target)) {\n      return;\n    }\n\n    // Get element bounds\n    const bounds = getElementBounds(target, 8);\n    this.selectedBounds = {\n      ...bounds,\n      clickX: e.clientX,\n      clickY: e.clientY,\n      visible: true,\n    };\n\n    const { selector, text } = generateElementInfo(target);\n    this.feedbackData.elementSelector = selector;\n    this.feedbackData.elementText = text;\n\n    // Remove targeting overlay and document listeners\n    this.removeTargetingOverlay();\n    document.removeEventListener(\"mousemove\", this.boundMouseMove);\n    document.removeEventListener(\"click\", this.boundClick, true);\n    document.removeEventListener(\"keydown\", this.boundKeyDown);\n    document.body.classList.remove(\"qaid-targeting\", \"qaid-type-up\");\n    document.body.style.removeProperty(\"--qaid-positive\");\n    document.body.style.removeProperty(\"--qaid-negative\");\n\n    this.state = \"SELECTED\";\n\n    // Show marker and submit feedback\n    this.showSelectedMarker();\n    this.submitFeedback();\n  }\n\n  private cancelTargeting(): void {\n    this.removeTargetingOverlay();\n    document.removeEventListener(\"mousemove\", this.boundMouseMove);\n    document.removeEventListener(\"click\", this.boundClick, true);\n    document.removeEventListener(\"keydown\", this.boundKeyDown);\n    document.body.classList.remove(\"qaid-targeting\", \"qaid-type-up\");\n    document.body.style.removeProperty(\"--qaid-positive\");\n    document.body.style.removeProperty(\"--qaid-negative\");\n\n    this.state = \"IDLE\";\n    this.feedbackData.feedbackType = null;\n    this.feedbackData.elementSelector = null;\n    this.feedbackData.elementText = null;\n    this.selectedBounds.visible = false;\n  }\n\n  private removeTargetingOverlay(): void {\n    if (this.overlayContainer) {\n      this.overlayContainer.remove();\n      this.overlayContainer = null;\n    }\n    this.captureLayer = null;\n    this.crosshairH = null;\n    this.crosshairV = null;\n    this.scope = null;\n  }\n\n  private showSelectedMarker(): void {\n    if (!this.selectedBounds.visible) return;\n    const root = this.ensureOverlayHost();\n\n    this.marker = document.createElement(\"div\");\n    this.marker.className = \"qaid-selected-marker\";\n    this.marker.style.left = `${this.selectedBounds.x}px`;\n    this.marker.style.top = `${this.selectedBounds.y}px`;\n    this.marker.style.width = `${this.selectedBounds.width}px`;\n    this.marker.style.height = `${this.selectedBounds.height}px`;\n    this.marker.style.zIndex = String(this.config.zIndex + 1);\n\n    this.applyVars(this.marker);\n    root.appendChild(this.marker);\n  }\n\n  private hideSelectedMarker(): void {\n    if (this.marker) {\n      this.marker.remove();\n      this.marker = null;\n    }\n  }\n\n  private async submitFeedback(): Promise<void> {\n    if (!this.feedbackData.feedbackType) return;\n\n    // Capture screenshot if enabled (server will gate by plan)\n    let screenshot: string | null = null;\n    if (this.config.captureScreenshot) {\n      if (this.config.screenshotMethod === \"dom\") {\n        screenshot = await captureDomScreenshot(this.config.screenshotOptions);\n      } else {\n        screenshot = await captureScreenshot(this.config.screenshotOptions);\n      }\n    }\n\n    // Include element bounds for server-side screenshot fallback\n    // Only include if we have an element selector (element was targeted)\n    const elementBounds = this.feedbackData.elementSelector\n      ? {\n          x: this.selectedBounds.x,\n          y: this.selectedBounds.y,\n          width: this.selectedBounds.width,\n          height: this.selectedBounds.height,\n        }\n      : null;\n\n    const payload: FeedbackPayload = {\n      feedbackType: this.feedbackData.feedbackType,\n      pageUrl: window.location.href,\n      apiKey: this.config.apiKey || undefined,\n      elementSelector: this.feedbackData.elementSelector,\n      elementText: this.feedbackData.elementText,\n      consoleErrors: [...this.feedbackData.consoleErrors],\n      screenWidth: window.innerWidth,\n      screenHeight: window.innerHeight,\n      clickX: this.selectedBounds.clickX,\n      clickY: this.selectedBounds.clickY,\n      scrollX: window.scrollX,\n      scrollY: window.scrollY,\n      screenshot,\n      visitorId: this.visitorId,\n      // Include element bounds and user agent for server-side screenshot fallback\n      elementBounds,\n      userAgent: navigator.userAgent,\n    };\n\n    try {\n      const response = await fetch(this.config.endpoint, {\n        method: \"POST\",\n        headers: { \"Content-Type\": \"application/json\" },\n        body: JSON.stringify(payload),\n      });\n\n      if (response.ok) {\n        const data: FeedbackResponse = await response.json();\n        this.feedbackId = data.id;\n      }\n    } catch (error) {\n      console.error(\"Failed to submit feedback:\", error);\n    }\n\n    // Always show modal (even if API failed - useful for demos)\n    this.state = \"MODAL_OPEN\";\n\n    this.showModal();\n\n    // Enable pointer events on overlay host for modal\n    if (this.overlayShadowHost) {\n      this.overlayShadowHost.style.pointerEvents = \"auto\";\n    }\n  }\n\n  private showModal(): void {\n    const root = this.ensureOverlayHost();\n\n    // Create backdrop\n    this.backdrop = document.createElement(\"div\");\n    this.backdrop.className = \"qaid-backdrop\";\n    this.backdrop.style.zIndex = String(this.config.zIndex + 2);\n    this.backdrop.style.background = `rgba(0, 0, 0, ${this.config.backdropOpacity})`;\n    this.backdrop.addEventListener(\"click\", () => this.closeModal());\n    this.applyVars(this.backdrop);\n\n    if (this.isMobile) {\n      this.showBottomSheet();\n    } else {\n      this.showPositionedModal();\n    }\n\n    root.appendChild(this.backdrop);\n    document.addEventListener(\"keydown\", this.boundKeyDown);\n  }\n\n  private showBottomSheet(): void {\n    const root = this.ensureOverlayHost();\n\n    const sheet = document.createElement(\"div\");\n    sheet.className = \"qaid-bottom-sheet\";\n    sheet.style.zIndex = String(this.config.zIndex + 3);\n\n    sheet.innerHTML = `\n      <div class=\"qaid-bottom-sheet-content\">\n        <div class=\"qaid-bottom-sheet-handle\"></div>\n        ${this.getModalContent()}\n      </div>\n    `;\n\n    this.applyVars(sheet);\n    root.appendChild(sheet);\n    this.modalContainer = sheet;\n\n    this.setupModalInteractions();\n  }\n\n  private showPositionedModal(): void {\n    const root = this.ensureOverlayHost();\n\n    const { modal, arrow } = calculateModalAndArrowPosition(\n      this.selectedBounds,\n      window.innerWidth,\n      window.innerHeight,\n      {\n        width: this.config.modalWidth,\n        height: 280,\n        arrowHeight: 12,\n        gap: 8,\n        viewportPadding: 16,\n      }\n    );\n\n    this.modalContainer = document.createElement(\"div\");\n    this.modalContainer.className = `qaid-modal-container qaid-${modal.position}`;\n    this.modalContainer.style.top = `${modal.top}px`;\n    this.modalContainer.style.left = `${modal.left}px`;\n    this.modalContainer.style.zIndex = String(this.config.zIndex + 3);\n\n    const arrowEl = document.createElement(\"div\");\n    arrowEl.className = \"qaid-modal-arrow\";\n    arrowEl.style.left = `${arrow.left}px`;\n\n    const box = document.createElement(\"div\");\n    box.className = \"qaid-modal-box\";\n    box.innerHTML = this.getModalContent();\n\n    this.modalContainer.appendChild(arrowEl);\n    this.modalContainer.appendChild(box);\n    this.applyVars(this.modalContainer);\n    root.appendChild(this.modalContainer);\n\n    this.setupModalInteractions();\n  }\n\n  private getModalContent(): string {\n    const isUp = this.feedbackData.feedbackType === \"up\";\n    const positiveIcon = this.config.positiveIcon || THUMBS_UP_ICON;\n    const negativeIcon = this.config.negativeIcon || THUMBS_DOWN_ICON;\n    const toggleClass = this.config.buttonClass\n      ? `qaid-type-toggle qaid-type-toggle-custom ${this.config.buttonClass} ${isUp ? \"qaid-btn-up\" : \"qaid-btn-down\"}`\n      : `qaid-type-toggle ${isUp ? \"qaid-type-up\" : \"qaid-type-down\"}`;\n    return `\n      <div class=\"qaid-modal-header\">\n        <button type=\"button\" class=\"${toggleClass}\" title=\"Click to switch\">\n          ${isUp ? positiveIcon : negativeIcon}\n        </button>\n        <div class=\"qaid-modal-header-text\">\n          <h3 class=\"qaid-modal-title\">${this.config.text.modalTitle}</h3>\n          <p class=\"qaid-modal-subtitle\">${this.config.text.modalSubtitle}</p>\n        </div>\n      </div>\n      <textarea class=\"qaid-textarea\" placeholder=\"${this.config.text.placeholder}\"></textarea>\n      <div class=\"qaid-btn-row\">\n        <button type=\"button\" class=\"qaid-btn-submit\">${this.config.text.skipButton}</button>\n      </div>\n    `;\n  }\n\n  private setupModalInteractions(): void {\n    if (!this.modalContainer) return;\n\n    const textarea =\n      this.modalContainer.querySelector<HTMLTextAreaElement>(\".qaid-textarea\");\n    const submitBtn =\n      this.modalContainer.querySelector<HTMLButtonElement>(\".qaid-btn-submit\");\n    if (textarea) {\n      // Auto-focus\n      setTimeout(() => textarea.focus(), 100);\n\n      // Update button text based on content\n      textarea.addEventListener(\"input\", () => {\n        if (submitBtn) {\n          submitBtn.textContent = textarea.value.trim() ? this.config.text.submitButton : this.config.text.skipButton;\n        }\n      });\n    }\n\n    if (submitBtn) {\n      submitBtn.addEventListener(\"click\", () => {\n        const message = textarea?.value.trim() || null;\n        this.submitMessage(message);\n      });\n    }\n\n    // Handle feedback type toggle\n    const typeToggle = this.modalContainer.querySelector<HTMLButtonElement>(\".qaid-type-toggle\");\n    if (typeToggle) {\n      typeToggle.addEventListener(\"click\", () => {\n        const newType = this.feedbackData.feedbackType === \"up\" ? \"down\" : \"up\";\n        this.feedbackData.feedbackType = newType;\n\n        // Update UI - use different classes depending on custom buttonClass\n        if (this.config.buttonClass) {\n          typeToggle.classList.toggle(\"qaid-btn-up\", newType === \"up\");\n          typeToggle.classList.toggle(\"qaid-btn-down\", newType === \"down\");\n        } else {\n          typeToggle.classList.toggle(\"qaid-type-up\", newType === \"up\");\n          typeToggle.classList.toggle(\"qaid-type-down\", newType === \"down\");\n        }\n        const positiveIcon = this.config.positiveIcon || THUMBS_UP_ICON;\n        const negativeIcon = this.config.negativeIcon || THUMBS_DOWN_ICON;\n        typeToggle.innerHTML = newType === \"up\" ? positiveIcon : negativeIcon;\n\n        // Update feedback on server\n        if (this.feedbackId) {\n          fetch(`${this.config.endpoint}/${this.feedbackId}`, {\n            method: \"PATCH\",\n            headers: { \"Content-Type\": \"application/json\" },\n            body: JSON.stringify({ feedbackType: newType }),\n          }).catch((err) => console.error(\"Failed to update feedback type:\", err));\n        }\n      });\n    }\n  }\n\n  private async submitMessage(message: string | null): Promise<void> {\n    if (this.feedbackId) {\n      try {\n        await fetch(`${this.config.endpoint}/${this.feedbackId}`, {\n          method: \"PATCH\",\n          headers: { \"Content-Type\": \"application/json\" },\n          body: JSON.stringify({ message }),\n        });\n      } catch (error) {\n        console.error(\"Failed to submit feedback message:\", error);\n      }\n      // Clear feedbackId so closeModal doesn't send another PATCH\n      this.feedbackId = null;\n    }\n\n    this.closeModal();\n  }\n\n  private closeModal(): void {\n    // If modal is open and we're closing without submitting, still finalize\n    if (this.state === \"MODAL_OPEN\" && this.feedbackId) {\n      fetch(`${this.config.endpoint}/${this.feedbackId}`, {\n        method: \"PATCH\",\n        headers: { \"Content-Type\": \"application/json\" },\n        body: JSON.stringify({ message: null }),\n      }).catch((err) => console.error(\"Failed to finalize feedback:\", err));\n    }\n\n    if (this.modalContainer) {\n      this.modalContainer.remove();\n      this.modalContainer = null;\n    }\n    if (this.backdrop) {\n      this.backdrop.remove();\n      this.backdrop = null;\n    }\n\n    document.removeEventListener(\"keydown\", this.boundKeyDown);\n    this.hideSelectedMarker();\n\n    // Reset overlay host pointer events\n    if (this.overlayShadowHost) {\n      this.overlayShadowHost.style.pointerEvents = \"none\";\n    }\n\n    this.state = \"IDLE\";\n    this.feedbackId = null;\n    this.feedbackData.feedbackType = null;\n    this.feedbackData.elementSelector = null;\n    this.feedbackData.elementText = null;\n    this.selectedBounds.visible = false;\n  }\n\n  // ==================== Video Recording ====================\n\n  private async startRecording(): Promise<void> {\n    // Don't start if already recording or in targeting/modal flow\n    if (this.isRecording || this.state !== \"IDLE\") return;\n\n    try {\n      // Start network capture\n      this.networkCapture = captureNetworkErrors();\n\n      // Create video recorder\n      this.videoRecorder = createVideoRecorder({\n        maxDuration: this.config.videoOptions.maxDuration,\n      });\n\n      this.videoRecorder.onTick((elapsed) => {\n        this.updateRecordingTimer(elapsed);\n      });\n\n      // Handle unexpected stops (browser stop button, max duration)\n      this.videoRecorder.onStop((blob) => {\n        if (this.isRecording) {\n          this.recordedBlob = blob;\n          this.isRecording = false;\n          this.removeRecordingIndicator();\n          document.removeEventListener(\"keydown\", this.boundKeyDown);\n          this.setButtonsDisabled(false);\n\n          if (blob && blob.size > 0) {\n            this.showRecordingPreview();\n          } else {\n            this.cleanupRecording();\n          }\n        }\n      });\n\n      await this.videoRecorder.start();\n      this.isRecording = true;\n\n      // Disable thumb buttons while recording\n      this.setButtonsDisabled(true);\n\n      // Show recording indicator\n      this.showRecordingIndicator();\n\n      // Listen for escape key\n      document.addEventListener(\"keydown\", this.boundKeyDown);\n    } catch (error) {\n      // User denied screen share or error occurred\n      this.cleanupRecording();\n    }\n  }\n\n  private async stopRecording(): Promise<void> {\n    if (!this.isRecording || !this.videoRecorder) return;\n\n    try {\n      this.recordedBlob = await this.videoRecorder.stop();\n    } catch {\n      this.recordedBlob = null;\n    }\n\n    this.isRecording = false;\n    this.removeRecordingIndicator();\n    document.removeEventListener(\"keydown\", this.boundKeyDown);\n\n    if (this.recordedBlob && this.recordedBlob.size > 0) {\n      this.showRecordingPreview();\n    } else {\n      this.cleanupRecording();\n    }\n  }\n\n  private showRecordingIndicator(): void {\n    const root = this.ensureOverlayHost();\n\n    this.recordingIndicator = document.createElement(\"div\");\n    this.recordingIndicator.className = \"qaid-recording-indicator\";\n    this.recordingIndicator.style.zIndex = String(this.config.zIndex + 100);\n\n    const dot = document.createElement(\"div\");\n    dot.className = \"qaid-recording-dot\";\n\n    const timer = document.createElement(\"span\");\n    timer.className = \"qaid-recording-time\";\n    timer.textContent = this.formatTime(this.config.videoOptions.maxDuration);\n\n    const stopBtn = document.createElement(\"button\");\n    stopBtn.type = \"button\";\n    stopBtn.className = \"qaid-recording-stop\";\n    stopBtn.textContent = \"Stop\";\n    stopBtn.addEventListener(\"click\", () => this.stopRecording());\n\n    this.recordingIndicator.appendChild(dot);\n    this.recordingIndicator.appendChild(timer);\n    this.recordingIndicator.appendChild(stopBtn);\n\n    this.applyVars(this.recordingIndicator);\n\n    // Enable pointer events on overlay host for recording indicator\n    if (this.overlayShadowHost) {\n      this.overlayShadowHost.style.pointerEvents = \"auto\";\n    }\n\n    root.appendChild(this.recordingIndicator);\n  }\n\n  private updateRecordingTimer(elapsed: number): void {\n    if (!this.recordingIndicator) return;\n    const timer = this.recordingIndicator.querySelector<HTMLSpanElement>(\".qaid-recording-time\");\n    if (timer) {\n      const remaining = Math.max(0, this.config.videoOptions.maxDuration - elapsed);\n      timer.textContent = this.formatTime(remaining);\n    }\n  }\n\n  private formatTime(seconds: number): string {\n    const m = Math.floor(seconds / 60);\n    const s = seconds % 60;\n    return `${m}:${s.toString().padStart(2, \"0\")}`;\n  }\n\n  private removeRecordingIndicator(): void {\n    if (this.recordingIndicator) {\n      this.recordingIndicator.remove();\n      this.recordingIndicator = null;\n    }\n  }\n\n  private showRecordingPreview(): void {\n    if (!this.recordedBlob) return;\n    const root = this.ensureOverlayHost();\n\n    const videoUrl = URL.createObjectURL(this.recordedBlob);\n\n    this.videoPreview = document.createElement(\"div\");\n    this.videoPreview.className = \"qaid-video-preview\";\n    this.videoPreview.style.zIndex = String(this.config.zIndex + 100);\n\n    const box = document.createElement(\"div\");\n    box.className = \"qaid-video-preview-box\";\n\n    const title = document.createElement(\"h3\");\n    title.textContent = \"Review your recording\";\n\n    const videoEl = document.createElement(\"video\");\n    videoEl.src = videoUrl;\n    videoEl.controls = true;\n    videoEl.autoplay = true;\n    videoEl.muted = true;\n\n    const textarea = document.createElement(\"textarea\");\n    textarea.placeholder = \"Optional: Describe the issue you recorded...\";\n\n    const actions = document.createElement(\"div\");\n    actions.className = \"qaid-video-preview-actions\";\n\n    const cancelBtn = document.createElement(\"button\");\n    cancelBtn.type = \"button\";\n    cancelBtn.className = \"qaid-video-btn qaid-video-btn-cancel\";\n    cancelBtn.textContent = \"Cancel\";\n    cancelBtn.addEventListener(\"click\", () => this.cancelRecordingPreview());\n\n    const rerecordBtn = document.createElement(\"button\");\n    rerecordBtn.type = \"button\";\n    rerecordBtn.className = \"qaid-video-btn qaid-video-btn-rerecord\";\n    rerecordBtn.textContent = \"Re-record\";\n    rerecordBtn.addEventListener(\"click\", () => {\n      this.cancelRecordingPreview();\n      this.startRecording();\n    });\n\n    const sendBtn = document.createElement(\"button\");\n    sendBtn.type = \"button\";\n    sendBtn.className = \"qaid-video-btn qaid-video-btn-send\";\n    sendBtn.textContent = \"Send\";\n    sendBtn.addEventListener(\"click\", () => {\n      const message = textarea.value.trim() || null;\n      this.submitVideoFeedback(message, sendBtn);\n    });\n\n    actions.appendChild(cancelBtn);\n    actions.appendChild(rerecordBtn);\n    actions.appendChild(sendBtn);\n\n    box.appendChild(title);\n    box.appendChild(videoEl);\n    box.appendChild(textarea);\n    box.appendChild(actions);\n\n    this.videoPreview.appendChild(box);\n    this.applyVars(this.videoPreview);\n\n    // Enable pointer events on overlay host for video preview\n    if (this.overlayShadowHost) {\n      this.overlayShadowHost.style.pointerEvents = \"auto\";\n    }\n\n    root.appendChild(this.videoPreview);\n\n    // Listen for escape key\n    document.addEventListener(\"keydown\", this.boundKeyDown);\n  }\n\n  private cancelRecordingPreview(): void {\n    this.removeVideoPreview();\n    this.cleanupRecording();\n  }\n\n  private removeVideoPreview(): void {\n    if (this.videoPreview) {\n      // Revoke object URLs\n      const videoEl = this.videoPreview.querySelector<HTMLVideoElement>(\"video\");\n      if (videoEl?.src) {\n        URL.revokeObjectURL(videoEl.src);\n      }\n      this.videoPreview.remove();\n      this.videoPreview = null;\n    }\n    document.removeEventListener(\"keydown\", this.boundKeyDown);\n  }\n\n  private async submitVideoFeedback(message: string | null, sendBtn: HTMLButtonElement): Promise<void> {\n    if (!this.recordedBlob || this.isSendingVideo) return;\n\n    this.isSendingVideo = true;\n    sendBtn.disabled = true;\n    sendBtn.textContent = \"Sending...\";\n\n    const formData = new FormData();\n    formData.append(\"video\", this.recordedBlob, `recording.${this.recordedBlob.type.includes(\"mp4\") ? \"mp4\" : \"webm\"}`);\n    formData.append(\"pageUrl\", window.location.href);\n    formData.append(\"visitorId\", this.visitorId);\n\n    if (this.config.apiKey) {\n      formData.append(\"apiKey\", this.config.apiKey);\n    }\n    if (message) {\n      formData.append(\"message\", message);\n    }\n    if (this.consoleCapture) {\n      formData.append(\"consoleErrors\", JSON.stringify(this.consoleCapture.errors));\n    }\n    if (this.networkCapture) {\n      formData.append(\"networkErrors\", JSON.stringify(this.networkCapture.errors));\n    }\n\n    try {\n      const response = await fetch(`${this.config.endpoint}/video`, {\n        method: \"POST\",\n        body: formData,\n      });\n\n      if (!response.ok) {\n        console.error(\"Failed to submit video feedback:\", await response.text());\n      }\n    } catch (error) {\n      console.error(\"Failed to submit video feedback:\", error);\n    }\n\n    this.isSendingVideo = false;\n    this.removeVideoPreview();\n    this.cleanupRecording();\n  }\n\n  private cleanupRecording(): void {\n    this.isRecording = false;\n    this.removeRecordingIndicator();\n\n    if (this.videoRecorder) {\n      this.videoRecorder.destroy();\n      this.videoRecorder = null;\n    }\n    if (this.networkCapture) {\n      this.networkCapture.restore();\n      this.networkCapture = null;\n    }\n    if (this.recordedBlob) {\n      this.recordedBlob = null;\n    }\n\n    // Re-enable buttons\n    this.setButtonsDisabled(false);\n\n    // Reset overlay host pointer events if nothing else needs them\n    if (this.overlayShadowHost && this.state === \"IDLE\") {\n      this.overlayShadowHost.style.pointerEvents = \"none\";\n    }\n  }\n\n  private setButtonsDisabled(disabled: boolean): void {\n    if (!this.buttonsContainer) return;\n    const buttons = this.buttonsContainer.querySelectorAll<HTMLButtonElement>(\"button.qaid-btn, button.qaid-btn-structural\");\n    buttons.forEach((btn) => {\n      if (disabled) {\n        // Don't disable the record button itself (it has its own state)\n        if (!btn.classList.contains(\"qaid-btn-record\")) {\n          btn.disabled = true;\n          btn.style.opacity = \"0.5\";\n        }\n      } else {\n        btn.disabled = false;\n        btn.style.opacity = \"\";\n      }\n    });\n  }\n\n  /**\n   * Destroy the embed and clean up all resources\n   */\n  public destroy(): void {\n    // Clean up video recording\n    this.cleanupRecording();\n    this.removeVideoPreview();\n\n    // Restore console.error\n    if (this.consoleCapture) {\n      this.consoleCapture.restore();\n      this.consoleCapture = null;\n    }\n\n    // Remove event listeners\n    window.removeEventListener(\"resize\", this.boundResize);\n    document.removeEventListener(\"keydown\", this.boundKeyDown);\n    document.removeEventListener(\"mousemove\", this.boundMouseMove);\n    document.removeEventListener(\"click\", this.boundClick, true);\n\n    document.body.classList.remove(\"qaid-targeting\", \"qaid-type-up\");\n    document.body.style.removeProperty(\"--qaid-positive\");\n    document.body.style.removeProperty(\"--qaid-negative\");\n\n    // Remove shadow hosts from DOM (this removes shadow roots and all their contents)\n    if (this.shadowHost) {\n      this.shadowHost.remove();\n      this.shadowHost = null;\n      this.shadowRoot = null;\n    }\n    if (this.overlayShadowHost) {\n      this.overlayShadowHost.remove();\n      this.overlayShadowHost = null;\n      this.overlayShadowRoot = null;\n    }\n    this.buttonsContainer = null;\n    this.overlayContainer = null;\n    this.captureLayer = null;\n    this.crosshairH = null;\n    this.crosshairV = null;\n    this.scope = null;\n    this.marker = null;\n    this.modalContainer = null;\n    this.backdrop = null;\n    this.tooltipElement = null;\n\n    // Remove light DOM styles (reference counted)\n    removeStyles();\n  }\n}\n","/**\n * @qaiddev/thumbs-embed - Standalone Feedback Embed\n *\n * A zero-dependency feedback embed with element targeting.\n *\n * Usage via ES module:\n * ```typescript\n * import { QaidFeedback } from '@qaiddev/thumbs-embed';\n *\n * const embed = new QaidFeedback({\n *   endpoint: '/api/feedback'\n * });\n * ```\n *\n * Usage via script tag:\n * ```html\n * <script src=\"feedback.umd.cjs\" data-endpoint=\"/api/feedback\"></script>\n * ```\n *\n * Or manually initialize:\n * ```html\n * <script src=\"feedback.umd.cjs\"></script>\n * <script>\n *   const embed = new QaidFeedback.QaidFeedback({\n *     endpoint: '/api/feedback'\n *   });\n * </script>\n * ```\n */\n\nimport { QaidFeedback } from \"./embed\";\n\nexport { QaidFeedback };\nexport type {\n  FeedbackConfig,\n  ResolvedFeedbackConfig,\n  ConsoleError,\n  NetworkError,\n  FeedbackData,\n  SelectedBounds,\n  FeedbackPayload,\n  FeedbackResponse,\n  FeedbackMessagePayload,\n} from \"./types\";\nexport { captureNetworkErrors } from \"./network-capture\";\nexport type { NetworkCapture } from \"./network-capture\";\nexport { createVideoRecorder, isVideoRecordingSupported, getSupportedMimeType } from \"./video-capture\";\nexport type { VideoRecorder, VideoRecorderOptions } from \"./video-capture\";\nexport { captureDomScreenshot, isDomScreenshotSupported } from \"./screenshot-dom\";\nexport type { DomScreenshotOptions } from \"./screenshot-dom\";\n\nimport type { FeedbackConfig } from \"./types\";\n\n/**\n * Find theme CSS from an element matched by a CSS selector.\n * Used by data-css-selector attribute and JSON cssSelector property.\n */\nfunction findCssFromSelector(selector: string): string {\n  const el = document.querySelector(selector);\n  return el?.textContent?.trim() ?? \"\";\n}\n\n/**\n * Parse JSON config from a separate script tag with type=\"application/json\"\n * Looks for: <script type=\"application/json\" data-feedback-config>{ ... }</script>\n */\nfunction parseJsonConfig(): Partial<FeedbackConfig> | null {\n  const configScript = document.querySelector(\n    'script[type=\"application/json\"][data-feedback-config]'\n  );\n  if (!configScript) return null;\n\n  const textContent = configScript.textContent?.trim();\n  if (!textContent) return null;\n\n  try {\n    const parsed = JSON.parse(textContent);\n    // Resolve cssSelector → css\n    if (parsed.cssSelector && !parsed.css) {\n      parsed.css = findCssFromSelector(parsed.cssSelector);\n      delete parsed.cssSelector;\n    }\n    return parsed;\n  } catch {\n    return null;\n  }\n}\n\n/**\n * Parse config from data-* attributes (backward compatibility)\n */\nfunction parseDataAttributes(script: HTMLScriptElement): Partial<FeedbackConfig> | null {\n  const endpoint = script.getAttribute(\"data-endpoint\");\n  if (!endpoint) return null;\n\n  const position = script.getAttribute(\"data-position\") as\n    | \"bottom-right\"\n    | \"bottom-left\"\n    | \"top-right\"\n    | \"top-left\"\n    | null;\n  const zIndex = script.getAttribute(\"data-zindex\");\n  const positiveColor = script.getAttribute(\"data-positive-color\");\n  const negativeColor = script.getAttribute(\"data-negative-color\");\n  const markerColor = script.getAttribute(\"data-marker-color\");\n  const container = script.getAttribute(\"data-container\");\n  const buttonClass = script.getAttribute(\"data-button-class\");\n  const skipTargeting = script.getAttribute(\"data-skip-targeting\");\n  const incognito = script.getAttribute(\"data-incognito\");\n  const buttonSize = script.getAttribute(\"data-button-size\") as\n    | \"small\"\n    | \"medium\"\n    | \"large\"\n    | null;\n  const offsetX = script.getAttribute(\"data-offset-x\");\n  const offsetY = script.getAttribute(\"data-offset-y\");\n  const modalWidth = script.getAttribute(\"data-modal-width\");\n  const backdropOpacity = script.getAttribute(\"data-backdrop-opacity\");\n  const fontFamily = script.getAttribute(\"data-font-family\");\n  const fontSize = script.getAttribute(\"data-font-size\");\n  const tooltip = script.getAttribute(\"data-tooltip\");\n  const modalTitle = script.getAttribute(\"data-modal-title\");\n  const modalSubtitle = script.getAttribute(\"data-modal-subtitle\");\n  const placeholder = script.getAttribute(\"data-placeholder\");\n  const submitButton = script.getAttribute(\"data-submit-button\");\n  const skipButton = script.getAttribute(\"data-skip-button\");\n  const positiveIcon = script.getAttribute(\"data-positive-icon\");\n  const negativeIcon = script.getAttribute(\"data-negative-icon\");\n  const apiKey = script.getAttribute(\"data-api-key\");\n  const captureScreenshot = script.getAttribute(\"data-capture-screenshot\");\n  const screenshotQuality = script.getAttribute(\"data-screenshot-quality\");\n  const screenshotMaxWidth = script.getAttribute(\"data-screenshot-max-width\");\n  const screenshotMaxHeight = script.getAttribute(\"data-screenshot-max-height\");\n  const captureVideo = script.getAttribute(\"data-capture-video\");\n  const hideThumbs = script.getAttribute(\"data-hide-thumbs\");\n  const videoMaxDuration = script.getAttribute(\"data-video-max-duration\");\n  const screenshotMethod = script.getAttribute(\"data-screenshot-method\") as \"dom\" | \"permission\" | null;\n  const direction = script.getAttribute(\"data-direction\") as \"horizontal\" | \"vertical\" | null;\n  const cssSelector = script.getAttribute(\"data-css-selector\");\n\n  return {\n    endpoint,\n    css: cssSelector ? findCssFromSelector(cssSelector) : undefined,\n    apiKey: apiKey ?? undefined,\n    captureScreenshot: captureScreenshot === \"true\" ? true : undefined,\n    screenshotOptions: (screenshotQuality || screenshotMaxWidth || screenshotMaxHeight) ? {\n      quality: screenshotQuality ? parseFloat(screenshotQuality) : undefined,\n      maxWidth: screenshotMaxWidth ? parseInt(screenshotMaxWidth, 10) : undefined,\n      maxHeight: screenshotMaxHeight ? parseInt(screenshotMaxHeight, 10) : undefined,\n    } : undefined,\n    container: container ?? undefined,\n    buttonClass: buttonClass ?? undefined,\n    direction: direction ?? undefined,\n    position: position ?? undefined,\n    zIndex: zIndex ? parseInt(zIndex, 10) : undefined,\n    skipTargeting: skipTargeting === \"true\" ? true : undefined,\n    incognito: incognito === \"true\" ? true : undefined,\n    buttonSize: buttonSize ?? undefined,\n    offset: (offsetX || offsetY) ? {\n      x: offsetX ? parseInt(offsetX, 10) : undefined,\n      y: offsetY ? parseInt(offsetY, 10) : undefined,\n    } : undefined,\n    modalWidth: modalWidth ? parseInt(modalWidth, 10) : undefined,\n    backdropOpacity: backdropOpacity ? parseFloat(backdropOpacity) : undefined,\n    fontFamily: fontFamily ?? undefined,\n    fontSize: fontSize ? parseInt(fontSize, 10) : undefined,\n    colors: {\n      positive: positiveColor ?? undefined,\n      negative: negativeColor ?? undefined,\n      marker: markerColor ?? undefined,\n    },\n    text: (tooltip || modalTitle || modalSubtitle || placeholder || submitButton || skipButton) ? {\n      tooltip: tooltip ?? undefined,\n      modalTitle: modalTitle ?? undefined,\n      modalSubtitle: modalSubtitle ?? undefined,\n      placeholder: placeholder ?? undefined,\n      submitButton: submitButton ?? undefined,\n      skipButton: skipButton ?? undefined,\n    } : undefined,\n    positiveIcon: positiveIcon ?? undefined,\n    negativeIcon: negativeIcon ?? undefined,\n    screenshotMethod: screenshotMethod ?? undefined,\n    captureVideo: captureVideo === \"true\" ? true : undefined,\n    hideThumbs: hideThumbs === \"true\" ? true : undefined,\n    videoOptions: videoMaxDuration ? {\n      maxDuration: parseInt(videoMaxDuration, 10),\n    } : undefined,\n  };\n}\n\n// Auto-initialize from script tag\nif (typeof document !== \"undefined\") {\n  const initFromScript = (): void => {\n    const script = document.currentScript as HTMLScriptElement | null;\n\n    // Try JSON config from separate script tag first, fall back to data-* attributes\n    const jsonConfig = parseJsonConfig();\n    const dataConfig = script ? parseDataAttributes(script) : null;\n    const config = jsonConfig ?? dataConfig;\n\n    if (config?.endpoint) {\n      new QaidFeedback(config as FeedbackConfig);\n    }\n  };\n\n  // Run immediately if DOM is ready, otherwise wait\n  if (document.readyState === \"loading\") {\n    document.addEventListener(\"DOMContentLoaded\", initFromScript);\n  } else {\n    initFromScript();\n  }\n}\n"],"names":["THUMBS_UP_ICON","THUMBS_DOWN_ICON","RECORD_ICON","instanceCount","DEFAULT_BUTTON_STYLES","BUTTON_SIZES","ICON_SIZES","getLuminance","r","g","b","rs","gs","bs","c","parseColor","color","hex","fullHex","num","match","getContrastTextColor","bgColor","rgb","buildCssVars","options","positiveColor","negativeColor","markerColor","buttonSize","modalWidth","backdropOpacity","fontFamily","fontSize","btnSize","iconSize","markerTextColor","applyCssVars","el","vars","name","value","getEmbedStyles","shadowStyles","injectStyles","style","lightStyles","removeStyles","DATA_ATTRS","findDataAttribute","element","stopAt","current","attr","getTruncatedText","maxLength","textContent","getNthChildIndex","index","sibling","generateNthChildPath","path","tag","escapeCSSIdentifier","str","generateSelector","dataAttr","generateElementInfo","text","DEFAULT_DIMENSIONS","calculateVerticalPosition","bounds","viewportHeight","totalHeight","gap","viewportPadding","spaceAbove","spaceBelow","position","top","calculateHorizontalPosition","viewportWidth","left","calculateArrowPosition","modalLeft","minOffset","arrowWidth","arrowLeft","calculateModalPosition","dimensions","vertical","calculateModalAndArrowPosition","modal","MAX_MESSAGES","captureConsoleErrors","onError","errors","originalError","originalWarn","originalLog","capture","level","args","error","arg","MAX_ENTRIES","MAX_BODY_SIZE","truncateBody","body","addEntry","entry","safeReadBody","response","captureNetworkErrors","originalFetch","input","init","url","method","requestBody","responseBody","originalXHROpen","originalXHRSend","rest","xhr","isVideoRecordingSupported","getSupportedMimeType","candidates","type","createVideoRecorder","maxDuration","videoBitsPerSecond","stream","recorder","chunks","tickCallback","stopCallback","tickInterval","startTime","resolveStop","rejectStop","stopped","autoStopTimeout","cleanup","t","finishRecording","mimeType","videoTrack","e","blob","elapsed","resolve","reject","callback","isMobileViewport","breakpoint","getElementAtPointUnderOverlay","x","y","hosts","saved","h","i","isEmbedElement","getElementBounds","padding","rect","captureScreenshot","quality","maxWidth","maxHeight","track","settings","video","checkFrame","srcWidth","srcHeight","scale","width","height","canvas","ctx","SCRIPT_URL","LOAD_TIMEOUT","POLL_INTERVAL","loadPromise","isDomScreenshotSupported","loadHtml2Canvas","script","start","poll","captureDomScreenshot","scaledWidth","scaledHeight","scaledCanvas","VISITOR_ID_KEY","getOrCreateVisitorId","visitorId","QaidFeedback","config","_error","userContainer","baseStyle","themeStyle","dirClass","offsetX","offsetY","useCustomClass","btnBaseClass","tooltipText","tooltip","upWrapper","upBtn","downWrapper","downBtn","recordWrapper","recordBtn","anchor","anchorRect","tooltipRect","buttonEl","root","vignette","elementUnder","target","selector","screenshot","elementBounds","payload","data","sheet","arrow","arrowEl","box","isUp","positiveIcon","negativeIcon","textarea","submitBtn","message","typeToggle","newType","err","dot","timer","stopBtn","remaining","seconds","m","s","videoUrl","title","videoEl","actions","cancelBtn","rerecordBtn","sendBtn","formData","disabled","btn","findCssFromSelector","parseJsonConfig","configScript","parsed","parseDataAttributes","endpoint","zIndex","container","buttonClass","skipTargeting","incognito","modalTitle","modalSubtitle","placeholder","submitButton","skipButton","apiKey","screenshotQuality","screenshotMaxWidth","screenshotMaxHeight","captureVideo","hideThumbs","videoMaxDuration","screenshotMethod","direction","cssSelector","initFromScript","jsonConfig","dataConfig"],"mappings":"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"}