bugstash 0.1.26 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/breadcrumbs.ts","../src/redact.ts","../src/logger.ts","../src/network.ts","../src/errors.ts","../src/performance.ts","../../node_modules/html-to-image/src/util.ts","../../node_modules/html-to-image/src/clone-pseudos.ts","../../node_modules/html-to-image/src/mimes.ts","../../node_modules/html-to-image/src/dataurl.ts","../../node_modules/html-to-image/src/clone-node.ts","../../node_modules/html-to-image/src/embed-resources.ts","../../node_modules/html-to-image/src/embed-images.ts","../../node_modules/html-to-image/src/apply-style.ts","../../node_modules/html-to-image/src/embed-webfonts.ts","../../node_modules/html-to-image/src/index.ts","../src/screenshot.ts","../src/api.ts","../src/themes.ts","../src/layouts.ts","../src/realtime.ts","../src/livepins.ts","../src/panel.ts","../src/annotation.ts"],"sourcesContent":["import type { BugStashConfig } from '@bugstash/shared';\nimport { initPanel, destroyPanel, setTheme, getCurrentThemeId, setLayout, getCurrentLayoutId } from './panel';\nimport { initLogger, getLogs, clearLogs, restoreConsole } from './logger';\nimport { initNetwork, getNetworkCaptures, getFailedNetworkCaptures, clearNetworkCaptures, restoreNetwork } from './network';\nimport { initErrors, getErrors, clearErrors, restoreErrors } from './errors';\nimport { initBreadcrumbs, getBreadcrumbs, addBreadcrumb, clearBreadcrumbs, restoreBreadcrumbs } from './breadcrumbs';\nimport { initPerformance, getPerformanceMetrics, restorePerformance } from './performance';\nimport { setEndpoint, getCurrentUser, login, logout, verifyDomain } from './api';\nimport { getThemes, getThemeById } from './themes';\nimport { getLayouts, getLayoutById } from './layouts';\nimport { initLivePins, destroyLivePins, togglePinMode, isPinModeActive } from './livepins';\nimport { connectRealtime, disconnectRealtime, isConnected } from './realtime';\nimport { openAnnotationEditor, type AnnotationResult } from './annotation';\nimport { redactString, redactObject } from './redact';\n\nexport type { AnnotationResult };\n\nexport type {\n BugStashConfig,\n LogEntry,\n NetworkEntry,\n ErrorEntry,\n Breadcrumb,\n PerformanceMetrics,\n BugReport,\n ReportContext,\n APIResponse,\n AuthUser,\n AuthTokens,\n LivePin,\n PinComment,\n Member,\n Organization,\n Project,\n Webhook,\n WebhookEvent,\n Integration,\n IntegrationType,\n SourceMap,\n PlanLimits,\n QuotaStatus,\n OrgBranding,\n AnnotationShape,\n TwoFactorSetup,\n TwoFactorStatus,\n DuplicateMatch,\n} from '@bugstash/shared';\n\nlet initialized = false;\nlet shadowRoot: ShadowRoot | null = null;\n\nfunction getOrCreateShadowRoot(): ShadowRoot {\n if (shadowRoot) return shadowRoot;\n // Custom element tag — immune to host CSS rules targeting div, span, p, *, etc.\n const host = document.createElement('bugstash-root');\n\n // ─── Core positioning ───\n host.style.setProperty('position', 'fixed', 'important');\n host.style.setProperty('inset', '0', 'important');\n host.style.setProperty('pointer-events', 'none', 'important');\n host.style.setProperty('z-index', '2147483640', 'important');\n host.style.setProperty('display', 'block', 'important');\n host.style.setProperty('visibility', 'visible', 'important');\n host.style.setProperty('opacity', '1', 'important');\n\n // ─── Prevent host from creating a containing block for fixed children ───\n // CSS spec: transform, perspective, filter, contain, will-change create\n // new containing blocks that break position:fixed on descendants.\n host.style.setProperty('transform', 'none', 'important');\n host.style.setProperty('perspective', 'none', 'important');\n host.style.setProperty('filter', 'none', 'important');\n host.style.setProperty('will-change', 'auto', 'important');\n host.style.setProperty('contain', 'none', 'important');\n host.style.setProperty('isolation', 'auto', 'important');\n host.style.setProperty('mix-blend-mode', 'normal', 'important');\n host.style.setProperty('clip-path', 'none', 'important');\n\n // ─── Resist host CSS interference ───\n host.style.setProperty('margin', '0', 'important');\n host.style.setProperty('padding', '0', 'important');\n host.style.setProperty('border', 'none', 'important');\n host.style.setProperty('background', 'none', 'important');\n host.style.setProperty('box-sizing', 'border-box', 'important');\n host.style.setProperty('overflow', 'visible', 'important');\n host.style.setProperty('min-width', '0', 'important');\n host.style.setProperty('min-height', '0', 'important');\n host.style.setProperty('max-width', 'none', 'important');\n host.style.setProperty('max-height', 'none', 'important');\n host.style.setProperty('float', 'none', 'important');\n host.style.setProperty('clear', 'none', 'important');\n host.style.setProperty('columns', 'auto', 'important');\n host.style.setProperty('font-size', '16px', 'important');\n host.style.setProperty('line-height', 'normal', 'important');\n host.style.setProperty('text-align', 'left', 'important');\n host.style.setProperty('direction', 'ltr', 'important');\n\n shadowRoot = host.attachShadow({ mode: 'closed' });\n document.body.appendChild(host);\n return shadowRoot;\n}\n\nfunction initModules(options: BugStashConfig) {\n if (initialized) return;\n initialized = true;\n\n const shadow = getOrCreateShadowRoot();\n\n // Order matters: breadcrumbs first (other modules push to it)\n initBreadcrumbs(options.maxBreadcrumbs);\n initLogger(options.maxLogs);\n initNetwork(options.maxNetworkCaptures);\n initErrors();\n if (options.enablePerformance !== false) initPerformance();\n initPanel(options, shadow);\n\n // Init live pins if enabled and user is logged in\n if (options.enableLivePins !== false) {\n const user = getCurrentUser();\n if (user) {\n initLivePins(options.projectId, shadow);\n connectRealtime(options.projectId);\n }\n }\n}\n\n/**\n * Auto-detect the environment from the current hostname when `environment`\n * is not explicitly set.\n *\n * Production hostnames → SDK stays silent (no UI, no network calls)\n * Staging/preview hosts → SDK activates in staging mode\n * localhost / 127.x / *.local / IP → SDK activates in development mode\n *\n * Users can always override by passing `environment` explicitly.\n */\nfunction detectEnvironment(): 'development' | 'staging' | 'production' {\n if (typeof window === 'undefined') return 'production';\n const host = window.location.hostname;\n\n // Explicit localhost / loopback / local network\n if (\n host === 'localhost' ||\n host === '127.0.0.1' ||\n host === '0.0.0.0' ||\n host.endsWith('.local') ||\n /^192\\.168\\./.test(host) ||\n /^10\\./.test(host) ||\n /^172\\.(1[6-9]|2\\d|3[01])\\./.test(host)\n ) return 'development';\n\n // Common staging/preview patterns\n if (\n host.includes('staging') ||\n host.includes('stage') ||\n host.includes('preview') ||\n host.includes('preprod') ||\n host.includes('pre-prod') ||\n host.includes('qa.') ||\n host.includes('.qa') ||\n host.includes('test.') ||\n host.includes('.dev.') ||\n host.includes('vercel.app') || // Vercel preview deployments\n host.includes('netlify.app') || // Netlify preview deployments\n host.includes('pages.dev') || // Cloudflare Pages previews\n host.includes('ngrok.io') || // ngrok tunnels\n host.includes('ngrok-free.app') || // ngrok free tier\n host.includes('localhost.run') || // localhost.run tunnels\n host.includes('loca.lt') // localtunnel\n ) return 'staging';\n\n // Everything else is treated as production — SDK will be silent\n return 'production';\n}\n\nexport const BugStash = {\n init(options: BugStashConfig) {\n if (initialized) return;\n if (typeof window === 'undefined') return;\n\n const env = options.environment ?? detectEnvironment();\n if (env === 'production') return;\n\n if (options.endpoint) setEndpoint(options.endpoint);\n\n const host = window.location.hostname;\n const isLocal =\n host === 'localhost' ||\n host === '127.0.0.1' ||\n host === '0.0.0.0' ||\n host.endsWith('.local') ||\n /^192\\.168\\./.test(host) ||\n /^10\\./.test(host) ||\n /^172\\.(1[6-9]|2\\d|3[01])\\./.test(host);\n\n if (isLocal) {\n // Fast path for local dev — skip domain verification\n initModules(options);\n } else {\n // Verify domain before initializing anything\n verifyDomain(options.projectId)\n .then((allowed) => {\n if (allowed) {\n initModules(options);\n }\n // If not allowed, do nothing — SDK stays invisible\n })\n .catch(() => {\n // Fail closed — SDK stays invisible on errors\n });\n }\n },\n\n destroy() {\n if (!initialized) return;\n destroyPanel();\n destroyLivePins();\n disconnectRealtime();\n restoreConsole();\n restoreNetwork();\n restoreErrors();\n restoreBreadcrumbs();\n restorePerformance();\n document.querySelector('bugstash-root')?.remove();\n shadowRoot = null;\n initialized = false;\n },\n\n // Programmatic API\n getLogs,\n clearLogs,\n getNetworkCaptures,\n getFailedNetworkCaptures,\n clearNetworkCaptures,\n getErrors,\n clearErrors,\n getBreadcrumbs,\n clearBreadcrumbs,\n getPerformanceMetrics,\n addBreadcrumb,\n // Theme API\n getThemes,\n getThemeById,\n setTheme,\n getCurrentThemeId,\n // Layout API\n getLayouts,\n getLayoutById,\n setLayout,\n getCurrentLayoutId,\n // Auth API\n getCurrentUser,\n login,\n logout,\n // Live Pins API\n togglePinMode,\n isPinModeActive,\n // Real-time\n isConnected,\n // Annotation\n openAnnotationEditor,\n // PII Redaction\n redactString,\n redactObject,\n};\n\nexport default BugStash;\n","import type { Breadcrumb } from '@bugstash/shared';\n\nlet crumbs: Breadcrumb[] = [];\nlet maxCrumbs = 50;\nlet clickHandler: ((e: MouseEvent) => void) | null = null;\nlet inputHandler: ((e: Event) => void) | null = null;\nlet popstateHandler: (() => void) | null = null;\nlet hashHandler: (() => void) | null = null;\n\nfunction getSelector(el: Element): string {\n if (el.id) return `#${el.id}`;\n const tag = el.tagName.toLowerCase();\n const cls = el.className && typeof el.className === 'string'\n ? '.' + el.className.trim().split(/\\s+/).slice(0, 2).join('.')\n : '';\n const text = (el.textContent || '').trim().slice(0, 30);\n const label = text ? ` \"${text}\"` : '';\n return `${tag}${cls}${label}`;\n}\n\nexport function addBreadcrumb(crumb: Breadcrumb) {\n crumbs.push(crumb);\n if (crumbs.length > maxCrumbs) crumbs.shift();\n}\n\nexport function initBreadcrumbs(max?: number) {\n if (max) maxCrumbs = max;\n\n // Track clicks\n clickHandler = (e: MouseEvent) => {\n const target = e.target as Element;\n if (!target || !target.tagName) return;\n addBreadcrumb({\n type: 'click',\n category: 'ui',\n message: `Clicked ${getSelector(target)}`,\n timestamp: Date.now(),\n data: { x: e.clientX, y: e.clientY, selector: getSelector(target) },\n });\n };\n document.addEventListener('click', clickHandler, true);\n\n // Track input changes (debounced per element)\n const inputTimers = new WeakMap<Element, number>();\n inputHandler = (e: Event) => {\n const target = e.target as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n if (!target || !target.tagName) return;\n const tag = target.tagName.toLowerCase();\n if (tag !== 'input' && tag !== 'textarea' && tag !== 'select') return;\n\n // Debounce per element\n const existing = inputTimers.get(target);\n if (existing) clearTimeout(existing);\n inputTimers.set(\n target,\n window.setTimeout(() => {\n const isPassword = target instanceof HTMLInputElement && target.type === 'password';\n addBreadcrumb({\n type: 'input',\n category: 'ui',\n message: `Input ${getSelector(target)}`,\n timestamp: Date.now(),\n data: {\n selector: getSelector(target),\n value: isPassword ? '[redacted]' : undefined,\n },\n });\n }, 300),\n );\n };\n document.addEventListener('input', inputHandler, true);\n\n // Track navigation\n popstateHandler = () => {\n addBreadcrumb({\n type: 'navigation',\n category: 'navigation',\n message: `Navigated to ${window.location.pathname}`,\n timestamp: Date.now(),\n data: { url: window.location.href },\n });\n };\n window.addEventListener('popstate', popstateHandler);\n\n hashHandler = () => {\n addBreadcrumb({\n type: 'navigation',\n category: 'navigation',\n message: `Hash changed to ${window.location.hash}`,\n timestamp: Date.now(),\n data: { url: window.location.href },\n });\n };\n window.addEventListener('hashchange', hashHandler);\n\n // Initial breadcrumb\n addBreadcrumb({\n type: 'navigation',\n category: 'navigation',\n message: `Page loaded: ${window.location.pathname}`,\n timestamp: Date.now(),\n data: { url: window.location.href },\n });\n}\n\nexport function getBreadcrumbs(): Breadcrumb[] {\n return [...crumbs];\n}\n\nexport function clearBreadcrumbs() {\n crumbs = [];\n}\n\nexport function restoreBreadcrumbs() {\n if (clickHandler) document.removeEventListener('click', clickHandler, true);\n if (inputHandler) document.removeEventListener('input', inputHandler, true);\n if (popstateHandler) window.removeEventListener('popstate', popstateHandler);\n if (hashHandler) window.removeEventListener('hashchange', hashHandler);\n clickHandler = null;\n inputHandler = null;\n popstateHandler = null;\n hashHandler = null;\n}\n","/**\n * PII/sensitive data redaction for captured data.\n * Masks passwords, tokens, credit cards, SSNs, emails in captured logs and network data.\n */\n\nconst REDACT_PLACEHOLDER = '[REDACTED]';\n\n// Patterns for common sensitive data\nconst PATTERNS: [RegExp, string | ((match: string) => string)][] = [\n // Credit card numbers (Visa, MC, Amex, etc.)\n [/\\b(?:\\d[ -]*?){13,19}\\b/g, '[CC_REDACTED]'],\n // SSN\n [/\\b\\d{3}-\\d{2}-\\d{4}\\b/g, '[SSN_REDACTED]'],\n // Email addresses (in log strings, not for user context)\n // Intentionally NOT redacting emails since they're often needed for debugging\n // Bearer tokens\n [/Bearer\\s+[A-Za-z0-9\\-._~+/]+=*/g, 'Bearer [TOKEN_REDACTED]'],\n // JWT tokens (xxx.yyy.zzz pattern)\n [/eyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, '[JWT_REDACTED]'],\n // API keys (long hex/base64 strings that look like keys)\n [/(?:api[_-]?key|apikey|secret|token|password|passwd|authorization)['\":\\s=]+['\"]?([A-Za-z0-9\\-._~+/]{20,})['\"]?/gi, (match) => {\n const eqIdx = match.search(/[=:]/);\n return match.slice(0, eqIdx + 1) + ' ' + REDACT_PLACEHOLDER;\n }],\n // AWS access keys\n [/AKIA[0-9A-Z]{16}/g, '[AWS_KEY_REDACTED]'],\n // Generic password fields in JSON\n [/\"(?:password|passwd|secret|token|access_token|refresh_token|api_key|apiKey|private_key)\":\\s*\"[^\"]*\"/gi, (match) => {\n const colonIdx = match.indexOf(':');\n return match.slice(0, colonIdx + 1) + ' \"' + REDACT_PLACEHOLDER + '\"';\n }],\n];\n\n// Header names that should be redacted\nconst SENSITIVE_HEADERS = new Set([\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'x-auth-token',\n 'x-csrf-token',\n 'proxy-authorization',\n]);\n\n/** Redact sensitive data from a string. */\nexport function redactString(input: string): string {\n let result = input;\n for (const [pattern, replacement] of PATTERNS) {\n if (typeof replacement === 'function') {\n result = result.replace(pattern, replacement as any);\n } else {\n result = result.replace(pattern, replacement);\n }\n }\n return result;\n}\n\n/** Redact sensitive headers from a headers object. */\nexport function redactHeaders(headers: Record<string, string> | undefined): Record<string, string> | undefined {\n if (!headers) return headers;\n const redacted: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (SENSITIVE_HEADERS.has(key.toLowerCase())) {\n redacted[key] = REDACT_PLACEHOLDER;\n } else {\n redacted[key] = redactString(value);\n }\n }\n return redacted;\n}\n\n/** Redact an array of log argument strings. */\nexport function redactLogArgs(args: string[]): string[] {\n return args.map(redactString);\n}\n\n/** Redact sensitive data from serialized objects. */\nexport function redactObject(obj: any): any {\n if (typeof obj === 'string') return redactString(obj);\n if (Array.isArray(obj)) return obj.map(redactObject);\n if (obj && typeof obj === 'object') {\n const result: any = {};\n for (const [key, value] of Object.entries(obj)) {\n const lk = key.toLowerCase();\n if (lk.includes('password') || lk.includes('secret') || lk.includes('token') ||\n lk.includes('apikey') || lk.includes('api_key') || lk.includes('private')) {\n result[key] = REDACT_PLACEHOLDER;\n } else {\n result[key] = redactObject(value);\n }\n }\n return result;\n }\n return obj;\n}\n","import type { LogEntry } from '@bugstash/shared';\nimport { addBreadcrumb } from './breadcrumbs';\nimport { redactLogArgs } from './redact';\n\nconst originals = {\n log: console.log,\n warn: console.warn,\n error: console.error,\n debug: console.debug,\n info: console.info,\n};\n\nlet logs: LogEntry[] = [];\nlet maxLogs = 50;\n\nfunction serialize(args: any[]): string[] {\n return args.map((a) => {\n if (a instanceof Error) return `${a.name}: ${a.message}\\n${a.stack ?? ''}`;\n if (typeof a === 'object') {\n try {\n return JSON.stringify(a, null, 2);\n } catch {\n return String(a);\n }\n }\n return String(a);\n });\n}\n\nfunction capture(level: LogEntry['level'], args: any[]) {\n const entry: LogEntry = {\n level,\n args: redactLogArgs(serialize(args)),\n timestamp: Date.now(),\n };\n if (level === 'error') {\n entry.stack = new Error().stack?.split('\\n').slice(2).join('\\n');\n }\n logs.push(entry);\n if (logs.length > maxLogs) logs.shift();\n\n addBreadcrumb({\n type: 'console',\n category: `console.${level}`,\n message: entry.args.join(' ').slice(0, 200),\n timestamp: entry.timestamp,\n });\n}\n\nexport function initLogger(max?: number) {\n if (max) maxLogs = max;\n\n for (const level of Object.keys(originals) as LogEntry['level'][]) {\n console[level] = function (...args: any[]) {\n capture(level, args);\n originals[level].apply(console, args);\n };\n }\n}\n\nexport function getLogs(): LogEntry[] {\n return [...logs];\n}\n\nexport function clearLogs() {\n logs = [];\n}\n\nexport function restoreConsole() {\n for (const level of Object.keys(originals) as LogEntry['level'][]) {\n console[level] = originals[level];\n }\n}\n","import type { NetworkEntry } from '@bugstash/shared';\nimport { addBreadcrumb } from './breadcrumbs';\nimport { redactString } from './redact';\n\nlet captures: NetworkEntry[] = [];\nlet maxCaptures = 50;\nlet originalFetch: typeof window.fetch;\nlet originalXHROpen: typeof XMLHttpRequest.prototype.open;\nlet originalXHRSend: typeof XMLHttpRequest.prototype.send;\n\nfunction record(entry: NetworkEntry) {\n captures.push(entry);\n if (captures.length > maxCaptures) captures.shift();\n\n addBreadcrumb({\n type: 'network',\n category: entry.failed ? 'network.error' : 'network.ok',\n message: `${entry.method} ${entry.url} → ${entry.status} (${entry.duration}ms)`,\n timestamp: entry.timestamp,\n data: { status: entry.status, duration: entry.duration },\n });\n}\n\nfunction shortenUrl(url: string): string {\n try {\n const u = new URL(url, window.location.origin);\n // Redact sensitive query params (tokens, keys, etc.)\n const params = new URLSearchParams(u.search);\n for (const key of params.keys()) {\n const lk = key.toLowerCase();\n if (lk.includes('token') || lk.includes('key') || lk.includes('secret') || lk.includes('password') || lk.includes('auth')) {\n params.set(key, '[REDACTED]');\n }\n }\n const qs = params.toString();\n return u.pathname + (qs ? '?' + qs : '');\n } catch {\n return redactString(url);\n }\n}\n\nfunction patchFetch() {\n originalFetch = window.fetch;\n\n window.fetch = async function (input: any, init?: any) {\n const method = init?.method?.toUpperCase() ?? 'GET';\n const rawUrl = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;\n const url = shortenUrl(rawUrl);\n const start = Date.now();\n\n try {\n const response = await originalFetch.call(window, input, init);\n record({\n method,\n url,\n status: response.status,\n statusText: response.statusText,\n duration: Date.now() - start,\n responseType: response.headers.get('content-type') ?? undefined,\n timestamp: start,\n failed: response.status >= 400,\n });\n return response;\n } catch (err) {\n record({\n method,\n url,\n status: 0,\n statusText: 'Network Error',\n duration: Date.now() - start,\n timestamp: start,\n failed: true,\n });\n throw err;\n }\n };\n}\n\nfunction patchXHR() {\n originalXHROpen = XMLHttpRequest.prototype.open;\n originalXHRSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (method: string, url: string | URL, ...rest: any[]) {\n (this as any).__bs_method = method.toUpperCase();\n (this as any).__bs_url = shortenUrl(typeof url === 'string' ? url : url.href);\n return originalXHROpen.apply(this, [method, url, ...rest] as any);\n };\n\n XMLHttpRequest.prototype.send = function (body?: any) {\n const start = Date.now();\n\n this.addEventListener('loadend', function () {\n record({\n method: (this as any).__bs_method ?? 'GET',\n url: (this as any).__bs_url ?? '',\n status: this.status,\n statusText: this.statusText,\n duration: Date.now() - start,\n responseType: this.getResponseHeader('content-type') ?? undefined,\n timestamp: start,\n failed: this.status >= 400 || this.status === 0,\n });\n });\n\n return originalXHRSend.call(this, body);\n };\n}\n\nexport function initNetwork(max?: number) {\n if (max) maxCaptures = max;\n patchFetch();\n patchXHR();\n}\n\nexport function getNetworkCaptures(): NetworkEntry[] {\n return [...captures];\n}\n\nexport function getFailedNetworkCaptures(): NetworkEntry[] {\n return captures.filter((c) => c.failed);\n}\n\nexport function clearNetworkCaptures() {\n captures = [];\n}\n\nexport function restoreNetwork() {\n if (originalFetch) window.fetch = originalFetch;\n if (originalXHROpen) XMLHttpRequest.prototype.open = originalXHROpen;\n if (originalXHRSend) XMLHttpRequest.prototype.send = originalXHRSend;\n}\n","import type { ErrorEntry } from '@bugstash/shared';\nimport { addBreadcrumb } from './breadcrumbs';\n\nlet errors: ErrorEntry[] = [];\nlet onErrorHandler: ((e: ErrorEvent) => void) | null = null;\nlet onRejectionHandler: ((e: PromiseRejectionEvent) => void) | null = null;\n\nexport function initErrors() {\n onErrorHandler = (event: ErrorEvent) => {\n const entry: ErrorEntry = {\n message: event.message || 'Unknown error',\n source: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n stack: event.error?.stack,\n type: 'error',\n timestamp: Date.now(),\n };\n errors.push(entry);\n addBreadcrumb({\n type: 'error',\n category: 'exception',\n message: entry.message,\n timestamp: entry.timestamp,\n data: { source: entry.source, lineno: entry.lineno },\n });\n };\n\n onRejectionHandler = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const message =\n reason instanceof Error ? reason.message : typeof reason === 'string' ? reason : 'Unhandled promise rejection';\n const entry: ErrorEntry = {\n message,\n stack: reason instanceof Error ? reason.stack : undefined,\n type: 'unhandledrejection',\n timestamp: Date.now(),\n };\n errors.push(entry);\n addBreadcrumb({\n type: 'error',\n category: 'promise',\n message,\n timestamp: entry.timestamp,\n });\n };\n\n window.addEventListener('error', onErrorHandler);\n window.addEventListener('unhandledrejection', onRejectionHandler);\n}\n\nexport function getErrors(): ErrorEntry[] {\n return [...errors];\n}\n\nexport function clearErrors() {\n errors = [];\n}\n\nexport function restoreErrors() {\n if (onErrorHandler) window.removeEventListener('error', onErrorHandler);\n if (onRejectionHandler) window.removeEventListener('unhandledrejection', onRejectionHandler);\n onErrorHandler = null;\n onRejectionHandler = null;\n}\n","import type { PerformanceMetrics } from '@bugstash/shared';\n\nlet metrics: PerformanceMetrics | null = null;\nlet lcpObserver: PerformanceObserver | null = null;\nlet clsObserver: PerformanceObserver | null = null;\nlet fidObserver: PerformanceObserver | null = null;\n\nexport function initPerformance() {\n metrics = { timestamp: Date.now() };\n\n // Navigation timing\n if (performance.getEntriesByType) {\n const onLoad = () => {\n const [nav] = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[];\n if (nav && metrics) {\n metrics.pageLoadTime = Math.round(nav.loadEventEnd - nav.startTime);\n metrics.domContentLoaded = Math.round(nav.domContentLoadedEventEnd - nav.startTime);\n }\n\n // Paint timing\n const paints = performance.getEntriesByType('paint');\n for (const p of paints) {\n if (p.name === 'first-paint' && metrics) metrics.firstPaint = Math.round(p.startTime);\n if (p.name === 'first-contentful-paint' && metrics) metrics.firstContentfulPaint = Math.round(p.startTime);\n }\n\n // Resource count\n if (metrics) {\n metrics.resourceCount = performance.getEntriesByType('resource').length;\n }\n\n // Memory (Chrome only)\n const mem = (performance as any).memory;\n if (mem && metrics) {\n metrics.memoryUsage = {\n usedJSHeapSize: mem.usedJSHeapSize,\n totalJSHeapSize: mem.totalJSHeapSize,\n };\n }\n };\n\n if (document.readyState === 'complete') {\n setTimeout(onLoad, 0);\n } else {\n window.addEventListener('load', () => setTimeout(onLoad, 100));\n }\n }\n\n // LCP\n if (typeof PerformanceObserver !== 'undefined') {\n try {\n lcpObserver = new PerformanceObserver((list) => {\n const entries = list.getEntries();\n const last = entries[entries.length - 1];\n if (last && metrics) metrics.largestContentfulPaint = Math.round(last.startTime);\n });\n lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });\n } catch {}\n\n // CLS\n try {\n let clsValue = 0;\n clsObserver = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (!(entry as any).hadRecentInput) {\n clsValue += (entry as any).value;\n }\n }\n if (metrics) metrics.cumulativeLayoutShift = Math.round(clsValue * 1000) / 1000;\n });\n clsObserver.observe({ type: 'layout-shift', buffered: true });\n } catch {}\n\n // FID\n try {\n fidObserver = new PerformanceObserver((list) => {\n const [entry] = list.getEntries();\n if (entry && metrics) metrics.firstInputDelay = Math.round((entry as any).processingStart - entry.startTime);\n });\n fidObserver.observe({ type: 'first-input', buffered: true });\n } catch {}\n }\n}\n\nexport function getPerformanceMetrics(): PerformanceMetrics | null {\n if (metrics) metrics.timestamp = Date.now();\n return metrics ? { ...metrics } : null;\n}\n\nexport function restorePerformance() {\n lcpObserver?.disconnect();\n clsObserver?.disconnect();\n fidObserver?.disconnect();\n lcpObserver = null;\n clsObserver = null;\n fidObserver = null;\n metrics = null;\n}\n","import type { Options } from './types'\n\nexport function resolveUrl(url: string, baseUrl: string | null): string {\n // url is absolute already\n if (url.match(/^[a-z]+:\\/\\//i)) {\n return url\n }\n\n // url is absolute already, without protocol\n if (url.match(/^\\/\\//)) {\n return window.location.protocol + url\n }\n\n // dataURI, mailto:, tel:, etc.\n if (url.match(/^[a-z]+:/i)) {\n return url\n }\n\n const doc = document.implementation.createHTMLDocument()\n const base = doc.createElement('base')\n const a = doc.createElement('a')\n\n doc.head.appendChild(base)\n doc.body.appendChild(a)\n\n if (baseUrl) {\n base.href = baseUrl\n }\n\n a.href = url\n\n return a.href\n}\n\nexport const uuid = (() => {\n // generate uuid for className of pseudo elements.\n // We should not use GUIDs, otherwise pseudo elements sometimes cannot be captured.\n let counter = 0\n\n // ref: http://stackoverflow.com/a/6248722/2519373\n const random = () =>\n // eslint-disable-next-line no-bitwise\n `0000${((Math.random() * 36 ** 4) << 0).toString(36)}`.slice(-4)\n\n return () => {\n counter += 1\n return `u${random()}${counter}`\n }\n})()\n\nexport function delay<T>(ms: number) {\n return (args: T) =>\n new Promise<T>((resolve) => {\n setTimeout(() => resolve(args), ms)\n })\n}\n\nexport function toArray<T>(arrayLike: any): T[] {\n const arr: T[] = []\n\n for (let i = 0, l = arrayLike.length; i < l; i++) {\n arr.push(arrayLike[i])\n }\n\n return arr\n}\n\nlet styleProps: string[] | null = null\nexport function getStyleProperties(options: Options = {}): string[] {\n if (styleProps) {\n return styleProps\n }\n\n if (options.includeStyleProperties) {\n styleProps = options.includeStyleProperties\n return styleProps\n }\n\n styleProps = toArray(window.getComputedStyle(document.documentElement))\n\n return styleProps\n}\n\nfunction px(node: HTMLElement, styleProperty: string) {\n const win = node.ownerDocument.defaultView || window\n const val = win.getComputedStyle(node).getPropertyValue(styleProperty)\n return val ? parseFloat(val.replace('px', '')) : 0\n}\n\nfunction getNodeWidth(node: HTMLElement) {\n const leftBorder = px(node, 'border-left-width')\n const rightBorder = px(node, 'border-right-width')\n return node.clientWidth + leftBorder + rightBorder\n}\n\nfunction getNodeHeight(node: HTMLElement) {\n const topBorder = px(node, 'border-top-width')\n const bottomBorder = px(node, 'border-bottom-width')\n return node.clientHeight + topBorder + bottomBorder\n}\n\nexport function getImageSize(targetNode: HTMLElement, options: Options = {}) {\n const width = options.width || getNodeWidth(targetNode)\n const height = options.height || getNodeHeight(targetNode)\n\n return { width, height }\n}\n\nexport function getPixelRatio() {\n let ratio\n\n let FINAL_PROCESS\n try {\n FINAL_PROCESS = process\n } catch (e) {\n // pass\n }\n\n const val =\n FINAL_PROCESS && FINAL_PROCESS.env\n ? FINAL_PROCESS.env.devicePixelRatio\n : null\n if (val) {\n ratio = parseInt(val, 10)\n if (Number.isNaN(ratio)) {\n ratio = 1\n }\n }\n return ratio || window.devicePixelRatio || 1\n}\n\n// @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#maximum_canvas_size\nconst canvasDimensionLimit = 16384\n\nexport function checkCanvasDimensions(canvas: HTMLCanvasElement) {\n if (\n canvas.width > canvasDimensionLimit ||\n canvas.height > canvasDimensionLimit\n ) {\n if (\n canvas.width > canvasDimensionLimit &&\n canvas.height > canvasDimensionLimit\n ) {\n if (canvas.width > canvas.height) {\n canvas.height *= canvasDimensionLimit / canvas.width\n canvas.width = canvasDimensionLimit\n } else {\n canvas.width *= canvasDimensionLimit / canvas.height\n canvas.height = canvasDimensionLimit\n }\n } else if (canvas.width > canvasDimensionLimit) {\n canvas.height *= canvasDimensionLimit / canvas.width\n canvas.width = canvasDimensionLimit\n } else {\n canvas.width *= canvasDimensionLimit / canvas.height\n canvas.height = canvasDimensionLimit\n }\n }\n}\n\nexport function canvasToBlob(\n canvas: HTMLCanvasElement,\n options: Options = {},\n): Promise<Blob | null> {\n if (canvas.toBlob) {\n return new Promise((resolve) => {\n canvas.toBlob(\n resolve,\n options.type ? options.type : 'image/png',\n options.quality ? options.quality : 1,\n )\n })\n }\n\n return new Promise((resolve) => {\n const binaryString = window.atob(\n canvas\n .toDataURL(\n options.type ? options.type : undefined,\n options.quality ? options.quality : undefined,\n )\n .split(',')[1],\n )\n const len = binaryString.length\n const binaryArray = new Uint8Array(len)\n\n for (let i = 0; i < len; i += 1) {\n binaryArray[i] = binaryString.charCodeAt(i)\n }\n\n resolve(\n new Blob([binaryArray], {\n type: options.type ? options.type : 'image/png',\n }),\n )\n })\n}\n\nexport function createImage(url: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image()\n img.onload = () => {\n img.decode().then(() => {\n requestAnimationFrame(() => resolve(img))\n })\n }\n img.onerror = reject\n img.crossOrigin = 'anonymous'\n img.decoding = 'async'\n img.src = url\n })\n}\n\nexport async function svgToDataURL(svg: SVGElement): Promise<string> {\n return Promise.resolve()\n .then(() => new XMLSerializer().serializeToString(svg))\n .then(encodeURIComponent)\n .then((html) => `data:image/svg+xml;charset=utf-8,${html}`)\n}\n\nexport async function nodeToDataURL(\n node: HTMLElement,\n width: number,\n height: number,\n): Promise<string> {\n const xmlns = 'http://www.w3.org/2000/svg'\n const svg = document.createElementNS(xmlns, 'svg')\n const foreignObject = document.createElementNS(xmlns, 'foreignObject')\n\n svg.setAttribute('width', `${width}`)\n svg.setAttribute('height', `${height}`)\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`)\n\n foreignObject.setAttribute('width', '100%')\n foreignObject.setAttribute('height', '100%')\n foreignObject.setAttribute('x', '0')\n foreignObject.setAttribute('y', '0')\n foreignObject.setAttribute('externalResourcesRequired', 'true')\n\n svg.appendChild(foreignObject)\n foreignObject.appendChild(node)\n return svgToDataURL(svg)\n}\n\nexport const isInstanceOfElement = <\n T extends typeof Element | typeof HTMLElement | typeof SVGImageElement,\n>(\n node: Element | HTMLElement | SVGImageElement,\n instance: T,\n): node is T['prototype'] => {\n if (node instanceof instance) return true\n\n const nodePrototype = Object.getPrototypeOf(node)\n\n if (nodePrototype === null) return false\n\n return (\n nodePrototype.constructor.name === instance.name ||\n isInstanceOfElement(nodePrototype, instance)\n )\n}\n","import type { Options } from './types'\nimport { uuid, getStyleProperties } from './util'\n\ntype Pseudo = ':before' | ':after'\n\nfunction formatCSSText(style: CSSStyleDeclaration) {\n const content = style.getPropertyValue('content')\n return `${style.cssText} content: '${content.replace(/'|\"/g, '')}';`\n}\n\nfunction formatCSSProperties(style: CSSStyleDeclaration, options: Options) {\n return getStyleProperties(options)\n .map((name) => {\n const value = style.getPropertyValue(name)\n const priority = style.getPropertyPriority(name)\n\n return `${name}: ${value}${priority ? ' !important' : ''};`\n })\n .join(' ')\n}\n\nfunction getPseudoElementStyle(\n className: string,\n pseudo: Pseudo,\n style: CSSStyleDeclaration,\n options: Options,\n): Text {\n const selector = `.${className}:${pseudo}`\n const cssText = style.cssText\n ? formatCSSText(style)\n : formatCSSProperties(style, options)\n\n return document.createTextNode(`${selector}{${cssText}}`)\n}\n\nfunction clonePseudoElement<T extends HTMLElement>(\n nativeNode: T,\n clonedNode: T,\n pseudo: Pseudo,\n options: Options,\n) {\n const style = window.getComputedStyle(nativeNode, pseudo)\n const content = style.getPropertyValue('content')\n if (content === '' || content === 'none') {\n return\n }\n\n const className = uuid()\n try {\n clonedNode.className = `${clonedNode.className} ${className}`\n } catch (err) {\n return\n }\n\n const styleElement = document.createElement('style')\n styleElement.appendChild(\n getPseudoElementStyle(className, pseudo, style, options),\n )\n clonedNode.appendChild(styleElement)\n}\n\nexport function clonePseudoElements<T extends HTMLElement>(\n nativeNode: T,\n clonedNode: T,\n options: Options,\n) {\n clonePseudoElement(nativeNode, clonedNode, ':before', options)\n clonePseudoElement(nativeNode, clonedNode, ':after', options)\n}\n","const WOFF = 'application/font-woff'\nconst JPEG = 'image/jpeg'\nconst mimes: { [key: string]: string } = {\n woff: WOFF,\n woff2: WOFF,\n ttf: 'application/font-truetype',\n eot: 'application/vnd.ms-fontobject',\n png: 'image/png',\n jpg: JPEG,\n jpeg: JPEG,\n gif: 'image/gif',\n tiff: 'image/tiff',\n svg: 'image/svg+xml',\n webp: 'image/webp',\n}\n\nfunction getExtension(url: string): string {\n const match = /\\.([^./]*?)$/g.exec(url)\n return match ? match[1] : ''\n}\n\nexport function getMimeType(url: string): string {\n const extension = getExtension(url).toLowerCase()\n return mimes[extension] || ''\n}\n","import { Options } from './types'\n\nfunction getContentFromDataUrl(dataURL: string) {\n return dataURL.split(/,/)[1]\n}\n\nexport function isDataUrl(url: string) {\n return url.search(/^(data:)/) !== -1\n}\n\nexport function makeDataUrl(content: string, mimeType: string) {\n return `data:${mimeType};base64,${content}`\n}\n\nexport async function fetchAsDataURL<T>(\n url: string,\n init: RequestInit | undefined,\n process: (data: { result: string; res: Response }) => T,\n): Promise<T> {\n const res = await fetch(url, init)\n if (res.status === 404) {\n throw new Error(`Resource \"${res.url}\" not found`)\n }\n const blob = await res.blob()\n return new Promise<T>((resolve, reject) => {\n const reader = new FileReader()\n reader.onerror = reject\n reader.onloadend = () => {\n try {\n resolve(process({ res, result: reader.result as string }))\n } catch (error) {\n reject(error)\n }\n }\n\n reader.readAsDataURL(blob)\n })\n}\n\nconst cache: { [url: string]: string } = {}\n\nfunction getCacheKey(\n url: string,\n contentType: string | undefined,\n includeQueryParams: boolean | undefined,\n) {\n let key = url.replace(/\\?.*/, '')\n\n if (includeQueryParams) {\n key = url\n }\n\n // font resource\n if (/ttf|otf|eot|woff2?/i.test(key)) {\n key = key.replace(/.*\\//, '')\n }\n\n return contentType ? `[${contentType}]${key}` : key\n}\n\nexport async function resourceToDataURL(\n resourceUrl: string,\n contentType: string | undefined,\n options: Options,\n) {\n const cacheKey = getCacheKey(\n resourceUrl,\n contentType,\n options.includeQueryParams,\n )\n\n if (cache[cacheKey] != null) {\n return cache[cacheKey]\n }\n\n // ref: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache\n if (options.cacheBust) {\n // eslint-disable-next-line no-param-reassign\n resourceUrl += (/\\?/.test(resourceUrl) ? '&' : '?') + new Date().getTime()\n }\n\n let dataURL: string\n try {\n const content = await fetchAsDataURL(\n resourceUrl,\n options.fetchRequestInit,\n ({ res, result }) => {\n if (!contentType) {\n // eslint-disable-next-line no-param-reassign\n contentType = res.headers.get('Content-Type') || ''\n }\n return getContentFromDataUrl(result)\n },\n )\n dataURL = makeDataUrl(content, contentType!)\n } catch (error) {\n dataURL = options.imagePlaceholder || ''\n\n let msg = `Failed to fetch resource: ${resourceUrl}`\n if (error) {\n msg = typeof error === 'string' ? error : error.message\n }\n\n if (msg) {\n console.warn(msg)\n }\n }\n\n cache[cacheKey] = dataURL\n return dataURL\n}\n","import type { Options } from './types'\nimport { clonePseudoElements } from './clone-pseudos'\nimport {\n createImage,\n toArray,\n isInstanceOfElement,\n getStyleProperties,\n} from './util'\nimport { getMimeType } from './mimes'\nimport { resourceToDataURL } from './dataurl'\n\nasync function cloneCanvasElement(canvas: HTMLCanvasElement) {\n const dataURL = canvas.toDataURL()\n if (dataURL === 'data:,') {\n return canvas.cloneNode(false) as HTMLCanvasElement\n }\n return createImage(dataURL)\n}\n\nasync function cloneVideoElement(video: HTMLVideoElement, options: Options) {\n if (video.currentSrc) {\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n canvas.width = video.clientWidth\n canvas.height = video.clientHeight\n ctx?.drawImage(video, 0, 0, canvas.width, canvas.height)\n const dataURL = canvas.toDataURL()\n return createImage(dataURL)\n }\n\n const poster = video.poster\n const contentType = getMimeType(poster)\n const dataURL = await resourceToDataURL(poster, contentType, options)\n return createImage(dataURL)\n}\n\nasync function cloneIFrameElement(iframe: HTMLIFrameElement, options: Options) {\n try {\n if (iframe?.contentDocument?.body) {\n return (await cloneNode(\n iframe.contentDocument.body,\n options,\n true,\n )) as HTMLBodyElement\n }\n } catch {\n // Failed to clone iframe\n }\n\n return iframe.cloneNode(false) as HTMLIFrameElement\n}\n\nasync function cloneSingleNode<T extends HTMLElement>(\n node: T,\n options: Options,\n): Promise<HTMLElement> {\n if (isInstanceOfElement(node, HTMLCanvasElement)) {\n return cloneCanvasElement(node)\n }\n\n if (isInstanceOfElement(node, HTMLVideoElement)) {\n return cloneVideoElement(node, options)\n }\n\n if (isInstanceOfElement(node, HTMLIFrameElement)) {\n return cloneIFrameElement(node, options)\n }\n\n return node.cloneNode(isSVGElement(node)) as T\n}\n\nconst isSlotElement = (node: HTMLElement): node is HTMLSlotElement =>\n node.tagName != null && node.tagName.toUpperCase() === 'SLOT'\n\nconst isSVGElement = (node: HTMLElement): node is HTMLSlotElement =>\n node.tagName != null && node.tagName.toUpperCase() === 'SVG'\n\nasync function cloneChildren<T extends HTMLElement>(\n nativeNode: T,\n clonedNode: T,\n options: Options,\n): Promise<T> {\n if (isSVGElement(clonedNode)) {\n return clonedNode\n }\n\n let children: T[] = []\n\n if (isSlotElement(nativeNode) && nativeNode.assignedNodes) {\n children = toArray<T>(nativeNode.assignedNodes())\n } else if (\n isInstanceOfElement(nativeNode, HTMLIFrameElement) &&\n nativeNode.contentDocument?.body\n ) {\n children = toArray<T>(nativeNode.contentDocument.body.childNodes)\n } else {\n children = toArray<T>((nativeNode.shadowRoot ?? nativeNode).childNodes)\n }\n\n if (\n children.length === 0 ||\n isInstanceOfElement(nativeNode, HTMLVideoElement)\n ) {\n return clonedNode\n }\n\n await children.reduce(\n (deferred, child) =>\n deferred\n .then(() => cloneNode(child, options))\n .then((clonedChild: HTMLElement | null) => {\n if (clonedChild) {\n clonedNode.appendChild(clonedChild)\n }\n }),\n Promise.resolve(),\n )\n\n return clonedNode\n}\n\nfunction cloneCSSStyle<T extends HTMLElement>(\n nativeNode: T,\n clonedNode: T,\n options: Options,\n) {\n const targetStyle = clonedNode.style\n if (!targetStyle) {\n return\n }\n\n const sourceStyle = window.getComputedStyle(nativeNode)\n if (sourceStyle.cssText) {\n targetStyle.cssText = sourceStyle.cssText\n targetStyle.transformOrigin = sourceStyle.transformOrigin\n } else {\n getStyleProperties(options).forEach((name) => {\n let value = sourceStyle.getPropertyValue(name)\n if (name === 'font-size' && value.endsWith('px')) {\n const reducedFont =\n Math.floor(parseFloat(value.substring(0, value.length - 2))) - 0.1\n value = `${reducedFont}px`\n }\n\n if (\n isInstanceOfElement(nativeNode, HTMLIFrameElement) &&\n name === 'display' &&\n value === 'inline'\n ) {\n value = 'block'\n }\n\n if (name === 'd' && clonedNode.getAttribute('d')) {\n value = `path(${clonedNode.getAttribute('d')})`\n }\n\n targetStyle.setProperty(\n name,\n value,\n sourceStyle.getPropertyPriority(name),\n )\n })\n }\n}\n\nfunction cloneInputValue<T extends HTMLElement>(nativeNode: T, clonedNode: T) {\n if (isInstanceOfElement(nativeNode, HTMLTextAreaElement)) {\n clonedNode.innerHTML = nativeNode.value\n }\n\n if (isInstanceOfElement(nativeNode, HTMLInputElement)) {\n clonedNode.setAttribute('value', nativeNode.value)\n }\n}\n\nfunction cloneSelectValue<T extends HTMLElement>(nativeNode: T, clonedNode: T) {\n if (isInstanceOfElement(nativeNode, HTMLSelectElement)) {\n const clonedSelect = clonedNode as any as HTMLSelectElement\n const selectedOption = Array.from(clonedSelect.children).find(\n (child) => nativeNode.value === child.getAttribute('value'),\n )\n\n if (selectedOption) {\n selectedOption.setAttribute('selected', '')\n }\n }\n}\n\nfunction decorate<T extends HTMLElement>(\n nativeNode: T,\n clonedNode: T,\n options: Options,\n): T {\n if (isInstanceOfElement(clonedNode, Element)) {\n cloneCSSStyle(nativeNode, clonedNode, options)\n clonePseudoElements(nativeNode, clonedNode, options)\n cloneInputValue(nativeNode, clonedNode)\n cloneSelectValue(nativeNode, clonedNode)\n }\n\n return clonedNode\n}\n\nasync function ensureSVGSymbols<T extends HTMLElement>(\n clone: T,\n options: Options,\n) {\n const uses = clone.querySelectorAll ? clone.querySelectorAll('use') : []\n if (uses.length === 0) {\n return clone\n }\n\n const processedDefs: { [key: string]: HTMLElement } = {}\n for (let i = 0; i < uses.length; i++) {\n const use = uses[i]\n const id = use.getAttribute('xlink:href')\n if (id) {\n const exist = clone.querySelector(id)\n const definition = document.querySelector(id) as HTMLElement\n if (!exist && definition && !processedDefs[id]) {\n // eslint-disable-next-line no-await-in-loop\n processedDefs[id] = (await cloneNode(definition, options, true))!\n }\n }\n }\n\n const nodes = Object.values(processedDefs)\n if (nodes.length) {\n const ns = 'http://www.w3.org/1999/xhtml'\n const svg = document.createElementNS(ns, 'svg')\n svg.setAttribute('xmlns', ns)\n svg.style.position = 'absolute'\n svg.style.width = '0'\n svg.style.height = '0'\n svg.style.overflow = 'hidden'\n svg.style.display = 'none'\n\n const defs = document.createElementNS(ns, 'defs')\n svg.appendChild(defs)\n\n for (let i = 0; i < nodes.length; i++) {\n defs.appendChild(nodes[i])\n }\n\n clone.appendChild(svg)\n }\n\n return clone\n}\n\nexport async function cloneNode<T extends HTMLElement>(\n node: T,\n options: Options,\n isRoot?: boolean,\n): Promise<T | null> {\n if (!isRoot && options.filter && !options.filter(node)) {\n return null\n }\n\n return Promise.resolve(node)\n .then((clonedNode) => cloneSingleNode(clonedNode, options) as Promise<T>)\n .then((clonedNode) => cloneChildren(node, clonedNode, options))\n .then((clonedNode) => decorate(node, clonedNode, options))\n .then((clonedNode) => ensureSVGSymbols(clonedNode, options))\n}\n","import { Options } from './types'\nimport { resolveUrl } from './util'\nimport { getMimeType } from './mimes'\nimport { isDataUrl, makeDataUrl, resourceToDataURL } from './dataurl'\n\nconst URL_REGEX = /url\\((['\"]?)([^'\"]+?)\\1\\)/g\nconst URL_WITH_FORMAT_REGEX = /url\\([^)]+\\)\\s*format\\(([\"']?)([^\"']+)\\1\\)/g\nconst FONT_SRC_REGEX = /src:\\s*(?:url\\([^)]+\\)\\s*format\\([^)]+\\)[,;]\\s*)+/g\n\nfunction toRegex(url: string): RegExp {\n // eslint-disable-next-line no-useless-escape\n const escaped = url.replace(/([.*+?^${}()|\\[\\]\\/\\\\])/g, '\\\\$1')\n return new RegExp(`(url\\\\(['\"]?)(${escaped})(['\"]?\\\\))`, 'g')\n}\n\nexport function parseURLs(cssText: string): string[] {\n const urls: string[] = []\n\n cssText.replace(URL_REGEX, (raw, quotation, url) => {\n urls.push(url)\n return raw\n })\n\n return urls.filter((url) => !isDataUrl(url))\n}\n\nexport async function embed(\n cssText: string,\n resourceURL: string,\n baseURL: string | null,\n options: Options,\n getContentFromUrl?: (url: string) => Promise<string>,\n): Promise<string> {\n try {\n const resolvedURL = baseURL ? resolveUrl(resourceURL, baseURL) : resourceURL\n const contentType = getMimeType(resourceURL)\n let dataURL: string\n if (getContentFromUrl) {\n const content = await getContentFromUrl(resolvedURL)\n dataURL = makeDataUrl(content, contentType)\n } else {\n dataURL = await resourceToDataURL(resolvedURL, contentType, options)\n }\n return cssText.replace(toRegex(resourceURL), `$1${dataURL}$3`)\n } catch (error) {\n // pass\n }\n return cssText\n}\n\nfunction filterPreferredFontFormat(\n str: string,\n { preferredFontFormat }: Options,\n): string {\n return !preferredFontFormat\n ? str\n : str.replace(FONT_SRC_REGEX, (match: string) => {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const [src, , format] = URL_WITH_FORMAT_REGEX.exec(match) || []\n if (!format) {\n return ''\n }\n\n if (format === preferredFontFormat) {\n return `src: ${src};`\n }\n }\n })\n}\n\nexport function shouldEmbed(url: string): boolean {\n return url.search(URL_REGEX) !== -1\n}\n\nexport async function embedResources(\n cssText: string,\n baseUrl: string | null,\n options: Options,\n): Promise<string> {\n if (!shouldEmbed(cssText)) {\n return cssText\n }\n\n const filteredCSSText = filterPreferredFontFormat(cssText, options)\n const urls = parseURLs(filteredCSSText)\n return urls.reduce(\n (deferred, url) =>\n deferred.then((css) => embed(css, url, baseUrl, options)),\n Promise.resolve(filteredCSSText),\n )\n}\n","import { Options } from './types'\nimport { embedResources } from './embed-resources'\nimport { toArray, isInstanceOfElement } from './util'\nimport { isDataUrl, resourceToDataURL } from './dataurl'\nimport { getMimeType } from './mimes'\n\nasync function embedProp(\n propName: string,\n node: HTMLElement,\n options: Options,\n) {\n const propValue = node.style?.getPropertyValue(propName)\n if (propValue) {\n const cssString = await embedResources(propValue, null, options)\n node.style.setProperty(\n propName,\n cssString,\n node.style.getPropertyPriority(propName),\n )\n return true\n }\n return false\n}\n\nasync function embedBackground<T extends HTMLElement>(\n clonedNode: T,\n options: Options,\n) {\n ;(await embedProp('background', clonedNode, options)) ||\n (await embedProp('background-image', clonedNode, options))\n ;(await embedProp('mask', clonedNode, options)) ||\n (await embedProp('-webkit-mask', clonedNode, options)) ||\n (await embedProp('mask-image', clonedNode, options)) ||\n (await embedProp('-webkit-mask-image', clonedNode, options))\n}\n\nasync function embedImageNode<T extends HTMLElement | SVGImageElement>(\n clonedNode: T,\n options: Options,\n) {\n const isImageElement = isInstanceOfElement(clonedNode, HTMLImageElement)\n\n if (\n !(isImageElement && !isDataUrl(clonedNode.src)) &&\n !(\n isInstanceOfElement(clonedNode, SVGImageElement) &&\n !isDataUrl(clonedNode.href.baseVal)\n )\n ) {\n return\n }\n\n const url = isImageElement ? clonedNode.src : clonedNode.href.baseVal\n\n const dataURL = await resourceToDataURL(url, getMimeType(url), options)\n await new Promise((resolve, reject) => {\n clonedNode.onload = resolve\n clonedNode.onerror = options.onImageErrorHandler\n ? (...attributes) => {\n try {\n resolve(options.onImageErrorHandler!(...attributes))\n } catch (error) {\n reject(error)\n }\n }\n : reject\n\n const image = clonedNode as HTMLImageElement\n if (image.decode) {\n image.decode = resolve as any\n }\n\n if (image.loading === 'lazy') {\n image.loading = 'eager'\n }\n\n if (isImageElement) {\n clonedNode.srcset = ''\n clonedNode.src = dataURL\n } else {\n clonedNode.href.baseVal = dataURL\n }\n })\n}\n\nasync function embedChildren<T extends HTMLElement>(\n clonedNode: T,\n options: Options,\n) {\n const children = toArray<HTMLElement>(clonedNode.childNodes)\n const deferreds = children.map((child) => embedImages(child, options))\n await Promise.all(deferreds).then(() => clonedNode)\n}\n\nexport async function embedImages<T extends HTMLElement>(\n clonedNode: T,\n options: Options,\n) {\n if (isInstanceOfElement(clonedNode, Element)) {\n await embedBackground(clonedNode, options)\n await embedImageNode(clonedNode, options)\n await embedChildren(clonedNode, options)\n }\n}\n","import type { Options } from './types'\n\nexport function applyStyle<T extends HTMLElement>(\n node: T,\n options: Options,\n): T {\n const { style } = node\n\n if (options.backgroundColor) {\n style.backgroundColor = options.backgroundColor\n }\n\n if (options.width) {\n style.width = `${options.width}px`\n }\n\n if (options.height) {\n style.height = `${options.height}px`\n }\n\n const manual = options.style\n if (manual != null) {\n Object.keys(manual).forEach((key: any) => {\n style[key] = manual[key] as string\n })\n }\n\n return node\n}\n","import type { Options } from './types'\nimport { toArray } from './util'\nimport { fetchAsDataURL } from './dataurl'\nimport { shouldEmbed, embedResources } from './embed-resources'\n\ninterface Metadata {\n url: string\n cssText: string\n}\n\nconst cssFetchCache: { [href: string]: Metadata } = {}\n\nasync function fetchCSS(url: string) {\n let cache = cssFetchCache[url]\n if (cache != null) {\n return cache\n }\n\n const res = await fetch(url)\n const cssText = await res.text()\n cache = { url, cssText }\n\n cssFetchCache[url] = cache\n\n return cache\n}\n\nasync function embedFonts(data: Metadata, options: Options): Promise<string> {\n let cssText = data.cssText\n const regexUrl = /url\\([\"']?([^\"')]+)[\"']?\\)/g\n const fontLocs = cssText.match(/url\\([^)]+\\)/g) || []\n const loadFonts = fontLocs.map(async (loc: string) => {\n let url = loc.replace(regexUrl, '$1')\n if (!url.startsWith('https://')) {\n url = new URL(url, data.url).href\n }\n\n return fetchAsDataURL<[string, string]>(\n url,\n options.fetchRequestInit,\n ({ result }) => {\n cssText = cssText.replace(loc, `url(${result})`)\n return [loc, result]\n },\n )\n })\n\n return Promise.all(loadFonts).then(() => cssText)\n}\n\nfunction parseCSS(source: string) {\n if (source == null) {\n return []\n }\n\n const result: string[] = []\n const commentsRegex = /(\\/\\*[\\s\\S]*?\\*\\/)/gi\n // strip out comments\n let cssText = source.replace(commentsRegex, '')\n\n // eslint-disable-next-line prefer-regex-literals\n const keyframesRegex = new RegExp(\n '((@.*?keyframes [\\\\s\\\\S]*?){([\\\\s\\\\S]*?}\\\\s*?)})',\n 'gi',\n )\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const matches = keyframesRegex.exec(cssText)\n if (matches === null) {\n break\n }\n result.push(matches[0])\n }\n cssText = cssText.replace(keyframesRegex, '')\n\n const importRegex = /@import[\\s\\S]*?url\\([^)]*\\)[\\s\\S]*?;/gi\n // to match css & media queries together\n const combinedCSSRegex =\n '((\\\\s*?(?:\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\/)?\\\\s*?@media[\\\\s\\\\S]' +\n '*?){([\\\\s\\\\S]*?)}\\\\s*?})|(([\\\\s\\\\S]*?){([\\\\s\\\\S]*?)})'\n // unified regex\n const unifiedRegex = new RegExp(combinedCSSRegex, 'gi')\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let matches = importRegex.exec(cssText)\n if (matches === null) {\n matches = unifiedRegex.exec(cssText)\n if (matches === null) {\n break\n } else {\n importRegex.lastIndex = unifiedRegex.lastIndex\n }\n } else {\n unifiedRegex.lastIndex = importRegex.lastIndex\n }\n result.push(matches[0])\n }\n\n return result\n}\n\nasync function getCSSRules(\n styleSheets: CSSStyleSheet[],\n options: Options,\n): Promise<CSSStyleRule[]> {\n const ret: CSSStyleRule[] = []\n const deferreds: Promise<number | void>[] = []\n\n // First loop inlines imports\n styleSheets.forEach((sheet) => {\n if ('cssRules' in sheet) {\n try {\n toArray<CSSRule>(sheet.cssRules || []).forEach((item, index) => {\n if (item.type === CSSRule.IMPORT_RULE) {\n let importIndex = index + 1\n const url = (item as CSSImportRule).href\n const deferred = fetchCSS(url)\n .then((metadata) => embedFonts(metadata, options))\n .then((cssText) =>\n parseCSS(cssText).forEach((rule) => {\n try {\n sheet.insertRule(\n rule,\n rule.startsWith('@import')\n ? (importIndex += 1)\n : sheet.cssRules.length,\n )\n } catch (error) {\n console.error('Error inserting rule from remote css', {\n rule,\n error,\n })\n }\n }),\n )\n .catch((e) => {\n console.error('Error loading remote css', e.toString())\n })\n\n deferreds.push(deferred)\n }\n })\n } catch (e) {\n const inline =\n styleSheets.find((a) => a.href == null) || document.styleSheets[0]\n if (sheet.href != null) {\n deferreds.push(\n fetchCSS(sheet.href)\n .then((metadata) => embedFonts(metadata, options))\n .then((cssText) =>\n parseCSS(cssText).forEach((rule) => {\n inline.insertRule(rule, inline.cssRules.length)\n }),\n )\n .catch((err: unknown) => {\n console.error('Error loading remote stylesheet', err)\n }),\n )\n }\n console.error('Error inlining remote css file', e)\n }\n }\n })\n\n return Promise.all(deferreds).then(() => {\n // Second loop parses rules\n styleSheets.forEach((sheet) => {\n if ('cssRules' in sheet) {\n try {\n toArray<CSSStyleRule>(sheet.cssRules || []).forEach((item) => {\n ret.push(item)\n })\n } catch (e) {\n console.error(`Error while reading CSS rules from ${sheet.href}`, e)\n }\n }\n })\n\n return ret\n })\n}\n\nfunction getWebFontRules(cssRules: CSSStyleRule[]): CSSStyleRule[] {\n return cssRules\n .filter((rule) => rule.type === CSSRule.FONT_FACE_RULE)\n .filter((rule) => shouldEmbed(rule.style.getPropertyValue('src')))\n}\n\nasync function parseWebFontRules<T extends HTMLElement>(\n node: T,\n options: Options,\n) {\n if (node.ownerDocument == null) {\n throw new Error('Provided element is not within a Document')\n }\n\n const styleSheets = toArray<CSSStyleSheet>(node.ownerDocument.styleSheets)\n const cssRules = await getCSSRules(styleSheets, options)\n\n return getWebFontRules(cssRules)\n}\n\nfunction normalizeFontFamily(font: string) {\n return font.trim().replace(/[\"']/g, '')\n}\n\nfunction getUsedFonts(node: HTMLElement) {\n const fonts = new Set<string>()\n function traverse(node: HTMLElement) {\n const fontFamily =\n node.style.fontFamily || getComputedStyle(node).fontFamily\n fontFamily.split(',').forEach((font) => {\n fonts.add(normalizeFontFamily(font))\n })\n\n Array.from(node.children).forEach((child) => {\n if (child instanceof HTMLElement) {\n traverse(child)\n }\n })\n }\n traverse(node)\n return fonts\n}\n\nexport async function getWebFontCSS<T extends HTMLElement>(\n node: T,\n options: Options,\n): Promise<string> {\n const rules = await parseWebFontRules(node, options)\n const usedFonts = getUsedFonts(node)\n const cssTexts = await Promise.all(\n rules\n .filter((rule) =>\n usedFonts.has(normalizeFontFamily(rule.style.fontFamily)),\n )\n .map((rule) => {\n const baseUrl = rule.parentStyleSheet\n ? rule.parentStyleSheet.href\n : null\n return embedResources(rule.cssText, baseUrl, options)\n }),\n )\n\n return cssTexts.join('\\n')\n}\n\nexport async function embedWebFonts<T extends HTMLElement>(\n clonedNode: T,\n options: Options,\n) {\n const cssText =\n options.fontEmbedCSS != null\n ? options.fontEmbedCSS\n : options.skipFonts\n ? null\n : await getWebFontCSS(clonedNode, options)\n\n if (cssText) {\n const styleNode = document.createElement('style')\n const sytleContent = document.createTextNode(cssText)\n\n styleNode.appendChild(sytleContent)\n\n if (clonedNode.firstChild) {\n clonedNode.insertBefore(styleNode, clonedNode.firstChild)\n } else {\n clonedNode.appendChild(styleNode)\n }\n }\n}\n","import { Options } from './types'\nimport { cloneNode } from './clone-node'\nimport { embedImages } from './embed-images'\nimport { applyStyle } from './apply-style'\nimport { embedWebFonts, getWebFontCSS } from './embed-webfonts'\nimport {\n getImageSize,\n getPixelRatio,\n createImage,\n canvasToBlob,\n nodeToDataURL,\n checkCanvasDimensions,\n} from './util'\n\nexport async function toSvg<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<string> {\n const { width, height } = getImageSize(node, options)\n const clonedNode = (await cloneNode(node, options, true)) as HTMLElement\n await embedWebFonts(clonedNode, options)\n await embedImages(clonedNode, options)\n applyStyle(clonedNode, options)\n const datauri = await nodeToDataURL(clonedNode, width, height)\n return datauri\n}\n\nexport async function toCanvas<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<HTMLCanvasElement> {\n const { width, height } = getImageSize(node, options)\n const svg = await toSvg(node, options)\n const img = await createImage(svg)\n\n const canvas = document.createElement('canvas')\n const context = canvas.getContext('2d')!\n const ratio = options.pixelRatio || getPixelRatio()\n const canvasWidth = options.canvasWidth || width\n const canvasHeight = options.canvasHeight || height\n\n canvas.width = canvasWidth * ratio\n canvas.height = canvasHeight * ratio\n\n if (!options.skipAutoScale) {\n checkCanvasDimensions(canvas)\n }\n canvas.style.width = `${canvasWidth}`\n canvas.style.height = `${canvasHeight}`\n\n if (options.backgroundColor) {\n context.fillStyle = options.backgroundColor\n context.fillRect(0, 0, canvas.width, canvas.height)\n }\n\n context.drawImage(img, 0, 0, canvas.width, canvas.height)\n\n return canvas\n}\n\nexport async function toPixelData<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<Uint8ClampedArray> {\n const { width, height } = getImageSize(node, options)\n const canvas = await toCanvas(node, options)\n const ctx = canvas.getContext('2d')!\n return ctx.getImageData(0, 0, width, height).data\n}\n\nexport async function toPng<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<string> {\n const canvas = await toCanvas(node, options)\n return canvas.toDataURL()\n}\n\nexport async function toJpeg<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<string> {\n const canvas = await toCanvas(node, options)\n return canvas.toDataURL('image/jpeg', options.quality || 1)\n}\n\nexport async function toBlob<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<Blob | null> {\n const canvas = await toCanvas(node, options)\n const blob = await canvasToBlob(canvas)\n return blob\n}\n\nexport async function getFontEmbedCSS<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<string> {\n return getWebFontCSS(node, options)\n}\n","/**\n * Screenshot capture — uses native Screen Capture API for pixel-perfect\n * screenshots, with html-to-image as a fallback for unsupported browsers.\n */\n\nimport { toPng } from 'html-to-image';\n\n/** Show a camera shutter flash animation */\nfunction showFlashAnimation(): void {\n const flash = document.createElement('div');\n flash.style.cssText = `\n position: fixed; inset: 0; z-index: 2147483647;\n background: white; opacity: 0;\n pointer-events: none;\n animation: bs-flash 0.4s ease-out forwards;\n `;\n\n if (!document.getElementById('bs-flash-style')) {\n const style = document.createElement('style');\n style.id = 'bs-flash-style';\n style.textContent = `\n @keyframes bs-flash {\n 0% { opacity: 0; }\n 15% { opacity: 0.7; }\n 100% { opacity: 0; }\n }\n `;\n document.head.appendChild(style);\n }\n\n document.body.appendChild(flash);\n flash.addEventListener('animationend', () => flash.remove());\n}\n\n/** Check if an element is BugStash UI (should be excluded from screenshots). */\nconst isBugStashUI = (el: Element): boolean => {\n const tag = el.tagName.toLowerCase();\n return tag === 'bugstash-root' ||\n tag === 'bugstash-overlay' ||\n (el as HTMLElement).classList?.contains('bs-fab') ||\n (el as HTMLElement).classList?.contains('bs-toolbar') ||\n (el as HTMLElement).classList?.contains('bs-modal') ||\n (el as HTMLElement).classList?.contains('bs-backdrop') ||\n el.id === 'bs-flash-style' ||\n el.id === 'bugstash-live-pins' ||\n el.id === 'bugstash-pin-overlay';\n};\n\nexport async function captureScreenshot(flash = false): Promise<string | null> {\n if (flash) showFlashAnimation();\n\n // Primary: native Screen Capture API — pixel-perfect, real screenshot\n try {\n const native = await captureWithDisplayMedia();\n if (native) return native;\n } catch {\n // User denied or API not available — fall through to html-to-image\n }\n\n // Fallback: html-to-image (DOM re-render, zero dependencies, faster than html2canvas)\n try {\n return await captureWithHtmlToImage();\n } catch {\n try {\n return await captureWithHtmlToImage(true);\n } catch {\n return null;\n }\n }\n}\n\n/**\n * Capture using the native Screen Capture API (getDisplayMedia).\n * This captures actual screen pixels — fonts, shadows, blur, video, canvas\n * all render perfectly. Requires a one-time user gesture (browser tab picker).\n */\nasync function captureWithDisplayMedia(): Promise<string | null> {\n if (!navigator.mediaDevices?.getDisplayMedia) return null;\n\n const stream = await navigator.mediaDevices.getDisplayMedia({\n video: {\n displaySurface: 'browser',\n width: { ideal: window.screen.width * (window.devicePixelRatio || 1) },\n height: { ideal: window.screen.height * (window.devicePixelRatio || 1) },\n } as MediaTrackConstraints,\n audio: false,\n // @ts-expect-error -- Chrome 109+ hints to pre-select current tab\n preferCurrentTab: true,\n selfBrowserSurface: 'include',\n monitorTypeSurfaces: 'exclude',\n });\n\n try {\n const track = stream.getVideoTracks()[0];\n if (!track) return null;\n\n // Create a video element to grab a single frame\n const video = document.createElement('video');\n video.srcObject = stream;\n video.muted = true;\n video.playsInline = true;\n\n await video.play();\n\n // Wait for the video to have actual frame data\n await new Promise<void>((resolve) => {\n if (video.readyState >= 2) { resolve(); return; }\n video.onloadeddata = () => resolve();\n });\n\n // Extra frame to ensure the capture is ready\n await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));\n\n const canvas = document.createElement('canvas');\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n const ctx = canvas.getContext('2d');\n if (!ctx) return null;\n\n ctx.drawImage(video, 0, 0);\n\n return canvas.toDataURL('image/png');\n } finally {\n // Always stop the stream — removes the browser \"sharing\" indicator\n stream.getTracks().forEach((t) => t.stop());\n }\n}\n\n/** html-to-image fallback — re-renders the DOM as a PNG. Faster and lighter than html2canvas. */\nasync function captureWithHtmlToImage(skipCrossOriginImages = false): Promise<string | null> {\n const bodyBg = window.getComputedStyle(document.body).backgroundColor;\n const htmlBg = window.getComputedStyle(document.documentElement).backgroundColor;\n const isTransparent = (c: string) => !c || c === 'transparent' || c === 'rgba(0, 0, 0, 0)';\n const bgColor = !isTransparent(bodyBg) ? bodyBg : !isTransparent(htmlBg) ? htmlBg : '#ffffff';\n\n const dataUrl = await toPng(document.body, {\n pixelRatio: Math.min(window.devicePixelRatio || 1, 2),\n backgroundColor: bgColor,\n width: window.innerWidth,\n height: window.innerHeight,\n // html-to-image filter: return true to INCLUDE, false to EXCLUDE (inverted from html2canvas)\n filter: (node: HTMLElement) => {\n if (skipCrossOriginImages && node.tagName === 'IMG') {\n const src = (node as HTMLImageElement).src || '';\n if (src && !src.startsWith(window.location.origin) && !src.startsWith('data:')) return false;\n }\n return !isBugStashUI(node);\n },\n // Placeholder for images that fail to load (avoids broken captures)\n imagePlaceholder: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',\n });\n\n return dataUrl;\n}\n","import type { BugReport, APIResponse, AuthUser, AuthTokens, LivePin, PinComment, Member } from '@bugstash/shared';\n\n\n// Primary cloud backend. Falls back to Azure if custom domain is unreachable.\n// Self-hosted users can override via BugStash.init({ endpoint: '...' }).\nconst PRIMARY_ENDPOINT = 'https://bugstash-backend.vercel.app';\nconst FALLBACK_ENDPOINT = 'https://bugstash-backend.vercel.app';\n\nlet endpoint = PRIMARY_ENDPOINT;\nlet _usingFallback = false;\n\nexport function setEndpoint(url: string) {\n endpoint = url.replace(/\\/$/, '');\n _usingFallback = false;\n}\n\nexport function getEndpoint() {\n return endpoint;\n}\n\n/**\n * Tries the current endpoint. On network failure (ERR_CONNECTION_REFUSED, etc.),\n * transparently falls back to the Azure backend so SDK login/reports always work\n * — even if a developer passes a bad endpoint or localhost isn't running.\n */\nasync function fetchWithFallback(url: string, init?: RequestInit): Promise<Response> {\n try {\n const res = await fetch(url, init);\n return res;\n } catch (err) {\n // Already on the final fallback — nothing left to try\n if (_usingFallback) throw err;\n\n // Fall back to Azure regardless of what the current endpoint is\n _usingFallback = true;\n const previousEndpoint = endpoint;\n endpoint = FALLBACK_ENDPOINT;\n const fallbackUrl = url.replace(previousEndpoint, FALLBACK_ENDPOINT);\n return fetch(fallbackUrl, init);\n }\n}\n\n// ─── Token Management ────────────────────────────────────\n\nconst STORAGE_KEY = 'bugstash_auth';\n\ninterface StoredAuth {\n user: AuthUser;\n tokens: AuthTokens;\n}\n\nfunction getStoredAuth(): StoredAuth | null {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return null;\n const auth = JSON.parse(raw) as StoredAuth;\n // Check if access token expired\n if (auth.tokens.expiresAt < Date.now()) {\n // Try to refresh\n return auth; // Will be refreshed on next request\n }\n return auth;\n } catch {\n return null;\n }\n}\n\nfunction setStoredAuth(auth: StoredAuth) {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(auth));\n}\n\nexport function clearStoredAuth() {\n localStorage.removeItem(STORAGE_KEY);\n}\n\nexport function getCurrentUser(): AuthUser | null {\n return getStoredAuth()?.user || null;\n}\n\nexport function getAccessToken(): string | null {\n return getStoredAuth()?.tokens.accessToken || null;\n}\n\nasync function authHeaders(): Promise<Record<string, string>> {\n const auth = getStoredAuth();\n if (!auth) return { 'Content-Type': 'application/json' };\n\n // Refresh if expired\n if (auth.tokens.expiresAt < Date.now() + 60000) {\n try {\n const res = await fetchWithFallback(`${endpoint}/api/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: auth.tokens.refreshToken }),\n });\n if (res.ok) {\n const data = await res.json();\n if (data.success) {\n auth.tokens = data.data;\n setStoredAuth(auth);\n }\n }\n } catch { /* Use existing token */ }\n }\n\n return {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${auth.tokens.accessToken}`,\n };\n}\n\n// ─── Auth API ────────────────────────────────────────────\n\nexport async function login(email: string, password: string, projectId: string): Promise<APIResponse<{ user: AuthUser; tokens: AuthTokens }>> {\n try {\n const res = await fetchWithFallback(`${endpoint}/api/auth/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password, projectId }),\n });\n const data = await res.json();\n if (data.success) {\n setStoredAuth({ user: data.data.user, tokens: data.data.tokens });\n }\n return data;\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\nexport async function logout() {\n clearStoredAuth();\n}\n\nexport async function fetchMe(): Promise<APIResponse<AuthUser>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/auth/me`, { headers });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\n// ─── Reports API ─────────────────────────────────────────\n\nexport async function submitReport(report: BugReport): Promise<APIResponse<{ id: string }>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/reports`, {\n method: 'POST',\n headers,\n body: JSON.stringify(report),\n });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error - could not reach BugStash' };\n }\n}\n\n// ─── Pins API ────────────────────────────────────────────\n\nexport async function fetchPagePins(projectId: string, pathname: string): Promise<APIResponse<LivePin[]>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins/by-page?projectId=${projectId}&pathname=${encodeURIComponent(pathname)}`, { headers });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\nexport async function createPin(pin: Partial<LivePin>): Promise<APIResponse<LivePin>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins`, {\n method: 'POST',\n headers,\n body: JSON.stringify(pin),\n });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\nexport async function updatePin(pinId: string, updates: Partial<LivePin>): Promise<APIResponse<LivePin>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins/${pinId}`, {\n method: 'PUT',\n headers,\n body: JSON.stringify(updates),\n });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\nexport async function deletePin(pinId: string): Promise<APIResponse<void>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins/${pinId}`, {\n method: 'DELETE',\n headers,\n });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\n// ─── Comments API ────────────────────────────────────────\n\nexport async function fetchComments(pinId: string): Promise<APIResponse<PinComment[]>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins/${pinId}/comments`, { headers });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\nexport async function createComment(pinId: string, body: string, mentions: string[] = []): Promise<APIResponse<PinComment>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins/${pinId}/comments`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ body, mentions }),\n });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\n// ─── Members API ─────────────────────────────────────────\n\nexport async function fetchProjectMembers(projectId: string): Promise<APIResponse<Member[]>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/members/for-project/${projectId}`, { headers });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\n// ─── Domain Verification ─────────────────────────────────\n\nlet _domainVerifyPromise: Promise<boolean> | null = null;\n\n/**\n * Check if the current domain is allowed for the given project.\n * Result is cached (promise-based) for the lifetime of the page.\n */\nexport function verifyDomain(projectId: string): Promise<boolean> {\n if (_domainVerifyPromise) return _domainVerifyPromise;\n\n _domainVerifyPromise = (async () => {\n try {\n const res = await fetch(\n `${endpoint}/api/orgs/projects/${encodeURIComponent(projectId)}/verify-domain`,\n { headers: { 'Content-Type': 'application/json' } },\n );\n if (!res.ok) return false;\n const data = await res.json();\n return data.allowed === true;\n } catch {\n // On network error, deny by default (fail closed)\n return false;\n }\n })();\n\n return _domainVerifyPromise;\n}\n\n// ─── Offline Queue ───────────────────────────────────────\n\nconst QUEUE_KEY = 'bugstash_offline_queue';\n\ninterface QueuedAction {\n id: string;\n type: 'create_pin' | 'create_comment' | 'update_pin' | 'submit_report';\n data: any;\n timestamp: number;\n}\n\nexport function queueOfflineAction(action: Omit<QueuedAction, 'id' | 'timestamp'>) {\n const queue = getOfflineQueue();\n queue.push({\n ...action,\n id: Math.random().toString(36).slice(2),\n timestamp: Date.now(),\n });\n localStorage.setItem(QUEUE_KEY, JSON.stringify(queue));\n}\n\nexport function getOfflineQueue(): QueuedAction[] {\n try {\n return JSON.parse(localStorage.getItem(QUEUE_KEY) || '[]');\n } catch {\n return [];\n }\n}\n\nexport async function flushOfflineQueue(): Promise<number> {\n const queue = getOfflineQueue();\n if (queue.length === 0) return 0;\n\n let flushed = 0;\n const remaining: QueuedAction[] = [];\n\n for (const action of queue) {\n try {\n let result: APIResponse<any>;\n switch (action.type) {\n case 'create_pin':\n result = await createPin(action.data);\n break;\n case 'create_comment':\n result = await createComment(action.data.pinId, action.data.body, action.data.mentions);\n break;\n case 'update_pin':\n result = await updatePin(action.data.pinId, action.data.updates);\n break;\n case 'submit_report':\n result = await submitReport(action.data);\n break;\n default:\n result = { success: false, error: 'Unknown action' };\n }\n if (result.success) {\n flushed++;\n } else {\n remaining.push(action);\n }\n } catch {\n remaining.push(action);\n }\n }\n\n localStorage.setItem(QUEUE_KEY, JSON.stringify(remaining));\n return flushed;\n}\n\n// Auto-flush when back online\nif (typeof window !== 'undefined') {\n window.addEventListener('online', () => {\n flushOfflineQueue().catch(() => {});\n });\n}\n","export interface BsTheme {\n id: string;\n name: string;\n preview: [string, string]; // [bg, accent] for switcher preview\n vars: Record<string, string>;\n}\n\nconst THEMES: BsTheme[] = [\n // ─── Slate (default — blue-gray) ──────────────────\n {\n id: 'slate',\n name: 'Slate',\n preview: ['#0f1117', '#6E9ED0'],\n vars: {\n '--bs-bg': '#0f1117',\n '--bs-bg2': '#1a1d27',\n '--bs-bg3': '#2a2d37',\n '--bs-text': '#e8eaed',\n '--bs-muted': '#9ca3af',\n '--bs-border': '#2a2d37',\n '--bs-accent': '#6E9ED0',\n '--bs-accent2': '#C3CAD6',\n '--bs-fab1': '#6E9ED0',\n '--bs-fab2': '#4a7ba8',\n '--bs-radius': '12px',\n '--bs-radius-sm': '8px',\n '--bs-red': '#ef4444',\n '--bs-green': '#22c55e',\n '--bs-orange': '#f97316',\n '--bs-yellow': '#eab308',\n },\n },\n // ─── Pure Black ────────────────────────────────────\n {\n id: 'black',\n name: 'Dark',\n preview: ['#0a0a0a', '#ffffff'],\n vars: {\n '--bs-bg': '#0a0a0a',\n '--bs-bg2': '#141414',\n '--bs-bg3': '#1e1e1e',\n '--bs-text': '#f5f5f5',\n '--bs-muted': '#737373',\n '--bs-border': '#262626',\n '--bs-accent': '#f5f5f5',\n '--bs-accent2': '#d4d4d4',\n '--bs-fab1': '#262626',\n '--bs-fab2': '#171717',\n '--bs-radius': '12px',\n '--bs-radius-sm': '8px',\n '--bs-red': '#ef4444',\n '--bs-green': '#22c55e',\n '--bs-orange': '#f97316',\n '--bs-yellow': '#eab308',\n },\n },\n // ─── Pure White ────────────────────────────────────\n {\n id: 'white',\n name: 'Light',\n preview: ['#ffffff', '#0a0a0a'],\n vars: {\n '--bs-bg': '#ffffff',\n '--bs-bg2': '#f5f5f5',\n '--bs-bg3': '#e5e5e5',\n '--bs-text': '#0a0a0a',\n '--bs-muted': '#737373',\n '--bs-border': '#e5e5e5',\n '--bs-accent': '#0a0a0a',\n '--bs-accent2': '#404040',\n '--bs-fab1': '#0a0a0a',\n '--bs-fab2': '#262626',\n '--bs-radius': '12px',\n '--bs-radius-sm': '8px',\n '--bs-red': '#dc2626',\n '--bs-green': '#16a34a',\n '--bs-orange': '#ea580c',\n '--bs-yellow': '#ca8a04',\n },\n },\n];\n\nexport function getThemes(): BsTheme[] {\n return THEMES;\n}\n\nexport function getThemeById(id: string): BsTheme | undefined {\n return THEMES.find((t) => t.id === id);\n}\n\nexport function getDefaultTheme(): BsTheme {\n return THEMES[0];\n}\n","export interface BsLayout {\n id: string;\n name: string;\n description: string;\n tabPosition: 'top' | 'left' | 'bottom';\n}\n\nconst LAYOUTS: BsLayout[] = [\n { id: 'classic', name: 'Center', description: 'Centered modal', tabPosition: 'top' },\n { id: 'drawer-right', name: 'Right Drawer', description: 'Slides from right', tabPosition: 'top' },\n { id: 'bottom-sheet', name: 'Bottom Sheet', description: 'Slides from bottom', tabPosition: 'top' },\n { id: 'sidebar-tabs', name: 'Sidebar', description: 'Side navigation', tabPosition: 'left' },\n];\n\nexport function getLayouts(): BsLayout[] {\n return LAYOUTS;\n}\n\nexport function getLayoutById(id: string): BsLayout | undefined {\n return LAYOUTS.find((l) => l.id === id);\n}\n\nexport function getDefaultLayout(): BsLayout {\n return LAYOUTS[0];\n}\n\n// ─── Layout CSS ──────────────────────────────────────────\n\nexport const LAYOUT_CSS = `\n/* ── 1. Classic (default — no overrides) ── */\n\n/* ── 2. Drawer Right ── */\n.bs-ly-drawer-right.bs-modal {\n top: 0; left: auto; right: 0; bottom: 0;\n width: 420px; max-width: 100vw; max-height: 100vh;\n height: 100vh;\n border-radius: 0;\n transform: translateX(100%);\n transition: transform 0.4s cubic-bezier(0.22,1,0.36,1), opacity 0.3s ease;\n}\n.bs-ly-drawer-right.bs-modal.bs-in {\n transform: translateX(0);\n opacity: 1;\n}\n\n/* ── 3. Bottom Sheet ── */\n.bs-ly-bottom-sheet.bs-modal {\n top: auto; left: 50%; right: auto; bottom: 0;\n width: 600px; max-width: 100vw;\n max-height: 80vh;\n border-radius: var(--bs-radius) var(--bs-radius) 0 0;\n transform: translate(-50%, 100%);\n transition: transform 0.45s cubic-bezier(0.22,1,0.36,1), opacity 0.3s ease;\n}\n.bs-ly-bottom-sheet.bs-modal.bs-in {\n transform: translate(-50%, 0);\n opacity: 1;\n}\n\n/* ── 4. Sidebar Tabs ── */\n.bs-ly-sidebar-tabs.bs-modal {\n width: 620px;\n}\n.bs-ly-sidebar-tabs .bs-body-wrap {\n display: flex;\n flex: 1;\n overflow: hidden;\n}\n.bs-ly-sidebar-tabs .bs-tabs {\n flex-direction: column;\n padding: 12px 0 12px 12px;\n gap: 4px;\n min-width: 140px;\n border-right: 1px solid var(--bs-border);\n overflow-y: auto;\n}\n.bs-ly-sidebar-tabs .bs-tab {\n border-radius: var(--bs-radius-sm);\n padding: 10px 12px;\n width: 100%;\n}\n.bs-ly-sidebar-tabs .bs-tab.bs-active::after {\n top: 8px; bottom: 8px; left: 0; right: auto;\n width: 2px; height: auto;\n border-radius: 0 2px 2px 0;\n}\n.bs-ly-sidebar-tabs .bs-tab-divider { display: none; }\n.bs-ly-sidebar-tabs .bs-scroll { flex: 1; }\n`;\n\nexport default LAYOUTS;\n","import { getEndpoint, getAccessToken } from './api';\nimport type { WSEvent } from '@bugstash/shared';\n\ntype EventHandler = (event: WSEvent) => void;\n\nlet pollTimer: ReturnType<typeof setInterval> | null = null;\nlet lastPollTime = 0;\nconst POLL_INTERVAL = 5000; // 5 seconds\nconst handlers = new Map<string, Set<EventHandler>>();\nlet currentProjectId: string | null = null;\nlet knownPinIds = new Set<string>();\n\nexport function connectRealtime(projectId: string) {\n currentProjectId = projectId;\n lastPollTime = Date.now();\n startPolling();\n}\n\nfunction startPolling() {\n if (pollTimer) return;\n pollTimer = setInterval(poll, POLL_INTERVAL);\n}\n\nasync function poll() {\n if (!currentProjectId) return;\n const token = getAccessToken();\n if (!token) return;\n\n try {\n const endpoint = getEndpoint();\n const pathname = window.location.pathname;\n const res = await fetch(\n `${endpoint}/api/pins/poll?projectId=${currentProjectId}&pathname=${encodeURIComponent(pathname)}&since=${lastPollTime}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n\n if (!res.ok) return;\n const data = await res.json();\n if (!data.success) return;\n\n const pins = Array.isArray(data.data) ? data.data : (data.data?.pins || []);\n lastPollTime = data.serverTime || data.data?.serverTime || Date.now();\n\n for (const pin of pins) {\n if (knownPinIds.has(pin.id)) {\n emit('pin:updated', {\n type: 'pin:updated',\n projectId: currentProjectId,\n data: pin,\n userId: '',\n timestamp: Date.now(),\n });\n } else {\n knownPinIds.add(pin.id);\n emit('pin:created', {\n type: 'pin:created',\n projectId: currentProjectId,\n data: pin,\n userId: '',\n timestamp: Date.now(),\n });\n }\n }\n } catch {\n // Silently fail — will retry next interval\n }\n}\n\nexport function disconnectRealtime() {\n if (pollTimer) {\n clearInterval(pollTimer);\n pollTimer = null;\n }\n currentProjectId = null;\n knownPinIds.clear();\n lastPollTime = 0;\n}\n\nexport function onRealtimeEvent(type: string, handler: EventHandler) {\n if (!handlers.has(type)) handlers.set(type, new Set());\n handlers.get(type)!.add(handler);\n return () => {\n handlers.get(type)?.delete(handler);\n };\n}\n\nfunction emit(type: string, event: WSEvent) {\n handlers.get(type)?.forEach((h) => h(event));\n handlers.get('*')?.forEach((h) => h(event));\n}\n\n/** Register known pin IDs so polling can detect new vs updated */\nexport function registerKnownPins(pinIds: string[]) {\n knownPinIds = new Set(pinIds);\n}\n\n// Cursor and navigation are no-ops in polling mode\nexport function sendCursorPosition(_x: number, _y: number, _pageUrl: string) {}\nexport function sendPageNavigate(_pageUrl: string) {}\n\nexport function isConnected(): boolean {\n return pollTimer !== null;\n}\n","import type { LivePin, Member } from '@bugstash/shared';\nimport { fetchPagePins, createPin, updatePin, deletePin, fetchComments, createComment, fetchProjectMembers, getCurrentUser, queueOfflineAction } from './api';\nimport { onRealtimeEvent, sendPageNavigate, registerKnownPins } from './realtime';\nimport { getLogs } from './logger';\nimport { getErrors } from './errors';\nimport { getFailedNetworkCaptures } from './network';\n\nlet projectId: string;\nlet container: HTMLDivElement | null = null;\nlet clickOverlay: HTMLElement | null = null;\nlet pins: LivePin[] = [];\nlet members: Member[] = [];\nlet pinMode = false;\nlet activePopup: HTMLDivElement | null = null;\nlet currentPathname = '';\nlet repositionRAF: number | null = null;\nlet mutationObserver: MutationObserver | null = null;\nlet nestedScrollCleanups: Array<() => void> = [];\nlet resizeObserver: ResizeObserver | null = null;\nlet shadow: ShadowRoot | null = null;\n\n// ─── Containing Block Compensation ───────────────────────\n//\n// CSS spec: if ANY ancestor has `transform`, `perspective`, `filter`,\n// `contain: paint/layout/strict/content`, or `will-change: transform`,\n// it becomes the containing block for `position: fixed` descendants.\n// This is extremely common in large SPAs (React transitions, Framer Motion,\n// animation libraries, CSS frameworks). We probe the actual offset and\n// compensate all fixed-position coordinates.\n\nlet _fixedOffset = { x: 0, y: 0 };\n\n/**\n * Probe where `position:fixed; top:0; left:0` actually renders inside our\n * shadow root. If (0,0) — no ancestor transforms. Otherwise, the delta\n * tells us exactly how much to compensate.\n */\nfunction probeFixedOffset() {\n if (!shadow) return;\n const probe = document.createElement('div');\n probe.style.cssText =\n 'position:fixed!important;top:0!important;left:0!important;' +\n 'width:1px!important;height:1px!important;pointer-events:none!important;' +\n 'visibility:hidden!important;z-index:-1!important;opacity:0!important;';\n shadow.appendChild(probe);\n try {\n const rect = probe.getBoundingClientRect();\n _fixedOffset = { x: -rect.left, y: -rect.top };\n } finally {\n probe.remove();\n }\n}\n\n/**\n * Convert viewport coordinates to CSS values that work correctly inside our\n * shadow root, compensating for any ancestor-created containing block offset.\n */\nfunction toFixedCSS(pos: { left: string; top: string; hidden: boolean }): { left: string; top: string; hidden: boolean } {\n if (_fixedOffset.x === 0 && _fixedOffset.y === 0) return pos;\n return {\n left: `${parseFloat(pos.left) + _fixedOffset.x}px`,\n top: `${parseFloat(pos.top) + _fixedOffset.y}px`,\n hidden: pos.hidden,\n };\n}\n\n/** Convert raw viewport x/y to fixed-position CSS values with offset. */\nfunction viewportToFixed(vx: number, vy: number): { left: string; top: string } {\n return {\n left: `${vx + _fixedOffset.x}px`,\n top: `${vy + _fixedOffset.y}px`,\n };\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n open: '#f97316',\n in_progress: '#3b82f6',\n resolved: '#22c55e',\n closed: '#6b7280',\n};\n\nconst PRIORITY_COLORS: Record<string, string> = {\n critical: '#ef4444',\n high: '#f97316',\n medium: '#eab308',\n low: '#6b7280',\n};\n\n\nexport function initLivePins(projId: string, sr: ShadowRoot) {\n projectId = projId;\n shadow = sr;\n currentPathname = window.location.pathname;\n\n createOverlay();\n probeFixedOffset();\n loadPins();\n loadMembers();\n setupRealtimeListeners();\n watchNavigation();\n setupRepositionListeners();\n}\n\nexport function destroyLivePins() {\n teardownRepositionListeners();\n container?.remove();\n container = null;\n clickOverlay?.remove();\n clickOverlay = null;\n shadow = null;\n pins = [];\n}\n\nexport function togglePinMode(enabled?: boolean) {\n pinMode = enabled !== undefined ? enabled : !pinMode;\n if (clickOverlay) {\n clickOverlay.style.setProperty('display', pinMode ? 'block' : 'none', 'important');\n }\n return pinMode;\n}\n\nexport function isPinModeActive() {\n return pinMode;\n}\n\n// ─── Element Position Resolution ──────────────────────────\n\n/**\n * Resolve a pin's **viewport-relative** position for fixed-position rendering.\n *\n * All return values are viewport coordinates (CSS `left`/`top` for `position: fixed`).\n * This means pins reposition on every scroll/resize via `repositionPins()`.\n *\n * Strategies (priority order):\n *\n * 1. **Element-relative** (new): xPercent/yPercent in [0, 1] range.\n * Position = element.getBoundingClientRect() + offset * size.\n * getBoundingClientRect already returns viewport coords — no scroll math needed.\n *\n * 2. **Legacy page-percentage** (backward compat): xPercent/yPercent > 1.\n * Convert page percentages to page pixels, then to viewport by subtracting scroll.\n *\n * 3. **Absolute page pixels**: pageX/pageY converted to viewport by subtracting scroll.\n */\nfunction resolvePosition(pin: LivePin): { left: string; top: string; hidden: boolean } {\n try {\n const pageW = document.documentElement.scrollWidth || document.body.scrollWidth || 1;\n const pageH = document.documentElement.scrollHeight || document.body.scrollHeight || 1;\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n\n const el = findElement(pin.elementSelector, pin.elementXPath);\n const isElementRelative = hasPercent(pin) && pin.xPercent >= 0 && pin.xPercent <= 1 && pin.yPercent >= 0 && pin.yPercent <= 1;\n\n // Check if anchor element is clipped by a scroll container\n const hidden = el ? isElementClipped(el) : false;\n\n // Strategy 1: Element-relative offsets (0-1 range)\n // getBoundingClientRect() returns viewport coordinates — perfect for position:fixed\n if (isElementRelative && el) {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n const vx = rect.left + pin.xPercent * rect.width;\n const vy = rect.top + pin.yPercent * rect.height;\n return { left: `${vx}px`, top: `${vy}px`, hidden };\n }\n }\n\n // Element-relative but element not found — fall back to stored pageX/pageY → viewport\n if (isElementRelative) {\n if (pin.pageX > 0 || pin.pageY > 0) {\n return { left: `${pin.pageX - scrollX}px`, top: `${pin.pageY - scrollY}px`, hidden: false };\n }\n return { left: `${pin.xPercent * pageW - scrollX}px`, top: `${pin.yPercent * pageH - scrollY}px`, hidden: false };\n }\n\n // Strategy 2: Legacy page-percentage pins (xPercent/yPercent > 1)\n if (el) {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n if (pin.pageX > 0 || pin.pageY > 0) {\n const storedAbsX = hasPercent(pin) ? (pin.xPercent / 100) * pageW : pin.pageX;\n const storedAbsY = hasPercent(pin) ? (pin.yPercent / 100) * pageH : pin.pageY;\n\n const elCenterVX = rect.left + rect.width / 2;\n const elCenterVY = rect.top + rect.height / 2;\n const storedVX = storedAbsX - scrollX;\n const storedVY = storedAbsY - scrollY;\n\n const drift = Math.abs(storedVX - elCenterVX) + Math.abs(storedVY - elCenterVY);\n\n if (drift > 100) {\n // Element moved significantly — snap to element center\n return { left: `${elCenterVX}px`, top: `${elCenterVY}px`, hidden };\n }\n\n return { left: `${storedVX}px`, top: `${storedVY}px`, hidden };\n }\n\n // No stored page coordinates — anchor to element center\n return {\n left: `${rect.left + rect.width / 2}px`,\n top: `${rect.top + rect.height / 2}px`,\n hidden,\n };\n }\n }\n\n // Strategy 2b: No element — convert legacy percentages to viewport\n if (hasPercent(pin)) {\n return {\n left: `${(pin.xPercent / 100) * pageW - scrollX}px`,\n top: `${(pin.yPercent / 100) * pageH - scrollY}px`,\n hidden: false,\n };\n }\n\n // Strategy 3: Raw page coordinates → viewport\n return { left: `${pin.pageX - scrollX}px`, top: `${pin.pageY - scrollY}px`, hidden: false };\n } catch {\n // Corrupt pin data — fall back to page coords or hide off-screen\n const fallbackX = (pin.pageX || 0) - (window.scrollX || 0);\n const fallbackY = (pin.pageY || 0) - (window.scrollY || 0);\n return { left: `${fallbackX}px`, top: `${fallbackY}px`, hidden: false };\n }\n}\n\n/** Check if pin has valid percentage coordinates. */\nfunction hasPercent(pin: LivePin): boolean {\n return pin.xPercent != null && pin.yPercent != null &&\n (pin.xPercent !== 0 || pin.yPercent !== 0 || (pin.pageX === 0 && pin.pageY === 0));\n}\n\n/** Try to find an element by CSS selector chain, then by XPath. */\nfunction findElement(selector: string, xpath: string): Element | null {\n // Parse: JSON array = selector chain; plain string = single selector (backward compat)\n let selectors: string[];\n if (selector && selector.startsWith('[\"') && selector.endsWith('\"]')) {\n try {\n const parsed = JSON.parse(selector);\n selectors = Array.isArray(parsed) ? parsed.filter((s): s is string => typeof s === 'string') : [selector];\n } catch { selectors = [selector]; }\n } else {\n selectors = selector ? [selector] : [];\n }\n\n for (const sel of selectors) {\n if (sel && sel !== 'body') {\n try {\n const el = document.querySelector(sel);\n if (el) return el;\n } catch { /* invalid selector */ }\n }\n }\n\n if (xpath) {\n try {\n const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);\n if (result.singleNodeValue instanceof Element) return result.singleNodeValue;\n } catch { /* invalid xpath */ }\n }\n return null;\n}\n\n/**\n * Check if an element is clipped (scrolled out of view) by any overflow ancestor.\n * Returns true if the element is not visible within its scroll containers or\n * is completely outside the viewport.\n */\nfunction isElementClipped(el: Element): boolean {\n const rect = el.getBoundingClientRect();\n\n // Off-screen entirely (viewport check)\n if (rect.bottom <= 0 || rect.top >= window.innerHeight ||\n rect.right <= 0 || rect.left >= window.innerWidth) {\n return true;\n }\n\n // Walk up and check against each overflow container\n let parent = el.parentElement;\n while (parent && parent !== document.documentElement) {\n const style = window.getComputedStyle(parent);\n const oy = style.overflowY;\n const ox = style.overflowX;\n if (oy === 'hidden' || oy === 'scroll' || oy === 'auto' ||\n ox === 'hidden' || ox === 'scroll' || ox === 'auto') {\n const pr = parent.getBoundingClientRect();\n if (rect.bottom <= pr.top || rect.top >= pr.bottom ||\n rect.right <= pr.left || rect.left >= pr.right) {\n return true;\n }\n }\n parent = parent.parentElement;\n }\n return false;\n}\n\n// ─── Scroll / Resize / Mutation Listeners ────────────────\n\nfunction setupRepositionListeners() {\n window.addEventListener('scroll', scheduleReposition, { passive: true });\n window.addEventListener('resize', scheduleReposition, { passive: true });\n\n // ESC key to exit pin mode\n window.addEventListener('keydown', handleKeyDown);\n\n // Watch for DOM changes that might shift element positions\n // Filter out mutations within our own container to prevent infinite reposition loops\n mutationObserver = new MutationObserver((mutations) => {\n const isOwnMutation = mutations.every(m =>\n container?.contains(m.target as Node) ||\n clickOverlay?.contains(m.target as Node)\n );\n if (!isOwnMutation) scheduleReposition();\n });\n mutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['style', 'class'],\n });\n\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => scheduleReposition());\n }\n}\n\nfunction teardownRepositionListeners() {\n window.removeEventListener('scroll', scheduleReposition);\n window.removeEventListener('resize', scheduleReposition);\n window.removeEventListener('keydown', handleKeyDown);\n detachNestedScrollListeners();\n mutationObserver?.disconnect();\n mutationObserver = null;\n resizeObserver?.disconnect();\n resizeObserver = null;\n if (repositionRAF) {\n cancelAnimationFrame(repositionRAF);\n repositionRAF = null;\n }\n}\n\nfunction handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n if (activePopup) {\n closePopup();\n } else if (pinMode) {\n // Close any open form first\n container?.querySelectorAll('.bs-lp-form').forEach(f => f.remove());\n togglePinMode(false);\n }\n }\n}\n\nfunction scheduleReposition() {\n if (repositionRAF) return;\n repositionRAF = requestAnimationFrame(() => {\n repositionRAF = null;\n // Re-probe offset — ancestor transforms can change dynamically\n // (modal open/close, route transitions, animation libraries)\n probeFixedOffset();\n repositionPins();\n });\n}\n\n/** Reposition all visible pin markers without full re-render. */\nfunction repositionPins() {\n if (!container) return;\n const markers = container.querySelectorAll<HTMLDivElement>('.bs-lp');\n markers.forEach((dot) => {\n const pinId = dot.dataset.pinId;\n const pin = pins.find(p => p.id === pinId);\n if (!pin) return;\n const pos = toFixedCSS(resolvePosition(pin));\n dot.style.left = pos.left;\n dot.style.top = pos.top;\n // Hide pin when anchor element is clipped by a scroll container\n dot.style.display = pos.hidden ? 'none' : '';\n });\n}\n\n// ─── Nested Scroll Listeners ─────────────────────────────\n\n/** Walk up the DOM from `el` and collect ancestors with scrollable overflow. */\nfunction getScrollableAncestors(el: Element): Element[] {\n const ancestors: Element[] = [];\n let current = el.parentElement;\n while (current && current !== document.documentElement) {\n const style = window.getComputedStyle(current);\n const overflowY = style.overflowY;\n const overflowX = style.overflowX;\n const isScrollable =\n (overflowY === 'auto' || overflowY === 'scroll' || overflowX === 'auto' || overflowX === 'scroll') &&\n (current.scrollHeight > current.clientHeight || current.scrollWidth > current.clientWidth);\n if (isScrollable) {\n ancestors.push(current);\n }\n current = current.parentElement;\n }\n return ancestors;\n}\n\n/** Attach scroll listeners to all scrollable ancestors of every pin's target element. */\nfunction attachNestedScrollListeners() {\n detachNestedScrollListeners();\n const seen = new Set<Element>();\n\n for (const pin of pins) {\n const el = findElement(pin.elementSelector, pin.elementXPath);\n if (!el) continue;\n\n const ancestors = getScrollableAncestors(el);\n for (const ancestor of ancestors) {\n if (seen.has(ancestor)) continue;\n seen.add(ancestor);\n\n const handler = () => scheduleReposition();\n ancestor.addEventListener('scroll', handler, { passive: true });\n nestedScrollCleanups.push(() => ancestor.removeEventListener('scroll', handler));\n }\n }\n}\n\n/** Remove all nested scroll listeners. */\nfunction detachNestedScrollListeners() {\n for (const cleanup of nestedScrollCleanups) {\n cleanup();\n }\n nestedScrollCleanups = [];\n}\n\n// ─── Overlay ─────────────────────────────────────────────\n\nfunction createOverlay() {\n if (container) return;\n\n container = document.createElement('div');\n container.id = 'bugstash-live-pins';\n\n // Click overlay stays in light DOM (elementFromPoint requires it).\n // Use custom element + !important inline styles to resist host CSS.\n clickOverlay = document.createElement('bugstash-overlay');\n clickOverlay.style.setProperty('display', 'none', 'important');\n clickOverlay.style.setProperty('position', 'fixed', 'important');\n clickOverlay.style.setProperty('inset', '0', 'important');\n clickOverlay.style.setProperty('z-index', '2147483641', 'important');\n clickOverlay.style.setProperty('cursor', 'crosshair', 'important');\n clickOverlay.style.setProperty('background', 'rgba(0,0,0,0.05)', 'important');\n clickOverlay.style.setProperty('margin', '0', 'important');\n clickOverlay.style.setProperty('padding', '0', 'important');\n clickOverlay.style.setProperty('border', 'none', 'important');\n clickOverlay.style.setProperty('opacity', '1', 'important');\n clickOverlay.style.setProperty('visibility', 'visible', 'important');\n clickOverlay.style.setProperty('pointer-events', 'auto', 'important');\n // Prevent host CSS from breaking the overlay\n clickOverlay.style.setProperty('transform', 'none', 'important');\n clickOverlay.style.setProperty('filter', 'none', 'important');\n clickOverlay.style.setProperty('perspective', 'none', 'important');\n clickOverlay.style.setProperty('will-change', 'auto', 'important');\n clickOverlay.style.setProperty('contain', 'none', 'important');\n clickOverlay.style.setProperty('clip-path', 'none', 'important');\n clickOverlay.style.setProperty('isolation', 'auto', 'important');\n clickOverlay.style.setProperty('mix-blend-mode', 'normal', 'important');\n clickOverlay.style.setProperty('box-sizing', 'border-box', 'important');\n clickOverlay.style.setProperty('overflow', 'visible', 'important');\n clickOverlay.style.setProperty('float', 'none', 'important');\n\n const style = document.createElement('style');\n style.textContent = `\n /* ─── Isolation Reset ─────────────────────────────────── */\n :host {\n all: initial !important;\n position: fixed !important;\n inset: 0 !important;\n pointer-events: none !important;\n z-index: 2147483640 !important;\n display: block !important;\n visibility: visible !important;\n opacity: 1 !important;\n transform: none !important;\n perspective: none !important;\n filter: none !important;\n will-change: auto !important;\n contain: none !important;\n isolation: auto !important;\n }\n *, *::before, *::after {\n box-sizing: border-box !important;\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;\n line-height: 1.5;\n direction: ltr;\n text-align: left;\n -webkit-text-size-adjust: 100%;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n /* Color scheme support */\n @media (prefers-color-scheme: light) {\n :host { --bs-pin-bg: #ffffff; --bs-pin-text: #171717; --bs-pin-muted: #6b7280; --bs-pin-border: #eaeaea; --bs-pin-surface: #fafafa; --bs-pin-input-bg: #ffffff; --bs-pin-hover: #f5f5f5; --bs-pin-shadow: rgba(0,0,0,0.08); --bs-pin-shadow-lg: rgba(0,0,0,0.12); }\n }\n @media (prefers-color-scheme: dark) {\n :host { --bs-pin-bg: #1a1a1a; --bs-pin-text: #ededed; --bs-pin-muted: #888; --bs-pin-border: #333; --bs-pin-surface: #222; --bs-pin-input-bg: #2a2a2a; --bs-pin-hover: #2a2a2a; --bs-pin-shadow: rgba(0,0,0,0.2); --bs-pin-shadow-lg: rgba(0,0,0,0.4); }\n }\n /* Fallback (default to light) */\n :host {\n --bs-pin-bg: #ffffff; --bs-pin-text: #171717; --bs-pin-muted: #6b7280; --bs-pin-border: #eaeaea; --bs-pin-surface: #fafafa; --bs-pin-input-bg: #ffffff; --bs-pin-hover: #f5f5f5; --bs-pin-shadow: rgba(0,0,0,0.08); --bs-pin-shadow-lg: rgba(0,0,0,0.12);\n }\n @media (prefers-color-scheme: dark) {\n :host { --bs-pin-bg: #1a1a1a; --bs-pin-text: #ededed; --bs-pin-muted: #888; --bs-pin-border: #333; --bs-pin-surface: #222; --bs-pin-input-bg: #2a2a2a; --bs-pin-hover: #2a2a2a; --bs-pin-shadow: rgba(0,0,0,0.2); --bs-pin-shadow-lg: rgba(0,0,0,0.4); }\n }\n #bugstash-live-pins {\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n width: 0 !important;\n height: 0 !important;\n overflow: visible !important;\n z-index: 2147483640 !important;\n pointer-events: none !important;\n transform: none !important;\n perspective: none !important;\n filter: none !important;\n will-change: auto !important;\n contain: none !important;\n }\n\n /* ── Pin Marker (Avatar-based) ── */\n .bs-lp {\n position: fixed !important;\n pointer-events: auto !important;\n cursor: pointer !important;\n transform: translate(-50%, -50%) !important;\n z-index: 1;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n }\n .bs-lp:hover { transform: translate(-50%, -50%) scale(1.1) !important; z-index: 5; }\n .bs-lp-dot {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 600;\n font-family: -apple-system, system-ui, sans-serif;\n color: #fff;\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n position: relative;\n overflow: hidden;\n background-size: cover;\n background-position: center;\n }\n .bs-lp-avatar {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n }\n .bs-lp-initials {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 600;\n color: #fff;\n }\n .bs-lp-badge {\n position: absolute;\n top: -3px;\n right: -3px;\n min-width: 14px;\n height: 14px;\n border-radius: 7px;\n background: var(--bs-pin-text, #171717);\n color: var(--bs-pin-bg, #fff);\n font-size: 9px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 3px;\n line-height: 1;\n z-index: 2;\n }\n\n /* ── Popup (Clean Card) ── */\n .bs-lp-popup {\n position: absolute;\n left: 40px;\n top: -8px;\n width: min(360px, calc(100vw - 48px));\n background: var(--bs-pin-bg);\n border: 1px solid var(--bs-pin-border);\n border-radius: 14px;\n box-shadow: 0 8px 30px var(--bs-pin-shadow-lg), 0 0 0 1px var(--bs-pin-shadow);\n backdrop-filter: blur(12px);\n z-index: 10;\n pointer-events: auto;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n color: var(--bs-pin-text);\n overflow: hidden;\n animation: bs-lp-pop-in 0.2s ease;\n }\n @keyframes bs-lp-pop-in {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .bs-lp-popup-hdr {\n padding: 14px 16px 12px;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n }\n .bs-lp-popup-hdr-avatar {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 10px;\n font-weight: 600;\n color: #fff;\n overflow: hidden;\n }\n .bs-lp-popup-hdr-avatar img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n .bs-lp-popup-hdr-body {\n flex: 1;\n min-width: 0;\n }\n .bs-lp-popup-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--bs-pin-text);\n line-height: 1.3;\n margin-bottom: 2px;\n }\n .bs-lp-popup-meta {\n font-size: 12px;\n color: var(--bs-pin-muted);\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n }\n .bs-lp-popup-pill {\n font-size: 11px;\n padding: 2px 8px;\n border-radius: 99px;\n font-weight: 500;\n white-space: nowrap;\n }\n .bs-lp-popup-close {\n all: initial;\n color: var(--bs-pin-muted);\n cursor: pointer;\n padding: 2px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n transition: background 0.15s, color 0.15s;\n }\n .bs-lp-popup-close:hover { color: var(--bs-pin-text); background: var(--bs-pin-hover); }\n .bs-lp-popup-close svg { width: 16px; height: 16px; }\n .bs-lp-popup-desc {\n padding: 0 16px 12px;\n font-size: 13px;\n line-height: 1.6;\n color: var(--bs-pin-muted);\n }\n .bs-lp-popup-info {\n padding: 8px 16px;\n font-size: 11px;\n color: var(--bs-pin-muted);\n background: var(--bs-pin-surface);\n border-top: 1px solid var(--bs-pin-border);\n display: flex;\n justify-content: space-between;\n }\n\n /* Comments */\n .bs-lp-cmts {\n max-height: 220px;\n overflow-y: auto;\n border-top: 1px solid var(--bs-pin-border);\n }\n .bs-lp-cmts::-webkit-scrollbar { width: 4px; }\n .bs-lp-cmts::-webkit-scrollbar-thumb { background: var(--bs-pin-border); border-radius: 2px; }\n .bs-lp-cmt {\n padding: 10px 16px;\n display: flex;\n gap: 8px;\n align-items: flex-start;\n border-bottom: 1px solid var(--bs-pin-border);\n }\n .bs-lp-cmt:last-child { border-bottom: none; }\n .bs-lp-cmt-avatar {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 8px;\n font-weight: 600;\n color: #fff;\n overflow: hidden;\n }\n .bs-lp-cmt-avatar img { width: 100%; height: 100%; object-fit: cover; }\n .bs-lp-cmt-content { flex: 1; min-width: 0; }\n .bs-lp-cmt-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 2px;\n }\n .bs-lp-cmt-author {\n font-weight: 600;\n color: var(--bs-pin-text);\n font-size: 12px;\n }\n .bs-lp-cmt-time {\n font-size: 11px;\n color: var(--bs-pin-muted);\n }\n .bs-lp-cmt-body {\n color: var(--bs-pin-text);\n font-size: 13px;\n line-height: 1.5;\n }\n\n /* Comment input */\n .bs-lp-input {\n display: flex;\n align-items: center;\n border-top: 1px solid var(--bs-pin-border);\n padding: 4px;\n gap: 4px;\n }\n .bs-lp-input input {\n all: initial;\n flex: 1;\n padding: 8px 12px;\n color: var(--bs-pin-text);\n font-size: 13px;\n font-family: inherit;\n background: var(--bs-pin-input-bg);\n border: 1px solid var(--bs-pin-border);\n border-radius: 8px;\n box-sizing: border-box;\n transition: border-color 0.15s;\n }\n .bs-lp-input input:focus { border-color: #6E9ED0; outline: none; }\n .bs-lp-input input::placeholder { color: var(--bs-pin-muted); }\n .bs-lp-input button {\n all: initial;\n width: 32px;\n height: 32px;\n border-radius: 8px;\n background: #6E9ED0;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: opacity 0.15s;\n }\n .bs-lp-input button:hover { opacity: 0.85; }\n .bs-lp-input button svg { width: 14px; height: 14px; }\n\n /* Actions */\n .bs-lp-acts {\n padding: 8px 16px 10px;\n display: flex;\n gap: 8px;\n border-top: 1px solid var(--bs-pin-border);\n }\n .bs-lp-act {\n all: initial;\n padding: 6px 14px;\n border-radius: 8px;\n background: var(--bs-pin-surface);\n color: var(--bs-pin-muted);\n font-size: 12px;\n font-weight: 500;\n font-family: inherit;\n cursor: pointer;\n transition: all 0.15s;\n display: flex;\n align-items: center;\n gap: 5px;\n }\n .bs-lp-act:hover { background: var(--bs-pin-hover); color: var(--bs-pin-text); }\n .bs-lp-act.resolve { color: #22c55e; }\n .bs-lp-act.resolve:hover { background: rgba(34,197,94,0.1); }\n .bs-lp-act.delete { color: #ef4444; }\n .bs-lp-act.delete:hover { background: rgba(239,68,68,0.1); }\n\n /* ── New Pin Form ── */\n .bs-lp-form {\n position: fixed;\n width: min(320px, calc(100vw - 32px));\n background: var(--bs-pin-bg);\n border: 1px solid var(--bs-pin-border);\n border-radius: 14px;\n box-shadow: 0 8px 30px var(--bs-pin-shadow-lg);\n backdrop-filter: blur(12px);\n z-index: 2147483645;\n pointer-events: auto;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n color: var(--bs-pin-text);\n padding: 16px;\n animation: bs-lp-pop-in 0.2s ease;\n }\n .bs-lp-form-label {\n display: block;\n font-size: 12px;\n color: var(--bs-pin-muted);\n margin-bottom: 4px;\n margin-top: 12px;\n font-weight: 500;\n }\n .bs-lp-form-label:first-child { margin-top: 0; }\n .bs-lp-form input,\n .bs-lp-form textarea,\n .bs-lp-form select {\n all: initial;\n display: block;\n width: 100%;\n background: var(--bs-pin-input-bg);\n border: 1px solid var(--bs-pin-border);\n border-radius: 10px;\n padding: 8px 12px;\n color: var(--bs-pin-text);\n font-size: 13px;\n font-family: inherit;\n box-sizing: border-box;\n transition: border-color 0.15s;\n }\n .bs-lp-form textarea {\n resize: vertical;\n min-height: 48px;\n white-space: pre-wrap;\n }\n .bs-lp-form input:focus,\n .bs-lp-form textarea:focus,\n .bs-lp-form select:focus {\n border-color: #6E9ED0;\n outline: none;\n }\n .bs-lp-form input::placeholder,\n .bs-lp-form textarea::placeholder { color: var(--bs-pin-muted); }\n /* Segmented buttons for priority/category */\n .bs-lp-seg-row {\n display: flex;\n gap: 0;\n border: 1px solid var(--bs-pin-border);\n border-radius: 10px;\n overflow: hidden;\n }\n .bs-lp-seg-btn {\n all: initial;\n flex: 1;\n padding: 7px 4px;\n text-align: center;\n font-size: 12px;\n font-weight: 500;\n font-family: inherit;\n cursor: pointer;\n color: var(--bs-pin-muted);\n background: var(--bs-pin-input-bg);\n border-right: 1px solid var(--bs-pin-border);\n transition: all 0.15s;\n box-sizing: border-box;\n }\n .bs-lp-seg-btn:last-child { border-right: none; }\n .bs-lp-seg-btn:hover { color: var(--bs-pin-text); background: var(--bs-pin-hover); }\n .bs-lp-seg-btn.bs-active {\n background: #6E9ED0;\n color: #fff;\n }\n .bs-lp-form-btns {\n display: flex;\n gap: 8px;\n margin-top: 14px;\n }\n .bs-lp-form-btns button {\n all: initial;\n padding: 9px 16px;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 600;\n font-family: inherit;\n cursor: pointer;\n text-align: center;\n transition: opacity 0.15s;\n }\n .bs-lp-form-submit {\n background: #6E9ED0;\n color: #fff;\n flex: 1;\n }\n .bs-lp-form-submit:hover { opacity: 0.85; }\n .bs-lp-form-cancel {\n background: transparent;\n color: var(--bs-pin-muted);\n }\n .bs-lp-form-cancel:hover { color: var(--bs-pin-text); }\n `;\n\n container.appendChild(style);\n // Pin markers go into shadow root for style isolation\n shadow!.appendChild(container);\n // Click overlay stays in light DOM — elementFromPoint only searches light DOM\n document.body.appendChild(clickOverlay);\n\n // Click overlay to place new pin\n clickOverlay.addEventListener('click', (e) => {\n const clientX = e.clientX;\n const clientY = e.clientY;\n\n // Detect element first (before coordinate calc uses it)\n // Use try/finally to guarantee pointerEvents is restored even if elementFromPoint throws\n let el: Element | null = null;\n try {\n clickOverlay!.style.setProperty('pointer-events', 'none', 'important');\n el = document.elementFromPoint(clientX, clientY);\n } finally {\n clickOverlay!.style.setProperty('pointer-events', 'auto', 'important');\n }\n\n const pageX = clientX + window.scrollX;\n const pageY = clientY + window.scrollY;\n\n // Compute element-relative offsets (0-1 range) — like Vercel comments\n // These survive layout shifts because they're anchored to the element, not the page\n let xPercent: number;\n let yPercent: number;\n if (el && el !== document.body && el !== document.documentElement) {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n xPercent = (clientX - rect.left) / rect.width;\n yPercent = (clientY - rect.top) / rect.height;\n } else {\n // Zero-size element — fall back to page percentages (legacy range > 1)\n const pageW = document.documentElement.scrollWidth || document.body.scrollWidth || 1;\n const pageH = document.documentElement.scrollHeight || document.body.scrollHeight || 1;\n xPercent = (pageX / pageW) * 100;\n yPercent = (pageY / pageH) * 100;\n }\n } else {\n // No meaningful element — store page percentages (legacy range > 1)\n const pageW = document.documentElement.scrollWidth || document.body.scrollWidth || 1;\n const pageH = document.documentElement.scrollHeight || document.body.scrollHeight || 1;\n xPercent = (pageX / pageW) * 100;\n yPercent = (pageY / pageH) * 100;\n }\n\n showNewPinForm(pageX, pageY, xPercent, yPercent, clientX, clientY, el);\n });\n}\n\n// ─── Load Data ───────────────────────────────────────────\n\nasync function loadPins() {\n const result = await fetchPagePins(projectId, window.location.pathname);\n if (result.success && result.data) {\n pins = result.data;\n registerKnownPins(pins.map(p => p.id));\n renderPins();\n }\n}\n\nasync function loadMembers() {\n const result = await fetchProjectMembers(projectId);\n if (result.success && result.data) {\n members = result.data as any[];\n }\n}\n\n// ─── Render Pins ─────────────────────────────────────────\n\nfunction renderPins() {\n if (!container) return;\n container.querySelectorAll('.bs-lp').forEach((el) => el.remove());\n\n pins.forEach((pin) => {\n const dot = document.createElement('div');\n dot.className = 'bs-lp';\n dot.dataset.pinId = pin.id;\n\n const pos = toFixedCSS(resolvePosition(pin));\n dot.style.left = pos.left;\n dot.style.top = pos.top;\n if (pos.hidden) dot.style.display = 'none';\n\n const statusColor = STATUS_COLORS[pin.status] || STATUS_COLORS.open;\n const initials = getInitials(pin.creatorName || 'U');\n const gradientBg = getAvatarGradient(pin.creatorName || 'U');\n\n const avatarContent = pin.creatorAvatar\n ? `<img class=\"bs-lp-avatar\" src=\"${escapeHtml(pin.creatorAvatar)}\" alt=\"\" />`\n : `<div class=\"bs-lp-initials\" style=\"background:${gradientBg}\">${initials}</div>`;\n\n const badgeHtml = pin.commentCount > 0\n ? `<span class=\"bs-lp-badge\">${pin.commentCount > 99 ? '99+' : pin.commentCount}</span>`\n : '';\n\n dot.innerHTML = `\n <div class=\"bs-lp-dot\" style=\"border:2px solid ${statusColor}; background:transparent;\">\n ${avatarContent}\n ${badgeHtml}\n </div>\n `;\n\n dot.addEventListener('click', (e) => {\n e.stopPropagation();\n showPinPopup(pin, dot);\n });\n\n container!.appendChild(dot);\n });\n\n attachNestedScrollListeners();\n\n // Observe pin target elements for resize (lazy images, accordions, dynamic content)\n resizeObserver?.disconnect();\n for (const pin of pins) {\n const el = findElement(pin.elementSelector, pin.elementXPath);\n if (el) resizeObserver?.observe(el);\n }\n}\n\n// ─── Pin Popup ───────────────────────────────────────────\n\nfunction timeAgo(ts: number | string): string {\n const time = typeof ts === 'string' ? new Date(ts).getTime() : ts;\n if (isNaN(time)) return '';\n const diff = Date.now() - time;\n const mins = Math.floor(diff / 60000);\n if (mins < 1) return 'just now';\n if (mins < 60) return `${mins}m ago`;\n const hrs = Math.floor(mins / 60);\n if (hrs < 24) return `${hrs}h ago`;\n return `${Math.floor(hrs / 24)}d ago`;\n}\n\n/**\n * Clamp popup or form inside the visible viewport.\n *\n * Popups use `position: absolute` relative to their parent (.bs-lp marker).\n * We read the element's viewport rect, compute the delta needed to keep it\n * on-screen, then adjust the current CSS left/top by that delta. This keeps\n * all math in the parent's local coordinate system, avoiding issues with\n * ancestor transforms shifting the containing block.\n */\nfunction clampToViewport(el: HTMLElement) {\n requestAnimationFrame(() => {\n const rect = el.getBoundingClientRect();\n const pad = 16;\n\n // Compute how far the element overflows each edge of the viewport.\n // Positive = needs to shift inward by that many px.\n let dx = 0;\n let dy = 0;\n\n if (rect.right > window.innerWidth - pad) {\n dx = (window.innerWidth - pad) - rect.right; // shift left\n }\n if (rect.left + dx < pad) {\n dx = pad - rect.left; // shift right\n }\n if (rect.bottom > window.innerHeight - pad) {\n dy = (window.innerHeight - pad) - rect.bottom; // shift up\n }\n if (rect.top + dy < pad) {\n dy = pad - rect.top; // shift down\n }\n\n // Apply delta to current style values (stays in parent's coord system)\n if (dx !== 0 || dy !== 0) {\n const curLeft = parseFloat(el.style.left) || 0;\n const curTop = parseFloat(el.style.top) || 0;\n el.style.left = `${curLeft + dx}px`;\n el.style.top = `${curTop + dy}px`;\n el.style.right = 'auto';\n el.style.bottom = 'auto';\n }\n });\n}\n\nasync function showPinPopup(pin: LivePin, dotEl: HTMLDivElement) {\n closePopup();\n\n const popup = document.createElement('div');\n popup.className = 'bs-lp-popup';\n\n const user = getCurrentUser();\n const pinCreator = pin.createdBy || (pin as any).createdById;\n const canManage = user && (user.role === 'owner' || user.role === 'admin' || user.id === pinCreator);\n const statusColor = STATUS_COLORS[pin.status] || STATUS_COLORS.open;\n const prioColor = PRIORITY_COLORS[pin.priority] || PRIORITY_COLORS.medium;\n const prioLabel = pin.priority ? pin.priority.charAt(0).toUpperCase() + pin.priority.slice(1) : 'Medium';\n\n const creatorInitials = getInitials(pin.creatorName || 'U');\n const creatorGradient = getAvatarGradient(pin.creatorName || 'U');\n const creatorAvatarHtml = pin.creatorAvatar\n ? `<img src=\"${escapeHtml(pin.creatorAvatar)}\" alt=\"\" style=\"width:100%;height:100%;object-fit:cover;border-radius:50%;\" />`\n : `<span>${creatorInitials}</span>`;\n const statusLabel = pin.status.replace('_', ' ');\n const sendIconSvg = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/><polygon points=\"22 2 15 22 11 13 2 9 22 2\"/></svg>`;\n const closeIconSvg = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`;\n\n popup.innerHTML = `\n <div class=\"bs-lp-popup-hdr\">\n <div class=\"bs-lp-popup-hdr-avatar\" style=\"background:${creatorGradient}\">\n ${creatorAvatarHtml}\n </div>\n <div class=\"bs-lp-popup-hdr-body\">\n <div class=\"bs-lp-popup-title\">${escapeHtml(pin.title)}</div>\n <div class=\"bs-lp-popup-meta\">\n <span>${pin.creatorName || 'Unknown'}</span>\n <span>&middot;</span>\n <span>${timeAgo(pin.createdAt)}</span>\n <span class=\"bs-lp-popup-pill\" style=\"background:${statusColor}18;color:${statusColor}\">${statusLabel}</span>\n <span class=\"bs-lp-popup-pill\" style=\"background:${prioColor}18;color:${prioColor}\">${prioLabel}</span>\n </div>\n </div>\n <button class=\"bs-lp-popup-close\">${closeIconSvg}</button>\n </div>\n ${pin.description ? `<div class=\"bs-lp-popup-desc\">${escapeHtml(pin.description)}</div>` : ''}\n ${pin.assigneeName ? `<div class=\"bs-lp-popup-info\"><span>Assigned to ${escapeHtml(pin.assigneeName)}</span></div>` : ''}\n <div class=\"bs-lp-cmts\" id=\"bs-lp-cmts\">\n <div style=\"text-align:center;color:var(--bs-pin-muted);padding:12px;font-size:12px\">Loading comments...</div>\n </div>\n <div class=\"bs-lp-input\">\n <input type=\"text\" placeholder=\"Write a comment...\" id=\"bs-lp-cmt-in\" name=\"pin-comment\" />\n <button id=\"bs-lp-cmt-send\">${sendIconSvg}</button>\n </div>\n <div class=\"bs-lp-acts\">\n ${pin.status !== 'resolved'\n ? `<button class=\"bs-lp-act resolve\" id=\"bs-lp-resolve\">&#10003; Resolve</button>`\n : `<button class=\"bs-lp-act\" id=\"bs-lp-reopen\">&#8634; Reopen</button>`\n }\n ${canManage ? `<button class=\"bs-lp-act delete\" id=\"bs-lp-delete\">&#10005; Delete</button>` : ''}\n </div>\n `;\n\n dotEl.appendChild(popup);\n activePopup = popup;\n\n // Load comments in background\n fetchComments(pin.id).then(commentsRes => {\n const cmtsEl = popup.querySelector('#bs-lp-cmts');\n if (!cmtsEl) return;\n const comments = commentsRes.success && commentsRes.data ? commentsRes.data : [];\n cmtsEl.innerHTML = comments.length\n ? comments.map((c: any) => renderCommentHtml(c)).join('')\n : '';\n // Re-clamp after comments load (popup height may have changed)\n clampToViewport(popup);\n });\n\n clampToViewport(popup);\n\n // Bind events\n popup.querySelector('.bs-lp-popup-close')!.addEventListener('click', (e) => {\n e.stopPropagation();\n closePopup();\n });\n\n popup.querySelector('#bs-lp-cmt-send')?.addEventListener('click', async () => {\n const input = popup.querySelector('#bs-lp-cmt-in') as HTMLInputElement;\n const body = input.value.trim();\n if (!body) return;\n input.value = '';\n\n if (navigator.onLine) {\n const res = await createComment(pin.id, body);\n if (res.success && res.data) {\n const cmtsEl = popup.querySelector('#bs-lp-cmts')!;\n cmtsEl.innerHTML += renderCommentHtml(res.data);\n cmtsEl.scrollTop = cmtsEl.scrollHeight;\n }\n } else {\n queueOfflineAction({ type: 'create_comment', data: { pinId: pin.id, body } });\n }\n });\n\n (popup.querySelector('#bs-lp-cmt-in') as HTMLInputElement)?.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') popup.querySelector('#bs-lp-cmt-send')?.dispatchEvent(new Event('click'));\n });\n\n popup.querySelector('#bs-lp-resolve')?.addEventListener('click', async () => {\n await updatePin(pin.id, { status: 'resolved' as any });\n const idx = pins.findIndex(p => p.id === pin.id);\n if (idx >= 0) pins = pins.map((p, i) => i === idx ? { ...p, status: 'resolved' as const } : p);\n closePopup();\n renderPins();\n });\n\n popup.querySelector('#bs-lp-reopen')?.addEventListener('click', async () => {\n await updatePin(pin.id, { status: 'open' as any });\n const idx = pins.findIndex(p => p.id === pin.id);\n if (idx >= 0) pins = pins.map((p, i) => i === idx ? { ...p, status: 'open' as const } : p);\n closePopup();\n renderPins();\n });\n\n let deleting = false;\n popup.querySelector('#bs-lp-delete')?.addEventListener('click', async () => {\n if (deleting) return;\n if (!confirm('Delete this pin?')) return;\n deleting = true;\n await deletePin(pin.id);\n pins = pins.filter((p) => p.id !== pin.id);\n closePopup();\n renderPins();\n });\n\n popup.addEventListener('click', (e) => e.stopPropagation());\n}\n\nfunction closePopup() {\n activePopup?.remove();\n activePopup = null;\n}\n\n// ─── New Pin Form ────────────────────────────────────────\n\n/** CSS.escape with fallback for older browsers. */\nconst cssEscape = (str: string): string => {\n if (!str) return '';\n if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') return CSS.escape(str);\n // Basic fallback: escape special CSS selector characters\n return str.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, '\\\\$1');\n};\n\nfunction getSelector(el: Element | null): string {\n if (!el || el === document.body || el === document.documentElement) return 'body';\n\n // Prefer data-testid / data-test-id / data-cy (standard in tested SPAs)\n for (const attr of ['data-testid', 'data-test-id', 'data-cy']) {\n const val = el.getAttribute(attr);\n if (val) return `[${attr}=\"${cssEscape(val)}\"]`;\n }\n\n // Prefer unique ID (escaped for safety)\n if (el.id) {\n try {\n const escaped = `#${cssEscape(el.id)}`;\n if (document.querySelectorAll(escaped).length === 1) return escaped;\n } catch { /* invalid id for CSS.escape */ }\n }\n\n // Prefer unique aria-label\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) {\n const candidate = `${el.tagName.toLowerCase()}[aria-label=\"${cssEscape(ariaLabel)}\"]`;\n try {\n if (document.querySelectorAll(candidate).length === 1) return candidate;\n } catch { /* ignore */ }\n }\n\n // Build a tag + class selector\n let selector = el.tagName.toLowerCase();\n if (el.className && typeof el.className === 'string') {\n const classes = el.className.trim().split(/\\s+/)\n .filter(c => !c.startsWith('bs-') && !c.startsWith('ng-') && !c.startsWith('_'))\n .slice(0, 3);\n if (classes.length) selector += '.' + classes.map(c => cssEscape(c)).join('.');\n }\n\n // Disambiguate with :nth-of-type instead of :nth-child (resilient to sibling type changes)\n const parent = el.parentElement;\n if (parent && parent !== document.body) {\n const sameTypeSiblings = Array.from(parent.children).filter(c => c.tagName === el.tagName);\n if (sameTypeSiblings.length > 1) {\n const idx = sameTypeSiblings.indexOf(el);\n selector += `:nth-of-type(${idx + 1})`;\n }\n return getSelector(parent) + ' > ' + selector;\n }\n return selector;\n}\n\n/** Build a ranked array of selectors for resilient element re-finding. */\nfunction getSelectorChain(el: Element | null): string[] {\n if (!el || el === document.body || el === document.documentElement) return ['body'];\n const selectors: string[] = [];\n\n // 1. Test attributes (most stable — survive refactors)\n for (const attr of ['data-testid', 'data-test-id', 'data-cy']) {\n const val = el.getAttribute(attr);\n if (val) { selectors.push(`[${attr}=\"${cssEscape(val)}\"]`); break; }\n }\n\n // 2. Unique ID\n if (el.id) {\n try {\n const escaped = `#${cssEscape(el.id)}`;\n if (document.querySelectorAll(escaped).length === 1) selectors.push(escaped);\n } catch { /* invalid id */ }\n }\n\n // 3. Unique aria-label\n const aria = el.getAttribute('aria-label');\n if (aria) {\n const candidate = `${el.tagName.toLowerCase()}[aria-label=\"${cssEscape(aria)}\"]`;\n try {\n if (document.querySelectorAll(candidate).length === 1) selectors.push(candidate);\n } catch { /* ignore */ }\n }\n\n // 4. Structural path (tag-only, no classes — survives CSS module hashes & Tailwind rebuilds)\n selectors.push(getStructuralPath(el));\n\n return selectors;\n}\n\n/** Tag-only structural path with :nth-of-type — zero classes, maximum resilience. */\nfunction getStructuralPath(el: Element): string {\n const parts: string[] = [];\n let current: Element | null = el;\n while (current && current !== document.body && current !== document.documentElement) {\n const node: Element = current;\n const parent = node.parentElement;\n if (!parent) break;\n let tag = node.tagName.toLowerCase();\n const siblings = Array.from(parent.children).filter((c: Element) => c.tagName === node.tagName);\n if (siblings.length > 1) tag += `:nth-of-type(${siblings.indexOf(node) + 1})`;\n parts.unshift(tag);\n current = parent;\n }\n return parts.join(' > ');\n}\n\nfunction getXPath(el: Element | null): string {\n if (!el) return '';\n const parts: string[] = [];\n let current: Element | null = el;\n while (current && current !== document.body) {\n let idx = 1;\n let sib = current.previousElementSibling;\n while (sib) {\n if (sib.tagName === current.tagName) idx++;\n sib = sib.previousElementSibling;\n }\n parts.unshift(`${current.tagName.toLowerCase()}[${idx}]`);\n current = current.parentElement;\n }\n return '/body/' + parts.join('/');\n}\n\nfunction showNewPinForm(pageX: number, pageY: number, xPct: number, yPct: number, clientX: number, clientY: number, targetEl: Element | null) {\n closePopup();\n container?.querySelectorAll('.bs-lp-form').forEach(e => e.remove());\n\n const form = document.createElement('div');\n form.className = 'bs-lp-form';\n\n // Position form near click point, clamped to viewport\n const formW = Math.min(300, window.innerWidth - 32);\n const pad = 16;\n let left = clientX + pad;\n let top = clientY - 8;\n if (left + formW > window.innerWidth - pad) {\n left = clientX - formW - pad;\n }\n if (left < pad) left = pad;\n const formPos = viewportToFixed(left, top);\n form.style.left = formPos.left;\n form.style.top = formPos.top;\n\n // Adjust vertical position after rendering\n requestAnimationFrame(() => {\n const rect = form.getBoundingClientRect();\n if (rect.bottom > window.innerHeight - pad) {\n const adjusted = viewportToFixed(left, Math.max(pad, clientY - rect.height));\n form.style.top = adjusted.top;\n }\n });\n\n const memberOptions = members\n .filter(m => (m as any).userId !== getCurrentUser()?.id)\n .map(m => `<option value=\"${(m as any).userId}\">${escapeHtml((m as any).name)}</option>`)\n .join('');\n\n form.innerHTML = `\n <label class=\"bs-lp-form-label\">Title</label>\n <input type=\"text\" id=\"bs-np-title\" name=\"pin-title\" placeholder=\"What's the issue?\" autofocus />\n <label class=\"bs-lp-form-label\">Description</label>\n <textarea id=\"bs-np-desc\" name=\"pin-desc\" placeholder=\"Add more details...\"></textarea>\n <label class=\"bs-lp-form-label\">Priority</label>\n <div class=\"bs-lp-seg-row\" id=\"bs-np-priority-row\">\n <button class=\"bs-lp-seg-btn\" data-value=\"low\">Low</button>\n <button class=\"bs-lp-seg-btn bs-active\" data-value=\"medium\">Medium</button>\n <button class=\"bs-lp-seg-btn\" data-value=\"high\">High</button>\n <button class=\"bs-lp-seg-btn\" data-value=\"critical\">Critical</button>\n </div>\n <label class=\"bs-lp-form-label\">Category</label>\n <div class=\"bs-lp-seg-row\" id=\"bs-np-category-row\">\n <button class=\"bs-lp-seg-btn\" data-value=\"ui\">UI</button>\n <button class=\"bs-lp-seg-btn\" data-value=\"functionality\">Func</button>\n <button class=\"bs-lp-seg-btn\" data-value=\"performance\">Perf</button>\n <button class=\"bs-lp-seg-btn\" data-value=\"content\">Content</button>\n <button class=\"bs-lp-seg-btn bs-active\" data-value=\"other\">Other</button>\n </div>\n ${memberOptions ? `\n <label class=\"bs-lp-form-label\">Assign to</label>\n <select id=\"bs-np-assignee\" name=\"pin-assignee\">\n <option value=\"\">Unassigned</option>\n ${memberOptions}\n </select>\n ` : ''}\n <div class=\"bs-lp-form-btns\">\n <button class=\"bs-lp-form-cancel\" id=\"bs-np-cancel\">Cancel</button>\n <button class=\"bs-lp-form-submit\" id=\"bs-np-submit\">Create pin</button>\n </div>\n `;\n\n container!.appendChild(form);\n\n form.addEventListener('click', (e) => e.stopPropagation());\n\n // Segmented button handlers\n setupSegmentedRow(form, '#bs-np-priority-row');\n setupSegmentedRow(form, '#bs-np-category-row');\n\n form.querySelector('#bs-np-cancel')!.addEventListener('click', () => form.remove());\n\n form.querySelector('#bs-np-submit')!.addEventListener('click', async () => {\n const title = (form.querySelector('#bs-np-title') as HTMLInputElement).value.trim();\n if (!title) {\n (form.querySelector('#bs-np-title') as HTMLInputElement).style.borderColor = '#ef4444';\n return;\n }\n\n const submitBtn = form.querySelector('#bs-np-submit') as HTMLButtonElement;\n submitBtn.textContent = 'Creating...';\n submitBtn.style.opacity = '0.6';\n submitBtn.style.pointerEvents = 'none';\n\n const desc = (form.querySelector('#bs-np-desc') as HTMLTextAreaElement).value.trim();\n const priority = getSegmentedValue(form, '#bs-np-priority-row') || 'medium';\n const category = getSegmentedValue(form, '#bs-np-category-row') || 'other';\n const assigneeEl = form.querySelector('#bs-np-assignee') as HTMLSelectElement;\n const assigneeId = assigneeEl?.value || undefined;\n\n const selector = JSON.stringify(getSelectorChain(targetEl));\n const xpath = getXPath(targetEl);\n\n const logs = getLogs().slice(-20).map(l => `[${l.level}] ${l.args.join(' ')}`);\n const errors = getErrors().slice(-10).map(e => `${e.message} at ${e.source}:${e.lineno}`);\n const netErrors = getFailedNetworkCaptures().slice(-10).map(n => `${n.method} ${n.url} → ${n.status}`);\n\n const pinData = {\n projectId,\n pageUrl: window.location.href,\n pathname: window.location.pathname,\n elementSelector: selector,\n elementXPath: xpath,\n xPercent: xPct,\n yPercent: yPct,\n pageX,\n pageY,\n title,\n description: desc,\n priority: priority as 'low' | 'medium' | 'high' | 'critical',\n category: category as 'ui' | 'functionality' | 'performance' | 'content' | 'other',\n assigneeId,\n browserInfo: navigator.userAgent,\n screenSize: `${screen.width}x${screen.height}`,\n viewportSize: `${window.innerWidth}x${window.innerHeight}`,\n devicePixelRatio: window.devicePixelRatio,\n consoleLogs: logs,\n networkErrors: netErrors,\n jsErrors: errors,\n };\n\n form.remove();\n\n if (navigator.onLine) {\n const res = await createPin(pinData);\n if (res.success && res.data) {\n pins = [...pins, res.data];\n renderPins();\n }\n } else {\n queueOfflineAction({ type: 'create_pin', data: pinData });\n const currentUser = getCurrentUser();\n pins = [...pins, {\n ...pinData,\n id: 'local-' + Date.now(),\n orgId: '',\n status: 'open',\n tags: [],\n createdBy: currentUser?.id || '',\n creatorName: currentUser?.name || '',\n commentCount: 0,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n } as any];\n renderPins();\n }\n });\n\n setTimeout(() => (form.querySelector('#bs-np-title') as HTMLInputElement)?.focus(), 50);\n}\n\n// ─── Real-time Updates ───────────────────────────────────\n\nfunction setupRealtimeListeners() {\n onRealtimeEvent('pin:created', (event) => {\n const pin = event.data as LivePin;\n if (pin.pathname === window.location.pathname) {\n if (!pins.find(p => p.id === pin.id)) {\n pins = [...pins, pin];\n registerKnownPins(pins.map(p => p.id));\n renderPins();\n }\n }\n });\n\n onRealtimeEvent('pin:updated', (event) => {\n const updated = event.data as LivePin;\n const idx = pins.findIndex(p => p.id === updated.id);\n if (idx >= 0) {\n pins = pins.map((p, i) => i === idx ? { ...p, ...updated } : p);\n renderPins();\n }\n });\n\n onRealtimeEvent('pin:deleted', (event) => {\n const { id } = event.data;\n pins = pins.filter(p => p.id !== id);\n closePopup();\n renderPins();\n });\n\n onRealtimeEvent('comment:created', (event) => {\n const comment = event.data;\n if (activePopup) {\n const cmtsEl = activePopup.querySelector('#bs-lp-cmts');\n if (cmtsEl) {\n cmtsEl.innerHTML += renderCommentHtml(comment);\n cmtsEl.scrollTop = cmtsEl.scrollHeight;\n }\n }\n });\n}\n\n// ─── Navigation Watch ────────────────────────────────────\n\nfunction watchNavigation() {\n let lastPath = window.location.pathname;\n\n const check = () => {\n if (window.location.pathname !== lastPath) {\n lastPath = window.location.pathname;\n sendPageNavigate(window.location.href);\n loadPins();\n }\n };\n\n const origPush = history.pushState;\n const origReplace = history.replaceState;\n\n history.pushState = function (...args) {\n origPush.apply(this, args);\n check();\n };\n\n history.replaceState = function (...args) {\n origReplace.apply(this, args);\n check();\n };\n\n window.addEventListener('popstate', check);\n}\n\n// ─── Util ────────────────────────────────────────────────\n\nfunction getInitials(name: string): string {\n return name.split(' ').map(w => w[0] || '').join('').toUpperCase().slice(0, 2) || 'U';\n}\n\nconst AVATAR_GRADIENTS = [\n 'linear-gradient(135deg, #667eea, #764ba2)',\n 'linear-gradient(135deg, #f093fb, #f5576c)',\n 'linear-gradient(135deg, #4facfe, #00f2fe)',\n 'linear-gradient(135deg, #43e97b, #38f9d7)',\n 'linear-gradient(135deg, #fa709a, #fee140)',\n 'linear-gradient(135deg, #a18cd1, #fbc2eb)',\n 'linear-gradient(135deg, #fccb90, #d57eeb)',\n 'linear-gradient(135deg, #e0c3fc, #8ec5fc)',\n];\n\nfunction getAvatarGradient(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;\n return AVATAR_GRADIENTS[Math.abs(hash) % AVATAR_GRADIENTS.length];\n}\n\nfunction renderCommentHtml(c: any): string {\n const name = c.author?.name || c.authorName || 'Unknown';\n const avatar = c.author?.avatar || c.authorAvatar;\n const commentInitials = getInitials(name);\n const commentGradient = getAvatarGradient(name);\n const avatarInner = avatar\n ? `<img src=\"${escapeHtml(avatar)}\" alt=\"\" />`\n : `<span style=\"font-size:8px\">${commentInitials}</span>`;\n return `\n <div class=\"bs-lp-cmt\">\n <div class=\"bs-lp-cmt-avatar\" style=\"background:${commentGradient}\">\n ${avatarInner}\n </div>\n <div class=\"bs-lp-cmt-content\">\n <div class=\"bs-lp-cmt-top\">\n <span class=\"bs-lp-cmt-author\">${escapeHtml(name)}</span>\n <span class=\"bs-lp-cmt-time\">${timeAgo(c.createdAt ? new Date(c.createdAt).getTime() : Date.now())}</span>\n </div>\n <div class=\"bs-lp-cmt-body\">${escapeHtml(c.body)}</div>\n </div>\n </div>\n `;\n}\n\nfunction setupSegmentedRow(form: HTMLElement, selector: string): void {\n const row = form.querySelector(selector);\n if (!row) return;\n row.querySelectorAll('.bs-lp-seg-btn').forEach(btn => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n row.querySelectorAll('.bs-lp-seg-btn').forEach(b => b.classList.remove('bs-active'));\n (btn as HTMLElement).classList.add('bs-active');\n });\n });\n}\n\nfunction getSegmentedValue(form: HTMLElement, selector: string): string {\n const active = form.querySelector(`${selector} .bs-lp-seg-btn.bs-active`) as HTMLElement | null;\n return active?.dataset.value || '';\n}\n\nfunction escapeHtml(str: string): string {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n}\n","import type { BugStashConfig, BugReport, ReportContext } from '@bugstash/shared';\nimport { getLogs } from './logger';\nimport { getNetworkCaptures, getFailedNetworkCaptures } from './network';\nimport { getErrors } from './errors';\nimport { getBreadcrumbs } from './breadcrumbs';\nimport { getPerformanceMetrics } from './performance';\nimport { captureScreenshot } from './screenshot';\nimport { submitReport, login as apiLogin, getCurrentUser, logout as apiLogout } from './api';\nimport { getDefaultTheme, getThemeById, getThemes, type BsTheme } from './themes';\nimport { getDefaultLayout, getLayoutById, getLayouts, LAYOUT_CSS, type BsLayout } from './layouts';\nimport { initLivePins, togglePinMode, isPinModeActive } from './livepins';\nimport { connectRealtime } from './realtime';\n\nlet config: BugStashConfig;\nlet fab: HTMLButtonElement | null = null;\nlet toolbar: HTMLDivElement | null = null;\nlet modal: HTMLDivElement | null = null;\nlet backdrop: HTMLDivElement | null = null;\nlet keyHandler: ((e: KeyboardEvent) => void) | null = null;\nlet shadow: ShadowRoot | null = null;\nlet iframeEl: HTMLIFrameElement | null = null;\nlet iframeDoc: Document | null = null;\nlet isOpen = false;\nlet toolbarVisible = false;\nlet isDragging = false;\nlet resizeHandler: (() => void) | null = null;\nlet dragCleanup: (() => void) | null = null;\n\nconst FAB_STORAGE_KEY = 'bugstash_fab_position';\nlet activeTab: 'report' | 'console' | 'network' | 'context' | 'history' | 'settings' = 'report';\nlet editingReportId: number | null = null;\nlet currentTheme: BsTheme = getDefaultTheme();\nlet currentLayout: BsLayout = getDefaultLayout();\n\n// ─── Icons ───────────────────────────────────────────────\n\nconst I = {\n bug: `<svg width=\"28\" height=\"28\" viewBox=\"55 38 60 105\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M95.8 44h-29c-3 0-5.4 2.4-5.4 5.4v29c0 3 2.4 5.4 5.4 5.4h19.5c13 0 23.5-10.5 23.5-23.5v-2.8c0-7.5-6-13.5-13.5-13.5h-.5zm-6.2 28.2H74.8V57.4h14.8c5.8 0 10.4 4.7 10.4 10.4s-4.7 10.4-10.4 10.4z\" fill=\"rgba(255,255,255,0.85)\"/><path d=\"M100.4 96h-33.6c-3 0-5.4 2.4-5.4 5.4v33.6c0 3 2.4 5.4 5.4 5.4h22c15 0 27-12 27-27v-3.9c0-7.5-6-13.5-13.5-13.5h-1.9zm-7.8 32.2H74.8v-20h17.8c6.7 0 12.2 5.5 12.2 12.2 0 4.3-3.5 7.8-7.8 7.8h-4.6z\" fill=\"rgba(255,255,255,1)\"/></svg>`,\n x: `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`,\n cam: `<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z\"/><circle cx=\"12\" cy=\"13\" r=\"4\"/></svg>`,\n check: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>`,\n report: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/></svg>`,\n console: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"4 17 10 11 4 5\"/><line x1=\"12\" y1=\"19\" x2=\"20\" y2=\"19\"/></svg>`,\n network: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\"/><path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\"/></svg>`,\n ctx: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"/></svg>`,\n settings: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"4\" y1=\"21\" x2=\"4\" y2=\"14\"/><line x1=\"4\" y1=\"10\" x2=\"4\" y2=\"3\"/><line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"3\"/><line x1=\"20\" y1=\"21\" x2=\"20\" y2=\"16\"/><line x1=\"20\" y1=\"12\" x2=\"20\" y2=\"3\"/><line x1=\"1\" y1=\"14\" x2=\"7\" y2=\"14\"/><line x1=\"9\" y1=\"8\" x2=\"15\" y2=\"8\"/><line x1=\"17\" y1=\"16\" x2=\"23\" y2=\"16\"/></svg>`,\n history: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><polyline points=\"12 6 12 12 16 14\"/></svg>`,\n pin: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>`,\n sun: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><circle cx=\"12\" cy=\"12\" r=\"5\"/><line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"3\"/><line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"23\"/><line x1=\"4.22\" y1=\"4.22\" x2=\"5.64\" y2=\"5.64\"/><line x1=\"18.36\" y1=\"18.36\" x2=\"19.78\" y2=\"19.78\"/><line x1=\"1\" y1=\"12\" x2=\"3\" y2=\"12\"/><line x1=\"21\" y1=\"12\" x2=\"23\" y2=\"12\"/><line x1=\"4.22\" y1=\"19.78\" x2=\"5.64\" y2=\"18.36\"/><line x1=\"18.36\" y1=\"5.64\" x2=\"19.78\" y2=\"4.22\"/></svg>`,\n moon: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z\"/></svg>`,\n keyboard: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\"/><line x1=\"6\" y1=\"8\" x2=\"6\" y2=\"8\"/><line x1=\"10\" y1=\"8\" x2=\"10\" y2=\"8\"/><line x1=\"14\" y1=\"8\" x2=\"14\" y2=\"8\"/><line x1=\"18\" y1=\"8\" x2=\"18\" y2=\"8\"/><line x1=\"8\" y1=\"12\" x2=\"16\" y2=\"12\"/><line x1=\"6\" y1=\"16\" x2=\"18\" y2=\"16\"/></svg>`,\n};\n\n// ─── Styles (CSS custom properties) ──────────────────────\n\nconst STYLES = `\n /* ── Shadow Boundary Reset ──\n * Cuts ALL inherited CSS from host page (color, font, line-height, etc.)\n * Every element below must declare its own styles explicitly. */\n :host {\n all: initial !important;\n display: block !important;\n position: fixed !important;\n inset: 0 !important;\n pointer-events: none !important;\n z-index: 2147483640 !important;\n visibility: visible !important;\n }\n\n /* ── FAB ── */\n .bs-fab {\n all: initial;\n pointer-events: auto;\n position: fixed;\n bottom: 24px;\n z-index: 2147483647;\n width: 56px;\n height: 56px;\n border-radius: var(--bs-radius);\n background: linear-gradient(135deg, var(--bs-fab1), var(--bs-fab2));\n color: #fff;\n cursor: grab;\n box-shadow: 0 4px 24px rgba(0,0,0,0.3), 0 0 0 0 rgba(0,0,0,0.15);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.35s cubic-bezier(0.34,1.56,0.64,1);\n animation: bs-pulse 3s ease-in-out infinite;\n touch-action: none;\n user-select: none;\n -webkit-user-select: none;\n }\n .bs-fab.bs-dragging {\n cursor: grabbing;\n transition: none;\n animation: none;\n }\n .bs-fab:hover {\n transform: scale(1.08) translateY(-2px);\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\n animation: none;\n }\n .bs-fab:active { transform: scale(0.95); }\n .bs-fab.bs-open {\n animation: none;\n transform: rotate(45deg) scale(0.9);\n box-shadow: 0 2px 12px rgba(0,0,0,0.3);\n }\n .bs-fab.bs-open:hover { transform: rotate(45deg) scale(1); }\n @keyframes bs-pulse {\n 0%, 100% { box-shadow: 0 4px 24px rgba(0,0,0,0.3), 0 0 0 0 rgba(0,0,0,0.15); }\n 50% { box-shadow: 0 4px 24px rgba(0,0,0,0.3), 0 0 0 10px rgba(0,0,0,0); }\n }\n .bs-fab-label {\n position: absolute;\n right: calc(100% + 12px);\n background: var(--bs-bg2);\n color: var(--bs-text);\n font-family: 'Inter', sans-serif;\n font-size: 13px;\n font-weight: 500;\n padding: 8px 14px;\n border-radius: var(--bs-radius-sm);\n white-space: nowrap;\n box-shadow: 0 4px 20px rgba(0,0,0,0.3);\n opacity: 0;\n transform: translateX(8px);\n transition: all 0.25s ease;\n pointer-events: none;\n }\n .bs-fab:hover .bs-fab-label { opacity: 1; transform: translateX(0); }\n .bs-fab-label::after {\n content: '';\n position: absolute;\n right: -6px;\n top: 50%;\n transform: translateY(-50%);\n border: 6px solid transparent;\n border-left-color: var(--bs-bg2);\n border-right: none;\n }\n\n /* ── Quick Action Toolbar ── */\n .bs-toolbar {\n pointer-events: auto;\n position: fixed;\n z-index: 2147483646;\n display: flex;\n flex-direction: column;\n gap: 6px;\n bottom: 88px;\n opacity: 0;\n transform: translateY(10px);\n transition: all 0.3s cubic-bezier(0.34,1.56,0.64,1);\n pointer-events: none;\n }\n .bs-toolbar.bs-show {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n }\n .bs-toolbar-btn {\n all: initial;\n width: 40px;\n height: 40px;\n border-radius: var(--bs-radius-sm);\n background: var(--bs-bg2);\n border: 1px solid var(--bs-border);\n color: var(--bs-muted);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n position: relative;\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n }\n .bs-toolbar-btn:hover { color: var(--bs-text); border-color: var(--bs-accent); background: var(--bs-bg3); }\n .bs-toolbar-btn.bs-active { color: var(--bs-accent); border-color: var(--bs-accent); }\n .bs-toolbar-tip {\n position: absolute;\n right: calc(100% + 8px);\n background: var(--bs-bg2);\n color: var(--bs-text);\n font-family: 'Inter', sans-serif;\n font-size: 11px;\n font-weight: 500;\n padding: 4px 8px;\n border-radius: 6px;\n white-space: nowrap;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n }\n .bs-toolbar-btn:hover .bs-toolbar-tip { opacity: 1; }\n .bs-toolbar-kbd {\n font-size: 9px;\n color: var(--bs-muted);\n margin-left: 4px;\n }\n\n /* ── Backdrop ── */\n .bs-backdrop {\n pointer-events: auto;\n position: fixed;\n inset: 0;\n z-index: 2147483644;\n background: rgba(0,0,0,0);\n backdrop-filter: blur(0px);\n transition: all 0.4s ease;\n pointer-events: none;\n }\n .bs-backdrop.bs-in {\n background: rgba(10,12,20,0.55);\n backdrop-filter: blur(6px);\n pointer-events: all;\n }\n\n /* ── Modal ── */\n .bs-modal {\n pointer-events: auto;\n position: fixed;\n z-index: 2147483645;\n top: 50%;\n left: 50%;\n width: 620px;\n height: 680px;\n max-width: calc(100vw - 32px);\n max-height: calc(100vh - 48px);\n background: var(--bs-bg);\n border: 1px solid var(--bs-border);\n border-radius: var(--bs-radius);\n box-shadow: 0 32px 80px rgba(0,0,0,0.55), 0 0 0 1px rgba(255,255,255,0.03) inset;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n font-family: 'Inter', -apple-system, sans-serif;\n transform: translate(-50%, -50%) scale(0.88);\n opacity: 0;\n transition: transform 0.4s cubic-bezier(0.34,1.56,0.64,1),\n opacity 0.3s ease,\n width 0.35s cubic-bezier(0.25,1,0.5,1),\n height 0.35s cubic-bezier(0.25,1,0.5,1);\n }\n .bs-modal.bs-in {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n .bs-modal.bs-out {\n transform: translate(-50%, -50%) scale(0.85);\n opacity: 0;\n transition: transform 0.3s cubic-bezier(0.4,0,1,1), opacity 0.25s ease;\n }\n\n /* ── Header ── */\n .bs-hdr {\n padding: 18px 22px 0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-shrink: 0;\n }\n .bs-logo {\n font-family: 'Comfortaa', cursive;\n font-weight: 700;\n font-size: 18px;\n background: linear-gradient(135deg, var(--bs-accent), #fff);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n }\n .bs-hdr-right {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .bs-pin-toggle {\n all: initial;\n cursor: pointer;\n padding: 5px 10px;\n border-radius: var(--bs-radius-sm);\n font-size: 11px;\n font-weight: 600;\n font-family: 'Inter', sans-serif;\n color: var(--bs-muted);\n border: 1px solid var(--bs-border);\n transition: all 0.2s;\n display: flex;\n align-items: center;\n gap: 5px;\n }\n .bs-pin-toggle:hover { color: var(--bs-text); border-color: var(--bs-accent); }\n .bs-pin-toggle.active {\n background: var(--bs-accent);\n color: #fff;\n border-color: var(--bs-accent);\n -webkit-text-fill-color: #fff;\n }\n .bs-hdr-icon {\n all: initial;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: var(--bs-radius-sm);\n color: var(--bs-muted);\n transition: all 0.2s;\n }\n .bs-hdr-icon:hover { color: var(--bs-text); background: var(--bs-bg3); }\n .bs-user-badge {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--bs-muted);\n font-family: 'Inter', sans-serif;\n }\n .bs-user-avatar {\n width: 22px;\n height: 22px;\n border-radius: 50%;\n background: linear-gradient(135deg, var(--bs-accent), var(--bs-accent2));\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 10px;\n font-weight: 700;\n color: #fff;\n }\n .bs-login-form {\n padding: 32px 24px;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n }\n .bs-login-logo {\n font-family: 'Comfortaa', cursive;\n font-weight: 700;\n font-size: 28px;\n background: linear-gradient(135deg, var(--bs-accent), #fff);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n margin-bottom: 4px;\n }\n .bs-login-subtitle {\n font-size: 13px;\n color: var(--bs-muted);\n margin-bottom: 8px;\n }\n .bs-login-input {\n width: 100%;\n max-width: 300px;\n padding: 10px 14px;\n border-radius: var(--bs-radius-sm);\n border: 1px solid var(--bs-border);\n background: var(--bs-bg2);\n color: var(--bs-text);\n font-size: 13px;\n font-family: 'Inter', sans-serif;\n outline: none;\n transition: border-color 0.2s;\n box-sizing: border-box;\n }\n .bs-login-input:focus { border-color: var(--bs-accent); }\n .bs-login-input::placeholder { color: var(--bs-muted); opacity: 0.6; }\n .bs-login-btn {\n width: 100%;\n max-width: 300px;\n padding: 10px;\n border-radius: var(--bs-radius-sm);\n border: none;\n background: linear-gradient(135deg, var(--bs-accent), var(--bs-accent2));\n color: #fff;\n font-size: 14px;\n font-weight: 600;\n font-family: 'Inter', sans-serif;\n cursor: pointer;\n transition: opacity 0.2s;\n }\n .bs-login-btn:hover { opacity: 0.9; }\n .bs-login-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n .bs-login-error {\n font-size: 12px;\n color: var(--bs-red);\n max-width: 300px;\n text-align: center;\n }\n .bs-login-logout {\n all: initial;\n cursor: pointer;\n font-size: 11px;\n color: var(--bs-muted);\n font-family: 'Inter', sans-serif;\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s;\n }\n .bs-login-logout:hover { color: var(--bs-red); }\n .bs-close-btn {\n all: initial;\n cursor: pointer;\n color: var(--bs-muted);\n padding: 6px;\n border-radius: var(--bs-radius-sm);\n display: flex;\n transition: all 0.2s;\n }\n .bs-close-btn:hover { color: var(--bs-text); background: var(--bs-bg3); }\n\n /* ── Tabs ── */\n .bs-tabs {\n display: flex;\n gap: 2px;\n padding: 12px 22px 0;\n position: relative;\n flex-shrink: 0;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n }\n .bs-tabs::-webkit-scrollbar { display: none; }\n .bs-tab {\n all: initial;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 10px 14px;\n border-radius: var(--bs-radius-sm) var(--bs-radius-sm) 0 0;\n font-family: 'Inter', sans-serif;\n font-size: 12px;\n font-weight: 600;\n color: var(--bs-muted);\n transition: all 0.25s ease;\n position: relative;\n white-space: nowrap;\n flex-shrink: 0;\n }\n .bs-tab:hover { color: var(--bs-text); background: var(--bs-bg2); }\n .bs-tab.bs-active {\n color: var(--bs-accent);\n background: var(--bs-bg2);\n }\n .bs-tab.bs-active::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 8px;\n right: 8px;\n height: 2px;\n background: var(--bs-accent);\n border-radius: 2px 2px 0 0;\n animation: bs-tabIn 0.25s ease;\n }\n @keyframes bs-tabIn { from { transform: scaleX(0); } to { transform: scaleX(1); } }\n .bs-tab-badge {\n font-size: 10px;\n font-weight: 700;\n padding: 1px 6px;\n border-radius: 10px;\n background: var(--bs-bg3);\n color: var(--bs-muted);\n line-height: 1.4;\n }\n .bs-tab.bs-active .bs-tab-badge { background: var(--bs-accent); color: #fff; }\n .bs-tab-badge.bs-warn { background: var(--bs-red); color: #fff; }\n .bs-tab-divider {\n height: 1px;\n background: var(--bs-border);\n flex-shrink: 0;\n }\n\n /* ── Scrollable Body ── */\n .bs-scroll {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 16px 22px 22px;\n overscroll-behavior: contain;\n }\n .bs-scroll::-webkit-scrollbar { width: 5px; }\n .bs-scroll::-webkit-scrollbar-track { background: transparent; }\n .bs-scroll::-webkit-scrollbar-thumb { background: var(--bs-border); border-radius: 4px; }\n\n /* ── View slide animation ── */\n .bs-view { animation: bs-slideUp 0.3s cubic-bezier(0.22,1,0.36,1); }\n @keyframes bs-slideUp {\n from { opacity: 0; transform: translateY(12px); }\n to { opacity: 1; transform: translateY(0); }\n }\n\n /* ── Form ── */\n .bs-field { margin-bottom: 16px; }\n .bs-field-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--bs-text);\n margin-bottom: 7px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .bs-field-hint { font-size: 11px; font-weight: 400; color: var(--bs-muted); }\n .bs-input, .bs-textarea {\n width: 100%;\n padding: 11px 14px;\n border: 1.5px solid var(--bs-border);\n border-radius: var(--bs-radius-sm);\n font-size: 14px;\n font-family: 'Inter', sans-serif;\n background: var(--bs-bg2);\n color: var(--bs-text);\n box-sizing: border-box;\n transition: all 0.2s ease;\n -webkit-appearance: none;\n }\n .bs-input::placeholder, .bs-textarea::placeholder { color: var(--bs-muted); opacity: 0.5; }\n .bs-input:focus, .bs-textarea:focus {\n outline: none;\n border-color: var(--bs-accent);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--bs-accent) 15%, transparent);\n }\n .bs-textarea { resize: vertical; min-height: 76px; line-height: 1.5; }\n /* ── Severity ── */\n .bs-sev-row { display: flex; gap: 8px; }\n .bs-sev-btn {\n all: initial;\n flex: 1;\n padding: 10px 0;\n border-radius: var(--bs-radius-sm);\n text-align: center;\n font-size: 12px;\n font-weight: 600;\n font-family: 'Inter', sans-serif;\n cursor: pointer;\n transition: all 0.25s ease;\n position: relative;\n }\n .bs-sev-btn.bs-sev-low { background: color-mix(in srgb, var(--bs-green) 8%, transparent); color: var(--bs-green); border: 1.5px solid color-mix(in srgb, var(--bs-green) 15%, transparent); }\n .bs-sev-btn.bs-sev-medium { background: color-mix(in srgb, var(--bs-yellow) 8%, transparent); color: var(--bs-yellow); border: 1.5px solid color-mix(in srgb, var(--bs-yellow) 15%, transparent); }\n .bs-sev-btn.bs-sev-high { background: color-mix(in srgb, var(--bs-orange) 8%, transparent); color: var(--bs-orange); border: 1.5px solid color-mix(in srgb, var(--bs-orange) 15%, transparent); }\n .bs-sev-btn.bs-sev-critical { background: color-mix(in srgb, var(--bs-red) 8%, transparent); color: var(--bs-red); border: 1.5px solid color-mix(in srgb, var(--bs-red) 15%, transparent); }\n .bs-sev-btn:hover { transform: translateY(-1px); }\n .bs-sev-btn:active { transform: scale(0.96); }\n .bs-sev-btn.bs-picked { box-shadow: 0 0 0 2px currentColor; transform: translateY(-1px); }\n .bs-sev-btn.bs-picked::after {\n content: '';\n position: absolute;\n top: 4px;\n right: 6px;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: currentColor;\n animation: bs-pop 0.3s cubic-bezier(0.34,1.56,0.64,1);\n }\n @keyframes bs-pop { from { transform: scale(0); } to { transform: scale(1); } }\n\n /* ── Screenshot ── */\n .bs-shot-area {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n background: var(--bs-bg2);\n border: 1.5px dashed var(--bs-border);\n border-radius: var(--bs-radius-sm);\n margin-bottom: 16px;\n cursor: pointer;\n transition: all 0.25s ease;\n }\n .bs-shot-area:hover { border-color: var(--bs-accent); border-style: solid; background: var(--bs-bg3); }\n .bs-shot-area:active { transform: scale(0.98); }\n .bs-shot-icon {\n width: 40px;\n height: 40px;\n border-radius: var(--bs-radius-sm);\n background: color-mix(in srgb, var(--bs-accent) 12%, transparent);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--bs-accent);\n flex-shrink: 0;\n }\n .bs-shot-text { flex: 1; }\n .bs-shot-title { font-size: 13px; font-weight: 600; color: var(--bs-text); }\n .bs-shot-sub { font-size: 11px; color: var(--bs-muted); margin-top: 2px; }\n .bs-shot-area.bs-captured { border-style: solid; border-color: var(--bs-green); }\n .bs-shot-area.bs-captured .bs-shot-icon { background: color-mix(in srgb, var(--bs-green) 12%, transparent); color: var(--bs-green); }\n\n /* ── Category Chips ── */\n .bs-cat-row { display: flex; flex-wrap: wrap; gap: 6px; }\n .bs-cat-btn {\n all: initial;\n padding: 7px 14px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 600;\n font-family: 'Inter', sans-serif;\n cursor: pointer;\n transition: all 0.2s ease;\n background: var(--bs-bg2);\n color: var(--bs-muted);\n border: 1.5px solid var(--bs-border);\n }\n .bs-cat-btn:hover { color: var(--bs-text); border-color: var(--bs-accent); }\n .bs-cat-btn.bs-picked {\n background: color-mix(in srgb, var(--bs-accent) 12%, transparent);\n color: var(--bs-accent);\n border-color: var(--bs-accent);\n }\n\n /* ── Context Bar ── */\n .bs-ctx-bar {\n display: flex;\n gap: 2px;\n margin-bottom: 16px;\n background: var(--bs-bg2);\n border-radius: var(--bs-radius-sm);\n padding: 3px;\n border: 1px solid var(--bs-border);\n }\n .bs-ctx-chip {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n padding: 8px 4px;\n border-radius: calc(var(--bs-radius-sm) - 2px);\n transition: background 0.2s;\n }\n .bs-ctx-chip.bs-has { background: var(--bs-bg3); }\n .bs-ctx-chip.bs-alert { background: color-mix(in srgb, var(--bs-red) 8%, transparent); }\n .bs-ctx-n {\n font-size: 15px;\n font-weight: 700;\n color: var(--bs-text);\n line-height: 1;\n }\n .bs-ctx-chip.bs-alert .bs-ctx-n { color: var(--bs-red); }\n .bs-ctx-l {\n font-size: 9px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: var(--bs-muted);\n }\n\n /* ── Report Summary Bar ── */\n .bs-report-summary {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n border-radius: var(--bs-radius-sm);\n background: var(--bs-bg2);\n border: 1px solid var(--bs-border);\n margin-bottom: 16px;\n font-size: 12px;\n color: var(--bs-muted);\n }\n .bs-report-summary.bs-alert {\n background: color-mix(in srgb, var(--bs-red) 6%, transparent);\n border-color: color-mix(in srgb, var(--bs-red) 15%, transparent);\n color: var(--bs-red);\n }\n .bs-report-summary.bs-has { color: var(--bs-text); }\n .bs-report-summary-left { display: flex; align-items: center; gap: 8px; }\n .bs-report-summary-icon {\n width: 22px; height: 22px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--bs-green) 12%, transparent);\n color: var(--bs-green);\n display: flex; align-items: center; justify-content: center;\n font-size: 10px; flex-shrink: 0;\n }\n .bs-report-summary-icon.bs-warn {\n background: color-mix(in srgb, var(--bs-red) 12%, transparent);\n color: var(--bs-red);\n font-weight: 800; font-size: 12px;\n }\n .bs-input-title {\n font-size: 16px !important;\n font-weight: 600;\n padding: 14px !important;\n }\n\n .bs-auto-step-n {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--bs-accent) 15%, transparent);\n color: var(--bs-accent);\n font-size: 10px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n .bs-auto-muted {\n font-size: 12px;\n color: var(--bs-muted);\n padding: 6px 0;\n }\n\n /* ── Submit ── */\n .bs-submit-btn {\n all: initial;\n width: 100%;\n padding: 14px;\n background: linear-gradient(135deg, var(--bs-fab1), var(--bs-fab2));\n color: #fff;\n border-radius: var(--bs-radius-sm);\n font-size: 15px;\n font-weight: 700;\n font-family: 'Inter', sans-serif;\n cursor: pointer;\n text-align: center;\n box-sizing: border-box;\n transition: all 0.3s ease;\n position: relative;\n overflow: hidden;\n }\n .bs-submit-btn:hover { box-shadow: 0 8px 28px rgba(0,0,0,0.3); transform: translateY(-1px); }\n .bs-submit-btn:active { transform: translateY(0) scale(0.98); }\n .bs-submit-btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none !important; box-shadow: none !important; }\n .bs-submit-btn.bs-submit-ok {\n background: var(--bs-green) !important;\n opacity: 1 !important;\n display: flex; align-items: center; justify-content: center; gap: 6px;\n }\n .bs-submit-btn.bs-submit-err {\n background: var(--bs-red) !important;\n opacity: 1 !important;\n font-size: 13px;\n }\n\n /* ── Console ── */\n .bs-log {\n padding: 8px 10px;\n border-radius: var(--bs-radius-sm);\n margin-bottom: 4px;\n font-family: 'SF Mono', 'Fira Code', monospace;\n font-size: 11.5px;\n line-height: 1.5;\n display: flex;\n gap: 8px;\n align-items: flex-start;\n transition: background 0.15s;\n }\n .bs-log:hover { background: var(--bs-bg2); }\n .bs-log-lv {\n font-weight: 700;\n text-transform: uppercase;\n font-size: 9px;\n padding: 3px 6px;\n border-radius: 5px;\n flex-shrink: 0;\n margin-top: 2px;\n letter-spacing: 0.4px;\n }\n .bs-log-lv.bs-le { background: color-mix(in srgb, var(--bs-red) 12%, transparent); color: var(--bs-red); }\n .bs-log-lv.bs-lw { background: color-mix(in srgb, var(--bs-orange) 10%, transparent); color: var(--bs-orange); }\n .bs-log-lv.bs-ll { background: var(--bs-bg3); color: var(--bs-muted); }\n .bs-log-lv.bs-li { background: color-mix(in srgb, var(--bs-accent) 10%, transparent); color: var(--bs-accent); }\n .bs-log-lv.bs-ld { background: var(--bs-bg2); color: var(--bs-muted); }\n .bs-log-m { color: var(--bs-text); word-break: break-word; flex: 1; white-space: pre-wrap; }\n .bs-log-t { color: var(--bs-muted); opacity: 0.5; flex-shrink: 0; font-size: 10px; margin-top: 3px; }\n\n /* ── Network ── */\n .bs-net {\n padding: 9px 10px;\n border-radius: var(--bs-radius-sm);\n margin-bottom: 4px;\n font-family: 'SF Mono', 'Fira Code', monospace;\n font-size: 11.5px;\n display: flex;\n gap: 8px;\n align-items: center;\n transition: background 0.15s;\n }\n .bs-net:hover { background: var(--bs-bg2); }\n .bs-net-m { font-weight: 700; font-size: 10px; color: var(--bs-accent); flex-shrink: 0; width: 34px; }\n .bs-net-s { font-weight: 700; font-size: 10px; padding: 3px 7px; border-radius: 5px; flex-shrink: 0; }\n .bs-net-s.bs-ok { background: color-mix(in srgb, var(--bs-green) 10%, transparent); color: var(--bs-green); }\n .bs-net-s.bs-fail { background: color-mix(in srgb, var(--bs-red) 10%, transparent); color: var(--bs-red); }\n .bs-net-u { color: var(--bs-text); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .bs-net-d { color: var(--bs-muted); opacity: 0.5; flex-shrink: 0; font-size: 10px; }\n\n /* ── Context: Errors ── */\n .bs-err-card {\n padding: 12px 14px;\n margin-bottom: 8px;\n background: color-mix(in srgb, var(--bs-red) 6%, transparent);\n border: 1px solid color-mix(in srgb, var(--bs-red) 10%, transparent);\n border-radius: var(--bs-radius-sm);\n transition: border-color 0.2s;\n }\n .bs-err-card:hover { border-color: color-mix(in srgb, var(--bs-red) 20%, transparent); }\n .bs-err-m { color: var(--bs-red); font-weight: 600; font-size: 13px; margin-bottom: 6px; line-height: 1.4; }\n .bs-err-stack {\n font-family: 'SF Mono', monospace;\n font-size: 10px;\n color: var(--bs-muted);\n white-space: pre-wrap;\n max-height: 72px;\n overflow-y: auto;\n line-height: 1.5;\n }\n .bs-err-meta { font-size: 10px; color: var(--bs-muted); margin-top: 6px; }\n\n /* ── Context: Section Title ── */\n .bs-sec {\n font-size: 10px;\n font-weight: 700;\n color: var(--bs-accent);\n text-transform: uppercase;\n letter-spacing: 0.8px;\n margin: 20px 0 10px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--bs-border);\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .bs-sec:first-child { margin-top: 0; }\n .bs-sec-n {\n background: var(--bs-bg3);\n color: var(--bs-muted);\n font-size: 9px;\n padding: 2px 6px;\n border-radius: 5px;\n }\n\n /* ── KV Grid ── */\n .bs-kv {\n display: grid;\n grid-template-columns: 100px 1fr;\n gap: 7px 12px;\n font-size: 12px;\n }\n .bs-kv-k { color: var(--bs-muted); font-size: 11px; }\n .bs-kv-v { color: var(--bs-text); word-break: break-all; font-size: 11px; }\n\n /* ── Breadcrumbs ── */\n .bs-bc {\n padding: 7px 10px;\n border-radius: 8px;\n margin-bottom: 3px;\n font-size: 11px;\n display: flex;\n gap: 8px;\n align-items: flex-start;\n transition: background 0.15s;\n }\n .bs-bc:hover { background: var(--bs-bg2); }\n .bs-bc-t {\n font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;\n padding: 3px 6px; border-radius: 5px; flex-shrink: 0;\n background: var(--bs-bg3); color: var(--bs-muted);\n }\n .bs-bc-t.bs-t-click { color: var(--bs-accent); background: color-mix(in srgb, var(--bs-accent) 10%, transparent); }\n .bs-bc-t.bs-t-input { color: var(--bs-green); background: color-mix(in srgb, var(--bs-green) 10%, transparent); }\n .bs-bc-t.bs-t-navigation { color: var(--bs-accent2); background: color-mix(in srgb, var(--bs-accent2) 10%, transparent); }\n .bs-bc-t.bs-t-error { color: var(--bs-red); background: color-mix(in srgb, var(--bs-red) 10%, transparent); }\n .bs-bc-t.bs-t-network { color: var(--bs-orange); background: color-mix(in srgb, var(--bs-orange) 10%, transparent); }\n .bs-bc-t.bs-t-console { color: var(--bs-yellow); background: color-mix(in srgb, var(--bs-yellow) 10%, transparent); }\n .bs-bc-t.bs-t-custom { color: var(--bs-accent); background: color-mix(in srgb, var(--bs-accent) 10%, transparent); }\n .bs-bc-m { color: var(--bs-text); flex: 1; line-height: 1.4; }\n .bs-bc-time { color: var(--bs-muted); opacity: 0.5; font-size: 10px; flex-shrink: 0; }\n\n /* ── Performance ── */\n .bs-pf { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }\n .bs-pf-l { font-size: 11px; color: var(--bs-muted); width: 85px; flex-shrink: 0; }\n .bs-pf-tr { flex: 1; height: 6px; background: var(--bs-bg3); border-radius: 4px; overflow: hidden; }\n .bs-pf-fl { height: 100%; border-radius: 4px; background: linear-gradient(90deg, var(--bs-accent), var(--bs-accent2)); transition: width 0.6s cubic-bezier(0.34,1.56,0.64,1); }\n .bs-pf-fl.bs-slow { background: linear-gradient(90deg, var(--bs-orange), var(--bs-red)); }\n .bs-pf-v { font-size: 11px; font-weight: 600; color: var(--bs-text); width: 55px; text-align: right; flex-shrink: 0; }\n\n /* ── Annotation ── */\n .bs-ann-wrap { position: relative; margin-bottom: 16px; border-radius: var(--bs-radius-sm); overflow: hidden; border: 1.5px solid var(--bs-border); animation: bs-slideUp 0.3s ease; }\n .bs-ann-viewport { overflow: hidden; position: relative; }\n .bs-ann-canvas { display: block; width: 100%; transform-origin: 0 0; transition: transform 0.15s ease; }\n .bs-ann-canvas.bs-select { cursor: default; }\n .bs-ann-canvas.bs-draw { cursor: crosshair; }\n .bs-ann-canvas.bs-arrow { cursor: crosshair; }\n .bs-ann-canvas.bs-rect { cursor: crosshair; }\n .bs-ann-canvas.bs-circle { cursor: crosshair; }\n .bs-ann-canvas.bs-text { cursor: text; }\n .bs-ann-canvas.bs-highlight { cursor: crosshair; }\n .bs-ann-canvas.bs-grab { cursor: grab; }\n .bs-ann-canvas.bs-grabbing { cursor: grabbing; }\n .bs-ann-toolbar { display: flex; gap: 2px; padding: 6px 8px; background: var(--bs-bg2); border-top: 1px solid var(--bs-border); align-items: center; flex-wrap: wrap; }\n .bs-ann-sep { width: 1px; height: 20px; background: var(--bs-border); margin: 0 4px; flex-shrink: 0; }\n .bs-ann-btn {\n all: initial; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center;\n border-radius: 6px; cursor: pointer; color: var(--bs-muted); transition: all 0.15s; font-size: 14px;\n }\n .bs-ann-btn:hover { background: var(--bs-bg3); color: var(--bs-text); }\n .bs-ann-btn.bs-sel { background: color-mix(in srgb, var(--bs-accent) 15%, transparent); color: var(--bs-accent); }\n .bs-ann-btn[title]::after { content: none; }\n .bs-ann-dot {\n width: 20px; height: 20px; border-radius: 50%; border: 2.5px solid transparent; cursor: pointer;\n transition: all 0.15s; flex-shrink: 0;\n }\n .bs-ann-dot:hover { transform: scale(1.15); }\n .bs-ann-dot.bs-sel { border-color: var(--bs-text); transform: scale(1.15); box-shadow: 0 0 8px rgba(255,255,255,0.15); }\n .bs-ann-size {\n width: 60px; height: 4px; -webkit-appearance: none; appearance: none; background: var(--bs-border);\n border-radius: 2px; outline: none; cursor: pointer;\n }\n .bs-ann-size::-webkit-slider-thumb {\n -webkit-appearance: none; width: 14px; height: 14px; border-radius: 50%;\n background: var(--bs-accent); cursor: pointer; border: 2px solid var(--bs-bg);\n }\n .bs-ann-zoom-label { font-size: 10px; font-weight: 600; color: var(--bs-muted); min-width: 32px; text-align: center; }\n .bs-ann-right { margin-left: auto; display: flex; gap: 2px; align-items: center; }\n .bs-ann-clr-btn {\n all: initial; padding: 3px 10px; border: 1px solid var(--bs-border); border-radius: 6px;\n color: var(--bs-muted); font-size: 10px; cursor: pointer; font-family: 'Inter', sans-serif; transition: all 0.15s;\n }\n .bs-ann-clr-btn:hover { color: var(--bs-red); border-color: color-mix(in srgb, var(--bs-red) 30%, transparent); }\n\n /* ── Pin Tool ── */\n .bs-ann-canvas.bs-pin { cursor: crosshair; }\n .bs-ann-pins { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; }\n .bs-ann-pin {\n position: absolute;\n width: 26px; height: 26px;\n border-radius: 50% 50% 50% 0;\n transform: translate(-50%, -100%) rotate(-45deg);\n display: flex; align-items: center; justify-content: center;\n font-size: 11px; font-weight: 700; font-family: 'Inter', sans-serif;\n color: #fff;\n pointer-events: all;\n cursor: grab;\n transition: transform 0.15s, box-shadow 0.15s;\n box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n z-index: 1;\n }\n .bs-ann-pin:hover { transform: translate(-50%, -100%) rotate(-45deg) scale(1.15); box-shadow: 0 4px 16px rgba(0,0,0,0.4); z-index: 2; }\n .bs-ann-pin.bs-dragging { cursor: grabbing; transform: translate(-50%, -100%) rotate(-45deg) scale(1.2); z-index: 3; }\n .bs-ann-pin-n { transform: rotate(45deg); line-height: 1; }\n .bs-ann-pin-pulse {\n position: absolute; inset: -4px; border-radius: 50% 50% 50% 0;\n border: 2px solid currentColor; opacity: 0;\n animation: bs-pin-ring 1.5s ease-out forwards;\n }\n @keyframes bs-pin-ring { 0% { opacity: 0.6; inset: -4px; } 100% { opacity: 0; inset: -14px; } }\n\n /* ── Pin List (below canvas) ── */\n .bs-ann-pin-list {\n max-height: 140px;\n overflow-y: auto;\n border-top: 1px solid var(--bs-border);\n background: var(--bs-bg2);\n }\n .bs-ann-pin-item {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 8px 12px;\n border-bottom: 1px solid color-mix(in srgb, var(--bs-border) 50%, transparent);\n font-size: 12px;\n color: var(--bs-text);\n }\n .bs-ann-pin-item:last-child { border-bottom: none; }\n .bs-ann-pin-num {\n width: 22px; height: 22px;\n border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 11px; font-weight: 700; color: #fff;\n flex-shrink: 0;\n }\n .bs-ann-pin-body { flex: 1; min-width: 0; }\n .bs-ann-pin-note { word-break: break-word; line-height: 1.4; }\n .bs-ann-pin-loc { font-size: 10px; color: var(--bs-muted); margin-top: 2px; }\n .bs-ann-pin-del {\n all: initial; cursor: pointer; color: var(--bs-muted); font-size: 14px;\n padding: 2px 4px; border-radius: 4px; transition: color 0.15s;\n flex-shrink: 0;\n }\n .bs-ann-pin-del:hover { color: var(--bs-red); }\n\n /* ── History ── */\n .bs-hist-card {\n background: var(--bs-bg2);\n border: 1px solid var(--bs-border);\n border-radius: var(--bs-radius-sm);\n padding: 14px;\n margin-bottom: 10px;\n transition: border-color 0.2s;\n }\n .bs-hist-card:hover { border-color: var(--bs-accent); }\n .bs-hist-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; margin-bottom: 8px; }\n .bs-hist-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--bs-text);\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .bs-hist-actions { display: flex; gap: 4px; flex-shrink: 0; }\n .bs-hist-btn {\n all: initial;\n width: 26px; height: 26px;\n display: flex; align-items: center; justify-content: center;\n border-radius: 6px;\n cursor: pointer;\n color: var(--bs-muted);\n transition: all 0.15s;\n font-size: 12px;\n }\n .bs-hist-btn:hover { background: var(--bs-bg3); color: var(--bs-text); }\n .bs-hist-btn.bs-del:hover { color: var(--bs-red); }\n .bs-hist-meta { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 6px; }\n .bs-hist-badge {\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n }\n .bs-hist-badge.bs-sev-low { background: color-mix(in srgb, var(--bs-green) 12%, transparent); color: var(--bs-green); }\n .bs-hist-badge.bs-sev-medium { background: color-mix(in srgb, var(--bs-yellow) 12%, transparent); color: var(--bs-yellow); }\n .bs-hist-badge.bs-sev-high { background: color-mix(in srgb, var(--bs-orange) 12%, transparent); color: var(--bs-orange); }\n .bs-hist-badge.bs-sev-critical { background: color-mix(in srgb, var(--bs-red) 12%, transparent); color: var(--bs-red); }\n .bs-hist-badge.bs-cat { background: color-mix(in srgb, var(--bs-accent) 12%, transparent); color: var(--bs-accent); }\n .bs-hist-badge.bs-status-sent { background: color-mix(in srgb, var(--bs-green) 12%, transparent); color: var(--bs-green); }\n .bs-hist-badge.bs-status-draft { background: color-mix(in srgb, var(--bs-yellow) 12%, transparent); color: var(--bs-yellow); }\n .bs-hist-desc { font-size: 12px; color: var(--bs-muted); line-height: 1.5; margin-bottom: 6px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }\n .bs-hist-foot { display: flex; justify-content: space-between; align-items: center; font-size: 10px; color: var(--bs-muted); }\n .bs-hist-pins { display: flex; gap: 4px; }\n .bs-hist-pin-dot { width: 18px; height: 18px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 700; color: #fff; }\n .bs-hist-thumb { width: 40px; height: 40px; border-radius: 6px; object-fit: cover; border: 1px solid var(--bs-border); flex-shrink: 0; }\n .bs-hist-confirm {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 14px;\n background: color-mix(in srgb, var(--bs-red) 8%, transparent);\n border: 1px solid color-mix(in srgb, var(--bs-red) 20%, transparent);\n border-radius: var(--bs-radius-sm);\n margin-bottom: 10px;\n font-size: 12px; color: var(--bs-text);\n animation: bs-slideUp 0.2s ease;\n }\n .bs-hist-confirm-yes {\n all: initial; padding: 4px 12px; background: var(--bs-red); color: #fff; border-radius: 6px;\n font-size: 11px; font-weight: 600; cursor: pointer; font-family: 'Inter', sans-serif;\n }\n .bs-hist-confirm-no {\n all: initial; padding: 4px 12px; border: 1px solid var(--bs-border); border-radius: 6px;\n font-size: 11px; font-weight: 600; cursor: pointer; color: var(--bs-muted); font-family: 'Inter', sans-serif;\n }\n .bs-hist-edit-wrap { margin-bottom: 10px; animation: bs-slideUp 0.2s ease; }\n .bs-hist-edit-row { display: flex; gap: 6px; margin-top: 8px; }\n .bs-hist-save {\n all: initial; padding: 6px 16px; background: linear-gradient(135deg, var(--bs-fab1), var(--bs-fab2));\n color: #fff; border-radius: 6px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: 'Inter', sans-serif;\n }\n .bs-hist-cancel {\n all: initial; padding: 6px 16px; border: 1px solid var(--bs-border); border-radius: 6px;\n font-size: 12px; font-weight: 600; cursor: pointer; color: var(--bs-muted); font-family: 'Inter', sans-serif;\n }\n\n /* ── Empty ── */\n .bs-empty { text-align: center; padding: 36px 16px; color: var(--bs-muted); font-size: 13px; line-height: 1.6; }\n .bs-empty svg { opacity: 0.12; margin-bottom: 10px; }\n\n /* ── Settings ── */\n .bs-set-sec {\n font-size: 11px;\n font-weight: 700;\n color: var(--bs-accent);\n text-transform: uppercase;\n letter-spacing: 0.8px;\n margin: 0 0 12px;\n }\n .bs-set-sec + .bs-set-sec { margin-top: 24px; }\n .bs-set-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));\n gap: 8px;\n }\n .bs-set-card {\n all: initial;\n cursor: pointer;\n border: 2px solid var(--bs-border);\n border-radius: var(--bs-radius-sm);\n overflow: hidden;\n transition: all 0.2s ease;\n display: flex;\n flex-direction: column;\n }\n .bs-set-card:hover { border-color: var(--bs-accent); transform: translateY(-1px); }\n .bs-set-card.bs-picked { border-color: var(--bs-accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--bs-accent) 25%, transparent); }\n .bs-set-preview {\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n }\n .bs-set-dot {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n border: 1px solid rgba(255,255,255,0.1);\n }\n .bs-set-name {\n padding: 6px 8px;\n font-family: 'Inter', sans-serif;\n font-size: 10px;\n font-weight: 600;\n text-align: center;\n color: var(--bs-text);\n background: var(--bs-bg2);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .bs-set-ly-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));\n gap: 8px;\n }\n .bs-set-ly {\n all: initial;\n cursor: pointer;\n border: 2px solid var(--bs-border);\n border-radius: var(--bs-radius-sm);\n padding: 10px 12px;\n transition: all 0.2s ease;\n font-family: 'Inter', sans-serif;\n }\n .bs-set-ly:hover { border-color: var(--bs-accent); transform: translateY(-1px); }\n .bs-set-ly.bs-picked { border-color: var(--bs-accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--bs-accent) 25%, transparent); }\n .bs-set-ly-name { font-size: 12px; font-weight: 600; color: var(--bs-text); margin-bottom: 2px; }\n .bs-set-ly-desc { font-size: 10px; color: var(--bs-muted); }\n`;\n\n// ─── Login Tab ───────────────────────────────────────────\n\nfunction tabLogin(): string {\n return `\n <div class=\"bs-login-form\">\n <div class=\"bs-login-logo\">BugStash</div>\n <div class=\"bs-login-subtitle\">Sign in to report bugs & collaborate</div>\n <input class=\"bs-login-input\" type=\"email\" id=\"bs-login-email\" placeholder=\"Email\" autocomplete=\"email\" />\n <input class=\"bs-login-input\" type=\"password\" id=\"bs-login-pass\" placeholder=\"Password\" autocomplete=\"current-password\" />\n <div class=\"bs-login-error\" id=\"bs-login-error\" style=\"display:none\"></div>\n <button class=\"bs-login-btn\" id=\"bs-login-submit\">Sign In</button>\n <div style=\"font-size:11px;color:var(--bs-muted);margin-top:4px\">Contact your admin for an account</div>\n </div>\n `;\n}\n\n// ─── Helpers ─────────────────────────────────────────────\n\nfunction esc(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n}\nfunction timeAgo(ts: number): string {\n const s = Math.floor((Date.now() - ts) / 1000);\n if (s < 5) return 'now';\n if (s < 60) return `${s}s ago`;\n if (s < 3600) return `${Math.floor(s / 60)}m ago`;\n return new Date(ts).toLocaleTimeString();\n}\nfunction fmtTime(ts: number): string {\n return new Date(ts).toLocaleTimeString('en', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\n// ─── Report History (localStorage) ───────────────────────\n\nconst HISTORY_KEY = 'bugstash_history';\n\ninterface HistoryEntry {\n id: number;\n title: string;\n description: string;\n category: string;\n severity: string;\n tags?: string[];\n screenshot?: string;\n pins?: { number: number; x: number; y: number; note: string }[];\n url: string;\n createdAt: number;\n status: 'sent' | 'draft';\n}\n\nfunction getReportHistory(): HistoryEntry[] {\n try {\n return JSON.parse(localStorage.getItem(HISTORY_KEY) || '[]');\n } catch { return []; }\n}\n\nfunction saveReportHistory(entries: HistoryEntry[]) {\n try {\n localStorage.setItem(HISTORY_KEY, JSON.stringify(entries));\n } catch { /* quota exceeded */ }\n}\n\nfunction addToHistory(entry: Omit<HistoryEntry, 'id'>) {\n const entries = getReportHistory();\n const id = Date.now();\n entries.unshift({ ...entry, id });\n // Keep last 50\n if (entries.length > 50) entries.length = 50;\n saveReportHistory(entries);\n}\n\nfunction deleteFromHistory(id: number) {\n const entries = getReportHistory().filter(e => e.id !== id);\n saveReportHistory(entries);\n}\n\nfunction updateInHistory(id: number, updates: Partial<HistoryEntry>) {\n const entries = getReportHistory();\n const idx = entries.findIndex(e => e.id === id);\n if (idx >= 0) {\n entries[idx] = { ...entries[idx], ...updates };\n saveReportHistory(entries);\n }\n}\n\n// ─── Build Context ───────────────────────────────────────\n\nfunction buildContext(): ReportContext {\n return {\n url: window.location.href,\n userAgent: navigator.userAgent,\n platform: navigator.platform,\n language: navigator.language,\n cookiesEnabled: navigator.cookieEnabled,\n online: navigator.onLine,\n screenWidth: screen.width,\n screenHeight: screen.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n devicePixelRatio: window.devicePixelRatio,\n timestamp: Date.now(),\n environment: config.environment ?? 'development',\n commitHash: config.commitHash,\n user: config.user,\n };\n}\n\n// ─── Tab Content ─────────────────────────────────────────\n\nfunction autoDetect() {\n const errors = getErrors();\n const logs = getLogs();\n const net = getNetworkCaptures();\n const failedNet = getFailedNetworkCaptures();\n const crumbs = getBreadcrumbs();\n const perf = getPerformanceMetrics();\n const consoleErrors = logs.filter(l => l.level === 'error');\n\n // Auto-detect severity\n let severity: BugReport['severity'] = 'low';\n if (errors.length >= 3 || failedNet.length >= 3) severity = 'critical';\n else if (errors.length >= 1 || failedNet.length >= 2) severity = 'high';\n else if (consoleErrors.length > 0 || failedNet.length >= 1) severity = 'medium';\n\n // Auto-generate tags\n const tags: string[] = [];\n if (errors.length) tags.push('has-errors');\n if (failedNet.length) tags.push('network-failures');\n if (consoleErrors.length) tags.push('console-errors');\n if (perf?.pageLoadTime && perf.pageLoadTime > 3000) tags.push('slow-load');\n if (perf?.cumulativeLayoutShift && perf.cumulativeLayoutShift > 0.25) tags.push('layout-shift');\n if (!navigator.onLine) tags.push('offline');\n if (window.innerWidth < 768) tags.push('mobile');\n\n return { severity, tags,\n counts: { logs: logs.length, network: net.length, failedNet: failedNet.length, errors: errors.length, crumbs: crumbs.length } };\n}\n\nfunction tabReport(): string {\n const d = autoDetect();\n const categories: { id: BugReport['category']; label: string }[] = [\n { id: 'ui', label: 'UI' },\n { id: 'functionality', label: 'Feature' },\n { id: 'performance', label: 'Speed' },\n { id: 'crash', label: 'Crash' },\n { id: 'security', label: 'Security' },\n { id: 'other', label: 'Other' },\n ];\n\n const hasIssues = d.counts.errors > 0 || d.counts.failedNet > 0;\n const summaryClass = hasIssues ? ' bs-alert' : d.counts.logs > 0 ? ' bs-has' : '';\n\n return `<div class=\"bs-view\">\n <form data-bs-form>\n <div class=\"bs-report-summary${summaryClass}\">\n <div class=\"bs-report-summary-left\">\n ${hasIssues\n ? `<div class=\"bs-report-summary-icon bs-warn\">!</div><span>${d.counts.errors} error${d.counts.errors !== 1 ? 's' : ''}, ${d.counts.failedNet} failed request${d.counts.failedNet !== 1 ? 's' : ''} detected</span>`\n : `<div class=\"bs-report-summary-icon\">${I.check}</div><span>Auto-collecting ${d.counts.logs} logs, ${d.counts.network} requests, ${d.counts.crumbs} actions</span>`}\n </div>\n </div>\n <div class=\"bs-field\">\n <input class=\"bs-input bs-input-title\" name=\"title\" placeholder=\"What's the bug?\" required autocomplete=\"off\" />\n </div>\n <div class=\"bs-field\">\n <textarea class=\"bs-textarea\" name=\"description\" placeholder=\"Steps to reproduce or extra details (optional)\"></textarea>\n </div>\n <div class=\"bs-field\">\n <div class=\"bs-field-label\">Category</div>\n <input type=\"hidden\" name=\"category\" value=\"functionality\" />\n <div class=\"bs-cat-row\">\n ${categories.map(c => `<button type=\"button\" class=\"bs-cat-btn${c.id === 'functionality' ? ' bs-picked' : ''}\" data-cat=\"${c.id}\">${c.label}</button>`).join('')}\n </div>\n </div>\n <div class=\"bs-field\">\n <div class=\"bs-field-label\">Severity</div>\n <input type=\"hidden\" name=\"severity\" value=\"${d.severity}\" />\n <div class=\"bs-sev-row\">\n <button type=\"button\" class=\"bs-sev-btn bs-sev-low${d.severity === 'low' ? ' bs-picked' : ''}\" data-sev=\"low\">Low</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-medium${d.severity === 'medium' ? ' bs-picked' : ''}\" data-sev=\"medium\">Med</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-high${d.severity === 'high' ? ' bs-picked' : ''}\" data-sev=\"high\">High</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-critical${d.severity === 'critical' ? ' bs-picked' : ''}\" data-sev=\"critical\">Critical</button>\n </div>\n </div>\n <div class=\"bs-shot-area\" data-bs-screenshot>\n <div class=\"bs-shot-icon\">${I.cam}</div>\n <div class=\"bs-shot-text\">\n <div class=\"bs-shot-title\" data-bs-shot-title>Attach screenshot</div>\n <div class=\"bs-shot-sub\" data-bs-shot-sub>Capture & annotate the current view</div>\n </div>\n </div>\n <div data-bs-annotate></div>\n <button type=\"submit\" class=\"bs-submit-btn\">Submit Report</button>\n </form>\n </div>`;\n}\n\nfunction tabConsole(): string {\n const logs = getLogs();\n const lvMap: Record<string, string> = { error: 'bs-le', warn: 'bs-lw', log: 'bs-ll', info: 'bs-li', debug: 'bs-ld' };\n if (!logs.length) {\n return `<div class=\"bs-view\"><div class=\"bs-empty\"><p>No console logs captured yet.<br>Use the app — logs will appear here automatically.</p></div></div>`;\n }\n return `<div class=\"bs-view\">${logs.slice().reverse().map(l =>\n `<div class=\"bs-log\"><span class=\"bs-log-lv ${lvMap[l.level] || 'bs-ll'}\">${l.level}</span><span class=\"bs-log-m\">${esc(l.args.join(' ')).slice(0, 500)}</span><span class=\"bs-log-t\">${fmtTime(l.timestamp)}</span></div>`\n ).join('')}</div>`;\n}\n\nfunction tabNetwork(): string {\n const caps = getNetworkCaptures();\n if (!caps.length) {\n return `<div class=\"bs-view\"><div class=\"bs-empty\"><p>No network requests captured yet.<br>API calls will show up here automatically.</p></div></div>`;\n }\n return `<div class=\"bs-view\">${caps.slice().reverse().map(n =>\n `<div class=\"bs-net\"><span class=\"bs-net-m\">${n.method}</span><span class=\"bs-net-s ${n.failed ? 'bs-fail' : 'bs-ok'}\">${n.status || 'ERR'}</span><span class=\"bs-net-u\" title=\"${esc(n.url)}\">${esc(n.url)}</span><span class=\"bs-net-d\">${n.duration}ms</span></div>`\n ).join('')}</div>`;\n}\n\nfunction tabContext(): string {\n let html = `<div class=\"bs-view\">`;\n\n const errs = getErrors();\n if (errs.length) {\n html += `<div class=\"bs-sec\">Errors <span class=\"bs-sec-n\">${errs.length}</span></div>`;\n html += errs.slice().reverse().map(e =>\n `<div class=\"bs-err-card\"><div class=\"bs-err-m\">${esc(e.message)}</div>${e.stack ? `<div class=\"bs-err-stack\">${esc(e.stack)}</div>` : ''}<div class=\"bs-err-meta\">${e.type} &middot; ${fmtTime(e.timestamp)}${e.source ? ` &middot; ${esc(e.source)}:${e.lineno}` : ''}</div></div>`\n ).join('');\n }\n\n const perf = getPerformanceMetrics();\n if (perf) {\n html += `<div class=\"bs-sec\">Performance</div>`;\n const bars: [string, number | undefined, number][] = [\n ['Page Load', perf.pageLoadTime, 5000], ['DOM Ready', perf.domContentLoaded, 3000],\n ['First Paint', perf.firstPaint, 2000], ['FCP', perf.firstContentfulPaint, 2500],\n ['LCP', perf.largestContentfulPaint, 4000], ['FID', perf.firstInputDelay, 300],\n ];\n for (const [label, val, max] of bars) {\n if (val === undefined) continue;\n const pct = Math.min(100, (val / max) * 100);\n html += `<div class=\"bs-pf\"><span class=\"bs-pf-l\">${label}</span><div class=\"bs-pf-tr\"><div class=\"bs-pf-fl${pct > 75 ? ' bs-slow' : ''}\" style=\"width:${pct}%\"></div></div><span class=\"bs-pf-v\">${val}ms</span></div>`;\n }\n if (perf.cumulativeLayoutShift !== undefined) {\n const p = Math.min(100, perf.cumulativeLayoutShift * 400);\n html += `<div class=\"bs-pf\"><span class=\"bs-pf-l\">CLS</span><div class=\"bs-pf-tr\"><div class=\"bs-pf-fl${p > 40 ? ' bs-slow' : ''}\" style=\"width:${p}%\"></div></div><span class=\"bs-pf-v\">${perf.cumulativeLayoutShift}</span></div>`;\n }\n }\n\n const crumbs = getBreadcrumbs();\n if (crumbs.length) {\n html += `<div class=\"bs-sec\">Your activity trail <span class=\"bs-sec-n\">${crumbs.length}</span></div>`;\n html += crumbs.slice().reverse().map(b =>\n `<div class=\"bs-bc\"><span class=\"bs-bc-t bs-t-${b.type}\">${b.type}</span><span class=\"bs-bc-m\">${esc(b.message).slice(0, 120)}</span><span class=\"bs-bc-time\">${timeAgo(b.timestamp)}</span></div>`\n ).join('');\n }\n\n const ctx = buildContext();\n html += `<div class=\"bs-sec\">Environment</div>`;\n html += `<div class=\"bs-kv\">\n <span class=\"bs-kv-k\">URL</span><span class=\"bs-kv-v\">${esc(ctx.url)}</span>\n <span class=\"bs-kv-k\">Viewport</span><span class=\"bs-kv-v\">${ctx.viewportWidth}&times;${ctx.viewportHeight} @${ctx.devicePixelRatio}x</span>\n <span class=\"bs-kv-k\">Screen</span><span class=\"bs-kv-v\">${ctx.screenWidth}&times;${ctx.screenHeight}</span>\n <span class=\"bs-kv-k\">Platform</span><span class=\"bs-kv-v\">${esc(ctx.platform)}</span>\n <span class=\"bs-kv-k\">Language</span><span class=\"bs-kv-v\">${ctx.language}</span>\n ${config.commitHash ? `<span class=\"bs-kv-k\">Commit</span><span class=\"bs-kv-v\">${esc(config.commitHash)}</span>` : ''}\n ${config.user?.email ? `<span class=\"bs-kv-k\">User</span><span class=\"bs-kv-v\">${esc(config.user.email)}</span>` : ''}\n </div>`;\n\n html += `</div>`;\n return html;\n}\n\nfunction tabHistory(): string {\n const entries = getReportHistory();\n if (!entries.length) {\n return `<div class=\"bs-view\"><div class=\"bs-empty\"><p>No reports yet.<br>Submitted bugs will appear here.</p></div></div>`;\n }\n\n const catLabels: Record<string, string> = { ui: 'UI', functionality: 'Feature', performance: 'Perf', crash: 'Crash', security: 'Security', other: 'Other' };\n const fmtDate = (ts: number) => {\n const d = new Date(ts);\n const now = new Date();\n const diffMs = now.getTime() - d.getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 1) return 'Just now';\n if (diffMin < 60) return `${diffMin}m ago`;\n const diffH = Math.floor(diffMin / 60);\n if (diffH < 24) return `${diffH}h ago`;\n const diffD = Math.floor(diffH / 24);\n if (diffD < 7) return `${diffD}d ago`;\n return d.toLocaleDateString('en', { month: 'short', day: 'numeric' });\n };\n\n let html = `<div class=\"bs-view\">`;\n for (const e of entries) {\n const pinsHtml = e.pins?.length\n ? `<div class=\"bs-hist-pins\">${e.pins.slice(0, 5).map(p => `<div class=\"bs-hist-pin-dot\" style=\"background:${['#ef4444','#3b82f6','#f59e0b','#10b981','#8b5cf6'][p.number % 5]}\">${p.number}</div>`).join('')}${e.pins.length > 5 ? `<span>+${e.pins.length - 5}</span>` : ''}</div>`\n : '';\n html += `<div class=\"bs-hist-card\" data-hist-id=\"${e.id}\">\n <div class=\"bs-hist-top\">\n <div class=\"bs-hist-title\">${esc(e.title)}</div>\n ${e.screenshot ? `<img class=\"bs-hist-thumb\" src=\"${e.screenshot}\" alt=\"\"/>` : ''}\n <div class=\"bs-hist-actions\">\n <button class=\"bs-hist-btn\" data-hist-edit=\"${e.id}\" title=\"Edit\"><svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><path d=\"M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7\"/><path d=\"M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z\"/></svg></button>\n <button class=\"bs-hist-btn bs-del\" data-hist-del=\"${e.id}\" title=\"Delete\"><svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6\"/><path d=\"M10 11v6\"/><path d=\"M14 11v6\"/></svg></button>\n </div>\n </div>\n <div class=\"bs-hist-meta\">\n <span class=\"bs-hist-badge bs-cat\">${catLabels[e.category] || e.category}</span>\n <span class=\"bs-hist-badge bs-sev-${e.severity}\">${e.severity}</span>\n <span class=\"bs-hist-badge bs-status-${e.status}\">${e.status}</span>\n </div>\n ${e.description ? `<div class=\"bs-hist-desc\">${esc(e.description)}</div>` : ''}\n <div class=\"bs-hist-foot\">\n <span>${fmtDate(e.createdAt)} &middot; ${esc(e.url.replace(/^https?:\\/\\//, '').slice(0, 40))}</span>\n ${pinsHtml}\n </div>\n </div>`;\n }\n html += `</div>`;\n return html;\n}\n\nfunction tabSettings(): string {\n const themes = getThemes();\n const layouts = getLayouts();\n\n let html = `<div class=\"bs-view\">`;\n\n html += `<div class=\"bs-set-sec\">Layout</div>`;\n html += `<div class=\"bs-set-ly-grid\">`;\n for (const l of layouts) {\n html += `<button class=\"bs-set-ly${l.id === currentLayout.id ? ' bs-picked' : ''}\" data-set-layout=\"${l.id}\"><div class=\"bs-set-ly-name\">${esc(l.name)}</div><div class=\"bs-set-ly-desc\">${esc(l.description)}</div></button>`;\n }\n html += `</div>`;\n\n html += `<div class=\"bs-set-sec\">Theme</div>`;\n html += `<div class=\"bs-set-grid\">`;\n for (const t of themes) {\n html += `<button class=\"bs-set-card${t.id === currentTheme.id ? ' bs-picked' : ''}\" data-set-theme=\"${t.id}\"><div class=\"bs-set-preview\" style=\"background:${t.preview[0]}\"><div class=\"bs-set-dot\" style=\"background:${t.preview[1]}\"></div><div class=\"bs-set-dot\" style=\"background:${t.vars['--bs-accent2'] || t.preview[1]};opacity:0.6\"></div></div><div class=\"bs-set-name\">${esc(t.name)}</div></button>`;\n }\n html += `</div>`;\n\n html += `</div>`;\n return html;\n}\n\n// ─── Annotation ──────────────────────────────────────────\n\nfunction setupAnnotation(container: HTMLElement, screenshotData: string): { getAnnotation: () => string | null; getPins: () => { number: number; x: number; y: number; note: string }[] } {\n const COLORS = ['#f87171', '#3b82f6', '#fb923c', '#4ade80', '#a78bfa', '#facc15'];\n type Tool = 'select' | 'draw' | 'arrow' | 'rect' | 'circle' | 'text' | 'highlight' | 'pin';\n\n interface AnnShape {\n type: 'draw' | 'highlight';\n color: string; size: number; alpha: number;\n points: { x: number; y: number }[];\n }\n interface AnnRect { type: 'rect'; color: string; size: number; x: number; y: number; w: number; h: number; }\n interface AnnCircle { type: 'circle'; color: string; size: number; cx: number; cy: number; rx: number; ry: number; }\n interface AnnArrow { type: 'arrow'; color: string; size: number; x1: number; y1: number; x2: number; y2: number; }\n interface AnnText { type: 'text'; color: string; size: number; x: number; y: number; text: string; }\n type AnnObj = AnnShape | AnnRect | AnnCircle | AnnArrow | AnnText;\n\n let currentColor = COLORS[0];\n interface Pin { x: number; y: number; note: string; color: string; }\n\n let currentTool: Tool = 'draw';\n let brushSize = 4;\n let zoom = 1;\n let isDark = false;\n const shapes: AnnObj[] = [];\n const pins: Pin[] = [];\n let selectedIdx = -1;\n let hoveredIdx = -1;\n let dragging = false;\n let drawing = false;\n let dragOffX = 0, dragOffY = 0;\n let startX = 0, startY = 0;\n let currentDraw: { x: number; y: number }[] = [];\n const PIN_COLORS = ['#ef4444', '#3b82f6', '#f59e0b', '#10b981', '#8b5cf6', '#ec4899'];\n\n const img = new Image();\n img.src = screenshotData;\n\n const wrap = document.createElement('div');\n wrap.className = 'bs-ann-wrap';\n const viewport = document.createElement('div');\n viewport.className = 'bs-ann-viewport';\n const canvas = document.createElement('canvas');\n canvas.className = 'bs-ann-canvas bs-draw';\n const toolbar = document.createElement('div');\n toolbar.className = 'bs-ann-toolbar';\n\n const tIcons: Record<Tool, string> = {\n select: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z\"/><path d=\"M13 13l6 6\"/></svg>`,\n draw: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M12 19l7-7 3 3-7 7-3-3z\"/><path d=\"M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z\"/><path d=\"M2 2l7.586 7.586\"/></svg>`,\n arrow: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/><polyline points=\"12 5 19 12 12 19\"/></svg>`,\n rect: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/></svg>`,\n circle: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"10\"/></svg>`,\n text: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><polyline points=\"4 7 4 4 20 4 20 7\"/><line x1=\"9.5\" y1=\"20\" x2=\"14.5\" y2=\"20\"/><line x1=\"12\" y1=\"4\" x2=\"12\" y2=\"20\"/></svg>`,\n highlight: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M9 11l-6 6v3h9l3-3\"/><path d=\"M22 12l-4.6 4.6a2 2 0 01-2.8 0l-5.2-5.2a2 2 0 010-2.8L14 4\"/></svg>`,\n pin: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>`,\n };\n const toolNames: Record<Tool, string> = { select: 'Select & Move', draw: 'Draw', arrow: 'Arrow', rect: 'Rectangle', circle: 'Circle', text: 'Text', highlight: 'Highlight', pin: 'Pin Issue' };\n\n // Tool buttons\n const toolBtns: HTMLButtonElement[] = [];\n const setTool = (t: Tool) => {\n currentTool = t;\n selectedIdx = -1;\n canvas.className = `bs-ann-canvas bs-${t}`;\n toolBtns.forEach(b => b.classList.remove('bs-sel'));\n toolBtns.find(b => b.dataset.tool === t)?.classList.add('bs-sel');\n };\n (Object.keys(tIcons) as Tool[]).forEach(t => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.dataset.tool = t;\n btn.className = `bs-ann-btn${t === currentTool ? ' bs-sel' : ''}`;\n btn.title = toolNames[t];\n btn.innerHTML = tIcons[t];\n btn.addEventListener('click', () => setTool(t));\n toolBtns.push(btn);\n toolbar.appendChild(btn);\n });\n\n // Separator\n toolbar.appendChild(Object.assign(document.createElement('div'), { className: 'bs-ann-sep' }));\n\n // Colors\n COLORS.forEach((color, i) => {\n const d = document.createElement('button');\n d.type = 'button';\n d.className = `bs-ann-dot${i === 0 ? ' bs-sel' : ''}`;\n d.style.background = color;\n d.addEventListener('click', () => {\n currentColor = color;\n toolbar.querySelectorAll('.bs-ann-dot').forEach(t => t.classList.remove('bs-sel'));\n d.classList.add('bs-sel');\n });\n toolbar.appendChild(d);\n });\n\n toolbar.appendChild(Object.assign(document.createElement('div'), { className: 'bs-ann-sep' }));\n\n // Brush size\n const sizeSlider = document.createElement('input');\n sizeSlider.type = 'range'; sizeSlider.min = '1'; sizeSlider.max = '12'; sizeSlider.value = '4';\n sizeSlider.className = 'bs-ann-size'; sizeSlider.title = 'Brush size';\n sizeSlider.addEventListener('input', () => { brushSize = parseInt(sizeSlider.value); });\n toolbar.appendChild(sizeSlider);\n\n // Right side\n const right = document.createElement('div');\n right.className = 'bs-ann-right';\n\n const mkBtn = (title: string, svg: string) => {\n const b = document.createElement('button');\n b.type = 'button'; b.className = 'bs-ann-btn'; b.title = title; b.innerHTML = svg;\n return b;\n };\n const zoomOut = mkBtn('Zoom out', `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"/><line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\"/></svg>`);\n const zoomLabel = Object.assign(document.createElement('span'), { className: 'bs-ann-zoom-label', textContent: '100%' });\n const zoomIn = mkBtn('Zoom in', `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"/><line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\"/><line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\"/></svg>`);\n const zoomReset = mkBtn('Fit', `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M15 3h6v6\"/><path d=\"M9 21H3v-6\"/><path d=\"M21 3l-7 7\"/><path d=\"M3 21l7-7\"/></svg>`);\n const undoBtn = mkBtn('Undo', `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 105.42-8.49L1 10\"/></svg>`);\n const clearBtn = Object.assign(document.createElement('button'), { type: 'button', className: 'bs-ann-clr-btn', textContent: 'Clear' });\n\n const applyZoom = () => { canvas.style.transform = `scale(${zoom})`; zoomLabel.textContent = `${Math.round(zoom * 100)}%`; };\n zoomIn.addEventListener('click', () => { if (zoom < 3) { zoom = Math.min(3, zoom + 0.25); applyZoom(); } });\n zoomOut.addEventListener('click', () => { if (zoom > 0.5) { zoom = Math.max(0.5, zoom - 0.25); applyZoom(); } });\n zoomReset.addEventListener('click', () => { zoom = 1; applyZoom(); });\n\n right.appendChild(Object.assign(document.createElement('div'), { className: 'bs-ann-sep' }));\n [zoomOut, zoomLabel, zoomIn, zoomReset, undoBtn, clearBtn].forEach(el => right.appendChild(el));\n toolbar.appendChild(right);\n\n // Pin overlay layer (positioned over the canvas)\n const pinLayer = document.createElement('div');\n pinLayer.className = 'bs-ann-pins';\n // Pin list below toolbar\n const pinList = document.createElement('div');\n pinList.className = 'bs-ann-pin-list';\n pinList.style.display = 'none';\n\n viewport.appendChild(canvas);\n viewport.appendChild(pinLayer);\n wrap.appendChild(viewport);\n wrap.appendChild(toolbar);\n wrap.appendChild(pinList);\n container.innerHTML = '';\n container.appendChild(wrap);\n\n // ── Pin rendering ──\n const renderPins = () => {\n pinLayer.innerHTML = '';\n pinList.innerHTML = '';\n pinList.style.display = pins.length ? '' : 'none';\n\n pins.forEach((pin, i) => {\n // Pin marker on canvas\n const el = document.createElement('div');\n el.className = 'bs-ann-pin';\n el.style.background = pin.color;\n el.style.color = pin.color;\n // Position as percentage of viewport\n const pctX = (pin.x / (canvas.width || 1)) * 100;\n const pctY = (pin.y / (canvas.height || 1)) * 100;\n el.style.left = `${pctX}%`;\n el.style.top = `${pctY}%`;\n el.innerHTML = `<span class=\"bs-ann-pin-n\">${i + 1}</span><span class=\"bs-ann-pin-pulse\"></span>`;\n el.title = `#${i + 1}: ${pin.note}`;\n\n // Drag pin\n let pinDragging = false;\n el.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n pinDragging = true;\n el.classList.add('bs-dragging');\n const onMove = (me: MouseEvent) => {\n if (!pinDragging) return;\n const r = viewport.getBoundingClientRect();\n pin.x = ((me.clientX - r.left) / r.width) * canvas.width;\n pin.y = ((me.clientY - r.top) / r.height) * canvas.height;\n el.style.left = `${((me.clientX - r.left) / r.width) * 100}%`;\n el.style.top = `${((me.clientY - r.top) / r.height) * 100}%`;\n };\n const onUp = () => {\n pinDragging = false;\n el.classList.remove('bs-dragging');\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n renderPins(); // refresh list coords\n };\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n pinLayer.appendChild(el);\n\n // Pin list item\n const item = document.createElement('div');\n item.className = 'bs-ann-pin-item';\n item.innerHTML = `\n <div class=\"bs-ann-pin-num\" style=\"background:${pin.color}\">${i + 1}</div>\n <div class=\"bs-ann-pin-body\">\n <div class=\"bs-ann-pin-note\">${esc(pin.note)}</div>\n <div class=\"bs-ann-pin-loc\">${Math.round(pctX)}% × ${Math.round(pctY)}%</div>\n </div>`;\n const del = document.createElement('button');\n del.type = 'button';\n del.className = 'bs-ann-pin-del';\n del.innerHTML = '&times;';\n del.title = 'Remove pin';\n del.addEventListener('click', () => {\n pins.splice(i, 1);\n renderPins();\n });\n item.appendChild(del);\n pinList.appendChild(item);\n });\n };\n\n // ── Render engine ──\n let ctx: CanvasRenderingContext2D;\n const outlineColor = () => isDark ? 'rgba(255,255,255,0.5)' : 'rgba(0,0,0,0.35)';\n\n const drawOutline = (fn: () => void, lw: number) => {\n // Draw shadow outline for contrast on any background\n ctx.save();\n ctx.strokeStyle = outlineColor();\n ctx.lineWidth = lw + 3;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n ctx.globalAlpha = 0.5;\n fn();\n ctx.restore();\n };\n\n const renderShape = (s: AnnObj, preview = false) => {\n if (s.type === 'draw' || s.type === 'highlight') {\n if (s.points.length < 2) return;\n const alpha = s.type === 'highlight' ? 0.25 : 1;\n const lw = s.type === 'highlight' ? s.size * 4 + 10 : s.size;\n const stroke = () => {\n ctx.beginPath();\n ctx.moveTo(s.points[0].x, s.points[0].y);\n for (let i = 1; i < s.points.length; i++) ctx.lineTo(s.points[i].x, s.points[i].y);\n ctx.stroke();\n };\n if (s.type !== 'highlight') drawOutline(stroke, lw);\n ctx.strokeStyle = s.color; ctx.lineWidth = lw;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n ctx.globalAlpha = alpha;\n stroke();\n ctx.globalAlpha = 1;\n } else if (s.type === 'rect') {\n const stroke = () => ctx.strokeRect(s.x, s.y, s.w, s.h);\n drawOutline(stroke, s.size);\n ctx.strokeStyle = s.color; ctx.lineWidth = s.size;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n stroke();\n } else if (s.type === 'circle') {\n const stroke = () => { ctx.beginPath(); ctx.ellipse(s.cx, s.cy, Math.abs(s.rx), Math.abs(s.ry), 0, 0, Math.PI * 2); ctx.stroke(); };\n drawOutline(stroke, s.size);\n ctx.strokeStyle = s.color; ctx.lineWidth = s.size;\n stroke();\n } else if (s.type === 'arrow') {\n const angle = Math.atan2(s.y2 - s.y1, s.x2 - s.x1);\n const headLen = 12 + s.size * 2;\n const stroke = () => {\n ctx.beginPath(); ctx.moveTo(s.x1, s.y1); ctx.lineTo(s.x2, s.y2); ctx.stroke();\n ctx.beginPath();\n ctx.moveTo(s.x2, s.y2);\n ctx.lineTo(s.x2 - headLen * Math.cos(angle - 0.45), s.y2 - headLen * Math.sin(angle - 0.45));\n ctx.moveTo(s.x2, s.y2);\n ctx.lineTo(s.x2 - headLen * Math.cos(angle + 0.45), s.y2 - headLen * Math.sin(angle + 0.45));\n ctx.stroke();\n };\n drawOutline(stroke, s.size);\n ctx.strokeStyle = s.color; ctx.lineWidth = s.size;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n stroke();\n } else if (s.type === 'text') {\n const fontSize = s.size * 5 + 12;\n ctx.font = `bold ${fontSize}px Inter, -apple-system, sans-serif`;\n // text shadow for contrast\n ctx.fillStyle = outlineColor();\n ctx.globalAlpha = 0.6;\n ctx.fillText(s.text, s.x + 1, s.y + 1);\n ctx.globalAlpha = 1;\n ctx.fillStyle = s.color;\n ctx.fillText(s.text, s.x, s.y);\n }\n\n // Selection / hover highlight\n const isSelected = !preview && selectedIdx >= 0 && shapes[selectedIdx] === s;\n const isHovered = !preview && !isSelected && hoveredIdx >= 0 && shapes[hoveredIdx] === s;\n if (isSelected || isHovered) {\n const b = shapeBounds(s);\n ctx.save();\n ctx.setLineDash([6, 4]);\n ctx.strokeStyle = isDark ? '#fff' : '#000';\n ctx.lineWidth = isSelected ? 1.5 : 1;\n ctx.globalAlpha = isSelected ? 0.7 : 0.45;\n ctx.strokeRect(b.x - 4, b.y - 4, b.w + 8, b.h + 8);\n\n // Corner/cardinal handles for rects and circles\n if (s.type === 'rect' || s.type === 'circle') {\n const hSize = 5;\n ctx.setLineDash([]);\n ctx.globalAlpha = isSelected ? 0.9 : 0.6;\n const handles: [number, number][] = s.type === 'rect'\n ? [[b.x, b.y], [b.x + b.w, b.y], [b.x, b.y + b.h], [b.x + b.w, b.y + b.h]]\n : [[b.x + b.w / 2, b.y], [b.x + b.w, b.y + b.h / 2], [b.x + b.w / 2, b.y + b.h], [b.x, b.y + b.h / 2]];\n for (const [hx, hy] of handles) {\n ctx.fillStyle = '#fff';\n ctx.fillRect(hx - hSize, hy - hSize, hSize * 2, hSize * 2);\n ctx.strokeStyle = isDark ? '#aaa' : '#333';\n ctx.lineWidth = 1.2;\n ctx.strokeRect(hx - hSize, hy - hSize, hSize * 2, hSize * 2);\n }\n }\n ctx.restore();\n }\n };\n\n const render = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(img, 0, 0);\n for (const s of shapes) renderShape(s);\n };\n\n // ── Hit testing & bounds ──\n const shapeBounds = (s: AnnObj): { x: number; y: number; w: number; h: number } => {\n if (s.type === 'rect') return { x: Math.min(s.x, s.x + s.w), y: Math.min(s.y, s.y + s.h), w: Math.abs(s.w), h: Math.abs(s.h) };\n if (s.type === 'circle') return { x: s.cx - Math.abs(s.rx), y: s.cy - Math.abs(s.ry), w: Math.abs(s.rx) * 2, h: Math.abs(s.ry) * 2 };\n if (s.type === 'arrow') {\n const x = Math.min(s.x1, s.x2), y = Math.min(s.y1, s.y2);\n return { x, y, w: Math.abs(s.x2 - s.x1) || 20, h: Math.abs(s.y2 - s.y1) || 20 };\n }\n if (s.type === 'text') return { x: s.x, y: s.y - (s.size * 5 + 12), w: s.text.length * (s.size * 3 + 8), h: s.size * 5 + 16 };\n // draw / highlight: bounding box of points\n if (s.points.length === 0) return { x: 0, y: 0, w: 0, h: 0 };\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of s.points) { minX = Math.min(minX, p.x); minY = Math.min(minY, p.y); maxX = Math.max(maxX, p.x); maxY = Math.max(maxY, p.y); }\n return { x: minX, y: minY, w: maxX - minX || 10, h: maxY - minY || 10 };\n };\n\n const hitTest = (x: number, y: number): number => {\n for (let i = shapes.length - 1; i >= 0; i--) {\n const b = shapeBounds(shapes[i]);\n const pad = 8;\n if (x >= b.x - pad && x <= b.x + b.w + pad && y >= b.y - pad && y <= b.y + b.h + pad) return i;\n }\n return -1;\n };\n\n const moveShape = (s: AnnObj, dx: number, dy: number) => {\n if (s.type === 'draw' || s.type === 'highlight') { for (const p of s.points) { p.x += dx; p.y += dy; } }\n else if (s.type === 'rect') { s.x += dx; s.y += dy; }\n else if (s.type === 'circle') { s.cx += dx; s.cy += dy; }\n else if (s.type === 'arrow') { s.x1 += dx; s.y1 += dy; s.x2 += dx; s.y2 += dy; }\n else if (s.type === 'text') { s.x += dx; s.y += dy; }\n };\n\n img.onload = () => {\n const maxW = container.clientWidth || 450;\n const scale = maxW / img.width;\n canvas.width = img.width;\n canvas.height = img.height;\n canvas.style.height = `${img.height * scale}px`;\n ctx = canvas.getContext('2d')!;\n ctx.drawImage(img, 0, 0);\n\n // Detect brightness: sample corners + center\n const samplePoints = [[10, 10], [canvas.width - 10, 10], [10, canvas.height - 10], [canvas.width - 10, canvas.height - 10], [canvas.width / 2, canvas.height / 2]];\n let totalBrightness = 0;\n for (const [sx, sy] of samplePoints) {\n const px = ctx.getImageData(sx, sy, 1, 1).data;\n totalBrightness += (px[0] * 299 + px[1] * 587 + px[2] * 114) / 1000;\n }\n isDark = (totalBrightness / samplePoints.length) < 128;\n\n const coords = (e: MouseEvent) => {\n const r = canvas.getBoundingClientRect();\n return { x: (e.clientX - r.left) * (canvas.width / r.width), y: (e.clientY - r.top) * (canvas.height / r.height) };\n };\n\n let autoSelectDrag = false; // true when we auto-switched to drag on hover-hit\n\n canvas.addEventListener('mousedown', e => {\n const c = coords(e);\n\n // Select mode: pick or drag\n if (currentTool === 'select') {\n const hit = hitTest(c.x, c.y);\n if (hit >= 0) {\n selectedIdx = hit;\n dragging = true;\n const b = shapeBounds(shapes[hit]);\n dragOffX = c.x - b.x;\n dragOffY = c.y - b.y;\n canvas.classList.add('bs-grabbing');\n canvas.classList.remove('bs-grab');\n render();\n } else {\n selectedIdx = -1;\n render();\n }\n return;\n }\n\n // Auto-drag: if hovering a shape in any drawing tool, grab it instead\n if (currentTool !== 'pin' && currentTool !== 'text') {\n const hit = hitTest(c.x, c.y);\n if (hit >= 0) {\n selectedIdx = hit;\n dragging = true;\n autoSelectDrag = true;\n const b = shapeBounds(shapes[hit]);\n dragOffX = c.x - b.x;\n dragOffY = c.y - b.y;\n canvas.classList.add('bs-grabbing');\n render();\n return;\n }\n }\n\n drawing = true;\n startX = c.x; startY = c.y;\n\n if (currentTool === 'pin') {\n drawing = false;\n const note = prompt('Describe the issue at this spot:');\n if (note) {\n const color = PIN_COLORS[pins.length % PIN_COLORS.length];\n pins.push({ x: c.x, y: c.y, note, color });\n renderPins();\n }\n return;\n }\n\n if (currentTool === 'text') {\n drawing = false;\n const input = prompt('Enter text:');\n if (input) {\n shapes.push({ type: 'text', color: currentColor, size: brushSize, x: c.x, y: c.y, text: input });\n render();\n }\n return;\n }\n\n if (currentTool === 'draw' || currentTool === 'highlight') {\n currentDraw = [{ x: c.x, y: c.y }];\n }\n });\n\n canvas.addEventListener('mousemove', e => {\n const c = coords(e);\n\n // Active drag (select mode or auto-drag from any tool)\n if (dragging && selectedIdx >= 0) {\n const b = shapeBounds(shapes[selectedIdx]);\n const dx = c.x - dragOffX - b.x;\n const dy = c.y - dragOffY - b.y;\n moveShape(shapes[selectedIdx], dx, dy);\n render();\n return;\n }\n\n // Select mode hover\n if (currentTool === 'select') {\n const hit = hitTest(c.x, c.y);\n canvas.classList.toggle('bs-grab', hit >= 0);\n if (hoveredIdx !== hit) { hoveredIdx = hit; render(); }\n return;\n }\n\n // Any tool: show grab cursor when hovering a shape\n if (currentTool !== 'pin' && currentTool !== 'text' && !drawing) {\n const hit = hitTest(c.x, c.y);\n canvas.classList.toggle('bs-grab', hit >= 0);\n if (hoveredIdx !== hit) { hoveredIdx = hit; render(); }\n }\n\n if (!drawing) return;\n\n if (currentTool === 'draw' || currentTool === 'highlight') {\n currentDraw.push({ x: c.x, y: c.y });\n // Live preview\n render();\n const alpha = currentTool === 'highlight' ? 0.25 : 1;\n const lw = currentTool === 'highlight' ? brushSize * 4 + 10 : brushSize;\n if (currentTool !== 'highlight') {\n ctx.save();\n ctx.strokeStyle = outlineColor(); ctx.lineWidth = lw + 3;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.globalAlpha = 0.5;\n ctx.beginPath(); ctx.moveTo(currentDraw[0].x, currentDraw[0].y);\n for (let i = 1; i < currentDraw.length; i++) ctx.lineTo(currentDraw[i].x, currentDraw[i].y);\n ctx.stroke(); ctx.restore();\n }\n ctx.strokeStyle = currentColor; ctx.lineWidth = lw;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.globalAlpha = alpha;\n ctx.beginPath(); ctx.moveTo(currentDraw[0].x, currentDraw[0].y);\n for (let i = 1; i < currentDraw.length; i++) ctx.lineTo(currentDraw[i].x, currentDraw[i].y);\n ctx.stroke(); ctx.globalAlpha = 1;\n } else {\n // Shape preview\n render();\n ctx.strokeStyle = currentColor; ctx.lineWidth = brushSize;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n if (currentTool === 'rect') {\n drawOutline(() => ctx.strokeRect(startX, startY, c.x - startX, c.y - startY), brushSize);\n ctx.strokeStyle = currentColor; ctx.lineWidth = brushSize;\n ctx.strokeRect(startX, startY, c.x - startX, c.y - startY);\n } else if (currentTool === 'circle') {\n const rx = Math.abs(c.x - startX) / 2, ry = Math.abs(c.y - startY) / 2;\n const cx2 = startX + (c.x - startX) / 2, cy2 = startY + (c.y - startY) / 2;\n drawOutline(() => { ctx.beginPath(); ctx.ellipse(cx2, cy2, rx, ry, 0, 0, Math.PI * 2); ctx.stroke(); }, brushSize);\n ctx.strokeStyle = currentColor; ctx.lineWidth = brushSize;\n ctx.beginPath(); ctx.ellipse(cx2, cy2, rx, ry, 0, 0, Math.PI * 2); ctx.stroke();\n } else if (currentTool === 'arrow') {\n const angle = Math.atan2(c.y - startY, c.x - startX);\n const headLen = 12 + brushSize * 2;\n const stroke = () => {\n ctx.beginPath(); ctx.moveTo(startX, startY); ctx.lineTo(c.x, c.y); ctx.stroke();\n ctx.beginPath();\n ctx.moveTo(c.x, c.y);\n ctx.lineTo(c.x - headLen * Math.cos(angle - 0.45), c.y - headLen * Math.sin(angle - 0.45));\n ctx.moveTo(c.x, c.y);\n ctx.lineTo(c.x - headLen * Math.cos(angle + 0.45), c.y - headLen * Math.sin(angle + 0.45));\n ctx.stroke();\n };\n drawOutline(stroke, brushSize);\n ctx.strokeStyle = currentColor; ctx.lineWidth = brushSize;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n stroke();\n }\n }\n });\n\n const endDraw = (e: MouseEvent) => {\n // Release auto-drag or select-mode drag\n if (dragging) {\n dragging = false;\n autoSelectDrag = false;\n selectedIdx = -1;\n canvas.classList.remove('bs-grabbing');\n canvas.classList.remove('bs-grab');\n render();\n if (currentTool === 'select') return;\n // For auto-drag from other tools, just stop — don't create a shape\n return;\n }\n if (!drawing) return;\n drawing = false;\n const c = coords(e);\n\n if (currentTool === 'draw' || currentTool === 'highlight') {\n if (currentDraw.length > 1) {\n shapes.push({ type: currentTool, color: currentColor, size: brushSize, alpha: currentTool === 'highlight' ? 0.25 : 1, points: [...currentDraw] });\n }\n currentDraw = [];\n } else if (currentTool === 'rect') {\n shapes.push({ type: 'rect', color: currentColor, size: brushSize, x: startX, y: startY, w: c.x - startX, h: c.y - startY });\n } else if (currentTool === 'circle') {\n const rx = Math.abs(c.x - startX) / 2, ry = Math.abs(c.y - startY) / 2;\n shapes.push({ type: 'circle', color: currentColor, size: brushSize, cx: startX + (c.x - startX) / 2, cy: startY + (c.y - startY) / 2, rx, ry });\n } else if (currentTool === 'arrow') {\n shapes.push({ type: 'arrow', color: currentColor, size: brushSize, x1: startX, y1: startY, x2: c.x, y2: c.y });\n }\n render();\n };\n\n canvas.addEventListener('mouseup', endDraw);\n canvas.addEventListener('mouseleave', (e) => {\n if (dragging) { dragging = false; autoSelectDrag = false; canvas.classList.remove('bs-grabbing'); canvas.classList.remove('bs-grab'); render(); }\n else if (drawing) endDraw(e);\n });\n\n // Delete selected with Backspace/Delete\n const keyHandler = (e: KeyboardEvent) => {\n if (selectedIdx >= 0 && (e.key === 'Delete' || e.key === 'Backspace')) {\n shapes.splice(selectedIdx, 1);\n selectedIdx = -1;\n render();\n }\n };\n document.addEventListener('keydown', keyHandler);\n\n undoBtn.addEventListener('click', () => {\n if (shapes.length) {\n shapes.pop();\n selectedIdx = -1;\n render();\n }\n });\n\n clearBtn.addEventListener('click', () => {\n shapes.length = 0;\n pins.length = 0;\n selectedIdx = -1;\n render();\n renderPins();\n });\n };\n\n // Draw pins onto canvas for final export\n const bakePins = () => {\n for (let i = 0; i < pins.length; i++) {\n const p = pins[i];\n const r = 16;\n // Pin circle\n ctx.beginPath();\n ctx.arc(p.x, p.y - r, r, 0, Math.PI * 2);\n ctx.fillStyle = p.color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2;\n ctx.stroke();\n // Pin tail\n ctx.beginPath();\n ctx.moveTo(p.x - 8, p.y - 6);\n ctx.lineTo(p.x, p.y + 4);\n ctx.lineTo(p.x + 8, p.y - 6);\n ctx.fillStyle = p.color;\n ctx.fill();\n // Number\n ctx.fillStyle = '#fff';\n ctx.font = 'bold 14px Inter, sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(`${i + 1}`, p.x, p.y - r);\n ctx.textAlign = 'start';\n ctx.textBaseline = 'alphabetic';\n }\n };\n\n return {\n getAnnotation: () => {\n try {\n selectedIdx = -1;\n render();\n bakePins();\n return canvas.toDataURL('image/jpeg', 0.7);\n } catch { return null; }\n },\n getPins: () => pins.map((p, i) => ({ number: i + 1, x: Math.round(p.x), y: Math.round(p.y), note: p.note })),\n };\n}\n\n// ─── Switch Tab ──────────────────────────────────────────\n\nfunction switchTab(tab: typeof activeTab) {\n if (!modal) return;\n activeTab = tab;\n\n // Update tab buttons\n modal.querySelectorAll('.bs-tab').forEach(el => {\n el.classList.toggle('bs-active', (el as HTMLElement).dataset.tab === tab);\n });\n\n // Render content\n const scroll = modal.querySelector('.bs-scroll')!;\n const renderers: Record<typeof activeTab, () => string> = {\n report: tabReport,\n console: tabConsole,\n network: tabNetwork,\n context: tabContext,\n history: tabHistory,\n settings: tabSettings,\n };\n scroll.innerHTML = renderers[tab]();\n scroll.scrollTop = 0;\n bindTabContent();\n}\n\nfunction bindTabContent() {\n if (!modal) return;\n\n if (activeTab === 'history') {\n // Delete buttons\n modal.querySelectorAll('[data-hist-del]').forEach(btn => {\n btn.addEventListener('click', () => {\n const id = parseInt((btn as HTMLElement).dataset.histDel!);\n const card = modal!.querySelector(`[data-hist-id=\"${id}\"]`);\n if (!card) return;\n // Show confirm inline\n const existing = card.querySelector('.bs-hist-confirm');\n if (existing) { existing.remove(); return; }\n const confirm = document.createElement('div');\n confirm.className = 'bs-hist-confirm';\n confirm.innerHTML = `<span>Delete this report?</span>`;\n const yes = document.createElement('button');\n yes.type = 'button'; yes.className = 'bs-hist-confirm-yes'; yes.textContent = 'Delete';\n const no = document.createElement('button');\n no.type = 'button'; no.className = 'bs-hist-confirm-no'; no.textContent = 'Cancel';\n yes.addEventListener('click', () => {\n deleteFromHistory(id);\n switchTab('history');\n });\n no.addEventListener('click', () => confirm.remove());\n confirm.appendChild(yes);\n confirm.appendChild(no);\n card.appendChild(confirm);\n });\n });\n\n // Edit buttons\n modal.querySelectorAll('[data-hist-edit]').forEach(btn => {\n btn.addEventListener('click', () => {\n const id = parseInt((btn as HTMLElement).dataset.histEdit!);\n const card = modal!.querySelector(`[data-hist-id=\"${id}\"]`);\n if (!card) return;\n const existing = card.querySelector('.bs-hist-edit-wrap');\n if (existing) { existing.remove(); return; }\n // Remove any confirm dialogs\n card.querySelector('.bs-hist-confirm')?.remove();\n\n const entry = getReportHistory().find(e => e.id === id);\n if (!entry) return;\n\n const wrap = document.createElement('div');\n wrap.className = 'bs-hist-edit-wrap';\n wrap.innerHTML = `\n <div class=\"bs-field\" style=\"margin-bottom:8px\">\n <input class=\"bs-input\" data-edit-title value=\"${esc(entry.title)}\" />\n </div>\n <div class=\"bs-field\" style=\"margin-bottom:8px\">\n <textarea class=\"bs-textarea\" data-edit-desc style=\"min-height:56px\">${esc(entry.description)}</textarea>\n </div>\n <div class=\"bs-field\" style=\"margin-bottom:8px\">\n <div class=\"bs-sev-row\">\n <button type=\"button\" class=\"bs-sev-btn bs-sev-low${entry.severity === 'low' ? ' bs-picked' : ''}\" data-edit-sev=\"low\">Low</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-medium${entry.severity === 'medium' ? ' bs-picked' : ''}\" data-edit-sev=\"medium\">Medium</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-high${entry.severity === 'high' ? ' bs-picked' : ''}\" data-edit-sev=\"high\">High</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-critical${entry.severity === 'critical' ? ' bs-picked' : ''}\" data-edit-sev=\"critical\">Critical</button>\n </div>\n </div>\n <div class=\"bs-hist-edit-row\"></div>`;\n\n let editSev = entry.severity;\n card.appendChild(wrap);\n\n // Severity picker in edit\n wrap.querySelectorAll('[data-edit-sev]').forEach(sb => {\n sb.addEventListener('click', () => {\n editSev = (sb as HTMLElement).dataset.editSev!;\n wrap.querySelectorAll('.bs-sev-btn').forEach(b => b.classList.remove('bs-picked'));\n sb.classList.add('bs-picked');\n });\n });\n\n const row = wrap.querySelector('.bs-hist-edit-row')!;\n const save = document.createElement('button');\n save.type = 'button'; save.className = 'bs-hist-save'; save.textContent = 'Save';\n const cancel = document.createElement('button');\n cancel.type = 'button'; cancel.className = 'bs-hist-cancel'; cancel.textContent = 'Cancel';\n\n save.addEventListener('click', () => {\n const newTitle = (wrap.querySelector('[data-edit-title]') as HTMLInputElement).value.trim();\n const newDesc = (wrap.querySelector('[data-edit-desc]') as HTMLTextAreaElement).value.trim();\n if (!newTitle) return;\n updateInHistory(id, { title: newTitle, description: newDesc, severity: editSev });\n switchTab('history');\n });\n cancel.addEventListener('click', () => wrap.remove());\n row.appendChild(save);\n row.appendChild(cancel);\n });\n });\n return;\n }\n\n if (activeTab === 'settings') {\n // Theme picker\n modal.querySelectorAll('[data-set-theme]').forEach(btn => {\n btn.addEventListener('click', () => {\n const id = (btn as HTMLElement).dataset.setTheme!;\n setTheme(id);\n // Update picked state\n modal!.querySelectorAll('[data-set-theme]').forEach(b => b.classList.remove('bs-picked'));\n btn.classList.add('bs-picked');\n });\n });\n // Layout picker\n modal.querySelectorAll('[data-set-layout]').forEach(btn => {\n btn.addEventListener('click', () => {\n const id = (btn as HTMLElement).dataset.setLayout!;\n const layout = getLayoutById(id);\n if (!layout) return;\n currentLayout = layout;\n // Close and reopen with new layout\n close();\n setTimeout(() => {\n activeTab = 'settings';\n open();\n // After open, switch to settings tab\n setTimeout(() => switchTab('settings'), 50);\n }, 400);\n });\n });\n return;\n }\n\n if (activeTab !== 'report') return;\n\n // Category\n modal.querySelectorAll('.bs-cat-btn').forEach(btn => {\n btn.addEventListener('click', () => {\n const cat = (btn as HTMLElement).dataset.cat!;\n (modal!.querySelector('input[name=\"category\"]') as HTMLInputElement).value = cat;\n modal!.querySelectorAll('.bs-cat-btn').forEach(b => b.classList.remove('bs-picked'));\n btn.classList.add('bs-picked');\n });\n });\n\n // Severity\n modal.querySelectorAll('.bs-sev-btn').forEach(btn => {\n btn.addEventListener('click', () => {\n const sev = (btn as HTMLElement).dataset.sev!;\n (modal!.querySelector('input[name=\"severity\"]') as HTMLInputElement).value = sev;\n modal!.querySelectorAll('.bs-sev-btn').forEach(b => b.classList.remove('bs-picked'));\n btn.classList.add('bs-picked');\n });\n });\n\n // Screenshot\n let screenshotData: string | null = null;\n let annotator: { getAnnotation: () => string | null; getPins: () => { number: number; x: number; y: number; note: string }[] } | null = null;\n\n modal.querySelector('[data-bs-screenshot]')?.addEventListener('click', async () => {\n const titleEl = modal?.querySelector('[data-bs-shot-title]');\n const subEl = modal?.querySelector('[data-bs-shot-sub]');\n const area = modal?.querySelector('[data-bs-screenshot]');\n if (titleEl) titleEl.textContent = 'Capturing...';\n\n if (modal) modal.style.visibility = 'hidden';\n if (backdrop) backdrop.style.visibility = 'hidden';\n await new Promise(r => setTimeout(r, 200));\n screenshotData = await captureScreenshot(true);\n if (modal) modal.style.visibility = '';\n if (backdrop) backdrop.style.visibility = '';\n\n if (screenshotData) {\n if (titleEl) titleEl.textContent = 'Screenshot captured!';\n if (subEl) subEl.textContent = 'Draw on the image below to highlight the issue';\n area?.classList.add('bs-captured');\n const container = modal?.querySelector('[data-bs-annotate]') as HTMLElement;\n if (container) annotator = setupAnnotation(container, screenshotData);\n } else {\n if (titleEl) titleEl.textContent = 'Screenshot unavailable';\n if (subEl) subEl.textContent = 'Could not capture screenshot on this page';\n }\n });\n\n // Submit\n modal.querySelector('[data-bs-form]')?.addEventListener('submit', async (e) => {\n e.preventDefault();\n const form = e.target as HTMLFormElement;\n const btn = form.querySelector('.bs-submit-btn') as HTMLButtonElement;\n\n const title = (form.elements.namedItem('title') as HTMLInputElement).value.trim();\n const description = (form.elements.namedItem('description') as HTMLTextAreaElement).value.trim();\n const severity = (form.elements.namedItem('severity') as HTMLInputElement).value as BugReport['severity'];\n const category = (form.elements.namedItem('category') as HTMLInputElement).value as BugReport['category'];\n\n if (!title) return;\n\n btn.disabled = true;\n btn.textContent = 'Sending...';\n\n const detected = autoDetect();\n\n const report: BugReport = {\n projectId: config.projectId,\n title,\n description,\n category,\n severity,\n tags: detected.tags.length ? detected.tags : undefined,\n context: buildContext(),\n consoleLogs: getLogs(),\n errors: getErrors(),\n networkCaptures: getFailedNetworkCaptures(),\n breadcrumbs: getBreadcrumbs(),\n performance: getPerformanceMetrics() ?? undefined,\n screenshot: screenshotData ?? undefined,\n annotation: annotator?.getAnnotation() ?? undefined,\n pins: annotator?.getPins().length ? annotator.getPins() : undefined,\n createdAt: Date.now(),\n };\n\n const result = await submitReport(report);\n\n // Save to history\n addToHistory({\n title: report.title,\n description: report.description,\n category: report.category,\n severity: report.severity,\n tags: report.tags,\n screenshot: report.screenshot,\n pins: report.pins,\n url: window.location.href,\n createdAt: report.createdAt,\n status: result.success ? 'sent' : 'draft',\n });\n\n if (result.success) {\n btn.innerHTML = `${I.check} Bug reported!`;\n btn.classList.add('bs-submit-ok');\n setTimeout(close, 1200);\n } else {\n btn.textContent = result.error ?? 'Failed — saved as draft';\n btn.classList.add('bs-submit-err');\n setTimeout(() => {\n btn.disabled = false;\n btn.textContent = 'Submit Report';\n btn.classList.remove('bs-submit-err');\n }, 2500);\n }\n });\n}\n\n// ─── Open / Close ────────────────────────────────────────\n\nfunction open() {\n if (!iframeDoc || isOpen) return;\n isOpen = true;\n activeTab = 'report';\n hideToolbar();\n\n backdrop = iframeDoc.createElement('div') as HTMLDivElement;\n backdrop.className = 'bs-backdrop';\n iframeDoc.body.appendChild(backdrop);\n\n const fails = getFailedNetworkCaptures().length;\n const errs = getErrors().length;\n\n modal = iframeDoc.createElement('div') as HTMLDivElement;\n modal.className = `bs-modal bs-ly-${currentLayout.id}`;\n applyThemeVars(modal);\n\n const tabsHtml = `\n <div class=\"bs-tabs\">\n <button class=\"bs-tab bs-active\" data-tab=\"report\">${I.report} Report</button>\n <button class=\"bs-tab\" data-tab=\"console\">${I.console} Console <span class=\"bs-tab-badge\">${getLogs().length}</span></button>\n <button class=\"bs-tab\" data-tab=\"network\">${I.network} Network ${fails ? `<span class=\"bs-tab-badge bs-warn\">${fails}</span>` : `<span class=\"bs-tab-badge\">${getNetworkCaptures().length}</span>`}</button>\n <button class=\"bs-tab\" data-tab=\"context\">${I.ctx} Context ${errs ? `<span class=\"bs-tab-badge bs-warn\">${errs}</span>` : ''}</button>\n <button class=\"bs-tab\" data-tab=\"history\">${I.history} History <span class=\"bs-tab-badge\">${getReportHistory().length}</span></button>\n </div>`;\n\n const user = getCurrentUser();\n const initials = user ? user.name.split(' ').map(w => w[0]).join('').toUpperCase().slice(0, 2) : '';\n const pinActive = isPinModeActive();\n\n const headerHtml = user ? `\n <div class=\"bs-hdr\">\n <div class=\"bs-logo\">BugStash</div>\n <div class=\"bs-hdr-right\">\n <button class=\"bs-pin-toggle${pinActive ? ' active' : ''}\" data-bs-pin-toggle title=\"Toggle pin mode\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>\n Pins ${pinActive ? 'ON' : 'OFF'}\n </button>\n <div class=\"bs-user-badge\">\n <div class=\"bs-user-avatar\">${initials}</div>\n <span>${user.name.split(' ')[0]}</span>\n </div>\n <button class=\"bs-hdr-icon\" data-tab=\"settings\" title=\"Settings\">${I.settings}</button>\n <button class=\"bs-login-logout\" data-bs-logout title=\"Sign out\">Logout</button>\n <button class=\"bs-close-btn\" data-bs-close title=\"Close\">${I.x}</button>\n </div>\n </div>` : `\n <div class=\"bs-hdr\" style=\"justify-content:flex-end\">\n <button class=\"bs-close-btn\" data-bs-close title=\"Close\">${I.x}</button>\n </div>`;\n\n const useSidebar = currentLayout.tabPosition === 'left';\n const useBottomTabs = currentLayout.tabPosition === 'bottom';\n\n // If not logged in, show login form instead of tabs\n const contentHtml = user ? tabReport() : tabLogin();\n\n if (useSidebar) {\n modal.innerHTML = `\n ${headerHtml}\n <div class=\"bs-body-wrap\">\n ${user ? tabsHtml : ''}\n <div class=\"bs-scroll\">${contentHtml}</div>\n </div>`;\n } else if (useBottomTabs) {\n modal.innerHTML = `\n ${headerHtml}\n <div class=\"bs-scroll\">${contentHtml}</div>\n ${user ? `<div class=\"bs-tab-divider\"></div>${tabsHtml}` : ''}`;\n } else {\n modal.innerHTML = `\n ${headerHtml}\n ${user ? `${tabsHtml}<div class=\"bs-tab-divider\"></div>` : ''}\n <div class=\"bs-scroll\">${contentHtml}</div>`;\n }\n iframeDoc!.body.appendChild(modal);\n\n if (fab) fab.classList.add('bs-open');\n\n requestAnimationFrame(() => {\n backdrop?.classList.add('bs-in');\n modal?.classList.add('bs-in');\n });\n\n // Tab switching\n modal.querySelectorAll('.bs-tab').forEach(tab => {\n tab.addEventListener('click', () => switchTab((tab as HTMLElement).dataset.tab as typeof activeTab));\n });\n\n // Header settings icon\n modal.querySelector('.bs-hdr-icon[data-tab=\"settings\"]')?.addEventListener('click', () => switchTab('settings'));\n\n modal.querySelector('[data-bs-close]')?.addEventListener('click', close);\n backdrop.addEventListener('click', close);\n\n // Pin toggle\n modal.querySelector('[data-bs-pin-toggle]')?.addEventListener('click', () => {\n const active = togglePinMode();\n const btn = modal?.querySelector('[data-bs-pin-toggle]');\n if (btn) {\n btn.classList.toggle('active', active);\n btn.innerHTML = `\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>\n Pins ${active ? 'ON' : 'OFF'}\n `;\n }\n });\n\n // Logout\n modal.querySelector('[data-bs-logout]')?.addEventListener('click', () => {\n apiLogout();\n close();\n // Reopen to show login form\n setTimeout(() => open(), 300);\n });\n\n // Login form binding\n if (!user) {\n bindLoginForm();\n } else {\n bindTabContent();\n }\n\n const escHandler = (e: KeyboardEvent) => { if (e.key === 'Escape') { close(); document.removeEventListener('keydown', escHandler); } };\n document.addEventListener('keydown', escHandler);\n}\n\nfunction bindLoginForm() {\n if (!modal) return;\n\n const submitBtn = modal.querySelector('#bs-login-submit');\n const emailInput = modal.querySelector('#bs-login-email') as HTMLInputElement;\n const passInput = modal.querySelector('#bs-login-pass') as HTMLInputElement;\n const errorEl = modal.querySelector('#bs-login-error') as HTMLElement;\n\n if (!submitBtn || !emailInput || !passInput) return;\n\n const doLogin = async () => {\n const email = emailInput.value.trim();\n const password = passInput.value;\n\n if (!email || !password) {\n errorEl.textContent = 'Please enter email and password';\n errorEl.style.display = 'block';\n return;\n }\n\n submitBtn.setAttribute('disabled', 'true');\n (submitBtn as HTMLButtonElement).textContent = 'Signing in...';\n errorEl.style.display = 'none';\n\n const result = await apiLogin(email, password, config.projectId);\n\n if (result.success) {\n // Initialize live pins + realtime now that user is logged in\n initLivePins(config.projectId, shadow!);\n connectRealtime(config.projectId);\n // Reopen panel with full UI\n close();\n setTimeout(() => open(), 300);\n } else {\n errorEl.textContent = result.error || 'Invalid credentials';\n errorEl.style.display = 'block';\n submitBtn.removeAttribute('disabled');\n (submitBtn as HTMLButtonElement).textContent = 'Sign In';\n }\n };\n\n submitBtn.addEventListener('click', doLogin);\n passInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') doLogin(); });\n emailInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') passInput.focus(); });\n\n // Auto-focus email\n setTimeout(() => emailInput.focus(), 100);\n}\n\nfunction close() {\n if (!isOpen) return;\n if (fab) fab.classList.remove('bs-open');\n if (modal) {\n modal.classList.remove('bs-in');\n modal.classList.add('bs-out');\n }\n if (backdrop) backdrop.classList.remove('bs-in');\n\n setTimeout(() => {\n modal?.remove();\n backdrop?.remove();\n modal = null;\n backdrop = null;\n isOpen = false;\n }, 350);\n}\n\n// ─── Theme ───────────────────────────────────────────────\n\nfunction applyThemeVars(el: HTMLElement) {\n for (const [key, val] of Object.entries(currentTheme.vars)) {\n el.style.setProperty(key, val);\n }\n}\n\nexport function setTheme(themeId: string) {\n const theme = getThemeById(themeId);\n if (!theme) return;\n currentTheme = theme;\n if (modal) applyThemeVars(modal);\n if (fab) applyThemeVars(fab);\n if (toolbar) applyThemeVars(toolbar);\n}\n\nexport function getCurrentThemeId(): string {\n return currentTheme.id;\n}\n\n// ─── Layout ──────────────────────────────────────────────\n\nexport function setLayout(layoutId: string) {\n const layout = getLayoutById(layoutId);\n if (!layout) return;\n currentLayout = layout;\n // If modal is open, close and reopen with new layout\n if (isOpen) {\n close();\n setTimeout(open, 400);\n }\n}\n\nexport function getCurrentLayoutId(): string {\n return currentLayout.id;\n}\n\n// ─── FAB Drag-to-Reposition ──────────────────────────────\n\nfunction getSavedFabPosition(): { top: number; left: number } | null {\n try {\n const raw = localStorage.getItem(FAB_STORAGE_KEY);\n if (!raw) return null;\n const pos = JSON.parse(raw);\n if (typeof pos.top === 'number' && typeof pos.left === 'number') return pos;\n } catch { /* ignore */ }\n return null;\n}\n\nfunction saveFabPosition(top: number, left: number): void {\n try {\n localStorage.setItem(FAB_STORAGE_KEY, JSON.stringify({ top, left }));\n } catch { /* ignore */ }\n}\n\nfunction clampFabToViewport(top: number, left: number): { top: number; left: number } {\n const pad = 8;\n const size = 56;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n return {\n top: Math.max(pad, Math.min(vh - size - pad, top)),\n left: Math.max(pad, Math.min(vw - size - pad, left)),\n };\n}\n\nfunction applyFabPosition(top: number, left: number): void {\n if (!fab) return;\n const clamped = clampFabToViewport(top, left);\n fab.style.top = `${clamped.top}px`;\n fab.style.left = `${clamped.left}px`;\n fab.style.bottom = 'auto';\n fab.style.right = 'auto';\n updateToolbarPosition(clamped.top, clamped.left);\n}\n\nfunction updateToolbarPosition(fabTop: number, fabLeft: number): void {\n if (!toolbar) return;\n const size = 56;\n const gap = 8;\n // Toolbar appears above FAB\n const toolbarH = toolbar.offsetHeight || 200;\n let tTop = fabTop - toolbarH - gap;\n // If not enough room above, show below\n if (tTop < 8) {\n tTop = fabTop + size + gap;\n }\n toolbar.style.top = `${tTop}px`;\n toolbar.style.bottom = 'auto';\n // Align horizontally center with FAB\n toolbar.style.left = `${fabLeft + (size / 2) - 20}px`;\n toolbar.style.right = 'auto';\n}\n\nfunction makeFabDraggable(): void {\n if (!fab) return;\n\n let startX = 0;\n let startY = 0;\n let startTop = 0;\n let startLeft = 0;\n let moved = false;\n\n function cleanupDrag() {\n if (fab) {\n fab.removeEventListener('pointermove', onPointerMove);\n fab.removeEventListener('pointerup', onPointerUp);\n fab.classList.remove('bs-dragging');\n }\n dragCleanup = null;\n }\n\n function onPointerDown(e: PointerEvent) {\n if (!fab) return;\n isDragging = false;\n moved = false;\n startX = e.clientX;\n startY = e.clientY;\n const rect = fab.getBoundingClientRect();\n startTop = rect.top;\n startLeft = rect.left;\n fab.setPointerCapture(e.pointerId);\n fab.addEventListener('pointermove', onPointerMove);\n fab.addEventListener('pointerup', onPointerUp);\n dragCleanup = cleanupDrag;\n }\n\n function onPointerMove(e: PointerEvent) {\n const dx = e.clientX - startX;\n const dy = e.clientY - startY;\n if (!moved && Math.abs(dx) < 5 && Math.abs(dy) < 5) return;\n moved = true;\n isDragging = true;\n fab?.classList.add('bs-dragging');\n const newTop = startTop + dy;\n const newLeft = startLeft + dx;\n applyFabPosition(newTop, newLeft);\n }\n\n function onPointerUp(e: PointerEvent) {\n fab?.releasePointerCapture(e.pointerId);\n cleanupDrag();\n if (moved && fab) {\n const rect = fab.getBoundingClientRect();\n saveFabPosition(rect.top, rect.left);\n e.preventDefault();\n e.stopPropagation();\n setTimeout(() => { isDragging = false; }, 10);\n } else {\n isDragging = false;\n }\n }\n\n fab.addEventListener('pointerdown', onPointerDown);\n}\n\n// ─── Init / Destroy ──────────────────────────────────────\n\nexport function initPanel(cfg: BugStashConfig, sr: ShadowRoot) {\n config = cfg;\n shadow = sr;\n\n // ── Create iframe for panel UI (bulletproof CSS isolation) ──\n iframeEl = document.createElement('iframe');\n iframeEl.style.cssText =\n 'position:fixed;inset:0;z-index:2147483640;pointer-events:none;' +\n 'border:none;background:transparent;width:100%;height:100%;' +\n 'color-scheme:normal;';\n\n const iframeStyles = `\n @import url('https://fonts.googleapis.com/css2?family=Comfortaa:wght@400;600;700&family=Inter:wght@300;400;500;600;700&display=swap');\n ${STYLES}\n ${LAYOUT_CSS}\n html, body { margin: 0; padding: 0; background: transparent; pointer-events: none; overflow: hidden; }\n `;\n iframeEl.srcdoc = `<!DOCTYPE html><html><head><style>${iframeStyles}</style></head><body></body></html>`;\n\n iframeEl.addEventListener('load', () => {\n iframeDoc = iframeEl!.contentDocument;\n if (!iframeDoc) return;\n initPanelUI(cfg);\n });\n\n shadow.appendChild(iframeEl);\n\n // ── Keyboard Shortcuts (always on host document) ──\n registerKeyboardShortcuts(cfg);\n\n // ── Re-clamp FAB position on viewport resize ──\n resizeHandler = () => {\n if (!fab || isDragging) return;\n if (fab.style.top && fab.style.top !== 'auto') {\n const rect = fab.getBoundingClientRect();\n applyFabPosition(rect.top, rect.left);\n }\n };\n window.addEventListener('resize', resizeHandler);\n}\n\nfunction initPanelUI(cfg: BugStashConfig) {\n if (!iframeDoc) return;\n\n const side = cfg.panelPosition === 'bottom-left' ? 'left' : 'right';\n\n fab = iframeDoc.createElement('button') as HTMLButtonElement;\n fab.className = 'bs-fab';\n applyThemeVars(fab);\n fab.innerHTML = `${I.bug}<span class=\"bs-fab-label\">Report a bug</span>`;\n\n // Restore saved position or use default corner\n const savedPos = getSavedFabPosition();\n if (savedPos) {\n applyFabPosition(savedPos.top, savedPos.left);\n } else {\n fab.style[side] = '24px';\n }\n\n fab.addEventListener('click', () => {\n if (isDragging) return; // Ignore click after drag\n isOpen ? close() : open();\n });\n iframeDoc.body.appendChild(fab);\n\n // Make FAB draggable\n makeFabDraggable();\n\n // ── Quick Action Toolbar ──\n toolbar = iframeDoc.createElement('div') as HTMLDivElement;\n toolbar.className = 'bs-toolbar';\n if (savedPos) {\n // Position toolbar relative to saved FAB position\n updateToolbarPosition(savedPos.top, savedPos.left);\n } else {\n toolbar.style[side] = '32px';\n }\n applyThemeVars(toolbar);\n\n const isMac = navigator.platform.toUpperCase().includes('MAC');\n const mod = isMac ? '⌘' : 'Ctrl';\n\n const tbButtons: { icon: string; tip: string; kbd: string; action: () => void; id?: string }[] = [\n {\n icon: I.cam,\n tip: 'Screenshot',\n kbd: `${mod}+Shift+S`,\n action: async () => {\n const shot = await captureScreenshot(true);\n if (shot) {\n // Open panel to report tab with screenshot pre-attached\n if (!isOpen) open();\n setTimeout(() => {\n const area = modal?.querySelector('[data-bs-screenshot]') as HTMLElement;\n if (area) {\n (area as any).__screenshot = shot;\n area.classList.add('bs-captured');\n const title = area.querySelector('[data-bs-shot-title]');\n const sub = area.querySelector('[data-bs-shot-sub]');\n if (title) title.textContent = 'Screenshot captured!';\n if (sub) sub.textContent = 'Click to retake or annotate';\n // Trigger annotation setup\n area.click();\n }\n }, 400);\n }\n },\n },\n {\n icon: I.pin,\n tip: 'Toggle Pins',\n kbd: `${mod}+Shift+P`,\n id: 'bs-tb-pin',\n action: () => {\n const user = getCurrentUser();\n if (!user) {\n // Not logged in — open panel to show login\n if (!isOpen) open();\n return;\n }\n // Ensure live pins are initialized\n if (!shadow?.querySelector('#bugstash-live-pins')) {\n initLivePins(config.projectId, shadow!);\n connectRealtime(config.projectId);\n }\n const active = togglePinMode();\n const btn = toolbar?.querySelector('#bs-tb-pin');\n if (btn) btn.classList.toggle('bs-active', active);\n // Also update modal pin toggle if open\n const modalBtn = modal?.querySelector('[data-bs-pin-toggle]');\n if (modalBtn) {\n modalBtn.classList.toggle('active', active);\n modalBtn.innerHTML = `\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>\n Pins ${active ? 'ON' : 'OFF'}\n `;\n }\n },\n },\n {\n icon: currentTheme.id === 'black' ? I.sun : I.moon,\n tip: 'Toggle Theme',\n kbd: `${mod}+Shift+T`,\n id: 'bs-tb-theme',\n action: () => {\n const newId = currentTheme.id === 'black' ? 'white' : 'black';\n setTheme(newId);\n if (toolbar) applyThemeVars(toolbar);\n const btn = toolbar?.querySelector('#bs-tb-theme');\n if (btn) btn.innerHTML = `${currentTheme.id === 'black' ? I.sun : I.moon}<span class=\"bs-toolbar-tip\">${currentTheme.id === 'black' ? 'Light' : 'Dark'} Mode<span class=\"bs-toolbar-kbd\">${mod}+Shift+T</span></span>`;\n },\n },\n {\n icon: I.report,\n tip: 'Open Panel',\n kbd: `${mod}+Shift+B`,\n action: () => { isOpen ? close() : open(); },\n },\n ];\n\n for (const tb of tbButtons) {\n const btn = iframeDoc!.createElement('button') as HTMLButtonElement;\n btn.className = 'bs-toolbar-btn';\n if (tb.id) btn.id = tb.id;\n btn.innerHTML = `${tb.icon}<span class=\"bs-toolbar-tip\">${tb.tip}<span class=\"bs-toolbar-kbd\">${tb.kbd}</span></span>`;\n btn.addEventListener('click', (e) => { e.stopPropagation(); tb.action(); });\n toolbar.appendChild(btn);\n }\n\n iframeDoc!.body.appendChild(toolbar);\n\n // Show toolbar on FAB hover or always show after first interaction\n fab.addEventListener('mouseenter', () => { if (!isOpen) showToolbar(); });\n fab.addEventListener('mouseleave', (e) => {\n const related = e.relatedTarget as HTMLElement;\n if (!toolbar?.contains(related)) hideToolbar();\n });\n toolbar.addEventListener('mouseenter', () => showToolbar());\n toolbar.addEventListener('mouseleave', (e) => {\n const related = e.relatedTarget as HTMLElement;\n if (!fab?.contains(related)) hideToolbar();\n });\n}\n\nfunction registerKeyboardShortcuts(_cfg: BugStashConfig) {\n const isMac = navigator.platform.toUpperCase().includes('MAC');\n const mod = isMac ? '⌘' : 'Ctrl';\n void mod; // used only for tooltip display in toolbar buttons\n\n keyHandler = (e: KeyboardEvent) => {\n const hasModShift = (e.ctrlKey || e.metaKey) && e.shiftKey;\n if (!hasModShift) return;\n\n if (e.key === 'B' || e.key === 'b') {\n e.preventDefault();\n isOpen ? close() : open();\n } else if (e.key === 'S' || e.key === 's') {\n e.preventDefault();\n // Screenshot\n captureScreenshot(true).then(shot => {\n if (shot) {\n if (!isOpen) open();\n setTimeout(() => {\n const area = modal?.querySelector('[data-bs-screenshot]') as HTMLElement;\n if (area) {\n (area as any).__screenshot = shot;\n area.classList.add('bs-captured');\n const title = area.querySelector('[data-bs-shot-title]');\n const sub = area.querySelector('[data-bs-shot-sub]');\n if (title) title.textContent = 'Screenshot captured!';\n if (sub) sub.textContent = 'Click to retake or annotate';\n area.click();\n }\n }, 400);\n }\n });\n } else if (e.key === 'P' || e.key === 'p') {\n e.preventDefault();\n // Pin toggle\n const user = getCurrentUser();\n if (!user) {\n if (!isOpen) open();\n return;\n }\n if (!shadow?.querySelector('#bugstash-live-pins')) {\n initLivePins(_cfg.projectId, shadow!);\n connectRealtime(_cfg.projectId);\n }\n const active = togglePinMode();\n const btn = toolbar?.querySelector('#bs-tb-pin');\n if (btn) btn.classList.toggle('bs-active', active);\n const modalBtn = modal?.querySelector('[data-bs-pin-toggle]');\n if (modalBtn) {\n modalBtn.classList.toggle('active', active);\n modalBtn.innerHTML = `\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>\n Pins ${active ? 'ON' : 'OFF'}\n `;\n }\n } else if (e.key === 'T' || e.key === 't') {\n e.preventDefault();\n // Theme toggle\n const isMacKbd = navigator.platform.toUpperCase().includes('MAC');\n const modKey = isMacKbd ? '⌘' : 'Ctrl';\n const newId = currentTheme.id === 'black' ? 'white' : 'black';\n setTheme(newId);\n if (toolbar) applyThemeVars(toolbar);\n const themeBtn = toolbar?.querySelector('#bs-tb-theme');\n if (themeBtn) themeBtn.innerHTML = `${currentTheme.id === 'black' ? I.sun : I.moon}<span class=\"bs-toolbar-tip\">${currentTheme.id === 'black' ? 'Light' : 'Dark'} Mode<span class=\"bs-toolbar-kbd\">${modKey}+Shift+T</span></span>`;\n }\n };\n document.addEventListener('keydown', keyHandler);\n}\n\nfunction showToolbar() {\n if (toolbarVisible || isOpen) return;\n toolbarVisible = true;\n toolbar?.classList.add('bs-show');\n}\n\nfunction hideToolbar() {\n toolbarVisible = false;\n toolbar?.classList.remove('bs-show');\n}\n\nexport function destroyPanel() {\n close();\n dragCleanup?.();\n isDragging = false;\n fab?.remove();\n fab = null;\n toolbar?.remove();\n toolbar = null;\n toolbarVisible = false;\n iframeEl?.remove();\n iframeEl = null;\n iframeDoc = null;\n shadow = null;\n if (keyHandler) document.removeEventListener('keydown', keyHandler);\n keyHandler = null;\n if (resizeHandler) window.removeEventListener('resize', resizeHandler);\n resizeHandler = null;\n}\n","/**\n * Annotation drawing tool for screenshots.\n * Provides a canvas overlay for drawing arrows, rectangles, circles, and freehand on screenshots.\n */\n\nimport type { AnnotationShape } from '@bugstash/shared';\n\nexport { AnnotationShape };\n\nexport interface AnnotationResult {\n dataUrl: string; // The annotated screenshot as a data URL\n annotations: AnnotationShape[];\n}\n\nlet overlay: HTMLDivElement | null = null;\nlet canvas: HTMLCanvasElement | null = null;\nlet ctx: CanvasRenderingContext2D | null = null;\nlet screenshotImg: HTMLImageElement | null = null;\nlet currentTool: AnnotationShape['type'] = 'freehand';\nlet currentColor = '#ef4444';\nlet lineWidth = 3;\nlet shapes: AnnotationShape[] = [];\nlet currentShape: AnnotationShape | null = null;\nlet isDrawing = false;\nlet resolvePromise: ((result: AnnotationResult | null) => void) | null = null;\n\nconst TOOLS: { id: AnnotationShape['type']; label: string; icon: string }[] = [\n { id: 'freehand', label: 'Draw', icon: 'M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25z' },\n { id: 'rectangle', label: 'Rect', icon: 'M3 3h18v18H3V3zm2 2v14h14V5H5z' },\n { id: 'circle', label: 'Circle', icon: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' },\n { id: 'arrow', label: 'Arrow', icon: 'M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z' },\n];\n\nconst COLORS = ['#ef4444', '#f97316', '#eab308', '#22c55e', '#3b82f6', '#8b5cf6', '#ffffff', '#000000'];\n\n/**\n * Opens the annotation editor overlay on a screenshot.\n * Returns a promise that resolves when the user saves or cancels.\n */\nexport function openAnnotationEditor(screenshotDataUrl: string): Promise<AnnotationResult | null> {\n return new Promise((resolve) => {\n resolvePromise = resolve;\n shapes = [];\n currentShape = null;\n currentTool = 'freehand';\n currentColor = '#ef4444';\n\n createOverlay(screenshotDataUrl);\n });\n}\n\nfunction createOverlay(screenshotDataUrl: string) {\n if (overlay) overlay.remove();\n\n overlay = document.createElement('div');\n overlay.id = 'bs-annotation-overlay';\n\n const style = document.createElement('style');\n style.textContent = `\n #bs-annotation-overlay {\n position: fixed; inset: 0; z-index: 2147483647;\n background: rgba(0,0,0,0.85);\n display: flex; flex-direction: column;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n .bs-ann-toolbar {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 16px; background: #1a1d2e;\n border-bottom: 1px solid #333;\n }\n .bs-ann-tool {\n width: 36px; height: 36px; border-radius: 8px;\n border: 2px solid transparent; background: #222639;\n cursor: pointer; display: flex; align-items: center; justify-content: center;\n transition: all 0.15s;\n }\n .bs-ann-tool:hover { border-color: #555; }\n .bs-ann-tool.active { border-color: #6E9ED0; background: #2a3550; }\n .bs-ann-tool svg { width: 18px; height: 18px; fill: #ccc; }\n .bs-ann-color {\n width: 24px; height: 24px; border-radius: 50%;\n border: 2px solid transparent; cursor: pointer;\n transition: transform 0.15s;\n }\n .bs-ann-color:hover { transform: scale(1.15); }\n .bs-ann-color.active { border-color: #fff; }\n .bs-ann-sep { width: 1px; height: 28px; background: #444; margin: 0 6px; }\n .bs-ann-btn {\n padding: 8px 18px; border-radius: 8px; border: none;\n font-size: 13px; font-weight: 600; cursor: pointer;\n margin-left: auto;\n }\n .bs-ann-cancel { background: #333; color: #aaa; margin-left: 8px; }\n .bs-ann-cancel:hover { background: #444; color: #fff; }\n .bs-ann-save { background: linear-gradient(135deg, #6E9ED0, #8FAFD6); color: #fff; }\n .bs-ann-save:hover { opacity: 0.9; }\n .bs-ann-undo { background: #333; color: #aaa; font-size: 12px; padding: 6px 12px; }\n .bs-ann-undo:hover { color: #fff; }\n .bs-ann-canvas-wrap {\n flex: 1; display: flex; align-items: center; justify-content: center;\n overflow: hidden; padding: 16px;\n }\n .bs-ann-canvas-wrap canvas { cursor: crosshair; border-radius: 4px; }\n `;\n\n overlay.appendChild(style);\n\n // Toolbar\n const toolbar = document.createElement('div');\n toolbar.className = 'bs-ann-toolbar';\n\n // Tool buttons\n for (const tool of TOOLS) {\n const btn = document.createElement('button');\n btn.className = `bs-ann-tool${tool.id === currentTool ? ' active' : ''}`;\n btn.title = tool.label;\n btn.innerHTML = `<svg viewBox=\"0 0 24 24\"><path d=\"${tool.icon}\"/></svg>`;\n btn.addEventListener('click', () => {\n currentTool = tool.id;\n toolbar.querySelectorAll('.bs-ann-tool').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n });\n toolbar.appendChild(btn);\n }\n\n toolbar.appendChild(createSep());\n\n // Color buttons\n for (const color of COLORS) {\n const btn = document.createElement('button');\n btn.className = `bs-ann-color${color === currentColor ? ' active' : ''}`;\n btn.style.background = color;\n btn.addEventListener('click', () => {\n currentColor = color;\n toolbar.querySelectorAll('.bs-ann-color').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n });\n toolbar.appendChild(btn);\n }\n\n toolbar.appendChild(createSep());\n\n // Undo\n const undoBtn = document.createElement('button');\n undoBtn.className = 'bs-ann-btn bs-ann-undo';\n undoBtn.textContent = 'Undo';\n undoBtn.addEventListener('click', () => {\n shapes.pop();\n redrawCanvas();\n });\n toolbar.appendChild(undoBtn);\n\n // Save / Cancel\n const saveBtn = document.createElement('button');\n saveBtn.className = 'bs-ann-btn bs-ann-save';\n saveBtn.textContent = 'Save';\n saveBtn.addEventListener('click', saveAnnotation);\n\n const cancelBtn = document.createElement('button');\n cancelBtn.className = 'bs-ann-btn bs-ann-cancel';\n cancelBtn.textContent = 'Cancel';\n cancelBtn.addEventListener('click', () => {\n cleanup();\n resolvePromise?.(null);\n });\n\n toolbar.appendChild(saveBtn);\n toolbar.appendChild(cancelBtn);\n overlay.appendChild(toolbar);\n\n // Canvas\n const canvasWrap = document.createElement('div');\n canvasWrap.className = 'bs-ann-canvas-wrap';\n\n canvas = document.createElement('canvas');\n ctx = canvas.getContext('2d')!;\n canvasWrap.appendChild(canvas);\n overlay.appendChild(canvasWrap);\n\n document.body.appendChild(overlay);\n\n // Load screenshot\n screenshotImg = new Image();\n screenshotImg.onload = () => {\n if (!canvas || !ctx || !screenshotImg) return;\n\n // Fit to viewport\n const maxW = window.innerWidth - 32;\n const maxH = window.innerHeight - 100;\n let w = screenshotImg.width;\n let h = screenshotImg.height;\n const scale = Math.min(1, maxW / w, maxH / h);\n w = Math.round(w * scale);\n h = Math.round(h * scale);\n\n canvas.width = w;\n canvas.height = h;\n redrawCanvas();\n setupCanvasEvents();\n };\n screenshotImg.src = screenshotDataUrl;\n}\n\nfunction createSep(): HTMLDivElement {\n const sep = document.createElement('div');\n sep.className = 'bs-ann-sep';\n return sep;\n}\n\nfunction setupCanvasEvents() {\n if (!canvas) return;\n\n canvas.addEventListener('mousedown', (e) => {\n isDrawing = true;\n const { x, y } = getCanvasPos(e);\n\n currentShape = {\n type: currentTool,\n color: currentColor,\n lineWidth,\n points: [{ x, y }],\n x, y, width: 0, height: 0,\n };\n });\n\n canvas.addEventListener('mousemove', (e) => {\n if (!isDrawing || !currentShape) return;\n const { x, y } = getCanvasPos(e);\n\n if (currentShape.type === 'freehand') {\n currentShape.points!.push({ x, y });\n } else {\n currentShape.width = x - currentShape.x!;\n currentShape.height = y - currentShape.y!;\n }\n redrawCanvas();\n drawShape(currentShape);\n });\n\n const endDraw = () => {\n if (isDrawing && currentShape) {\n shapes.push(currentShape);\n currentShape = null;\n }\n isDrawing = false;\n redrawCanvas();\n };\n\n canvas.addEventListener('mouseup', endDraw);\n canvas.addEventListener('mouseleave', endDraw);\n}\n\nfunction getCanvasPos(e: MouseEvent): { x: number; y: number } {\n const rect = canvas!.getBoundingClientRect();\n return {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top,\n };\n}\n\nfunction redrawCanvas() {\n if (!ctx || !canvas || !screenshotImg) return;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(screenshotImg, 0, 0, canvas.width, canvas.height);\n for (const shape of shapes) {\n drawShape(shape);\n }\n}\n\nfunction drawShape(shape: AnnotationShape) {\n if (!ctx) return;\n ctx.strokeStyle = shape.color;\n ctx.fillStyle = shape.color;\n ctx.lineWidth = shape.lineWidth;\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n\n switch (shape.type) {\n case 'freehand': {\n if (!shape.points || shape.points.length < 2) return;\n ctx.beginPath();\n ctx.moveTo(shape.points[0].x, shape.points[0].y);\n for (let i = 1; i < shape.points.length; i++) {\n ctx.lineTo(shape.points[i].x, shape.points[i].y);\n }\n ctx.stroke();\n break;\n }\n case 'rectangle': {\n ctx.strokeRect(shape.x!, shape.y!, shape.width!, shape.height!);\n break;\n }\n case 'circle': {\n const cx = shape.x! + shape.width! / 2;\n const cy = shape.y! + shape.height! / 2;\n const rx = Math.abs(shape.width!) / 2;\n const ry = Math.abs(shape.height!) / 2;\n ctx.beginPath();\n ctx.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);\n ctx.stroke();\n break;\n }\n case 'arrow': {\n const startX = shape.x!;\n const startY = shape.y!;\n const endX = shape.x! + shape.width!;\n const endY = shape.y! + shape.height!;\n const headLen = 14;\n const angle = Math.atan2(endY - startY, endX - startX);\n\n ctx.beginPath();\n ctx.moveTo(startX, startY);\n ctx.lineTo(endX, endY);\n ctx.stroke();\n\n // Arrowhead\n ctx.beginPath();\n ctx.moveTo(endX, endY);\n ctx.lineTo(endX - headLen * Math.cos(angle - Math.PI / 6), endY - headLen * Math.sin(angle - Math.PI / 6));\n ctx.lineTo(endX - headLen * Math.cos(angle + Math.PI / 6), endY - headLen * Math.sin(angle + Math.PI / 6));\n ctx.closePath();\n ctx.fill();\n break;\n }\n }\n}\n\nfunction saveAnnotation() {\n if (!canvas) { cleanup(); resolvePromise?.(null); return; }\n const dataUrl = canvas.toDataURL('image/png');\n const result: AnnotationResult = { dataUrl, annotations: shapes };\n cleanup();\n resolvePromise?.(result);\n}\n\nfunction cleanup() {\n overlay?.remove();\n overlay = null;\n canvas = null;\n ctx = null;\n screenshotImg = null;\n shapes = [];\n currentShape = null;\n isDrawing = false;\n}\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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","names":["index_exports","__export","BugStash","index_default","__toCommonJS","crumbs","maxCrumbs","clickHandler","inputHandler","popstateHandler","hashHandler","getSelector","el","tag","cls","text","label","addBreadcrumb","crumb","initBreadcrumbs","max","e","target","inputTimers","existing","isPassword","getBreadcrumbs","clearBreadcrumbs","restoreBreadcrumbs","REDACT_PLACEHOLDER","PATTERNS","match","eqIdx","colonIdx","redactString","input","result","pattern","replacement","PATTERNS","redactLogArgs","args","redactString","redactObject","obj","result","key","value","lk","REDACT_PLACEHOLDER","originals","logs","maxLogs","serialize","args","a","capture","level","entry","redactLogArgs","addBreadcrumb","initLogger","max","getLogs","clearLogs","restoreConsole","captures","maxCaptures","originalFetch","originalXHROpen","originalXHRSend","record","entry","addBreadcrumb","shortenUrl","url","u","params","key","lk","qs","redactString","patchFetch","input","init","method","rawUrl","start","response","err","patchXHR","rest","body","initNetwork","max","getNetworkCaptures","getFailedNetworkCaptures","c","clearNetworkCaptures","restoreNetwork","errors","onErrorHandler","onRejectionHandler","initErrors","event","entry","addBreadcrumb","reason","message","getErrors","clearErrors","restoreErrors","metrics","lcpObserver","clsObserver","fidObserver","initPerformance","onLoad","nav","paints","p","mem","list","entries","last","clsValue","entry","getPerformanceMetrics","restorePerformance","resolveUrl","url","baseUrl","doc","base","a","uuid","counter","random","toArray","arrayLike","arr","i","l","styleProps","getStyleProperties","options","px","node","styleProperty","val","getNodeWidth","leftBorder","rightBorder","getNodeHeight","topBorder","bottomBorder","getImageSize","targetNode","width","height","getPixelRatio","ratio","FINAL_PROCESS","canvasDimensionLimit","checkCanvasDimensions","canvas","createImage","url","resolve","reject","img","svgToDataURL","svg","html","nodeToDataURL","node","width","height","xmlns","foreignObject","isInstanceOfElement","instance","nodePrototype","formatCSSText","style","content","formatCSSProperties","options","getStyleProperties","name","value","priority","getPseudoElementStyle","className","pseudo","selector","cssText","clonePseudoElement","nativeNode","clonedNode","uuid","styleElement","clonePseudoElements","WOFF","JPEG","mimes","getExtension","url","match","getMimeType","extension","getContentFromDataUrl","dataURL","isDataUrl","url","makeDataUrl","content","mimeType","fetchAsDataURL","init","process","res","blob","resolve","reject","reader","error","cache","getCacheKey","contentType","includeQueryParams","key","resourceToDataURL","resourceUrl","options","cacheKey","result","msg","cloneCanvasElement","canvas","dataURL","createImage","cloneVideoElement","video","options","ctx","poster","contentType","getMimeType","resourceToDataURL","cloneIFrameElement","iframe","_a","cloneNode","cloneSingleNode","node","isInstanceOfElement","isSVGElement","isSlotElement","cloneChildren","nativeNode","clonedNode","children","toArray","_b","deferred","child","clonedChild","cloneCSSStyle","targetStyle","sourceStyle","getStyleProperties","name","value","cloneInputValue","cloneSelectValue","selectedOption","decorate","clonePseudoElements","ensureSVGSymbols","clone","uses","processedDefs","i","id","exist","definition","nodes","ns","svg","defs","isRoot","URL_REGEX","URL_WITH_FORMAT_REGEX","FONT_SRC_REGEX","toRegex","url","escaped","parseURLs","cssText","urls","raw","quotation","isDataUrl","embed","resourceURL","baseURL","options","getContentFromUrl","resolvedURL","resolveUrl","contentType","getMimeType","dataURL","content","makeDataUrl","resourceToDataURL","filterPreferredFontFormat","str","preferredFontFormat","match","src","format","shouldEmbed","embedResources","baseUrl","filteredCSSText","deferred","css","embedProp","propName","node","options","propValue","_a","cssString","embedResources","embedBackground","clonedNode","embedImageNode","isImageElement","isInstanceOfElement","isDataUrl","url","dataURL","resourceToDataURL","getMimeType","resolve","reject","attributes","error","image","embedChildren","deferreds","toArray","child","embedImages","applyStyle","node","options","style","manual","key","cssFetchCache","fetchCSS","url","cache","cssText","embedFonts","data","options","regexUrl","loadFonts","loc","fetchAsDataURL","result","parseCSS","source","commentsRegex","keyframesRegex","matches","importRegex","combinedCSSRegex","unifiedRegex","getCSSRules","styleSheets","ret","deferreds","sheet","toArray","item","index","importIndex","deferred","metadata","rule","error","e","inline","err","getWebFontRules","cssRules","shouldEmbed","parseWebFontRules","node","normalizeFontFamily","font","getUsedFonts","fonts","traverse","child","getWebFontCSS","rules","usedFonts","baseUrl","embedResources","embedWebFonts","clonedNode","styleNode","sytleContent","toSvg","node","options","width","height","getImageSize","clonedNode","cloneNode","embedWebFonts","embedImages","applyStyle","nodeToDataURL","toCanvas","svg","img","createImage","canvas","context","ratio","getPixelRatio","canvasWidth","canvasHeight","checkCanvasDimensions","toPng","node","options","toCanvas","showFlashAnimation","flash","style","isBugStashUI","el","tag","captureScreenshot","native","captureWithDisplayMedia","captureWithHtmlToImage","stream","video","resolve","canvas","ctx","t","skipCrossOriginImages","bodyBg","htmlBg","isTransparent","c","bgColor","toPng","node","src","PRIMARY_ENDPOINT","FALLBACK_ENDPOINT","endpoint","_usingFallback","setEndpoint","url","getEndpoint","fetchWithFallback","init","err","previousEndpoint","fallbackUrl","STORAGE_KEY","getStoredAuth","raw","auth","setStoredAuth","clearStoredAuth","getCurrentUser","getAccessToken","authHeaders","res","data","login","email","password","projectId","logout","submitReport","report","headers","authHeaders","fetchWithFallback","endpoint","fetchPagePins","projectId","pathname","createPin","pin","updatePin","pinId","updates","deletePin","fetchComments","createComment","body","mentions","fetchProjectMembers","_domainVerifyPromise","verifyDomain","res","QUEUE_KEY","queueOfflineAction","action","queue","getOfflineQueue","flushOfflineQueue","flushed","remaining","result","THEMES","getThemes","getThemeById","id","t","getDefaultTheme","LAYOUTS","getLayouts","getLayoutById","id","l","getDefaultLayout","LAYOUT_CSS","pollTimer","lastPollTime","POLL_INTERVAL","handlers","currentProjectId","knownPinIds","connectRealtime","projectId","startPolling","poll","token","getAccessToken","endpoint","getEndpoint","pathname","res","data","pins","pin","emit","disconnectRealtime","onRealtimeEvent","type","handler","event","h","registerKnownPins","pinIds","isConnected","pollTimer","projectId","container","clickOverlay","pins","members","pinMode","activePopup","currentPathname","repositionRAF","mutationObserver","nestedScrollCleanups","resizeObserver","shadow","_fixedOffset","probeFixedOffset","probe","rect","toFixedCSS","pos","viewportToFixed","vx","vy","STATUS_COLORS","PRIORITY_COLORS","initLivePins","projId","sr","createOverlay","loadPins","loadMembers","setupRealtimeListeners","watchNavigation","setupRepositionListeners","destroyLivePins","teardownRepositionListeners","togglePinMode","enabled","isPinModeActive","resolvePosition","pin","pageW","pageH","scrollX","scrollY","el","findElement","isElementRelative","hasPercent","hidden","isElementClipped","storedAbsX","storedAbsY","elCenterVX","elCenterVY","storedVX","storedVY","fallbackX","fallbackY","selector","xpath","selectors","parsed","sel","result","parent","style","oy","ox","pr","scheduleReposition","handleKeyDown","mutations","m","detachNestedScrollListeners","e","closePopup","f","repositionPins","dot","pinId","p","getScrollableAncestors","ancestors","current","overflowY","overflowX","attachNestedScrollListeners","seen","ancestor","handler","cleanup","clientX","clientY","pageX","pageY","xPercent","yPercent","showNewPinForm","fetchPagePins","registerKnownPins","renderPins","fetchProjectMembers","statusColor","initials","getInitials","gradientBg","getAvatarGradient","avatarContent","escapeHtml","badgeHtml","showPinPopup","timeAgo","ts","time","diff","mins","hrs","clampToViewport","pad","dx","dy","curLeft","curTop","dotEl","popup","user","getCurrentUser","pinCreator","canManage","prioColor","prioLabel","creatorInitials","creatorGradient","creatorAvatarHtml","statusLabel","sendIconSvg","closeIconSvg","fetchComments","commentsRes","cmtsEl","comments","c","renderCommentHtml","input","body","res","createComment","queueOfflineAction","updatePin","idx","i","deleting","deletePin","cssEscape","str","getSelectorChain","el","selectors","attr","val","cssEscape","escaped","aria","candidate","getStructuralPath","parts","current","node","parent","tag","siblings","c","getXPath","idx","sib","showNewPinForm","pageX","pageY","xPct","yPct","clientX","clientY","targetEl","closePopup","container","e","form","formW","pad","left","top","formPos","viewportToFixed","rect","adjusted","memberOptions","members","m","getCurrentUser","escapeHtml","setupSegmentedRow","title","submitBtn","desc","priority","getSegmentedValue","category","assigneeId","selector","xpath","logs","getLogs","l","errors","getErrors","netErrors","getFailedNetworkCaptures","n","pinData","projectId","res","createPin","pins","renderPins","queueOfflineAction","currentUser","setupRealtimeListeners","onRealtimeEvent","event","pin","p","registerKnownPins","updated","i","id","comment","activePopup","cmtsEl","renderCommentHtml","watchNavigation","lastPath","check","loadPins","origPush","origReplace","args","getInitials","name","w","AVATAR_GRADIENTS","getAvatarGradient","hash","avatar","commentInitials","commentGradient","avatarInner","timeAgo","row","btn","b","str","div","config","fab","toolbar","modal","backdrop","keyHandler","shadow","iframeEl","iframeDoc","isOpen","toolbarVisible","isDragging","resizeHandler","dragCleanup","FAB_STORAGE_KEY","activeTab","currentTheme","getDefaultTheme","currentLayout","getDefaultLayout","I","STYLES","tabLogin","esc","s","timeAgo","ts","fmtTime","HISTORY_KEY","getReportHistory","saveReportHistory","entries","addToHistory","entry","id","deleteFromHistory","e","updateInHistory","updates","idx","buildContext","config","autoDetect","errors","getErrors","logs","getLogs","net","getNetworkCaptures","failedNet","getFailedNetworkCaptures","crumbs","getBreadcrumbs","perf","getPerformanceMetrics","consoleErrors","l","severity","tags","tabReport","d","categories","hasIssues","c","tabConsole","lvMap","tabNetwork","caps","n","tabContext","html","errs","bars","label","val","max","pct","p","b","ctx","tabHistory","catLabels","fmtDate","diffMs","diffMin","diffH","diffD","pinsHtml","tabSettings","themes","getThemes","layouts","getLayouts","t","setupAnnotation","container","screenshotData","COLORS","currentColor","currentTool","brushSize","zoom","isDark","shapes","pins","selectedIdx","hoveredIdx","dragging","drawing","dragOffX","dragOffY","startX","startY","currentDraw","PIN_COLORS","img","wrap","viewport","canvas","toolbar","tIcons","toolNames","toolBtns","setTool","btn","color","i","sizeSlider","right","mkBtn","title","svg","zoomOut","zoomLabel","zoomIn","zoomReset","undoBtn","clearBtn","applyZoom","el","pinLayer","pinList","renderPins","pin","pctX","pctY","pinDragging","onMove","me","r","onUp","item","del","outlineColor","drawOutline","fn","lw","renderShape","preview","alpha","stroke","angle","headLen","fontSize","isSelected","isHovered","shapeBounds","handles","hx","hy","render","x","y","minX","minY","maxX","maxY","hitTest","pad","moveShape","dx","dy","scale","samplePoints","totalBrightness","sx","sy","px","coords","autoSelectDrag","hit","note","input","rx","ry","cx2","cy2","endDraw","keyHandler","bakePins","switchTab","tab","modal","activeTab","scroll","renderers","bindTabContent","card","existing","confirm","yes","no","editSev","sb","row","save","cancel","newTitle","newDesc","setTheme","layout","getLayoutById","close","open","cat","sev","annotator","titleEl","subEl","area","backdrop","captureScreenshot","form","description","category","detected","report","result","submitReport","iframeDoc","isOpen","hideToolbar","fails","applyThemeVars","tabsHtml","user","getCurrentUser","initials","w","pinActive","isPinModeActive","headerHtml","useSidebar","useBottomTabs","contentHtml","fab","active","togglePinMode","logout","bindLoginForm","escHandler","submitBtn","emailInput","passInput","errorEl","doLogin","email","password","login","initLivePins","shadow","connectRealtime","key","themeId","theme","getThemeById","getCurrentThemeId","setLayout","layoutId","getCurrentLayoutId","getSavedFabPosition","raw","FAB_STORAGE_KEY","pos","saveFabPosition","top","left","clampFabToViewport","vw","vh","applyFabPosition","clamped","updateToolbarPosition","fabTop","fabLeft","size","gap","toolbarH","tTop","makeFabDraggable","startTop","startLeft","moved","cleanupDrag","onPointerMove","onPointerUp","dragCleanup","onPointerDown","isDragging","rect","newTop","newLeft","initPanel","cfg","sr","iframeEl","iframeStyles","LAYOUT_CSS","initPanelUI","registerKeyboardShortcuts","resizeHandler","side","savedPos","mod","tbButtons","shot","sub","modalBtn","newId","tb","showToolbar","related","_cfg","modKey","themeBtn","toolbarVisible","destroyPanel","overlay","canvas","ctx","screenshotImg","currentTool","currentColor","lineWidth","shapes","currentShape","isDrawing","resolvePromise","TOOLS","COLORS","openAnnotationEditor","screenshotDataUrl","resolve","createOverlay","style","toolbar","tool","btn","b","createSep","color","undoBtn","redrawCanvas","saveBtn","saveAnnotation","cancelBtn","cleanup","canvasWrap","maxW","maxH","w","h","scale","setupCanvasEvents","sep","x","y","getCanvasPos","drawShape","endDraw","e","rect","shape","i","cx","cy","rx","ry","startX","startY","endX","endY","headLen","angle","result","initialized","shadowRoot","getOrCreateShadowRoot","host","initModules","options","shadow","initBreadcrumbs","initLogger","initNetwork","initErrors","initPerformance","initPanel","getCurrentUser","initLivePins","connectRealtime","detectEnvironment","BugStash","setEndpoint","verifyDomain","allowed","destroyPanel","destroyLivePins","disconnectRealtime","restoreConsole","restoreNetwork","restoreErrors","restoreBreadcrumbs","restorePerformance","getLogs","clearLogs","getNetworkCaptures","getFailedNetworkCaptures","clearNetworkCaptures","getErrors","clearErrors","getBreadcrumbs","clearBreadcrumbs","getPerformanceMetrics","addBreadcrumb","getThemes","getThemeById","setTheme","getCurrentThemeId","getLayouts","getLayoutById","setLayout","getCurrentLayoutId","login","logout","togglePinMode","isPinModeActive","isConnected","openAnnotationEditor","redactString","redactObject","index_default"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/breadcrumbs.ts","../src/redact.ts","../src/logger.ts","../src/network.ts","../src/errors.ts","../src/performance.ts","../../node_modules/html-to-image/src/util.ts","../../node_modules/html-to-image/src/clone-pseudos.ts","../../node_modules/html-to-image/src/mimes.ts","../../node_modules/html-to-image/src/dataurl.ts","../../node_modules/html-to-image/src/clone-node.ts","../../node_modules/html-to-image/src/embed-resources.ts","../../node_modules/html-to-image/src/embed-images.ts","../../node_modules/html-to-image/src/apply-style.ts","../../node_modules/html-to-image/src/embed-webfonts.ts","../../node_modules/html-to-image/src/index.ts","../src/screenshot.ts","../src/api.ts","../src/themes.ts","../src/layouts.ts","../src/realtime.ts","../src/pin-styles.ts","../src/livepins.ts","../src/panel.ts","../src/annotation.ts"],"sourcesContent":["import type { BugStashConfig } from '@bugstash/shared';\nimport { initPanel, destroyPanel, setTheme, getCurrentThemeId, setLayout, getCurrentLayoutId } from './panel';\nimport { initLogger, getLogs, clearLogs, restoreConsole } from './logger';\nimport { initNetwork, getNetworkCaptures, getFailedNetworkCaptures, clearNetworkCaptures, restoreNetwork } from './network';\nimport { initErrors, getErrors, clearErrors, restoreErrors } from './errors';\nimport { initBreadcrumbs, getBreadcrumbs, addBreadcrumb, clearBreadcrumbs, restoreBreadcrumbs } from './breadcrumbs';\nimport { initPerformance, getPerformanceMetrics, restorePerformance } from './performance';\nimport { setEndpoint, getCurrentUser, login, logout, verifyDomain } from './api';\nimport { getThemes, getThemeById } from './themes';\nimport { getLayouts, getLayoutById } from './layouts';\nimport { initLivePins, destroyLivePins, togglePinMode, isPinModeActive } from './livepins';\nimport { connectRealtime, disconnectRealtime, isConnected } from './realtime';\nimport { openAnnotationEditor, type AnnotationResult } from './annotation';\nimport { redactString, redactObject } from './redact';\n\nexport type { AnnotationResult };\n\nexport type {\n BugStashConfig,\n LogEntry,\n NetworkEntry,\n ErrorEntry,\n Breadcrumb,\n PerformanceMetrics,\n BugReport,\n ReportContext,\n APIResponse,\n AuthUser,\n AuthTokens,\n LivePin,\n PinComment,\n Member,\n Organization,\n Project,\n Webhook,\n WebhookEvent,\n Integration,\n IntegrationType,\n SourceMap,\n PlanLimits,\n QuotaStatus,\n OrgBranding,\n AnnotationShape,\n TwoFactorSetup,\n TwoFactorStatus,\n DuplicateMatch,\n} from '@bugstash/shared';\n\nlet initialized = false;\nlet shadowRoot: ShadowRoot | null = null;\n\nfunction getOrCreateShadowRoot(): ShadowRoot {\n if (shadowRoot) return shadowRoot;\n // Custom element tag — immune to host CSS rules targeting div, span, p, *, etc.\n const host = document.createElement('bugstash-root');\n\n // ─── Core positioning ───\n host.style.setProperty('position', 'fixed', 'important');\n host.style.setProperty('inset', '0', 'important');\n host.style.setProperty('pointer-events', 'none', 'important');\n host.style.setProperty('z-index', '2147483640', 'important');\n host.style.setProperty('display', 'block', 'important');\n host.style.setProperty('visibility', 'visible', 'important');\n host.style.setProperty('opacity', '1', 'important');\n\n // ─── Prevent host from creating a containing block for fixed children ───\n // CSS spec: transform, perspective, filter, contain, will-change create\n // new containing blocks that break position:fixed on descendants.\n host.style.setProperty('transform', 'none', 'important');\n host.style.setProperty('perspective', 'none', 'important');\n host.style.setProperty('filter', 'none', 'important');\n host.style.setProperty('will-change', 'auto', 'important');\n host.style.setProperty('contain', 'none', 'important');\n host.style.setProperty('isolation', 'auto', 'important');\n host.style.setProperty('mix-blend-mode', 'normal', 'important');\n host.style.setProperty('clip-path', 'none', 'important');\n\n // ─── Resist host CSS interference ───\n host.style.setProperty('margin', '0', 'important');\n host.style.setProperty('padding', '0', 'important');\n host.style.setProperty('border', 'none', 'important');\n host.style.setProperty('background', 'none', 'important');\n host.style.setProperty('box-sizing', 'border-box', 'important');\n host.style.setProperty('overflow', 'visible', 'important');\n host.style.setProperty('min-width', '0', 'important');\n host.style.setProperty('min-height', '0', 'important');\n host.style.setProperty('max-width', 'none', 'important');\n host.style.setProperty('max-height', 'none', 'important');\n host.style.setProperty('float', 'none', 'important');\n host.style.setProperty('clear', 'none', 'important');\n host.style.setProperty('columns', 'auto', 'important');\n host.style.setProperty('font-size', '16px', 'important');\n host.style.setProperty('line-height', 'normal', 'important');\n host.style.setProperty('text-align', 'left', 'important');\n host.style.setProperty('direction', 'ltr', 'important');\n\n shadowRoot = host.attachShadow({ mode: 'closed' });\n document.body.appendChild(host);\n return shadowRoot;\n}\n\nfunction initModules(options: BugStashConfig) {\n if (initialized) return;\n initialized = true;\n\n const shadow = getOrCreateShadowRoot();\n\n // Order matters: breadcrumbs first (other modules push to it)\n initBreadcrumbs(options.maxBreadcrumbs);\n initLogger(options.maxLogs);\n initNetwork(options.maxNetworkCaptures);\n initErrors();\n if (options.enablePerformance !== false) initPerformance();\n initPanel(options, shadow);\n\n // Init live pins if enabled and user is logged in\n if (options.enableLivePins !== false) {\n const user = getCurrentUser();\n if (user) {\n initLivePins(options.projectId, shadow);\n connectRealtime(options.projectId);\n }\n }\n}\n\n/**\n * Auto-detect the environment from the current hostname when `environment`\n * is not explicitly set.\n *\n * Production hostnames → SDK stays silent (no UI, no network calls)\n * Staging/preview hosts → SDK activates in staging mode\n * localhost / 127.x / *.local / IP → SDK activates in development mode\n *\n * Users can always override by passing `environment` explicitly.\n */\nfunction detectEnvironment(): 'development' | 'staging' | 'production' {\n if (typeof window === 'undefined') return 'production';\n const host = window.location.hostname;\n\n // Explicit localhost / loopback / local network\n if (\n host === 'localhost' ||\n host === '127.0.0.1' ||\n host === '0.0.0.0' ||\n host.endsWith('.local') ||\n /^192\\.168\\./.test(host) ||\n /^10\\./.test(host) ||\n /^172\\.(1[6-9]|2\\d|3[01])\\./.test(host)\n ) return 'development';\n\n // Common staging/preview patterns\n if (\n host.includes('staging') ||\n host.includes('stage') ||\n host.includes('preview') ||\n host.includes('preprod') ||\n host.includes('pre-prod') ||\n host.includes('qa.') ||\n host.includes('.qa') ||\n host.includes('test.') ||\n host.includes('.dev.') ||\n host.includes('vercel.app') || // Vercel preview deployments\n host.includes('netlify.app') || // Netlify preview deployments\n host.includes('pages.dev') || // Cloudflare Pages previews\n host.includes('ngrok.io') || // ngrok tunnels\n host.includes('ngrok-free.app') || // ngrok free tier\n host.includes('localhost.run') || // localhost.run tunnels\n host.includes('loca.lt') // localtunnel\n ) return 'staging';\n\n // Everything else is treated as production — SDK will be silent\n return 'production';\n}\n\nexport const BugStash = {\n init(options: BugStashConfig) {\n if (initialized) return;\n if (typeof window === 'undefined') return;\n\n const env = options.environment ?? detectEnvironment();\n if (env === 'production') return;\n\n if (options.endpoint) setEndpoint(options.endpoint);\n\n const host = window.location.hostname;\n const isLocal =\n host === 'localhost' ||\n host === '127.0.0.1' ||\n host === '0.0.0.0' ||\n host.endsWith('.local') ||\n /^192\\.168\\./.test(host) ||\n /^10\\./.test(host) ||\n /^172\\.(1[6-9]|2\\d|3[01])\\./.test(host);\n\n if (isLocal) {\n // Fast path for local dev — skip domain verification\n initModules(options);\n } else {\n // Verify domain before initializing anything\n verifyDomain(options.projectId)\n .then((allowed) => {\n if (allowed) {\n initModules(options);\n }\n // If not allowed, do nothing — SDK stays invisible\n })\n .catch(() => {\n // Fail closed — SDK stays invisible on errors\n });\n }\n },\n\n destroy() {\n if (!initialized) return;\n destroyPanel();\n destroyLivePins();\n disconnectRealtime();\n restoreConsole();\n restoreNetwork();\n restoreErrors();\n restoreBreadcrumbs();\n restorePerformance();\n document.querySelector('bugstash-root')?.remove();\n shadowRoot = null;\n initialized = false;\n },\n\n // Programmatic API\n getLogs,\n clearLogs,\n getNetworkCaptures,\n getFailedNetworkCaptures,\n clearNetworkCaptures,\n getErrors,\n clearErrors,\n getBreadcrumbs,\n clearBreadcrumbs,\n getPerformanceMetrics,\n addBreadcrumb,\n // Theme API\n getThemes,\n getThemeById,\n setTheme,\n getCurrentThemeId,\n // Layout API\n getLayouts,\n getLayoutById,\n setLayout,\n getCurrentLayoutId,\n // Auth API\n getCurrentUser,\n login,\n logout,\n // Live Pins API\n togglePinMode,\n isPinModeActive,\n // Real-time\n isConnected,\n // Annotation\n openAnnotationEditor,\n // PII Redaction\n redactString,\n redactObject,\n};\n\nexport default BugStash;\n","import type { Breadcrumb } from '@bugstash/shared';\n\nlet crumbs: Breadcrumb[] = [];\nlet maxCrumbs = 50;\nlet clickHandler: ((e: MouseEvent) => void) | null = null;\nlet inputHandler: ((e: Event) => void) | null = null;\nlet popstateHandler: (() => void) | null = null;\nlet hashHandler: (() => void) | null = null;\n\nfunction getSelector(el: Element): string {\n if (el.id) return `#${el.id}`;\n const tag = el.tagName.toLowerCase();\n const cls = el.className && typeof el.className === 'string'\n ? '.' + el.className.trim().split(/\\s+/).slice(0, 2).join('.')\n : '';\n const text = (el.textContent || '').trim().slice(0, 30);\n const label = text ? ` \"${text}\"` : '';\n return `${tag}${cls}${label}`;\n}\n\nexport function addBreadcrumb(crumb: Breadcrumb) {\n crumbs.push(crumb);\n if (crumbs.length > maxCrumbs) crumbs.shift();\n}\n\nexport function initBreadcrumbs(max?: number) {\n if (max) maxCrumbs = max;\n\n // Track clicks\n clickHandler = (e: MouseEvent) => {\n const target = e.target as Element;\n if (!target || !target.tagName) return;\n addBreadcrumb({\n type: 'click',\n category: 'ui',\n message: `Clicked ${getSelector(target)}`,\n timestamp: Date.now(),\n data: { x: e.clientX, y: e.clientY, selector: getSelector(target) },\n });\n };\n document.addEventListener('click', clickHandler, true);\n\n // Track input changes (debounced per element)\n const inputTimers = new WeakMap<Element, number>();\n inputHandler = (e: Event) => {\n const target = e.target as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n if (!target || !target.tagName) return;\n const tag = target.tagName.toLowerCase();\n if (tag !== 'input' && tag !== 'textarea' && tag !== 'select') return;\n\n // Debounce per element\n const existing = inputTimers.get(target);\n if (existing) clearTimeout(existing);\n inputTimers.set(\n target,\n window.setTimeout(() => {\n const isPassword = target instanceof HTMLInputElement && target.type === 'password';\n addBreadcrumb({\n type: 'input',\n category: 'ui',\n message: `Input ${getSelector(target)}`,\n timestamp: Date.now(),\n data: {\n selector: getSelector(target),\n value: isPassword ? '[redacted]' : undefined,\n },\n });\n }, 300),\n );\n };\n document.addEventListener('input', inputHandler, true);\n\n // Track navigation\n popstateHandler = () => {\n addBreadcrumb({\n type: 'navigation',\n category: 'navigation',\n message: `Navigated to ${window.location.pathname}`,\n timestamp: Date.now(),\n data: { url: window.location.href },\n });\n };\n window.addEventListener('popstate', popstateHandler);\n\n hashHandler = () => {\n addBreadcrumb({\n type: 'navigation',\n category: 'navigation',\n message: `Hash changed to ${window.location.hash}`,\n timestamp: Date.now(),\n data: { url: window.location.href },\n });\n };\n window.addEventListener('hashchange', hashHandler);\n\n // Initial breadcrumb\n addBreadcrumb({\n type: 'navigation',\n category: 'navigation',\n message: `Page loaded: ${window.location.pathname}`,\n timestamp: Date.now(),\n data: { url: window.location.href },\n });\n}\n\nexport function getBreadcrumbs(): Breadcrumb[] {\n return [...crumbs];\n}\n\nexport function clearBreadcrumbs() {\n crumbs = [];\n}\n\nexport function restoreBreadcrumbs() {\n if (clickHandler) document.removeEventListener('click', clickHandler, true);\n if (inputHandler) document.removeEventListener('input', inputHandler, true);\n if (popstateHandler) window.removeEventListener('popstate', popstateHandler);\n if (hashHandler) window.removeEventListener('hashchange', hashHandler);\n clickHandler = null;\n inputHandler = null;\n popstateHandler = null;\n hashHandler = null;\n}\n","/**\n * PII/sensitive data redaction for captured data.\n * Masks passwords, tokens, credit cards, SSNs, emails in captured logs and network data.\n */\n\nconst REDACT_PLACEHOLDER = '[REDACTED]';\n\n// Patterns for common sensitive data\nconst PATTERNS: [RegExp, string | ((match: string) => string)][] = [\n // Credit card numbers (Visa, MC, Amex, etc.)\n [/\\b(?:\\d[ -]*?){13,19}\\b/g, '[CC_REDACTED]'],\n // SSN\n [/\\b\\d{3}-\\d{2}-\\d{4}\\b/g, '[SSN_REDACTED]'],\n // Email addresses (in log strings, not for user context)\n // Intentionally NOT redacting emails since they're often needed for debugging\n // Bearer tokens\n [/Bearer\\s+[A-Za-z0-9\\-._~+/]+=*/g, 'Bearer [TOKEN_REDACTED]'],\n // JWT tokens (xxx.yyy.zzz pattern)\n [/eyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, '[JWT_REDACTED]'],\n // API keys (long hex/base64 strings that look like keys)\n [/(?:api[_-]?key|apikey|secret|token|password|passwd|authorization)['\":\\s=]+['\"]?([A-Za-z0-9\\-._~+/]{20,})['\"]?/gi, (match) => {\n const eqIdx = match.search(/[=:]/);\n return match.slice(0, eqIdx + 1) + ' ' + REDACT_PLACEHOLDER;\n }],\n // AWS access keys\n [/AKIA[0-9A-Z]{16}/g, '[AWS_KEY_REDACTED]'],\n // Generic password fields in JSON\n [/\"(?:password|passwd|secret|token|access_token|refresh_token|api_key|apiKey|private_key)\":\\s*\"[^\"]*\"/gi, (match) => {\n const colonIdx = match.indexOf(':');\n return match.slice(0, colonIdx + 1) + ' \"' + REDACT_PLACEHOLDER + '\"';\n }],\n];\n\n// Header names that should be redacted\nconst SENSITIVE_HEADERS = new Set([\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'x-auth-token',\n 'x-csrf-token',\n 'proxy-authorization',\n]);\n\n/** Redact sensitive data from a string. */\nexport function redactString(input: string): string {\n let result = input;\n for (const [pattern, replacement] of PATTERNS) {\n if (typeof replacement === 'function') {\n result = result.replace(pattern, replacement as any);\n } else {\n result = result.replace(pattern, replacement);\n }\n }\n return result;\n}\n\n/** Redact sensitive headers from a headers object. */\nexport function redactHeaders(headers: Record<string, string> | undefined): Record<string, string> | undefined {\n if (!headers) return headers;\n const redacted: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (SENSITIVE_HEADERS.has(key.toLowerCase())) {\n redacted[key] = REDACT_PLACEHOLDER;\n } else {\n redacted[key] = redactString(value);\n }\n }\n return redacted;\n}\n\n/** Redact an array of log argument strings. */\nexport function redactLogArgs(args: string[]): string[] {\n return args.map(redactString);\n}\n\n/** Redact sensitive data from serialized objects. */\nexport function redactObject(obj: any): any {\n if (typeof obj === 'string') return redactString(obj);\n if (Array.isArray(obj)) return obj.map(redactObject);\n if (obj && typeof obj === 'object') {\n const result: any = {};\n for (const [key, value] of Object.entries(obj)) {\n const lk = key.toLowerCase();\n if (lk.includes('password') || lk.includes('secret') || lk.includes('token') ||\n lk.includes('apikey') || lk.includes('api_key') || lk.includes('private')) {\n result[key] = REDACT_PLACEHOLDER;\n } else {\n result[key] = redactObject(value);\n }\n }\n return result;\n }\n return obj;\n}\n","import type { LogEntry } from '@bugstash/shared';\nimport { addBreadcrumb } from './breadcrumbs';\nimport { redactLogArgs } from './redact';\n\nconst originals = {\n log: console.log,\n warn: console.warn,\n error: console.error,\n debug: console.debug,\n info: console.info,\n};\n\nlet logs: LogEntry[] = [];\nlet maxLogs = 50;\n\nfunction serialize(args: any[]): string[] {\n return args.map((a) => {\n if (a instanceof Error) return `${a.name}: ${a.message}\\n${a.stack ?? ''}`;\n if (typeof a === 'object') {\n try {\n return JSON.stringify(a, null, 2);\n } catch {\n return String(a);\n }\n }\n return String(a);\n });\n}\n\nfunction capture(level: LogEntry['level'], args: any[]) {\n const entry: LogEntry = {\n level,\n args: redactLogArgs(serialize(args)),\n timestamp: Date.now(),\n };\n if (level === 'error') {\n entry.stack = new Error().stack?.split('\\n').slice(2).join('\\n');\n }\n logs.push(entry);\n if (logs.length > maxLogs) logs.shift();\n\n addBreadcrumb({\n type: 'console',\n category: `console.${level}`,\n message: entry.args.join(' ').slice(0, 200),\n timestamp: entry.timestamp,\n });\n}\n\nexport function initLogger(max?: number) {\n if (max) maxLogs = max;\n\n for (const level of Object.keys(originals) as LogEntry['level'][]) {\n console[level] = function (...args: any[]) {\n capture(level, args);\n originals[level].apply(console, args);\n };\n }\n}\n\nexport function getLogs(): LogEntry[] {\n return [...logs];\n}\n\nexport function clearLogs() {\n logs = [];\n}\n\nexport function restoreConsole() {\n for (const level of Object.keys(originals) as LogEntry['level'][]) {\n console[level] = originals[level];\n }\n}\n","import type { NetworkEntry } from '@bugstash/shared';\nimport { addBreadcrumb } from './breadcrumbs';\nimport { redactString } from './redact';\n\nlet captures: NetworkEntry[] = [];\nlet maxCaptures = 50;\nlet originalFetch: typeof window.fetch;\nlet originalXHROpen: typeof XMLHttpRequest.prototype.open;\nlet originalXHRSend: typeof XMLHttpRequest.prototype.send;\n\nfunction record(entry: NetworkEntry) {\n captures.push(entry);\n if (captures.length > maxCaptures) captures.shift();\n\n addBreadcrumb({\n type: 'network',\n category: entry.failed ? 'network.error' : 'network.ok',\n message: `${entry.method} ${entry.url} → ${entry.status} (${entry.duration}ms)`,\n timestamp: entry.timestamp,\n data: { status: entry.status, duration: entry.duration },\n });\n}\n\nfunction shortenUrl(url: string): string {\n try {\n const u = new URL(url, window.location.origin);\n // Redact sensitive query params (tokens, keys, etc.)\n const params = new URLSearchParams(u.search);\n for (const key of params.keys()) {\n const lk = key.toLowerCase();\n if (lk.includes('token') || lk.includes('key') || lk.includes('secret') || lk.includes('password') || lk.includes('auth')) {\n params.set(key, '[REDACTED]');\n }\n }\n const qs = params.toString();\n return u.pathname + (qs ? '?' + qs : '');\n } catch {\n return redactString(url);\n }\n}\n\nfunction patchFetch() {\n originalFetch = window.fetch;\n\n window.fetch = async function (input: any, init?: any) {\n const method = init?.method?.toUpperCase() ?? 'GET';\n const rawUrl = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;\n const url = shortenUrl(rawUrl);\n const start = Date.now();\n\n try {\n const response = await originalFetch.call(window, input, init);\n record({\n method,\n url,\n status: response.status,\n statusText: response.statusText,\n duration: Date.now() - start,\n responseType: response.headers.get('content-type') ?? undefined,\n timestamp: start,\n failed: response.status >= 400,\n });\n return response;\n } catch (err) {\n record({\n method,\n url,\n status: 0,\n statusText: 'Network Error',\n duration: Date.now() - start,\n timestamp: start,\n failed: true,\n });\n throw err;\n }\n };\n}\n\nfunction patchXHR() {\n originalXHROpen = XMLHttpRequest.prototype.open;\n originalXHRSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (method: string, url: string | URL, ...rest: any[]) {\n (this as any).__bs_method = method.toUpperCase();\n (this as any).__bs_url = shortenUrl(typeof url === 'string' ? url : url.href);\n return originalXHROpen.apply(this, [method, url, ...rest] as any);\n };\n\n XMLHttpRequest.prototype.send = function (body?: any) {\n const start = Date.now();\n\n this.addEventListener('loadend', function () {\n record({\n method: (this as any).__bs_method ?? 'GET',\n url: (this as any).__bs_url ?? '',\n status: this.status,\n statusText: this.statusText,\n duration: Date.now() - start,\n responseType: this.getResponseHeader('content-type') ?? undefined,\n timestamp: start,\n failed: this.status >= 400 || this.status === 0,\n });\n });\n\n return originalXHRSend.call(this, body);\n };\n}\n\nexport function initNetwork(max?: number) {\n if (max) maxCaptures = max;\n patchFetch();\n patchXHR();\n}\n\nexport function getNetworkCaptures(): NetworkEntry[] {\n return [...captures];\n}\n\nexport function getFailedNetworkCaptures(): NetworkEntry[] {\n return captures.filter((c) => c.failed);\n}\n\nexport function clearNetworkCaptures() {\n captures = [];\n}\n\nexport function restoreNetwork() {\n if (originalFetch) window.fetch = originalFetch;\n if (originalXHROpen) XMLHttpRequest.prototype.open = originalXHROpen;\n if (originalXHRSend) XMLHttpRequest.prototype.send = originalXHRSend;\n}\n","import type { ErrorEntry } from '@bugstash/shared';\nimport { addBreadcrumb } from './breadcrumbs';\n\nlet errors: ErrorEntry[] = [];\nlet onErrorHandler: ((e: ErrorEvent) => void) | null = null;\nlet onRejectionHandler: ((e: PromiseRejectionEvent) => void) | null = null;\n\nexport function initErrors() {\n onErrorHandler = (event: ErrorEvent) => {\n const entry: ErrorEntry = {\n message: event.message || 'Unknown error',\n source: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n stack: event.error?.stack,\n type: 'error',\n timestamp: Date.now(),\n };\n errors.push(entry);\n addBreadcrumb({\n type: 'error',\n category: 'exception',\n message: entry.message,\n timestamp: entry.timestamp,\n data: { source: entry.source, lineno: entry.lineno },\n });\n };\n\n onRejectionHandler = (event: PromiseRejectionEvent) => {\n const reason = event.reason;\n const message =\n reason instanceof Error ? reason.message : typeof reason === 'string' ? reason : 'Unhandled promise rejection';\n const entry: ErrorEntry = {\n message,\n stack: reason instanceof Error ? reason.stack : undefined,\n type: 'unhandledrejection',\n timestamp: Date.now(),\n };\n errors.push(entry);\n addBreadcrumb({\n type: 'error',\n category: 'promise',\n message,\n timestamp: entry.timestamp,\n });\n };\n\n window.addEventListener('error', onErrorHandler);\n window.addEventListener('unhandledrejection', onRejectionHandler);\n}\n\nexport function getErrors(): ErrorEntry[] {\n return [...errors];\n}\n\nexport function clearErrors() {\n errors = [];\n}\n\nexport function restoreErrors() {\n if (onErrorHandler) window.removeEventListener('error', onErrorHandler);\n if (onRejectionHandler) window.removeEventListener('unhandledrejection', onRejectionHandler);\n onErrorHandler = null;\n onRejectionHandler = null;\n}\n","import type { PerformanceMetrics } from '@bugstash/shared';\n\nlet metrics: PerformanceMetrics | null = null;\nlet lcpObserver: PerformanceObserver | null = null;\nlet clsObserver: PerformanceObserver | null = null;\nlet fidObserver: PerformanceObserver | null = null;\n\nexport function initPerformance() {\n metrics = { timestamp: Date.now() };\n\n // Navigation timing\n if (performance.getEntriesByType) {\n const onLoad = () => {\n const [nav] = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[];\n if (nav && metrics) {\n metrics.pageLoadTime = Math.round(nav.loadEventEnd - nav.startTime);\n metrics.domContentLoaded = Math.round(nav.domContentLoadedEventEnd - nav.startTime);\n }\n\n // Paint timing\n const paints = performance.getEntriesByType('paint');\n for (const p of paints) {\n if (p.name === 'first-paint' && metrics) metrics.firstPaint = Math.round(p.startTime);\n if (p.name === 'first-contentful-paint' && metrics) metrics.firstContentfulPaint = Math.round(p.startTime);\n }\n\n // Resource count\n if (metrics) {\n metrics.resourceCount = performance.getEntriesByType('resource').length;\n }\n\n // Memory (Chrome only)\n const mem = (performance as any).memory;\n if (mem && metrics) {\n metrics.memoryUsage = {\n usedJSHeapSize: mem.usedJSHeapSize,\n totalJSHeapSize: mem.totalJSHeapSize,\n };\n }\n };\n\n if (document.readyState === 'complete') {\n setTimeout(onLoad, 0);\n } else {\n window.addEventListener('load', () => setTimeout(onLoad, 100));\n }\n }\n\n // LCP\n if (typeof PerformanceObserver !== 'undefined') {\n try {\n lcpObserver = new PerformanceObserver((list) => {\n const entries = list.getEntries();\n const last = entries[entries.length - 1];\n if (last && metrics) metrics.largestContentfulPaint = Math.round(last.startTime);\n });\n lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });\n } catch {}\n\n // CLS\n try {\n let clsValue = 0;\n clsObserver = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (!(entry as any).hadRecentInput) {\n clsValue += (entry as any).value;\n }\n }\n if (metrics) metrics.cumulativeLayoutShift = Math.round(clsValue * 1000) / 1000;\n });\n clsObserver.observe({ type: 'layout-shift', buffered: true });\n } catch {}\n\n // FID\n try {\n fidObserver = new PerformanceObserver((list) => {\n const [entry] = list.getEntries();\n if (entry && metrics) metrics.firstInputDelay = Math.round((entry as any).processingStart - entry.startTime);\n });\n fidObserver.observe({ type: 'first-input', buffered: true });\n } catch {}\n }\n}\n\nexport function getPerformanceMetrics(): PerformanceMetrics | null {\n if (metrics) metrics.timestamp = Date.now();\n return metrics ? { ...metrics } : null;\n}\n\nexport function restorePerformance() {\n lcpObserver?.disconnect();\n clsObserver?.disconnect();\n fidObserver?.disconnect();\n lcpObserver = null;\n clsObserver = null;\n fidObserver = null;\n metrics = null;\n}\n","import type { Options } from './types'\n\nexport function resolveUrl(url: string, baseUrl: string | null): string {\n // url is absolute already\n if (url.match(/^[a-z]+:\\/\\//i)) {\n return url\n }\n\n // url is absolute already, without protocol\n if (url.match(/^\\/\\//)) {\n return window.location.protocol + url\n }\n\n // dataURI, mailto:, tel:, etc.\n if (url.match(/^[a-z]+:/i)) {\n return url\n }\n\n const doc = document.implementation.createHTMLDocument()\n const base = doc.createElement('base')\n const a = doc.createElement('a')\n\n doc.head.appendChild(base)\n doc.body.appendChild(a)\n\n if (baseUrl) {\n base.href = baseUrl\n }\n\n a.href = url\n\n return a.href\n}\n\nexport const uuid = (() => {\n // generate uuid for className of pseudo elements.\n // We should not use GUIDs, otherwise pseudo elements sometimes cannot be captured.\n let counter = 0\n\n // ref: http://stackoverflow.com/a/6248722/2519373\n const random = () =>\n // eslint-disable-next-line no-bitwise\n `0000${((Math.random() * 36 ** 4) << 0).toString(36)}`.slice(-4)\n\n return () => {\n counter += 1\n return `u${random()}${counter}`\n }\n})()\n\nexport function delay<T>(ms: number) {\n return (args: T) =>\n new Promise<T>((resolve) => {\n setTimeout(() => resolve(args), ms)\n })\n}\n\nexport function toArray<T>(arrayLike: any): T[] {\n const arr: T[] = []\n\n for (let i = 0, l = arrayLike.length; i < l; i++) {\n arr.push(arrayLike[i])\n }\n\n return arr\n}\n\nlet styleProps: string[] | null = null\nexport function getStyleProperties(options: Options = {}): string[] {\n if (styleProps) {\n return styleProps\n }\n\n if (options.includeStyleProperties) {\n styleProps = options.includeStyleProperties\n return styleProps\n }\n\n styleProps = toArray(window.getComputedStyle(document.documentElement))\n\n return styleProps\n}\n\nfunction px(node: HTMLElement, styleProperty: string) {\n const win = node.ownerDocument.defaultView || window\n const val = win.getComputedStyle(node).getPropertyValue(styleProperty)\n return val ? parseFloat(val.replace('px', '')) : 0\n}\n\nfunction getNodeWidth(node: HTMLElement) {\n const leftBorder = px(node, 'border-left-width')\n const rightBorder = px(node, 'border-right-width')\n return node.clientWidth + leftBorder + rightBorder\n}\n\nfunction getNodeHeight(node: HTMLElement) {\n const topBorder = px(node, 'border-top-width')\n const bottomBorder = px(node, 'border-bottom-width')\n return node.clientHeight + topBorder + bottomBorder\n}\n\nexport function getImageSize(targetNode: HTMLElement, options: Options = {}) {\n const width = options.width || getNodeWidth(targetNode)\n const height = options.height || getNodeHeight(targetNode)\n\n return { width, height }\n}\n\nexport function getPixelRatio() {\n let ratio\n\n let FINAL_PROCESS\n try {\n FINAL_PROCESS = process\n } catch (e) {\n // pass\n }\n\n const val =\n FINAL_PROCESS && FINAL_PROCESS.env\n ? FINAL_PROCESS.env.devicePixelRatio\n : null\n if (val) {\n ratio = parseInt(val, 10)\n if (Number.isNaN(ratio)) {\n ratio = 1\n }\n }\n return ratio || window.devicePixelRatio || 1\n}\n\n// @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#maximum_canvas_size\nconst canvasDimensionLimit = 16384\n\nexport function checkCanvasDimensions(canvas: HTMLCanvasElement) {\n if (\n canvas.width > canvasDimensionLimit ||\n canvas.height > canvasDimensionLimit\n ) {\n if (\n canvas.width > canvasDimensionLimit &&\n canvas.height > canvasDimensionLimit\n ) {\n if (canvas.width > canvas.height) {\n canvas.height *= canvasDimensionLimit / canvas.width\n canvas.width = canvasDimensionLimit\n } else {\n canvas.width *= canvasDimensionLimit / canvas.height\n canvas.height = canvasDimensionLimit\n }\n } else if (canvas.width > canvasDimensionLimit) {\n canvas.height *= canvasDimensionLimit / canvas.width\n canvas.width = canvasDimensionLimit\n } else {\n canvas.width *= canvasDimensionLimit / canvas.height\n canvas.height = canvasDimensionLimit\n }\n }\n}\n\nexport function canvasToBlob(\n canvas: HTMLCanvasElement,\n options: Options = {},\n): Promise<Blob | null> {\n if (canvas.toBlob) {\n return new Promise((resolve) => {\n canvas.toBlob(\n resolve,\n options.type ? options.type : 'image/png',\n options.quality ? options.quality : 1,\n )\n })\n }\n\n return new Promise((resolve) => {\n const binaryString = window.atob(\n canvas\n .toDataURL(\n options.type ? options.type : undefined,\n options.quality ? options.quality : undefined,\n )\n .split(',')[1],\n )\n const len = binaryString.length\n const binaryArray = new Uint8Array(len)\n\n for (let i = 0; i < len; i += 1) {\n binaryArray[i] = binaryString.charCodeAt(i)\n }\n\n resolve(\n new Blob([binaryArray], {\n type: options.type ? options.type : 'image/png',\n }),\n )\n })\n}\n\nexport function createImage(url: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image()\n img.onload = () => {\n img.decode().then(() => {\n requestAnimationFrame(() => resolve(img))\n })\n }\n img.onerror = reject\n img.crossOrigin = 'anonymous'\n img.decoding = 'async'\n img.src = url\n })\n}\n\nexport async function svgToDataURL(svg: SVGElement): Promise<string> {\n return Promise.resolve()\n .then(() => new XMLSerializer().serializeToString(svg))\n .then(encodeURIComponent)\n .then((html) => `data:image/svg+xml;charset=utf-8,${html}`)\n}\n\nexport async function nodeToDataURL(\n node: HTMLElement,\n width: number,\n height: number,\n): Promise<string> {\n const xmlns = 'http://www.w3.org/2000/svg'\n const svg = document.createElementNS(xmlns, 'svg')\n const foreignObject = document.createElementNS(xmlns, 'foreignObject')\n\n svg.setAttribute('width', `${width}`)\n svg.setAttribute('height', `${height}`)\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`)\n\n foreignObject.setAttribute('width', '100%')\n foreignObject.setAttribute('height', '100%')\n foreignObject.setAttribute('x', '0')\n foreignObject.setAttribute('y', '0')\n foreignObject.setAttribute('externalResourcesRequired', 'true')\n\n svg.appendChild(foreignObject)\n foreignObject.appendChild(node)\n return svgToDataURL(svg)\n}\n\nexport const isInstanceOfElement = <\n T extends typeof Element | typeof HTMLElement | typeof SVGImageElement,\n>(\n node: Element | HTMLElement | SVGImageElement,\n instance: T,\n): node is T['prototype'] => {\n if (node instanceof instance) return true\n\n const nodePrototype = Object.getPrototypeOf(node)\n\n if (nodePrototype === null) return false\n\n return (\n nodePrototype.constructor.name === instance.name ||\n isInstanceOfElement(nodePrototype, instance)\n )\n}\n","import type { Options } from './types'\nimport { uuid, getStyleProperties } from './util'\n\ntype Pseudo = ':before' | ':after'\n\nfunction formatCSSText(style: CSSStyleDeclaration) {\n const content = style.getPropertyValue('content')\n return `${style.cssText} content: '${content.replace(/'|\"/g, '')}';`\n}\n\nfunction formatCSSProperties(style: CSSStyleDeclaration, options: Options) {\n return getStyleProperties(options)\n .map((name) => {\n const value = style.getPropertyValue(name)\n const priority = style.getPropertyPriority(name)\n\n return `${name}: ${value}${priority ? ' !important' : ''};`\n })\n .join(' ')\n}\n\nfunction getPseudoElementStyle(\n className: string,\n pseudo: Pseudo,\n style: CSSStyleDeclaration,\n options: Options,\n): Text {\n const selector = `.${className}:${pseudo}`\n const cssText = style.cssText\n ? formatCSSText(style)\n : formatCSSProperties(style, options)\n\n return document.createTextNode(`${selector}{${cssText}}`)\n}\n\nfunction clonePseudoElement<T extends HTMLElement>(\n nativeNode: T,\n clonedNode: T,\n pseudo: Pseudo,\n options: Options,\n) {\n const style = window.getComputedStyle(nativeNode, pseudo)\n const content = style.getPropertyValue('content')\n if (content === '' || content === 'none') {\n return\n }\n\n const className = uuid()\n try {\n clonedNode.className = `${clonedNode.className} ${className}`\n } catch (err) {\n return\n }\n\n const styleElement = document.createElement('style')\n styleElement.appendChild(\n getPseudoElementStyle(className, pseudo, style, options),\n )\n clonedNode.appendChild(styleElement)\n}\n\nexport function clonePseudoElements<T extends HTMLElement>(\n nativeNode: T,\n clonedNode: T,\n options: Options,\n) {\n clonePseudoElement(nativeNode, clonedNode, ':before', options)\n clonePseudoElement(nativeNode, clonedNode, ':after', options)\n}\n","const WOFF = 'application/font-woff'\nconst JPEG = 'image/jpeg'\nconst mimes: { [key: string]: string } = {\n woff: WOFF,\n woff2: WOFF,\n ttf: 'application/font-truetype',\n eot: 'application/vnd.ms-fontobject',\n png: 'image/png',\n jpg: JPEG,\n jpeg: JPEG,\n gif: 'image/gif',\n tiff: 'image/tiff',\n svg: 'image/svg+xml',\n webp: 'image/webp',\n}\n\nfunction getExtension(url: string): string {\n const match = /\\.([^./]*?)$/g.exec(url)\n return match ? match[1] : ''\n}\n\nexport function getMimeType(url: string): string {\n const extension = getExtension(url).toLowerCase()\n return mimes[extension] || ''\n}\n","import { Options } from './types'\n\nfunction getContentFromDataUrl(dataURL: string) {\n return dataURL.split(/,/)[1]\n}\n\nexport function isDataUrl(url: string) {\n return url.search(/^(data:)/) !== -1\n}\n\nexport function makeDataUrl(content: string, mimeType: string) {\n return `data:${mimeType};base64,${content}`\n}\n\nexport async function fetchAsDataURL<T>(\n url: string,\n init: RequestInit | undefined,\n process: (data: { result: string; res: Response }) => T,\n): Promise<T> {\n const res = await fetch(url, init)\n if (res.status === 404) {\n throw new Error(`Resource \"${res.url}\" not found`)\n }\n const blob = await res.blob()\n return new Promise<T>((resolve, reject) => {\n const reader = new FileReader()\n reader.onerror = reject\n reader.onloadend = () => {\n try {\n resolve(process({ res, result: reader.result as string }))\n } catch (error) {\n reject(error)\n }\n }\n\n reader.readAsDataURL(blob)\n })\n}\n\nconst cache: { [url: string]: string } = {}\n\nfunction getCacheKey(\n url: string,\n contentType: string | undefined,\n includeQueryParams: boolean | undefined,\n) {\n let key = url.replace(/\\?.*/, '')\n\n if (includeQueryParams) {\n key = url\n }\n\n // font resource\n if (/ttf|otf|eot|woff2?/i.test(key)) {\n key = key.replace(/.*\\//, '')\n }\n\n return contentType ? `[${contentType}]${key}` : key\n}\n\nexport async function resourceToDataURL(\n resourceUrl: string,\n contentType: string | undefined,\n options: Options,\n) {\n const cacheKey = getCacheKey(\n resourceUrl,\n contentType,\n options.includeQueryParams,\n )\n\n if (cache[cacheKey] != null) {\n return cache[cacheKey]\n }\n\n // ref: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache\n if (options.cacheBust) {\n // eslint-disable-next-line no-param-reassign\n resourceUrl += (/\\?/.test(resourceUrl) ? '&' : '?') + new Date().getTime()\n }\n\n let dataURL: string\n try {\n const content = await fetchAsDataURL(\n resourceUrl,\n options.fetchRequestInit,\n ({ res, result }) => {\n if (!contentType) {\n // eslint-disable-next-line no-param-reassign\n contentType = res.headers.get('Content-Type') || ''\n }\n return getContentFromDataUrl(result)\n },\n )\n dataURL = makeDataUrl(content, contentType!)\n } catch (error) {\n dataURL = options.imagePlaceholder || ''\n\n let msg = `Failed to fetch resource: ${resourceUrl}`\n if (error) {\n msg = typeof error === 'string' ? error : error.message\n }\n\n if (msg) {\n console.warn(msg)\n }\n }\n\n cache[cacheKey] = dataURL\n return dataURL\n}\n","import type { Options } from './types'\nimport { clonePseudoElements } from './clone-pseudos'\nimport {\n createImage,\n toArray,\n isInstanceOfElement,\n getStyleProperties,\n} from './util'\nimport { getMimeType } from './mimes'\nimport { resourceToDataURL } from './dataurl'\n\nasync function cloneCanvasElement(canvas: HTMLCanvasElement) {\n const dataURL = canvas.toDataURL()\n if (dataURL === 'data:,') {\n return canvas.cloneNode(false) as HTMLCanvasElement\n }\n return createImage(dataURL)\n}\n\nasync function cloneVideoElement(video: HTMLVideoElement, options: Options) {\n if (video.currentSrc) {\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n canvas.width = video.clientWidth\n canvas.height = video.clientHeight\n ctx?.drawImage(video, 0, 0, canvas.width, canvas.height)\n const dataURL = canvas.toDataURL()\n return createImage(dataURL)\n }\n\n const poster = video.poster\n const contentType = getMimeType(poster)\n const dataURL = await resourceToDataURL(poster, contentType, options)\n return createImage(dataURL)\n}\n\nasync function cloneIFrameElement(iframe: HTMLIFrameElement, options: Options) {\n try {\n if (iframe?.contentDocument?.body) {\n return (await cloneNode(\n iframe.contentDocument.body,\n options,\n true,\n )) as HTMLBodyElement\n }\n } catch {\n // Failed to clone iframe\n }\n\n return iframe.cloneNode(false) as HTMLIFrameElement\n}\n\nasync function cloneSingleNode<T extends HTMLElement>(\n node: T,\n options: Options,\n): Promise<HTMLElement> {\n if (isInstanceOfElement(node, HTMLCanvasElement)) {\n return cloneCanvasElement(node)\n }\n\n if (isInstanceOfElement(node, HTMLVideoElement)) {\n return cloneVideoElement(node, options)\n }\n\n if (isInstanceOfElement(node, HTMLIFrameElement)) {\n return cloneIFrameElement(node, options)\n }\n\n return node.cloneNode(isSVGElement(node)) as T\n}\n\nconst isSlotElement = (node: HTMLElement): node is HTMLSlotElement =>\n node.tagName != null && node.tagName.toUpperCase() === 'SLOT'\n\nconst isSVGElement = (node: HTMLElement): node is HTMLSlotElement =>\n node.tagName != null && node.tagName.toUpperCase() === 'SVG'\n\nasync function cloneChildren<T extends HTMLElement>(\n nativeNode: T,\n clonedNode: T,\n options: Options,\n): Promise<T> {\n if (isSVGElement(clonedNode)) {\n return clonedNode\n }\n\n let children: T[] = []\n\n if (isSlotElement(nativeNode) && nativeNode.assignedNodes) {\n children = toArray<T>(nativeNode.assignedNodes())\n } else if (\n isInstanceOfElement(nativeNode, HTMLIFrameElement) &&\n nativeNode.contentDocument?.body\n ) {\n children = toArray<T>(nativeNode.contentDocument.body.childNodes)\n } else {\n children = toArray<T>((nativeNode.shadowRoot ?? nativeNode).childNodes)\n }\n\n if (\n children.length === 0 ||\n isInstanceOfElement(nativeNode, HTMLVideoElement)\n ) {\n return clonedNode\n }\n\n await children.reduce(\n (deferred, child) =>\n deferred\n .then(() => cloneNode(child, options))\n .then((clonedChild: HTMLElement | null) => {\n if (clonedChild) {\n clonedNode.appendChild(clonedChild)\n }\n }),\n Promise.resolve(),\n )\n\n return clonedNode\n}\n\nfunction cloneCSSStyle<T extends HTMLElement>(\n nativeNode: T,\n clonedNode: T,\n options: Options,\n) {\n const targetStyle = clonedNode.style\n if (!targetStyle) {\n return\n }\n\n const sourceStyle = window.getComputedStyle(nativeNode)\n if (sourceStyle.cssText) {\n targetStyle.cssText = sourceStyle.cssText\n targetStyle.transformOrigin = sourceStyle.transformOrigin\n } else {\n getStyleProperties(options).forEach((name) => {\n let value = sourceStyle.getPropertyValue(name)\n if (name === 'font-size' && value.endsWith('px')) {\n const reducedFont =\n Math.floor(parseFloat(value.substring(0, value.length - 2))) - 0.1\n value = `${reducedFont}px`\n }\n\n if (\n isInstanceOfElement(nativeNode, HTMLIFrameElement) &&\n name === 'display' &&\n value === 'inline'\n ) {\n value = 'block'\n }\n\n if (name === 'd' && clonedNode.getAttribute('d')) {\n value = `path(${clonedNode.getAttribute('d')})`\n }\n\n targetStyle.setProperty(\n name,\n value,\n sourceStyle.getPropertyPriority(name),\n )\n })\n }\n}\n\nfunction cloneInputValue<T extends HTMLElement>(nativeNode: T, clonedNode: T) {\n if (isInstanceOfElement(nativeNode, HTMLTextAreaElement)) {\n clonedNode.innerHTML = nativeNode.value\n }\n\n if (isInstanceOfElement(nativeNode, HTMLInputElement)) {\n clonedNode.setAttribute('value', nativeNode.value)\n }\n}\n\nfunction cloneSelectValue<T extends HTMLElement>(nativeNode: T, clonedNode: T) {\n if (isInstanceOfElement(nativeNode, HTMLSelectElement)) {\n const clonedSelect = clonedNode as any as HTMLSelectElement\n const selectedOption = Array.from(clonedSelect.children).find(\n (child) => nativeNode.value === child.getAttribute('value'),\n )\n\n if (selectedOption) {\n selectedOption.setAttribute('selected', '')\n }\n }\n}\n\nfunction decorate<T extends HTMLElement>(\n nativeNode: T,\n clonedNode: T,\n options: Options,\n): T {\n if (isInstanceOfElement(clonedNode, Element)) {\n cloneCSSStyle(nativeNode, clonedNode, options)\n clonePseudoElements(nativeNode, clonedNode, options)\n cloneInputValue(nativeNode, clonedNode)\n cloneSelectValue(nativeNode, clonedNode)\n }\n\n return clonedNode\n}\n\nasync function ensureSVGSymbols<T extends HTMLElement>(\n clone: T,\n options: Options,\n) {\n const uses = clone.querySelectorAll ? clone.querySelectorAll('use') : []\n if (uses.length === 0) {\n return clone\n }\n\n const processedDefs: { [key: string]: HTMLElement } = {}\n for (let i = 0; i < uses.length; i++) {\n const use = uses[i]\n const id = use.getAttribute('xlink:href')\n if (id) {\n const exist = clone.querySelector(id)\n const definition = document.querySelector(id) as HTMLElement\n if (!exist && definition && !processedDefs[id]) {\n // eslint-disable-next-line no-await-in-loop\n processedDefs[id] = (await cloneNode(definition, options, true))!\n }\n }\n }\n\n const nodes = Object.values(processedDefs)\n if (nodes.length) {\n const ns = 'http://www.w3.org/1999/xhtml'\n const svg = document.createElementNS(ns, 'svg')\n svg.setAttribute('xmlns', ns)\n svg.style.position = 'absolute'\n svg.style.width = '0'\n svg.style.height = '0'\n svg.style.overflow = 'hidden'\n svg.style.display = 'none'\n\n const defs = document.createElementNS(ns, 'defs')\n svg.appendChild(defs)\n\n for (let i = 0; i < nodes.length; i++) {\n defs.appendChild(nodes[i])\n }\n\n clone.appendChild(svg)\n }\n\n return clone\n}\n\nexport async function cloneNode<T extends HTMLElement>(\n node: T,\n options: Options,\n isRoot?: boolean,\n): Promise<T | null> {\n if (!isRoot && options.filter && !options.filter(node)) {\n return null\n }\n\n return Promise.resolve(node)\n .then((clonedNode) => cloneSingleNode(clonedNode, options) as Promise<T>)\n .then((clonedNode) => cloneChildren(node, clonedNode, options))\n .then((clonedNode) => decorate(node, clonedNode, options))\n .then((clonedNode) => ensureSVGSymbols(clonedNode, options))\n}\n","import { Options } from './types'\nimport { resolveUrl } from './util'\nimport { getMimeType } from './mimes'\nimport { isDataUrl, makeDataUrl, resourceToDataURL } from './dataurl'\n\nconst URL_REGEX = /url\\((['\"]?)([^'\"]+?)\\1\\)/g\nconst URL_WITH_FORMAT_REGEX = /url\\([^)]+\\)\\s*format\\(([\"']?)([^\"']+)\\1\\)/g\nconst FONT_SRC_REGEX = /src:\\s*(?:url\\([^)]+\\)\\s*format\\([^)]+\\)[,;]\\s*)+/g\n\nfunction toRegex(url: string): RegExp {\n // eslint-disable-next-line no-useless-escape\n const escaped = url.replace(/([.*+?^${}()|\\[\\]\\/\\\\])/g, '\\\\$1')\n return new RegExp(`(url\\\\(['\"]?)(${escaped})(['\"]?\\\\))`, 'g')\n}\n\nexport function parseURLs(cssText: string): string[] {\n const urls: string[] = []\n\n cssText.replace(URL_REGEX, (raw, quotation, url) => {\n urls.push(url)\n return raw\n })\n\n return urls.filter((url) => !isDataUrl(url))\n}\n\nexport async function embed(\n cssText: string,\n resourceURL: string,\n baseURL: string | null,\n options: Options,\n getContentFromUrl?: (url: string) => Promise<string>,\n): Promise<string> {\n try {\n const resolvedURL = baseURL ? resolveUrl(resourceURL, baseURL) : resourceURL\n const contentType = getMimeType(resourceURL)\n let dataURL: string\n if (getContentFromUrl) {\n const content = await getContentFromUrl(resolvedURL)\n dataURL = makeDataUrl(content, contentType)\n } else {\n dataURL = await resourceToDataURL(resolvedURL, contentType, options)\n }\n return cssText.replace(toRegex(resourceURL), `$1${dataURL}$3`)\n } catch (error) {\n // pass\n }\n return cssText\n}\n\nfunction filterPreferredFontFormat(\n str: string,\n { preferredFontFormat }: Options,\n): string {\n return !preferredFontFormat\n ? str\n : str.replace(FONT_SRC_REGEX, (match: string) => {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const [src, , format] = URL_WITH_FORMAT_REGEX.exec(match) || []\n if (!format) {\n return ''\n }\n\n if (format === preferredFontFormat) {\n return `src: ${src};`\n }\n }\n })\n}\n\nexport function shouldEmbed(url: string): boolean {\n return url.search(URL_REGEX) !== -1\n}\n\nexport async function embedResources(\n cssText: string,\n baseUrl: string | null,\n options: Options,\n): Promise<string> {\n if (!shouldEmbed(cssText)) {\n return cssText\n }\n\n const filteredCSSText = filterPreferredFontFormat(cssText, options)\n const urls = parseURLs(filteredCSSText)\n return urls.reduce(\n (deferred, url) =>\n deferred.then((css) => embed(css, url, baseUrl, options)),\n Promise.resolve(filteredCSSText),\n )\n}\n","import { Options } from './types'\nimport { embedResources } from './embed-resources'\nimport { toArray, isInstanceOfElement } from './util'\nimport { isDataUrl, resourceToDataURL } from './dataurl'\nimport { getMimeType } from './mimes'\n\nasync function embedProp(\n propName: string,\n node: HTMLElement,\n options: Options,\n) {\n const propValue = node.style?.getPropertyValue(propName)\n if (propValue) {\n const cssString = await embedResources(propValue, null, options)\n node.style.setProperty(\n propName,\n cssString,\n node.style.getPropertyPriority(propName),\n )\n return true\n }\n return false\n}\n\nasync function embedBackground<T extends HTMLElement>(\n clonedNode: T,\n options: Options,\n) {\n ;(await embedProp('background', clonedNode, options)) ||\n (await embedProp('background-image', clonedNode, options))\n ;(await embedProp('mask', clonedNode, options)) ||\n (await embedProp('-webkit-mask', clonedNode, options)) ||\n (await embedProp('mask-image', clonedNode, options)) ||\n (await embedProp('-webkit-mask-image', clonedNode, options))\n}\n\nasync function embedImageNode<T extends HTMLElement | SVGImageElement>(\n clonedNode: T,\n options: Options,\n) {\n const isImageElement = isInstanceOfElement(clonedNode, HTMLImageElement)\n\n if (\n !(isImageElement && !isDataUrl(clonedNode.src)) &&\n !(\n isInstanceOfElement(clonedNode, SVGImageElement) &&\n !isDataUrl(clonedNode.href.baseVal)\n )\n ) {\n return\n }\n\n const url = isImageElement ? clonedNode.src : clonedNode.href.baseVal\n\n const dataURL = await resourceToDataURL(url, getMimeType(url), options)\n await new Promise((resolve, reject) => {\n clonedNode.onload = resolve\n clonedNode.onerror = options.onImageErrorHandler\n ? (...attributes) => {\n try {\n resolve(options.onImageErrorHandler!(...attributes))\n } catch (error) {\n reject(error)\n }\n }\n : reject\n\n const image = clonedNode as HTMLImageElement\n if (image.decode) {\n image.decode = resolve as any\n }\n\n if (image.loading === 'lazy') {\n image.loading = 'eager'\n }\n\n if (isImageElement) {\n clonedNode.srcset = ''\n clonedNode.src = dataURL\n } else {\n clonedNode.href.baseVal = dataURL\n }\n })\n}\n\nasync function embedChildren<T extends HTMLElement>(\n clonedNode: T,\n options: Options,\n) {\n const children = toArray<HTMLElement>(clonedNode.childNodes)\n const deferreds = children.map((child) => embedImages(child, options))\n await Promise.all(deferreds).then(() => clonedNode)\n}\n\nexport async function embedImages<T extends HTMLElement>(\n clonedNode: T,\n options: Options,\n) {\n if (isInstanceOfElement(clonedNode, Element)) {\n await embedBackground(clonedNode, options)\n await embedImageNode(clonedNode, options)\n await embedChildren(clonedNode, options)\n }\n}\n","import type { Options } from './types'\n\nexport function applyStyle<T extends HTMLElement>(\n node: T,\n options: Options,\n): T {\n const { style } = node\n\n if (options.backgroundColor) {\n style.backgroundColor = options.backgroundColor\n }\n\n if (options.width) {\n style.width = `${options.width}px`\n }\n\n if (options.height) {\n style.height = `${options.height}px`\n }\n\n const manual = options.style\n if (manual != null) {\n Object.keys(manual).forEach((key: any) => {\n style[key] = manual[key] as string\n })\n }\n\n return node\n}\n","import type { Options } from './types'\nimport { toArray } from './util'\nimport { fetchAsDataURL } from './dataurl'\nimport { shouldEmbed, embedResources } from './embed-resources'\n\ninterface Metadata {\n url: string\n cssText: string\n}\n\nconst cssFetchCache: { [href: string]: Metadata } = {}\n\nasync function fetchCSS(url: string) {\n let cache = cssFetchCache[url]\n if (cache != null) {\n return cache\n }\n\n const res = await fetch(url)\n const cssText = await res.text()\n cache = { url, cssText }\n\n cssFetchCache[url] = cache\n\n return cache\n}\n\nasync function embedFonts(data: Metadata, options: Options): Promise<string> {\n let cssText = data.cssText\n const regexUrl = /url\\([\"']?([^\"')]+)[\"']?\\)/g\n const fontLocs = cssText.match(/url\\([^)]+\\)/g) || []\n const loadFonts = fontLocs.map(async (loc: string) => {\n let url = loc.replace(regexUrl, '$1')\n if (!url.startsWith('https://')) {\n url = new URL(url, data.url).href\n }\n\n return fetchAsDataURL<[string, string]>(\n url,\n options.fetchRequestInit,\n ({ result }) => {\n cssText = cssText.replace(loc, `url(${result})`)\n return [loc, result]\n },\n )\n })\n\n return Promise.all(loadFonts).then(() => cssText)\n}\n\nfunction parseCSS(source: string) {\n if (source == null) {\n return []\n }\n\n const result: string[] = []\n const commentsRegex = /(\\/\\*[\\s\\S]*?\\*\\/)/gi\n // strip out comments\n let cssText = source.replace(commentsRegex, '')\n\n // eslint-disable-next-line prefer-regex-literals\n const keyframesRegex = new RegExp(\n '((@.*?keyframes [\\\\s\\\\S]*?){([\\\\s\\\\S]*?}\\\\s*?)})',\n 'gi',\n )\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const matches = keyframesRegex.exec(cssText)\n if (matches === null) {\n break\n }\n result.push(matches[0])\n }\n cssText = cssText.replace(keyframesRegex, '')\n\n const importRegex = /@import[\\s\\S]*?url\\([^)]*\\)[\\s\\S]*?;/gi\n // to match css & media queries together\n const combinedCSSRegex =\n '((\\\\s*?(?:\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\/)?\\\\s*?@media[\\\\s\\\\S]' +\n '*?){([\\\\s\\\\S]*?)}\\\\s*?})|(([\\\\s\\\\S]*?){([\\\\s\\\\S]*?)})'\n // unified regex\n const unifiedRegex = new RegExp(combinedCSSRegex, 'gi')\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let matches = importRegex.exec(cssText)\n if (matches === null) {\n matches = unifiedRegex.exec(cssText)\n if (matches === null) {\n break\n } else {\n importRegex.lastIndex = unifiedRegex.lastIndex\n }\n } else {\n unifiedRegex.lastIndex = importRegex.lastIndex\n }\n result.push(matches[0])\n }\n\n return result\n}\n\nasync function getCSSRules(\n styleSheets: CSSStyleSheet[],\n options: Options,\n): Promise<CSSStyleRule[]> {\n const ret: CSSStyleRule[] = []\n const deferreds: Promise<number | void>[] = []\n\n // First loop inlines imports\n styleSheets.forEach((sheet) => {\n if ('cssRules' in sheet) {\n try {\n toArray<CSSRule>(sheet.cssRules || []).forEach((item, index) => {\n if (item.type === CSSRule.IMPORT_RULE) {\n let importIndex = index + 1\n const url = (item as CSSImportRule).href\n const deferred = fetchCSS(url)\n .then((metadata) => embedFonts(metadata, options))\n .then((cssText) =>\n parseCSS(cssText).forEach((rule) => {\n try {\n sheet.insertRule(\n rule,\n rule.startsWith('@import')\n ? (importIndex += 1)\n : sheet.cssRules.length,\n )\n } catch (error) {\n console.error('Error inserting rule from remote css', {\n rule,\n error,\n })\n }\n }),\n )\n .catch((e) => {\n console.error('Error loading remote css', e.toString())\n })\n\n deferreds.push(deferred)\n }\n })\n } catch (e) {\n const inline =\n styleSheets.find((a) => a.href == null) || document.styleSheets[0]\n if (sheet.href != null) {\n deferreds.push(\n fetchCSS(sheet.href)\n .then((metadata) => embedFonts(metadata, options))\n .then((cssText) =>\n parseCSS(cssText).forEach((rule) => {\n inline.insertRule(rule, inline.cssRules.length)\n }),\n )\n .catch((err: unknown) => {\n console.error('Error loading remote stylesheet', err)\n }),\n )\n }\n console.error('Error inlining remote css file', e)\n }\n }\n })\n\n return Promise.all(deferreds).then(() => {\n // Second loop parses rules\n styleSheets.forEach((sheet) => {\n if ('cssRules' in sheet) {\n try {\n toArray<CSSStyleRule>(sheet.cssRules || []).forEach((item) => {\n ret.push(item)\n })\n } catch (e) {\n console.error(`Error while reading CSS rules from ${sheet.href}`, e)\n }\n }\n })\n\n return ret\n })\n}\n\nfunction getWebFontRules(cssRules: CSSStyleRule[]): CSSStyleRule[] {\n return cssRules\n .filter((rule) => rule.type === CSSRule.FONT_FACE_RULE)\n .filter((rule) => shouldEmbed(rule.style.getPropertyValue('src')))\n}\n\nasync function parseWebFontRules<T extends HTMLElement>(\n node: T,\n options: Options,\n) {\n if (node.ownerDocument == null) {\n throw new Error('Provided element is not within a Document')\n }\n\n const styleSheets = toArray<CSSStyleSheet>(node.ownerDocument.styleSheets)\n const cssRules = await getCSSRules(styleSheets, options)\n\n return getWebFontRules(cssRules)\n}\n\nfunction normalizeFontFamily(font: string) {\n return font.trim().replace(/[\"']/g, '')\n}\n\nfunction getUsedFonts(node: HTMLElement) {\n const fonts = new Set<string>()\n function traverse(node: HTMLElement) {\n const fontFamily =\n node.style.fontFamily || getComputedStyle(node).fontFamily\n fontFamily.split(',').forEach((font) => {\n fonts.add(normalizeFontFamily(font))\n })\n\n Array.from(node.children).forEach((child) => {\n if (child instanceof HTMLElement) {\n traverse(child)\n }\n })\n }\n traverse(node)\n return fonts\n}\n\nexport async function getWebFontCSS<T extends HTMLElement>(\n node: T,\n options: Options,\n): Promise<string> {\n const rules = await parseWebFontRules(node, options)\n const usedFonts = getUsedFonts(node)\n const cssTexts = await Promise.all(\n rules\n .filter((rule) =>\n usedFonts.has(normalizeFontFamily(rule.style.fontFamily)),\n )\n .map((rule) => {\n const baseUrl = rule.parentStyleSheet\n ? rule.parentStyleSheet.href\n : null\n return embedResources(rule.cssText, baseUrl, options)\n }),\n )\n\n return cssTexts.join('\\n')\n}\n\nexport async function embedWebFonts<T extends HTMLElement>(\n clonedNode: T,\n options: Options,\n) {\n const cssText =\n options.fontEmbedCSS != null\n ? options.fontEmbedCSS\n : options.skipFonts\n ? null\n : await getWebFontCSS(clonedNode, options)\n\n if (cssText) {\n const styleNode = document.createElement('style')\n const sytleContent = document.createTextNode(cssText)\n\n styleNode.appendChild(sytleContent)\n\n if (clonedNode.firstChild) {\n clonedNode.insertBefore(styleNode, clonedNode.firstChild)\n } else {\n clonedNode.appendChild(styleNode)\n }\n }\n}\n","import { Options } from './types'\nimport { cloneNode } from './clone-node'\nimport { embedImages } from './embed-images'\nimport { applyStyle } from './apply-style'\nimport { embedWebFonts, getWebFontCSS } from './embed-webfonts'\nimport {\n getImageSize,\n getPixelRatio,\n createImage,\n canvasToBlob,\n nodeToDataURL,\n checkCanvasDimensions,\n} from './util'\n\nexport async function toSvg<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<string> {\n const { width, height } = getImageSize(node, options)\n const clonedNode = (await cloneNode(node, options, true)) as HTMLElement\n await embedWebFonts(clonedNode, options)\n await embedImages(clonedNode, options)\n applyStyle(clonedNode, options)\n const datauri = await nodeToDataURL(clonedNode, width, height)\n return datauri\n}\n\nexport async function toCanvas<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<HTMLCanvasElement> {\n const { width, height } = getImageSize(node, options)\n const svg = await toSvg(node, options)\n const img = await createImage(svg)\n\n const canvas = document.createElement('canvas')\n const context = canvas.getContext('2d')!\n const ratio = options.pixelRatio || getPixelRatio()\n const canvasWidth = options.canvasWidth || width\n const canvasHeight = options.canvasHeight || height\n\n canvas.width = canvasWidth * ratio\n canvas.height = canvasHeight * ratio\n\n if (!options.skipAutoScale) {\n checkCanvasDimensions(canvas)\n }\n canvas.style.width = `${canvasWidth}`\n canvas.style.height = `${canvasHeight}`\n\n if (options.backgroundColor) {\n context.fillStyle = options.backgroundColor\n context.fillRect(0, 0, canvas.width, canvas.height)\n }\n\n context.drawImage(img, 0, 0, canvas.width, canvas.height)\n\n return canvas\n}\n\nexport async function toPixelData<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<Uint8ClampedArray> {\n const { width, height } = getImageSize(node, options)\n const canvas = await toCanvas(node, options)\n const ctx = canvas.getContext('2d')!\n return ctx.getImageData(0, 0, width, height).data\n}\n\nexport async function toPng<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<string> {\n const canvas = await toCanvas(node, options)\n return canvas.toDataURL()\n}\n\nexport async function toJpeg<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<string> {\n const canvas = await toCanvas(node, options)\n return canvas.toDataURL('image/jpeg', options.quality || 1)\n}\n\nexport async function toBlob<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<Blob | null> {\n const canvas = await toCanvas(node, options)\n const blob = await canvasToBlob(canvas)\n return blob\n}\n\nexport async function getFontEmbedCSS<T extends HTMLElement>(\n node: T,\n options: Options = {},\n): Promise<string> {\n return getWebFontCSS(node, options)\n}\n","/**\n * Screenshot capture — uses native Screen Capture API for pixel-perfect\n * screenshots, with html-to-image as a fallback for unsupported browsers.\n */\n\nimport { toCanvas, getFontEmbedCSS } from 'html-to-image';\n\n/** Show a camera shutter flash animation */\nfunction showFlashAnimation(): void {\n const flash = document.createElement('div');\n flash.style.cssText = `\n position: fixed; inset: 0; z-index: 2147483647;\n background: white; opacity: 0;\n pointer-events: none;\n animation: bs-flash 0.4s ease-out forwards;\n `;\n\n if (!document.getElementById('bs-flash-style')) {\n const style = document.createElement('style');\n style.id = 'bs-flash-style';\n style.textContent = `\n @keyframes bs-flash {\n 0% { opacity: 0; }\n 15% { opacity: 0.7; }\n 100% { opacity: 0; }\n }\n `;\n document.head.appendChild(style);\n }\n\n document.body.appendChild(flash);\n flash.addEventListener('animationend', () => flash.remove());\n}\n\n/** Check if an element is BugStash UI (should be excluded from screenshots). */\nconst isBugStashUI = (el: Element): boolean => {\n const tag = el.tagName.toLowerCase();\n return tag === 'bugstash-root' ||\n tag === 'bugstash-overlay' ||\n tag === 'bugstash-pin' ||\n (el as HTMLElement).classList?.contains('bs-fab') ||\n (el as HTMLElement).classList?.contains('bs-toolbar') ||\n (el as HTMLElement).classList?.contains('bs-modal') ||\n (el as HTMLElement).classList?.contains('bs-backdrop') ||\n el.id === 'bs-flash-style' ||\n el.id === 'bugstash-live-pins' ||\n el.id === 'bugstash-pin-overlay';\n};\n\n/** Quality tier controls pixel ratio, timeout, and cross-origin handling. */\ntype QualityTier = 'high' | 'reduced' | 'reduced-skip-cors';\n\nexport async function captureScreenshot(flash = false): Promise<string | null> {\n if (flash) showFlashAnimation();\n\n // Primary: native Screen Capture API — pixel-perfect, real screenshot\n try {\n const native = await captureWithDisplayMedia();\n if (native) return native;\n } catch {\n // User denied or API not available — fall through to html-to-image\n }\n\n // Fallback chain: toCanvas(high, 5s) → toCanvas(reduced, 8s) → toCanvas(reduced+skipCORS, 8s) → null\n const tiers: ReadonlyArray<{ readonly tier: QualityTier; readonly timeout: number }> = [\n { tier: 'high', timeout: 5_000 },\n { tier: 'reduced', timeout: 8_000 },\n { tier: 'reduced-skip-cors', timeout: 8_000 },\n ];\n\n for (const { tier, timeout } of tiers) {\n try {\n const result = await captureWithHtmlToImage(tier, timeout);\n if (result) return result;\n } catch {\n // Fall through to next tier\n }\n }\n\n return null;\n}\n\n/**\n * Capture using the native Screen Capture API (getDisplayMedia).\n * This captures actual screen pixels — fonts, shadows, blur, video, canvas\n * all render perfectly. Requires a one-time user gesture (browser tab picker).\n */\nasync function captureWithDisplayMedia(): Promise<string | null> {\n if (!navigator.mediaDevices?.getDisplayMedia) return null;\n\n const stream = await navigator.mediaDevices.getDisplayMedia({\n video: {\n displaySurface: 'browser',\n width: { ideal: window.screen.width * (window.devicePixelRatio || 1) },\n height: { ideal: window.screen.height * (window.devicePixelRatio || 1) },\n } as MediaTrackConstraints,\n audio: false,\n // @ts-expect-error -- Chrome 109+ hints to pre-select current tab\n preferCurrentTab: true,\n selfBrowserSurface: 'include',\n monitorTypeSurfaces: 'exclude',\n });\n\n try {\n const track = stream.getVideoTracks()[0];\n if (!track) return null;\n\n // Create a video element to grab a single frame\n const video = document.createElement('video');\n video.srcObject = stream;\n video.muted = true;\n video.playsInline = true;\n\n await video.play();\n\n // Wait for the video to have actual frame data\n await new Promise<void>((resolve) => {\n if (video.readyState >= 2) { resolve(); return; }\n video.onloadeddata = () => resolve();\n });\n\n // Extra frame to ensure the capture is ready\n await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));\n\n const canvas = document.createElement('canvas');\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n const ctx = canvas.getContext('2d');\n if (!ctx) return null;\n\n ctx.drawImage(video, 0, 0);\n\n return canvas.toDataURL('image/png');\n } finally {\n // Always stop the stream — removes the browser \"sharing\" indicator\n stream.getTracks().forEach((t) => t.stop());\n }\n}\n\n/**\n * Inject a `<style>` that pauses all CSS animations and disables transitions.\n * Returns a cleanup function that removes the style element.\n */\nfunction pauseAnimations(): () => void {\n const style = document.createElement('style');\n style.id = 'bs-pause-animations';\n style.textContent = `\n *, *::before, *::after {\n animation-play-state: paused !important;\n transition: none !important;\n }\n `;\n document.head.appendChild(style);\n return () => style.remove();\n}\n\n/**\n * Composite native `<canvas>` and `<video>` elements on top of the captured\n * DOM canvas so their live content is preserved (html-to-image cannot clone them).\n */\nfunction compositeNativeElements(target: HTMLCanvasElement, pixelRatio: number): void {\n const ctx = target.getContext('2d');\n if (!ctx) return;\n\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n\n const elements = document.querySelectorAll<HTMLCanvasElement | HTMLVideoElement>('canvas, video');\n elements.forEach((el) => {\n if (isBugStashUI(el)) return;\n\n const rect = el.getBoundingClientRect();\n const x = (rect.left + scrollX) * pixelRatio;\n const y = (rect.top + scrollY) * pixelRatio;\n const w = rect.width * pixelRatio;\n const h = rect.height * pixelRatio;\n\n try {\n ctx.drawImage(el, x, y, w, h);\n } catch {\n // Cross-origin or tainted canvas — skip silently\n }\n });\n}\n\n/** Create a timeout promise that rejects after `ms` milliseconds. */\nfunction timeoutPromise(ms: number): Promise<never> {\n return new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error(`Screenshot capture timed out after ${ms}ms`)), ms);\n });\n}\n\n/**\n * html-to-image fallback — re-renders the DOM via toCanvas(), composites\n * native canvas/video elements, and converts to a data URL.\n */\nasync function captureWithHtmlToImage(\n tier: QualityTier,\n timeout: number,\n): Promise<string | null> {\n const skipCrossOriginImages = tier === 'reduced-skip-cors';\n const pixelRatio = tier === 'high'\n ? Math.min(window.devicePixelRatio || 1, 3)\n : Math.min(window.devicePixelRatio || 1, 2);\n\n const bodyBg = window.getComputedStyle(document.body).backgroundColor;\n const htmlBg = window.getComputedStyle(document.documentElement).backgroundColor;\n const isTransparent = (c: string) => !c || c === 'transparent' || c === 'rgba(0, 0, 0, 0)';\n const bgColor = !isTransparent(bodyBg) ? bodyBg : !isTransparent(htmlBg) ? htmlBg : '#ffffff';\n\n // Pre-embed fonts so the rendered canvas matches the live page\n const fontEmbedCSS = await getFontEmbedCSS(document.body);\n\n const resumeAnimations = pauseAnimations();\n\n try {\n const canvas = await Promise.race([\n toCanvas(document.body, {\n pixelRatio,\n backgroundColor: bgColor,\n width: window.innerWidth,\n height: window.innerHeight,\n cacheBust: true,\n fontEmbedCSS,\n // html-to-image filter: return true to INCLUDE, false to EXCLUDE\n filter: (node: HTMLElement) => {\n if (skipCrossOriginImages && node.tagName === 'IMG') {\n const src = (node as HTMLImageElement).src || '';\n if (src && !src.startsWith(window.location.origin) && !src.startsWith('data:')) {\n return false;\n }\n }\n return !isBugStashUI(node);\n },\n // Placeholder for images that fail to load (avoids broken captures)\n imagePlaceholder:\n 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',\n }),\n timeoutPromise(timeout),\n ]);\n\n // Overlay native <canvas> and <video> content that html-to-image cannot clone\n compositeNativeElements(canvas, pixelRatio);\n\n return canvas.toDataURL('image/png');\n } finally {\n resumeAnimations();\n }\n}\n","import type { BugReport, APIResponse, AuthUser, AuthTokens, LivePin, PinComment, Member } from '@bugstash/shared';\n\n\n// Primary cloud backend. Falls back to Azure if custom domain is unreachable.\n// Self-hosted users can override via BugStash.init({ endpoint: '...' }).\nconst PRIMARY_ENDPOINT = 'https://bugstash-backend.vercel.app';\nconst FALLBACK_ENDPOINT = 'https://bugstash-backend.vercel.app';\n\nlet endpoint = PRIMARY_ENDPOINT;\nlet _usingFallback = false;\n\nexport function setEndpoint(url: string) {\n endpoint = url.replace(/\\/$/, '');\n _usingFallback = false;\n}\n\nexport function getEndpoint() {\n return endpoint;\n}\n\n/**\n * Tries the current endpoint. On network failure (ERR_CONNECTION_REFUSED, etc.),\n * transparently falls back to the Azure backend so SDK login/reports always work\n * — even if a developer passes a bad endpoint or localhost isn't running.\n */\nasync function fetchWithFallback(url: string, init?: RequestInit): Promise<Response> {\n try {\n const res = await fetch(url, init);\n return res;\n } catch (err) {\n // Already on the final fallback — nothing left to try\n if (_usingFallback) throw err;\n\n // Fall back to Azure regardless of what the current endpoint is\n _usingFallback = true;\n const previousEndpoint = endpoint;\n endpoint = FALLBACK_ENDPOINT;\n const fallbackUrl = url.replace(previousEndpoint, FALLBACK_ENDPOINT);\n return fetch(fallbackUrl, init);\n }\n}\n\n// ─── Token Management ────────────────────────────────────\n\nconst STORAGE_KEY = 'bugstash_auth';\n\ninterface StoredAuth {\n user: AuthUser;\n tokens: AuthTokens;\n}\n\nfunction getStoredAuth(): StoredAuth | null {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return null;\n const auth = JSON.parse(raw) as StoredAuth;\n // Check if access token expired\n if (auth.tokens.expiresAt < Date.now()) {\n // Try to refresh\n return auth; // Will be refreshed on next request\n }\n return auth;\n } catch {\n return null;\n }\n}\n\nfunction setStoredAuth(auth: StoredAuth) {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(auth));\n}\n\nexport function clearStoredAuth() {\n localStorage.removeItem(STORAGE_KEY);\n}\n\nexport function getCurrentUser(): AuthUser | null {\n return getStoredAuth()?.user || null;\n}\n\nexport function getAccessToken(): string | null {\n return getStoredAuth()?.tokens.accessToken || null;\n}\n\nasync function authHeaders(): Promise<Record<string, string>> {\n const auth = getStoredAuth();\n if (!auth) return { 'Content-Type': 'application/json' };\n\n // Refresh if expired\n if (auth.tokens.expiresAt < Date.now() + 60000) {\n try {\n const res = await fetchWithFallback(`${endpoint}/api/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: auth.tokens.refreshToken }),\n });\n if (res.ok) {\n const data = await res.json();\n if (data.success) {\n auth.tokens = data.data;\n setStoredAuth(auth);\n }\n }\n } catch { /* Use existing token */ }\n }\n\n return {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${auth.tokens.accessToken}`,\n };\n}\n\n// ─── Auth API ────────────────────────────────────────────\n\nexport async function login(email: string, password: string, projectId: string): Promise<APIResponse<{ user: AuthUser; tokens: AuthTokens }>> {\n try {\n const res = await fetchWithFallback(`${endpoint}/api/auth/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, password, projectId }),\n });\n const data = await res.json();\n if (data.success) {\n setStoredAuth({ user: data.data.user, tokens: data.data.tokens });\n }\n return data;\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\nexport async function logout() {\n clearStoredAuth();\n}\n\nexport async function fetchMe(): Promise<APIResponse<AuthUser>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/auth/me`, { headers });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\n// ─── Reports API ─────────────────────────────────────────\n\nexport async function submitReport(report: BugReport): Promise<APIResponse<{ id: string }>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/reports`, {\n method: 'POST',\n headers,\n body: JSON.stringify(report),\n });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error - could not reach BugStash' };\n }\n}\n\n// ─── Pins API ────────────────────────────────────────────\n\nexport async function fetchPagePins(projectId: string, pathname: string): Promise<APIResponse<LivePin[]>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins/by-page?projectId=${projectId}&pathname=${encodeURIComponent(pathname)}`, { headers });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\nexport async function createPin(pin: Partial<LivePin>): Promise<APIResponse<LivePin>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins`, {\n method: 'POST',\n headers,\n body: JSON.stringify(pin),\n });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\nexport async function updatePin(pinId: string, updates: Partial<LivePin>): Promise<APIResponse<LivePin>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins/${pinId}`, {\n method: 'PUT',\n headers,\n body: JSON.stringify(updates),\n });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\nexport async function deletePin(pinId: string): Promise<APIResponse<void>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins/${pinId}`, {\n method: 'DELETE',\n headers,\n });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\n// ─── Comments API ────────────────────────────────────────\n\nexport async function fetchComments(pinId: string): Promise<APIResponse<PinComment[]>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins/${pinId}/comments`, { headers });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\nexport async function createComment(pinId: string, body: string, mentions: string[] = []): Promise<APIResponse<PinComment>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/pins/${pinId}/comments`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ body, mentions }),\n });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\n// ─── Members API ─────────────────────────────────────────\n\nexport async function fetchProjectMembers(projectId: string): Promise<APIResponse<Member[]>> {\n try {\n const headers = await authHeaders();\n const res = await fetchWithFallback(`${endpoint}/api/members/for-project/${projectId}`, { headers });\n return await res.json();\n } catch {\n return { success: false, error: 'Network error' };\n }\n}\n\n// ─── Domain Verification ─────────────────────────────────\n\nlet _domainVerifyPromise: Promise<boolean> | null = null;\n\n/**\n * Check if the current domain is allowed for the given project.\n * Result is cached (promise-based) for the lifetime of the page.\n */\nexport function verifyDomain(projectId: string): Promise<boolean> {\n if (_domainVerifyPromise) return _domainVerifyPromise;\n\n _domainVerifyPromise = (async () => {\n try {\n const res = await fetch(\n `${endpoint}/api/orgs/projects/${encodeURIComponent(projectId)}/verify-domain`,\n { headers: { 'Content-Type': 'application/json' } },\n );\n if (!res.ok) return false;\n const data = await res.json();\n return data.allowed === true;\n } catch {\n // On network error, deny by default (fail closed)\n return false;\n }\n })();\n\n return _domainVerifyPromise;\n}\n\n// ─── Offline Queue ───────────────────────────────────────\n\nconst QUEUE_KEY = 'bugstash_offline_queue';\n\ninterface QueuedAction {\n id: string;\n type: 'create_pin' | 'create_comment' | 'update_pin' | 'submit_report';\n data: any;\n timestamp: number;\n}\n\nexport function queueOfflineAction(action: Omit<QueuedAction, 'id' | 'timestamp'>) {\n const queue = getOfflineQueue();\n queue.push({\n ...action,\n id: Math.random().toString(36).slice(2),\n timestamp: Date.now(),\n });\n localStorage.setItem(QUEUE_KEY, JSON.stringify(queue));\n}\n\nexport function getOfflineQueue(): QueuedAction[] {\n try {\n return JSON.parse(localStorage.getItem(QUEUE_KEY) || '[]');\n } catch {\n return [];\n }\n}\n\nexport async function flushOfflineQueue(): Promise<number> {\n const queue = getOfflineQueue();\n if (queue.length === 0) return 0;\n\n let flushed = 0;\n const remaining: QueuedAction[] = [];\n\n for (const action of queue) {\n try {\n let result: APIResponse<any>;\n switch (action.type) {\n case 'create_pin':\n result = await createPin(action.data);\n break;\n case 'create_comment':\n result = await createComment(action.data.pinId, action.data.body, action.data.mentions);\n break;\n case 'update_pin':\n result = await updatePin(action.data.pinId, action.data.updates);\n break;\n case 'submit_report':\n result = await submitReport(action.data);\n break;\n default:\n result = { success: false, error: 'Unknown action' };\n }\n if (result.success) {\n flushed++;\n } else {\n remaining.push(action);\n }\n } catch {\n remaining.push(action);\n }\n }\n\n localStorage.setItem(QUEUE_KEY, JSON.stringify(remaining));\n return flushed;\n}\n\n// Auto-flush when back online\nif (typeof window !== 'undefined') {\n window.addEventListener('online', () => {\n flushOfflineQueue().catch(() => {});\n });\n}\n","export interface BsTheme {\n id: string;\n name: string;\n preview: [string, string]; // [bg, accent] for switcher preview\n vars: Record<string, string>;\n}\n\nconst THEMES: BsTheme[] = [\n // ─── Slate (default — blue-gray) ──────────────────\n {\n id: 'slate',\n name: 'Slate',\n preview: ['#0f1117', '#6E9ED0'],\n vars: {\n '--bs-bg': '#0f1117',\n '--bs-bg2': '#1a1d27',\n '--bs-bg3': '#2a2d37',\n '--bs-text': '#e8eaed',\n '--bs-muted': '#9ca3af',\n '--bs-border': '#2a2d37',\n '--bs-accent': '#6E9ED0',\n '--bs-accent2': '#C3CAD6',\n '--bs-fab1': '#6E9ED0',\n '--bs-fab2': '#4a7ba8',\n '--bs-radius': '12px',\n '--bs-radius-sm': '8px',\n '--bs-red': '#ef4444',\n '--bs-green': '#22c55e',\n '--bs-orange': '#f97316',\n '--bs-yellow': '#eab308',\n },\n },\n // ─── Pure Black ────────────────────────────────────\n {\n id: 'black',\n name: 'Dark',\n preview: ['#0a0a0a', '#ffffff'],\n vars: {\n '--bs-bg': '#0a0a0a',\n '--bs-bg2': '#141414',\n '--bs-bg3': '#1e1e1e',\n '--bs-text': '#f5f5f5',\n '--bs-muted': '#737373',\n '--bs-border': '#262626',\n '--bs-accent': '#f5f5f5',\n '--bs-accent2': '#d4d4d4',\n '--bs-fab1': '#262626',\n '--bs-fab2': '#171717',\n '--bs-radius': '12px',\n '--bs-radius-sm': '8px',\n '--bs-red': '#ef4444',\n '--bs-green': '#22c55e',\n '--bs-orange': '#f97316',\n '--bs-yellow': '#eab308',\n },\n },\n // ─── Pure White ────────────────────────────────────\n {\n id: 'white',\n name: 'Light',\n preview: ['#ffffff', '#0a0a0a'],\n vars: {\n '--bs-bg': '#ffffff',\n '--bs-bg2': '#f5f5f5',\n '--bs-bg3': '#e5e5e5',\n '--bs-text': '#0a0a0a',\n '--bs-muted': '#737373',\n '--bs-border': '#e5e5e5',\n '--bs-accent': '#0a0a0a',\n '--bs-accent2': '#404040',\n '--bs-fab1': '#0a0a0a',\n '--bs-fab2': '#262626',\n '--bs-radius': '12px',\n '--bs-radius-sm': '8px',\n '--bs-red': '#dc2626',\n '--bs-green': '#16a34a',\n '--bs-orange': '#ea580c',\n '--bs-yellow': '#ca8a04',\n },\n },\n];\n\nexport function getThemes(): BsTheme[] {\n return THEMES;\n}\n\nexport function getThemeById(id: string): BsTheme | undefined {\n return THEMES.find((t) => t.id === id);\n}\n\nexport function getDefaultTheme(): BsTheme {\n return THEMES[0];\n}\n","export interface BsLayout {\n id: string;\n name: string;\n description: string;\n tabPosition: 'top' | 'left' | 'bottom';\n}\n\nconst LAYOUTS: BsLayout[] = [\n { id: 'classic', name: 'Center', description: 'Centered modal', tabPosition: 'top' },\n { id: 'drawer-right', name: 'Right Drawer', description: 'Slides from right', tabPosition: 'top' },\n { id: 'bottom-sheet', name: 'Bottom Sheet', description: 'Slides from bottom', tabPosition: 'top' },\n { id: 'sidebar-tabs', name: 'Sidebar', description: 'Side navigation', tabPosition: 'left' },\n];\n\nexport function getLayouts(): BsLayout[] {\n return LAYOUTS;\n}\n\nexport function getLayoutById(id: string): BsLayout | undefined {\n return LAYOUTS.find((l) => l.id === id);\n}\n\nexport function getDefaultLayout(): BsLayout {\n return LAYOUTS[0];\n}\n\n// ─── Layout CSS ──────────────────────────────────────────\n\nexport const LAYOUT_CSS = `\n/* ── 1. Classic (default — no overrides) ── */\n\n/* ── 2. Drawer Right ── */\n.bs-ly-drawer-right.bs-modal {\n top: 0; left: auto; right: 0; bottom: 0;\n width: 420px; max-width: 100vw; max-height: 100vh;\n height: 100vh;\n border-radius: 0;\n transform: translateX(100%);\n transition: transform 0.4s cubic-bezier(0.22,1,0.36,1), opacity 0.3s ease;\n}\n.bs-ly-drawer-right.bs-modal.bs-in {\n transform: translateX(0);\n opacity: 1;\n}\n\n/* ── 3. Bottom Sheet ── */\n.bs-ly-bottom-sheet.bs-modal {\n top: auto; left: 50%; right: auto; bottom: 0;\n width: 600px; max-width: 100vw;\n max-height: 80vh;\n border-radius: var(--bs-radius) var(--bs-radius) 0 0;\n transform: translate(-50%, 100%);\n transition: transform 0.45s cubic-bezier(0.22,1,0.36,1), opacity 0.3s ease;\n}\n.bs-ly-bottom-sheet.bs-modal.bs-in {\n transform: translate(-50%, 0);\n opacity: 1;\n}\n\n/* ── 4. Sidebar Tabs ── */\n.bs-ly-sidebar-tabs.bs-modal {\n width: 620px;\n}\n.bs-ly-sidebar-tabs .bs-body-wrap {\n display: flex;\n flex: 1;\n overflow: hidden;\n}\n.bs-ly-sidebar-tabs .bs-tabs {\n flex-direction: column;\n padding: 12px 0 12px 12px;\n gap: 4px;\n min-width: 140px;\n border-right: 1px solid var(--bs-border);\n overflow-y: auto;\n}\n.bs-ly-sidebar-tabs .bs-tab {\n border-radius: var(--bs-radius-sm);\n padding: 10px 12px;\n width: 100%;\n}\n.bs-ly-sidebar-tabs .bs-tab.bs-active::after {\n top: 8px; bottom: 8px; left: 0; right: auto;\n width: 2px; height: auto;\n border-radius: 0 2px 2px 0;\n}\n.bs-ly-sidebar-tabs .bs-tab-divider { display: none; }\n.bs-ly-sidebar-tabs .bs-scroll { flex: 1; }\n`;\n\nexport default LAYOUTS;\n","import { getEndpoint, getAccessToken } from './api';\nimport type { WSEvent } from '@bugstash/shared';\n\ntype EventHandler = (event: WSEvent) => void;\n\nlet pollTimer: ReturnType<typeof setInterval> | null = null;\nlet lastPollTime = 0;\nconst POLL_INTERVAL = 5000; // 5 seconds\nconst handlers = new Map<string, Set<EventHandler>>();\nlet currentProjectId: string | null = null;\nlet knownPinIds = new Set<string>();\n\nexport function connectRealtime(projectId: string) {\n currentProjectId = projectId;\n lastPollTime = Date.now();\n startPolling();\n}\n\nfunction startPolling() {\n if (pollTimer) return;\n pollTimer = setInterval(poll, POLL_INTERVAL);\n}\n\nasync function poll() {\n if (!currentProjectId) return;\n const token = getAccessToken();\n if (!token) return;\n\n try {\n const endpoint = getEndpoint();\n const pathname = window.location.pathname;\n const res = await fetch(\n `${endpoint}/api/pins/poll?projectId=${currentProjectId}&pathname=${encodeURIComponent(pathname)}&since=${lastPollTime}`,\n { headers: { Authorization: `Bearer ${token}` } }\n );\n\n if (!res.ok) return;\n const data = await res.json();\n if (!data.success) return;\n\n const pins = Array.isArray(data.data) ? data.data : (data.data?.pins || []);\n lastPollTime = data.serverTime || data.data?.serverTime || Date.now();\n\n for (const pin of pins) {\n if (knownPinIds.has(pin.id)) {\n emit('pin:updated', {\n type: 'pin:updated',\n projectId: currentProjectId,\n data: pin,\n userId: '',\n timestamp: Date.now(),\n });\n } else {\n knownPinIds.add(pin.id);\n emit('pin:created', {\n type: 'pin:created',\n projectId: currentProjectId,\n data: pin,\n userId: '',\n timestamp: Date.now(),\n });\n }\n }\n } catch {\n // Silently fail — will retry next interval\n }\n}\n\nexport function disconnectRealtime() {\n if (pollTimer) {\n clearInterval(pollTimer);\n pollTimer = null;\n }\n currentProjectId = null;\n knownPinIds.clear();\n lastPollTime = 0;\n}\n\nexport function onRealtimeEvent(type: string, handler: EventHandler) {\n if (!handlers.has(type)) handlers.set(type, new Set());\n handlers.get(type)!.add(handler);\n return () => {\n handlers.get(type)?.delete(handler);\n };\n}\n\nfunction emit(type: string, event: WSEvent) {\n handlers.get(type)?.forEach((h) => h(event));\n handlers.get('*')?.forEach((h) => h(event));\n}\n\n/** Register known pin IDs so polling can detect new vs updated */\nexport function registerKnownPins(pinIds: string[]) {\n knownPinIds = new Set(pinIds);\n}\n\n// Cursor and navigation are no-ops in polling mode\nexport function sendCursorPosition(_x: number, _y: number, _pageUrl: string) {}\nexport function sendPageNavigate(_pageUrl: string) {}\n\nexport function isConnected(): boolean {\n return pollTimer !== null;\n}\n","/**\n * Pin CSS constants — extracted from livepins.ts to keep files under 800 lines.\n * Styles are injected into each <bugstash-pin> shadow DOM for isolation.\n */\n\nexport const PIN_MARKER_STYLES = `\n :host {\n all: initial !important;\n display: block !important;\n position: absolute !important;\n /* CSS custom properties survive all:initial — inline --bs-x/--bs-y set per pin */\n left: var(--bs-x, 0) !important;\n top: var(--bs-y, 0) !important;\n pointer-events: auto !important;\n z-index: 2147483640 !important;\n cursor: pointer !important;\n transform: translate(-50%, -50%) !important;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n :host(:hover) {\n transform: translate(-50%, -50%) scale(1.1) !important;\n z-index: 2147483645 !important;\n }\n\n /* Color scheme support */\n @media (prefers-color-scheme: light) {\n :host { --bs-pin-bg: #ffffff; --bs-pin-text: #171717; --bs-pin-muted: #6b7280; --bs-pin-border: #eaeaea; --bs-pin-surface: #fafafa; --bs-pin-input-bg: #ffffff; --bs-pin-hover: #f5f5f5; --bs-pin-shadow: rgba(0,0,0,0.08); --bs-pin-shadow-lg: rgba(0,0,0,0.12); }\n }\n @media (prefers-color-scheme: dark) {\n :host { --bs-pin-bg: #1a1a1a; --bs-pin-text: #ededed; --bs-pin-muted: #888; --bs-pin-border: #333; --bs-pin-surface: #222; --bs-pin-input-bg: #2a2a2a; --bs-pin-hover: #2a2a2a; --bs-pin-shadow: rgba(0,0,0,0.2); --bs-pin-shadow-lg: rgba(0,0,0,0.4); }\n }\n /* Fallback (default to light) */\n :host {\n --bs-pin-bg: #ffffff; --bs-pin-text: #171717; --bs-pin-muted: #6b7280; --bs-pin-border: #eaeaea; --bs-pin-surface: #fafafa; --bs-pin-input-bg: #ffffff; --bs-pin-hover: #f5f5f5; --bs-pin-shadow: rgba(0,0,0,0.08); --bs-pin-shadow-lg: rgba(0,0,0,0.12);\n }\n @media (prefers-color-scheme: dark) {\n :host { --bs-pin-bg: #1a1a1a; --bs-pin-text: #ededed; --bs-pin-muted: #888; --bs-pin-border: #333; --bs-pin-surface: #222; --bs-pin-input-bg: #2a2a2a; --bs-pin-hover: #2a2a2a; --bs-pin-shadow: rgba(0,0,0,0.2); --bs-pin-shadow-lg: rgba(0,0,0,0.4); }\n }\n\n *, *::before, *::after {\n box-sizing: border-box !important;\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;\n line-height: 1.5;\n direction: ltr;\n text-align: left;\n }\n\n /* ── Pin Marker (Avatar-based) ── */\n .bs-lp-dot {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 600;\n color: #fff;\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n position: relative;\n overflow: hidden;\n background-size: cover;\n background-position: center;\n }\n .bs-lp-dot.bs-overdue {\n box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.4), 0 0 12px rgba(239, 68, 68, 0.25);\n }\n .bs-lp-avatar {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n }\n .bs-lp-initials {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 600;\n color: #fff;\n }\n .bs-lp-badge {\n position: absolute;\n top: -3px;\n right: -3px;\n min-width: 14px;\n height: 14px;\n border-radius: 7px;\n background: var(--bs-pin-text, #171717);\n color: var(--bs-pin-bg, #fff);\n font-size: 9px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 3px;\n line-height: 1;\n z-index: 2;\n }\n`;\n\nexport const PIN_POPUP_STYLES = `\n /* ── Popup (Clean Card) ── */\n .bs-lp-popup {\n position: absolute;\n left: 40px;\n top: -8px;\n width: min(360px, calc(100vw - 48px));\n background: var(--bs-pin-bg);\n border: 1px solid var(--bs-pin-border);\n border-radius: 14px;\n box-shadow: 0 8px 30px var(--bs-pin-shadow-lg), 0 0 0 1px var(--bs-pin-shadow);\n backdrop-filter: blur(12px);\n z-index: 10;\n pointer-events: auto;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n color: var(--bs-pin-text);\n overflow: hidden;\n animation: bs-lp-pop-in 0.2s ease;\n }\n @keyframes bs-lp-pop-in {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .bs-lp-popup-hdr {\n padding: 14px 16px 12px;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n }\n .bs-lp-popup-hdr-avatar {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 10px;\n font-weight: 600;\n color: #fff;\n overflow: hidden;\n }\n .bs-lp-popup-hdr-avatar img { width: 100%; height: 100%; object-fit: cover; }\n .bs-lp-popup-hdr-body { flex: 1; min-width: 0; }\n .bs-lp-popup-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--bs-pin-text);\n line-height: 1.3;\n margin-bottom: 2px;\n }\n .bs-lp-popup-meta {\n font-size: 12px;\n color: var(--bs-pin-muted);\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n }\n .bs-lp-popup-pill {\n font-size: 11px;\n padding: 2px 8px;\n border-radius: 99px;\n font-weight: 500;\n white-space: nowrap;\n }\n .bs-lp-popup-close {\n all: initial;\n color: var(--bs-pin-muted);\n cursor: pointer;\n padding: 2px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n transition: background 0.15s, color 0.15s;\n }\n .bs-lp-popup-close:hover { color: var(--bs-pin-text); background: var(--bs-pin-hover); }\n .bs-lp-popup-close svg { width: 16px; height: 16px; }\n .bs-lp-popup-desc {\n padding: 0 16px 12px;\n font-size: 13px;\n line-height: 1.6;\n color: var(--bs-pin-muted);\n }\n .bs-lp-popup-due {\n padding: 6px 16px;\n font-size: 12px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 4px;\n }\n .bs-lp-popup-due.overdue { color: #ef4444; background: rgba(239,68,68,0.06); }\n .bs-lp-popup-due:not(.overdue) { color: var(--bs-pin-muted); }\n .bs-lp-popup-info {\n padding: 8px 16px;\n font-size: 11px;\n color: var(--bs-pin-muted);\n background: var(--bs-pin-surface);\n border-top: 1px solid var(--bs-pin-border);\n display: flex;\n justify-content: space-between;\n }\n\n /* Comments */\n .bs-lp-cmts {\n max-height: 220px;\n overflow-y: auto;\n border-top: 1px solid var(--bs-pin-border);\n }\n .bs-lp-cmts::-webkit-scrollbar { width: 4px; }\n .bs-lp-cmts::-webkit-scrollbar-thumb { background: var(--bs-pin-border); border-radius: 2px; }\n .bs-lp-cmt {\n padding: 10px 16px;\n display: flex;\n gap: 8px;\n align-items: flex-start;\n border-bottom: 1px solid var(--bs-pin-border);\n }\n .bs-lp-cmt:last-child { border-bottom: none; }\n .bs-lp-cmt-avatar {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 8px;\n font-weight: 600;\n color: #fff;\n overflow: hidden;\n }\n .bs-lp-cmt-avatar img { width: 100%; height: 100%; object-fit: cover; }\n .bs-lp-cmt-content { flex: 1; min-width: 0; }\n .bs-lp-cmt-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 2px; }\n .bs-lp-cmt-author { font-weight: 600; color: var(--bs-pin-text); font-size: 12px; }\n .bs-lp-cmt-time { font-size: 11px; color: var(--bs-pin-muted); }\n .bs-lp-cmt-body { color: var(--bs-pin-text); font-size: 13px; line-height: 1.5; }\n\n /* Comment input */\n .bs-lp-input {\n display: flex;\n align-items: center;\n border-top: 1px solid var(--bs-pin-border);\n padding: 4px;\n gap: 4px;\n }\n .bs-lp-input input {\n all: initial;\n flex: 1;\n padding: 8px 12px;\n color: var(--bs-pin-text);\n font-size: 13px;\n font-family: inherit;\n background: var(--bs-pin-input-bg);\n border: 1px solid var(--bs-pin-border);\n border-radius: 8px;\n box-sizing: border-box;\n transition: border-color 0.15s;\n }\n .bs-lp-input input:focus { border-color: #6E9ED0; outline: none; }\n .bs-lp-input input::placeholder { color: var(--bs-pin-muted); }\n .bs-lp-input button {\n all: initial;\n width: 32px;\n height: 32px;\n border-radius: 8px;\n background: #6E9ED0;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: opacity 0.15s;\n }\n .bs-lp-input button:hover { opacity: 0.85; }\n .bs-lp-input button svg { width: 14px; height: 14px; }\n\n /* Actions */\n .bs-lp-acts {\n padding: 8px 16px 10px;\n display: flex;\n gap: 8px;\n border-top: 1px solid var(--bs-pin-border);\n }\n .bs-lp-act {\n all: initial;\n padding: 6px 14px;\n border-radius: 8px;\n background: var(--bs-pin-surface);\n color: var(--bs-pin-muted);\n font-size: 12px;\n font-weight: 500;\n font-family: inherit;\n cursor: pointer;\n transition: all 0.15s;\n display: flex;\n align-items: center;\n gap: 5px;\n }\n .bs-lp-act:hover { background: var(--bs-pin-hover); color: var(--bs-pin-text); }\n .bs-lp-act.resolve { color: #22c55e; }\n .bs-lp-act.resolve:hover { background: rgba(34,197,94,0.1); }\n .bs-lp-act.delete { color: #ef4444; }\n .bs-lp-act.delete:hover { background: rgba(239,68,68,0.1); }\n`;\n\nexport const PIN_FORM_STYLES = `\n /* ── New Pin Form ── */\n .bs-lp-form {\n position: fixed;\n width: min(320px, calc(100vw - 32px));\n background: var(--bs-pin-bg);\n border: 1px solid var(--bs-pin-border);\n border-radius: 14px;\n box-shadow: 0 8px 30px var(--bs-pin-shadow-lg);\n backdrop-filter: blur(12px);\n z-index: 2147483645;\n pointer-events: auto;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n color: var(--bs-pin-text);\n padding: 16px;\n animation: bs-lp-pop-in 0.2s ease;\n }\n .bs-lp-form-label {\n display: block;\n font-size: 12px;\n color: var(--bs-pin-muted);\n margin-bottom: 4px;\n margin-top: 12px;\n font-weight: 500;\n }\n .bs-lp-form-label:first-child { margin-top: 0; }\n .bs-lp-form input,\n .bs-lp-form textarea,\n .bs-lp-form select {\n all: initial;\n display: block;\n width: 100%;\n background: var(--bs-pin-input-bg);\n border: 1px solid var(--bs-pin-border);\n border-radius: 10px;\n padding: 8px 12px;\n color: var(--bs-pin-text);\n font-size: 13px;\n font-family: inherit;\n box-sizing: border-box;\n transition: border-color 0.15s;\n }\n .bs-lp-form textarea { resize: vertical; min-height: 48px; white-space: pre-wrap; }\n .bs-lp-form input:focus,\n .bs-lp-form textarea:focus,\n .bs-lp-form select:focus { border-color: #6E9ED0; outline: none; }\n .bs-lp-form input::placeholder,\n .bs-lp-form textarea::placeholder { color: var(--bs-pin-muted); }\n /* Segmented buttons for priority/category */\n .bs-lp-seg-row {\n display: flex;\n gap: 0;\n border: 1px solid var(--bs-pin-border);\n border-radius: 10px;\n overflow: hidden;\n }\n .bs-lp-seg-btn {\n all: initial;\n flex: 1;\n padding: 7px 4px;\n text-align: center;\n font-size: 12px;\n font-weight: 500;\n font-family: inherit;\n cursor: pointer;\n color: var(--bs-pin-muted);\n background: var(--bs-pin-input-bg);\n border-right: 1px solid var(--bs-pin-border);\n transition: all 0.15s;\n box-sizing: border-box;\n }\n .bs-lp-seg-btn:last-child { border-right: none; }\n .bs-lp-seg-btn:hover { color: var(--bs-pin-text); background: var(--bs-pin-hover); }\n .bs-lp-seg-btn.bs-active { background: #6E9ED0; color: #fff; }\n .bs-lp-form-btns { display: flex; gap: 8px; margin-top: 14px; }\n .bs-lp-form-btns button {\n all: initial;\n padding: 9px 16px;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 600;\n font-family: inherit;\n cursor: pointer;\n text-align: center;\n transition: opacity 0.15s;\n }\n .bs-lp-form-submit { background: #6E9ED0; color: #fff; flex: 1; }\n .bs-lp-form-submit:hover { opacity: 0.85; }\n .bs-lp-form-cancel { background: transparent; color: var(--bs-pin-muted); }\n .bs-lp-form-cancel:hover { color: var(--bs-pin-text); }\n`;\n","import type { LivePin, Member } from '@bugstash/shared';\nimport { fetchPagePins, createPin, updatePin, deletePin, fetchComments, createComment, fetchProjectMembers, getCurrentUser, queueOfflineAction } from './api';\nimport { onRealtimeEvent, sendPageNavigate, registerKnownPins } from './realtime';\nimport { getLogs } from './logger';\nimport { getErrors } from './errors';\nimport { getFailedNetworkCaptures } from './network';\nimport { PIN_MARKER_STYLES, PIN_POPUP_STYLES, PIN_FORM_STYLES } from './pin-styles';\n\nlet projectId: string;\nlet container: HTMLDivElement | null = null;\nlet clickOverlay: HTMLElement | null = null;\nlet pins: LivePin[] = [];\nlet members: Member[] = [];\nlet pinMode = false;\nlet activePopup: HTMLDivElement | null = null;\nlet currentPathname = '';\nlet mutationObserver: MutationObserver | null = null;\nlet shadow: ShadowRoot | null = null;\n/** Map of pin ID → <bugstash-pin> element in the light DOM */\nlet pinElements: Map<string, HTMLElement> = new Map();\n/** Interval for periodic visibility checks on pin target elements */\nlet visibilityCheckInterval: ReturnType<typeof setInterval> | null = null;\n\nconst STATUS_COLORS: Record<string, string> = {\n open: '#f97316',\n in_progress: '#3b82f6',\n resolved: '#22c55e',\n closed: '#6b7280',\n};\n\nconst PRIORITY_COLORS: Record<string, string> = {\n critical: '#ef4444',\n high: '#f97316',\n medium: '#eab308',\n low: '#6b7280',\n};\n\n\nexport function initLivePins(projId: string, sr: ShadowRoot) {\n projectId = projId;\n shadow = sr;\n currentPathname = window.location.pathname;\n\n createOverlay();\n loadPins();\n loadMembers();\n setupRealtimeListeners();\n watchNavigation();\n setupListeners();\n}\n\nexport function destroyLivePins() {\n teardownListeners();\n removePinElements();\n container?.remove();\n container = null;\n clickOverlay?.remove();\n clickOverlay = null;\n shadow = null;\n pins = [];\n}\n\nexport function togglePinMode(enabled?: boolean) {\n pinMode = enabled !== undefined ? enabled : !pinMode;\n if (clickOverlay) {\n clickOverlay.style.setProperty('display', pinMode ? 'block' : 'none', 'important');\n }\n return pinMode;\n}\n\nexport function isPinModeActive() {\n return pinMode;\n}\n\n// ─── Element Resolution ─────────────────────────────────\n\n/** Try to find an element by CSS selector chain, then by XPath. */\nfunction findElement(selector: string, xpath: string): Element | null {\n // Parse: JSON array = selector chain; plain string = single selector (backward compat)\n let selectors: string[];\n if (selector && selector.startsWith('[\"') && selector.endsWith('\"]')) {\n try {\n const parsed = JSON.parse(selector);\n selectors = Array.isArray(parsed) ? parsed.filter((s): s is string => typeof s === 'string') : [selector];\n } catch { selectors = [selector]; }\n } else {\n selectors = selector ? [selector] : [];\n }\n\n for (const sel of selectors) {\n if (sel && sel !== 'body') {\n try {\n const el = document.querySelector(sel);\n if (el) return el;\n } catch { /* invalid selector */ }\n }\n }\n\n if (xpath) {\n try {\n const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);\n if (result.singleNodeValue instanceof Element) return result.singleNodeValue;\n } catch { /* invalid xpath */ }\n }\n return null;\n}\n\n/**\n * Check if an element is clipped (scrolled out of view) by any overflow ancestor.\n * Returns true if the element is not visible within its scroll containers or\n * is completely outside the viewport.\n */\nfunction isElementClipped(el: Element): boolean {\n const rect = el.getBoundingClientRect();\n\n // Off-screen entirely (viewport check)\n if (rect.bottom <= 0 || rect.top >= window.innerHeight ||\n rect.right <= 0 || rect.left >= window.innerWidth) {\n return true;\n }\n\n // Walk up and check against each overflow container\n let parent = el.parentElement;\n while (parent && parent !== document.documentElement) {\n const style = window.getComputedStyle(parent);\n const oy = style.overflowY;\n const ox = style.overflowX;\n if (oy === 'hidden' || oy === 'scroll' || oy === 'auto' ||\n ox === 'hidden' || ox === 'scroll' || ox === 'auto') {\n const pr = parent.getBoundingClientRect();\n if (rect.bottom <= pr.top || rect.top >= pr.bottom ||\n rect.right <= pr.left || rect.left >= pr.right) {\n return true;\n }\n }\n parent = parent.parentElement;\n }\n return false;\n}\n\n// ─── Event Listeners ─────────────────────────────────────\n\nfunction setupListeners() {\n // ESC key to exit pin mode\n window.addEventListener('keydown', handleKeyDown);\n\n // Watch for DOM changes that might remove pin target elements\n mutationObserver = new MutationObserver((mutations) => {\n // Check if any pin target elements were removed\n for (const mutation of mutations) {\n for (const removed of mutation.removedNodes) {\n if (removed.nodeType !== Node.ELEMENT_NODE) continue;\n // If a removed node contained a pin element, re-render\n for (const [pinId, pinEl] of pinElements) {\n if (removed.contains(pinEl)) {\n pinElements.delete(pinId);\n renderPins();\n return;\n }\n }\n }\n }\n });\n mutationObserver.observe(document.body, { childList: true, subtree: true });\n\n // Periodic visibility check — hide pins whose targets are clipped\n visibilityCheckInterval = setInterval(checkPinVisibility, 500);\n}\n\nfunction teardownListeners() {\n window.removeEventListener('keydown', handleKeyDown);\n mutationObserver?.disconnect();\n mutationObserver = null;\n if (visibilityCheckInterval) {\n clearInterval(visibilityCheckInterval);\n visibilityCheckInterval = null;\n }\n}\n\nfunction handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n if (activePopup) {\n closePopup();\n } else if (pinMode) {\n container?.querySelectorAll('.bs-lp-form').forEach(f => f.remove());\n togglePinMode(false);\n }\n }\n}\n\n/** Periodically check if pin target elements are visible; hide pins if clipped. */\nfunction checkPinVisibility() {\n for (const [pinId, pinEl] of pinElements) {\n const pin = pins.find(p => p.id === pinId);\n if (!pin) continue;\n const target = findElement(pin.elementSelector, pin.elementXPath);\n if (target && isElementClipped(target)) {\n pinEl.style.display = 'none';\n } else {\n pinEl.style.display = '';\n }\n }\n}\n\n/** Remove all light-DOM pin elements. */\nfunction removePinElements() {\n for (const [, el] of pinElements) {\n el.remove();\n }\n pinElements = new Map();\n}\n\n// ─── Overlay ─────────────────────────────────────────────\n\nfunction createOverlay() {\n if (container) return;\n\n container = document.createElement('div');\n container.id = 'bugstash-live-pins';\n\n // Click overlay stays in light DOM (elementFromPoint requires it).\n // Use custom element + !important inline styles to resist host CSS.\n clickOverlay = document.createElement('bugstash-overlay');\n clickOverlay.style.setProperty('display', 'none', 'important');\n clickOverlay.style.setProperty('position', 'fixed', 'important');\n clickOverlay.style.setProperty('inset', '0', 'important');\n clickOverlay.style.setProperty('z-index', '2147483641', 'important');\n clickOverlay.style.setProperty('cursor', 'crosshair', 'important');\n clickOverlay.style.setProperty('background', 'rgba(0,0,0,0.05)', 'important');\n clickOverlay.style.setProperty('margin', '0', 'important');\n clickOverlay.style.setProperty('padding', '0', 'important');\n clickOverlay.style.setProperty('border', 'none', 'important');\n clickOverlay.style.setProperty('opacity', '1', 'important');\n clickOverlay.style.setProperty('visibility', 'visible', 'important');\n clickOverlay.style.setProperty('pointer-events', 'auto', 'important');\n // Prevent host CSS from breaking the overlay\n clickOverlay.style.setProperty('transform', 'none', 'important');\n clickOverlay.style.setProperty('filter', 'none', 'important');\n clickOverlay.style.setProperty('perspective', 'none', 'important');\n clickOverlay.style.setProperty('will-change', 'auto', 'important');\n clickOverlay.style.setProperty('contain', 'none', 'important');\n clickOverlay.style.setProperty('clip-path', 'none', 'important');\n clickOverlay.style.setProperty('isolation', 'auto', 'important');\n clickOverlay.style.setProperty('mix-blend-mode', 'normal', 'important');\n clickOverlay.style.setProperty('box-sizing', 'border-box', 'important');\n clickOverlay.style.setProperty('overflow', 'visible', 'important');\n clickOverlay.style.setProperty('float', 'none', 'important');\n\n const style = document.createElement('style');\n style.textContent = `\n /* ─── Container styles for form overlay (pins are in light DOM now) ─── */\n :host {\n all: initial !important;\n position: fixed !important;\n inset: 0 !important;\n pointer-events: none !important;\n z-index: 2147483640 !important;\n display: block !important;\n visibility: visible !important;\n opacity: 1 !important;\n transform: none !important;\n perspective: none !important;\n filter: none !important;\n will-change: auto !important;\n contain: none !important;\n isolation: auto !important;\n }\n *, *::before, *::after {\n box-sizing: border-box !important;\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n line-height: 1.5;\n }\n /* Color scheme support */\n @media (prefers-color-scheme: light) {\n :host { --bs-pin-bg: #ffffff; --bs-pin-text: #171717; --bs-pin-muted: #6b7280; --bs-pin-border: #eaeaea; --bs-pin-surface: #fafafa; --bs-pin-input-bg: #ffffff; --bs-pin-hover: #f5f5f5; --bs-pin-shadow: rgba(0,0,0,0.08); --bs-pin-shadow-lg: rgba(0,0,0,0.12); }\n }\n @media (prefers-color-scheme: dark) {\n :host { --bs-pin-bg: #1a1a1a; --bs-pin-text: #ededed; --bs-pin-muted: #888; --bs-pin-border: #333; --bs-pin-surface: #222; --bs-pin-input-bg: #2a2a2a; --bs-pin-hover: #2a2a2a; --bs-pin-shadow: rgba(0,0,0,0.2); --bs-pin-shadow-lg: rgba(0,0,0,0.4); }\n }\n :host {\n --bs-pin-bg: #ffffff; --bs-pin-text: #171717; --bs-pin-muted: #6b7280; --bs-pin-border: #eaeaea; --bs-pin-surface: #fafafa; --bs-pin-input-bg: #ffffff; --bs-pin-hover: #f5f5f5; --bs-pin-shadow: rgba(0,0,0,0.08); --bs-pin-shadow-lg: rgba(0,0,0,0.12);\n }\n @media (prefers-color-scheme: dark) {\n :host { --bs-pin-bg: #1a1a1a; --bs-pin-text: #ededed; --bs-pin-muted: #888; --bs-pin-border: #333; --bs-pin-surface: #222; --bs-pin-input-bg: #2a2a2a; --bs-pin-hover: #2a2a2a; --bs-pin-shadow: rgba(0,0,0,0.2); --bs-pin-shadow-lg: rgba(0,0,0,0.4); }\n }\n #bugstash-live-pins {\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n width: 0 !important;\n height: 0 !important;\n overflow: visible !important;\n z-index: 2147483640 !important;\n pointer-events: none !important;\n transform: none !important;\n perspective: none !important;\n filter: none !important;\n will-change: auto !important;\n contain: none !important;\n }\n\n ${PIN_FORM_STYLES}\n `;\n\n container.appendChild(style);\n // Container goes in shadow root (holds forms only — pins are in light DOM)\n shadow!.appendChild(container);\n // Click overlay stays in light DOM — elementFromPoint only searches light DOM\n document.body.appendChild(clickOverlay);\n\n // Click overlay to place new pin\n clickOverlay.addEventListener('click', (e) => {\n const clientX = e.clientX;\n const clientY = e.clientY;\n\n let el: Element | null = null;\n try {\n clickOverlay!.style.setProperty('pointer-events', 'none', 'important');\n el = document.elementFromPoint(clientX, clientY);\n } finally {\n clickOverlay!.style.setProperty('pointer-events', 'auto', 'important');\n }\n\n const pageX = clientX + window.scrollX;\n const pageY = clientY + window.scrollY;\n\n let xPercent: number;\n let yPercent: number;\n if (el && el !== document.body && el !== document.documentElement) {\n const rect = el.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n xPercent = (clientX - rect.left) / rect.width;\n yPercent = (clientY - rect.top) / rect.height;\n } else {\n const pageW = document.documentElement.scrollWidth || document.body.scrollWidth || 1;\n const pageH = document.documentElement.scrollHeight || document.body.scrollHeight || 1;\n xPercent = (pageX / pageW) * 100;\n yPercent = (pageY / pageH) * 100;\n }\n } else {\n const pageW = document.documentElement.scrollWidth || document.body.scrollWidth || 1;\n const pageH = document.documentElement.scrollHeight || document.body.scrollHeight || 1;\n xPercent = (pageX / pageW) * 100;\n yPercent = (pageY / pageH) * 100;\n }\n\n showNewPinForm(pageX, pageY, xPercent, yPercent, clientX, clientY, el);\n });\n}\n\n// ─── Load Data ───────────────────────────────────────────\n\nasync function loadPins() {\n const result = await fetchPagePins(projectId, window.location.pathname);\n if (result.success && result.data) {\n pins = result.data;\n registerKnownPins(pins.map(p => p.id));\n renderPins();\n }\n}\n\nasync function loadMembers() {\n const result = await fetchProjectMembers(projectId);\n if (result.success && result.data) {\n members = result.data as any[];\n }\n}\n\n// ─── Render Pins (Light DOM Injection) ───────────────────\n\n/**\n * Render pins as `<bugstash-pin>` custom elements in the light DOM.\n * Each pin is a child of its target element with `position: absolute`\n * and percentage-based coordinates. Pins scroll naturally with content.\n */\nfunction renderPins() {\n removePinElements();\n\n pins.forEach((pin) => {\n const isElementRelative = pin.xPercent >= 0 && pin.xPercent <= 1 && pin.yPercent >= 0 && pin.yPercent <= 1;\n const target = findElement(pin.elementSelector, pin.elementXPath);\n\n // Create a <bugstash-pin> custom element\n const pinEl = document.createElement('bugstash-pin');\n pinEl.dataset.pinId = pin.id;\n\n if (isElementRelative && target) {\n // Ensure target has position: relative for absolute child positioning\n const computed = window.getComputedStyle(target);\n if (computed.position === 'static') {\n (target as HTMLElement).style.position = 'relative';\n }\n // Position via CSS custom properties — :host { all: initial !important }\n // in shadow DOM beats inline !important, but custom properties survive.\n pinEl.style.setProperty('--bs-x', `${pin.xPercent * 100}%`);\n pinEl.style.setProperty('--bs-y', `${pin.yPercent * 100}%`);\n target.appendChild(pinEl);\n } else {\n // Fallback: absolute positioning on document.body with page coordinates\n pinEl.style.setProperty('--bs-x', `${pin.pageX}px`);\n pinEl.style.setProperty('--bs-y', `${pin.pageY}px`);\n document.body.appendChild(pinEl);\n }\n\n // Create shadow DOM for style isolation within each pin\n const pinShadow = pinEl.attachShadow({ mode: 'open' });\n const pinStyle = document.createElement('style');\n pinStyle.textContent = PIN_MARKER_STYLES + PIN_POPUP_STYLES;\n pinShadow.appendChild(pinStyle);\n\n // Render pin marker content\n const statusColor = STATUS_COLORS[pin.status] || STATUS_COLORS.open;\n const initials = getInitials(pin.creatorName || 'U');\n const gradientBg = getAvatarGradient(pin.creatorName || 'U');\n\n const avatarContent = isSafeImageUrl(pin.creatorAvatar)\n ? `<img class=\"bs-lp-avatar\" src=\"${escapeHtml(pin.creatorAvatar!)}\" alt=\"\" />`\n : `<div class=\"bs-lp-initials\" style=\"background:${gradientBg}\">${initials}</div>`;\n\n const badgeHtml = pin.commentCount > 0\n ? `<span class=\"bs-lp-badge\">${pin.commentCount > 99 ? '99+' : pin.commentCount}</span>`\n : '';\n\n const isOverdue = pin.dueDate && pin.dueDate < Date.now() &&\n pin.status !== 'resolved' && pin.status !== 'closed';\n\n const marker = document.createElement('div');\n marker.className = 'bs-lp-marker';\n marker.innerHTML = `\n <div class=\"bs-lp-dot${isOverdue ? ' bs-overdue' : ''}\" style=\"border:2px solid ${statusColor}; background:transparent;\">\n ${avatarContent}\n ${badgeHtml}\n </div>\n `;\n pinShadow.appendChild(marker);\n\n marker.addEventListener('click', (e) => {\n e.stopPropagation();\n showPinPopup(pin, pinEl);\n });\n\n pinElements.set(pin.id, pinEl);\n });\n}\n\n// ─── Pin Popup ───────────────────────────────────────────\n\nfunction timeAgo(ts: number | string): string {\n const time = typeof ts === 'string' ? new Date(ts).getTime() : ts;\n if (isNaN(time)) return '';\n const diff = Date.now() - time;\n const mins = Math.floor(diff / 60000);\n if (mins < 1) return 'just now';\n if (mins < 60) return `${mins}m ago`;\n const hrs = Math.floor(mins / 60);\n if (hrs < 24) return `${hrs}h ago`;\n return `${Math.floor(hrs / 24)}d ago`;\n}\n\n/**\n * Clamp popup or form inside the visible viewport.\n *\n * Popups use `position: absolute` relative to their parent (.bs-lp marker).\n * We read the element's viewport rect, compute the delta needed to keep it\n * on-screen, then adjust the current CSS left/top by that delta. This keeps\n * all math in the parent's local coordinate system, avoiding issues with\n * ancestor transforms shifting the containing block.\n */\nfunction clampToViewport(el: HTMLElement) {\n requestAnimationFrame(() => {\n const rect = el.getBoundingClientRect();\n const pad = 16;\n\n // Compute how far the element overflows each edge of the viewport.\n // Positive = needs to shift inward by that many px.\n let dx = 0;\n let dy = 0;\n\n if (rect.right > window.innerWidth - pad) {\n dx = (window.innerWidth - pad) - rect.right; // shift left\n }\n if (rect.left + dx < pad) {\n dx = pad - rect.left; // shift right\n }\n if (rect.bottom > window.innerHeight - pad) {\n dy = (window.innerHeight - pad) - rect.bottom; // shift up\n }\n if (rect.top + dy < pad) {\n dy = pad - rect.top; // shift down\n }\n\n // Apply delta to current style values (stays in parent's coord system)\n if (dx !== 0 || dy !== 0) {\n const curLeft = parseFloat(el.style.left) || 0;\n const curTop = parseFloat(el.style.top) || 0;\n el.style.left = `${curLeft + dx}px`;\n el.style.top = `${curTop + dy}px`;\n el.style.right = 'auto';\n el.style.bottom = 'auto';\n }\n });\n}\n\nasync function showPinPopup(pin: LivePin, pinHost: HTMLElement) {\n closePopup();\n\n const popup = document.createElement('div');\n popup.className = 'bs-lp-popup';\n\n const user = getCurrentUser();\n const pinCreator = pin.createdBy || (pin as any).createdById;\n const canManage = user && (user.role === 'owner' || user.role === 'admin' || user.id === pinCreator);\n const statusColor = STATUS_COLORS[pin.status] || STATUS_COLORS.open;\n const prioColor = PRIORITY_COLORS[pin.priority] || PRIORITY_COLORS.medium;\n const prioLabel = pin.priority ? pin.priority.charAt(0).toUpperCase() + pin.priority.slice(1) : 'Medium';\n\n const creatorInitials = getInitials(pin.creatorName || 'U');\n const creatorGradient = getAvatarGradient(pin.creatorName || 'U');\n const creatorAvatarHtml = isSafeImageUrl(pin.creatorAvatar)\n ? `<img src=\"${escapeHtml(pin.creatorAvatar!)}\" alt=\"\" style=\"width:100%;height:100%;object-fit:cover;border-radius:50%;\" />`\n : `<span>${creatorInitials}</span>`;\n const statusLabel = pin.status.replace('_', ' ');\n const sendIconSvg = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/><polygon points=\"22 2 15 22 11 13 2 9 22 2\"/></svg>`;\n const closeIconSvg = `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`;\n\n const isOverdue = pin.dueDate && pin.dueDate < Date.now() &&\n pin.status !== 'resolved' && pin.status !== 'closed';\n const dueDateHtml = pin.dueDate\n ? `<div class=\"bs-lp-popup-due${isOverdue ? ' overdue' : ''}\">${isOverdue ? 'OVERDUE: ' : 'Due: '}${new Date(pin.dueDate).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}</div>`\n : '';\n\n popup.innerHTML = `\n <div class=\"bs-lp-popup-hdr\">\n <div class=\"bs-lp-popup-hdr-avatar\" style=\"background:${creatorGradient}\">\n ${creatorAvatarHtml}\n </div>\n <div class=\"bs-lp-popup-hdr-body\">\n <div class=\"bs-lp-popup-title\">${escapeHtml(pin.title)}</div>\n <div class=\"bs-lp-popup-meta\">\n <span>${pin.creatorName || 'Unknown'}</span>\n <span>&middot;</span>\n <span>${timeAgo(pin.createdAt)}</span>\n <span class=\"bs-lp-popup-pill\" style=\"background:${statusColor}18;color:${statusColor}\">${statusLabel}</span>\n <span class=\"bs-lp-popup-pill\" style=\"background:${prioColor}18;color:${prioColor}\">${prioLabel}</span>\n </div>\n </div>\n <button class=\"bs-lp-popup-close\">${closeIconSvg}</button>\n </div>\n ${pin.description ? `<div class=\"bs-lp-popup-desc\">${escapeHtml(pin.description)}</div>` : ''}\n ${dueDateHtml}\n ${pin.assigneeName ? `<div class=\"bs-lp-popup-info\"><span>Assigned to ${escapeHtml(pin.assigneeName)}</span></div>` : ''}\n <div class=\"bs-lp-cmts\" id=\"bs-lp-cmts\">\n <div style=\"text-align:center;color:var(--bs-pin-muted);padding:12px;font-size:12px\">Loading comments...</div>\n </div>\n <div class=\"bs-lp-input\">\n <input type=\"text\" placeholder=\"Write a comment...\" id=\"bs-lp-cmt-in\" name=\"pin-comment\" />\n <button id=\"bs-lp-cmt-send\">${sendIconSvg}</button>\n </div>\n <div class=\"bs-lp-acts\">\n ${pin.status !== 'resolved'\n ? `<button class=\"bs-lp-act resolve\" id=\"bs-lp-resolve\">&#10003; Resolve</button>`\n : `<button class=\"bs-lp-act\" id=\"bs-lp-reopen\">&#8634; Reopen</button>`\n }\n ${canManage ? `<button class=\"bs-lp-act delete\" id=\"bs-lp-delete\">&#10005; Delete</button>` : ''}\n </div>\n `;\n\n pinHost.shadowRoot!.appendChild(popup);\n activePopup = popup;\n\n // Load comments in background\n fetchComments(pin.id).then(commentsRes => {\n const cmtsEl = popup.querySelector('#bs-lp-cmts');\n if (!cmtsEl) return;\n const comments = commentsRes.success && commentsRes.data ? commentsRes.data : [];\n cmtsEl.innerHTML = comments.length\n ? comments.map((c: any) => renderCommentHtml(c)).join('')\n : '';\n // Re-clamp after comments load (popup height may have changed)\n clampToViewport(popup);\n });\n\n clampToViewport(popup);\n\n // Bind events\n popup.querySelector('.bs-lp-popup-close')!.addEventListener('click', (e) => {\n e.stopPropagation();\n closePopup();\n });\n\n popup.querySelector('#bs-lp-cmt-send')?.addEventListener('click', async () => {\n const input = popup.querySelector('#bs-lp-cmt-in') as HTMLInputElement;\n const body = input.value.trim();\n if (!body) return;\n input.value = '';\n\n if (navigator.onLine) {\n const res = await createComment(pin.id, body);\n if (res.success && res.data) {\n const cmtsEl = popup.querySelector('#bs-lp-cmts')!;\n cmtsEl.innerHTML += renderCommentHtml(res.data);\n cmtsEl.scrollTop = cmtsEl.scrollHeight;\n }\n } else {\n queueOfflineAction({ type: 'create_comment', data: { pinId: pin.id, body } });\n }\n });\n\n (popup.querySelector('#bs-lp-cmt-in') as HTMLInputElement)?.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') popup.querySelector('#bs-lp-cmt-send')?.dispatchEvent(new Event('click'));\n });\n\n popup.querySelector('#bs-lp-resolve')?.addEventListener('click', async () => {\n await updatePin(pin.id, { status: 'resolved' as any });\n const idx = pins.findIndex(p => p.id === pin.id);\n if (idx >= 0) pins = pins.map((p, i) => i === idx ? { ...p, status: 'resolved' as const } : p);\n closePopup();\n renderPins();\n });\n\n popup.querySelector('#bs-lp-reopen')?.addEventListener('click', async () => {\n await updatePin(pin.id, { status: 'open' as any });\n const idx = pins.findIndex(p => p.id === pin.id);\n if (idx >= 0) pins = pins.map((p, i) => i === idx ? { ...p, status: 'open' as const } : p);\n closePopup();\n renderPins();\n });\n\n let deleting = false;\n popup.querySelector('#bs-lp-delete')?.addEventListener('click', async () => {\n if (deleting) return;\n if (!confirm('Delete this pin?')) return;\n deleting = true;\n await deletePin(pin.id);\n pins = pins.filter((p) => p.id !== pin.id);\n closePopup();\n renderPins();\n });\n\n popup.addEventListener('click', (e) => e.stopPropagation());\n}\n\nfunction closePopup() {\n activePopup?.remove();\n activePopup = null;\n}\n\n// ─── New Pin Form ────────────────────────────────────────\n\n/** CSS.escape with fallback for older browsers. */\nconst cssEscape = (str: string): string => {\n if (!str) return '';\n if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') return CSS.escape(str);\n // Basic fallback: escape special CSS selector characters\n return str.replace(/([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^`{|}~])/g, '\\\\$1');\n};\n\nfunction getSelector(el: Element | null): string {\n if (!el || el === document.body || el === document.documentElement) return 'body';\n\n // Prefer data-testid / data-test-id / data-cy (standard in tested SPAs)\n for (const attr of ['data-testid', 'data-test-id', 'data-cy']) {\n const val = el.getAttribute(attr);\n if (val) return `[${attr}=\"${cssEscape(val)}\"]`;\n }\n\n // Prefer unique ID (escaped for safety)\n if (el.id) {\n try {\n const escaped = `#${cssEscape(el.id)}`;\n if (document.querySelectorAll(escaped).length === 1) return escaped;\n } catch { /* invalid id for CSS.escape */ }\n }\n\n // Prefer unique aria-label\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) {\n const candidate = `${el.tagName.toLowerCase()}[aria-label=\"${cssEscape(ariaLabel)}\"]`;\n try {\n if (document.querySelectorAll(candidate).length === 1) return candidate;\n } catch { /* ignore */ }\n }\n\n // Build a tag + class selector\n let selector = el.tagName.toLowerCase();\n if (el.className && typeof el.className === 'string') {\n const classes = el.className.trim().split(/\\s+/)\n .filter(c => !c.startsWith('bs-') && !c.startsWith('ng-') && !c.startsWith('_'))\n .slice(0, 3);\n if (classes.length) selector += '.' + classes.map(c => cssEscape(c)).join('.');\n }\n\n // Disambiguate with :nth-of-type instead of :nth-child (resilient to sibling type changes)\n const parent = el.parentElement;\n if (parent && parent !== document.body) {\n const sameTypeSiblings = Array.from(parent.children).filter(c => c.tagName === el.tagName);\n if (sameTypeSiblings.length > 1) {\n const idx = sameTypeSiblings.indexOf(el);\n selector += `:nth-of-type(${idx + 1})`;\n }\n return getSelector(parent) + ' > ' + selector;\n }\n return selector;\n}\n\n/** Build a ranked array of selectors for resilient element re-finding. */\nfunction getSelectorChain(el: Element | null): string[] {\n if (!el || el === document.body || el === document.documentElement) return ['body'];\n const selectors: string[] = [];\n\n // 1. Test attributes (most stable — survive refactors)\n for (const attr of ['data-testid', 'data-test-id', 'data-cy']) {\n const val = el.getAttribute(attr);\n if (val) { selectors.push(`[${attr}=\"${cssEscape(val)}\"]`); break; }\n }\n\n // 2. Unique ID\n if (el.id) {\n try {\n const escaped = `#${cssEscape(el.id)}`;\n if (document.querySelectorAll(escaped).length === 1) selectors.push(escaped);\n } catch { /* invalid id */ }\n }\n\n // 3. Unique aria-label\n const aria = el.getAttribute('aria-label');\n if (aria) {\n const candidate = `${el.tagName.toLowerCase()}[aria-label=\"${cssEscape(aria)}\"]`;\n try {\n if (document.querySelectorAll(candidate).length === 1) selectors.push(candidate);\n } catch { /* ignore */ }\n }\n\n // 4. Structural path (tag-only, no classes — survives CSS module hashes & Tailwind rebuilds)\n selectors.push(getStructuralPath(el));\n\n return selectors;\n}\n\n/** Tag-only structural path with :nth-of-type — zero classes, maximum resilience. */\nfunction getStructuralPath(el: Element): string {\n const parts: string[] = [];\n let current: Element | null = el;\n while (current && current !== document.body && current !== document.documentElement) {\n const node: Element = current;\n const parent = node.parentElement;\n if (!parent) break;\n let tag = node.tagName.toLowerCase();\n const siblings = Array.from(parent.children).filter((c: Element) => c.tagName === node.tagName);\n if (siblings.length > 1) tag += `:nth-of-type(${siblings.indexOf(node) + 1})`;\n parts.unshift(tag);\n current = parent;\n }\n return parts.join(' > ');\n}\n\nfunction getXPath(el: Element | null): string {\n if (!el) return '';\n const parts: string[] = [];\n let current: Element | null = el;\n while (current && current !== document.body) {\n let idx = 1;\n let sib = current.previousElementSibling;\n while (sib) {\n if (sib.tagName === current.tagName) idx++;\n sib = sib.previousElementSibling;\n }\n parts.unshift(`${current.tagName.toLowerCase()}[${idx}]`);\n current = current.parentElement;\n }\n return '/body/' + parts.join('/');\n}\n\nfunction showNewPinForm(pageX: number, pageY: number, xPct: number, yPct: number, clientX: number, clientY: number, targetEl: Element | null) {\n closePopup();\n container?.querySelectorAll('.bs-lp-form').forEach(e => e.remove());\n\n const form = document.createElement('div');\n form.className = 'bs-lp-form';\n\n // Position form near click point, clamped to viewport\n const formW = Math.min(300, window.innerWidth - 32);\n const pad = 16;\n let left = clientX + pad;\n let top = clientY - 8;\n if (left + formW > window.innerWidth - pad) {\n left = clientX - formW - pad;\n }\n if (left < pad) left = pad;\n form.style.left = `${left}px`;\n form.style.top = `${top}px`;\n\n // Adjust vertical position after rendering\n requestAnimationFrame(() => {\n const rect = form.getBoundingClientRect();\n if (rect.bottom > window.innerHeight - pad) {\n form.style.top = `${Math.max(pad, clientY - rect.height)}px`;\n }\n });\n\n const memberOptions = members\n .filter(m => (m as any).userId !== getCurrentUser()?.id)\n .map(m => `<option value=\"${(m as any).userId}\">${escapeHtml((m as any).name)}</option>`)\n .join('');\n\n form.innerHTML = `\n <label class=\"bs-lp-form-label\">Title</label>\n <input type=\"text\" id=\"bs-np-title\" name=\"pin-title\" placeholder=\"What's the issue?\" autofocus />\n <label class=\"bs-lp-form-label\">Description</label>\n <textarea id=\"bs-np-desc\" name=\"pin-desc\" placeholder=\"Add more details...\"></textarea>\n <label class=\"bs-lp-form-label\">Priority</label>\n <div class=\"bs-lp-seg-row\" id=\"bs-np-priority-row\">\n <button class=\"bs-lp-seg-btn\" data-value=\"low\">Low</button>\n <button class=\"bs-lp-seg-btn bs-active\" data-value=\"medium\">Medium</button>\n <button class=\"bs-lp-seg-btn\" data-value=\"high\">High</button>\n <button class=\"bs-lp-seg-btn\" data-value=\"critical\">Critical</button>\n </div>\n <label class=\"bs-lp-form-label\">Category</label>\n <div class=\"bs-lp-seg-row\" id=\"bs-np-category-row\">\n <button class=\"bs-lp-seg-btn\" data-value=\"ui\">UI</button>\n <button class=\"bs-lp-seg-btn\" data-value=\"functionality\">Func</button>\n <button class=\"bs-lp-seg-btn\" data-value=\"performance\">Perf</button>\n <button class=\"bs-lp-seg-btn\" data-value=\"content\">Content</button>\n <button class=\"bs-lp-seg-btn bs-active\" data-value=\"other\">Other</button>\n </div>\n ${memberOptions ? `\n <label class=\"bs-lp-form-label\">Assign to</label>\n <select id=\"bs-np-assignee\" name=\"pin-assignee\">\n <option value=\"\">Unassigned</option>\n ${memberOptions}\n </select>\n ` : ''}\n <label class=\"bs-lp-form-label\">Due date</label>\n <input type=\"date\" id=\"bs-np-duedate\" name=\"pin-duedate\" />\n <div class=\"bs-lp-form-btns\">\n <button class=\"bs-lp-form-cancel\" id=\"bs-np-cancel\">Cancel</button>\n <button class=\"bs-lp-form-submit\" id=\"bs-np-submit\">Create pin</button>\n </div>\n `;\n\n container!.appendChild(form);\n\n form.addEventListener('click', (e) => e.stopPropagation());\n\n // Segmented button handlers\n setupSegmentedRow(form, '#bs-np-priority-row');\n setupSegmentedRow(form, '#bs-np-category-row');\n\n form.querySelector('#bs-np-cancel')!.addEventListener('click', () => form.remove());\n\n form.querySelector('#bs-np-submit')!.addEventListener('click', async () => {\n const title = (form.querySelector('#bs-np-title') as HTMLInputElement).value.trim();\n if (!title) {\n (form.querySelector('#bs-np-title') as HTMLInputElement).style.borderColor = '#ef4444';\n return;\n }\n\n const submitBtn = form.querySelector('#bs-np-submit') as HTMLButtonElement;\n submitBtn.textContent = 'Creating...';\n submitBtn.style.opacity = '0.6';\n submitBtn.style.pointerEvents = 'none';\n\n const desc = (form.querySelector('#bs-np-desc') as HTMLTextAreaElement).value.trim();\n const priority = getSegmentedValue(form, '#bs-np-priority-row') || 'medium';\n const category = getSegmentedValue(form, '#bs-np-category-row') || 'other';\n const assigneeEl = form.querySelector('#bs-np-assignee') as HTMLSelectElement;\n const assigneeId = assigneeEl?.value || undefined;\n const dueDateInput = (form.querySelector('#bs-np-duedate') as HTMLInputElement)?.value;\n const dueDate = dueDateInput ? new Date(dueDateInput).getTime() : undefined;\n\n const selector = JSON.stringify(getSelectorChain(targetEl));\n const xpath = getXPath(targetEl);\n\n const logs = getLogs().slice(-20).map(l => `[${l.level}] ${l.args.join(' ')}`);\n const errors = getErrors().slice(-10).map(e => `${e.message} at ${e.source}:${e.lineno}`);\n const netErrors = getFailedNetworkCaptures().slice(-10).map(n => `${n.method} ${n.url} → ${n.status}`);\n\n const pinData = {\n projectId,\n pageUrl: window.location.href,\n pathname: window.location.pathname,\n elementSelector: selector,\n elementXPath: xpath,\n xPercent: xPct,\n yPercent: yPct,\n pageX,\n pageY,\n title,\n description: desc,\n priority: priority as 'low' | 'medium' | 'high' | 'critical',\n category: category as 'ui' | 'functionality' | 'performance' | 'content' | 'other',\n assigneeId,\n dueDate,\n browserInfo: navigator.userAgent,\n screenSize: `${screen.width}x${screen.height}`,\n viewportSize: `${window.innerWidth}x${window.innerHeight}`,\n devicePixelRatio: window.devicePixelRatio,\n consoleLogs: logs,\n networkErrors: netErrors,\n jsErrors: errors,\n };\n\n form.remove();\n\n if (navigator.onLine) {\n const res = await createPin(pinData);\n if (res.success && res.data) {\n pins = [...pins, res.data];\n renderPins();\n }\n } else {\n queueOfflineAction({ type: 'create_pin', data: pinData });\n const currentUser = getCurrentUser();\n pins = [...pins, {\n ...pinData,\n id: 'local-' + Date.now(),\n orgId: '',\n status: 'open',\n tags: [],\n createdBy: currentUser?.id || '',\n creatorName: currentUser?.name || '',\n commentCount: 0,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n } as any];\n renderPins();\n }\n });\n\n setTimeout(() => (form.querySelector('#bs-np-title') as HTMLInputElement)?.focus(), 50);\n}\n\n// ─── Real-time Updates ───────────────────────────────────\n\nfunction setupRealtimeListeners() {\n onRealtimeEvent('pin:created', (event) => {\n const pin = event.data as LivePin;\n if (pin.pathname === window.location.pathname) {\n if (!pins.find(p => p.id === pin.id)) {\n pins = [...pins, pin];\n registerKnownPins(pins.map(p => p.id));\n renderPins();\n }\n }\n });\n\n onRealtimeEvent('pin:updated', (event) => {\n const updated = event.data as LivePin;\n const idx = pins.findIndex(p => p.id === updated.id);\n if (idx >= 0) {\n pins = pins.map((p, i) => i === idx ? { ...p, ...updated } : p);\n renderPins();\n }\n });\n\n onRealtimeEvent('pin:deleted', (event) => {\n const { id } = event.data;\n pins = pins.filter(p => p.id !== id);\n closePopup();\n renderPins();\n });\n\n onRealtimeEvent('comment:created', (event) => {\n const comment = event.data;\n if (activePopup) {\n const cmtsEl = activePopup.querySelector('#bs-lp-cmts');\n if (cmtsEl) {\n cmtsEl.innerHTML += renderCommentHtml(comment);\n cmtsEl.scrollTop = cmtsEl.scrollHeight;\n }\n }\n });\n}\n\n// ─── Navigation Watch ────────────────────────────────────\n\nfunction watchNavigation() {\n let lastPath = window.location.pathname;\n\n const check = () => {\n if (window.location.pathname !== lastPath) {\n lastPath = window.location.pathname;\n sendPageNavigate(window.location.href);\n loadPins();\n }\n };\n\n const origPush = history.pushState;\n const origReplace = history.replaceState;\n\n history.pushState = function (...args) {\n origPush.apply(this, args);\n check();\n };\n\n history.replaceState = function (...args) {\n origReplace.apply(this, args);\n check();\n };\n\n window.addEventListener('popstate', check);\n}\n\n// ─── Util ────────────────────────────────────────────────\n\nfunction getInitials(name: string): string {\n return name.split(' ').map(w => w[0] || '').join('').toUpperCase().slice(0, 2) || 'U';\n}\n\n/** Validate that a URL is a safe HTTPS image URL (prevents SSRF/javascript: injection). */\nfunction isSafeImageUrl(url: string | undefined): boolean {\n if (!url) return false;\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'https:' || parsed.protocol === 'http:';\n } catch {\n return false;\n }\n}\n\nconst AVATAR_GRADIENTS = [\n 'linear-gradient(135deg, #667eea, #764ba2)',\n 'linear-gradient(135deg, #f093fb, #f5576c)',\n 'linear-gradient(135deg, #4facfe, #00f2fe)',\n 'linear-gradient(135deg, #43e97b, #38f9d7)',\n 'linear-gradient(135deg, #fa709a, #fee140)',\n 'linear-gradient(135deg, #a18cd1, #fbc2eb)',\n 'linear-gradient(135deg, #fccb90, #d57eeb)',\n 'linear-gradient(135deg, #e0c3fc, #8ec5fc)',\n];\n\nfunction getAvatarGradient(name: string): string {\n let hash = 0;\n for (let i = 0; i < name.length; i++) hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;\n return AVATAR_GRADIENTS[Math.abs(hash) % AVATAR_GRADIENTS.length];\n}\n\nfunction renderCommentHtml(c: any): string {\n const name = c.author?.name || c.authorName || 'Unknown';\n const avatar = c.author?.avatar || c.authorAvatar;\n const commentInitials = getInitials(name);\n const commentGradient = getAvatarGradient(name);\n const avatarInner = isSafeImageUrl(avatar)\n ? `<img src=\"${escapeHtml(avatar)}\" alt=\"\" />`\n : `<span style=\"font-size:8px\">${commentInitials}</span>`;\n return `\n <div class=\"bs-lp-cmt\">\n <div class=\"bs-lp-cmt-avatar\" style=\"background:${commentGradient}\">\n ${avatarInner}\n </div>\n <div class=\"bs-lp-cmt-content\">\n <div class=\"bs-lp-cmt-top\">\n <span class=\"bs-lp-cmt-author\">${escapeHtml(name)}</span>\n <span class=\"bs-lp-cmt-time\">${timeAgo(c.createdAt ? new Date(c.createdAt).getTime() : Date.now())}</span>\n </div>\n <div class=\"bs-lp-cmt-body\">${escapeHtml(c.body)}</div>\n </div>\n </div>\n `;\n}\n\nfunction setupSegmentedRow(form: HTMLElement, selector: string): void {\n const row = form.querySelector(selector);\n if (!row) return;\n row.querySelectorAll('.bs-lp-seg-btn').forEach(btn => {\n btn.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n row.querySelectorAll('.bs-lp-seg-btn').forEach(b => b.classList.remove('bs-active'));\n (btn as HTMLElement).classList.add('bs-active');\n });\n });\n}\n\nfunction getSegmentedValue(form: HTMLElement, selector: string): string {\n const active = form.querySelector(`${selector} .bs-lp-seg-btn.bs-active`) as HTMLElement | null;\n return active?.dataset.value || '';\n}\n\nfunction escapeHtml(str: string): string {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n}\n","import type { BugStashConfig, BugReport, ReportContext } from '@bugstash/shared';\nimport { getLogs } from './logger';\nimport { getNetworkCaptures, getFailedNetworkCaptures } from './network';\nimport { getErrors } from './errors';\nimport { getBreadcrumbs } from './breadcrumbs';\nimport { getPerformanceMetrics } from './performance';\nimport { captureScreenshot } from './screenshot';\nimport { submitReport, login as apiLogin, getCurrentUser, logout as apiLogout } from './api';\nimport { getDefaultTheme, getThemeById, getThemes, type BsTheme } from './themes';\nimport { getDefaultLayout, getLayoutById, getLayouts, LAYOUT_CSS, type BsLayout } from './layouts';\nimport { initLivePins, togglePinMode, isPinModeActive } from './livepins';\nimport { connectRealtime } from './realtime';\n\nlet config: BugStashConfig;\nlet fab: HTMLButtonElement | null = null;\nlet toolbar: HTMLDivElement | null = null;\nlet modal: HTMLDivElement | null = null;\nlet backdrop: HTMLDivElement | null = null;\nlet keyHandler: ((e: KeyboardEvent) => void) | null = null;\nlet shadow: ShadowRoot | null = null;\nlet iframeEl: HTMLIFrameElement | null = null;\nlet iframeDoc: Document | null = null;\nlet isOpen = false;\nlet toolbarVisible = false;\nlet isDragging = false;\nlet resizeHandler: (() => void) | null = null;\nlet dragCleanup: (() => void) | null = null;\n\nconst FAB_STORAGE_KEY = 'bugstash_fab_position';\nlet shadowStyleEl: HTMLStyleElement | null = null;\nlet shadowFontLink: HTMLLinkElement | null = null;\nlet activeTab: 'report' | 'console' | 'network' | 'context' | 'history' | 'settings' = 'report';\nlet editingReportId: number | null = null;\nlet currentTheme: BsTheme = getDefaultTheme();\nlet currentLayout: BsLayout = getDefaultLayout();\n\n// ─── Icons ───────────────────────────────────────────────\n\nconst I = {\n bug: `<svg width=\"28\" height=\"28\" viewBox=\"55 38 60 105\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M95.8 44h-29c-3 0-5.4 2.4-5.4 5.4v29c0 3 2.4 5.4 5.4 5.4h19.5c13 0 23.5-10.5 23.5-23.5v-2.8c0-7.5-6-13.5-13.5-13.5h-.5zm-6.2 28.2H74.8V57.4h14.8c5.8 0 10.4 4.7 10.4 10.4s-4.7 10.4-10.4 10.4z\" fill=\"rgba(255,255,255,0.85)\"/><path d=\"M100.4 96h-33.6c-3 0-5.4 2.4-5.4 5.4v33.6c0 3 2.4 5.4 5.4 5.4h22c15 0 27-12 27-27v-3.9c0-7.5-6-13.5-13.5-13.5h-1.9zm-7.8 32.2H74.8v-20h17.8c6.7 0 12.2 5.5 12.2 12.2 0 4.3-3.5 7.8-7.8 7.8h-4.6z\" fill=\"rgba(255,255,255,1)\"/></svg>`,\n x: `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>`,\n cam: `<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z\"/><circle cx=\"12\" cy=\"13\" r=\"4\"/></svg>`,\n check: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>`,\n report: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/></svg>`,\n console: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"4 17 10 11 4 5\"/><line x1=\"12\" y1=\"19\" x2=\"20\" y2=\"19\"/></svg>`,\n network: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\"/><path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\"/></svg>`,\n ctx: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"3\"/><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z\"/></svg>`,\n settings: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"4\" y1=\"21\" x2=\"4\" y2=\"14\"/><line x1=\"4\" y1=\"10\" x2=\"4\" y2=\"3\"/><line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"3\"/><line x1=\"20\" y1=\"21\" x2=\"20\" y2=\"16\"/><line x1=\"20\" y1=\"12\" x2=\"20\" y2=\"3\"/><line x1=\"1\" y1=\"14\" x2=\"7\" y2=\"14\"/><line x1=\"9\" y1=\"8\" x2=\"15\" y2=\"8\"/><line x1=\"17\" y1=\"16\" x2=\"23\" y2=\"16\"/></svg>`,\n history: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><polyline points=\"12 6 12 12 16 14\"/></svg>`,\n pin: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>`,\n sun: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><circle cx=\"12\" cy=\"12\" r=\"5\"/><line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"3\"/><line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"23\"/><line x1=\"4.22\" y1=\"4.22\" x2=\"5.64\" y2=\"5.64\"/><line x1=\"18.36\" y1=\"18.36\" x2=\"19.78\" y2=\"19.78\"/><line x1=\"1\" y1=\"12\" x2=\"3\" y2=\"12\"/><line x1=\"21\" y1=\"12\" x2=\"23\" y2=\"12\"/><line x1=\"4.22\" y1=\"19.78\" x2=\"5.64\" y2=\"18.36\"/><line x1=\"18.36\" y1=\"5.64\" x2=\"19.78\" y2=\"4.22\"/></svg>`,\n moon: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z\"/></svg>`,\n keyboard: `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\"/><line x1=\"6\" y1=\"8\" x2=\"6\" y2=\"8\"/><line x1=\"10\" y1=\"8\" x2=\"10\" y2=\"8\"/><line x1=\"14\" y1=\"8\" x2=\"14\" y2=\"8\"/><line x1=\"18\" y1=\"8\" x2=\"18\" y2=\"8\"/><line x1=\"8\" y1=\"12\" x2=\"16\" y2=\"12\"/><line x1=\"6\" y1=\"16\" x2=\"18\" y2=\"16\"/></svg>`,\n};\n\n// ─── Styles (CSS custom properties) ──────────────────────\n\nconst STYLES = `\n /* ── Shadow Boundary Reset ──\n * Cuts ALL inherited CSS from host page (color, font, line-height, etc.)\n * Every element below must declare its own styles explicitly. */\n :host {\n all: initial !important;\n display: block !important;\n position: fixed !important;\n inset: 0 !important;\n pointer-events: none !important;\n z-index: 2147483640 !important;\n visibility: visible !important;\n }\n\n /* ── FAB ── */\n .bs-fab {\n all: initial;\n pointer-events: auto;\n position: fixed;\n bottom: 24px;\n z-index: 2147483647;\n width: 56px;\n height: 56px;\n border-radius: var(--bs-radius);\n background: linear-gradient(135deg, var(--bs-fab1), var(--bs-fab2));\n color: #fff;\n cursor: grab;\n box-shadow: 0 4px 24px rgba(0,0,0,0.3), 0 0 0 0 rgba(0,0,0,0.15);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.35s cubic-bezier(0.34,1.56,0.64,1);\n animation: bs-pulse 3s ease-in-out infinite;\n touch-action: none;\n user-select: none;\n -webkit-user-select: none;\n }\n .bs-fab.bs-dragging {\n cursor: grabbing;\n transition: none;\n animation: none;\n }\n .bs-fab:hover {\n transform: scale(1.08) translateY(-2px);\n box-shadow: 0 8px 32px rgba(0,0,0,0.4);\n animation: none;\n }\n .bs-fab:active { transform: scale(0.95); }\n .bs-fab.bs-open {\n animation: none;\n transform: rotate(45deg) scale(0.9);\n box-shadow: 0 2px 12px rgba(0,0,0,0.3);\n }\n .bs-fab.bs-open:hover { transform: rotate(45deg) scale(1); }\n @keyframes bs-pulse {\n 0%, 100% { box-shadow: 0 4px 24px rgba(0,0,0,0.3), 0 0 0 0 rgba(0,0,0,0.15); }\n 50% { box-shadow: 0 4px 24px rgba(0,0,0,0.3), 0 0 0 10px rgba(0,0,0,0); }\n }\n .bs-fab-label {\n position: absolute;\n right: calc(100% + 12px);\n background: var(--bs-bg2);\n color: var(--bs-text);\n font-family: 'Inter', sans-serif;\n font-size: 13px;\n font-weight: 500;\n padding: 8px 14px;\n border-radius: var(--bs-radius-sm);\n white-space: nowrap;\n box-shadow: 0 4px 20px rgba(0,0,0,0.3);\n opacity: 0;\n transform: translateX(8px);\n transition: all 0.25s ease;\n pointer-events: none;\n }\n .bs-fab:hover .bs-fab-label { opacity: 1; transform: translateX(0); }\n .bs-fab-label::after {\n content: '';\n position: absolute;\n right: -6px;\n top: 50%;\n transform: translateY(-50%);\n border: 6px solid transparent;\n border-left-color: var(--bs-bg2);\n border-right: none;\n }\n\n /* ── Quick Action Toolbar ── */\n .bs-toolbar {\n pointer-events: auto;\n position: fixed;\n z-index: 2147483646;\n display: flex;\n flex-direction: column;\n gap: 6px;\n bottom: 88px;\n opacity: 0;\n transform: translateY(10px);\n transition: all 0.3s cubic-bezier(0.34,1.56,0.64,1);\n pointer-events: none;\n }\n .bs-toolbar.bs-show {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n }\n .bs-toolbar-btn {\n all: initial;\n width: 40px;\n height: 40px;\n border-radius: var(--bs-radius-sm);\n background: var(--bs-bg2);\n border: 1px solid var(--bs-border);\n color: var(--bs-muted);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n position: relative;\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n }\n .bs-toolbar-btn:hover { color: var(--bs-text); border-color: var(--bs-accent); background: var(--bs-bg3); }\n .bs-toolbar-btn.bs-active { color: var(--bs-accent); border-color: var(--bs-accent); }\n .bs-toolbar-tip {\n position: absolute;\n right: calc(100% + 8px);\n background: var(--bs-bg2);\n color: var(--bs-text);\n font-family: 'Inter', sans-serif;\n font-size: 11px;\n font-weight: 500;\n padding: 4px 8px;\n border-radius: 6px;\n white-space: nowrap;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n }\n .bs-toolbar-btn:hover .bs-toolbar-tip { opacity: 1; }\n .bs-toolbar-kbd {\n font-size: 9px;\n color: var(--bs-muted);\n margin-left: 4px;\n }\n\n /* ── Backdrop ── */\n .bs-backdrop {\n pointer-events: auto;\n position: fixed;\n inset: 0;\n z-index: 2147483644;\n background: rgba(0,0,0,0);\n backdrop-filter: blur(0px);\n transition: all 0.4s ease;\n pointer-events: none;\n }\n .bs-backdrop.bs-in {\n background: rgba(10,12,20,0.55);\n backdrop-filter: blur(6px);\n pointer-events: all;\n }\n\n /* ── Modal ── */\n .bs-modal {\n pointer-events: auto;\n position: fixed;\n z-index: 2147483645;\n top: 50%;\n left: 50%;\n width: 620px;\n height: 680px;\n max-width: calc(100vw - 32px);\n max-height: calc(100vh - 48px);\n background: var(--bs-bg);\n border: 1px solid var(--bs-border);\n border-radius: var(--bs-radius);\n box-shadow: 0 32px 80px rgba(0,0,0,0.55), 0 0 0 1px rgba(255,255,255,0.03) inset;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n font-family: 'Inter', -apple-system, sans-serif;\n transform: translate(-50%, -50%) scale(0.88);\n opacity: 0;\n transition: transform 0.4s cubic-bezier(0.34,1.56,0.64,1),\n opacity 0.3s ease,\n width 0.35s cubic-bezier(0.25,1,0.5,1),\n height 0.35s cubic-bezier(0.25,1,0.5,1);\n }\n .bs-modal.bs-in {\n transform: translate(-50%, -50%) scale(1);\n opacity: 1;\n }\n .bs-modal.bs-out {\n transform: translate(-50%, -50%) scale(0.85);\n opacity: 0;\n transition: transform 0.3s cubic-bezier(0.4,0,1,1), opacity 0.25s ease;\n }\n\n /* ── Header ── */\n .bs-hdr {\n padding: 18px 22px 0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-shrink: 0;\n }\n .bs-logo {\n font-family: 'Comfortaa', cursive;\n font-weight: 700;\n font-size: 18px;\n background: linear-gradient(135deg, var(--bs-accent), #fff);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n }\n .bs-hdr-right {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .bs-pin-toggle {\n all: initial;\n cursor: pointer;\n padding: 5px 10px;\n border-radius: var(--bs-radius-sm);\n font-size: 11px;\n font-weight: 600;\n font-family: 'Inter', sans-serif;\n color: var(--bs-muted);\n border: 1px solid var(--bs-border);\n transition: all 0.2s;\n display: flex;\n align-items: center;\n gap: 5px;\n }\n .bs-pin-toggle:hover { color: var(--bs-text); border-color: var(--bs-accent); }\n .bs-pin-toggle.active {\n background: var(--bs-accent);\n color: #fff;\n border-color: var(--bs-accent);\n -webkit-text-fill-color: #fff;\n }\n .bs-hdr-icon {\n all: initial;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: var(--bs-radius-sm);\n color: var(--bs-muted);\n transition: all 0.2s;\n }\n .bs-hdr-icon:hover { color: var(--bs-text); background: var(--bs-bg3); }\n .bs-user-badge {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--bs-muted);\n font-family: 'Inter', sans-serif;\n }\n .bs-user-avatar {\n width: 22px;\n height: 22px;\n border-radius: 50%;\n background: linear-gradient(135deg, var(--bs-accent), var(--bs-accent2));\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 10px;\n font-weight: 700;\n color: #fff;\n }\n .bs-login-form {\n padding: 32px 24px;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n }\n .bs-login-logo {\n font-family: 'Comfortaa', cursive;\n font-weight: 700;\n font-size: 28px;\n background: linear-gradient(135deg, var(--bs-accent), #fff);\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n margin-bottom: 4px;\n }\n .bs-login-subtitle {\n font-size: 13px;\n color: var(--bs-muted);\n margin-bottom: 8px;\n }\n .bs-login-input {\n width: 100%;\n max-width: 300px;\n padding: 10px 14px;\n border-radius: var(--bs-radius-sm);\n border: 1px solid var(--bs-border);\n background: var(--bs-bg2);\n color: var(--bs-text);\n font-size: 13px;\n font-family: 'Inter', sans-serif;\n outline: none;\n transition: border-color 0.2s;\n box-sizing: border-box;\n }\n .bs-login-input:focus { border-color: var(--bs-accent); }\n .bs-login-input::placeholder { color: var(--bs-muted); opacity: 0.6; }\n .bs-login-btn {\n width: 100%;\n max-width: 300px;\n padding: 10px;\n border-radius: var(--bs-radius-sm);\n border: none;\n background: linear-gradient(135deg, var(--bs-accent), var(--bs-accent2));\n color: #fff;\n font-size: 14px;\n font-weight: 600;\n font-family: 'Inter', sans-serif;\n cursor: pointer;\n transition: opacity 0.2s;\n }\n .bs-login-btn:hover { opacity: 0.9; }\n .bs-login-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n .bs-login-error {\n font-size: 12px;\n color: var(--bs-red);\n max-width: 300px;\n text-align: center;\n }\n .bs-login-logout {\n all: initial;\n cursor: pointer;\n font-size: 11px;\n color: var(--bs-muted);\n font-family: 'Inter', sans-serif;\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s;\n }\n .bs-login-logout:hover { color: var(--bs-red); }\n .bs-close-btn {\n all: initial;\n cursor: pointer;\n color: var(--bs-muted);\n padding: 6px;\n border-radius: var(--bs-radius-sm);\n display: flex;\n transition: all 0.2s;\n }\n .bs-close-btn:hover { color: var(--bs-text); background: var(--bs-bg3); }\n\n /* ── Tabs ── */\n .bs-tabs {\n display: flex;\n gap: 2px;\n padding: 12px 22px 0;\n position: relative;\n flex-shrink: 0;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n }\n .bs-tabs::-webkit-scrollbar { display: none; }\n .bs-tab {\n all: initial;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 10px 14px;\n border-radius: var(--bs-radius-sm) var(--bs-radius-sm) 0 0;\n font-family: 'Inter', sans-serif;\n font-size: 12px;\n font-weight: 600;\n color: var(--bs-muted);\n transition: all 0.25s ease;\n position: relative;\n white-space: nowrap;\n flex-shrink: 0;\n }\n .bs-tab:hover { color: var(--bs-text); background: var(--bs-bg2); }\n .bs-tab.bs-active {\n color: var(--bs-accent);\n background: var(--bs-bg2);\n }\n .bs-tab.bs-active::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 8px;\n right: 8px;\n height: 2px;\n background: var(--bs-accent);\n border-radius: 2px 2px 0 0;\n animation: bs-tabIn 0.25s ease;\n }\n @keyframes bs-tabIn { from { transform: scaleX(0); } to { transform: scaleX(1); } }\n .bs-tab-badge {\n font-size: 10px;\n font-weight: 700;\n padding: 1px 6px;\n border-radius: 10px;\n background: var(--bs-bg3);\n color: var(--bs-muted);\n line-height: 1.4;\n }\n .bs-tab.bs-active .bs-tab-badge { background: var(--bs-accent); color: #fff; }\n .bs-tab-badge.bs-warn { background: var(--bs-red); color: #fff; }\n .bs-tab-divider {\n height: 1px;\n background: var(--bs-border);\n flex-shrink: 0;\n }\n\n /* ── Scrollable Body ── */\n .bs-scroll {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 16px 22px 22px;\n overscroll-behavior: contain;\n }\n .bs-scroll::-webkit-scrollbar { width: 5px; }\n .bs-scroll::-webkit-scrollbar-track { background: transparent; }\n .bs-scroll::-webkit-scrollbar-thumb { background: var(--bs-border); border-radius: 4px; }\n\n /* ── View slide animation ── */\n .bs-view { animation: bs-slideUp 0.3s cubic-bezier(0.22,1,0.36,1); }\n @keyframes bs-slideUp {\n from { opacity: 0; transform: translateY(12px); }\n to { opacity: 1; transform: translateY(0); }\n }\n\n /* ── Form ── */\n .bs-field { margin-bottom: 16px; }\n .bs-field-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--bs-text);\n margin-bottom: 7px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .bs-field-hint { font-size: 11px; font-weight: 400; color: var(--bs-muted); }\n .bs-input, .bs-textarea {\n width: 100%;\n padding: 11px 14px;\n border: 1.5px solid var(--bs-border);\n border-radius: var(--bs-radius-sm);\n font-size: 14px;\n font-family: 'Inter', sans-serif;\n background: var(--bs-bg2);\n color: var(--bs-text);\n box-sizing: border-box;\n transition: all 0.2s ease;\n -webkit-appearance: none;\n }\n .bs-input::placeholder, .bs-textarea::placeholder { color: var(--bs-muted); opacity: 0.5; }\n .bs-input:focus, .bs-textarea:focus {\n outline: none;\n border-color: var(--bs-accent);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--bs-accent) 15%, transparent);\n }\n .bs-textarea { resize: vertical; min-height: 76px; line-height: 1.5; }\n /* ── Severity ── */\n .bs-sev-row { display: flex; gap: 8px; }\n .bs-sev-btn {\n all: initial;\n flex: 1;\n padding: 10px 0;\n border-radius: var(--bs-radius-sm);\n text-align: center;\n font-size: 12px;\n font-weight: 600;\n font-family: 'Inter', sans-serif;\n cursor: pointer;\n transition: all 0.25s ease;\n position: relative;\n }\n .bs-sev-btn.bs-sev-low { background: color-mix(in srgb, var(--bs-green) 8%, transparent); color: var(--bs-green); border: 1.5px solid color-mix(in srgb, var(--bs-green) 15%, transparent); }\n .bs-sev-btn.bs-sev-medium { background: color-mix(in srgb, var(--bs-yellow) 8%, transparent); color: var(--bs-yellow); border: 1.5px solid color-mix(in srgb, var(--bs-yellow) 15%, transparent); }\n .bs-sev-btn.bs-sev-high { background: color-mix(in srgb, var(--bs-orange) 8%, transparent); color: var(--bs-orange); border: 1.5px solid color-mix(in srgb, var(--bs-orange) 15%, transparent); }\n .bs-sev-btn.bs-sev-critical { background: color-mix(in srgb, var(--bs-red) 8%, transparent); color: var(--bs-red); border: 1.5px solid color-mix(in srgb, var(--bs-red) 15%, transparent); }\n .bs-sev-btn:hover { transform: translateY(-1px); }\n .bs-sev-btn:active { transform: scale(0.96); }\n .bs-sev-btn.bs-picked { box-shadow: 0 0 0 2px currentColor; transform: translateY(-1px); }\n .bs-sev-btn.bs-picked::after {\n content: '';\n position: absolute;\n top: 4px;\n right: 6px;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: currentColor;\n animation: bs-pop 0.3s cubic-bezier(0.34,1.56,0.64,1);\n }\n @keyframes bs-pop { from { transform: scale(0); } to { transform: scale(1); } }\n\n /* ── Screenshot ── */\n .bs-shot-area {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n background: var(--bs-bg2);\n border: 1.5px dashed var(--bs-border);\n border-radius: var(--bs-radius-sm);\n margin-bottom: 16px;\n cursor: pointer;\n transition: all 0.25s ease;\n }\n .bs-shot-area:hover { border-color: var(--bs-accent); border-style: solid; background: var(--bs-bg3); }\n .bs-shot-area:active { transform: scale(0.98); }\n .bs-shot-icon {\n width: 40px;\n height: 40px;\n border-radius: var(--bs-radius-sm);\n background: color-mix(in srgb, var(--bs-accent) 12%, transparent);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--bs-accent);\n flex-shrink: 0;\n }\n .bs-shot-text { flex: 1; }\n .bs-shot-title { font-size: 13px; font-weight: 600; color: var(--bs-text); }\n .bs-shot-sub { font-size: 11px; color: var(--bs-muted); margin-top: 2px; }\n .bs-shot-area.bs-captured { border-style: solid; border-color: var(--bs-green); }\n .bs-shot-area.bs-captured .bs-shot-icon { background: color-mix(in srgb, var(--bs-green) 12%, transparent); color: var(--bs-green); }\n\n /* ── Category Chips ── */\n .bs-cat-row { display: flex; flex-wrap: wrap; gap: 6px; }\n .bs-cat-btn {\n all: initial;\n padding: 7px 14px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 600;\n font-family: 'Inter', sans-serif;\n cursor: pointer;\n transition: all 0.2s ease;\n background: var(--bs-bg2);\n color: var(--bs-muted);\n border: 1.5px solid var(--bs-border);\n }\n .bs-cat-btn:hover { color: var(--bs-text); border-color: var(--bs-accent); }\n .bs-cat-btn.bs-picked {\n background: color-mix(in srgb, var(--bs-accent) 12%, transparent);\n color: var(--bs-accent);\n border-color: var(--bs-accent);\n }\n\n /* ── Context Bar ── */\n .bs-ctx-bar {\n display: flex;\n gap: 2px;\n margin-bottom: 16px;\n background: var(--bs-bg2);\n border-radius: var(--bs-radius-sm);\n padding: 3px;\n border: 1px solid var(--bs-border);\n }\n .bs-ctx-chip {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n padding: 8px 4px;\n border-radius: calc(var(--bs-radius-sm) - 2px);\n transition: background 0.2s;\n }\n .bs-ctx-chip.bs-has { background: var(--bs-bg3); }\n .bs-ctx-chip.bs-alert { background: color-mix(in srgb, var(--bs-red) 8%, transparent); }\n .bs-ctx-n {\n font-size: 15px;\n font-weight: 700;\n color: var(--bs-text);\n line-height: 1;\n }\n .bs-ctx-chip.bs-alert .bs-ctx-n { color: var(--bs-red); }\n .bs-ctx-l {\n font-size: 9px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: var(--bs-muted);\n }\n\n /* ── Report Summary Bar ── */\n .bs-report-summary {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n border-radius: var(--bs-radius-sm);\n background: var(--bs-bg2);\n border: 1px solid var(--bs-border);\n margin-bottom: 16px;\n font-size: 12px;\n color: var(--bs-muted);\n }\n .bs-report-summary.bs-alert {\n background: color-mix(in srgb, var(--bs-red) 6%, transparent);\n border-color: color-mix(in srgb, var(--bs-red) 15%, transparent);\n color: var(--bs-red);\n }\n .bs-report-summary.bs-has { color: var(--bs-text); }\n .bs-report-summary-left { display: flex; align-items: center; gap: 8px; }\n .bs-report-summary-icon {\n width: 22px; height: 22px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--bs-green) 12%, transparent);\n color: var(--bs-green);\n display: flex; align-items: center; justify-content: center;\n font-size: 10px; flex-shrink: 0;\n }\n .bs-report-summary-icon.bs-warn {\n background: color-mix(in srgb, var(--bs-red) 12%, transparent);\n color: var(--bs-red);\n font-weight: 800; font-size: 12px;\n }\n .bs-input-title {\n font-size: 16px !important;\n font-weight: 600;\n padding: 14px !important;\n }\n\n .bs-auto-step-n {\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--bs-accent) 15%, transparent);\n color: var(--bs-accent);\n font-size: 10px;\n font-weight: 700;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n .bs-auto-muted {\n font-size: 12px;\n color: var(--bs-muted);\n padding: 6px 0;\n }\n\n /* ── Submit ── */\n .bs-submit-btn {\n all: initial;\n width: 100%;\n padding: 14px;\n background: linear-gradient(135deg, var(--bs-fab1), var(--bs-fab2));\n color: #fff;\n border-radius: var(--bs-radius-sm);\n font-size: 15px;\n font-weight: 700;\n font-family: 'Inter', sans-serif;\n cursor: pointer;\n text-align: center;\n box-sizing: border-box;\n transition: all 0.3s ease;\n position: relative;\n overflow: hidden;\n }\n .bs-submit-btn:hover { box-shadow: 0 8px 28px rgba(0,0,0,0.3); transform: translateY(-1px); }\n .bs-submit-btn:active { transform: translateY(0) scale(0.98); }\n .bs-submit-btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none !important; box-shadow: none !important; }\n .bs-submit-btn.bs-submit-ok {\n background: var(--bs-green) !important;\n opacity: 1 !important;\n display: flex; align-items: center; justify-content: center; gap: 6px;\n }\n .bs-submit-btn.bs-submit-err {\n background: var(--bs-red) !important;\n opacity: 1 !important;\n font-size: 13px;\n }\n\n /* ── Console ── */\n .bs-log {\n padding: 8px 10px;\n border-radius: var(--bs-radius-sm);\n margin-bottom: 4px;\n font-family: 'SF Mono', 'Fira Code', monospace;\n font-size: 11.5px;\n line-height: 1.5;\n display: flex;\n gap: 8px;\n align-items: flex-start;\n transition: background 0.15s;\n }\n .bs-log:hover { background: var(--bs-bg2); }\n .bs-log-lv {\n font-weight: 700;\n text-transform: uppercase;\n font-size: 9px;\n padding: 3px 6px;\n border-radius: 5px;\n flex-shrink: 0;\n margin-top: 2px;\n letter-spacing: 0.4px;\n }\n .bs-log-lv.bs-le { background: color-mix(in srgb, var(--bs-red) 12%, transparent); color: var(--bs-red); }\n .bs-log-lv.bs-lw { background: color-mix(in srgb, var(--bs-orange) 10%, transparent); color: var(--bs-orange); }\n .bs-log-lv.bs-ll { background: var(--bs-bg3); color: var(--bs-muted); }\n .bs-log-lv.bs-li { background: color-mix(in srgb, var(--bs-accent) 10%, transparent); color: var(--bs-accent); }\n .bs-log-lv.bs-ld { background: var(--bs-bg2); color: var(--bs-muted); }\n .bs-log-m { color: var(--bs-text); word-break: break-word; flex: 1; white-space: pre-wrap; }\n .bs-log-t { color: var(--bs-muted); opacity: 0.5; flex-shrink: 0; font-size: 10px; margin-top: 3px; }\n\n /* ── Network ── */\n .bs-net {\n padding: 9px 10px;\n border-radius: var(--bs-radius-sm);\n margin-bottom: 4px;\n font-family: 'SF Mono', 'Fira Code', monospace;\n font-size: 11.5px;\n display: flex;\n gap: 8px;\n align-items: center;\n transition: background 0.15s;\n }\n .bs-net:hover { background: var(--bs-bg2); }\n .bs-net-m { font-weight: 700; font-size: 10px; color: var(--bs-accent); flex-shrink: 0; width: 34px; }\n .bs-net-s { font-weight: 700; font-size: 10px; padding: 3px 7px; border-radius: 5px; flex-shrink: 0; }\n .bs-net-s.bs-ok { background: color-mix(in srgb, var(--bs-green) 10%, transparent); color: var(--bs-green); }\n .bs-net-s.bs-fail { background: color-mix(in srgb, var(--bs-red) 10%, transparent); color: var(--bs-red); }\n .bs-net-u { color: var(--bs-text); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .bs-net-d { color: var(--bs-muted); opacity: 0.5; flex-shrink: 0; font-size: 10px; }\n\n /* ── Context: Errors ── */\n .bs-err-card {\n padding: 12px 14px;\n margin-bottom: 8px;\n background: color-mix(in srgb, var(--bs-red) 6%, transparent);\n border: 1px solid color-mix(in srgb, var(--bs-red) 10%, transparent);\n border-radius: var(--bs-radius-sm);\n transition: border-color 0.2s;\n }\n .bs-err-card:hover { border-color: color-mix(in srgb, var(--bs-red) 20%, transparent); }\n .bs-err-m { color: var(--bs-red); font-weight: 600; font-size: 13px; margin-bottom: 6px; line-height: 1.4; }\n .bs-err-stack {\n font-family: 'SF Mono', monospace;\n font-size: 10px;\n color: var(--bs-muted);\n white-space: pre-wrap;\n max-height: 72px;\n overflow-y: auto;\n line-height: 1.5;\n }\n .bs-err-meta { font-size: 10px; color: var(--bs-muted); margin-top: 6px; }\n\n /* ── Context: Section Title ── */\n .bs-sec {\n font-size: 10px;\n font-weight: 700;\n color: var(--bs-accent);\n text-transform: uppercase;\n letter-spacing: 0.8px;\n margin: 20px 0 10px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--bs-border);\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .bs-sec:first-child { margin-top: 0; }\n .bs-sec-n {\n background: var(--bs-bg3);\n color: var(--bs-muted);\n font-size: 9px;\n padding: 2px 6px;\n border-radius: 5px;\n }\n\n /* ── KV Grid ── */\n .bs-kv {\n display: grid;\n grid-template-columns: 100px 1fr;\n gap: 7px 12px;\n font-size: 12px;\n }\n .bs-kv-k { color: var(--bs-muted); font-size: 11px; }\n .bs-kv-v { color: var(--bs-text); word-break: break-all; font-size: 11px; }\n\n /* ── Breadcrumbs ── */\n .bs-bc {\n padding: 7px 10px;\n border-radius: 8px;\n margin-bottom: 3px;\n font-size: 11px;\n display: flex;\n gap: 8px;\n align-items: flex-start;\n transition: background 0.15s;\n }\n .bs-bc:hover { background: var(--bs-bg2); }\n .bs-bc-t {\n font-size: 8px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;\n padding: 3px 6px; border-radius: 5px; flex-shrink: 0;\n background: var(--bs-bg3); color: var(--bs-muted);\n }\n .bs-bc-t.bs-t-click { color: var(--bs-accent); background: color-mix(in srgb, var(--bs-accent) 10%, transparent); }\n .bs-bc-t.bs-t-input { color: var(--bs-green); background: color-mix(in srgb, var(--bs-green) 10%, transparent); }\n .bs-bc-t.bs-t-navigation { color: var(--bs-accent2); background: color-mix(in srgb, var(--bs-accent2) 10%, transparent); }\n .bs-bc-t.bs-t-error { color: var(--bs-red); background: color-mix(in srgb, var(--bs-red) 10%, transparent); }\n .bs-bc-t.bs-t-network { color: var(--bs-orange); background: color-mix(in srgb, var(--bs-orange) 10%, transparent); }\n .bs-bc-t.bs-t-console { color: var(--bs-yellow); background: color-mix(in srgb, var(--bs-yellow) 10%, transparent); }\n .bs-bc-t.bs-t-custom { color: var(--bs-accent); background: color-mix(in srgb, var(--bs-accent) 10%, transparent); }\n .bs-bc-m { color: var(--bs-text); flex: 1; line-height: 1.4; }\n .bs-bc-time { color: var(--bs-muted); opacity: 0.5; font-size: 10px; flex-shrink: 0; }\n\n /* ── Performance ── */\n .bs-pf { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }\n .bs-pf-l { font-size: 11px; color: var(--bs-muted); width: 85px; flex-shrink: 0; }\n .bs-pf-tr { flex: 1; height: 6px; background: var(--bs-bg3); border-radius: 4px; overflow: hidden; }\n .bs-pf-fl { height: 100%; border-radius: 4px; background: linear-gradient(90deg, var(--bs-accent), var(--bs-accent2)); transition: width 0.6s cubic-bezier(0.34,1.56,0.64,1); }\n .bs-pf-fl.bs-slow { background: linear-gradient(90deg, var(--bs-orange), var(--bs-red)); }\n .bs-pf-v { font-size: 11px; font-weight: 600; color: var(--bs-text); width: 55px; text-align: right; flex-shrink: 0; }\n\n /* ── Annotation ── */\n .bs-ann-wrap { position: relative; margin-bottom: 16px; border-radius: var(--bs-radius-sm); overflow: hidden; border: 1.5px solid var(--bs-border); animation: bs-slideUp 0.3s ease; }\n .bs-ann-viewport { overflow: hidden; position: relative; }\n .bs-ann-canvas { display: block; width: 100%; transform-origin: 0 0; transition: transform 0.15s ease; }\n .bs-ann-canvas.bs-select { cursor: default; }\n .bs-ann-canvas.bs-draw { cursor: crosshair; }\n .bs-ann-canvas.bs-arrow { cursor: crosshair; }\n .bs-ann-canvas.bs-rect { cursor: crosshair; }\n .bs-ann-canvas.bs-circle { cursor: crosshair; }\n .bs-ann-canvas.bs-text { cursor: text; }\n .bs-ann-canvas.bs-highlight { cursor: crosshair; }\n .bs-ann-canvas.bs-grab { cursor: grab; }\n .bs-ann-canvas.bs-grabbing { cursor: grabbing; }\n .bs-ann-toolbar { display: flex; gap: 2px; padding: 6px 8px; background: var(--bs-bg2); border-top: 1px solid var(--bs-border); align-items: center; flex-wrap: wrap; }\n .bs-ann-sep { width: 1px; height: 20px; background: var(--bs-border); margin: 0 4px; flex-shrink: 0; }\n .bs-ann-btn {\n all: initial; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center;\n border-radius: 6px; cursor: pointer; color: var(--bs-muted); transition: all 0.15s; font-size: 14px;\n }\n .bs-ann-btn:hover { background: var(--bs-bg3); color: var(--bs-text); }\n .bs-ann-btn.bs-sel { background: color-mix(in srgb, var(--bs-accent) 15%, transparent); color: var(--bs-accent); }\n .bs-ann-btn[title]::after { content: none; }\n .bs-ann-dot {\n width: 20px; height: 20px; border-radius: 50%; border: 2.5px solid transparent; cursor: pointer;\n transition: all 0.15s; flex-shrink: 0;\n }\n .bs-ann-dot:hover { transform: scale(1.15); }\n .bs-ann-dot.bs-sel { border-color: var(--bs-text); transform: scale(1.15); box-shadow: 0 0 8px rgba(255,255,255,0.15); }\n .bs-ann-size {\n width: 60px; height: 4px; -webkit-appearance: none; appearance: none; background: var(--bs-border);\n border-radius: 2px; outline: none; cursor: pointer;\n }\n .bs-ann-size::-webkit-slider-thumb {\n -webkit-appearance: none; width: 14px; height: 14px; border-radius: 50%;\n background: var(--bs-accent); cursor: pointer; border: 2px solid var(--bs-bg);\n }\n .bs-ann-zoom-label { font-size: 10px; font-weight: 600; color: var(--bs-muted); min-width: 32px; text-align: center; }\n .bs-ann-right { margin-left: auto; display: flex; gap: 2px; align-items: center; }\n .bs-ann-clr-btn {\n all: initial; padding: 3px 10px; border: 1px solid var(--bs-border); border-radius: 6px;\n color: var(--bs-muted); font-size: 10px; cursor: pointer; font-family: 'Inter', sans-serif; transition: all 0.15s;\n }\n .bs-ann-clr-btn:hover { color: var(--bs-red); border-color: color-mix(in srgb, var(--bs-red) 30%, transparent); }\n\n /* ── Pin Tool ── */\n .bs-ann-canvas.bs-pin { cursor: crosshair; }\n .bs-ann-pins { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; }\n .bs-ann-pin {\n position: absolute;\n width: 26px; height: 26px;\n border-radius: 50% 50% 50% 0;\n transform: translate(-50%, -100%) rotate(-45deg);\n display: flex; align-items: center; justify-content: center;\n font-size: 11px; font-weight: 700; font-family: 'Inter', sans-serif;\n color: #fff;\n pointer-events: all;\n cursor: grab;\n transition: transform 0.15s, box-shadow 0.15s;\n box-shadow: 0 2px 8px rgba(0,0,0,0.3);\n z-index: 1;\n }\n .bs-ann-pin:hover { transform: translate(-50%, -100%) rotate(-45deg) scale(1.15); box-shadow: 0 4px 16px rgba(0,0,0,0.4); z-index: 2; }\n .bs-ann-pin.bs-dragging { cursor: grabbing; transform: translate(-50%, -100%) rotate(-45deg) scale(1.2); z-index: 3; }\n .bs-ann-pin-n { transform: rotate(45deg); line-height: 1; }\n .bs-ann-pin-pulse {\n position: absolute; inset: -4px; border-radius: 50% 50% 50% 0;\n border: 2px solid currentColor; opacity: 0;\n animation: bs-pin-ring 1.5s ease-out forwards;\n }\n @keyframes bs-pin-ring { 0% { opacity: 0.6; inset: -4px; } 100% { opacity: 0; inset: -14px; } }\n\n /* ── Pin List (below canvas) ── */\n .bs-ann-pin-list {\n max-height: 140px;\n overflow-y: auto;\n border-top: 1px solid var(--bs-border);\n background: var(--bs-bg2);\n }\n .bs-ann-pin-item {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 8px 12px;\n border-bottom: 1px solid color-mix(in srgb, var(--bs-border) 50%, transparent);\n font-size: 12px;\n color: var(--bs-text);\n }\n .bs-ann-pin-item:last-child { border-bottom: none; }\n .bs-ann-pin-num {\n width: 22px; height: 22px;\n border-radius: 50%;\n display: flex; align-items: center; justify-content: center;\n font-size: 11px; font-weight: 700; color: #fff;\n flex-shrink: 0;\n }\n .bs-ann-pin-body { flex: 1; min-width: 0; }\n .bs-ann-pin-note { word-break: break-word; line-height: 1.4; }\n .bs-ann-pin-loc { font-size: 10px; color: var(--bs-muted); margin-top: 2px; }\n .bs-ann-pin-del {\n all: initial; cursor: pointer; color: var(--bs-muted); font-size: 14px;\n padding: 2px 4px; border-radius: 4px; transition: color 0.15s;\n flex-shrink: 0;\n }\n .bs-ann-pin-del:hover { color: var(--bs-red); }\n\n /* ── History ── */\n .bs-hist-card {\n background: var(--bs-bg2);\n border: 1px solid var(--bs-border);\n border-radius: var(--bs-radius-sm);\n padding: 14px;\n margin-bottom: 10px;\n transition: border-color 0.2s;\n }\n .bs-hist-card:hover { border-color: var(--bs-accent); }\n .bs-hist-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; margin-bottom: 8px; }\n .bs-hist-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--bs-text);\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .bs-hist-actions { display: flex; gap: 4px; flex-shrink: 0; }\n .bs-hist-btn {\n all: initial;\n width: 26px; height: 26px;\n display: flex; align-items: center; justify-content: center;\n border-radius: 6px;\n cursor: pointer;\n color: var(--bs-muted);\n transition: all 0.15s;\n font-size: 12px;\n }\n .bs-hist-btn:hover { background: var(--bs-bg3); color: var(--bs-text); }\n .bs-hist-btn.bs-del:hover { color: var(--bs-red); }\n .bs-hist-meta { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 6px; }\n .bs-hist-badge {\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n }\n .bs-hist-badge.bs-sev-low { background: color-mix(in srgb, var(--bs-green) 12%, transparent); color: var(--bs-green); }\n .bs-hist-badge.bs-sev-medium { background: color-mix(in srgb, var(--bs-yellow) 12%, transparent); color: var(--bs-yellow); }\n .bs-hist-badge.bs-sev-high { background: color-mix(in srgb, var(--bs-orange) 12%, transparent); color: var(--bs-orange); }\n .bs-hist-badge.bs-sev-critical { background: color-mix(in srgb, var(--bs-red) 12%, transparent); color: var(--bs-red); }\n .bs-hist-badge.bs-cat { background: color-mix(in srgb, var(--bs-accent) 12%, transparent); color: var(--bs-accent); }\n .bs-hist-badge.bs-status-sent { background: color-mix(in srgb, var(--bs-green) 12%, transparent); color: var(--bs-green); }\n .bs-hist-badge.bs-status-draft { background: color-mix(in srgb, var(--bs-yellow) 12%, transparent); color: var(--bs-yellow); }\n .bs-hist-desc { font-size: 12px; color: var(--bs-muted); line-height: 1.5; margin-bottom: 6px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }\n .bs-hist-foot { display: flex; justify-content: space-between; align-items: center; font-size: 10px; color: var(--bs-muted); }\n .bs-hist-pins { display: flex; gap: 4px; }\n .bs-hist-pin-dot { width: 18px; height: 18px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 700; color: #fff; }\n .bs-hist-thumb { width: 40px; height: 40px; border-radius: 6px; object-fit: cover; border: 1px solid var(--bs-border); flex-shrink: 0; }\n .bs-hist-confirm {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 14px;\n background: color-mix(in srgb, var(--bs-red) 8%, transparent);\n border: 1px solid color-mix(in srgb, var(--bs-red) 20%, transparent);\n border-radius: var(--bs-radius-sm);\n margin-bottom: 10px;\n font-size: 12px; color: var(--bs-text);\n animation: bs-slideUp 0.2s ease;\n }\n .bs-hist-confirm-yes {\n all: initial; padding: 4px 12px; background: var(--bs-red); color: #fff; border-radius: 6px;\n font-size: 11px; font-weight: 600; cursor: pointer; font-family: 'Inter', sans-serif;\n }\n .bs-hist-confirm-no {\n all: initial; padding: 4px 12px; border: 1px solid var(--bs-border); border-radius: 6px;\n font-size: 11px; font-weight: 600; cursor: pointer; color: var(--bs-muted); font-family: 'Inter', sans-serif;\n }\n .bs-hist-edit-wrap { margin-bottom: 10px; animation: bs-slideUp 0.2s ease; }\n .bs-hist-edit-row { display: flex; gap: 6px; margin-top: 8px; }\n .bs-hist-save {\n all: initial; padding: 6px 16px; background: linear-gradient(135deg, var(--bs-fab1), var(--bs-fab2));\n color: #fff; border-radius: 6px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: 'Inter', sans-serif;\n }\n .bs-hist-cancel {\n all: initial; padding: 6px 16px; border: 1px solid var(--bs-border); border-radius: 6px;\n font-size: 12px; font-weight: 600; cursor: pointer; color: var(--bs-muted); font-family: 'Inter', sans-serif;\n }\n\n /* ── Empty ── */\n .bs-empty { text-align: center; padding: 36px 16px; color: var(--bs-muted); font-size: 13px; line-height: 1.6; }\n .bs-empty svg { opacity: 0.12; margin-bottom: 10px; }\n\n /* ── Settings ── */\n .bs-set-sec {\n font-size: 11px;\n font-weight: 700;\n color: var(--bs-accent);\n text-transform: uppercase;\n letter-spacing: 0.8px;\n margin: 0 0 12px;\n }\n .bs-set-sec + .bs-set-sec { margin-top: 24px; }\n .bs-set-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));\n gap: 8px;\n }\n .bs-set-card {\n all: initial;\n cursor: pointer;\n border: 2px solid var(--bs-border);\n border-radius: var(--bs-radius-sm);\n overflow: hidden;\n transition: all 0.2s ease;\n display: flex;\n flex-direction: column;\n }\n .bs-set-card:hover { border-color: var(--bs-accent); transform: translateY(-1px); }\n .bs-set-card.bs-picked { border-color: var(--bs-accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--bs-accent) 25%, transparent); }\n .bs-set-preview {\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n }\n .bs-set-dot {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n border: 1px solid rgba(255,255,255,0.1);\n }\n .bs-set-name {\n padding: 6px 8px;\n font-family: 'Inter', sans-serif;\n font-size: 10px;\n font-weight: 600;\n text-align: center;\n color: var(--bs-text);\n background: var(--bs-bg2);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .bs-set-ly-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));\n gap: 8px;\n }\n .bs-set-ly {\n all: initial;\n cursor: pointer;\n border: 2px solid var(--bs-border);\n border-radius: var(--bs-radius-sm);\n padding: 10px 12px;\n transition: all 0.2s ease;\n font-family: 'Inter', sans-serif;\n }\n .bs-set-ly:hover { border-color: var(--bs-accent); transform: translateY(-1px); }\n .bs-set-ly.bs-picked { border-color: var(--bs-accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--bs-accent) 25%, transparent); }\n .bs-set-ly-name { font-size: 12px; font-weight: 600; color: var(--bs-text); margin-bottom: 2px; }\n .bs-set-ly-desc { font-size: 10px; color: var(--bs-muted); }\n`;\n\n// ─── Shadow-root styles for FAB + Toolbar (outside iframe) ──\n\nconst SHADOW_STYLES = `\n :host {\n all: initial !important;\n display: block !important;\n position: fixed !important;\n inset: 0 !important;\n pointer-events: none !important;\n z-index: 2147483640 !important;\n visibility: visible !important;\n }\n\n /* ── FAB ── */\n .bs-fab {\n all: initial;\n pointer-events: auto;\n position: fixed;\n bottom: 24px;\n z-index: 2147483647;\n width: 56px;\n height: 56px;\n border-radius: var(--bs-radius);\n background: linear-gradient(135deg, var(--bs-fab1), var(--bs-fab2));\n color: #fff;\n cursor: grab;\n box-shadow: 0 4px 24px rgba(0,0,0,0.3), 0 0 0 0 rgba(0,0,0,0.15);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.35s cubic-bezier(0.34,1.56,0.64,1);\n animation: bs-pulse 3s ease-in-out infinite;\n touch-action: none;\n user-select: none;\n -webkit-user-select: none;\n font-family: 'Inter', -apple-system, sans-serif;\n }\n .bs-fab.bs-dragging { cursor: grabbing; transition: none; animation: none; }\n .bs-fab:hover { transform: scale(1.08) translateY(-2px); box-shadow: 0 8px 32px rgba(0,0,0,0.4); animation: none; }\n .bs-fab:active { transform: scale(0.95); }\n .bs-fab.bs-open { animation: none; transform: rotate(45deg) scale(0.9); box-shadow: 0 2px 12px rgba(0,0,0,0.3); }\n .bs-fab.bs-open:hover { transform: rotate(45deg) scale(1); }\n @keyframes bs-pulse {\n 0%, 100% { box-shadow: 0 4px 24px rgba(0,0,0,0.3), 0 0 0 0 rgba(0,0,0,0.15); }\n 50% { box-shadow: 0 4px 24px rgba(0,0,0,0.3), 0 0 0 10px rgba(0,0,0,0); }\n }\n .bs-fab-label {\n position: absolute;\n right: calc(100% + 12px);\n background: var(--bs-bg2);\n color: var(--bs-text);\n font-family: 'Inter', sans-serif;\n font-size: 13px;\n font-weight: 500;\n padding: 8px 14px;\n border-radius: var(--bs-radius-sm);\n white-space: nowrap;\n box-shadow: 0 4px 20px rgba(0,0,0,0.3);\n opacity: 0;\n transform: translateX(8px);\n transition: all 0.25s ease;\n pointer-events: none;\n }\n .bs-fab:hover .bs-fab-label { opacity: 1; transform: translateX(0); }\n .bs-fab-label::after {\n content: '';\n position: absolute;\n right: -6px;\n top: 50%;\n transform: translateY(-50%);\n border: 6px solid transparent;\n border-left-color: var(--bs-bg2);\n border-right: none;\n }\n\n /* ── Quick Action Toolbar ── */\n .bs-toolbar {\n pointer-events: auto;\n position: fixed;\n z-index: 2147483646;\n display: flex;\n flex-direction: column;\n gap: 6px;\n bottom: 88px;\n opacity: 0;\n transform: translateY(10px);\n transition: all 0.3s cubic-bezier(0.34,1.56,0.64,1);\n pointer-events: none;\n font-family: 'Inter', -apple-system, sans-serif;\n }\n .bs-toolbar.bs-show { opacity: 1; transform: translateY(0); pointer-events: all; }\n .bs-toolbar-btn {\n all: initial;\n width: 40px;\n height: 40px;\n border-radius: var(--bs-radius-sm);\n background: var(--bs-bg2);\n border: 1px solid var(--bs-border);\n color: var(--bs-muted);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n position: relative;\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n }\n .bs-toolbar-btn:hover { color: var(--bs-text); border-color: var(--bs-accent); background: var(--bs-bg3); }\n .bs-toolbar-btn.bs-active { color: var(--bs-accent); border-color: var(--bs-accent); }\n .bs-toolbar-tip {\n position: absolute;\n right: calc(100% + 8px);\n background: var(--bs-bg2);\n color: var(--bs-text);\n font-family: 'Inter', sans-serif;\n font-size: 11px;\n font-weight: 500;\n padding: 4px 8px;\n border-radius: 6px;\n white-space: nowrap;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s;\n }\n .bs-toolbar-btn:hover .bs-toolbar-tip { opacity: 1; }\n .bs-toolbar-kbd { font-size: 9px; color: var(--bs-muted); margin-left: 4px; }\n`;\n\n// ─── Login Tab ───────────────────────────────────────────\n\nfunction tabLogin(): string {\n return `\n <div class=\"bs-login-form\">\n <div class=\"bs-login-logo\">BugStash</div>\n <div class=\"bs-login-subtitle\">Sign in to report bugs & collaborate</div>\n <input class=\"bs-login-input\" type=\"email\" id=\"bs-login-email\" placeholder=\"Email\" autocomplete=\"email\" />\n <input class=\"bs-login-input\" type=\"password\" id=\"bs-login-pass\" placeholder=\"Password\" autocomplete=\"current-password\" />\n <div class=\"bs-login-error\" id=\"bs-login-error\" style=\"display:none\"></div>\n <button class=\"bs-login-btn\" id=\"bs-login-submit\">Sign In</button>\n <div style=\"font-size:11px;color:var(--bs-muted);margin-top:4px\">Contact your admin for an account</div>\n </div>\n `;\n}\n\n// ─── Helpers ─────────────────────────────────────────────\n\nfunction esc(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n}\nfunction timeAgo(ts: number): string {\n const s = Math.floor((Date.now() - ts) / 1000);\n if (s < 5) return 'now';\n if (s < 60) return `${s}s ago`;\n if (s < 3600) return `${Math.floor(s / 60)}m ago`;\n return new Date(ts).toLocaleTimeString();\n}\nfunction fmtTime(ts: number): string {\n return new Date(ts).toLocaleTimeString('en', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\n// ─── Report History (localStorage) ───────────────────────\n\nconst HISTORY_KEY = 'bugstash_history';\n\ninterface HistoryEntry {\n id: number;\n title: string;\n description: string;\n category: string;\n severity: string;\n tags?: string[];\n screenshot?: string;\n pins?: { number: number; x: number; y: number; note: string }[];\n url: string;\n createdAt: number;\n status: 'sent' | 'draft';\n}\n\nfunction getReportHistory(): HistoryEntry[] {\n try {\n return JSON.parse(localStorage.getItem(HISTORY_KEY) || '[]');\n } catch { return []; }\n}\n\nfunction saveReportHistory(entries: HistoryEntry[]) {\n try {\n localStorage.setItem(HISTORY_KEY, JSON.stringify(entries));\n } catch { /* quota exceeded */ }\n}\n\nfunction addToHistory(entry: Omit<HistoryEntry, 'id'>) {\n const entries = getReportHistory();\n const id = Date.now();\n entries.unshift({ ...entry, id });\n // Keep last 50\n if (entries.length > 50) entries.length = 50;\n saveReportHistory(entries);\n}\n\nfunction deleteFromHistory(id: number) {\n const entries = getReportHistory().filter(e => e.id !== id);\n saveReportHistory(entries);\n}\n\nfunction updateInHistory(id: number, updates: Partial<HistoryEntry>) {\n const entries = getReportHistory();\n const idx = entries.findIndex(e => e.id === id);\n if (idx >= 0) {\n entries[idx] = { ...entries[idx], ...updates };\n saveReportHistory(entries);\n }\n}\n\n// ─── Build Context ───────────────────────────────────────\n\nfunction buildContext(): ReportContext {\n return {\n url: window.location.href,\n userAgent: navigator.userAgent,\n platform: navigator.platform,\n language: navigator.language,\n cookiesEnabled: navigator.cookieEnabled,\n online: navigator.onLine,\n screenWidth: screen.width,\n screenHeight: screen.height,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n devicePixelRatio: window.devicePixelRatio,\n timestamp: Date.now(),\n environment: config.environment ?? 'development',\n commitHash: config.commitHash,\n user: config.user,\n };\n}\n\n// ─── Tab Content ─────────────────────────────────────────\n\nfunction autoDetect() {\n const errors = getErrors();\n const logs = getLogs();\n const net = getNetworkCaptures();\n const failedNet = getFailedNetworkCaptures();\n const crumbs = getBreadcrumbs();\n const perf = getPerformanceMetrics();\n const consoleErrors = logs.filter(l => l.level === 'error');\n\n // Auto-detect severity\n let severity: BugReport['severity'] = 'low';\n if (errors.length >= 3 || failedNet.length >= 3) severity = 'critical';\n else if (errors.length >= 1 || failedNet.length >= 2) severity = 'high';\n else if (consoleErrors.length > 0 || failedNet.length >= 1) severity = 'medium';\n\n // Auto-generate tags\n const tags: string[] = [];\n if (errors.length) tags.push('has-errors');\n if (failedNet.length) tags.push('network-failures');\n if (consoleErrors.length) tags.push('console-errors');\n if (perf?.pageLoadTime && perf.pageLoadTime > 3000) tags.push('slow-load');\n if (perf?.cumulativeLayoutShift && perf.cumulativeLayoutShift > 0.25) tags.push('layout-shift');\n if (!navigator.onLine) tags.push('offline');\n if (window.innerWidth < 768) tags.push('mobile');\n\n return { severity, tags,\n counts: { logs: logs.length, network: net.length, failedNet: failedNet.length, errors: errors.length, crumbs: crumbs.length } };\n}\n\nfunction tabReport(): string {\n const d = autoDetect();\n const categories: { id: BugReport['category']; label: string }[] = [\n { id: 'ui', label: 'UI' },\n { id: 'functionality', label: 'Feature' },\n { id: 'performance', label: 'Speed' },\n { id: 'crash', label: 'Crash' },\n { id: 'security', label: 'Security' },\n { id: 'other', label: 'Other' },\n ];\n\n const hasIssues = d.counts.errors > 0 || d.counts.failedNet > 0;\n const summaryClass = hasIssues ? ' bs-alert' : d.counts.logs > 0 ? ' bs-has' : '';\n\n return `<div class=\"bs-view\">\n <form data-bs-form>\n <div class=\"bs-report-summary${summaryClass}\">\n <div class=\"bs-report-summary-left\">\n ${hasIssues\n ? `<div class=\"bs-report-summary-icon bs-warn\">!</div><span>${d.counts.errors} error${d.counts.errors !== 1 ? 's' : ''}, ${d.counts.failedNet} failed request${d.counts.failedNet !== 1 ? 's' : ''} detected</span>`\n : `<div class=\"bs-report-summary-icon\">${I.check}</div><span>Auto-collecting ${d.counts.logs} logs, ${d.counts.network} requests, ${d.counts.crumbs} actions</span>`}\n </div>\n </div>\n <div class=\"bs-field\">\n <input class=\"bs-input bs-input-title\" name=\"title\" placeholder=\"What's the bug?\" required autocomplete=\"off\" />\n </div>\n <div class=\"bs-field\">\n <textarea class=\"bs-textarea\" name=\"description\" placeholder=\"Steps to reproduce or extra details (optional)\"></textarea>\n </div>\n <div class=\"bs-field\">\n <div class=\"bs-field-label\">Category</div>\n <input type=\"hidden\" name=\"category\" value=\"functionality\" />\n <div class=\"bs-cat-row\">\n ${categories.map(c => `<button type=\"button\" class=\"bs-cat-btn${c.id === 'functionality' ? ' bs-picked' : ''}\" data-cat=\"${c.id}\">${c.label}</button>`).join('')}\n </div>\n </div>\n <div class=\"bs-field\">\n <div class=\"bs-field-label\">Severity</div>\n <input type=\"hidden\" name=\"severity\" value=\"${d.severity}\" />\n <div class=\"bs-sev-row\">\n <button type=\"button\" class=\"bs-sev-btn bs-sev-low${d.severity === 'low' ? ' bs-picked' : ''}\" data-sev=\"low\">Low</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-medium${d.severity === 'medium' ? ' bs-picked' : ''}\" data-sev=\"medium\">Med</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-high${d.severity === 'high' ? ' bs-picked' : ''}\" data-sev=\"high\">High</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-critical${d.severity === 'critical' ? ' bs-picked' : ''}\" data-sev=\"critical\">Critical</button>\n </div>\n </div>\n <div class=\"bs-shot-area\" data-bs-screenshot>\n <div class=\"bs-shot-icon\">${I.cam}</div>\n <div class=\"bs-shot-text\">\n <div class=\"bs-shot-title\" data-bs-shot-title>Attach screenshot</div>\n <div class=\"bs-shot-sub\" data-bs-shot-sub>Capture & annotate the current view</div>\n </div>\n </div>\n <div data-bs-annotate></div>\n <button type=\"submit\" class=\"bs-submit-btn\">Submit Report</button>\n </form>\n </div>`;\n}\n\nfunction tabConsole(): string {\n const logs = getLogs();\n const lvMap: Record<string, string> = { error: 'bs-le', warn: 'bs-lw', log: 'bs-ll', info: 'bs-li', debug: 'bs-ld' };\n if (!logs.length) {\n return `<div class=\"bs-view\"><div class=\"bs-empty\"><p>No console logs captured yet.<br>Use the app — logs will appear here automatically.</p></div></div>`;\n }\n return `<div class=\"bs-view\">${logs.slice().reverse().map(l =>\n `<div class=\"bs-log\"><span class=\"bs-log-lv ${lvMap[l.level] || 'bs-ll'}\">${l.level}</span><span class=\"bs-log-m\">${esc(l.args.join(' ')).slice(0, 500)}</span><span class=\"bs-log-t\">${fmtTime(l.timestamp)}</span></div>`\n ).join('')}</div>`;\n}\n\nfunction tabNetwork(): string {\n const caps = getNetworkCaptures();\n if (!caps.length) {\n return `<div class=\"bs-view\"><div class=\"bs-empty\"><p>No network requests captured yet.<br>API calls will show up here automatically.</p></div></div>`;\n }\n return `<div class=\"bs-view\">${caps.slice().reverse().map(n =>\n `<div class=\"bs-net\"><span class=\"bs-net-m\">${n.method}</span><span class=\"bs-net-s ${n.failed ? 'bs-fail' : 'bs-ok'}\">${n.status || 'ERR'}</span><span class=\"bs-net-u\" title=\"${esc(n.url)}\">${esc(n.url)}</span><span class=\"bs-net-d\">${n.duration}ms</span></div>`\n ).join('')}</div>`;\n}\n\nfunction tabContext(): string {\n let html = `<div class=\"bs-view\">`;\n\n const errs = getErrors();\n if (errs.length) {\n html += `<div class=\"bs-sec\">Errors <span class=\"bs-sec-n\">${errs.length}</span></div>`;\n html += errs.slice().reverse().map(e =>\n `<div class=\"bs-err-card\"><div class=\"bs-err-m\">${esc(e.message)}</div>${e.stack ? `<div class=\"bs-err-stack\">${esc(e.stack)}</div>` : ''}<div class=\"bs-err-meta\">${e.type} &middot; ${fmtTime(e.timestamp)}${e.source ? ` &middot; ${esc(e.source)}:${e.lineno}` : ''}</div></div>`\n ).join('');\n }\n\n const perf = getPerformanceMetrics();\n if (perf) {\n html += `<div class=\"bs-sec\">Performance</div>`;\n const bars: [string, number | undefined, number][] = [\n ['Page Load', perf.pageLoadTime, 5000], ['DOM Ready', perf.domContentLoaded, 3000],\n ['First Paint', perf.firstPaint, 2000], ['FCP', perf.firstContentfulPaint, 2500],\n ['LCP', perf.largestContentfulPaint, 4000], ['FID', perf.firstInputDelay, 300],\n ];\n for (const [label, val, max] of bars) {\n if (val === undefined) continue;\n const pct = Math.min(100, (val / max) * 100);\n html += `<div class=\"bs-pf\"><span class=\"bs-pf-l\">${label}</span><div class=\"bs-pf-tr\"><div class=\"bs-pf-fl${pct > 75 ? ' bs-slow' : ''}\" style=\"width:${pct}%\"></div></div><span class=\"bs-pf-v\">${val}ms</span></div>`;\n }\n if (perf.cumulativeLayoutShift !== undefined) {\n const p = Math.min(100, perf.cumulativeLayoutShift * 400);\n html += `<div class=\"bs-pf\"><span class=\"bs-pf-l\">CLS</span><div class=\"bs-pf-tr\"><div class=\"bs-pf-fl${p > 40 ? ' bs-slow' : ''}\" style=\"width:${p}%\"></div></div><span class=\"bs-pf-v\">${perf.cumulativeLayoutShift}</span></div>`;\n }\n }\n\n const crumbs = getBreadcrumbs();\n if (crumbs.length) {\n html += `<div class=\"bs-sec\">Your activity trail <span class=\"bs-sec-n\">${crumbs.length}</span></div>`;\n html += crumbs.slice().reverse().map(b =>\n `<div class=\"bs-bc\"><span class=\"bs-bc-t bs-t-${b.type}\">${b.type}</span><span class=\"bs-bc-m\">${esc(b.message).slice(0, 120)}</span><span class=\"bs-bc-time\">${timeAgo(b.timestamp)}</span></div>`\n ).join('');\n }\n\n const ctx = buildContext();\n html += `<div class=\"bs-sec\">Environment</div>`;\n html += `<div class=\"bs-kv\">\n <span class=\"bs-kv-k\">URL</span><span class=\"bs-kv-v\">${esc(ctx.url)}</span>\n <span class=\"bs-kv-k\">Viewport</span><span class=\"bs-kv-v\">${ctx.viewportWidth}&times;${ctx.viewportHeight} @${ctx.devicePixelRatio}x</span>\n <span class=\"bs-kv-k\">Screen</span><span class=\"bs-kv-v\">${ctx.screenWidth}&times;${ctx.screenHeight}</span>\n <span class=\"bs-kv-k\">Platform</span><span class=\"bs-kv-v\">${esc(ctx.platform)}</span>\n <span class=\"bs-kv-k\">Language</span><span class=\"bs-kv-v\">${ctx.language}</span>\n ${config.commitHash ? `<span class=\"bs-kv-k\">Commit</span><span class=\"bs-kv-v\">${esc(config.commitHash)}</span>` : ''}\n ${config.user?.email ? `<span class=\"bs-kv-k\">User</span><span class=\"bs-kv-v\">${esc(config.user.email)}</span>` : ''}\n </div>`;\n\n html += `</div>`;\n return html;\n}\n\nfunction tabHistory(): string {\n const entries = getReportHistory();\n if (!entries.length) {\n return `<div class=\"bs-view\"><div class=\"bs-empty\"><p>No reports yet.<br>Submitted bugs will appear here.</p></div></div>`;\n }\n\n const catLabels: Record<string, string> = { ui: 'UI', functionality: 'Feature', performance: 'Perf', crash: 'Crash', security: 'Security', other: 'Other' };\n const fmtDate = (ts: number) => {\n const d = new Date(ts);\n const now = new Date();\n const diffMs = now.getTime() - d.getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 1) return 'Just now';\n if (diffMin < 60) return `${diffMin}m ago`;\n const diffH = Math.floor(diffMin / 60);\n if (diffH < 24) return `${diffH}h ago`;\n const diffD = Math.floor(diffH / 24);\n if (diffD < 7) return `${diffD}d ago`;\n return d.toLocaleDateString('en', { month: 'short', day: 'numeric' });\n };\n\n let html = `<div class=\"bs-view\">`;\n for (const e of entries) {\n const pinsHtml = e.pins?.length\n ? `<div class=\"bs-hist-pins\">${e.pins.slice(0, 5).map(p => `<div class=\"bs-hist-pin-dot\" style=\"background:${['#ef4444','#3b82f6','#f59e0b','#10b981','#8b5cf6'][p.number % 5]}\">${p.number}</div>`).join('')}${e.pins.length > 5 ? `<span>+${e.pins.length - 5}</span>` : ''}</div>`\n : '';\n html += `<div class=\"bs-hist-card\" data-hist-id=\"${e.id}\">\n <div class=\"bs-hist-top\">\n <div class=\"bs-hist-title\">${esc(e.title)}</div>\n ${e.screenshot ? `<img class=\"bs-hist-thumb\" src=\"${e.screenshot}\" alt=\"\"/>` : ''}\n <div class=\"bs-hist-actions\">\n <button class=\"bs-hist-btn\" data-hist-edit=\"${e.id}\" title=\"Edit\"><svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><path d=\"M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7\"/><path d=\"M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z\"/></svg></button>\n <button class=\"bs-hist-btn bs-del\" data-hist-del=\"${e.id}\" title=\"Delete\"><svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6\"/><path d=\"M10 11v6\"/><path d=\"M14 11v6\"/></svg></button>\n </div>\n </div>\n <div class=\"bs-hist-meta\">\n <span class=\"bs-hist-badge bs-cat\">${catLabels[e.category] || e.category}</span>\n <span class=\"bs-hist-badge bs-sev-${e.severity}\">${e.severity}</span>\n <span class=\"bs-hist-badge bs-status-${e.status}\">${e.status}</span>\n </div>\n ${e.description ? `<div class=\"bs-hist-desc\">${esc(e.description)}</div>` : ''}\n <div class=\"bs-hist-foot\">\n <span>${fmtDate(e.createdAt)} &middot; ${esc(e.url.replace(/^https?:\\/\\//, '').slice(0, 40))}</span>\n ${pinsHtml}\n </div>\n </div>`;\n }\n html += `</div>`;\n return html;\n}\n\nfunction tabSettings(): string {\n const themes = getThemes();\n const layouts = getLayouts();\n\n let html = `<div class=\"bs-view\">`;\n\n html += `<div class=\"bs-set-sec\">Layout</div>`;\n html += `<div class=\"bs-set-ly-grid\">`;\n for (const l of layouts) {\n html += `<button class=\"bs-set-ly${l.id === currentLayout.id ? ' bs-picked' : ''}\" data-set-layout=\"${l.id}\"><div class=\"bs-set-ly-name\">${esc(l.name)}</div><div class=\"bs-set-ly-desc\">${esc(l.description)}</div></button>`;\n }\n html += `</div>`;\n\n html += `<div class=\"bs-set-sec\">Theme</div>`;\n html += `<div class=\"bs-set-grid\">`;\n for (const t of themes) {\n html += `<button class=\"bs-set-card${t.id === currentTheme.id ? ' bs-picked' : ''}\" data-set-theme=\"${t.id}\"><div class=\"bs-set-preview\" style=\"background:${t.preview[0]}\"><div class=\"bs-set-dot\" style=\"background:${t.preview[1]}\"></div><div class=\"bs-set-dot\" style=\"background:${t.vars['--bs-accent2'] || t.preview[1]};opacity:0.6\"></div></div><div class=\"bs-set-name\">${esc(t.name)}</div></button>`;\n }\n html += `</div>`;\n\n html += `</div>`;\n return html;\n}\n\n// ─── Annotation ──────────────────────────────────────────\n\nfunction setupAnnotation(container: HTMLElement, screenshotData: string): { getAnnotation: () => string | null; getPins: () => { number: number; x: number; y: number; note: string }[] } {\n const COLORS = ['#f87171', '#3b82f6', '#fb923c', '#4ade80', '#a78bfa', '#facc15'];\n type Tool = 'select' | 'draw' | 'arrow' | 'rect' | 'circle' | 'text' | 'highlight' | 'pin';\n\n interface AnnShape {\n type: 'draw' | 'highlight';\n color: string; size: number; alpha: number;\n points: { x: number; y: number }[];\n }\n interface AnnRect { type: 'rect'; color: string; size: number; x: number; y: number; w: number; h: number; }\n interface AnnCircle { type: 'circle'; color: string; size: number; cx: number; cy: number; rx: number; ry: number; }\n interface AnnArrow { type: 'arrow'; color: string; size: number; x1: number; y1: number; x2: number; y2: number; }\n interface AnnText { type: 'text'; color: string; size: number; x: number; y: number; text: string; }\n type AnnObj = AnnShape | AnnRect | AnnCircle | AnnArrow | AnnText;\n\n let currentColor = COLORS[0];\n interface Pin { x: number; y: number; note: string; color: string; }\n\n let currentTool: Tool = 'draw';\n let brushSize = 4;\n let zoom = 1;\n let isDark = false;\n const shapes: AnnObj[] = [];\n const pins: Pin[] = [];\n let selectedIdx = -1;\n let hoveredIdx = -1;\n let dragging = false;\n let drawing = false;\n let dragOffX = 0, dragOffY = 0;\n let startX = 0, startY = 0;\n let currentDraw: { x: number; y: number }[] = [];\n const PIN_COLORS = ['#ef4444', '#3b82f6', '#f59e0b', '#10b981', '#8b5cf6', '#ec4899'];\n\n const img = new Image();\n img.src = screenshotData;\n\n const wrap = document.createElement('div');\n wrap.className = 'bs-ann-wrap';\n const viewport = document.createElement('div');\n viewport.className = 'bs-ann-viewport';\n const canvas = document.createElement('canvas');\n canvas.className = 'bs-ann-canvas bs-draw';\n const toolbar = document.createElement('div');\n toolbar.className = 'bs-ann-toolbar';\n\n const tIcons: Record<Tool, string> = {\n select: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z\"/><path d=\"M13 13l6 6\"/></svg>`,\n draw: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M12 19l7-7 3 3-7 7-3-3z\"/><path d=\"M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z\"/><path d=\"M2 2l7.586 7.586\"/></svg>`,\n arrow: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/><polyline points=\"12 5 19 12 12 19\"/></svg>`,\n rect: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/></svg>`,\n circle: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"10\"/></svg>`,\n text: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><polyline points=\"4 7 4 4 20 4 20 7\"/><line x1=\"9.5\" y1=\"20\" x2=\"14.5\" y2=\"20\"/><line x1=\"12\" y1=\"4\" x2=\"12\" y2=\"20\"/></svg>`,\n highlight: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M9 11l-6 6v3h9l3-3\"/><path d=\"M22 12l-4.6 4.6a2 2 0 01-2.8 0l-5.2-5.2a2 2 0 010-2.8L14 4\"/></svg>`,\n pin: `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>`,\n };\n const toolNames: Record<Tool, string> = { select: 'Select & Move', draw: 'Draw', arrow: 'Arrow', rect: 'Rectangle', circle: 'Circle', text: 'Text', highlight: 'Highlight', pin: 'Pin Issue' };\n\n // Tool buttons\n const toolBtns: HTMLButtonElement[] = [];\n const setTool = (t: Tool) => {\n currentTool = t;\n selectedIdx = -1;\n canvas.className = `bs-ann-canvas bs-${t}`;\n toolBtns.forEach(b => b.classList.remove('bs-sel'));\n toolBtns.find(b => b.dataset.tool === t)?.classList.add('bs-sel');\n };\n (Object.keys(tIcons) as Tool[]).forEach(t => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.dataset.tool = t;\n btn.className = `bs-ann-btn${t === currentTool ? ' bs-sel' : ''}`;\n btn.title = toolNames[t];\n btn.innerHTML = tIcons[t];\n btn.addEventListener('click', () => setTool(t));\n toolBtns.push(btn);\n toolbar.appendChild(btn);\n });\n\n // Separator\n toolbar.appendChild(Object.assign(document.createElement('div'), { className: 'bs-ann-sep' }));\n\n // Colors\n COLORS.forEach((color, i) => {\n const d = document.createElement('button');\n d.type = 'button';\n d.className = `bs-ann-dot${i === 0 ? ' bs-sel' : ''}`;\n d.style.background = color;\n d.addEventListener('click', () => {\n currentColor = color;\n toolbar.querySelectorAll('.bs-ann-dot').forEach(t => t.classList.remove('bs-sel'));\n d.classList.add('bs-sel');\n });\n toolbar.appendChild(d);\n });\n\n toolbar.appendChild(Object.assign(document.createElement('div'), { className: 'bs-ann-sep' }));\n\n // Brush size\n const sizeSlider = document.createElement('input');\n sizeSlider.type = 'range'; sizeSlider.min = '1'; sizeSlider.max = '12'; sizeSlider.value = '4';\n sizeSlider.className = 'bs-ann-size'; sizeSlider.title = 'Brush size';\n sizeSlider.addEventListener('input', () => { brushSize = parseInt(sizeSlider.value); });\n toolbar.appendChild(sizeSlider);\n\n // Right side\n const right = document.createElement('div');\n right.className = 'bs-ann-right';\n\n const mkBtn = (title: string, svg: string) => {\n const b = document.createElement('button');\n b.type = 'button'; b.className = 'bs-ann-btn'; b.title = title; b.innerHTML = svg;\n return b;\n };\n const zoomOut = mkBtn('Zoom out', `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"/><line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\"/></svg>`);\n const zoomLabel = Object.assign(document.createElement('span'), { className: 'bs-ann-zoom-label', textContent: '100%' });\n const zoomIn = mkBtn('Zoom in', `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"/><line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\"/><line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\"/></svg>`);\n const zoomReset = mkBtn('Fit', `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><path d=\"M15 3h6v6\"/><path d=\"M9 21H3v-6\"/><path d=\"M21 3l-7 7\"/><path d=\"M3 21l7-7\"/></svg>`);\n const undoBtn = mkBtn('Undo', `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"><polyline points=\"1 4 1 10 7 10\"/><path d=\"M3.51 15a9 9 0 105.42-8.49L1 10\"/></svg>`);\n const clearBtn = Object.assign(document.createElement('button'), { type: 'button', className: 'bs-ann-clr-btn', textContent: 'Clear' });\n\n const applyZoom = () => { canvas.style.transform = `scale(${zoom})`; zoomLabel.textContent = `${Math.round(zoom * 100)}%`; };\n zoomIn.addEventListener('click', () => { if (zoom < 3) { zoom = Math.min(3, zoom + 0.25); applyZoom(); } });\n zoomOut.addEventListener('click', () => { if (zoom > 0.5) { zoom = Math.max(0.5, zoom - 0.25); applyZoom(); } });\n zoomReset.addEventListener('click', () => { zoom = 1; applyZoom(); });\n\n right.appendChild(Object.assign(document.createElement('div'), { className: 'bs-ann-sep' }));\n [zoomOut, zoomLabel, zoomIn, zoomReset, undoBtn, clearBtn].forEach(el => right.appendChild(el));\n toolbar.appendChild(right);\n\n // Pin overlay layer (positioned over the canvas)\n const pinLayer = document.createElement('div');\n pinLayer.className = 'bs-ann-pins';\n // Pin list below toolbar\n const pinList = document.createElement('div');\n pinList.className = 'bs-ann-pin-list';\n pinList.style.display = 'none';\n\n viewport.appendChild(canvas);\n viewport.appendChild(pinLayer);\n wrap.appendChild(viewport);\n wrap.appendChild(toolbar);\n wrap.appendChild(pinList);\n container.innerHTML = '';\n container.appendChild(wrap);\n\n // ── Pin rendering ──\n const renderPins = () => {\n pinLayer.innerHTML = '';\n pinList.innerHTML = '';\n pinList.style.display = pins.length ? '' : 'none';\n\n pins.forEach((pin, i) => {\n // Pin marker on canvas\n const el = document.createElement('div');\n el.className = 'bs-ann-pin';\n el.style.background = pin.color;\n el.style.color = pin.color;\n // Position as percentage of viewport\n const pctX = (pin.x / (canvas.width || 1)) * 100;\n const pctY = (pin.y / (canvas.height || 1)) * 100;\n el.style.left = `${pctX}%`;\n el.style.top = `${pctY}%`;\n el.innerHTML = `<span class=\"bs-ann-pin-n\">${i + 1}</span><span class=\"bs-ann-pin-pulse\"></span>`;\n el.title = `#${i + 1}: ${pin.note}`;\n\n // Drag pin\n let pinDragging = false;\n el.addEventListener('mousedown', (e) => {\n e.stopPropagation();\n pinDragging = true;\n el.classList.add('bs-dragging');\n const onMove = (me: MouseEvent) => {\n if (!pinDragging) return;\n const r = viewport.getBoundingClientRect();\n pin.x = ((me.clientX - r.left) / r.width) * canvas.width;\n pin.y = ((me.clientY - r.top) / r.height) * canvas.height;\n el.style.left = `${((me.clientX - r.left) / r.width) * 100}%`;\n el.style.top = `${((me.clientY - r.top) / r.height) * 100}%`;\n };\n const onUp = () => {\n pinDragging = false;\n el.classList.remove('bs-dragging');\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n renderPins(); // refresh list coords\n };\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n });\n pinLayer.appendChild(el);\n\n // Pin list item\n const item = document.createElement('div');\n item.className = 'bs-ann-pin-item';\n item.innerHTML = `\n <div class=\"bs-ann-pin-num\" style=\"background:${pin.color}\">${i + 1}</div>\n <div class=\"bs-ann-pin-body\">\n <div class=\"bs-ann-pin-note\">${esc(pin.note)}</div>\n <div class=\"bs-ann-pin-loc\">${Math.round(pctX)}% × ${Math.round(pctY)}%</div>\n </div>`;\n const del = document.createElement('button');\n del.type = 'button';\n del.className = 'bs-ann-pin-del';\n del.innerHTML = '&times;';\n del.title = 'Remove pin';\n del.addEventListener('click', () => {\n pins.splice(i, 1);\n renderPins();\n });\n item.appendChild(del);\n pinList.appendChild(item);\n });\n };\n\n // ── Render engine ──\n let ctx: CanvasRenderingContext2D;\n const outlineColor = () => isDark ? 'rgba(255,255,255,0.5)' : 'rgba(0,0,0,0.35)';\n\n const drawOutline = (fn: () => void, lw: number) => {\n // Draw shadow outline for contrast on any background\n ctx.save();\n ctx.strokeStyle = outlineColor();\n ctx.lineWidth = lw + 3;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n ctx.globalAlpha = 0.5;\n fn();\n ctx.restore();\n };\n\n const renderShape = (s: AnnObj, preview = false) => {\n if (s.type === 'draw' || s.type === 'highlight') {\n if (s.points.length < 2) return;\n const alpha = s.type === 'highlight' ? 0.25 : 1;\n const lw = s.type === 'highlight' ? s.size * 4 + 10 : s.size;\n const stroke = () => {\n ctx.beginPath();\n ctx.moveTo(s.points[0].x, s.points[0].y);\n for (let i = 1; i < s.points.length; i++) ctx.lineTo(s.points[i].x, s.points[i].y);\n ctx.stroke();\n };\n if (s.type !== 'highlight') drawOutline(stroke, lw);\n ctx.strokeStyle = s.color; ctx.lineWidth = lw;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n ctx.globalAlpha = alpha;\n stroke();\n ctx.globalAlpha = 1;\n } else if (s.type === 'rect') {\n const stroke = () => ctx.strokeRect(s.x, s.y, s.w, s.h);\n drawOutline(stroke, s.size);\n ctx.strokeStyle = s.color; ctx.lineWidth = s.size;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n stroke();\n } else if (s.type === 'circle') {\n const stroke = () => { ctx.beginPath(); ctx.ellipse(s.cx, s.cy, Math.abs(s.rx), Math.abs(s.ry), 0, 0, Math.PI * 2); ctx.stroke(); };\n drawOutline(stroke, s.size);\n ctx.strokeStyle = s.color; ctx.lineWidth = s.size;\n stroke();\n } else if (s.type === 'arrow') {\n const angle = Math.atan2(s.y2 - s.y1, s.x2 - s.x1);\n const headLen = 12 + s.size * 2;\n const stroke = () => {\n ctx.beginPath(); ctx.moveTo(s.x1, s.y1); ctx.lineTo(s.x2, s.y2); ctx.stroke();\n ctx.beginPath();\n ctx.moveTo(s.x2, s.y2);\n ctx.lineTo(s.x2 - headLen * Math.cos(angle - 0.45), s.y2 - headLen * Math.sin(angle - 0.45));\n ctx.moveTo(s.x2, s.y2);\n ctx.lineTo(s.x2 - headLen * Math.cos(angle + 0.45), s.y2 - headLen * Math.sin(angle + 0.45));\n ctx.stroke();\n };\n drawOutline(stroke, s.size);\n ctx.strokeStyle = s.color; ctx.lineWidth = s.size;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n stroke();\n } else if (s.type === 'text') {\n const fontSize = s.size * 5 + 12;\n ctx.font = `bold ${fontSize}px Inter, -apple-system, sans-serif`;\n // text shadow for contrast\n ctx.fillStyle = outlineColor();\n ctx.globalAlpha = 0.6;\n ctx.fillText(s.text, s.x + 1, s.y + 1);\n ctx.globalAlpha = 1;\n ctx.fillStyle = s.color;\n ctx.fillText(s.text, s.x, s.y);\n }\n\n // Selection / hover highlight\n const isSelected = !preview && selectedIdx >= 0 && shapes[selectedIdx] === s;\n const isHovered = !preview && !isSelected && hoveredIdx >= 0 && shapes[hoveredIdx] === s;\n if (isSelected || isHovered) {\n const b = shapeBounds(s);\n ctx.save();\n ctx.setLineDash([6, 4]);\n ctx.strokeStyle = isDark ? '#fff' : '#000';\n ctx.lineWidth = isSelected ? 1.5 : 1;\n ctx.globalAlpha = isSelected ? 0.7 : 0.45;\n ctx.strokeRect(b.x - 4, b.y - 4, b.w + 8, b.h + 8);\n\n // Corner/cardinal handles for rects and circles\n if (s.type === 'rect' || s.type === 'circle') {\n const hSize = 5;\n ctx.setLineDash([]);\n ctx.globalAlpha = isSelected ? 0.9 : 0.6;\n const handles: [number, number][] = s.type === 'rect'\n ? [[b.x, b.y], [b.x + b.w, b.y], [b.x, b.y + b.h], [b.x + b.w, b.y + b.h]]\n : [[b.x + b.w / 2, b.y], [b.x + b.w, b.y + b.h / 2], [b.x + b.w / 2, b.y + b.h], [b.x, b.y + b.h / 2]];\n for (const [hx, hy] of handles) {\n ctx.fillStyle = '#fff';\n ctx.fillRect(hx - hSize, hy - hSize, hSize * 2, hSize * 2);\n ctx.strokeStyle = isDark ? '#aaa' : '#333';\n ctx.lineWidth = 1.2;\n ctx.strokeRect(hx - hSize, hy - hSize, hSize * 2, hSize * 2);\n }\n }\n ctx.restore();\n }\n };\n\n const render = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(img, 0, 0);\n for (const s of shapes) renderShape(s);\n };\n\n // ── Hit testing & bounds ──\n const shapeBounds = (s: AnnObj): { x: number; y: number; w: number; h: number } => {\n if (s.type === 'rect') return { x: Math.min(s.x, s.x + s.w), y: Math.min(s.y, s.y + s.h), w: Math.abs(s.w), h: Math.abs(s.h) };\n if (s.type === 'circle') return { x: s.cx - Math.abs(s.rx), y: s.cy - Math.abs(s.ry), w: Math.abs(s.rx) * 2, h: Math.abs(s.ry) * 2 };\n if (s.type === 'arrow') {\n const x = Math.min(s.x1, s.x2), y = Math.min(s.y1, s.y2);\n return { x, y, w: Math.abs(s.x2 - s.x1) || 20, h: Math.abs(s.y2 - s.y1) || 20 };\n }\n if (s.type === 'text') return { x: s.x, y: s.y - (s.size * 5 + 12), w: s.text.length * (s.size * 3 + 8), h: s.size * 5 + 16 };\n // draw / highlight: bounding box of points\n if (s.points.length === 0) return { x: 0, y: 0, w: 0, h: 0 };\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of s.points) { minX = Math.min(minX, p.x); minY = Math.min(minY, p.y); maxX = Math.max(maxX, p.x); maxY = Math.max(maxY, p.y); }\n return { x: minX, y: minY, w: maxX - minX || 10, h: maxY - minY || 10 };\n };\n\n const hitTest = (x: number, y: number): number => {\n for (let i = shapes.length - 1; i >= 0; i--) {\n const b = shapeBounds(shapes[i]);\n const pad = 8;\n if (x >= b.x - pad && x <= b.x + b.w + pad && y >= b.y - pad && y <= b.y + b.h + pad) return i;\n }\n return -1;\n };\n\n const moveShape = (s: AnnObj, dx: number, dy: number) => {\n if (s.type === 'draw' || s.type === 'highlight') { for (const p of s.points) { p.x += dx; p.y += dy; } }\n else if (s.type === 'rect') { s.x += dx; s.y += dy; }\n else if (s.type === 'circle') { s.cx += dx; s.cy += dy; }\n else if (s.type === 'arrow') { s.x1 += dx; s.y1 += dy; s.x2 += dx; s.y2 += dy; }\n else if (s.type === 'text') { s.x += dx; s.y += dy; }\n };\n\n img.onload = () => {\n const maxW = container.clientWidth || 450;\n const scale = maxW / img.width;\n canvas.width = img.width;\n canvas.height = img.height;\n canvas.style.height = `${img.height * scale}px`;\n ctx = canvas.getContext('2d')!;\n ctx.drawImage(img, 0, 0);\n\n // Detect brightness: sample corners + center\n const samplePoints = [[10, 10], [canvas.width - 10, 10], [10, canvas.height - 10], [canvas.width - 10, canvas.height - 10], [canvas.width / 2, canvas.height / 2]];\n let totalBrightness = 0;\n for (const [sx, sy] of samplePoints) {\n const px = ctx.getImageData(sx, sy, 1, 1).data;\n totalBrightness += (px[0] * 299 + px[1] * 587 + px[2] * 114) / 1000;\n }\n isDark = (totalBrightness / samplePoints.length) < 128;\n\n const coords = (e: MouseEvent) => {\n const r = canvas.getBoundingClientRect();\n return { x: (e.clientX - r.left) * (canvas.width / r.width), y: (e.clientY - r.top) * (canvas.height / r.height) };\n };\n\n let autoSelectDrag = false; // true when we auto-switched to drag on hover-hit\n\n canvas.addEventListener('mousedown', e => {\n const c = coords(e);\n\n // Select mode: pick or drag\n if (currentTool === 'select') {\n const hit = hitTest(c.x, c.y);\n if (hit >= 0) {\n selectedIdx = hit;\n dragging = true;\n const b = shapeBounds(shapes[hit]);\n dragOffX = c.x - b.x;\n dragOffY = c.y - b.y;\n canvas.classList.add('bs-grabbing');\n canvas.classList.remove('bs-grab');\n render();\n } else {\n selectedIdx = -1;\n render();\n }\n return;\n }\n\n // Auto-drag: if hovering a shape in any drawing tool, grab it instead\n if (currentTool !== 'pin' && currentTool !== 'text') {\n const hit = hitTest(c.x, c.y);\n if (hit >= 0) {\n selectedIdx = hit;\n dragging = true;\n autoSelectDrag = true;\n const b = shapeBounds(shapes[hit]);\n dragOffX = c.x - b.x;\n dragOffY = c.y - b.y;\n canvas.classList.add('bs-grabbing');\n render();\n return;\n }\n }\n\n drawing = true;\n startX = c.x; startY = c.y;\n\n if (currentTool === 'pin') {\n drawing = false;\n const note = prompt('Describe the issue at this spot:');\n if (note) {\n const color = PIN_COLORS[pins.length % PIN_COLORS.length];\n pins.push({ x: c.x, y: c.y, note, color });\n renderPins();\n }\n return;\n }\n\n if (currentTool === 'text') {\n drawing = false;\n const input = prompt('Enter text:');\n if (input) {\n shapes.push({ type: 'text', color: currentColor, size: brushSize, x: c.x, y: c.y, text: input });\n render();\n }\n return;\n }\n\n if (currentTool === 'draw' || currentTool === 'highlight') {\n currentDraw = [{ x: c.x, y: c.y }];\n }\n });\n\n canvas.addEventListener('mousemove', e => {\n const c = coords(e);\n\n // Active drag (select mode or auto-drag from any tool)\n if (dragging && selectedIdx >= 0) {\n const b = shapeBounds(shapes[selectedIdx]);\n const dx = c.x - dragOffX - b.x;\n const dy = c.y - dragOffY - b.y;\n moveShape(shapes[selectedIdx], dx, dy);\n render();\n return;\n }\n\n // Select mode hover\n if (currentTool === 'select') {\n const hit = hitTest(c.x, c.y);\n canvas.classList.toggle('bs-grab', hit >= 0);\n if (hoveredIdx !== hit) { hoveredIdx = hit; render(); }\n return;\n }\n\n // Any tool: show grab cursor when hovering a shape\n if (currentTool !== 'pin' && currentTool !== 'text' && !drawing) {\n const hit = hitTest(c.x, c.y);\n canvas.classList.toggle('bs-grab', hit >= 0);\n if (hoveredIdx !== hit) { hoveredIdx = hit; render(); }\n }\n\n if (!drawing) return;\n\n if (currentTool === 'draw' || currentTool === 'highlight') {\n currentDraw.push({ x: c.x, y: c.y });\n // Live preview\n render();\n const alpha = currentTool === 'highlight' ? 0.25 : 1;\n const lw = currentTool === 'highlight' ? brushSize * 4 + 10 : brushSize;\n if (currentTool !== 'highlight') {\n ctx.save();\n ctx.strokeStyle = outlineColor(); ctx.lineWidth = lw + 3;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.globalAlpha = 0.5;\n ctx.beginPath(); ctx.moveTo(currentDraw[0].x, currentDraw[0].y);\n for (let i = 1; i < currentDraw.length; i++) ctx.lineTo(currentDraw[i].x, currentDraw[i].y);\n ctx.stroke(); ctx.restore();\n }\n ctx.strokeStyle = currentColor; ctx.lineWidth = lw;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.globalAlpha = alpha;\n ctx.beginPath(); ctx.moveTo(currentDraw[0].x, currentDraw[0].y);\n for (let i = 1; i < currentDraw.length; i++) ctx.lineTo(currentDraw[i].x, currentDraw[i].y);\n ctx.stroke(); ctx.globalAlpha = 1;\n } else {\n // Shape preview\n render();\n ctx.strokeStyle = currentColor; ctx.lineWidth = brushSize;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n if (currentTool === 'rect') {\n drawOutline(() => ctx.strokeRect(startX, startY, c.x - startX, c.y - startY), brushSize);\n ctx.strokeStyle = currentColor; ctx.lineWidth = brushSize;\n ctx.strokeRect(startX, startY, c.x - startX, c.y - startY);\n } else if (currentTool === 'circle') {\n const rx = Math.abs(c.x - startX) / 2, ry = Math.abs(c.y - startY) / 2;\n const cx2 = startX + (c.x - startX) / 2, cy2 = startY + (c.y - startY) / 2;\n drawOutline(() => { ctx.beginPath(); ctx.ellipse(cx2, cy2, rx, ry, 0, 0, Math.PI * 2); ctx.stroke(); }, brushSize);\n ctx.strokeStyle = currentColor; ctx.lineWidth = brushSize;\n ctx.beginPath(); ctx.ellipse(cx2, cy2, rx, ry, 0, 0, Math.PI * 2); ctx.stroke();\n } else if (currentTool === 'arrow') {\n const angle = Math.atan2(c.y - startY, c.x - startX);\n const headLen = 12 + brushSize * 2;\n const stroke = () => {\n ctx.beginPath(); ctx.moveTo(startX, startY); ctx.lineTo(c.x, c.y); ctx.stroke();\n ctx.beginPath();\n ctx.moveTo(c.x, c.y);\n ctx.lineTo(c.x - headLen * Math.cos(angle - 0.45), c.y - headLen * Math.sin(angle - 0.45));\n ctx.moveTo(c.x, c.y);\n ctx.lineTo(c.x - headLen * Math.cos(angle + 0.45), c.y - headLen * Math.sin(angle + 0.45));\n ctx.stroke();\n };\n drawOutline(stroke, brushSize);\n ctx.strokeStyle = currentColor; ctx.lineWidth = brushSize;\n ctx.lineCap = 'round'; ctx.lineJoin = 'round';\n stroke();\n }\n }\n });\n\n const endDraw = (e: MouseEvent) => {\n // Release auto-drag or select-mode drag\n if (dragging) {\n dragging = false;\n autoSelectDrag = false;\n selectedIdx = -1;\n canvas.classList.remove('bs-grabbing');\n canvas.classList.remove('bs-grab');\n render();\n if (currentTool === 'select') return;\n // For auto-drag from other tools, just stop — don't create a shape\n return;\n }\n if (!drawing) return;\n drawing = false;\n const c = coords(e);\n\n if (currentTool === 'draw' || currentTool === 'highlight') {\n if (currentDraw.length > 1) {\n shapes.push({ type: currentTool, color: currentColor, size: brushSize, alpha: currentTool === 'highlight' ? 0.25 : 1, points: [...currentDraw] });\n }\n currentDraw = [];\n } else if (currentTool === 'rect') {\n shapes.push({ type: 'rect', color: currentColor, size: brushSize, x: startX, y: startY, w: c.x - startX, h: c.y - startY });\n } else if (currentTool === 'circle') {\n const rx = Math.abs(c.x - startX) / 2, ry = Math.abs(c.y - startY) / 2;\n shapes.push({ type: 'circle', color: currentColor, size: brushSize, cx: startX + (c.x - startX) / 2, cy: startY + (c.y - startY) / 2, rx, ry });\n } else if (currentTool === 'arrow') {\n shapes.push({ type: 'arrow', color: currentColor, size: brushSize, x1: startX, y1: startY, x2: c.x, y2: c.y });\n }\n render();\n };\n\n canvas.addEventListener('mouseup', endDraw);\n canvas.addEventListener('mouseleave', (e) => {\n if (dragging) { dragging = false; autoSelectDrag = false; canvas.classList.remove('bs-grabbing'); canvas.classList.remove('bs-grab'); render(); }\n else if (drawing) endDraw(e);\n });\n\n // Delete selected with Backspace/Delete\n const keyHandler = (e: KeyboardEvent) => {\n if (selectedIdx >= 0 && (e.key === 'Delete' || e.key === 'Backspace')) {\n shapes.splice(selectedIdx, 1);\n selectedIdx = -1;\n render();\n }\n };\n document.addEventListener('keydown', keyHandler);\n\n undoBtn.addEventListener('click', () => {\n if (shapes.length) {\n shapes.pop();\n selectedIdx = -1;\n render();\n }\n });\n\n clearBtn.addEventListener('click', () => {\n shapes.length = 0;\n pins.length = 0;\n selectedIdx = -1;\n render();\n renderPins();\n });\n };\n\n // Draw pins onto canvas for final export\n const bakePins = () => {\n for (let i = 0; i < pins.length; i++) {\n const p = pins[i];\n const r = 16;\n // Pin circle\n ctx.beginPath();\n ctx.arc(p.x, p.y - r, r, 0, Math.PI * 2);\n ctx.fillStyle = p.color;\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2;\n ctx.stroke();\n // Pin tail\n ctx.beginPath();\n ctx.moveTo(p.x - 8, p.y - 6);\n ctx.lineTo(p.x, p.y + 4);\n ctx.lineTo(p.x + 8, p.y - 6);\n ctx.fillStyle = p.color;\n ctx.fill();\n // Number\n ctx.fillStyle = '#fff';\n ctx.font = 'bold 14px Inter, sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(`${i + 1}`, p.x, p.y - r);\n ctx.textAlign = 'start';\n ctx.textBaseline = 'alphabetic';\n }\n };\n\n return {\n getAnnotation: () => {\n try {\n selectedIdx = -1;\n render();\n bakePins();\n return canvas.toDataURL('image/jpeg', 0.7);\n } catch { return null; }\n },\n getPins: () => pins.map((p, i) => ({ number: i + 1, x: Math.round(p.x), y: Math.round(p.y), note: p.note })),\n };\n}\n\n// ─── Switch Tab ──────────────────────────────────────────\n\nfunction switchTab(tab: typeof activeTab) {\n if (!modal) return;\n activeTab = tab;\n\n // Update tab buttons\n modal.querySelectorAll('.bs-tab').forEach(el => {\n el.classList.toggle('bs-active', (el as HTMLElement).dataset.tab === tab);\n });\n\n // Render content\n const scroll = modal.querySelector('.bs-scroll')!;\n const renderers: Record<typeof activeTab, () => string> = {\n report: tabReport,\n console: tabConsole,\n network: tabNetwork,\n context: tabContext,\n history: tabHistory,\n settings: tabSettings,\n };\n scroll.innerHTML = renderers[tab]();\n scroll.scrollTop = 0;\n bindTabContent();\n}\n\nfunction bindTabContent() {\n if (!modal) return;\n\n if (activeTab === 'history') {\n // Delete buttons\n modal.querySelectorAll('[data-hist-del]').forEach(btn => {\n btn.addEventListener('click', () => {\n const id = parseInt((btn as HTMLElement).dataset.histDel!);\n const card = modal!.querySelector(`[data-hist-id=\"${id}\"]`);\n if (!card) return;\n // Show confirm inline\n const existing = card.querySelector('.bs-hist-confirm');\n if (existing) { existing.remove(); return; }\n const confirm = document.createElement('div');\n confirm.className = 'bs-hist-confirm';\n confirm.innerHTML = `<span>Delete this report?</span>`;\n const yes = document.createElement('button');\n yes.type = 'button'; yes.className = 'bs-hist-confirm-yes'; yes.textContent = 'Delete';\n const no = document.createElement('button');\n no.type = 'button'; no.className = 'bs-hist-confirm-no'; no.textContent = 'Cancel';\n yes.addEventListener('click', () => {\n deleteFromHistory(id);\n switchTab('history');\n });\n no.addEventListener('click', () => confirm.remove());\n confirm.appendChild(yes);\n confirm.appendChild(no);\n card.appendChild(confirm);\n });\n });\n\n // Edit buttons\n modal.querySelectorAll('[data-hist-edit]').forEach(btn => {\n btn.addEventListener('click', () => {\n const id = parseInt((btn as HTMLElement).dataset.histEdit!);\n const card = modal!.querySelector(`[data-hist-id=\"${id}\"]`);\n if (!card) return;\n const existing = card.querySelector('.bs-hist-edit-wrap');\n if (existing) { existing.remove(); return; }\n // Remove any confirm dialogs\n card.querySelector('.bs-hist-confirm')?.remove();\n\n const entry = getReportHistory().find(e => e.id === id);\n if (!entry) return;\n\n const wrap = document.createElement('div');\n wrap.className = 'bs-hist-edit-wrap';\n wrap.innerHTML = `\n <div class=\"bs-field\" style=\"margin-bottom:8px\">\n <input class=\"bs-input\" data-edit-title value=\"${esc(entry.title)}\" />\n </div>\n <div class=\"bs-field\" style=\"margin-bottom:8px\">\n <textarea class=\"bs-textarea\" data-edit-desc style=\"min-height:56px\">${esc(entry.description)}</textarea>\n </div>\n <div class=\"bs-field\" style=\"margin-bottom:8px\">\n <div class=\"bs-sev-row\">\n <button type=\"button\" class=\"bs-sev-btn bs-sev-low${entry.severity === 'low' ? ' bs-picked' : ''}\" data-edit-sev=\"low\">Low</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-medium${entry.severity === 'medium' ? ' bs-picked' : ''}\" data-edit-sev=\"medium\">Medium</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-high${entry.severity === 'high' ? ' bs-picked' : ''}\" data-edit-sev=\"high\">High</button>\n <button type=\"button\" class=\"bs-sev-btn bs-sev-critical${entry.severity === 'critical' ? ' bs-picked' : ''}\" data-edit-sev=\"critical\">Critical</button>\n </div>\n </div>\n <div class=\"bs-hist-edit-row\"></div>`;\n\n let editSev = entry.severity;\n card.appendChild(wrap);\n\n // Severity picker in edit\n wrap.querySelectorAll('[data-edit-sev]').forEach(sb => {\n sb.addEventListener('click', () => {\n editSev = (sb as HTMLElement).dataset.editSev!;\n wrap.querySelectorAll('.bs-sev-btn').forEach(b => b.classList.remove('bs-picked'));\n sb.classList.add('bs-picked');\n });\n });\n\n const row = wrap.querySelector('.bs-hist-edit-row')!;\n const save = document.createElement('button');\n save.type = 'button'; save.className = 'bs-hist-save'; save.textContent = 'Save';\n const cancel = document.createElement('button');\n cancel.type = 'button'; cancel.className = 'bs-hist-cancel'; cancel.textContent = 'Cancel';\n\n save.addEventListener('click', () => {\n const newTitle = (wrap.querySelector('[data-edit-title]') as HTMLInputElement).value.trim();\n const newDesc = (wrap.querySelector('[data-edit-desc]') as HTMLTextAreaElement).value.trim();\n if (!newTitle) return;\n updateInHistory(id, { title: newTitle, description: newDesc, severity: editSev });\n switchTab('history');\n });\n cancel.addEventListener('click', () => wrap.remove());\n row.appendChild(save);\n row.appendChild(cancel);\n });\n });\n return;\n }\n\n if (activeTab === 'settings') {\n // Theme picker\n modal.querySelectorAll('[data-set-theme]').forEach(btn => {\n btn.addEventListener('click', () => {\n const id = (btn as HTMLElement).dataset.setTheme!;\n setTheme(id);\n // Update picked state\n modal!.querySelectorAll('[data-set-theme]').forEach(b => b.classList.remove('bs-picked'));\n btn.classList.add('bs-picked');\n });\n });\n // Layout picker\n modal.querySelectorAll('[data-set-layout]').forEach(btn => {\n btn.addEventListener('click', () => {\n const id = (btn as HTMLElement).dataset.setLayout!;\n const layout = getLayoutById(id);\n if (!layout) return;\n currentLayout = layout;\n // Close and reopen with new layout\n close();\n setTimeout(() => {\n activeTab = 'settings';\n open();\n // After open, switch to settings tab\n setTimeout(() => switchTab('settings'), 50);\n }, 400);\n });\n });\n return;\n }\n\n if (activeTab !== 'report') return;\n\n // Category\n modal.querySelectorAll('.bs-cat-btn').forEach(btn => {\n btn.addEventListener('click', () => {\n const cat = (btn as HTMLElement).dataset.cat!;\n (modal!.querySelector('input[name=\"category\"]') as HTMLInputElement).value = cat;\n modal!.querySelectorAll('.bs-cat-btn').forEach(b => b.classList.remove('bs-picked'));\n btn.classList.add('bs-picked');\n });\n });\n\n // Severity\n modal.querySelectorAll('.bs-sev-btn').forEach(btn => {\n btn.addEventListener('click', () => {\n const sev = (btn as HTMLElement).dataset.sev!;\n (modal!.querySelector('input[name=\"severity\"]') as HTMLInputElement).value = sev;\n modal!.querySelectorAll('.bs-sev-btn').forEach(b => b.classList.remove('bs-picked'));\n btn.classList.add('bs-picked');\n });\n });\n\n // Screenshot\n let screenshotData: string | null = null;\n let annotator: { getAnnotation: () => string | null; getPins: () => { number: number; x: number; y: number; note: string }[] } | null = null;\n\n modal.querySelector('[data-bs-screenshot]')?.addEventListener('click', async () => {\n const titleEl = modal?.querySelector('[data-bs-shot-title]');\n const subEl = modal?.querySelector('[data-bs-shot-sub]');\n const area = modal?.querySelector('[data-bs-screenshot]');\n if (titleEl) titleEl.textContent = 'Capturing...';\n\n if (modal) modal.style.visibility = 'hidden';\n if (backdrop) backdrop.style.visibility = 'hidden';\n await new Promise(r => setTimeout(r, 200));\n screenshotData = await captureScreenshot(true);\n if (modal) modal.style.visibility = '';\n if (backdrop) backdrop.style.visibility = '';\n\n if (screenshotData) {\n if (titleEl) titleEl.textContent = 'Screenshot captured!';\n if (subEl) subEl.textContent = 'Draw on the image below to highlight the issue';\n area?.classList.add('bs-captured');\n const container = modal?.querySelector('[data-bs-annotate]') as HTMLElement;\n if (container) annotator = setupAnnotation(container, screenshotData);\n } else {\n if (titleEl) titleEl.textContent = 'Screenshot unavailable';\n if (subEl) subEl.textContent = 'Could not capture screenshot on this page';\n }\n });\n\n // Submit\n modal.querySelector('[data-bs-form]')?.addEventListener('submit', async (e) => {\n e.preventDefault();\n const form = e.target as HTMLFormElement;\n const btn = form.querySelector('.bs-submit-btn') as HTMLButtonElement;\n\n const title = (form.elements.namedItem('title') as HTMLInputElement).value.trim();\n const description = (form.elements.namedItem('description') as HTMLTextAreaElement).value.trim();\n const severity = (form.elements.namedItem('severity') as HTMLInputElement).value as BugReport['severity'];\n const category = (form.elements.namedItem('category') as HTMLInputElement).value as BugReport['category'];\n\n if (!title) return;\n\n btn.disabled = true;\n btn.textContent = 'Sending...';\n\n const detected = autoDetect();\n\n const report: BugReport = {\n projectId: config.projectId,\n title,\n description,\n category,\n severity,\n tags: detected.tags.length ? detected.tags : undefined,\n context: buildContext(),\n consoleLogs: getLogs(),\n errors: getErrors(),\n networkCaptures: getFailedNetworkCaptures(),\n breadcrumbs: getBreadcrumbs(),\n performance: getPerformanceMetrics() ?? undefined,\n screenshot: screenshotData ?? undefined,\n annotation: annotator?.getAnnotation() ?? undefined,\n pins: annotator?.getPins().length ? annotator.getPins() : undefined,\n createdAt: Date.now(),\n };\n\n const result = await submitReport(report);\n\n // Save to history\n addToHistory({\n title: report.title,\n description: report.description,\n category: report.category,\n severity: report.severity,\n tags: report.tags,\n screenshot: report.screenshot,\n pins: report.pins,\n url: window.location.href,\n createdAt: report.createdAt,\n status: result.success ? 'sent' : 'draft',\n });\n\n if (result.success) {\n btn.innerHTML = `${I.check} Bug reported!`;\n btn.classList.add('bs-submit-ok');\n setTimeout(close, 1200);\n } else {\n btn.textContent = result.error ?? 'Failed — saved as draft';\n btn.classList.add('bs-submit-err');\n setTimeout(() => {\n btn.disabled = false;\n btn.textContent = 'Submit Report';\n btn.classList.remove('bs-submit-err');\n }, 2500);\n }\n });\n}\n\n// ─── Open / Close ────────────────────────────────────────\n\nfunction open() {\n if (!iframeDoc || isOpen) return;\n isOpen = true;\n activeTab = 'report';\n hideToolbar();\n\n // Show iframe for modal content\n if (iframeEl) {\n iframeEl.style.display = '';\n iframeEl.style.pointerEvents = 'auto';\n }\n\n backdrop = iframeDoc.createElement('div') as HTMLDivElement;\n backdrop.className = 'bs-backdrop';\n iframeDoc.body.appendChild(backdrop);\n\n const fails = getFailedNetworkCaptures().length;\n const errs = getErrors().length;\n\n modal = iframeDoc.createElement('div') as HTMLDivElement;\n modal.className = `bs-modal bs-ly-${currentLayout.id}`;\n applyThemeVars(modal);\n\n const tabsHtml = `\n <div class=\"bs-tabs\">\n <button class=\"bs-tab bs-active\" data-tab=\"report\">${I.report} Report</button>\n <button class=\"bs-tab\" data-tab=\"console\">${I.console} Console <span class=\"bs-tab-badge\">${getLogs().length}</span></button>\n <button class=\"bs-tab\" data-tab=\"network\">${I.network} Network ${fails ? `<span class=\"bs-tab-badge bs-warn\">${fails}</span>` : `<span class=\"bs-tab-badge\">${getNetworkCaptures().length}</span>`}</button>\n <button class=\"bs-tab\" data-tab=\"context\">${I.ctx} Context ${errs ? `<span class=\"bs-tab-badge bs-warn\">${errs}</span>` : ''}</button>\n <button class=\"bs-tab\" data-tab=\"history\">${I.history} History <span class=\"bs-tab-badge\">${getReportHistory().length}</span></button>\n </div>`;\n\n const user = getCurrentUser();\n const initials = user ? user.name.split(' ').map(w => w[0]).join('').toUpperCase().slice(0, 2) : '';\n const pinActive = isPinModeActive();\n\n const headerHtml = user ? `\n <div class=\"bs-hdr\">\n <div class=\"bs-logo\">BugStash</div>\n <div class=\"bs-hdr-right\">\n <button class=\"bs-pin-toggle${pinActive ? ' active' : ''}\" data-bs-pin-toggle title=\"Toggle pin mode\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>\n Pins ${pinActive ? 'ON' : 'OFF'}\n </button>\n <div class=\"bs-user-badge\">\n <div class=\"bs-user-avatar\">${initials}</div>\n <span>${user.name.split(' ')[0]}</span>\n </div>\n <button class=\"bs-hdr-icon\" data-tab=\"settings\" title=\"Settings\">${I.settings}</button>\n <button class=\"bs-login-logout\" data-bs-logout title=\"Sign out\">Logout</button>\n <button class=\"bs-close-btn\" data-bs-close title=\"Close\">${I.x}</button>\n </div>\n </div>` : `\n <div class=\"bs-hdr\" style=\"justify-content:flex-end\">\n <button class=\"bs-close-btn\" data-bs-close title=\"Close\">${I.x}</button>\n </div>`;\n\n const useSidebar = currentLayout.tabPosition === 'left';\n const useBottomTabs = currentLayout.tabPosition === 'bottom';\n\n // If not logged in, show login form instead of tabs\n const contentHtml = user ? tabReport() : tabLogin();\n\n if (useSidebar) {\n modal.innerHTML = `\n ${headerHtml}\n <div class=\"bs-body-wrap\">\n ${user ? tabsHtml : ''}\n <div class=\"bs-scroll\">${contentHtml}</div>\n </div>`;\n } else if (useBottomTabs) {\n modal.innerHTML = `\n ${headerHtml}\n <div class=\"bs-scroll\">${contentHtml}</div>\n ${user ? `<div class=\"bs-tab-divider\"></div>${tabsHtml}` : ''}`;\n } else {\n modal.innerHTML = `\n ${headerHtml}\n ${user ? `${tabsHtml}<div class=\"bs-tab-divider\"></div>` : ''}\n <div class=\"bs-scroll\">${contentHtml}</div>`;\n }\n iframeDoc!.body.appendChild(modal);\n\n if (fab) fab.classList.add('bs-open');\n\n requestAnimationFrame(() => {\n backdrop?.classList.add('bs-in');\n modal?.classList.add('bs-in');\n });\n\n // Tab switching\n modal.querySelectorAll('.bs-tab').forEach(tab => {\n tab.addEventListener('click', () => switchTab((tab as HTMLElement).dataset.tab as typeof activeTab));\n });\n\n // Header settings icon\n modal.querySelector('.bs-hdr-icon[data-tab=\"settings\"]')?.addEventListener('click', () => switchTab('settings'));\n\n modal.querySelector('[data-bs-close]')?.addEventListener('click', close);\n backdrop.addEventListener('click', close);\n\n // Pin toggle\n modal.querySelector('[data-bs-pin-toggle]')?.addEventListener('click', () => {\n const active = togglePinMode();\n const btn = modal?.querySelector('[data-bs-pin-toggle]');\n if (btn) {\n btn.classList.toggle('active', active);\n btn.innerHTML = `\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>\n Pins ${active ? 'ON' : 'OFF'}\n `;\n }\n });\n\n // Logout\n modal.querySelector('[data-bs-logout]')?.addEventListener('click', () => {\n apiLogout();\n close();\n // Reopen to show login form\n setTimeout(() => open(), 300);\n });\n\n // Login form binding\n if (!user) {\n bindLoginForm();\n } else {\n bindTabContent();\n }\n\n const escHandler = (e: KeyboardEvent) => { if (e.key === 'Escape') { close(); document.removeEventListener('keydown', escHandler); } };\n document.addEventListener('keydown', escHandler);\n}\n\nfunction bindLoginForm() {\n if (!modal) return;\n\n const submitBtn = modal.querySelector('#bs-login-submit');\n const emailInput = modal.querySelector('#bs-login-email') as HTMLInputElement;\n const passInput = modal.querySelector('#bs-login-pass') as HTMLInputElement;\n const errorEl = modal.querySelector('#bs-login-error') as HTMLElement;\n\n if (!submitBtn || !emailInput || !passInput) return;\n\n const doLogin = async () => {\n const email = emailInput.value.trim();\n const password = passInput.value;\n\n if (!email || !password) {\n errorEl.textContent = 'Please enter email and password';\n errorEl.style.display = 'block';\n return;\n }\n\n submitBtn.setAttribute('disabled', 'true');\n (submitBtn as HTMLButtonElement).textContent = 'Signing in...';\n errorEl.style.display = 'none';\n\n const result = await apiLogin(email, password, config.projectId);\n\n if (result.success) {\n // Initialize live pins + realtime now that user is logged in\n initLivePins(config.projectId, shadow!);\n connectRealtime(config.projectId);\n // Reopen panel with full UI\n close();\n setTimeout(() => open(), 300);\n } else {\n errorEl.textContent = result.error || 'Invalid credentials';\n errorEl.style.display = 'block';\n submitBtn.removeAttribute('disabled');\n (submitBtn as HTMLButtonElement).textContent = 'Sign In';\n }\n };\n\n submitBtn.addEventListener('click', doLogin);\n passInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') doLogin(); });\n emailInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') passInput.focus(); });\n\n // Auto-focus email\n setTimeout(() => emailInput.focus(), 100);\n}\n\nfunction close() {\n if (!isOpen) return;\n if (fab) fab.classList.remove('bs-open');\n if (modal) {\n modal.classList.remove('bs-in');\n modal.classList.add('bs-out');\n }\n if (backdrop) backdrop.classList.remove('bs-in');\n\n setTimeout(() => {\n modal?.remove();\n backdrop?.remove();\n modal = null;\n backdrop = null;\n isOpen = false;\n\n // Hide iframe when modal is closed\n if (iframeEl) {\n iframeEl.style.display = 'none';\n iframeEl.style.pointerEvents = 'none';\n }\n }, 350);\n}\n\n// ─── Theme ───────────────────────────────────────────────\n\nfunction applyThemeVars(el: HTMLElement) {\n for (const [key, val] of Object.entries(currentTheme.vars)) {\n el.style.setProperty(key, val);\n }\n}\n\nexport function setTheme(themeId: string) {\n const theme = getThemeById(themeId);\n if (!theme) return;\n currentTheme = theme;\n if (modal) applyThemeVars(modal);\n if (fab) applyThemeVars(fab);\n if (toolbar) applyThemeVars(toolbar);\n}\n\nexport function getCurrentThemeId(): string {\n return currentTheme.id;\n}\n\n// ─── Layout ──────────────────────────────────────────────\n\nexport function setLayout(layoutId: string) {\n const layout = getLayoutById(layoutId);\n if (!layout) return;\n currentLayout = layout;\n // If modal is open, close and reopen with new layout\n if (isOpen) {\n close();\n setTimeout(open, 400);\n }\n}\n\nexport function getCurrentLayoutId(): string {\n return currentLayout.id;\n}\n\n// ─── FAB Drag-to-Reposition ──────────────────────────────\n\nfunction getSavedFabPosition(): { top: number; left: number } | null {\n try {\n const raw = localStorage.getItem(FAB_STORAGE_KEY);\n if (!raw) return null;\n const pos = JSON.parse(raw);\n if (typeof pos.top === 'number' && typeof pos.left === 'number') return pos;\n } catch { /* ignore */ }\n return null;\n}\n\nfunction saveFabPosition(top: number, left: number): void {\n try {\n localStorage.setItem(FAB_STORAGE_KEY, JSON.stringify({ top, left }));\n } catch { /* ignore */ }\n}\n\nfunction clampFabToViewport(top: number, left: number): { top: number; left: number } {\n const pad = 8;\n const size = 56;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n return {\n top: Math.max(pad, Math.min(vh - size - pad, top)),\n left: Math.max(pad, Math.min(vw - size - pad, left)),\n };\n}\n\nfunction applyFabPosition(top: number, left: number): void {\n if (!fab) return;\n const clamped = clampFabToViewport(top, left);\n fab.style.top = `${clamped.top}px`;\n fab.style.left = `${clamped.left}px`;\n fab.style.bottom = 'auto';\n fab.style.right = 'auto';\n updateToolbarPosition(clamped.top, clamped.left);\n}\n\nfunction updateToolbarPosition(fabTop: number, fabLeft: number): void {\n if (!toolbar) return;\n const size = 56;\n const gap = 8;\n // Toolbar appears above FAB\n const toolbarH = toolbar.offsetHeight || 200;\n let tTop = fabTop - toolbarH - gap;\n // If not enough room above, show below\n if (tTop < 8) {\n tTop = fabTop + size + gap;\n }\n toolbar.style.top = `${tTop}px`;\n toolbar.style.bottom = 'auto';\n // Align horizontally center with FAB\n toolbar.style.left = `${fabLeft + (size / 2) - 20}px`;\n toolbar.style.right = 'auto';\n}\n\nfunction makeFabDraggable(): void {\n if (!fab) return;\n\n let startX = 0;\n let startY = 0;\n let startTop = 0;\n let startLeft = 0;\n let moved = false;\n\n function cleanupDrag() {\n if (fab) {\n fab.removeEventListener('pointermove', onPointerMove);\n fab.removeEventListener('pointerup', onPointerUp);\n fab.classList.remove('bs-dragging');\n }\n dragCleanup = null;\n }\n\n function onPointerDown(e: PointerEvent) {\n if (!fab) return;\n isDragging = false;\n moved = false;\n startX = e.clientX;\n startY = e.clientY;\n const rect = fab.getBoundingClientRect();\n startTop = rect.top;\n startLeft = rect.left;\n fab.setPointerCapture(e.pointerId);\n fab.addEventListener('pointermove', onPointerMove);\n fab.addEventListener('pointerup', onPointerUp);\n dragCleanup = cleanupDrag;\n }\n\n function onPointerMove(e: PointerEvent) {\n const dx = e.clientX - startX;\n const dy = e.clientY - startY;\n if (!moved && Math.abs(dx) < 5 && Math.abs(dy) < 5) return;\n moved = true;\n isDragging = true;\n fab?.classList.add('bs-dragging');\n const newTop = startTop + dy;\n const newLeft = startLeft + dx;\n applyFabPosition(newTop, newLeft);\n }\n\n function onPointerUp(e: PointerEvent) {\n fab?.releasePointerCapture(e.pointerId);\n cleanupDrag();\n if (moved && fab) {\n const rect = fab.getBoundingClientRect();\n saveFabPosition(rect.top, rect.left);\n e.preventDefault();\n e.stopPropagation();\n setTimeout(() => { isDragging = false; }, 10);\n } else {\n isDragging = false;\n }\n }\n\n fab.addEventListener('pointerdown', onPointerDown);\n}\n\n// ─── Init / Destroy ──────────────────────────────────────\n\nexport function initPanel(cfg: BugStashConfig, sr: ShadowRoot) {\n config = cfg;\n shadow = sr;\n\n // ── Inject FAB/toolbar styles + font into shadow root ──\n shadowFontLink = document.createElement('link');\n shadowFontLink.rel = 'stylesheet';\n shadowFontLink.href = 'https://fonts.googleapis.com/css2?family=Comfortaa:wght@400;600;700&family=Inter:wght@300;400;500;600;700&display=swap';\n shadow.appendChild(shadowFontLink);\n\n shadowStyleEl = document.createElement('style');\n shadowStyleEl.textContent = SHADOW_STYLES;\n shadow.appendChild(shadowStyleEl);\n\n // ── Create FAB + toolbar in shadow root (not iframe) ──\n initShadowUI(cfg);\n\n // ── Create iframe for modal UI only (bulletproof CSS isolation) ──\n iframeEl = document.createElement('iframe');\n iframeEl.style.cssText =\n 'position:fixed;inset:0;z-index:2147483640;pointer-events:none;' +\n 'border:none;background:transparent;width:100%;height:100%;' +\n 'color-scheme:normal;display:none;';\n\n const iframeStyles = `\n @import url('https://fonts.googleapis.com/css2?family=Comfortaa:wght@400;600;700&family=Inter:wght@300;400;500;600;700&display=swap');\n ${STYLES}\n ${LAYOUT_CSS}\n html, body { margin: 0; padding: 0; background: transparent; pointer-events: none; overflow: hidden; }\n `;\n iframeEl.srcdoc = `<!DOCTYPE html><html><head><style>${iframeStyles}</style></head><body></body></html>`;\n\n iframeEl.addEventListener('load', () => {\n iframeDoc = iframeEl!.contentDocument;\n });\n\n shadow.appendChild(iframeEl);\n\n // ── Keyboard Shortcuts (always on host document) ──\n registerKeyboardShortcuts(cfg);\n\n // ── Re-clamp FAB position on viewport resize ──\n resizeHandler = () => {\n if (!fab || isDragging) return;\n if (fab.style.top && fab.style.top !== 'auto') {\n const rect = fab.getBoundingClientRect();\n applyFabPosition(rect.top, rect.left);\n }\n };\n window.addEventListener('resize', resizeHandler);\n}\n\nfunction initShadowUI(cfg: BugStashConfig) {\n if (!shadow) return;\n\n const side = cfg.panelPosition === 'bottom-left' ? 'left' : 'right';\n\n fab = document.createElement('button') as HTMLButtonElement;\n fab.className = 'bs-fab';\n applyThemeVars(fab);\n fab.innerHTML = `${I.bug}<span class=\"bs-fab-label\">Report a bug</span>`;\n\n // Restore saved position or use default corner\n const savedPos = getSavedFabPosition();\n if (savedPos) {\n applyFabPosition(savedPos.top, savedPos.left);\n } else {\n fab.style[side] = '24px';\n }\n\n fab.addEventListener('click', () => {\n if (isDragging) return; // Ignore click after drag\n isOpen ? close() : open();\n });\n shadow.appendChild(fab);\n\n // Make FAB draggable\n makeFabDraggable();\n\n // ── Quick Action Toolbar ──\n toolbar = document.createElement('div') as HTMLDivElement;\n toolbar.className = 'bs-toolbar';\n if (savedPos) {\n // Position toolbar relative to saved FAB position\n updateToolbarPosition(savedPos.top, savedPos.left);\n } else {\n toolbar.style[side] = '32px';\n }\n applyThemeVars(toolbar);\n\n const isMac = navigator.platform.toUpperCase().includes('MAC');\n const mod = isMac ? '⌘' : 'Ctrl';\n\n const tbButtons: { icon: string; tip: string; kbd: string; action: () => void; id?: string }[] = [\n {\n icon: I.cam,\n tip: 'Screenshot',\n kbd: `${mod}+Shift+S`,\n action: async () => {\n const shot = await captureScreenshot(true);\n if (shot) {\n // Open panel to report tab with screenshot pre-attached\n if (!isOpen) open();\n setTimeout(() => {\n const area = modal?.querySelector('[data-bs-screenshot]') as HTMLElement;\n if (area) {\n (area as any).__screenshot = shot;\n area.classList.add('bs-captured');\n const title = area.querySelector('[data-bs-shot-title]');\n const sub = area.querySelector('[data-bs-shot-sub]');\n if (title) title.textContent = 'Screenshot captured!';\n if (sub) sub.textContent = 'Click to retake or annotate';\n // Trigger annotation setup\n area.click();\n }\n }, 400);\n }\n },\n },\n {\n icon: I.pin,\n tip: 'Toggle Pins',\n kbd: `${mod}+Shift+P`,\n id: 'bs-tb-pin',\n action: () => {\n const user = getCurrentUser();\n if (!user) {\n // Not logged in — open panel to show login\n if (!isOpen) open();\n return;\n }\n // Ensure live pins are initialized\n if (!shadow?.querySelector('#bugstash-live-pins')) {\n initLivePins(config.projectId, shadow!);\n connectRealtime(config.projectId);\n }\n const active = togglePinMode();\n const btn = toolbar?.querySelector('#bs-tb-pin');\n if (btn) btn.classList.toggle('bs-active', active);\n // Also update modal pin toggle if open\n const modalBtn = modal?.querySelector('[data-bs-pin-toggle]');\n if (modalBtn) {\n modalBtn.classList.toggle('active', active);\n modalBtn.innerHTML = `\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>\n Pins ${active ? 'ON' : 'OFF'}\n `;\n }\n },\n },\n {\n icon: currentTheme.id === 'black' ? I.sun : I.moon,\n tip: 'Toggle Theme',\n kbd: `${mod}+Shift+T`,\n id: 'bs-tb-theme',\n action: () => {\n const newId = currentTheme.id === 'black' ? 'white' : 'black';\n setTheme(newId);\n if (toolbar) applyThemeVars(toolbar);\n const btn = toolbar?.querySelector('#bs-tb-theme');\n if (btn) btn.innerHTML = `${currentTheme.id === 'black' ? I.sun : I.moon}<span class=\"bs-toolbar-tip\">${currentTheme.id === 'black' ? 'Light' : 'Dark'} Mode<span class=\"bs-toolbar-kbd\">${mod}+Shift+T</span></span>`;\n },\n },\n {\n icon: I.report,\n tip: 'Open Panel',\n kbd: `${mod}+Shift+B`,\n action: () => { isOpen ? close() : open(); },\n },\n ];\n\n for (const tb of tbButtons) {\n const btn = document.createElement('button') as HTMLButtonElement;\n btn.className = 'bs-toolbar-btn';\n if (tb.id) btn.id = tb.id;\n btn.innerHTML = `${tb.icon}<span class=\"bs-toolbar-tip\">${tb.tip}<span class=\"bs-toolbar-kbd\">${tb.kbd}</span></span>`;\n btn.addEventListener('click', (e) => { e.stopPropagation(); tb.action(); });\n toolbar.appendChild(btn);\n }\n\n shadow!.appendChild(toolbar);\n\n // Show toolbar on FAB hover or always show after first interaction\n fab.addEventListener('mouseenter', () => { if (!isOpen) showToolbar(); });\n fab.addEventListener('mouseleave', (e) => {\n const related = e.relatedTarget as HTMLElement;\n if (!toolbar?.contains(related)) hideToolbar();\n });\n toolbar.addEventListener('mouseenter', () => showToolbar());\n toolbar.addEventListener('mouseleave', (e) => {\n const related = e.relatedTarget as HTMLElement;\n if (!fab?.contains(related)) hideToolbar();\n });\n}\n\nfunction registerKeyboardShortcuts(_cfg: BugStashConfig) {\n const isMac = navigator.platform.toUpperCase().includes('MAC');\n const mod = isMac ? '⌘' : 'Ctrl';\n void mod; // used only for tooltip display in toolbar buttons\n\n keyHandler = (e: KeyboardEvent) => {\n const hasModShift = (e.ctrlKey || e.metaKey) && e.shiftKey;\n if (!hasModShift) return;\n\n if (e.key === 'B' || e.key === 'b') {\n e.preventDefault();\n isOpen ? close() : open();\n } else if (e.key === 'S' || e.key === 's') {\n e.preventDefault();\n // Screenshot\n captureScreenshot(true).then(shot => {\n if (shot) {\n if (!isOpen) open();\n setTimeout(() => {\n const area = modal?.querySelector('[data-bs-screenshot]') as HTMLElement;\n if (area) {\n (area as any).__screenshot = shot;\n area.classList.add('bs-captured');\n const title = area.querySelector('[data-bs-shot-title]');\n const sub = area.querySelector('[data-bs-shot-sub]');\n if (title) title.textContent = 'Screenshot captured!';\n if (sub) sub.textContent = 'Click to retake or annotate';\n area.click();\n }\n }, 400);\n }\n });\n } else if (e.key === 'P' || e.key === 'p') {\n e.preventDefault();\n // Pin toggle\n const user = getCurrentUser();\n if (!user) {\n if (!isOpen) open();\n return;\n }\n if (!shadow?.querySelector('#bugstash-live-pins')) {\n initLivePins(_cfg.projectId, shadow!);\n connectRealtime(_cfg.projectId);\n }\n const active = togglePinMode();\n const btn = toolbar?.querySelector('#bs-tb-pin');\n if (btn) btn.classList.toggle('bs-active', active);\n const modalBtn = modal?.querySelector('[data-bs-pin-toggle]');\n if (modalBtn) {\n modalBtn.classList.toggle('active', active);\n modalBtn.innerHTML = `\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg>\n Pins ${active ? 'ON' : 'OFF'}\n `;\n }\n } else if (e.key === 'T' || e.key === 't') {\n e.preventDefault();\n // Theme toggle\n const isMacKbd = navigator.platform.toUpperCase().includes('MAC');\n const modKey = isMacKbd ? '⌘' : 'Ctrl';\n const newId = currentTheme.id === 'black' ? 'white' : 'black';\n setTheme(newId);\n if (toolbar) applyThemeVars(toolbar);\n const themeBtn = toolbar?.querySelector('#bs-tb-theme');\n if (themeBtn) themeBtn.innerHTML = `${currentTheme.id === 'black' ? I.sun : I.moon}<span class=\"bs-toolbar-tip\">${currentTheme.id === 'black' ? 'Light' : 'Dark'} Mode<span class=\"bs-toolbar-kbd\">${modKey}+Shift+T</span></span>`;\n }\n };\n document.addEventListener('keydown', keyHandler);\n}\n\nfunction showToolbar() {\n if (toolbarVisible || isOpen) return;\n toolbarVisible = true;\n toolbar?.classList.add('bs-show');\n}\n\nfunction hideToolbar() {\n toolbarVisible = false;\n toolbar?.classList.remove('bs-show');\n}\n\nexport function destroyPanel() {\n close();\n dragCleanup?.();\n isDragging = false;\n fab?.remove();\n fab = null;\n toolbar?.remove();\n toolbar = null;\n toolbarVisible = false;\n shadowStyleEl?.remove();\n shadowStyleEl = null;\n shadowFontLink?.remove();\n shadowFontLink = null;\n iframeEl?.remove();\n iframeEl = null;\n iframeDoc = null;\n shadow = null;\n if (keyHandler) document.removeEventListener('keydown', keyHandler);\n keyHandler = null;\n if (resizeHandler) window.removeEventListener('resize', resizeHandler);\n resizeHandler = null;\n}\n","/**\n * Annotation drawing tool for screenshots.\n * Provides a canvas overlay for drawing arrows, rectangles, circles, and freehand on screenshots.\n */\n\nimport type { AnnotationShape } from '@bugstash/shared';\n\nexport { AnnotationShape };\n\nexport interface AnnotationResult {\n dataUrl: string; // The annotated screenshot as a data URL\n annotations: AnnotationShape[];\n}\n\nlet overlay: HTMLDivElement | null = null;\nlet canvas: HTMLCanvasElement | null = null;\nlet ctx: CanvasRenderingContext2D | null = null;\nlet screenshotImg: HTMLImageElement | null = null;\nlet currentTool: AnnotationShape['type'] = 'freehand';\nlet currentColor = '#ef4444';\nlet lineWidth = 3;\nlet shapes: AnnotationShape[] = [];\nlet currentShape: AnnotationShape | null = null;\nlet isDrawing = false;\nlet resolvePromise: ((result: AnnotationResult | null) => void) | null = null;\n\nconst TOOLS: { id: AnnotationShape['type']; label: string; icon: string }[] = [\n { id: 'freehand', label: 'Draw', icon: 'M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25z' },\n { id: 'rectangle', label: 'Rect', icon: 'M3 3h18v18H3V3zm2 2v14h14V5H5z' },\n { id: 'circle', label: 'Circle', icon: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z' },\n { id: 'arrow', label: 'Arrow', icon: 'M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z' },\n];\n\nconst COLORS = ['#ef4444', '#f97316', '#eab308', '#22c55e', '#3b82f6', '#8b5cf6', '#ffffff', '#000000'];\n\n/**\n * Opens the annotation editor overlay on a screenshot.\n * Returns a promise that resolves when the user saves or cancels.\n */\nexport function openAnnotationEditor(screenshotDataUrl: string): Promise<AnnotationResult | null> {\n return new Promise((resolve) => {\n resolvePromise = resolve;\n shapes = [];\n currentShape = null;\n currentTool = 'freehand';\n currentColor = '#ef4444';\n\n createOverlay(screenshotDataUrl);\n });\n}\n\nfunction createOverlay(screenshotDataUrl: string) {\n if (overlay) overlay.remove();\n\n overlay = document.createElement('div');\n overlay.id = 'bs-annotation-overlay';\n\n const style = document.createElement('style');\n style.textContent = `\n #bs-annotation-overlay {\n position: fixed; inset: 0; z-index: 2147483647;\n background: rgba(0,0,0,0.85);\n display: flex; flex-direction: column;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n .bs-ann-toolbar {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 16px; background: #1a1d2e;\n border-bottom: 1px solid #333;\n }\n .bs-ann-tool {\n width: 36px; height: 36px; border-radius: 8px;\n border: 2px solid transparent; background: #222639;\n cursor: pointer; display: flex; align-items: center; justify-content: center;\n transition: all 0.15s;\n }\n .bs-ann-tool:hover { border-color: #555; }\n .bs-ann-tool.active { border-color: #6E9ED0; background: #2a3550; }\n .bs-ann-tool svg { width: 18px; height: 18px; fill: #ccc; }\n .bs-ann-color {\n width: 24px; height: 24px; border-radius: 50%;\n border: 2px solid transparent; cursor: pointer;\n transition: transform 0.15s;\n }\n .bs-ann-color:hover { transform: scale(1.15); }\n .bs-ann-color.active { border-color: #fff; }\n .bs-ann-sep { width: 1px; height: 28px; background: #444; margin: 0 6px; }\n .bs-ann-btn {\n padding: 8px 18px; border-radius: 8px; border: none;\n font-size: 13px; font-weight: 600; cursor: pointer;\n margin-left: auto;\n }\n .bs-ann-cancel { background: #333; color: #aaa; margin-left: 8px; }\n .bs-ann-cancel:hover { background: #444; color: #fff; }\n .bs-ann-save { background: linear-gradient(135deg, #6E9ED0, #8FAFD6); color: #fff; }\n .bs-ann-save:hover { opacity: 0.9; }\n .bs-ann-undo { background: #333; color: #aaa; font-size: 12px; padding: 6px 12px; }\n .bs-ann-undo:hover { color: #fff; }\n .bs-ann-canvas-wrap {\n flex: 1; display: flex; align-items: center; justify-content: center;\n overflow: hidden; padding: 16px;\n }\n .bs-ann-canvas-wrap canvas { cursor: crosshair; border-radius: 4px; }\n `;\n\n overlay.appendChild(style);\n\n // Toolbar\n const toolbar = document.createElement('div');\n toolbar.className = 'bs-ann-toolbar';\n\n // Tool buttons\n for (const tool of TOOLS) {\n const btn = document.createElement('button');\n btn.className = `bs-ann-tool${tool.id === currentTool ? ' active' : ''}`;\n btn.title = tool.label;\n btn.innerHTML = `<svg viewBox=\"0 0 24 24\"><path d=\"${tool.icon}\"/></svg>`;\n btn.addEventListener('click', () => {\n currentTool = tool.id;\n toolbar.querySelectorAll('.bs-ann-tool').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n });\n toolbar.appendChild(btn);\n }\n\n toolbar.appendChild(createSep());\n\n // Color buttons\n for (const color of COLORS) {\n const btn = document.createElement('button');\n btn.className = `bs-ann-color${color === currentColor ? ' active' : ''}`;\n btn.style.background = color;\n btn.addEventListener('click', () => {\n currentColor = color;\n toolbar.querySelectorAll('.bs-ann-color').forEach((b) => b.classList.remove('active'));\n btn.classList.add('active');\n });\n toolbar.appendChild(btn);\n }\n\n toolbar.appendChild(createSep());\n\n // Undo\n const undoBtn = document.createElement('button');\n undoBtn.className = 'bs-ann-btn bs-ann-undo';\n undoBtn.textContent = 'Undo';\n undoBtn.addEventListener('click', () => {\n shapes.pop();\n redrawCanvas();\n });\n toolbar.appendChild(undoBtn);\n\n // Save / Cancel\n const saveBtn = document.createElement('button');\n saveBtn.className = 'bs-ann-btn bs-ann-save';\n saveBtn.textContent = 'Save';\n saveBtn.addEventListener('click', saveAnnotation);\n\n const cancelBtn = document.createElement('button');\n cancelBtn.className = 'bs-ann-btn bs-ann-cancel';\n cancelBtn.textContent = 'Cancel';\n cancelBtn.addEventListener('click', () => {\n cleanup();\n resolvePromise?.(null);\n });\n\n toolbar.appendChild(saveBtn);\n toolbar.appendChild(cancelBtn);\n overlay.appendChild(toolbar);\n\n // Canvas\n const canvasWrap = document.createElement('div');\n canvasWrap.className = 'bs-ann-canvas-wrap';\n\n canvas = document.createElement('canvas');\n ctx = canvas.getContext('2d')!;\n canvasWrap.appendChild(canvas);\n overlay.appendChild(canvasWrap);\n\n document.body.appendChild(overlay);\n\n // Load screenshot\n screenshotImg = new Image();\n screenshotImg.onload = () => {\n if (!canvas || !ctx || !screenshotImg) return;\n\n // Fit to viewport\n const maxW = window.innerWidth - 32;\n const maxH = window.innerHeight - 100;\n let w = screenshotImg.width;\n let h = screenshotImg.height;\n const scale = Math.min(1, maxW / w, maxH / h);\n w = Math.round(w * scale);\n h = Math.round(h * scale);\n\n canvas.width = w;\n canvas.height = h;\n redrawCanvas();\n setupCanvasEvents();\n };\n screenshotImg.src = screenshotDataUrl;\n}\n\nfunction createSep(): HTMLDivElement {\n const sep = document.createElement('div');\n sep.className = 'bs-ann-sep';\n return sep;\n}\n\nfunction setupCanvasEvents() {\n if (!canvas) return;\n\n canvas.addEventListener('mousedown', (e) => {\n isDrawing = true;\n const { x, y } = getCanvasPos(e);\n\n currentShape = {\n type: currentTool,\n color: currentColor,\n lineWidth,\n points: [{ x, y }],\n x, y, width: 0, height: 0,\n };\n });\n\n canvas.addEventListener('mousemove', (e) => {\n if (!isDrawing || !currentShape) return;\n const { x, y } = getCanvasPos(e);\n\n if (currentShape.type === 'freehand') {\n currentShape.points!.push({ x, y });\n } else {\n currentShape.width = x - currentShape.x!;\n currentShape.height = y - currentShape.y!;\n }\n redrawCanvas();\n drawShape(currentShape);\n });\n\n const endDraw = () => {\n if (isDrawing && currentShape) {\n shapes.push(currentShape);\n currentShape = null;\n }\n isDrawing = false;\n redrawCanvas();\n };\n\n canvas.addEventListener('mouseup', endDraw);\n canvas.addEventListener('mouseleave', endDraw);\n}\n\nfunction getCanvasPos(e: MouseEvent): { x: number; y: number } {\n const rect = canvas!.getBoundingClientRect();\n return {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top,\n };\n}\n\nfunction redrawCanvas() {\n if (!ctx || !canvas || !screenshotImg) return;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(screenshotImg, 0, 0, canvas.width, canvas.height);\n for (const shape of shapes) {\n drawShape(shape);\n }\n}\n\nfunction drawShape(shape: AnnotationShape) {\n if (!ctx) return;\n ctx.strokeStyle = shape.color;\n ctx.fillStyle = shape.color;\n ctx.lineWidth = shape.lineWidth;\n ctx.lineCap = 'round';\n ctx.lineJoin = 'round';\n\n switch (shape.type) {\n case 'freehand': {\n if (!shape.points || shape.points.length < 2) return;\n ctx.beginPath();\n ctx.moveTo(shape.points[0].x, shape.points[0].y);\n for (let i = 1; i < shape.points.length; i++) {\n ctx.lineTo(shape.points[i].x, shape.points[i].y);\n }\n ctx.stroke();\n break;\n }\n case 'rectangle': {\n ctx.strokeRect(shape.x!, shape.y!, shape.width!, shape.height!);\n break;\n }\n case 'circle': {\n const cx = shape.x! + shape.width! / 2;\n const cy = shape.y! + shape.height! / 2;\n const rx = Math.abs(shape.width!) / 2;\n const ry = Math.abs(shape.height!) / 2;\n ctx.beginPath();\n ctx.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);\n ctx.stroke();\n break;\n }\n case 'arrow': {\n const startX = shape.x!;\n const startY = shape.y!;\n const endX = shape.x! + shape.width!;\n const endY = shape.y! + shape.height!;\n const headLen = 14;\n const angle = Math.atan2(endY - startY, endX - startX);\n\n ctx.beginPath();\n ctx.moveTo(startX, startY);\n ctx.lineTo(endX, endY);\n ctx.stroke();\n\n // Arrowhead\n ctx.beginPath();\n ctx.moveTo(endX, endY);\n ctx.lineTo(endX - headLen * Math.cos(angle - Math.PI / 6), endY - headLen * Math.sin(angle - Math.PI / 6));\n ctx.lineTo(endX - headLen * Math.cos(angle + Math.PI / 6), endY - headLen * Math.sin(angle + Math.PI / 6));\n ctx.closePath();\n ctx.fill();\n break;\n }\n }\n}\n\nfunction saveAnnotation() {\n if (!canvas) { cleanup(); resolvePromise?.(null); return; }\n const dataUrl = canvas.toDataURL('image/png');\n const result: AnnotationResult = { dataUrl, annotations: shapes };\n cleanup();\n resolvePromise?.(result);\n}\n\nfunction cleanup() {\n overlay?.remove();\n overlay = null;\n canvas = null;\n ctx = null;\n screenshotImg = null;\n shapes = [];\n currentShape = null;\n isDrawing = false;\n}\n"],"mappings":"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,IACvB,CCjGO,IAAMC,GAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyGpBC,GAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0kCTC,GAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":["index_exports","__export","BugStash","index_default","__toCommonJS","crumbs","maxCrumbs","clickHandler","inputHandler","popstateHandler","hashHandler","getSelector","el","tag","cls","text","label","addBreadcrumb","crumb","initBreadcrumbs","max","e","target","inputTimers","existing","isPassword","getBreadcrumbs","clearBreadcrumbs","restoreBreadcrumbs","REDACT_PLACEHOLDER","PATTERNS","match","eqIdx","colonIdx","redactString","input","result","pattern","replacement","PATTERNS","redactLogArgs","args","redactString","redactObject","obj","result","key","value","lk","REDACT_PLACEHOLDER","originals","logs","maxLogs","serialize","args","a","capture","level","entry","redactLogArgs","addBreadcrumb","initLogger","max","getLogs","clearLogs","restoreConsole","captures","maxCaptures","originalFetch","originalXHROpen","originalXHRSend","record","entry","addBreadcrumb","shortenUrl","url","u","params","key","lk","qs","redactString","patchFetch","input","init","method","rawUrl","start","response","err","patchXHR","rest","body","initNetwork","max","getNetworkCaptures","getFailedNetworkCaptures","c","clearNetworkCaptures","restoreNetwork","errors","onErrorHandler","onRejectionHandler","initErrors","event","entry","addBreadcrumb","reason","message","getErrors","clearErrors","restoreErrors","metrics","lcpObserver","clsObserver","fidObserver","initPerformance","onLoad","nav","paints","p","mem","list","entries","last","clsValue","entry","getPerformanceMetrics","restorePerformance","resolveUrl","url","baseUrl","doc","base","a","uuid","counter","random","toArray","arrayLike","arr","i","l","styleProps","getStyleProperties","options","px","node","styleProperty","val","getNodeWidth","leftBorder","rightBorder","getNodeHeight","topBorder","bottomBorder","getImageSize","targetNode","width","height","getPixelRatio","ratio","FINAL_PROCESS","canvasDimensionLimit","checkCanvasDimensions","canvas","createImage","url","resolve","reject","img","svgToDataURL","svg","html","nodeToDataURL","node","width","height","xmlns","foreignObject","isInstanceOfElement","instance","nodePrototype","formatCSSText","style","content","formatCSSProperties","options","getStyleProperties","name","value","priority","getPseudoElementStyle","className","pseudo","selector","cssText","clonePseudoElement","nativeNode","clonedNode","uuid","styleElement","clonePseudoElements","WOFF","JPEG","mimes","getExtension","url","match","getMimeType","extension","getContentFromDataUrl","dataURL","isDataUrl","url","makeDataUrl","content","mimeType","fetchAsDataURL","init","process","res","blob","resolve","reject","reader","error","cache","getCacheKey","contentType","includeQueryParams","key","resourceToDataURL","resourceUrl","options","cacheKey","result","msg","cloneCanvasElement","canvas","dataURL","createImage","cloneVideoElement","video","options","ctx","poster","contentType","getMimeType","resourceToDataURL","cloneIFrameElement","iframe","_a","cloneNode","cloneSingleNode","node","isInstanceOfElement","isSVGElement","isSlotElement","cloneChildren","nativeNode","clonedNode","children","toArray","_b","deferred","child","clonedChild","cloneCSSStyle","targetStyle","sourceStyle","getStyleProperties","name","value","cloneInputValue","cloneSelectValue","selectedOption","decorate","clonePseudoElements","ensureSVGSymbols","clone","uses","processedDefs","i","id","exist","definition","nodes","ns","svg","defs","isRoot","URL_REGEX","URL_WITH_FORMAT_REGEX","FONT_SRC_REGEX","toRegex","url","escaped","parseURLs","cssText","urls","raw","quotation","isDataUrl","embed","resourceURL","baseURL","options","getContentFromUrl","resolvedURL","resolveUrl","contentType","getMimeType","dataURL","content","makeDataUrl","resourceToDataURL","filterPreferredFontFormat","str","preferredFontFormat","match","src","format","shouldEmbed","embedResources","baseUrl","filteredCSSText","deferred","css","embedProp","propName","node","options","propValue","_a","cssString","embedResources","embedBackground","clonedNode","embedImageNode","isImageElement","isInstanceOfElement","isDataUrl","url","dataURL","resourceToDataURL","getMimeType","resolve","reject","attributes","error","image","embedChildren","deferreds","toArray","child","embedImages","applyStyle","node","options","style","manual","key","cssFetchCache","fetchCSS","url","cache","cssText","embedFonts","data","options","regexUrl","loadFonts","loc","fetchAsDataURL","result","parseCSS","source","commentsRegex","keyframesRegex","matches","importRegex","combinedCSSRegex","unifiedRegex","getCSSRules","styleSheets","ret","deferreds","sheet","toArray","item","index","importIndex","deferred","metadata","rule","error","e","inline","err","getWebFontRules","cssRules","shouldEmbed","parseWebFontRules","node","normalizeFontFamily","font","getUsedFonts","fonts","traverse","child","getWebFontCSS","rules","usedFonts","baseUrl","embedResources","embedWebFonts","clonedNode","styleNode","sytleContent","toSvg","node","options","width","height","getImageSize","clonedNode","cloneNode","embedWebFonts","embedImages","applyStyle","nodeToDataURL","toCanvas","svg","img","createImage","canvas","context","ratio","getPixelRatio","canvasWidth","canvasHeight","checkCanvasDimensions","getFontEmbedCSS","node","options","getWebFontCSS","showFlashAnimation","flash","style","isBugStashUI","el","tag","captureScreenshot","native","captureWithDisplayMedia","tiers","tier","timeout","result","captureWithHtmlToImage","stream","video","resolve","canvas","ctx","pauseAnimations","compositeNativeElements","target","pixelRatio","scrollX","scrollY","rect","x","y","w","h","timeoutPromise","ms","_","reject","skipCrossOriginImages","bodyBg","htmlBg","isTransparent","c","bgColor","fontEmbedCSS","getFontEmbedCSS","resumeAnimations","toCanvas","node","src","PRIMARY_ENDPOINT","FALLBACK_ENDPOINT","endpoint","_usingFallback","setEndpoint","url","getEndpoint","fetchWithFallback","init","err","previousEndpoint","fallbackUrl","STORAGE_KEY","getStoredAuth","raw","auth","setStoredAuth","clearStoredAuth","getCurrentUser","getAccessToken","authHeaders","res","data","login","email","password","projectId","logout","submitReport","report","headers","authHeaders","fetchWithFallback","endpoint","fetchPagePins","projectId","pathname","createPin","pin","updatePin","pinId","updates","deletePin","fetchComments","createComment","body","mentions","fetchProjectMembers","_domainVerifyPromise","verifyDomain","res","QUEUE_KEY","queueOfflineAction","action","queue","getOfflineQueue","flushOfflineQueue","flushed","remaining","result","THEMES","getThemes","getThemeById","id","getDefaultTheme","LAYOUTS","getLayouts","getLayoutById","id","l","getDefaultLayout","LAYOUT_CSS","pollTimer","lastPollTime","POLL_INTERVAL","handlers","currentProjectId","knownPinIds","connectRealtime","projectId","startPolling","poll","token","getAccessToken","endpoint","getEndpoint","pathname","res","data","pins","pin","emit","disconnectRealtime","onRealtimeEvent","type","handler","event","h","registerKnownPins","pinIds","isConnected","pollTimer","PIN_MARKER_STYLES","PIN_POPUP_STYLES","PIN_FORM_STYLES","projectId","container","clickOverlay","pins","members","pinMode","activePopup","currentPathname","mutationObserver","shadow","pinElements","visibilityCheckInterval","STATUS_COLORS","PRIORITY_COLORS","initLivePins","projId","sr","createOverlay","loadPins","loadMembers","setupRealtimeListeners","watchNavigation","setupListeners","destroyLivePins","teardownListeners","removePinElements","togglePinMode","enabled","isPinModeActive","findElement","selector","xpath","selectors","parsed","sel","el","result","isElementClipped","rect","parent","style","oy","ox","pr","handleKeyDown","mutations","mutation","removed","pinId","pinEl","renderPins","checkPinVisibility","closePopup","f","pin","p","target","PIN_FORM_STYLES","e","clientX","clientY","pageX","pageY","xPercent","yPercent","pageW","pageH","showNewPinForm","fetchPagePins","registerKnownPins","fetchProjectMembers","isElementRelative","pinShadow","pinStyle","PIN_MARKER_STYLES","PIN_POPUP_STYLES","statusColor","initials","getInitials","gradientBg","getAvatarGradient","avatarContent","isSafeImageUrl","escapeHtml","badgeHtml","isOverdue","marker","showPinPopup","timeAgo","ts","time","diff","mins","hrs","clampToViewport","pad","dx","dy","curLeft","curTop","pinHost","popup","user","getCurrentUser","pinCreator","canManage","prioColor","prioLabel","creatorInitials","creatorGradient","creatorAvatarHtml","statusLabel","sendIconSvg","closeIconSvg","dueDateHtml","fetchComments","commentsRes","cmtsEl","comments","c","renderCommentHtml","input","body","res","createComment","queueOfflineAction","updatePin","idx","i","deleting","deletePin","cssEscape","str","getSelectorChain","el","selectors","attr","val","cssEscape","escaped","aria","candidate","getStructuralPath","parts","current","node","parent","tag","siblings","c","getXPath","idx","sib","showNewPinForm","pageX","pageY","xPct","yPct","clientX","clientY","targetEl","closePopup","container","e","form","formW","pad","left","top","rect","memberOptions","members","m","getCurrentUser","escapeHtml","setupSegmentedRow","title","submitBtn","desc","priority","getSegmentedValue","category","assigneeId","dueDateInput","dueDate","selector","xpath","logs","getLogs","l","errors","getErrors","netErrors","getFailedNetworkCaptures","n","pinData","projectId","res","createPin","pins","renderPins","queueOfflineAction","currentUser","setupRealtimeListeners","onRealtimeEvent","event","pin","p","registerKnownPins","updated","i","id","comment","activePopup","cmtsEl","renderCommentHtml","watchNavigation","lastPath","check","loadPins","origPush","origReplace","args","getInitials","name","w","isSafeImageUrl","url","parsed","AVATAR_GRADIENTS","getAvatarGradient","hash","avatar","commentInitials","commentGradient","avatarInner","timeAgo","row","btn","b","str","div","config","fab","toolbar","modal","backdrop","keyHandler","shadow","iframeEl","iframeDoc","isOpen","toolbarVisible","isDragging","resizeHandler","dragCleanup","FAB_STORAGE_KEY","shadowStyleEl","shadowFontLink","activeTab","currentTheme","getDefaultTheme","currentLayout","getDefaultLayout","I","STYLES","SHADOW_STYLES","tabLogin","esc","s","timeAgo","ts","fmtTime","HISTORY_KEY","getReportHistory","saveReportHistory","entries","addToHistory","entry","id","deleteFromHistory","e","updateInHistory","updates","idx","buildContext","config","autoDetect","errors","getErrors","logs","getLogs","net","getNetworkCaptures","failedNet","getFailedNetworkCaptures","crumbs","getBreadcrumbs","perf","getPerformanceMetrics","consoleErrors","l","severity","tags","tabReport","d","categories","hasIssues","c","tabConsole","lvMap","tabNetwork","caps","n","tabContext","html","errs","bars","label","val","max","pct","p","b","ctx","tabHistory","catLabels","fmtDate","diffMs","diffMin","diffH","diffD","pinsHtml","tabSettings","themes","getThemes","layouts","getLayouts","t","setupAnnotation","container","screenshotData","COLORS","currentColor","currentTool","brushSize","zoom","isDark","shapes","pins","selectedIdx","hoveredIdx","dragging","drawing","dragOffX","dragOffY","startX","startY","currentDraw","PIN_COLORS","img","wrap","viewport","canvas","toolbar","tIcons","toolNames","toolBtns","setTool","btn","color","i","sizeSlider","right","mkBtn","title","svg","zoomOut","zoomLabel","zoomIn","zoomReset","undoBtn","clearBtn","applyZoom","el","pinLayer","pinList","renderPins","pin","pctX","pctY","pinDragging","onMove","me","r","onUp","item","del","outlineColor","drawOutline","fn","lw","renderShape","preview","alpha","stroke","angle","headLen","fontSize","isSelected","isHovered","shapeBounds","handles","hx","hy","render","x","y","minX","minY","maxX","maxY","hitTest","pad","moveShape","dx","dy","scale","samplePoints","totalBrightness","sx","sy","px","coords","autoSelectDrag","hit","note","input","rx","ry","cx2","cy2","endDraw","keyHandler","bakePins","switchTab","tab","modal","activeTab","scroll","renderers","bindTabContent","card","existing","confirm","yes","no","editSev","sb","row","save","cancel","newTitle","newDesc","setTheme","layout","getLayoutById","close","open","cat","sev","annotator","titleEl","subEl","area","backdrop","captureScreenshot","form","description","category","detected","report","result","submitReport","iframeDoc","isOpen","hideToolbar","iframeEl","fails","applyThemeVars","tabsHtml","user","getCurrentUser","initials","w","pinActive","isPinModeActive","headerHtml","useSidebar","useBottomTabs","contentHtml","fab","active","togglePinMode","logout","bindLoginForm","escHandler","submitBtn","emailInput","passInput","errorEl","doLogin","email","password","login","initLivePins","shadow","connectRealtime","key","themeId","theme","getThemeById","getCurrentThemeId","setLayout","layoutId","getCurrentLayoutId","getSavedFabPosition","raw","FAB_STORAGE_KEY","pos","saveFabPosition","top","left","clampFabToViewport","vw","vh","applyFabPosition","clamped","updateToolbarPosition","fabTop","fabLeft","size","gap","toolbarH","tTop","makeFabDraggable","startTop","startLeft","moved","cleanupDrag","onPointerMove","onPointerUp","dragCleanup","onPointerDown","isDragging","rect","newTop","newLeft","initPanel","cfg","sr","shadowFontLink","shadowStyleEl","initShadowUI","iframeStyles","LAYOUT_CSS","registerKeyboardShortcuts","resizeHandler","side","savedPos","mod","tbButtons","shot","sub","modalBtn","newId","tb","showToolbar","related","_cfg","modKey","themeBtn","toolbarVisible","destroyPanel","overlay","canvas","ctx","screenshotImg","currentTool","currentColor","lineWidth","shapes","currentShape","isDrawing","resolvePromise","TOOLS","COLORS","openAnnotationEditor","screenshotDataUrl","resolve","createOverlay","style","toolbar","tool","btn","b","createSep","color","undoBtn","redrawCanvas","saveBtn","saveAnnotation","cancelBtn","cleanup","canvasWrap","maxW","maxH","w","h","scale","setupCanvasEvents","sep","e","x","y","getCanvasPos","drawShape","endDraw","rect","shape","i","cx","cy","rx","ry","startX","startY","endX","endY","headLen","angle","result","initialized","shadowRoot","getOrCreateShadowRoot","host","initModules","options","shadow","initBreadcrumbs","initLogger","initNetwork","initErrors","initPerformance","initPanel","getCurrentUser","initLivePins","connectRealtime","detectEnvironment","BugStash","setEndpoint","verifyDomain","allowed","destroyPanel","destroyLivePins","disconnectRealtime","restoreConsole","restoreNetwork","restoreErrors","restoreBreadcrumbs","restorePerformance","getLogs","clearLogs","getNetworkCaptures","getFailedNetworkCaptures","clearNetworkCaptures","getErrors","clearErrors","getBreadcrumbs","clearBreadcrumbs","getPerformanceMetrics","addBreadcrumb","getThemes","getThemeById","setTheme","getCurrentThemeId","getLayouts","getLayoutById","setLayout","getCurrentLayoutId","login","logout","togglePinMode","isPinModeActive","isConnected","openAnnotationEditor","redactString","redactObject","index_default"]}