@impakers/debug 1.4.17 → 1.4.18

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/react.tsx","../src/core/auth.ts","../src/index.ts","../src/components/debug-widget/index.tsx","../src/components/annotation-popup-css/index.tsx","../src/components/annotation-popup-css/styles.module.scss","../src/components/icons.tsx","../src/utils/freeze-animations.ts","../src/utils/element-identification.ts","../src/utils/react-detection.ts","../src/utils/source-location.ts","../src/utils/capture-element.ts","../src/core/collector.ts","../src/core/debug-targets.ts","../src/core/api.ts","../src/core/sourcemap-resolver.ts","../src/components/annotation-marker/styles.module.scss","../src/components/annotation-marker/index.tsx","../src/components/comment-thread/index.tsx","../src/components/comment-thread/styles.module.scss","../src/components/fab-menu/index.tsx","../src/components/fab-menu/styles.module.scss","../src/components/inbox-panel/index.tsx","../src/components/inbox-panel/styles.module.scss","../src/components/settings-panel/index.tsx","../src/core/settings.ts","../src/components/settings-panel/styles.module.scss","../src/components/debug-widget/styles.module.scss","../src/ui/AuthPromptPortal.tsx"],"sourcesContent":["\"use client\";\n\n// =============================================================================\n// @impakers/debug — React Provider\n// =============================================================================\n//\n// Usage:\n// import { ImpakersDebugProvider } from '@impakers/debug/react'\n//\n// <ImpakersDebugProvider\n// endpoint=\"https://impakers-os.vercel.app/api/external/feedback\"\n// getUser={() => ({ id: user.id, name: user.name })}\n// />\n//\n\nimport React, { useEffect, useState, useCallback } from \"react\";\nimport type { ImpakersDebugConfig } from \"./core/types\";\nimport { isAuthenticated } from \"./core/auth\";\nimport { ImpakersDebug } from \"./index\";\nimport { DebugWidget } from \"./components/debug-widget\";\nimport { AuthPromptPortal } from \"./ui/AuthPromptPortal\";\n\n/**\n * React Provider — 클라이언트 프로젝트의 레이아웃에 추가\n *\n * 인증 전: Ctrl+Shift+. (Mac: Cmd+Shift+.) 으로 인증 프롬프트\n * 인증 후: 플로팅 버튼 + DOM 선택 → popover 피드백\n * 숨기기: FAB 우클릭 → \"위젯 숨기기\" / 다시 Ctrl+Shift+. 으로 복원\n */\nexport function ImpakersDebugProvider({ endpoint, getUser }: ImpakersDebugConfig) {\n const [authenticated, setAuthenticated] = useState(false);\n const [showAuth, setShowAuth] = useState(false);\n const [hidden, setHidden] = useState(() => {\n try { return localStorage.getItem(\"impakers-debug-hidden\") === \"1\"; } catch { return false; }\n });\n\n // 클라이언트에서만 인증 상태 확인\n useEffect(() => {\n setAuthenticated(isAuthenticated());\n }, []);\n\n // Vanilla API 이벤트 연결\n useEffect(() => {\n const unsubs = [\n ImpakersDebug._on(\"impakers-debug:show-auth\", () => {\n setShowAuth(true);\n setHidden(false);\n try { localStorage.removeItem(\"impakers-debug-hidden\"); } catch {}\n }),\n ImpakersDebug._on(\"impakers-debug:open\", () => {\n setHidden(false);\n try { localStorage.removeItem(\"impakers-debug-hidden\"); } catch {}\n }),\n ImpakersDebug._on(\"impakers-debug:deactivate\", () => {\n setAuthenticated(false);\n setShowAuth(false);\n }),\n ];\n return () => unsubs.forEach((fn) => fn());\n }, []);\n\n // Ctrl+Shift+. / Cmd+Shift+. 키보드 단축키\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n if ((e.ctrlKey || e.metaKey) && e.shiftKey && (e.key === \".\" || e.key === \">\" || e.code === \"Period\")) {\n e.preventDefault();\n\n // 숨겨진 상태면 다시 보이기\n if (hidden) {\n setHidden(false);\n try { localStorage.removeItem(\"impakers-debug-hidden\"); } catch {}\n return;\n }\n\n if (isAuthenticated()) {\n setAuthenticated(true);\n } else {\n setShowAuth((v) => !v);\n }\n }\n }\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [hidden]);\n\n const handleAuthSuccess = useCallback((_serviceName: string) => {\n setAuthenticated(true);\n setShowAuth(false);\n }, []);\n\n const handleAuthClose = useCallback(() => {\n setShowAuth(false);\n }, []);\n\n const handleHide = useCallback(() => {\n setHidden(true);\n try { localStorage.setItem(\"impakers-debug-hidden\", \"1\"); } catch {}\n }, []);\n\n return (\n <>\n {/* 인증된 상태 + 숨겨지지 않은 상태: DOM 선택 위젯 */}\n {authenticated && !hidden && (\n <DebugWidget endpoint={endpoint} getUser={getUser} onHide={handleHide} />\n )}\n\n {/* 미인증 상태: 인증 프롬프트 */}\n {showAuth && !authenticated && (\n <AuthPromptPortal\n endpoint={endpoint}\n onSuccess={handleAuthSuccess}\n onClose={handleAuthClose}\n />\n )}\n </>\n );\n}\n\nexport { ImpakersDebug } from \"./index\";\n","// =============================================================================\n// @impakers/debug — Authentication\n// =============================================================================\n//\n// 시크릿 코드 → JWT 토큰 인증 플로우\n// 토큰은 localStorage에 저장되며, 피드백 전송 시 Authorization 헤더로 전달\n//\n\nimport type { AuthResponse } from \"./types\";\n\nconst STORAGE_KEY = \"impakers-debug-token\";\nconst TOKEN_DATA_KEY = \"impakers-debug-token-data\";\n\n/** 저장된 토큰 데이터 */\ninterface StoredTokenData {\n token: string;\n serviceName: string;\n expiresAt: string;\n}\n\n/** 로컬스토리지에서 토큰 로드 */\nexport function loadToken(): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n const data = localStorage.getItem(TOKEN_DATA_KEY);\n if (!data) return null;\n\n const parsed: StoredTokenData = JSON.parse(data);\n\n // 만료 확인\n if (new Date(parsed.expiresAt) < new Date()) {\n clearToken();\n return null;\n }\n\n return parsed.token;\n } catch {\n return null;\n }\n}\n\n/** 토큰이 유효한지 확인 */\nexport function isAuthenticated(): boolean {\n return loadToken() !== null;\n}\n\n/** 저장된 서비스 이름 */\nexport function getServiceName(): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n const data = localStorage.getItem(TOKEN_DATA_KEY);\n if (!data) return null;\n const parsed: StoredTokenData = JSON.parse(data);\n return parsed.serviceName;\n } catch {\n return null;\n }\n}\n\n/** 인증 토큰 저장 */\nexport function saveToken(authResponse: AuthResponse): void {\n if (typeof window === \"undefined\") return;\n try {\n const data: StoredTokenData = {\n token: authResponse.token,\n serviceName: authResponse.serviceName,\n expiresAt: authResponse.expiresAt,\n };\n localStorage.setItem(TOKEN_DATA_KEY, JSON.stringify(data));\n localStorage.setItem(STORAGE_KEY, authResponse.token);\n } catch {\n // localStorage 불가\n }\n}\n\n/** 인증 토큰 삭제 */\nexport function clearToken(): void {\n if (typeof window === \"undefined\") return;\n try {\n localStorage.removeItem(TOKEN_DATA_KEY);\n localStorage.removeItem(STORAGE_KEY);\n } catch {\n // ignore\n }\n}\n\n/** 시크릿 코드로 인증 요청 */\nexport async function authenticate(\n endpoint: string,\n code: string,\n): Promise<AuthResponse> {\n const domain = window.location.hostname;\n\n const res = await fetch(`${endpoint}/auth`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ code, domain }),\n });\n\n if (!res.ok) {\n const error = await res.json().catch(() => ({ message: \"인증 실패\" }));\n throw new Error(error.message || \"인증 실패\");\n }\n\n const authResponse: AuthResponse = await res.json();\n saveToken(authResponse);\n return authResponse;\n}\n","// =============================================================================\n// @impakers/debug — Vanilla JS API\n// =============================================================================\n//\n// 프레임워크 없이 사용 가능한 정적 API.\n// React Provider를 사용하는 경우 이 모듈 대신 '@impakers/debug/react'를 사용.\n//\n// Usage:\n// import { ImpakersDebug } from '@impakers/debug'\n// ImpakersDebug.showAuth()\n// ImpakersDebug.isActive()\n// ImpakersDebug.deactivate()\n// ImpakersDebug.open()\n//\n\nimport { isAuthenticated, clearToken, loadToken } from \"./core/auth\";\n\nexport type { FeedbackUser, ImpakersDebugConfig } from \"./core/types\";\n\n/**\n * @impakers/debug Vanilla JS API\n *\n * React를 쓰지 않는 환경에서 사용하거나,\n * 프로그래밍 방식으로 위젯을 제어할 때 사용합니다.\n */\nexport class ImpakersDebug {\n private static _eventTarget = typeof EventTarget !== \"undefined\" ? new EventTarget() : null;\n\n /** 인증 프롬프트 띄우기 */\n static showAuth(): void {\n ImpakersDebug._eventTarget?.dispatchEvent(new CustomEvent(\"impakers-debug:show-auth\"));\n }\n\n /** 인증 상태 확인 */\n static isActive(): boolean {\n return isAuthenticated();\n }\n\n /** 로그아웃 (토큰 삭제 + UI 숨김) */\n static deactivate(): void {\n clearToken();\n ImpakersDebug._eventTarget?.dispatchEvent(new CustomEvent(\"impakers-debug:deactivate\"));\n }\n\n /** 피드백 폼 열기 (인증된 상태에서) */\n static open(): void {\n if (!isAuthenticated()) {\n ImpakersDebug.showAuth();\n return;\n }\n ImpakersDebug._eventTarget?.dispatchEvent(new CustomEvent(\"impakers-debug:open\"));\n }\n\n /** 내부 이벤트 리스너 등록 (React Provider에서 사용) */\n static _on(event: string, handler: EventListener): () => void {\n ImpakersDebug._eventTarget?.addEventListener(event, handler);\n return () => ImpakersDebug._eventTarget?.removeEventListener(event, handler);\n }\n}\n","\"use client\";\n\nimport { useState, useCallback, useEffect, useRef, useMemo } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport {\n AnnotationPopupCSS,\n AnnotationPopupCSSHandle,\n} from \"../annotation-popup-css\";\nimport {\n identifyElement,\n getNearbyText,\n getElementClasses,\n getDetailedComputedStyles,\n getForensicComputedStyles,\n getFullElementPath,\n getAccessibilityInfo,\n closestCrossingShadow,\n} from \"../../utils/element-identification\";\nimport { getReactComponentName } from \"../../utils/react-detection\";\nimport { getSourceLocation, findNearestComponentSource, formatSourceLocation } from \"../../utils/source-location\";\nimport { originalSetTimeout } from \"../../utils/freeze-animations\";\nimport { captureFullPage } from \"../../utils/capture-element\";\nimport { collectMetadata } from \"../../core/collector\";\nimport { getRouteDebugTargets, mergeDebugTargets } from \"../../core/debug-targets\";\nimport {\n submitFeedback,\n fetchFeedbacks,\n fetchAllFeedbacks,\n fetchComments,\n postComment,\n uploadFile,\n getCachedSnapshot,\n subscribeCache,\n getCommentsCacheKey,\n getFeedbacksCacheKey,\n getAllFeedbacksCacheKey,\n updateTaskStatus,\n type FeedbackTask,\n type FeedbackComment,\n} from \"../../core/api\";\nimport { resolveSourceString } from \"../../core/sourcemap-resolver\";\nimport type { DebugTarget, FeedbackUser } from \"../../core/types\";\nimport type { Annotation } from \"../../types\";\nimport { AnnotationMarker, PendingMarker } from \"../annotation-marker\";\nimport { CommentThread, type ThreadTask, type CommentData } from \"../comment-thread\";\nimport { FabMenu, type FabMenuItem } from \"../fab-menu\";\nimport { InboxPanel, type InboxItem } from \"../inbox-panel\";\nimport { SettingsPanel } from \"../settings-panel\";\nimport { getServiceName } from \"../../core/auth\";\nimport { loadSettings, saveSettings, type DebugSettings } from \"../../core/settings\";\nimport styles from \"./styles.module.scss\";\n\n// =============================================================================\n// Utils\n// =============================================================================\n\nfunction deepElementFromPoint(x: number, y: number): HTMLElement | null {\n let element = document.elementFromPoint(x, y) as HTMLElement | null;\n if (!element) return null;\n while (element?.shadowRoot) {\n const deeper = element.shadowRoot.elementFromPoint(x, y) as HTMLElement | null;\n if (!deeper || deeper === element) break;\n element = deeper;\n }\n return element;\n}\n\nfunction isElementFixed(element: HTMLElement): boolean {\n let current: HTMLElement | null = element;\n while (current && current !== document.body) {\n const style = window.getComputedStyle(current);\n if (style.position === \"fixed\" || style.position === \"sticky\") return true;\n current = current.parentElement;\n }\n return false;\n}\n\nfunction identifyElementWithReact(element: HTMLElement): {\n name: string;\n elementName: string;\n path: string;\n reactComponents: string | null;\n} {\n const { name: elementName, path } = identifyElement(element);\n const reactInfo = getReactComponentName(element, { mode: \"filtered\" });\n return {\n name: reactInfo.path ? `${reactInfo.path} ${elementName}` : elementName,\n elementName,\n path,\n reactComponents: reactInfo.path,\n };\n}\n\nfunction detectSourceFile(element: Element): string | undefined {\n const result = getSourceLocation(element as HTMLElement);\n const loc = result.found ? result : findNearestComponentSource(element as HTMLElement);\n if (loc.found && loc.source) {\n return formatSourceLocation(loc.source, \"path\");\n }\n return undefined;\n}\n\n/** 여러 소스 파일 후보를 반환 (프로덕션에서 첫 번째 청크가 node_modules일 수 있음) */\nfunction detectSourceFileCandidates(element: Element): string[] {\n const result = getSourceLocation(element as HTMLElement);\n const loc = result.found ? result : findNearestComponentSource(element as HTMLElement);\n if (loc.found && loc.sourceCandidates && loc.sourceCandidates.length > 0) {\n return loc.sourceCandidates.map((s) => formatSourceLocation(s, \"path\"));\n }\n if (loc.found && loc.source) {\n return [formatSourceLocation(loc.source, \"path\")];\n }\n return [];\n}\n\nfunction buildComponentDebugTarget(\n resolvedSource: string,\n componentName?: string | null,\n): DebugTarget | null {\n const match = resolvedSource.match(/^(.+):(\\d+)(?::(\\d+))?$/);\n if (!match) return null;\n\n const [, file, lineStr, columnStr] = match;\n const line = Number.parseInt(lineStr, 10);\n const column = columnStr ? Number.parseInt(columnStr, 10) : undefined;\n if (!file || Number.isNaN(line)) return null;\n\n return {\n kind: \"component\",\n file,\n line,\n column,\n label: componentName || \"Resolved component source\",\n confidence: 0.98,\n reason: \"resolved-from-source-map\",\n };\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\ntype HoverInfo = {\n element: string;\n elementName: string;\n elementPath: string;\n rect: DOMRect | null;\n reactComponents?: string | null;\n};\n\ntype PendingAnnotation = {\n x: number;\n y: number;\n clientY: number;\n element: string;\n elementPath: string;\n selectedText?: string;\n boundingBox?: { x: number; y: number; width: number; height: number };\n nearbyText?: string;\n cssClasses?: string;\n isFixed?: boolean;\n fullPath?: string;\n accessibility?: string;\n computedStyles?: string;\n computedStylesObj?: Record<string, string>;\n nearbyElements?: string;\n reactComponents?: string;\n sourceFile?: string;\n resolvedSource?: string;\n resolvedName?: string;\n targetElement?: HTMLElement;\n};\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport interface DebugWidgetProps {\n endpoint: string;\n getUser?: () => FeedbackUser | null;\n onHide?: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// 라우트별 마커 localStorage 저장/복원\n// ---------------------------------------------------------------------------\n\nconst STORAGE_PREFIX = \"impakers-debug-markers-\";\n\nfunction getRouteKey(): string {\n return STORAGE_PREFIX + window.location.pathname;\n}\n\nfunction loadRouteAnnotations(): Annotation[] {\n try {\n const stored = localStorage.getItem(getRouteKey());\n if (!stored) return [];\n return JSON.parse(stored);\n } catch {\n return [];\n }\n}\n\nfunction saveRouteAnnotations(annotations: Annotation[]): void {\n try {\n if (annotations.length === 0) {\n localStorage.removeItem(getRouteKey());\n } else {\n localStorage.setItem(getRouteKey(), JSON.stringify(annotations));\n }\n } catch {\n // ignore\n }\n}\n\nfunction taskToAnnotation(task: FeedbackTask): Annotation | null {\n if (!task.feedbackMarker) return null;\n return {\n id: task.id,\n x: task.feedbackMarker.x,\n y: task.feedbackMarker.y,\n comment: task.title.replace(/^\\[피드백\\]\\s*/, \"\"),\n element: task.feedbackMarker.element || \"\",\n elementPath: \"\",\n timestamp: new Date(task.createdAt).getTime(),\n isFixed: task.feedbackMarker.isFixed,\n boundingBox: task.feedbackMarker.boundingBox,\n status: task.status as Annotation[\"status\"],\n };\n}\n\nexport function DebugWidget({ endpoint, getUser, onHide }: DebugWidgetProps) {\n const [isActive, setIsActive] = useState(false);\n const [annotations, setAnnotations] = useState<Annotation[]>(() => loadRouteAnnotations());\n const [pendingAnnotation, setPendingAnnotation] = useState<PendingAnnotation | null>(null);\n const [pendingExiting, setPendingExiting] = useState(false);\n const [hoverInfo, setHoverInfo] = useState<HoverInfo | null>(null);\n const [hoverPosition, setHoverPosition] = useState({ x: 0, y: 0 });\n const [animatedMarkers, setAnimatedMarkers] = useState<Set<string>>(new Set());\n const [submitting, setSubmitting] = useState(false);\n const [hoveredMarkerId, setHoveredMarkerId] = useState<string | null>(null);\n const [hoveredTargetElement, setHoveredTargetElement] = useState<HTMLElement | null>(null);\n const [showToast, setShowToast] = useState(false);\n const [toastError, setToastError] = useState<string | null>(null);\n const [activeThread, setActiveThread] = useState<string | null>(null);\n const [threadComments, setThreadComments] = useState<Record<string, CommentData[]>>({});\n const [serverTasks, setServerTasks] = useState<FeedbackTask[]>([]);\n const [allServerTasks, setAllServerTasks] = useState<FeedbackTask[]>([]);\n const [showInbox, setShowInbox] = useState(false);\n const [showSettings, setShowSettings] = useState(false);\n const [settings, setSettings] = useState<DebugSettings>(() => loadSettings());\n const [routePath, setRoutePath] = useState(() => window.location.pathname);\n const [hasHydratedServerTasks, setHasHydratedServerTasks] = useState(false);\n\n const [delayCountdown, setDelayCountdown] = useState<number | null>(null);\n const delayTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const popupRef = useRef<AnnotationPopupCSSHandle>(null);\n const recentlyAddedIdRef = useRef<string | null>(null);\n const justSubmittedRef = useRef(false);\n\n // -------------------------------------------------------------------------\n // FAB menu handler\n // -------------------------------------------------------------------------\n const startDelayedCapture = useCallback(() => {\n setDelayCountdown(3);\n let count = 3;\n const tick = () => {\n count -= 1;\n if (count <= 0) {\n setDelayCountdown(null);\n // 딜레이 후 피드백 모드 활성화\n setIsActive(true);\n document.documentElement.classList.add(\"impakers-selecting\");\n } else {\n setDelayCountdown(count);\n delayTimerRef.current = setTimeout(tick, 1000);\n }\n };\n delayTimerRef.current = setTimeout(tick, 1000);\n }, []);\n\n const handleFabSelect = useCallback((id: string) => {\n if (id === \"comment\") {\n toggleActive();\n } else if (id === \"delay-capture\") {\n startDelayedCapture();\n } else if (id === \"inbox\") {\n setShowInbox(true);\n // All 탭용 전체 피드백 로드\n fetchAllFeedbacks(endpoint, { staleWhileRevalidate: true })\n .then(setAllServerTasks)\n .catch(() => {});\n if (isActive) {\n setIsActive(false);\n document.documentElement.classList.remove(\"impakers-selecting\");\n setHoverInfo(null);\n setPendingAnnotation(null);\n }\n } else if (id === \"settings\") {\n setShowSettings(true);\n }\n }, [isActive, startDelayedCapture]);\n\n const handleSettingsChange = useCallback((newSettings: DebugSettings) => {\n setSettings(newSettings);\n saveSettings(newSettings);\n }, []);\n\n // -------------------------------------------------------------------------\n // Toggle active state\n // -------------------------------------------------------------------------\n const toggleActive = useCallback(() => {\n setIsActive((prev) => {\n const next = !prev;\n if (next) {\n document.documentElement.classList.add(\"impakers-selecting\");\n } else {\n document.documentElement.classList.remove(\"impakers-selecting\");\n setHoverInfo(null);\n setPendingAnnotation(null);\n }\n return next;\n });\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n document.documentElement.classList.remove(\"impakers-selecting\");\n };\n }, []);\n\n // 라우트별 마커 로드 (마운트 시 + 라우트 변경 시)\n useEffect(() => {\n setAnnotations(loadRouteAnnotations());\n\n // SPA 라우트 변경 감지 (pushState/popstate)\n const handleRouteChange = () => {\n setRoutePath(window.location.pathname);\n setAnnotations(loadRouteAnnotations());\n setPendingAnnotation(null);\n setHoverInfo(null);\n };\n window.addEventListener(\"popstate\", handleRouteChange);\n\n // Next.js 등 pushState 감지를 위한 패치\n const originalPushState = history.pushState.bind(history);\n history.pushState = (...args) => {\n originalPushState(...args);\n // pushState 후 약간 딜레이를 줘야 pathname이 갱신됨\n setTimeout(handleRouteChange, 50);\n };\n\n return () => {\n window.removeEventListener(\"popstate\", handleRouteChange);\n history.pushState = originalPushState;\n };\n }, []);\n\n useEffect(() => {\n const cacheKey = getFeedbacksCacheKey(routePath);\n const cached = getCachedSnapshot<FeedbackTask[]>(cacheKey);\n if (cached) {\n setServerTasks(cached);\n setHasHydratedServerTasks(true);\n }\n\n const unsubscribe = subscribeCache<FeedbackTask[]>(cacheKey, (tasks) => {\n setServerTasks(tasks);\n setHasHydratedServerTasks(true);\n });\n\n fetchFeedbacks(endpoint, routePath, { staleWhileRevalidate: true })\n .then((tasks) => {\n setServerTasks(tasks);\n setHasHydratedServerTasks(true);\n })\n .catch(() => {\n // 서버 로드 실패 → localStorage fallback (이미 로드됨)\n });\n\n return unsubscribe;\n }, [endpoint, routePath]);\n\n useEffect(() => {\n if (!hasHydratedServerTasks) return;\n const serverAnnotations = serverTasks\n .map(taskToAnnotation)\n .filter((annotation): annotation is Annotation => annotation !== null);\n setAnnotations(serverAnnotations);\n saveRouteAnnotations(serverAnnotations);\n }, [serverTasks, hasHydratedServerTasks]);\n\n // annotations 변경 시 localStorage 저장 (초기 마운트 skip)\n const isInitialMount = useRef(true);\n useEffect(() => {\n if (isInitialMount.current) {\n isInitialMount.current = false;\n return;\n }\n saveRouteAnnotations(annotations);\n }, [annotations]);\n\n // Escape key: popover 닫기 → 선택모드 해제 (2단계)\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n\n // inbox 열려있으면 닫기\n if (showInbox) {\n setShowInbox(false);\n return;\n }\n\n // pending annotation 있으면 popover 닫기\n if (pendingAnnotation) {\n e.preventDefault();\n setPendingExiting(true);\n originalSetTimeout(() => {\n setPendingAnnotation(null);\n setPendingExiting(false);\n }, 150);\n return;\n }\n\n // 선택 모드면 해제\n if (isActive) {\n e.preventDefault();\n setIsActive(false);\n document.documentElement.classList.remove(\"impakers-selecting\");\n setHoverInfo(null);\n }\n };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [showInbox, pendingAnnotation, isActive]);\n\n // -------------------------------------------------------------------------\n // Mouse move — hover highlight\n // -------------------------------------------------------------------------\n useEffect(() => {\n if (!isActive || pendingAnnotation) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n const target = (e.composedPath()[0] || e.target) as HTMLElement;\n if (closestCrossingShadow(target, \"[data-impakers-debug]\")) {\n setHoverInfo(null);\n return;\n }\n\n const elementUnder = deepElementFromPoint(e.clientX, e.clientY);\n if (!elementUnder || closestCrossingShadow(elementUnder, \"[data-impakers-debug]\")) {\n setHoverInfo(null);\n return;\n }\n\n const { name, elementName, path, reactComponents } = identifyElementWithReact(elementUnder);\n const rect = elementUnder.getBoundingClientRect();\n\n setHoverInfo({ element: name, elementName, elementPath: path, rect, reactComponents });\n setHoverPosition({ x: e.clientX, y: e.clientY });\n };\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n return () => document.removeEventListener(\"mousemove\", handleMouseMove);\n }, [isActive, pendingAnnotation]);\n\n // -------------------------------------------------------------------------\n // Click — select element\n // -------------------------------------------------------------------------\n useEffect(() => {\n if (!isActive) return;\n\n const handleClick = (e: MouseEvent) => {\n if (justSubmittedRef.current) return;\n const target = (e.composedPath()[0] || e.target) as HTMLElement;\n\n // 우리 UI 요소 클릭은 무시 (FAB, popup, marker 등)\n if (closestCrossingShadow(target, \"[data-impakers-debug]\")) return;\n if (closestCrossingShadow(target, \"[data-annotation-popup]\")) return;\n if (closestCrossingShadow(target, \"[data-annotation-marker]\")) return;\n\n // 이미 pending annotation이 있으면 shake로 알림\n if (pendingAnnotation) {\n e.preventDefault();\n e.stopPropagation();\n popupRef.current?.shake();\n return;\n }\n\n // 인터랙티브 요소 클릭 차단 (피드백 모드에서 네비게이션 방지)\n e.preventDefault();\n e.stopPropagation();\n\n const elementUnder = deepElementFromPoint(e.clientX, e.clientY);\n if (!elementUnder) return;\n\n const { name, path, reactComponents } = identifyElementWithReact(elementUnder);\n const rect = elementUnder.getBoundingClientRect();\n const x = (e.clientX / window.innerWidth) * 100;\n const isFixed = isElementFixed(elementUnder);\n const y = isFixed ? e.clientY : e.clientY + window.scrollY;\n\n const selection = window.getSelection();\n let selectedText: string | undefined;\n if (selection && selection.toString().trim().length > 0) {\n selectedText = selection.toString().trim().slice(0, 500);\n }\n\n const computedStylesObj = getDetailedComputedStyles(elementUnder);\n const computedStylesStr = getForensicComputedStyles(elementUnder);\n\n setPendingAnnotation({\n x,\n y,\n clientY: e.clientY,\n element: name,\n elementPath: path,\n selectedText,\n boundingBox: {\n x: rect.left,\n y: isFixed ? rect.top : rect.top + window.scrollY,\n width: rect.width,\n height: rect.height,\n },\n nearbyText: getNearbyText(elementUnder),\n cssClasses: getElementClasses(elementUnder),\n isFixed,\n fullPath: getFullElementPath(elementUnder),\n accessibility: getAccessibilityInfo(elementUnder),\n computedStyles: computedStylesStr,\n computedStylesObj,\n reactComponents: reactComponents ?? undefined,\n sourceFile: detectSourceFile(elementUnder),\n targetElement: elementUnder,\n });\n setHoverInfo(null);\n\n // 비동기 소스맵 resolve (popover 표시 후 업데이트)\n // 여러 후보를 시도하여 node_modules가 아닌 결과를 찾음\n const candidates = detectSourceFileCandidates(elementUnder);\n const chunkCandidates = candidates.filter((c) => c.includes(\"/chunks/\"));\n if (chunkCandidates.length > 0) {\n (async () => {\n for (const candidate of chunkCandidates) {\n try {\n const resolved = await resolveSourceString(candidate);\n if (resolved) {\n setPendingAnnotation((prev) =>\n prev ? {\n ...prev,\n resolvedSource: `${resolved.source}:${resolved.line}`,\n resolvedName: resolved.name ?? undefined,\n } : prev\n );\n break; // 첫 성공에서 멈춤\n }\n } catch {\n // 다음 후보 시도\n }\n }\n })();\n }\n };\n\n // Capture phase로 인터셉트\n document.addEventListener(\"click\", handleClick, true);\n return () => document.removeEventListener(\"click\", handleClick, true);\n }, [isActive, pendingAnnotation]);\n\n const showErrorToast = useCallback((msg: string) => {\n setToastError(msg);\n originalSetTimeout(() => setToastError(null), 4000);\n }, []);\n\n // -------------------------------------------------------------------------\n // Submit feedback — annotation comment → server\n // -------------------------------------------------------------------------\n const addAnnotation = useCallback(\n async (comment: string) => {\n if (!pendingAnnotation || submitting) return;\n setSubmitting(true);\n\n try {\n const metadata = collectMetadata(getUser);\n\n // 스크린샷 캡처 (위젯 숨기고 캡처)\n const screenshot = await captureFullPage();\n\n // 소스맵으로 원본 소스 파일 resolve 시도\n // 비동기 resolve가 이미 완료됐으면 resolvedSource 사용\n let resolvedSource = pendingAnnotation.resolvedSource || pendingAnnotation.sourceFile || \"\";\n let resolvedName: string | null = pendingAnnotation.resolvedName || null;\n // 아직 resolve 안 됐으면 시도\n if (!pendingAnnotation.resolvedSource && pendingAnnotation.sourceFile?.includes(\"/chunks/\")) {\n try {\n const resolved = await resolveSourceString(pendingAnnotation.sourceFile);\n if (resolved) {\n resolvedSource = `${resolved.source}:${resolved.line}:${resolved.column}`;\n resolvedName = resolved.name;\n }\n } catch {\n // resolve 실패 시 원본 유지\n }\n }\n\n const routeMatch = await getRouteDebugTargets(window.location.pathname);\n const componentTarget = resolvedSource && !resolvedSource.includes(\"/chunks/\")\n ? buildComponentDebugTarget(resolvedSource, resolvedName)\n : null;\n const debugTargets = mergeDebugTargets(\n componentTarget ? [componentTarget] : undefined,\n routeMatch?.targets,\n );\n if (debugTargets.length > 0) {\n metadata.debugTargets = debugTargets;\n }\n if (routeMatch?.context) {\n metadata.routeDebug = routeMatch.context;\n }\n\n // debugInfo 조합 (별도 컬럼으로 저장 — 마크다운 형식)\n const debugParts: string[] = [];\n\n // 피드백 제목\n debugParts.push(`## 피드백 ${comment}`);\n\n // 디버깅 타겟 파일\n if (debugTargets.length > 0) {\n debugParts.push(\"\");\n debugParts.push(\"---\");\n debugParts.push(\"\");\n debugParts.push(\"**디버깅 타겟 파일**:\");\n debugTargets.forEach((target) => {\n const suffix = target.line ? `:${target.line}${typeof target.column === \"number\" ? `:${target.column}` : \"\"}` : \"\";\n debugParts.push(`- [${target.kind}] \\`${target.file}${suffix}\\` (${target.reason})`);\n });\n }\n\n // 요소 정보\n const elementInfo: string[] = [];\n if (pendingAnnotation.element) {\n elementInfo.push(`**선택된 요소**: ${pendingAnnotation.element}`);\n }\n if (pendingAnnotation.elementPath) {\n elementInfo.push(`**DOM 경로**: \\`${pendingAnnotation.elementPath}\\``);\n }\n if (pendingAnnotation.selectedText) {\n elementInfo.push(`**선택된 텍스트**: \"${pendingAnnotation.selectedText}\"`);\n }\n if (pendingAnnotation.reactComponents?.trim()) {\n elementInfo.push(`**React 컴포넌트**: ${pendingAnnotation.reactComponents}`);\n } else if (resolvedName) {\n elementInfo.push(`**컴포넌트/함수**: ${resolvedName}`);\n }\n if (resolvedSource && !resolvedSource.includes(\"/chunks/\")) {\n elementInfo.push(`**소스 파일**: \\`${resolvedSource}\\``);\n }\n if (pendingAnnotation.cssClasses) {\n elementInfo.push(`**CSS 클래스**: \\`${pendingAnnotation.cssClasses}\\``);\n }\n if (pendingAnnotation.nearbyText) {\n elementInfo.push(`**주변 텍스트**: ${pendingAnnotation.nearbyText}`);\n }\n if (pendingAnnotation.accessibility) {\n elementInfo.push(`**접근성**: ${pendingAnnotation.accessibility}`);\n }\n if (elementInfo.length > 0) {\n debugParts.push(\"\");\n debugParts.push(\"---\");\n debugParts.push(\"\");\n elementInfo.forEach((line) => debugParts.push(line));\n }\n\n // 에러 로그\n if (metadata.consoleErrors?.length) {\n debugParts.push(\"\");\n debugParts.push(\"---\");\n debugParts.push(\"\");\n debugParts.push(\"**최근 콘솔 에러**:\");\n metadata.consoleErrors.slice(-10).forEach((e) => debugParts.push(`- \\`${e.slice(0, 200)}\\``));\n }\n\n // 최근 콘솔 로그 (에러/경고)\n if (metadata.consoleLogs?.length) {\n const recentLogs = metadata.consoleLogs\n .filter((l) => l.level === \"error\" || l.level === \"warn\")\n .slice(-10);\n if (recentLogs.length > 0) {\n debugParts.push(\"\");\n debugParts.push(\"**최근 콘솔 로그**:\");\n recentLogs.forEach((l) => debugParts.push(`- [${l.level}] \\`${l.message.slice(0, 200)}\\``));\n }\n }\n\n // 환경 정보\n debugParts.push(\"\");\n debugParts.push(\"---\");\n debugParts.push(\"\");\n debugParts.push(\"## 환경 정보\");\n debugParts.push(\"\");\n debugParts.push(`- **URL**: ${metadata.url}`);\n debugParts.push(`- **시점**: ${new Date(metadata.timestamp).toLocaleString(\"ko-KR\")}`);\n debugParts.push(`- **브라우저**: ${metadata.browser}`);\n debugParts.push(`- **화면**: ${metadata.viewport} (@${metadata.pixelRatio}x)`);\n debugParts.push(`- **언어**: ${metadata.language}`);\n if (metadata.user?.name) {\n debugParts.push(`- **사용자**: ${metadata.user.name}`);\n }\n\n // 성능\n if (metadata.performance && Object.keys(metadata.performance).length > 0) {\n debugParts.push(\"\");\n debugParts.push(\"---\");\n debugParts.push(\"\");\n debugParts.push(\"## 성능\");\n debugParts.push(\"\");\n debugParts.push(\"| 항목 | 값 |\");\n debugParts.push(\"|------|-----|\");\n const perfLabels: Record<string, string> = {\n pageLoadTime: \"페이지 로딩\",\n domContentLoaded: \"DOM 로드\",\n ttfb: \"TTFB\",\n firstContentfulPaint: \"FCP\",\n usedJSHeapMB: \"메모리 사용\",\n totalJSHeapMB: \"메모리 전체\",\n };\n for (const [key, value] of Object.entries(metadata.performance)) {\n const label = perfLabels[key] || key;\n const unit = key.includes(\"Heap\") ? \"MB\" : \"ms\";\n debugParts.push(`| ${label} | ${value}${unit} |`);\n }\n }\n\n const debugInfoContent = debugParts.join(\"\\n\");\n\n const result = await submitFeedback(endpoint, {\n title: comment.slice(0, 100),\n description: \"\",\n priority: \"medium\",\n metadata,\n debugInfo: debugInfoContent,\n debug_info: debugInfoContent,\n screenshot,\n feedbackUrl: window.location.pathname,\n feedbackMarker: {\n x: pendingAnnotation.x,\n y: pendingAnnotation.y,\n isFixed: pendingAnnotation.isFixed || false,\n element: pendingAnnotation.element,\n boundingBox: pendingAnnotation.boundingBox,\n },\n authorName: getUser?.()?.name ? String(getUser()!.name) : undefined,\n });\n\n // 성공 토스트\n setShowToast(true);\n originalSetTimeout(() => setShowToast(false), 3000);\n\n const newTaskId = result.taskId || null;\n recentlyAddedIdRef.current = newTaskId;\n originalSetTimeout(() => {\n recentlyAddedIdRef.current = null;\n }, 300);\n originalSetTimeout(() => {\n if (!newTaskId) return;\n setAnimatedMarkers((prev) => new Set(prev).add(newTaskId));\n }, 250);\n\n setPendingExiting(true);\n originalSetTimeout(() => {\n setPendingAnnotation(null);\n setPendingExiting(false);\n // 피드백 제출 완료 → 선택 모드 해제\n setIsActive(false);\n document.documentElement.classList.remove(\"impakers-selecting\");\n justSubmittedRef.current = true;\n setTimeout(() => { justSubmittedRef.current = false; }, 300);\n }, 150);\n\n window.getSelection()?.removeAllRanges();\n } catch (err: any) {\n const msg = err?.message || \"피드백 전송 실패\";\n showErrorToast(msg);\n console.error(\"[@impakers/debug] 피드백 전송 실패:\", err);\n } finally {\n setSubmitting(false);\n }\n },\n [pendingAnnotation, submitting, endpoint, getUser, showErrorToast],\n );\n\n const cancelAnnotation = useCallback(() => {\n setPendingExiting(true);\n originalSetTimeout(() => {\n setPendingAnnotation(null);\n setPendingExiting(false);\n setIsActive(false);\n document.documentElement.classList.remove(\"impakers-selecting\");\n justSubmittedRef.current = true;\n setTimeout(() => { justSubmittedRef.current = false; }, 300);\n }, 150);\n }, []);\n\n // -------------------------------------------------------------------------\n // Marker click → open comment thread\n // -------------------------------------------------------------------------\n const handleMarkerClick = useCallback((annotation: Annotation) => {\n const newId = annotation.id;\n setActiveThread((prev) => {\n if (prev === newId) return null;\n return newId;\n });\n }, []);\n\n useEffect(() => {\n if (!activeThread) return;\n\n const cacheKey = getCommentsCacheKey(activeThread);\n const cached = getCachedSnapshot<FeedbackComment[]>(cacheKey);\n if (cached) {\n setThreadComments((prev) => ({ ...prev, [activeThread]: cached }));\n }\n\n const unsubscribe = subscribeCache<FeedbackComment[]>(cacheKey, (comments) => {\n setThreadComments((prev) => ({ ...prev, [activeThread]: comments }));\n });\n\n fetchComments(endpoint, activeThread, { staleWhileRevalidate: true }).catch(() => {});\n return unsubscribe;\n }, [activeThread, endpoint]);\n\n const handleThreadReply = useCallback(async (taskId: string, content: string, screenshot?: string, file?: File) => {\n const authorName = getUser?.()?.name ? String(getUser()!.name) : \"익명\";\n const authorId = getUser?.()?.id ? String(getUser()!.id) : undefined;\n\n try {\n let fileResult;\n if (file) {\n try {\n fileResult = await uploadFile(endpoint, file, \"comment\", taskId);\n } catch (uploadErr: any) {\n const msg = uploadErr?.message || \"파일 업로드 실패\";\n showErrorToast(msg);\n console.error(\"[@impakers/debug] 파일 업로드 실패:\", uploadErr);\n // 파일 업로드 실패해도 텍스트/스크린샷 코멘트는 전송\n }\n }\n\n await postComment(endpoint, taskId, content, authorName, authorId, screenshot, fileResult);\n } catch (err: any) {\n const msg = err?.message || \"코멘트 전송 실패\";\n showErrorToast(msg);\n console.error(\"[@impakers/debug] 코멘트 전송 실패:\", err);\n }\n }, [getUser, endpoint, showErrorToast]);\n\n const handleThreadClose = useCallback(() => {\n setActiveThread(null);\n }, []);\n\n // -------------------------------------------------------------------------\n // Marker hover — show element outline\n // -------------------------------------------------------------------------\n const handleMarkerHover = useCallback((annotation: Annotation | null) => {\n if (!annotation) {\n setHoveredMarkerId(null);\n setHoveredTargetElement(null);\n return;\n }\n setHoveredMarkerId(annotation.id);\n\n if (annotation.boundingBox) {\n const bb = annotation.boundingBox;\n const centerX = bb.x + bb.width / 2;\n const centerY = annotation.isFixed\n ? bb.y + bb.height / 2\n : bb.y + bb.height / 2 - window.scrollY;\n const el = deepElementFromPoint(centerX, centerY);\n if (el) {\n const elRect = el.getBoundingClientRect();\n const widthRatio = elRect.width / bb.width;\n const heightRatio = elRect.height / bb.height;\n if (widthRatio >= 0.5 && heightRatio >= 0.5) {\n setHoveredTargetElement(el);\n return;\n }\n }\n }\n setHoveredTargetElement(null);\n }, []);\n\n // -------------------------------------------------------------------------\n // Popup positioning\n // -------------------------------------------------------------------------\n const getPopupPosition = useCallback(() => {\n if (!pendingAnnotation) return { left: 0, top: 0 };\n\n const markerX = (pendingAnnotation.x / 100) * window.innerWidth;\n const markerY = pendingAnnotation.isFixed\n ? pendingAnnotation.y\n : pendingAnnotation.y - window.scrollY;\n\n const left = Math.max(160, Math.min(window.innerWidth - 160, markerX));\n\n if (markerY > window.innerHeight - 290) {\n return { left, bottom: window.innerHeight - markerY + 20 };\n }\n return { left, top: markerY + 20 };\n }, [pendingAnnotation]);\n\n // -------------------------------------------------------------------------\n // Render\n // -------------------------------------------------------------------------\n if (typeof document === \"undefined\") return null;\n\n const popupPos = getPopupPosition();\n const hoveredRect = hoveredTargetElement?.getBoundingClientRect();\n\n // FAB menu items\n const fabItems: FabMenuItem[] = [\n {\n id: \"comment\",\n label: \"피드백\",\n active: isActive,\n icon: (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z\" />\n </svg>\n ),\n },\n {\n id: \"delay-capture\",\n label: \"딜레이 캡처\",\n icon: (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 16 14\" />\n </svg>\n ),\n },\n {\n id: \"inbox\",\n label: \"Inbox\",\n badge: annotations.length || undefined,\n icon: (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"22 12 16 12 14 15 10 15 8 12 2 12\" />\n <path d=\"M5.45 5.11L2 12v6a2 2 0 002 2h16a2 2 0 002-2v-6l-3.45-6.89A2 2 0 0016.76 4H7.24a2 2 0 00-1.79 1.11z\" />\n </svg>\n ),\n },\n {\n id: \"settings\",\n label: \"설정\",\n icon: (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\" />\n </svg>\n ),\n },\n ];\n\n // Inbox items from local annotations\n const currentPath = routePath;\n // 설정에 따라 마커 필터링\n const currentUserName = getUser?.()?.name ? String(getUser()!.name) : null;\n const visibleAnnotations = useMemo(() => {\n return annotations.filter((a) => {\n const task = serverTasks.find((t) => t.id === a.id);\n if (settings.hideDoneMarkers && (a.status === \"done\" || a.status === \"resolved\")) return false;\n if (settings.showOnlyMine && task?.authorName && currentUserName && task.authorName !== currentUserName) return false;\n return true;\n });\n }, [annotations, serverTasks, settings.hideDoneMarkers, settings.showOnlyMine, currentUserName]);\n\n const allInboxItems: InboxItem[] = serverTasks.map((task) => ({\n id: task.id,\n title: task.title || \"피드백\",\n status: task.status,\n priority: task.priority,\n authorName: task.authorName || \"익명\",\n feedbackUrl: task.feedbackUrl || currentPath,\n createdAt: task.createdAt,\n commentCount: task.commentCount || 0,\n }));\n\n // All 탭: 서버에서 가져온 전체 피드백 사용\n const allRouteItems: InboxItem[] = allServerTasks.map((task) => ({\n id: task.id,\n title: task.title || \"피드백\",\n status: task.status,\n priority: task.priority,\n authorName: task.authorName || \"익명\",\n feedbackUrl: task.feedbackUrl || \"\",\n createdAt: task.createdAt,\n commentCount: task.commentCount || 0,\n }));\n\n return createPortal(\n <div data-impakers-debug=\"\">\n {/* FAB Menu */}\n <FabMenu\n items={fabItems}\n onSelect={handleFabSelect}\n onHide={onHide}\n onDoubleTap={toggleActive}\n />\n\n {/* Inbox Panel */}\n {showInbox && (\n <InboxPanel\n pageItems={allInboxItems}\n allItems={allRouteItems}\n currentPath={currentPath}\n serviceName={getServiceName() || undefined}\n endpoint={endpoint}\n currentUserName={getUser?.()?.name ? String(getUser()!.name) : \"익명\"}\n currentUserId={getUser?.()?.id ? String(getUser()!.id) : undefined}\n onClose={() => setShowInbox(false)}\n />\n )}\n\n {/* Settings Panel */}\n {showSettings && (\n <SettingsPanel\n settings={settings}\n onChange={handleSettingsChange}\n onClose={() => setShowSettings(false)}\n />\n )}\n\n {/* Hover highlight + tooltip */}\n {isActive && (\n <>\n {/* Hover highlight box */}\n {hoverInfo?.rect && !pendingAnnotation && (\n <div\n className={`${styles.hoverHighlight} ${styles.enter}`}\n style={{\n left: hoverInfo.rect.left,\n top: hoverInfo.rect.top,\n width: hoverInfo.rect.width,\n height: hoverInfo.rect.height,\n }}\n />\n )}\n\n {/* Hover tooltip */}\n {hoverInfo && !pendingAnnotation && (\n <div\n className={`${styles.hoverTooltip} ${styles.enter}`}\n style={{\n left: Math.min(hoverPosition.x + 14, window.innerWidth - 200),\n top: hoverPosition.y + 14,\n }}\n >\n {hoverInfo.reactComponents && (\n <div className={styles.hoverReactPath}>{hoverInfo.reactComponents}</div>\n )}\n <div className={styles.hoverElementName}>{hoverInfo.elementName}</div>\n </div>\n )}\n\n {/* Selected element outline (when hovering marker) */}\n {hoveredRect && hoveredMarkerId && (\n <div\n className={`${styles.singleSelectOutline} ${styles.enter}`}\n style={{\n left: hoveredRect.left,\n top: hoveredRect.top,\n width: hoveredRect.width,\n height: hoveredRect.height,\n }}\n />\n )}\n\n {/* Pending annotation element outline */}\n {pendingAnnotation?.targetElement && (() => {\n const r = pendingAnnotation.targetElement!.getBoundingClientRect();\n return (\n <div\n className={`${styles.singleSelectOutline} ${styles.enter}`}\n style={{ left: r.left, top: r.top, width: r.width, height: r.height }}\n />\n );\n })()}\n </>\n )}\n\n {/* Markers layer (scroll with page) */}\n <div className={styles.markersLayer} data-impakers-debug=\"\" style={{ display: settings.markersVisible ? undefined : \"none\" }}>\n {visibleAnnotations\n .filter((a) => !a.isFixed)\n .map((annotation, i) => (\n <AnnotationMarker\n key={annotation.id}\n annotation={annotation}\n layerIndex={i}\n isAnimated={animatedMarkers.has(annotation.id)}\n isHovered={hoveredMarkerId === annotation.id}\n isDeleting={false}\n markerClickBehavior=\"edit\"\n accentColor={settings.markerColor}\n onHover={() => handleMarkerHover(annotation)}\n onHoverEnd={() => handleMarkerHover(null)}\n onClick={() => handleMarkerClick(annotation)}\n onContextMenu={() => {}}\n />\n ))}\n </div>\n\n {/* Fixed markers layer */}\n <div className={styles.fixedMarkersLayer} data-impakers-debug=\"\" style={{ display: settings.markersVisible ? undefined : \"none\" }}>\n {visibleAnnotations\n .filter((a) => a.isFixed)\n .map((annotation, i) => (\n <AnnotationMarker\n key={annotation.id}\n annotation={annotation}\n layerIndex={i}\n isAnimated={animatedMarkers.has(annotation.id)}\n isHovered={hoveredMarkerId === annotation.id}\n isDeleting={false}\n markerClickBehavior=\"edit\"\n accentColor={settings.markerColor}\n onHover={() => handleMarkerHover(annotation)}\n onHoverEnd={() => handleMarkerHover(null)}\n onClick={() => handleMarkerClick(annotation)}\n onContextMenu={() => {}}\n />\n ))}\n\n {/* Pending marker */}\n {pendingAnnotation && (\n <PendingMarker\n x={pendingAnnotation.x}\n y={pendingAnnotation.clientY}\n isMultiSelect={false}\n accentColor={settings.markerColor}\n />\n )}\n </div>\n\n {/* Annotation popup */}\n {pendingAnnotation && (\n <AnnotationPopupCSS\n ref={popupRef}\n element={pendingAnnotation.resolvedSource || pendingAnnotation.resolvedName || pendingAnnotation.element}\n selectedText={pendingAnnotation.selectedText}\n isExiting={pendingExiting}\n style={{\n position: \"fixed\",\n left: popupPos.left,\n ...(\"top\" in popupPos ? { top: popupPos.top } : {}),\n ...(\"bottom\" in popupPos ? { bottom: (popupPos as any).bottom } : {}),\n transform: \"translateX(-50%)\",\n zIndex: 100001,\n }}\n onSubmit={addAnnotation}\n onCancel={cancelAnnotation}\n />\n )}\n\n {/* Comment thread */}\n {activeThread && (() => {\n const annotation = annotations.find((a) => a.id === activeThread);\n const taskData = serverTasks.find((task) => task.id === activeThread);\n if (!annotation) return null;\n\n const markerX = (annotation.x / 100) * window.innerWidth;\n const markerY = annotation.isFixed\n ? annotation.y\n : annotation.y - window.scrollY;\n\n const threadLeft = Math.max(10, Math.min(markerX + 20, window.innerWidth - 360));\n const threadTop = Math.max(10, Math.min(markerY, window.innerHeight - 400));\n\n const task: ThreadTask = {\n id: annotation.id,\n title: taskData?.title || annotation.comment || \"피드백\",\n status: taskData?.status || \"todo\",\n authorName: taskData?.authorName || undefined,\n createdAt: taskData?.createdAt || new Date(annotation.timestamp).toISOString(),\n comments: threadComments[annotation.id] || [],\n };\n\n return (\n <CommentThread\n task={task}\n currentUserName={getUser?.()?.name ? String(getUser()!.name) : \"익명\"}\n currentUserId={getUser?.()?.id ? String(getUser()!.id) : undefined}\n left={threadLeft}\n top={threadTop}\n onClose={handleThreadClose}\n onReply={handleThreadReply}\n />\n );\n })()}\n\n {/* 딜레이 캡처 카운트다운 */}\n {delayCountdown !== null && (\n <div className={styles.countdownOverlay} data-impakers-debug=\"\">\n <div className={styles.countdownNumber}>{delayCountdown}</div>\n <div className={styles.countdownLabel}>피드백 모드 활성화까지...</div>\n <button\n className={styles.countdownCancel}\n onClick={() => {\n if (delayTimerRef.current) clearTimeout(delayTimerRef.current);\n setDelayCountdown(null);\n }}\n type=\"button\"\n >\n 취소\n </button>\n </div>\n )}\n\n {/* 성공 토스트 */}\n {showToast && (\n <div className={styles.toast} data-impakers-debug=\"\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#16a34a\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n <span>\n 태스크 생성이 완료되었습니다\n </span>\n </div>\n )}\n\n {/* 에러 토스트 */}\n {toastError && (\n <div className={`${styles.toast} ${styles.toastError}`} data-impakers-debug=\"\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ef4444\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\n </svg>\n <span>{toastError}</span>\n </div>\n )}\n </div>,\n document.body,\n );\n}\n","\"use client\";\n\nimport { useState, useRef, useEffect, useCallback, forwardRef, useImperativeHandle } from \"react\";\nimport styles from \"./styles.module.scss\";\nimport { IconTrash } from \"../icons\";\nimport { originalSetTimeout } from \"../../utils/freeze-animations\";\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\n/** Focus an element while temporarily blocking focus-trap libraries (e.g. Radix\n * FocusScope) from reclaiming focus via focusin/focusout handlers. */\nfunction focusBypassingTraps(el: HTMLElement | null) {\n if (!el) return;\n const trap = (e: Event) => e.stopImmediatePropagation();\n document.addEventListener(\"focusin\", trap, true);\n document.addEventListener(\"focusout\", trap, true);\n try {\n el.focus();\n } finally {\n document.removeEventListener(\"focusin\", trap, true);\n document.removeEventListener(\"focusout\", trap, true);\n }\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface AnnotationPopupCSSProps {\n /** Element name to display in header */\n element: string;\n /** Optional timestamp display (e.g., \"@ 1.23s\" for animation feedback) */\n timestamp?: string;\n /** Optional selected/highlighted text */\n selectedText?: string;\n /** Placeholder text for the textarea */\n placeholder?: string;\n /** Initial value for textarea (for edit mode) */\n initialValue?: string;\n /** Label for submit button (default: \"Add\") */\n submitLabel?: string;\n /** Called when annotation is submitted with text */\n onSubmit: (text: string) => void;\n /** Called when popup is cancelled/dismissed */\n onCancel: () => void;\n /** Called when delete button is clicked (only shown if provided) */\n onDelete?: () => void;\n /** Position styles (left, top) */\n style?: React.CSSProperties;\n /** Custom color for submit button and textarea focus (hex) */\n accentColor?: string;\n /** External exit state (parent controls exit animation) */\n isExiting?: boolean;\n /** Light mode styling */\n lightMode?: boolean;\n /** Computed styles for the selected element */\n computedStyles?: Record<string, string>;\n}\n\nexport interface AnnotationPopupCSSHandle {\n /** Shake the popup (e.g., when user clicks outside) */\n shake: () => void;\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport const AnnotationPopupCSS = forwardRef<AnnotationPopupCSSHandle, AnnotationPopupCSSProps>(\n function AnnotationPopupCSS(\n {\n element,\n timestamp,\n selectedText,\n placeholder = \"What should change?\",\n initialValue = \"\",\n submitLabel = \"Add\",\n onSubmit,\n onCancel,\n onDelete,\n style,\n accentColor = \"#3c82f7\",\n isExiting = false,\n lightMode = false,\n computedStyles,\n },\n ref\n ) {\n const [text, setText] = useState(initialValue);\n const [isShaking, setIsShaking] = useState(false);\n const [animState, setAnimState] = useState<\"initial\" | \"enter\" | \"entered\" | \"exit\">(\"initial\");\n const [isFocused, setIsFocused] = useState(false);\n const [isStylesExpanded, setIsStylesExpanded] = useState(false); // Computed styles accordion state\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const popupRef = useRef<HTMLDivElement>(null);\n const cancelTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const shakeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Sync with parent exit state\n useEffect(() => {\n if (isExiting && animState !== \"exit\") {\n setAnimState(\"exit\");\n }\n }, [isExiting, animState]);\n\n // Animate in on mount and focus textarea\n useEffect(() => {\n // Start enter animation (use originalSetTimeout to bypass freeze patch)\n originalSetTimeout(() => {\n setAnimState(\"enter\");\n }, 0);\n // Transition to entered state after animation completes\n const enterTimer = originalSetTimeout(() => {\n setAnimState(\"entered\");\n }, 200); // Match animation duration\n const focusTimer = originalSetTimeout(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n focusBypassingTraps(textarea);\n textarea.selectionStart = textarea.selectionEnd = textarea.value.length;\n textarea.scrollTop = textarea.scrollHeight;\n }\n }, 50);\n return () => {\n clearTimeout(enterTimer);\n clearTimeout(focusTimer);\n if (cancelTimerRef.current) clearTimeout(cancelTimerRef.current);\n if (shakeTimerRef.current) clearTimeout(shakeTimerRef.current);\n };\n }, []);\n\n // Shake animation\n const shake = useCallback(() => {\n if (shakeTimerRef.current) clearTimeout(shakeTimerRef.current);\n setIsShaking(true);\n shakeTimerRef.current = originalSetTimeout(() => {\n setIsShaking(false);\n focusBypassingTraps(textareaRef.current);\n }, 250);\n }, []);\n\n // Expose shake to parent via ref\n useImperativeHandle(ref, () => ({\n shake,\n }), [shake]);\n\n // Handle cancel with exit animation\n const handleCancel = useCallback(() => {\n setAnimState(\"exit\");\n cancelTimerRef.current = originalSetTimeout(() => {\n onCancel();\n }, 150); // Match exit animation duration\n }, [onCancel]);\n\n // Handle submit\n const handleSubmit = useCallback(() => {\n if (!text.trim()) return;\n onSubmit(text.trim());\n }, [text, onSubmit]);\n\n // Handle keyboard\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n e.stopPropagation();\n if (e.nativeEvent.isComposing) return;\n if (e.key === \"Enter\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n handleSubmit();\n }\n if (e.key === \"Escape\") {\n handleCancel();\n }\n },\n [handleSubmit, handleCancel]\n );\n\n const popupClassName = [\n styles.popup,\n lightMode ? styles.light : \"\",\n animState === \"enter\" ? styles.enter : \"\",\n animState === \"entered\" ? styles.entered : \"\",\n animState === \"exit\" ? styles.exit : \"\",\n isShaking ? styles.shake : \"\",\n ].filter(Boolean).join(\" \");\n\n return (\n <div\n ref={popupRef}\n className={popupClassName}\n data-annotation-popup\n style={style}\n onClick={(e) => e.stopPropagation()}\n >\n <div className={styles.header}>\n {computedStyles && Object.keys(computedStyles).length > 0 ? (\n <button\n className={styles.headerToggle}\n onClick={() => {\n const wasExpanded = isStylesExpanded;\n setIsStylesExpanded(!isStylesExpanded);\n if (wasExpanded) {\n // Refocus textarea when closing\n originalSetTimeout(() => focusBypassingTraps(textareaRef.current), 0);\n }\n }}\n type=\"button\"\n >\n <svg\n className={`${styles.chevron} ${isStylesExpanded ? styles.expanded : \"\"}`}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M5.5 10.25L9 7.25L5.75 4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span className={styles.element}>{element}</span>\n </button>\n ) : (\n <span className={styles.element}>{element}</span>\n )}\n {timestamp && <span className={styles.timestamp}>{timestamp}</span>}\n </div>\n\n {/* Collapsible computed styles section - uses grid-template-rows for smooth animation */}\n {computedStyles && Object.keys(computedStyles).length > 0 && (\n <div className={`${styles.stylesWrapper} ${isStylesExpanded ? styles.expanded : \"\"}`}>\n <div className={styles.stylesInner}>\n <div className={styles.stylesBlock}>\n {Object.entries(computedStyles).map(([key, value]) => (\n <div key={key} className={styles.styleLine}>\n <span className={styles.styleProperty}>\n {key.replace(/([A-Z])/g, \"-$1\").toLowerCase()}\n </span>\n : <span className={styles.styleValue}>{value}</span>;\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n\n {selectedText && (\n <div className={styles.quote}>\n &ldquo;{selectedText.slice(0, 80)}\n {selectedText.length > 80 ? \"...\" : \"\"}&rdquo;\n </div>\n )}\n\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n style={{ borderColor: isFocused ? accentColor : undefined }}\n placeholder={placeholder}\n value={text}\n onChange={(e) => {\n setText(e.target.value);\n // auto-resize\n const el = e.target;\n el.style.height = \"auto\";\n el.style.height = `${Math.min(el.scrollHeight, 200)}px`;\n }}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n rows={4}\n onKeyDown={handleKeyDown}\n />\n\n <div className={styles.actions}>\n {onDelete && (\n <div className={styles.deleteWrapper}>\n <button className={styles.deleteButton} onClick={onDelete} type=\"button\">\n <IconTrash size={22} />\n </button>\n </div>\n )}\n <button className={styles.cancel} onClick={handleCancel}>\n Cancel\n </button>\n <button\n className={styles.submit}\n style={{\n backgroundColor: accentColor,\n opacity: text.trim() ? 1 : 0.4,\n }}\n onClick={handleSubmit}\n disabled={!text.trim()}\n >\n {submitLabel}\n </button>\n </div>\n <div className={styles.shortcutHint}>\n {navigator?.platform?.includes(\"Mac\") ? \"⌘\" : \"Ctrl\"}+Enter to submit\n </div>\n </div>\n );\n }\n);\n\nexport default AnnotationPopupCSS;\n","\nconst css = \".styles-module__popup___IhzrD svg[fill=none] {\\n fill: none !important;\\n}\\n.styles-module__popup___IhzrD svg[fill=none] :not([fill]) {\\n fill: none !important;\\n}\\n\\n@keyframes styles-module__popupEnter___AuQDN {\\n from {\\n opacity: 0;\\n transform: translateX(-50%) scale(0.95) translateY(4px);\\n }\\n to {\\n opacity: 1;\\n transform: translateX(-50%) scale(1) translateY(0);\\n }\\n}\\n@keyframes styles-module__popupExit___JJKQX {\\n from {\\n opacity: 1;\\n transform: translateX(-50%) scale(1) translateY(0);\\n }\\n to {\\n opacity: 0;\\n transform: translateX(-50%) scale(0.95) translateY(4px);\\n }\\n}\\n@keyframes styles-module__shake___jdbWe {\\n 0%, 100% {\\n transform: translateX(-50%) scale(1) translateY(0) translateX(0);\\n }\\n 20% {\\n transform: translateX(-50%) scale(1) translateY(0) translateX(-3px);\\n }\\n 40% {\\n transform: translateX(-50%) scale(1) translateY(0) translateX(3px);\\n }\\n 60% {\\n transform: translateX(-50%) scale(1) translateY(0) translateX(-2px);\\n }\\n 80% {\\n transform: translateX(-50%) scale(1) translateY(0) translateX(2px);\\n }\\n}\\n.styles-module__popup___IhzrD {\\n position: fixed;\\n transform: translateX(-50%);\\n width: 280px;\\n padding: 0.75rem 1rem 14px;\\n background: #1a1a1a;\\n border-radius: 16px;\\n box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.08);\\n z-index: 100001;\\n font-family: system-ui, -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, sans-serif;\\n will-change: transform, opacity;\\n opacity: 0;\\n}\\n.styles-module__popup___IhzrD.styles-module__enter___L7U7N {\\n animation: styles-module__popupEnter___AuQDN 0.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;\\n}\\n.styles-module__popup___IhzrD.styles-module__entered___COX-w {\\n opacity: 1;\\n transform: translateX(-50%) scale(1) translateY(0);\\n}\\n.styles-module__popup___IhzrD.styles-module__exit___5eGjE {\\n animation: styles-module__popupExit___JJKQX 0.15s ease-in forwards;\\n}\\n.styles-module__popup___IhzrD.styles-module__entered___COX-w.styles-module__shake___jdbWe {\\n animation: styles-module__shake___jdbWe 0.25s ease-out;\\n}\\n\\n.styles-module__header___wWsSi {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n margin-bottom: 0.5625rem;\\n}\\n\\n.styles-module__element___fTV2z {\\n font-size: 0.75rem;\\n font-weight: 400;\\n color: rgba(255, 255, 255, 0.5);\\n max-width: 100%;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n flex: 1;\\n}\\n\\n.styles-module__headerToggle___WpW0b {\\n display: flex;\\n align-items: center;\\n gap: 0.25rem;\\n background: none;\\n border: none;\\n padding: 0;\\n cursor: pointer;\\n flex: 1;\\n min-width: 0;\\n text-align: left;\\n}\\n.styles-module__headerToggle___WpW0b .styles-module__element___fTV2z {\\n flex: 1;\\n}\\n\\n.styles-module__chevron___ZZJlR {\\n color: rgba(255, 255, 255, 0.5);\\n transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);\\n flex-shrink: 0;\\n}\\n.styles-module__chevron___ZZJlR.styles-module__expanded___2Hxgv {\\n transform: rotate(90deg);\\n}\\n\\n.styles-module__stylesWrapper___pnHgy {\\n display: grid;\\n grid-template-rows: 0fr;\\n transition: grid-template-rows 0.3s cubic-bezier(0.16, 1, 0.3, 1);\\n}\\n.styles-module__stylesWrapper___pnHgy.styles-module__expanded___2Hxgv {\\n grid-template-rows: 1fr;\\n}\\n\\n.styles-module__stylesInner___YYZe2 {\\n overflow: hidden;\\n}\\n\\n.styles-module__stylesBlock___VfQKn {\\n background: rgba(255, 255, 255, 0.05);\\n border-radius: 0.375rem;\\n padding: 0.5rem 0.625rem;\\n margin-bottom: 0.5rem;\\n font-family: ui-monospace, SFMono-Regular, \\\"SF Mono\\\", Menlo, Consolas, monospace;\\n font-size: 0.6875rem;\\n line-height: 1.5;\\n}\\n\\n.styles-module__styleLine___1YQiD {\\n color: rgba(255, 255, 255, 0.85);\\n word-break: break-word;\\n}\\n\\n.styles-module__styleProperty___84L1i {\\n color: #c792ea;\\n}\\n\\n.styles-module__styleValue___q51-h {\\n color: rgba(255, 255, 255, 0.85);\\n}\\n\\n.styles-module__timestamp___Dtpsv {\\n font-size: 0.625rem;\\n font-weight: 500;\\n color: rgba(255, 255, 255, 0.35);\\n font-variant-numeric: tabular-nums;\\n margin-left: 0.5rem;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__quote___mcMmQ {\\n font-size: 12px;\\n font-style: italic;\\n color: rgba(255, 255, 255, 0.6);\\n margin-bottom: 0.5rem;\\n padding: 0.4rem 0.5rem;\\n background: rgba(255, 255, 255, 0.05);\\n border-radius: 0.25rem;\\n line-height: 1.45;\\n}\\n\\n.styles-module__textarea___jrSae {\\n box-sizing: border-box;\\n width: 100%;\\n padding: 0.5rem 0.625rem;\\n font-size: 0.8125rem;\\n font-family: inherit;\\n line-height: 1.55;\\n background: rgba(255, 255, 255, 0.05);\\n color: #fff;\\n border: 1px solid rgba(255, 255, 255, 0.15);\\n border-radius: 8px;\\n resize: none;\\n outline: none;\\n min-height: 80px;\\n max-height: 200px;\\n transition: border-color 0.15s ease, height 0.1s ease;\\n}\\n.styles-module__textarea___jrSae:focus {\\n border-color: var(--agentation-color-blue);\\n}\\n.styles-module__textarea___jrSae.styles-module__green___99l3h:focus {\\n border-color: var(--agentation-color-green);\\n}\\n.styles-module__textarea___jrSae::placeholder {\\n color: rgba(255, 255, 255, 0.35);\\n}\\n.styles-module__textarea___jrSae::-webkit-scrollbar {\\n width: 6px;\\n}\\n.styles-module__textarea___jrSae::-webkit-scrollbar-track {\\n background: transparent;\\n}\\n.styles-module__textarea___jrSae::-webkit-scrollbar-thumb {\\n background: rgba(255, 255, 255, 0.2);\\n border-radius: 3px;\\n}\\n\\n.styles-module__actions___D6x3f {\\n display: flex;\\n justify-content: flex-end;\\n gap: 0.375rem;\\n margin-top: 0.5rem;\\n}\\n\\n.styles-module__cancel___hRjnL,\\n.styles-module__submit___K-mIR {\\n padding: 0.4rem 0.875rem;\\n font-size: 0.75rem;\\n font-weight: 500;\\n border-radius: 1rem;\\n border: none;\\n cursor: pointer;\\n transition: background-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;\\n}\\n\\n.styles-module__cancel___hRjnL {\\n background: transparent;\\n color: rgba(255, 255, 255, 0.5);\\n}\\n.styles-module__cancel___hRjnL:hover {\\n background: rgba(255, 255, 255, 0.1);\\n color: rgba(255, 255, 255, 0.8);\\n}\\n\\n.styles-module__submit___K-mIR {\\n color: white;\\n}\\n.styles-module__submit___K-mIR:hover:not(:disabled) {\\n filter: brightness(0.9);\\n}\\n.styles-module__submit___K-mIR:disabled {\\n cursor: not-allowed;\\n}\\n\\n.styles-module__shortcutHint___ihsrd {\\n text-align: right;\\n font-size: 11px;\\n color: #9ca3af;\\n padding: 2px 4px 0;\\n user-select: none;\\n}\\n\\n.styles-module__deleteWrapper___oSjdo {\\n margin-right: auto;\\n}\\n\\n.styles-module__deleteButton___4VuAE {\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n width: 28px;\\n height: 28px;\\n border-radius: 50%;\\n border: none;\\n background: transparent;\\n color: rgba(255, 255, 255, 0.4);\\n transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease;\\n}\\n.styles-module__deleteButton___4VuAE:hover {\\n background-color: color-mix(in srgb, var(--agentation-color-red) 25%, transparent);\\n color: var(--agentation-color-red);\\n}\\n.styles-module__deleteButton___4VuAE:active {\\n transform: scale(0.92);\\n}\\n\\n.styles-module__light___6AaSQ.styles-module__popup___IhzrD {\\n background: #fff;\\n box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.06);\\n}\\n.styles-module__light___6AaSQ .styles-module__element___fTV2z {\\n color: rgba(0, 0, 0, 0.6);\\n}\\n.styles-module__light___6AaSQ .styles-module__timestamp___Dtpsv {\\n color: rgba(0, 0, 0, 0.4);\\n}\\n.styles-module__light___6AaSQ .styles-module__chevron___ZZJlR {\\n color: rgba(0, 0, 0, 0.4);\\n}\\n.styles-module__light___6AaSQ .styles-module__stylesBlock___VfQKn {\\n background: rgba(0, 0, 0, 0.03);\\n}\\n.styles-module__light___6AaSQ .styles-module__styleLine___1YQiD {\\n color: rgba(0, 0, 0, 0.75);\\n}\\n.styles-module__light___6AaSQ .styles-module__styleProperty___84L1i {\\n color: #7c3aed;\\n}\\n.styles-module__light___6AaSQ .styles-module__styleValue___q51-h {\\n color: rgba(0, 0, 0, 0.75);\\n}\\n.styles-module__light___6AaSQ .styles-module__quote___mcMmQ {\\n color: rgba(0, 0, 0, 0.55);\\n background: rgba(0, 0, 0, 0.04);\\n}\\n.styles-module__light___6AaSQ .styles-module__textarea___jrSae {\\n background: rgba(0, 0, 0, 0.03);\\n color: #1a1a1a;\\n border-color: rgba(0, 0, 0, 0.12);\\n}\\n.styles-module__light___6AaSQ .styles-module__textarea___jrSae::placeholder {\\n color: rgba(0, 0, 0, 0.4);\\n}\\n.styles-module__light___6AaSQ .styles-module__textarea___jrSae::-webkit-scrollbar-thumb {\\n background: rgba(0, 0, 0, 0.15);\\n}\\n.styles-module__light___6AaSQ .styles-module__cancel___hRjnL {\\n color: rgba(0, 0, 0, 0.5);\\n}\\n.styles-module__light___6AaSQ .styles-module__cancel___hRjnL:hover {\\n background: rgba(0, 0, 0, 0.06);\\n color: rgba(0, 0, 0, 0.75);\\n}\\n.styles-module__light___6AaSQ .styles-module__deleteButton___4VuAE {\\n color: rgba(0, 0, 0, 0.4);\\n}\\n.styles-module__light___6AaSQ .styles-module__deleteButton___4VuAE:hover {\\n background-color: color-mix(in srgb, var(--agentation-color-red) 25%, transparent);\\n color: var(--agentation-color-red);\\n}\";\nconst classNames = {\"popup\":\"styles-module__popup___IhzrD\",\"enter\":\"styles-module__enter___L7U7N\",\"popupEnter\":\"styles-module__popupEnter___AuQDN\",\"entered\":\"styles-module__entered___COX-w\",\"exit\":\"styles-module__exit___5eGjE\",\"popupExit\":\"styles-module__popupExit___JJKQX\",\"shake\":\"styles-module__shake___jdbWe\",\"header\":\"styles-module__header___wWsSi\",\"element\":\"styles-module__element___fTV2z\",\"headerToggle\":\"styles-module__headerToggle___WpW0b\",\"chevron\":\"styles-module__chevron___ZZJlR\",\"expanded\":\"styles-module__expanded___2Hxgv\",\"stylesWrapper\":\"styles-module__stylesWrapper___pnHgy\",\"stylesInner\":\"styles-module__stylesInner___YYZe2\",\"stylesBlock\":\"styles-module__stylesBlock___VfQKn\",\"styleLine\":\"styles-module__styleLine___1YQiD\",\"styleProperty\":\"styles-module__styleProperty___84L1i\",\"styleValue\":\"styles-module__styleValue___q51-h\",\"timestamp\":\"styles-module__timestamp___Dtpsv\",\"quote\":\"styles-module__quote___mcMmQ\",\"textarea\":\"styles-module__textarea___jrSae\",\"green\":\"styles-module__green___99l3h\",\"actions\":\"styles-module__actions___D6x3f\",\"cancel\":\"styles-module__cancel___hRjnL\",\"submit\":\"styles-module__submit___K-mIR\",\"shortcutHint\":\"styles-module__shortcutHint___ihsrd\",\"deleteWrapper\":\"styles-module__deleteWrapper___oSjdo\",\"deleteButton\":\"styles-module__deleteButton___4VuAE\",\"light\":\"styles-module__light___6AaSQ\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-annotation-popup-css-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-annotation-popup-css-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\"use client\";\n\nimport s from \"./icon-transitions.module.scss\";\n\n// =============================================================================\n// Icons\n// =============================================================================\n\n// Small X for marker delete\nexport const IconClose = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M4 4l8 8M12 4l-8 8\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Plus icon\nexport const IconPlus = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M8 3v10M3 8h10\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Checkmark icon\nexport const IconCheck = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M3 8l3.5 3.5L13 5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Checkbox checkmark (smaller, optimized for checkboxes)\nexport const IconCheckSmall = ({ size = 14 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 14 14\" fill=\"none\">\n <path\n d=\"M3.9375 7L6.125 9.1875L10.5 4.8125\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// List with sparkle icon\nexport const IconListSparkle = ({\n size = 24,\n style = {},\n}: {\n size?: number;\n style?: React.CSSProperties;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" style={style}>\n <g clipPath=\"url(#clip0_list_sparkle)\">\n <path\n d=\"M11.5 12L5.5 12\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M18.5 6.75L5.5 6.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M9.25 17.25L5.5 17.25\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M16 12.75L16.5179 13.9677C16.8078 14.6494 17.3506 15.1922 18.0323 15.4821L19.25 16L18.0323 16.5179C17.3506 16.8078 16.8078 17.3506 16.5179 18.0323L16 19.25L15.4821 18.0323C15.1922 17.3506 14.6494 16.8078 13.9677 16.5179L12.75 16L13.9677 15.4821C14.6494 15.1922 15.1922 14.6494 15.4821 13.9677L16 12.75Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_list_sparkle\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\n// Help/Question mark icon for tooltips\nexport const IconHelp = ({\n size = 20,\n ...props\n}: { size?: number } & React.SVGProps<SVGSVGElement>) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n {...props}\n >\n <circle\n cx=\"10\"\n cy=\"10\"\n r=\"5.375\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n />\n <path\n d=\"M8.5 8.5C8.73 7.85 9.31 7.49 10 7.5C10.86 7.51 11.5 8.13 11.5 9C11.5 10.08 10 10.5 10 10.5V10.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <circle cx=\"10\" cy=\"12.625\" r=\"0.625\" fill=\"currentColor\" />\n </svg>\n);\n\n// Animated checkmark with draw + bounce effect\nexport const IconCheckSmallAnimated = ({ size = 14 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 14 14\" fill=\"none\">\n <style>{`\n @keyframes checkDraw {\n 0% {\n stroke-dashoffset: 12;\n }\n 100% {\n stroke-dashoffset: 0;\n }\n }\n @keyframes checkBounce {\n 0% {\n transform: scale(0.5);\n opacity: 0;\n }\n 50% {\n transform: scale(1.12);\n opacity: 1;\n }\n 75% {\n transform: scale(0.95);\n }\n 100% {\n transform: scale(1);\n }\n }\n .check-path-animated {\n stroke-dasharray: 12;\n stroke-dashoffset: 0;\n transform-origin: center;\n animation: checkDraw 0.18s ease-out, checkBounce 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n `}</style>\n <path\n className=\"check-path-animated\"\n d=\"M3.9375 7L6.125 9.1875L10.5 4.8125\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// =============================================================================\n// New Icons from SVG files\n// =============================================================================\n\n// Copy icon (two overlapping rectangles)\nexport const IconCopyAlt = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M4.75 11.25C4.75 10.4216 5.42157 9.75 6.25 9.75H12.75C13.5784 9.75 14.25 10.4216 14.25 11.25V17.75C14.25 18.5784 13.5784 19.25 12.75 19.25H6.25C5.42157 19.25 4.75 18.5784 4.75 17.75V11.25Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M17.25 14.25H17.75C18.5784 14.25 19.25 13.5784 19.25 12.75V6.25C19.25 5.42157 18.5784 4.75 17.75 4.75H11.25C10.4216 4.75 9.75 5.42157 9.75 6.25V6.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Animated copy/checkmark icon\nexport const IconCopyAnimated = ({\n size = 24,\n copied = false,\n tint,\n}: {\n size?: number;\n copied?: boolean;\n tint?: string;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" style={tint ? { color: tint, transition: 'color 0.3s ease' } : undefined}>\n {/* Copy icon */}\n <g\n className={`${s.iconState} ${copied ? s.hiddenScaled : s.visibleScaled}`}\n >\n <path\n d=\"M4.75 11.25C4.75 10.4216 5.42157 9.75 6.25 9.75H12.75C13.5784 9.75 14.25 10.4216 14.25 11.25V17.75C14.25 18.5784 13.5784 19.25 12.75 19.25H6.25C5.42157 19.25 4.75 18.5784 4.75 17.75V11.25Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M17.25 14.25H17.75C18.5784 14.25 19.25 13.5784 19.25 12.75V6.25C19.25 5.42157 18.5784 4.75 17.75 4.75H11.25C10.4216 4.75 9.75 5.42157 9.75 6.25V6.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </g>\n {/* Checkmark circle */}\n <g\n className={`${s.iconState} ${copied ? s.visibleScaled : s.hiddenScaled}`}\n >\n <path\n d=\"M12 20C7.58172 20 4 16.4182 4 12C4 7.58172 7.58172 4 12 4C16.4182 4 20 7.58172 20 12C20 16.4182 16.4182 20 12 20Z\"\n stroke=\"var(--agentation-color-green)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M15 10L11 14.25L9.25 12.25\"\n stroke=\"var(--agentation-color-green)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n </svg>\n);\n\n// Animated send arrow icon (paper plane style with checkmark/error transition)\nexport const IconSendArrow = ({\n size = 24,\n state = \"idle\",\n}: {\n size?: number;\n state?: \"idle\" | \"sending\" | \"sent\" | \"failed\";\n}) => {\n const showArrow = state === \"idle\";\n const showCheck = state === \"sent\";\n const showError = state === \"failed\";\n const isSending = state === \"sending\";\n\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n {/* Send arrow */}\n <g\n className={`${s.iconStateFast} ${showArrow ? s.visibleScaled : isSending ? s.sending : s.hiddenScaled}`}\n >\n <path\n d=\"M9.875 14.125L12.3506 19.6951C12.7184 20.5227 13.9091 20.4741 14.2083 19.6193L18.8139 6.46032C19.0907 5.6695 18.3305 4.90933 17.5397 5.18611L4.38072 9.79174C3.52589 10.0909 3.47731 11.2816 4.30494 11.6494L9.875 14.125ZM9.875 14.125L13.375 10.625\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n {/* Green checkmark circle */}\n <g\n className={`${s.iconStateFast} ${showCheck ? s.visibleScaled : s.hiddenScaled}`}\n >\n <path\n d=\"M12 20C7.58172 20 4 16.4182 4 12C4 7.58172 7.58172 4 12 4C16.4182 4 20 7.58172 20 12C20 16.4182 16.4182 20 12 20Z\"\n stroke=\"var(--agentation-color-green)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M15 10L11 14.25L9.25 12.25\"\n stroke=\"var(--agentation-color-green)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n {/* Red error circle with exclamation */}\n <g\n className={`${s.iconStateFast} ${showError ? s.visibleScaled : s.hiddenScaled}`}\n >\n <path\n d=\"M12 20C7.58172 20 4 16.4182 4 12C4 7.58172 7.58172 4 12 4C16.4182 4 20 7.58172 20 12C20 16.4182 16.4182 20 12 20Z\"\n stroke=\"var(--agentation-color-red)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M12 8V12\"\n stroke=\"var(--agentation-color-red)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <circle\n cx=\"12\"\n cy=\"15\"\n r=\"0.5\"\n fill=\"var(--agentation-color-red)\"\n stroke=\"var(--agentation-color-red)\"\n strokeWidth=\"1\"\n />\n </g>\n </svg>\n );\n};\n\n// Animated send/checkmark icon (for \"Send to Agent\" button)\nexport const IconSendAnimated = ({\n size = 24,\n sent = false,\n}: {\n size?: number;\n sent?: boolean;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 22 21\" fill=\"none\">\n {/* Send icon (document with arrow) */}\n <g className={`${s.iconState} ${sent ? s.hiddenScaled : s.visibleScaled}`}>\n <path\n d=\"M9.5 5H6.5C4.84315 5 3.5 6.34315 3.5 8V15C3.5 16.6569 4.84315 18 6.5 18H13.5C15.1569 18 16.5 16.6569 16.5 15V12\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M13.5 8.5L18.5 3.5M18.5 3.5L14.4524 3.5M18.5 3.5L18.5 7.54762\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M7.5 13.75H12.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M7.5 10.75H10.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </g>\n {/* Checkmark circle (success state) */}\n <g className={`${s.iconState} ${sent ? s.visibleScaled : s.hiddenScaled}`}>\n <path\n d=\"M11 19C6.58172 19 3 15.4182 3 11C3 6.58172 6.58172 3 11 3C15.4182 3 19 6.58172 19 11C19 15.4182 15.4182 19 11 19Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14 9L10 13.25L8.25 11.25\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n </svg>\n);\n\n// Eye icon (original)\nexport const IconEye = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M4.91516 12.7108C4.63794 12.2883 4.63705 11.7565 4.91242 11.3328C5.84146 9.9033 8.30909 6.74994 12 6.74994C15.6909 6.74994 18.1585 9.9033 19.0876 11.3328C19.3629 11.7565 19.3621 12.2883 19.0848 12.7108C18.1537 14.13 15.6873 17.2499 12 17.2499C8.31272 17.2499 5.8463 14.13 4.91516 12.7108Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M12 14.25C13.2426 14.25 14.25 13.2426 14.25 12C14.25 10.7574 13.2426 9.75 12 9.75C10.7574 9.75 9.75 10.7574 9.75 12C9.75 13.2426 10.7574 14.25 12 14.25Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Eye icon (alt version - larger pupil)\nexport const IconEyeAlt = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M3.91752 12.7539C3.65127 12.2996 3.65037 11.7515 3.9149 11.2962C4.9042 9.59346 7.72688 5.49994 12 5.49994C16.2731 5.49994 19.0958 9.59346 20.0851 11.2962C20.3496 11.7515 20.3487 12.2996 20.0825 12.7539C19.0908 14.4459 16.2694 18.4999 12 18.4999C7.73064 18.4999 4.90918 14.4459 3.91752 12.7539Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M12 14.8261C13.5608 14.8261 14.8261 13.5608 14.8261 12C14.8261 10.4392 13.5608 9.17392 12 9.17392C10.4392 9.17392 9.17391 10.4392 9.17391 12C9.17391 13.5608 10.4392 14.8261 12 14.8261Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Eye closed (with slash)\nexport const IconEyeClosed = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M18.6025 9.28503C18.9174 8.9701 19.4364 8.99481 19.7015 9.35271C20.1484 9.95606 20.4943 10.507 20.7342 10.9199C21.134 11.6086 21.1329 12.4454 20.7303 13.1328C20.2144 14.013 19.2151 15.5225 17.7723 16.8193C16.3293 18.1162 14.3852 19.2497 12.0008 19.25C11.4192 19.25 10.8638 19.1823 10.3355 19.0613C9.77966 18.934 9.63498 18.2525 10.0382 17.8493C10.2412 17.6463 10.5374 17.573 10.8188 17.6302C11.1993 17.7076 11.5935 17.75 12.0008 17.75C13.8848 17.7497 15.4867 16.8568 16.7693 15.7041C18.0522 14.5511 18.9606 13.1867 19.4363 12.375C19.5656 12.1543 19.5659 11.8943 19.4373 11.6729C19.2235 11.3049 18.921 10.8242 18.5364 10.3003C18.3085 9.98991 18.3302 9.5573 18.6025 9.28503ZM12.0008 4.75C12.5814 4.75006 13.1358 4.81803 13.6632 4.93953C14.2182 5.06741 14.362 5.74812 13.9593 6.15091C13.7558 6.35435 13.4589 6.42748 13.1771 6.36984C12.7983 6.29239 12.4061 6.25006 12.0008 6.25C10.1167 6.25 8.51415 7.15145 7.23028 8.31543C5.94678 9.47919 5.03918 10.8555 4.56426 11.6729C4.43551 11.8945 4.43582 12.1542 4.56524 12.375C4.77587 12.7343 5.07189 13.2012 5.44718 13.7105C5.67623 14.0213 5.65493 14.4552 5.38193 14.7282C5.0671 15.0431 4.54833 15.0189 4.28292 14.6614C3.84652 14.0736 3.50813 13.5369 3.27129 13.1328C2.86831 12.4451 2.86717 11.6088 3.26739 10.9199C3.78185 10.0345 4.77959 8.51239 6.22247 7.2041C7.66547 5.89584 9.61202 4.75 12.0008 4.75Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M5 19L19 5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Animated eye icon that transitions between open/closed states\nexport const IconEyeAnimated = ({\n size = 24,\n isOpen = true,\n}: {\n size?: number;\n isOpen?: boolean;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n {/* Open state - full outline + pupil */}\n <g className={`${s.iconFade} ${isOpen ? s.visible : s.hidden}`}>\n <path\n d=\"M3.91752 12.7539C3.65127 12.2996 3.65037 11.7515 3.9149 11.2962C4.9042 9.59346 7.72688 5.49994 12 5.49994C16.2731 5.49994 19.0958 9.59346 20.0851 11.2962C20.3496 11.7515 20.3487 12.2996 20.0825 12.7539C19.0908 14.4459 16.2694 18.4999 12 18.4999C7.73064 18.4999 4.90918 14.4459 3.91752 12.7539Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M12 14.8261C13.5608 14.8261 14.8261 13.5608 14.8261 12C14.8261 10.4392 13.5608 9.17392 12 9.17392C10.4392 9.17392 9.17391 10.4392 9.17391 12C9.17391 13.5608 10.4392 14.8261 12 14.8261Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n {/* Closed state - split outline + slash */}\n <g className={`${s.iconFade} ${isOpen ? s.hidden : s.visible}`}>\n <path\n d=\"M18.6025 9.28503C18.9174 8.9701 19.4364 8.99481 19.7015 9.35271C20.1484 9.95606 20.4943 10.507 20.7342 10.9199C21.134 11.6086 21.1329 12.4454 20.7303 13.1328C20.2144 14.013 19.2151 15.5225 17.7723 16.8193C16.3293 18.1162 14.3852 19.2497 12.0008 19.25C11.4192 19.25 10.8638 19.1823 10.3355 19.0613C9.77966 18.934 9.63498 18.2525 10.0382 17.8493C10.2412 17.6463 10.5374 17.573 10.8188 17.6302C11.1993 17.7076 11.5935 17.75 12.0008 17.75C13.8848 17.7497 15.4867 16.8568 16.7693 15.7041C18.0522 14.5511 18.9606 13.1867 19.4363 12.375C19.5656 12.1543 19.5659 11.8943 19.4373 11.6729C19.2235 11.3049 18.921 10.8242 18.5364 10.3003C18.3085 9.98991 18.3302 9.5573 18.6025 9.28503ZM12.0008 4.75C12.5814 4.75006 13.1358 4.81803 13.6632 4.93953C14.2182 5.06741 14.362 5.74812 13.9593 6.15091C13.7558 6.35435 13.4589 6.42748 13.1771 6.36984C12.7983 6.29239 12.4061 6.25006 12.0008 6.25C10.1167 6.25 8.51415 7.15145 7.23028 8.31543C5.94678 9.47919 5.03918 10.8555 4.56426 11.6729C4.43551 11.8945 4.43582 12.1542 4.56524 12.375C4.77587 12.7343 5.07189 13.2012 5.44718 13.7105C5.67623 14.0213 5.65493 14.4552 5.38193 14.7282C5.0671 15.0431 4.54833 15.0189 4.28292 14.6614C3.84652 14.0736 3.50813 13.5369 3.27129 13.1328C2.86831 12.4451 2.86717 11.6088 3.26739 10.9199C3.78185 10.0345 4.77959 8.51239 6.22247 7.2041C7.66547 5.89584 9.61202 4.75 12.0008 4.75Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M5 19L19 5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </g>\n </svg>\n);\n\n// Animated pause/play icon that transitions between states\nexport const IconPausePlayAnimated = ({\n size = 24,\n isPaused = false,\n}: {\n size?: number;\n isPaused?: boolean;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n {/* Pause bars - visible when not paused */}\n <g className={`${s.iconFadeFast} ${isPaused ? s.hidden : s.visible}`}>\n <path\n d=\"M8 6L8 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M16 18L16 6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </g>\n {/* Play triangle - visible when paused */}\n <path\n className={`${s.iconFadeFast} ${isPaused ? s.visible : s.hidden}`}\n d=\"M17.75 10.701C18.75 11.2783 18.75 12.7217 17.75 13.299L8.75 18.4952C7.75 19.0725 6.5 18.3509 6.5 17.1962L6.5 6.80384C6.5 5.64914 7.75 4.92746 8.75 5.50481L17.75 10.701Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n\n// Eye with minus (hidden/collapsed state)\nexport const IconEyeMinus = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M4.91516 12.7108C4.63794 12.2883 4.63705 11.7565 4.91242 11.3328C5.84146 9.9033 8.30909 6.74994 12 6.74994C15.6909 6.74994 18.1585 9.9033 19.0876 11.3328C19.3629 11.7565 19.3621 12.2883 19.0848 12.7108C18.1537 14.13 15.6873 17.2499 12 17.2499C8.31272 17.2499 5.8463 14.13 4.91516 12.7108Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M9 12H15\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Gear icon\nexport const IconGear = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M10.6504 5.81117C10.9939 4.39628 13.0061 4.39628 13.3496 5.81117C13.5715 6.72517 14.6187 7.15891 15.4219 6.66952C16.6652 5.91193 18.0881 7.33479 17.3305 8.57815C16.8411 9.38134 17.2748 10.4285 18.1888 10.6504C19.6037 10.9939 19.6037 13.0061 18.1888 13.3496C17.2748 13.5715 16.8411 14.6187 17.3305 15.4219C18.0881 16.6652 16.6652 18.0881 15.4219 17.3305C14.6187 16.8411 13.5715 17.2748 13.3496 18.1888C13.0061 19.6037 10.9939 19.6037 10.6504 18.1888C10.4285 17.2748 9.38135 16.8411 8.57815 17.3305C7.33479 18.0881 5.91193 16.6652 6.66952 15.4219C7.15891 14.6187 6.72517 13.5715 5.81117 13.3496C4.39628 13.0061 4.39628 10.9939 5.81117 10.6504C6.72517 10.4285 7.15891 9.38134 6.66952 8.57815C5.91193 7.33479 7.33479 5.91192 8.57815 6.66952C9.38135 7.15891 10.4285 6.72517 10.6504 5.81117Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <circle cx=\"12\" cy=\"12\" r=\"2.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n </svg>\n);\n\n// Pause icon (two vertical bars - original)\nexport const IconPauseAlt = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M9.25 5.75C9.80228 5.75 10.25 6.19772 10.25 6.75L10.25 17.25C10.25 17.8023 9.80228 18.25 9.25 18.25L6.75 18.25C6.19772 18.25 5.75 17.8023 5.75 17.25L5.75 6.75C5.75 6.19772 6.19772 5.75 6.75 5.75L9.25 5.75Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M17.25 5.75C17.8023 5.75 18.25 6.19772 18.25 6.75L18.25 17.25C18.25 17.8023 17.8023 18.25 17.25 18.25L14.75 18.25C14.1977 18.25 13.75 17.8023 13.75 17.25L13.75 6.75C13.75 6.19772 14.1977 5.75 14.75 5.75L17.25 5.75Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n\n// Pause icon (simple lines)\nexport const IconPause = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M8 6L8 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M16 18L16 6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Play icon (triangle pointing right)\nexport const IconPlayAlt = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M17.75 10.701C18.75 11.2783 18.75 12.7217 17.75 13.299L8.75 18.4952C7.75 19.0725 6.5 18.3509 6.5 17.1962L6.5 6.80384C6.5 5.64914 7.75 4.92746 8.75 5.50481L17.75 10.701Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n\n// Trash can icon (filled)\nexport const IconTrashAlt = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M13.5 4C14.7426 4 15.75 5.00736 15.75 6.25V7H18.5C18.9142 7 19.25 7.33579 19.25 7.75C19.25 8.16421 18.9142 8.5 18.5 8.5H17.9678L17.6328 16.2217C17.61 16.7475 17.5912 17.1861 17.5469 17.543C17.5015 17.9087 17.4225 18.2506 17.2461 18.5723C16.9747 19.0671 16.5579 19.4671 16.0518 19.7168C15.7227 19.8791 15.3772 19.9422 15.0098 19.9717C14.6514 20.0004 14.2126 20 13.6865 20H10.3135C9.78735 20 9.34856 20.0004 8.99023 19.9717C8.62278 19.9422 8.27729 19.8791 7.94824 19.7168C7.44205 19.4671 7.02532 19.0671 6.75391 18.5723C6.57751 18.2506 6.49853 17.9087 6.45312 17.543C6.40883 17.1861 6.39005 16.7475 6.36719 16.2217L6.03223 8.5H5.5C5.08579 8.5 4.75 8.16421 4.75 7.75C4.75 7.33579 5.08579 7 5.5 7H8.25V6.25C8.25 5.00736 9.25736 4 10.5 4H13.5ZM7.86621 16.1562C7.89013 16.7063 7.90624 17.0751 7.94141 17.3584C7.97545 17.6326 8.02151 17.7644 8.06934 17.8516C8.19271 18.0763 8.38239 18.2577 8.6123 18.3711C8.70153 18.4151 8.83504 18.4545 9.11035 18.4766C9.39482 18.4994 9.76335 18.5 10.3135 18.5H13.6865C14.2367 18.5 14.6052 18.4994 14.8896 18.4766C15.165 18.4545 15.2985 18.4151 15.3877 18.3711C15.6176 18.2577 15.8073 18.0763 15.9307 17.8516C15.9785 17.7644 16.0245 17.6326 16.0586 17.3584C16.0938 17.0751 16.1099 16.7063 16.1338 16.1562L16.4668 8.5H7.5332L7.86621 16.1562ZM9.97656 10.75C10.3906 10.7371 10.7371 11.0626 10.75 11.4766L10.875 15.4766C10.8879 15.8906 10.5624 16.2371 10.1484 16.25C9.73443 16.2629 9.38794 15.9374 9.375 15.5234L9.25 11.5234C9.23706 11.1094 9.56255 10.7629 9.97656 10.75ZM14.0244 10.75C14.4384 10.7635 14.7635 11.1105 14.75 11.5244L14.6201 15.5244C14.6066 15.9384 14.2596 16.2634 13.8457 16.25C13.4317 16.2365 13.1067 15.8896 13.1201 15.4756L13.251 11.4756C13.2645 11.0617 13.6105 10.7366 14.0244 10.75ZM10.5 5.5C10.0858 5.5 9.75 5.83579 9.75 6.25V7H14.25V6.25C14.25 5.83579 13.9142 5.5 13.5 5.5H10.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\n// Chat bubble with ellipsis\nexport const IconChatEllipsis = ({\n size = 16,\n style = {},\n}: {\n size?: number;\n style?: React.CSSProperties;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" style={style}>\n <path\n d=\"M18.8875 19.25L19.6112 19.0533C19.6823 19.3148 19.6068 19.5943 19.4137 19.7844C19.2206 19.9746 18.9399 20.0457 18.6795 19.9706L18.8875 19.25ZM14.9631 18.244L15.263 18.9314L14.9631 18.244ZM18.0914 15.6309L17.4669 15.2156L18.0914 15.6309ZM4.75 11.8041H5.5C5.5 15.2664 8.39065 18.1081 12 18.1081V18.8581V19.6081C7.60123 19.6081 4 16.1334 4 11.8041H4.75ZM19.25 11.8041H18.5C18.5 8.34166 15.6094 5.5 12 5.5V4.75V4C16.3988 4 20 7.47476 20 11.8041H19.25ZM12 4.75V5.5C8.39065 5.5 5.5 8.34166 5.5 11.8041H4.75H4C4 7.47476 7.60123 4 12 4V4.75ZM18.0914 15.6309L17.4669 15.2156C18.1213 14.2315 18.5 13.0612 18.5 11.8041H19.25H20C20 13.3681 19.5276 14.8257 18.716 16.0462L18.0914 15.6309ZM18.8875 19.25L18.1638 19.4467L17.2953 16.2517L18.019 16.055L18.7428 15.8583L19.6112 19.0533L18.8875 19.25ZM12 18.8581V18.1081C12.9509 18.1081 13.8518 17.9105 14.6632 17.5565L14.9631 18.244L15.263 18.9314C14.2652 19.3667 13.1603 19.6081 12 19.6081V18.8581ZM15.3144 18.2188L15.5224 17.4982L19.0955 18.5294L18.8875 19.25L18.6795 19.9706L15.1064 18.9394L15.3144 18.2188ZM14.9631 18.244L14.6632 17.5565C14.925 17.4423 15.2286 17.4134 15.5224 17.4982L15.3144 18.2188L15.1064 18.9394C15.1677 18.957 15.223 18.9489 15.263 18.9314L14.9631 18.244ZM18.0914 15.6309L18.716 16.0462C18.7451 16.0024 18.7636 15.9351 18.7428 15.8583L18.019 16.055L17.2953 16.2517C17.1957 15.8853 17.2716 15.5093 17.4669 15.2156L18.0914 15.6309Z\"\n fill=\"currentColor\"\n />\n <circle cx=\"15\" cy=\"11.75\" r=\"1\" fill=\"currentColor\" />\n <circle cx=\"12\" cy=\"11.75\" r=\"1\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"11.75\" r=\"1\" fill=\"currentColor\" />\n </svg>\n);\n\n// Checkmark icon\nexport const IconCheckmark = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <g clipPath=\"url(#clip0_2_45)\">\n <path\n d=\"M16.25 8.75L10 15.25L7.25 12.25\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_2_45\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\n// Large checkmark icon\nexport const IconCheckmarkLarge = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <g clipPath=\"url(#clip0_2_37)\">\n <path\n d=\"M17.5962 7.75L9.42308 16.25L6.15385 12.6538\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_2_37\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\n// Checkmark in circle icon\nexport const IconCheckmarkCircle = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <g clipPath=\"url(#clip0_checkmark_circle)\">\n <path\n d=\"M12 20C7.58172 20 4 16.4182 4 12C4 7.58172 7.58172 4 12 4C16.4182 4 20 7.58172 20 12C20 16.4182 16.4182 20 12 20Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M15 10L11 14.25L9.25 12.25\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_checkmark_circle\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\n// X mark / close icon\nexport const IconXmark = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <g clipPath=\"url(#clip0_2_53)\">\n <path\n d=\"M16.25 16.25L7.75 7.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M7.75 16.25L16.25 7.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_2_53\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\n// X mark large / close icon (larger variant)\nexport const IconXmarkLarge = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M16.7198 6.21973C17.0127 5.92683 17.4874 5.92683 17.7803 6.21973C18.0732 6.51262 18.0732 6.9874 17.7803 7.28027L13.0606 12L17.7803 16.7197C18.0732 17.0126 18.0732 17.4874 17.7803 17.7803C17.4875 18.0731 17.0127 18.0731 16.7198 17.7803L12.0001 13.0605L7.28033 17.7803C6.98746 18.0731 6.51268 18.0731 6.21979 17.7803C5.92689 17.4874 5.92689 17.0126 6.21979 16.7197L10.9395 12L6.21979 7.28027C5.92689 6.98738 5.92689 6.51262 6.21979 6.21973C6.51268 5.92683 6.98744 5.92683 7.28033 6.21973L12.0001 10.9395L16.7198 6.21973Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\n// Sun icon (light mode)\nexport const IconSun = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M9.99999 12.7082C11.4958 12.7082 12.7083 11.4956 12.7083 9.99984C12.7083 8.50407 11.4958 7.2915 9.99999 7.2915C8.50422 7.2915 7.29166 8.50407 7.29166 9.99984C7.29166 11.4956 8.50422 12.7082 9.99999 12.7082Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M10 3.9585V5.05698\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M10 14.9429V16.0414\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M5.7269 5.72656L6.50682 6.50649\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M13.4932 13.4932L14.2731 14.2731\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M3.95834 10H5.05683\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14.9432 10H16.0417\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M5.7269 14.2731L6.50682 13.4932\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M13.4932 6.50649L14.2731 5.72656\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Moon icon (dark mode)\nexport const IconMoon = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M15.5 10.4955C15.4037 11.5379 15.0124 12.5314 14.3721 13.3596C13.7317 14.1878 12.8688 14.8165 11.8841 15.1722C10.8995 15.5278 9.83397 15.5957 8.81217 15.3679C7.79038 15.1401 6.8546 14.6259 6.11434 13.8857C5.37408 13.1454 4.85995 12.2096 4.63211 11.1878C4.40427 10.166 4.47215 9.10048 4.82781 8.11585C5.18346 7.13123 5.81218 6.26825 6.64039 5.62791C7.4686 4.98756 8.46206 4.59634 9.5045 4.5C8.89418 5.32569 8.60049 6.34302 8.67685 7.36695C8.75321 8.39087 9.19454 9.35339 9.92058 10.0794C10.6466 10.8055 11.6091 11.2468 12.6331 11.3231C13.657 11.3995 14.6743 11.1058 15.5 10.4955Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.13793\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Edit/pencil icon for marker hover\nexport const IconEdit = ({ size = 16 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M11.3799 6.9572L9.05645 4.63375M11.3799 6.9572L6.74949 11.5699C6.61925 11.6996 6.45577 11.791 6.277 11.8339L4.29549 12.3092C3.93194 12.3964 3.60478 12.0683 3.69297 11.705L4.16585 9.75693C4.20893 9.57947 4.29978 9.4172 4.42854 9.28771L9.05645 4.63375M11.3799 6.9572L12.3455 5.98759C12.9839 5.34655 12.9839 4.31002 12.3455 3.66897C11.7033 3.02415 10.6594 3.02415 10.0172 3.66897L9.06126 4.62892L9.05645 4.63375\"\n stroke=\"currentColor\"\n strokeWidth=\"0.9\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Trash icon for delete button in edit panel\nexport const IconTrash = ({ size = 24 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M13.5 4C14.7426 4 15.75 5.00736 15.75 6.25V7H18.5C18.9142 7 19.25 7.33579 19.25 7.75C19.25 8.16421 18.9142 8.5 18.5 8.5H17.9678L17.6328 16.2217C17.61 16.7475 17.5912 17.1861 17.5469 17.543C17.5015 17.9087 17.4225 18.2506 17.2461 18.5723C16.9747 19.0671 16.5579 19.4671 16.0518 19.7168C15.7227 19.8791 15.3772 19.9422 15.0098 19.9717C14.6514 20.0004 14.2126 20 13.6865 20H10.3135C9.78735 20 9.34856 20.0004 8.99023 19.9717C8.62278 19.9422 8.27729 19.8791 7.94824 19.7168C7.44205 19.4671 7.02532 19.0671 6.75391 18.5723C6.57751 18.2506 6.49853 17.9087 6.45312 17.543C6.40883 17.1861 6.39005 16.7475 6.36719 16.2217L6.03223 8.5H5.5C5.08579 8.5 4.75 8.16421 4.75 7.75C4.75 7.33579 5.08579 7 5.5 7H8.25V6.25C8.25 5.00736 9.25736 4 10.5 4H13.5ZM7.86621 16.1562C7.89013 16.7063 7.90624 17.0751 7.94141 17.3584C7.97545 17.6326 8.02151 17.7644 8.06934 17.8516C8.19271 18.0763 8.38239 18.2577 8.6123 18.3711C8.70153 18.4151 8.83504 18.4545 9.11035 18.4766C9.39482 18.4994 9.76335 18.5 10.3135 18.5H13.6865C14.2367 18.5 14.6052 18.4994 14.8896 18.4766C15.165 18.4545 15.2985 18.4151 15.3877 18.3711C15.6176 18.2577 15.8073 18.0763 15.9307 17.8516C15.9785 17.7644 16.0245 17.6326 16.0586 17.3584C16.0938 17.0751 16.1099 16.7063 16.1338 16.1562L16.4668 8.5H7.5332L7.86621 16.1562ZM9.97656 10.75C10.3906 10.7371 10.7371 11.0626 10.75 11.4766L10.875 15.4766C10.8879 15.8906 10.5624 16.2371 10.1484 16.25C9.73443 16.2629 9.38794 15.9374 9.375 15.5234L9.25 11.5234C9.23706 11.1094 9.56255 10.7629 9.97656 10.75ZM14.0244 10.75C14.4383 10.7635 14.7635 11.1105 14.75 11.5244L14.6201 15.5244C14.6066 15.9384 14.2596 16.2634 13.8457 16.25C13.4317 16.2365 13.1067 15.8896 13.1201 15.4756L13.251 11.4756C13.2645 11.0617 13.6105 10.7366 14.0244 10.75ZM10.5 5.5C10.0858 5.5 9.75 5.83579 9.75 6.25V7H14.25V6.25C14.25 5.83579 13.9142 5.5 13.5 5.5H10.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\n// Chevron icons for navigation\nexport const IconChevronLeft = ({ size = 16 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8.5 3.5L4 8L8.5 12.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const IconChevronRight = ({ size = 16 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8.5 11.5L12 8L8.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Animated Bunny mascot\nexport const AnimatedBunny = ({\n size = 20,\n color = \"#4C74FF\",\n}: {\n size?: number;\n color?: string;\n}) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 28 28\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <style>{`\n @keyframes bunnyEnterEar {\n 0% { opacity: 0; transform: scale(0.8); }\n 100% { opacity: 1; transform: scale(1); }\n }\n @keyframes bunnyEnterFace {\n 0% { opacity: 0; transform: scale(0.9); }\n 100% { opacity: 1; transform: scale(1); }\n }\n @keyframes bunnyEnterEye {\n 0% { opacity: 0; transform: scale(0.5); }\n 100% { opacity: 1; transform: scale(1); }\n }\n @keyframes leftEyeLook {\n 0%, 8% { transform: translate(0, 0); }\n 10%, 18% { transform: translate(1.5px, 0); }\n 20%, 22% { transform: translate(1.5px, 0) scaleY(0.1); }\n 24%, 32% { transform: translate(1.5px, 0); }\n 35%, 48% { transform: translate(-0.8px, -0.6px); }\n 52%, 54% { transform: translate(0, 0) scaleY(0.1); }\n 56%, 68% { transform: translate(0, 0); }\n 72%, 82% { transform: translate(-0.5px, 0.5px); }\n 85%, 100% { transform: translate(0, 0); }\n }\n @keyframes rightEyeLook {\n 0%, 8% { transform: translate(0, 0); }\n 10%, 18% { transform: translate(0.8px, 0); }\n 20%, 22% { transform: translate(0.8px, 0) scaleY(0.1); }\n 24%, 32% { transform: translate(0.8px, 0); }\n 35%, 48% { transform: translate(-1.5px, -0.6px); }\n 52%, 54% { transform: translate(0, 0) scaleY(0.1); }\n 56%, 68% { transform: translate(0, 0); }\n 72%, 82% { transform: translate(-1.2px, 0.5px); }\n 85%, 100% { transform: translate(0, 0); }\n }\n @keyframes leftEarTwitch {\n 0%, 9% { transform: rotate(0deg); }\n 12% { transform: rotate(-8deg); }\n 16%, 34% { transform: rotate(0deg); }\n 38% { transform: rotate(-12deg); }\n 42% { transform: rotate(-6deg); }\n 48%, 100% { transform: rotate(0deg); }\n }\n @keyframes rightEarTwitch {\n 0%, 9% { transform: rotate(0deg); }\n 12% { transform: rotate(6deg); }\n 16%, 34% { transform: rotate(0deg); }\n 38% { transform: rotate(10deg); }\n 42% { transform: rotate(4deg); }\n 48%, 71% { transform: rotate(0deg); }\n 74% { transform: rotate(8deg); }\n 78%, 100% { transform: rotate(0deg); }\n }\n .bunny-eye-left {\n opacity: 0;\n animation: bunnyEnterEye 0.3s ease-out 0.35s forwards, leftEyeLook 5s ease-in-out 0.65s infinite;\n transform-origin: center;\n transform-box: fill-box;\n }\n .bunny-eye-right {\n opacity: 0;\n animation: bunnyEnterEye 0.3s ease-out 0.4s forwards, rightEyeLook 5s ease-in-out 0.7s infinite;\n transform-origin: center;\n transform-box: fill-box;\n }\n .bunny-ear-left {\n opacity: 0;\n animation: bunnyEnterEar 0.3s ease-out 0.1s forwards, leftEarTwitch 5s ease-in-out 0.4s infinite;\n transform-origin: bottom center;\n transform-box: fill-box;\n }\n .bunny-ear-right {\n opacity: 0;\n animation: bunnyEnterEar 0.3s ease-out 0.15s forwards, rightEarTwitch 5s ease-in-out 0.45s infinite;\n transform-origin: bottom center;\n transform-box: fill-box;\n }\n .bunny-face {\n opacity: 0;\n animation: bunnyEnterFace 0.3s ease-out 0.25s forwards;\n transform-origin: center;\n transform-box: fill-box;\n }\n svg:hover .bunny-eye-left,\n svg:hover .bunny-eye-right {\n opacity: 0;\n transition: opacity 0.2s ease;\n }\n .bunny-happy-face {\n opacity: 0;\n transition: opacity 0.2s ease;\n }\n svg:hover .bunny-happy-face {\n opacity: 1;\n }\n `}</style>\n {/* Invisible hover area to catch all hover events */}\n <rect width=\"28\" height=\"28\" fill=\"transparent\" />\n {/* Left ear */}\n <path\n className=\"bunny-ear-left\"\n d=\"M3.738 10.2164L7.224 2.007H9.167L5.676 10.2164H3.738ZM10.791 6.42705C10.791 5.90346 10.726 5.42764 10.596 4.99959C10.47 4.57155 10.292 4.16643 10.063 3.78425C9.833 3.39825 9.56 3.01797 9.243 2.64343C8.926 2.26507 8.767 2.07589 8.767 2.07589L10.24 0.957996C10.24 0.957996 10.433 1.17203 10.819 1.60007C11.209 2.0243 11.559 2.49056 11.869 2.99886C12.178 3.50717 12.413 4.04222 12.574 4.60403C12.734 5.16584 12.814 5.77352 12.814 6.42705C12.814 7.10734 12.73 7.7303 12.562 8.29593C12.394 8.85774 12.153 9.3966 11.84 9.9126C11.526 10.4247 11.181 10.8833 10.802 11.2884C10.428 11.6974 10.24 11.9018 10.24 11.9018L8.767 10.7839C8.767 10.7839 8.924 10.5948 9.237 10.2164C9.554 9.8419 9.83 9.4597 10.063 9.06985C10.3 8.6762 10.479 8.26726 10.602 7.84304C10.728 7.41499 10.791 6.943 10.791 6.42705Z\"\n fill={color}\n />\n {/* Right ear */}\n <path\n className=\"bunny-ear-right\"\n d=\"M15.003 10.2164L18.489 2.007H20.432L16.941 10.2164H15.003ZM22.056 6.42705C22.056 5.90346 21.991 5.42764 21.861 4.99959C21.735 4.57155 21.557 4.16643 21.328 3.78425C21.098 3.39825 20.825 3.01797 20.508 2.64343C20.191 2.26507 20.032 2.07589 20.032 2.07589L21.505 0.957996C21.505 0.957996 21.698 1.17203 22.084 1.60007C22.474 2.0243 22.824 2.49056 23.133 2.99886C23.443 3.50717 23.678 4.04222 23.839 4.60403C23.999 5.16584 24.079 5.77352 24.079 6.42705C24.079 7.10734 23.995 7.7303 23.827 8.29593C23.659 8.85774 23.418 9.3966 23.105 9.9126C22.791 10.4247 22.445 10.8833 22.067 11.2884C21.693 11.6974 21.505 11.9018 21.505 11.9018L20.032 10.7839C20.032 10.7839 20.189 10.5948 20.502 10.2164C20.819 9.8419 21.094 9.4597 21.328 9.06985C21.565 8.6762 21.744 8.26726 21.866 7.84304C21.993 7.41499 22.056 6.943 22.056 6.42705Z\"\n fill={color}\n />\n {/* Face outline */}\n <path\n className=\"bunny-face\"\n d=\"M2.03 20.4328C2.03 20.9564 2.093 21.4322 2.219 21.8602C2.345 22.2883 2.523 22.6953 2.752 23.0813C2.981 23.4635 3.254 23.8419 3.572 24.2164C3.889 24.5948 4.047 24.7839 4.047 24.7839L2.574 25.9018C2.574 25.9018 2.379 25.6878 1.989 25.2598C1.603 24.8355 1.256 24.3693 0.946 23.861C0.636 23.3527 0.401 22.8176 0.241 22.2558C0.08 21.694 0 21.0863 0 20.4328C0 19.7525 0.084 19.1314 0.252 18.5696C0.421 18.004 0.661 17.4651 0.975 16.953C1.288 16.4371 1.632 15.9765 2.007 15.5714C2.385 15.1625 2.574 14.958 2.574 14.958L4.047 16.0759C4.047 16.0759 3.889 16.2651 3.572 16.6434C3.258 17.018 2.983 17.4021 2.746 17.7957C2.513 18.1855 2.335 18.5945 2.213 19.0225C2.091 19.4467 2.03 19.9168 2.03 20.4328ZM23.687 20.4271C23.687 19.9035 23.622 19.4276 23.492 18.9996C23.366 18.5715 23.188 18.1664 22.959 17.7843C22.729 17.3982 22.456 17.018 22.139 16.6434C21.822 16.2651 21.663 16.0759 21.663 16.0759L23.136 14.958C23.136 14.958 23.329 15.172 23.715 15.6001C24.105 16.0243 24.455 16.4906 24.765 16.9989C25.074 17.5072 25.309 18.0422 25.47 18.604C25.63 19.1658 25.71 19.7735 25.71 20.4271C25.71 21.1073 25.626 21.7303 25.458 22.2959C25.29 22.8577 25.049 23.3966 24.736 23.9126C24.422 24.4247 24.077 24.8833 23.698 25.2884C23.324 25.6974 23.136 25.9018 23.136 25.9018L21.663 24.7839C21.663 24.7839 21.82 24.5948 22.133 24.2164C22.45 23.8419 22.726 23.4597 22.959 23.0698C23.196 22.6762 23.375 22.2673 23.498 21.843C23.624 21.415 23.687 20.943 23.687 20.4271Z\"\n fill={color}\n />\n {/* Animated bunny eyes */}\n <circle\n className=\"bunny-eye-left\"\n cx=\"8.277\"\n cy=\"20.466\"\n r=\"1.8\"\n fill={color}\n />\n <circle\n className=\"bunny-eye-right\"\n cx=\"19.878\"\n cy=\"20.466\"\n r=\"1.8\"\n fill={color}\n />\n {/* Happy face on hover */}\n <text\n className=\"bunny-happy-face\"\n x=\"14\"\n y=\"26\"\n textAnchor=\"middle\"\n fontSize=\"12\"\n fontWeight=\"bold\"\n fill={color}\n fontFamily=\"system-ui, -apple-system, sans-serif\"\n >\n ˃ ᵕ ˂\n </text>\n </svg>\n);\n\n// Layout / grid icon for layout mode\nexport const IconLayout = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <rect\n x=\"3\"\n y=\"3\"\n width=\"18\"\n height=\"18\"\n rx=\"2\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <line\n x1=\"3\"\n y1=\"9\"\n x2=\"21\"\n y2=\"9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <line\n x1=\"9\"\n y1=\"9\"\n x2=\"9\"\n y2=\"21\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n","// =============================================================================\n// Freeze Animations\n// =============================================================================\n//\n// Monkey-patches setTimeout, setInterval, and requestAnimationFrame so that\n// callbacks are silently skipped while frozen. Also injects CSS to pause\n// CSS animations/transitions, pauses WAAPI animations, and pauses videos.\n//\n// Toolbar/popup code must import `originalSetTimeout` etc. to bypass the patch.\n//\n// Patches are installed as a side effect of importing this module.\n// =============================================================================\n\n// Exclude selectors — agentation UI elements should never be frozen\nconst EXCLUDE_ATTRS = [\n \"data-feedback-toolbar\",\n \"data-annotation-popup\",\n \"data-annotation-marker\",\n];\nconst NOT_SELECTORS = EXCLUDE_ATTRS\n .flatMap((a) => [`:not([${a}])`, `:not([${a}] *)`])\n .join(\"\");\n\nconst STYLE_ID = \"feedback-freeze-styles\";\nconst STATE_KEY = \"__agentation_freeze\";\n\n// ---------------------------------------------------------------------------\n// Shared mutable state on window (survives HMR module re-execution)\n// ---------------------------------------------------------------------------\ninterface FreezeState {\n frozen: boolean;\n installed: boolean;\n origSetTimeout: typeof setTimeout;\n origSetInterval: typeof setInterval;\n origRAF: typeof requestAnimationFrame;\n // Queues live on window so they survive HMR module re-execution\n pausedAnimations: Animation[];\n frozenTimeoutQueue: Array<() => void>;\n frozenRAFQueue: FrameRequestCallback[];\n}\n\nfunction getState(): FreezeState {\n if (typeof window === \"undefined\") {\n // SSR stub\n return {\n frozen: false,\n installed: true, // prevent patching on server\n origSetTimeout: setTimeout,\n origSetInterval: setInterval,\n origRAF: (cb: FrameRequestCallback) => 0 as any,\n pausedAnimations: [],\n frozenTimeoutQueue: [],\n frozenRAFQueue: [],\n };\n }\n const w = window as any;\n if (!w[STATE_KEY]) {\n w[STATE_KEY] = {\n frozen: false,\n installed: false,\n origSetTimeout: null,\n origSetInterval: null,\n origRAF: null,\n pausedAnimations: [],\n frozenTimeoutQueue: [],\n frozenRAFQueue: [],\n };\n }\n return w[STATE_KEY];\n}\n\nconst _s = getState();\n\n// ---------------------------------------------------------------------------\n// Install patches (once — survives HMR because `installed` lives on window)\n// ---------------------------------------------------------------------------\nif (typeof window !== \"undefined\" && !_s.installed) {\n // Save the real functions\n _s.origSetTimeout = window.setTimeout.bind(window);\n _s.origSetInterval = window.setInterval.bind(window);\n _s.origRAF = window.requestAnimationFrame.bind(window);\n\n // Patch setTimeout — queue callback when frozen (replayed on unfreeze)\n (window as any).setTimeout = (\n handler: TimerHandler,\n timeout?: number,\n ...args: any[]\n ): ReturnType<typeof setTimeout> => {\n if (typeof handler === \"string\") {\n return _s.origSetTimeout(handler, timeout);\n }\n return _s.origSetTimeout(\n (...a: any[]) => {\n if (_s.frozen) {\n _s.frozenTimeoutQueue.push(() => (handler as Function)(...a));\n } else {\n (handler as Function)(...a);\n }\n },\n timeout,\n ...args,\n );\n };\n\n // Patch setInterval — skip callback when frozen\n (window as any).setInterval = (\n handler: TimerHandler,\n timeout?: number,\n ...args: any[]\n ): ReturnType<typeof setInterval> => {\n if (typeof handler === \"string\") {\n return _s.origSetInterval(handler, timeout);\n }\n return _s.origSetInterval(\n (...a: any[]) => {\n if (!_s.frozen) (handler as Function)(...a);\n },\n timeout,\n ...args,\n );\n };\n\n // Patch requestAnimationFrame — queue callback when frozen (no CPU spin)\n // The wrapper fires once on the next frame; if still frozen the callback\n // is stored in _s.frozenRAFQueue and replayed on unfreeze.\n (window as any).requestAnimationFrame = (\n callback: FrameRequestCallback,\n ): number => {\n return _s.origRAF((timestamp: number) => {\n if (_s.frozen) {\n _s.frozenRAFQueue.push(callback);\n } else {\n callback(timestamp);\n }\n });\n };\n\n _s.installed = true;\n}\n\n// ---------------------------------------------------------------------------\n// Exports — original (unpatched) timing functions for toolbar/popup use\n// ---------------------------------------------------------------------------\nexport const originalSetTimeout = _s.origSetTimeout;\nexport const originalSetInterval = _s.origSetInterval;\nexport const originalRequestAnimationFrame = _s.origRAF;\n\n// ---------------------------------------------------------------------------\n// Freeze / Unfreeze\n// ---------------------------------------------------------------------------\n\nfunction isAgentationElement(el: Element | null): boolean {\n if (!el) return false;\n return EXCLUDE_ATTRS.some((attr) => !!el.closest?.(`[${attr}]`));\n}\n\nexport function freeze(): void {\n if (typeof document === \"undefined\") return;\n if (_s.frozen) return;\n _s.frozen = true;\n _s.frozenTimeoutQueue = [];\n _s.frozenRAFQueue = [];\n\n // CSS injection — pause CSS animations and kill transitions\n let style = document.getElementById(STYLE_ID);\n if (!style) {\n style = document.createElement(\"style\");\n style.id = STYLE_ID;\n }\n style.textContent = `\n *${NOT_SELECTORS},\n *${NOT_SELECTORS}::before,\n *${NOT_SELECTORS}::after {\n animation-play-state: paused !important;\n transition: none !important;\n }\n `;\n document.head.appendChild(style);\n\n // WAAPI — pause only RUNNING non-agentation animations and store references\n // (pausing finished animations would restart them on play(), breaking entrance anims)\n _s.pausedAnimations = [];\n try {\n document.getAnimations().forEach((anim) => {\n if (anim.playState !== \"running\") return;\n const target = (anim.effect as KeyframeEffect)?.target as Element | null;\n if (!isAgentationElement(target)) {\n anim.pause();\n _s.pausedAnimations.push(anim);\n }\n });\n } catch {\n // getAnimations may not be available in all environments\n }\n\n // Pause videos\n document.querySelectorAll(\"video\").forEach((video) => {\n if (!video.paused) {\n video.dataset.wasPaused = \"false\";\n video.pause();\n }\n });\n}\n\nexport function unfreeze(): void {\n if (typeof document === \"undefined\") return;\n if (!_s.frozen) return;\n _s.frozen = false;\n\n // Replay queued setTimeout callbacks asynchronously (resolves stuck delay()\n // Promises, restarts animation loops interrupted by visibilitychange, etc.)\n // Using origSetTimeout(cb, 0) avoids blocking the main thread in one go.\n // Re-check _s.frozen before executing — if freeze() was called again between\n // scheduling and execution, re-queue the callback instead of running it.\n const timeoutQueue = _s.frozenTimeoutQueue;\n _s.frozenTimeoutQueue = [];\n for (const cb of timeoutQueue) {\n _s.origSetTimeout(() => {\n if (_s.frozen) {\n _s.frozenTimeoutQueue.push(cb);\n return;\n }\n try {\n cb();\n } catch (e) {\n console.warn(\"[agentation] Error replaying queued timeout:\", e);\n }\n }, 0);\n }\n\n // Schedule queued rAF callbacks for the next frame.\n // Re-check _s.frozen — if re-frozen before the frame fires, re-queue.\n const rafQueue = _s.frozenRAFQueue;\n _s.frozenRAFQueue = [];\n for (const cb of rafQueue) {\n _s.origRAF((ts: number) => {\n if (_s.frozen) {\n _s.frozenRAFQueue.push(cb);\n return;\n }\n cb(ts);\n });\n }\n\n // WAAPI — resume the exact animations we paused BEFORE removing CSS\n // (removing CSS first can cause the browser to replace animation objects)\n for (const anim of _s.pausedAnimations) {\n try {\n anim.play();\n } catch (e) {\n console.warn(\"[agentation] Error resuming animation:\", e);\n }\n }\n _s.pausedAnimations = [];\n\n // Now remove CSS injection\n document.getElementById(STYLE_ID)?.remove();\n\n // Resume videos\n document.querySelectorAll(\"video\").forEach((video) => {\n if (video.dataset.wasPaused === \"false\") {\n video.play().catch(() => {});\n delete video.dataset.wasPaused;\n }\n });\n}\n","// =============================================================================\n// Element Identification Utilities\n// =============================================================================\n\n// =============================================================================\n// Shadow DOM Helpers\n// =============================================================================\n\n/**\n * Gets the parent element, crossing shadow DOM boundaries.\n * When inside a shadow root with no parentElement, returns the shadow host.\n */\nfunction getParentElement(element: Element): Element | null {\n if (element.parentElement) {\n return element.parentElement;\n }\n const root = element.getRootNode();\n if (root instanceof ShadowRoot) {\n return root.host;\n }\n return null;\n}\n\n/**\n * Finds the closest ancestor matching a selector, crossing shadow DOM boundaries.\n */\nexport function closestCrossingShadow(element: Element, selector: string): Element | null {\n let current: Element | null = element;\n while (current) {\n if (current.matches(selector)) return current;\n current = getParentElement(current);\n }\n return null;\n}\n\n/**\n * Checks if an element is inside a shadow DOM\n */\nexport function isInShadowDOM(element: Element): boolean {\n return element.getRootNode() instanceof ShadowRoot;\n}\n\n/**\n * Gets the shadow host for an element, or null if not in shadow DOM\n */\nexport function getShadowHost(element: Element): Element | null {\n const root = element.getRootNode();\n if (root instanceof ShadowRoot) {\n return root.host;\n }\n return null;\n}\n\n// =============================================================================\n// Element Path Utilities\n// =============================================================================\n\n/**\n * Gets a readable path for an element (e.g., \"article > section > p\")\n * Supports elements inside shadow DOM by crossing shadow boundaries.\n */\nexport function getElementPath(target: HTMLElement, maxDepth = 4): string {\n const parts: string[] = [];\n let current: HTMLElement | null = target;\n let depth = 0;\n\n while (current && depth < maxDepth) {\n const tag = current.tagName.toLowerCase();\n\n // Skip generic wrappers\n if (tag === \"html\" || tag === \"body\") break;\n\n // Get identifier\n let identifier = tag;\n if (current.id) {\n identifier = `#${current.id}`;\n } else if (current.className && typeof current.className === \"string\") {\n const meaningfulClass = current.className\n .split(/\\s+/)\n .find(c => c.length > 2 && !c.match(/^[a-z]{1,2}$/) && !c.match(/[A-Z0-9]{5,}/));\n if (meaningfulClass) {\n identifier = `.${meaningfulClass.split(\"_\")[0]}`;\n }\n }\n\n // Mark shadow boundary crossings\n const nextParent = getParentElement(current);\n if (!current.parentElement && nextParent) {\n identifier = `⟨shadow⟩ ${identifier}`;\n }\n\n parts.unshift(identifier);\n current = nextParent as HTMLElement | null;\n depth++;\n }\n\n return parts.join(\" > \");\n}\n\n/**\n * Identifies an element and returns a human-readable name + path\n */\nexport function identifyElement(target: HTMLElement): { name: string; path: string } {\n const path = getElementPath(target);\n\n if (target.dataset.element) {\n return { name: target.dataset.element, path };\n }\n\n const tag = target.tagName.toLowerCase();\n\n // SVG elements\n if ([\"path\", \"circle\", \"rect\", \"line\", \"g\"].includes(tag)) {\n // Try to find parent SVG context (crossing shadow boundaries)\n const svg = closestCrossingShadow(target, \"svg\");\n if (svg) {\n const parent = getParentElement(svg);\n if (parent instanceof HTMLElement) {\n const parentName = identifyElement(parent).name;\n return { name: `graphic in ${parentName}`, path };\n }\n }\n return { name: \"graphic element\", path };\n }\n if (tag === \"svg\") {\n const parent = getParentElement(target);\n if (parent?.tagName.toLowerCase() === \"button\") {\n const btnText = parent.textContent?.trim();\n return { name: btnText ? `icon in \"${btnText}\" button` : \"button icon\", path };\n }\n return { name: \"icon\", path };\n }\n\n // Interactive elements\n if (tag === \"button\") {\n const text = target.textContent?.trim();\n const ariaLabel = target.getAttribute(\"aria-label\");\n if (ariaLabel) return { name: `button [${ariaLabel}]`, path };\n return { name: text ? `button \"${text.slice(0, 25)}\"` : \"button\", path };\n }\n if (tag === \"a\") {\n const text = target.textContent?.trim();\n const href = target.getAttribute(\"href\");\n if (text) return { name: `link \"${text.slice(0, 25)}\"`, path };\n if (href) return { name: `link to ${href.slice(0, 30)}`, path };\n return { name: \"link\", path };\n }\n if (tag === \"input\") {\n const type = target.getAttribute(\"type\") || \"text\";\n const placeholder = target.getAttribute(\"placeholder\");\n const name = target.getAttribute(\"name\");\n if (placeholder) return { name: `input \"${placeholder}\"`, path };\n if (name) return { name: `input [${name}]`, path };\n return { name: `${type} input`, path };\n }\n\n // Headings\n if ([\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\"].includes(tag)) {\n const text = target.textContent?.trim();\n return { name: text ? `${tag} \"${text.slice(0, 35)}\"` : tag, path };\n }\n\n // Text elements\n if (tag === \"p\") {\n const text = target.textContent?.trim();\n if (text) return { name: `paragraph: \"${text.slice(0, 40)}${text.length > 40 ? '...' : ''}\"`, path };\n return { name: \"paragraph\", path };\n }\n if (tag === \"span\" || tag === \"label\") {\n const text = target.textContent?.trim();\n if (text && text.length < 40) return { name: `\"${text}\"`, path };\n return { name: tag, path };\n }\n if (tag === \"li\") {\n const text = target.textContent?.trim();\n if (text && text.length < 40) return { name: `list item: \"${text.slice(0, 35)}\"`, path };\n return { name: \"list item\", path };\n }\n if (tag === \"blockquote\") return { name: \"blockquote\", path };\n if (tag === \"code\") {\n const text = target.textContent?.trim();\n if (text && text.length < 30) return { name: `code: \\`${text}\\``, path };\n return { name: \"code\", path };\n }\n if (tag === \"pre\") return { name: \"code block\", path };\n\n // Media\n if (tag === \"img\") {\n const alt = target.getAttribute(\"alt\");\n return { name: alt ? `image \"${alt.slice(0, 30)}\"` : \"image\", path };\n }\n if (tag === \"video\") return { name: \"video\", path };\n\n // Containers - try to infer meaningful name\n if ([\"div\", \"section\", \"article\", \"nav\", \"header\", \"footer\", \"aside\", \"main\"].includes(tag)) {\n const className = target.className;\n const role = target.getAttribute(\"role\");\n const ariaLabel = target.getAttribute(\"aria-label\");\n\n if (ariaLabel) return { name: `${tag} [${ariaLabel}]`, path };\n if (role) return { name: `${role}`, path };\n\n if (typeof className === \"string\" && className) {\n const words = className\n .split(/[\\s_-]+/)\n .map((c) => c.replace(/[A-Z0-9]{5,}.*$/, \"\")) // Remove CSS module hashes\n .filter((c) => c.length > 2 && !/^[a-z]{1,2}$/.test(c))\n .slice(0, 2);\n if (words.length > 0) return { name: words.join(\" \"), path };\n }\n\n return { name: tag === \"div\" ? \"container\" : tag, path };\n }\n\n return { name: tag, path };\n}\n\n/**\n * Gets text content from element and siblings for context\n */\nexport function getNearbyText(element: HTMLElement): string {\n const texts: string[] = [];\n\n // Own text\n const ownText = element.textContent?.trim();\n if (ownText && ownText.length < 100) {\n texts.push(ownText);\n }\n\n // Previous sibling text\n const prev = element.previousElementSibling;\n if (prev) {\n const prevText = prev.textContent?.trim();\n if (prevText && prevText.length < 50) {\n texts.unshift(`[before: \"${prevText.slice(0, 40)}\"]`);\n }\n }\n\n // Next sibling text\n const next = element.nextElementSibling;\n if (next) {\n const nextText = next.textContent?.trim();\n if (nextText && nextText.length < 50) {\n texts.push(`[after: \"${nextText.slice(0, 40)}\"]`);\n }\n }\n\n return texts.join(\" \");\n}\n\n/**\n * Simplified element identifier for animation feedback (less verbose)\n */\nexport function identifyAnimationElement(target: HTMLElement): string {\n // Allow explicit labeling via data attribute\n if (target.dataset.element) return target.dataset.element;\n\n const tag = target.tagName.toLowerCase();\n\n // SVG elements\n if (tag === \"path\") return \"path\";\n if (tag === \"circle\") return \"circle\";\n if (tag === \"rect\") return \"rectangle\";\n if (tag === \"line\") return \"line\";\n if (tag === \"ellipse\") return \"ellipse\";\n if (tag === \"polygon\") return \"polygon\";\n if (tag === \"g\") return \"group\";\n if (tag === \"svg\") return \"svg\";\n\n // Interactive elements\n if (tag === \"button\") {\n const text = target.textContent?.trim();\n return text ? `button \"${text}\"` : \"button\";\n }\n if (tag === \"input\") {\n const type = target.getAttribute(\"type\") || \"text\";\n return `input (${type})`;\n }\n\n // Text elements\n if (tag === \"span\" || tag === \"p\" || tag === \"label\") {\n const text = target.textContent?.trim();\n if (text && text.length < 30) return `\"${text}\"`;\n return \"text\";\n }\n\n // Containers - try to infer purpose from class name\n if (tag === \"div\") {\n const className = target.className;\n if (typeof className === \"string\" && className) {\n const words = className\n .split(/[\\s_-]+/)\n .map(c => c.replace(/[A-Z0-9]{5,}.*$/, \"\"))\n .filter(c => c.length > 2 && !/^[a-z]{1,2}$/.test(c))\n .slice(0, 2);\n if (words.length > 0) {\n return words.join(\" \");\n }\n }\n return \"container\";\n }\n\n return tag;\n}\n\n/**\n * Gets nearby sibling elements for structural context.\n * Supports elements inside shadow DOM.\n */\nexport function getNearbyElements(element: HTMLElement): string {\n const parent = getParentElement(element);\n if (!parent) return \"\";\n\n // Get siblings from the correct source\n const elementRoot = element.getRootNode();\n const children = (elementRoot instanceof ShadowRoot && element.parentElement)\n ? Array.from(element.parentElement.children)\n : Array.from(parent.children);\n\n const siblings = children.filter(\n (child) => child !== element && child instanceof HTMLElement\n ) as HTMLElement[];\n\n if (siblings.length === 0) return \"\";\n\n // Get concise identifiers for up to 4 nearby siblings\n const siblingIds = siblings.slice(0, 4).map((sib) => {\n const tag = sib.tagName.toLowerCase();\n const className = sib.className;\n\n // Get first meaningful class\n let cls = \"\";\n if (typeof className === \"string\" && className) {\n const meaningful = className\n .split(/\\s+/)\n .map((c) => c.replace(/[_][a-zA-Z0-9]{5,}.*$/, \"\")) // Remove module hashes\n .find((c) => c.length > 2 && !/^[a-z]{1,2}$/.test(c));\n if (meaningful) cls = `.${meaningful}`;\n }\n\n // For buttons/links, include short text\n if (tag === \"button\" || tag === \"a\") {\n const text = sib.textContent?.trim().slice(0, 15);\n if (text) return `${tag}${cls} \"${text}\"`;\n }\n\n return `${tag}${cls}`;\n });\n\n // Add parent context\n const parentTag = parent.tagName.toLowerCase();\n let parentId = parentTag;\n if (typeof parent.className === \"string\" && parent.className) {\n const parentCls = parent.className\n .split(/\\s+/)\n .map((c) => c.replace(/[_][a-zA-Z0-9]{5,}.*$/, \"\"))\n .find((c) => c.length > 2 && !/^[a-z]{1,2}$/.test(c));\n if (parentCls) parentId = `.${parentCls}`;\n }\n\n const total = parent.children.length;\n const suffix = total > siblingIds.length + 1 ? ` (${total} total in ${parentId})` : \"\";\n\n return siblingIds.join(\", \") + suffix;\n}\n\n/**\n * Gets CSS class names from an element (cleaned of module hashes)\n */\nexport function getElementClasses(target: HTMLElement): string {\n const className = target.className;\n if (typeof className !== \"string\" || !className) return \"\";\n\n // Split and clean class names (remove module hashes like _abc123)\n const classes = className\n .split(/\\s+/)\n .filter(c => c.length > 0)\n .map(c => {\n // Keep the meaningful part before the hash\n const match = c.match(/^([a-zA-Z][a-zA-Z0-9_-]*?)(?:_[a-zA-Z0-9]{5,})?$/);\n return match ? match[1] : c;\n })\n .filter((c, i, arr) => arr.indexOf(c) === i); // dedupe\n\n return classes.join(\", \");\n}\n\n/**\n * Gets key computed styles for an element (useful for styling issues)\n */\nexport function getComputedStylesSnapshot(target: HTMLElement): string {\n if (typeof window === \"undefined\") return \"\";\n\n const styles = window.getComputedStyle(target);\n const parts: string[] = [];\n\n // Color & text\n const color = styles.color;\n const bg = styles.backgroundColor;\n if (color && color !== \"rgb(0, 0, 0)\") parts.push(`color: ${color}`);\n if (bg && bg !== \"rgba(0, 0, 0, 0)\" && bg !== \"transparent\") parts.push(`bg: ${bg}`);\n\n // Typography\n const fontSize = styles.fontSize;\n const fontWeight = styles.fontWeight;\n if (fontSize) parts.push(`font: ${fontSize}`);\n if (fontWeight && fontWeight !== \"400\" && fontWeight !== \"normal\") parts.push(`weight: ${fontWeight}`);\n\n // Spacing\n const padding = styles.padding;\n const margin = styles.margin;\n if (padding && padding !== \"0px\") parts.push(`padding: ${padding}`);\n if (margin && margin !== \"0px\") parts.push(`margin: ${margin}`);\n\n // Layout\n const display = styles.display;\n const position = styles.position;\n if (display && display !== \"block\" && display !== \"inline\") parts.push(`display: ${display}`);\n if (position && position !== \"static\") parts.push(`position: ${position}`);\n\n // Border\n const borderRadius = styles.borderRadius;\n if (borderRadius && borderRadius !== \"0px\") parts.push(`radius: ${borderRadius}`);\n\n return parts.join(\", \");\n}\n\n// Values to filter out when collecting computed styles (browser defaults / uninteresting)\nconst DEFAULT_STYLE_VALUES = new Set([\n \"none\", \"normal\", \"auto\", \"0px\", \"rgba(0, 0, 0, 0)\", \"transparent\", \"static\", \"visible\"\n]);\n\n// Element type categories for style property selection\nconst TEXT_ELEMENTS = new Set([\n \"p\", \"span\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"label\", \"li\", \"td\", \"th\",\n \"blockquote\", \"figcaption\", \"caption\", \"legend\", \"dt\", \"dd\", \"pre\", \"code\",\n \"em\", \"strong\", \"b\", \"i\", \"a\", \"time\", \"cite\", \"q\"\n]);\nconst FORM_INPUT_ELEMENTS = new Set([\"input\", \"textarea\", \"select\"]);\nconst MEDIA_ELEMENTS = new Set([\"img\", \"video\", \"canvas\", \"svg\"]);\nconst CONTAINER_ELEMENTS = new Set([\n \"div\", \"section\", \"article\", \"nav\", \"header\", \"footer\", \"aside\", \"main\",\n \"ul\", \"ol\", \"form\", \"fieldset\"\n]);\n\n/**\n * Gets key computed styles for the annotation popup display.\n * Returns different properties based on element type to show the most relevant\n * CSS properties for debugging (e.g., typography for text, layout for containers).\n */\nexport function getDetailedComputedStyles(target: HTMLElement): Record<string, string> {\n if (typeof window === \"undefined\") return {};\n\n const styles = window.getComputedStyle(target);\n const result: Record<string, string> = {};\n const tag = target.tagName.toLowerCase();\n\n // Select relevant properties based on element type\n let properties: string[];\n\n if (TEXT_ELEMENTS.has(tag)) {\n // Typography-focused for text elements\n properties = [\"color\", \"fontSize\", \"fontWeight\", \"fontFamily\", \"lineHeight\"];\n } else if (tag === \"button\" || (tag === \"a\" && target.getAttribute(\"role\") === \"button\")) {\n // Appearance and spacing for interactive elements\n properties = [\"backgroundColor\", \"color\", \"padding\", \"borderRadius\", \"fontSize\"];\n } else if (FORM_INPUT_ELEMENTS.has(tag)) {\n // Form styling\n properties = [\"backgroundColor\", \"color\", \"padding\", \"borderRadius\", \"fontSize\"];\n } else if (MEDIA_ELEMENTS.has(tag)) {\n // Dimensions for media\n properties = [\"width\", \"height\", \"objectFit\", \"borderRadius\"];\n } else if (CONTAINER_ELEMENTS.has(tag)) {\n // Layout-focused for containers\n properties = [\"display\", \"padding\", \"margin\", \"gap\", \"backgroundColor\"];\n } else {\n // Default fallback\n properties = [\"color\", \"fontSize\", \"margin\", \"padding\", \"backgroundColor\"];\n }\n\n for (const prop of properties) {\n const cssPropertyName = prop.replace(/([A-Z])/g, \"-$1\").toLowerCase();\n const value = styles.getPropertyValue(cssPropertyName);\n if (value && !DEFAULT_STYLE_VALUES.has(value)) {\n result[prop] = value;\n }\n }\n\n return result;\n}\n\n// Comprehensive list of CSS properties for forensic output\nconst FORENSIC_PROPERTIES = [\n // Colors\n \"color\", \"backgroundColor\", \"borderColor\",\n // Typography\n \"fontSize\", \"fontWeight\", \"fontFamily\", \"lineHeight\", \"letterSpacing\", \"textAlign\",\n // Box model\n \"width\", \"height\", \"padding\", \"margin\", \"border\", \"borderRadius\",\n // Layout & positioning\n \"display\", \"position\", \"top\", \"right\", \"bottom\", \"left\", \"zIndex\",\n \"flexDirection\", \"justifyContent\", \"alignItems\", \"gap\",\n // Visual effects\n \"opacity\", \"visibility\", \"overflow\", \"boxShadow\",\n // Transform\n \"transform\",\n];\n\n/**\n * Gets full computed styles for forensic output.\n * Returns a comprehensive semicolon-separated string of all relevant CSS properties\n * for maximum debugging detail in the forensic output format.\n */\nexport function getForensicComputedStyles(target: HTMLElement): string {\n if (typeof window === \"undefined\") return \"\";\n\n const styles = window.getComputedStyle(target);\n const parts: string[] = [];\n\n for (const prop of FORENSIC_PROPERTIES) {\n const cssPropertyName = prop.replace(/([A-Z])/g, \"-$1\").toLowerCase();\n const value = styles.getPropertyValue(cssPropertyName);\n if (value && !DEFAULT_STYLE_VALUES.has(value)) {\n parts.push(`${cssPropertyName}: ${value}`);\n }\n }\n\n return parts.join(\"; \");\n}\n\n/**\n * Parses a forensic computed styles string back into a Record.\n * Inverse of getForensicComputedStyles - used when editing annotations.\n */\nexport function parseComputedStylesString(\n stylesStr: string | undefined,\n): Record<string, string> | undefined {\n if (!stylesStr) return undefined;\n\n const result: Record<string, string> = {};\n const parts = stylesStr.split(\";\").map((p) => p.trim()).filter(Boolean);\n\n for (const part of parts) {\n const colonIndex = part.indexOf(\":\");\n if (colonIndex > 0) {\n const key = part.slice(0, colonIndex).trim();\n const value = part.slice(colonIndex + 1).trim();\n if (key && value) {\n result[key] = value;\n }\n }\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/**\n * Gets accessibility information for an element\n */\nexport function getAccessibilityInfo(target: HTMLElement): string {\n const parts: string[] = [];\n\n const role = target.getAttribute(\"role\");\n const ariaLabel = target.getAttribute(\"aria-label\");\n const ariaDescribedBy = target.getAttribute(\"aria-describedby\");\n const tabIndex = target.getAttribute(\"tabindex\");\n const ariaHidden = target.getAttribute(\"aria-hidden\");\n\n if (role) parts.push(`role=\"${role}\"`);\n if (ariaLabel) parts.push(`aria-label=\"${ariaLabel}\"`);\n if (ariaDescribedBy) parts.push(`aria-describedby=\"${ariaDescribedBy}\"`);\n if (tabIndex) parts.push(`tabindex=${tabIndex}`);\n if (ariaHidden === \"true\") parts.push(\"aria-hidden\");\n\n // Check focusability\n const focusable = target.matches(\"a, button, input, select, textarea, [tabindex]\");\n if (focusable) parts.push(\"focusable\");\n\n return parts.join(\", \");\n}\n\n/**\n * Gets full DOM ancestry path (for forensic mode).\n * Supports elements inside shadow DOM by marking shadow boundary crossings.\n */\nexport function getFullElementPath(target: HTMLElement): string {\n const parts: string[] = [];\n let current: HTMLElement | null = target;\n\n while (current && current.tagName.toLowerCase() !== \"html\") {\n const tag = current.tagName.toLowerCase();\n let identifier = tag;\n\n if (current.id) {\n identifier = `${tag}#${current.id}`;\n } else if (current.className && typeof current.className === \"string\") {\n const cls = current.className\n .split(/\\s+/)\n .map(c => c.replace(/[_][a-zA-Z0-9]{5,}.*$/, \"\"))\n .find(c => c.length > 2);\n if (cls) identifier = `${tag}.${cls}`;\n }\n\n // Mark shadow boundary crossings\n const nextParent = getParentElement(current);\n if (!current.parentElement && nextParent) {\n identifier = `⟨shadow⟩ ${identifier}`;\n }\n\n parts.unshift(identifier);\n current = nextParent as HTMLElement | null;\n }\n\n return parts.join(\" > \");\n}\n","// =============================================================================\n// React Component Name Detection\n// Uses React DevTools techniques to extract component names from fiber nodes\n// =============================================================================\n\n/**\n * React Fiber node type (minimal subset we care about)\n * Based on React internal structure\n */\ninterface ReactFiber {\n tag: number;\n type: ComponentType | string | null;\n elementType: ComponentType | null;\n return: ReactFiber | null;\n}\n\ninterface ComponentType {\n name?: string;\n displayName?: string;\n render?: { name?: string; displayName?: string };\n type?: ComponentType;\n _context?: { displayName?: string };\n _status?: number;\n _result?: ComponentType;\n $$typeof?: symbol;\n}\n\n/**\n * Fiber tags from React source (stable across versions)\n * https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactWorkTags.js\n */\nconst FiberTags = {\n FunctionComponent: 0,\n ClassComponent: 1,\n IndeterminateComponent: 2,\n HostRoot: 3,\n HostPortal: 4,\n HostComponent: 5, // DOM elements like <div>\n HostText: 6,\n Fragment: 7,\n Mode: 8,\n ContextConsumer: 9,\n ContextProvider: 10,\n ForwardRef: 11,\n Profiler: 12,\n SuspenseComponent: 13,\n MemoComponent: 14,\n SimpleMemoComponent: 15,\n LazyComponent: 16,\n // React 18/19 additions\n IncompleteClassComponent: 17,\n DehydratedFragment: 18,\n SuspenseListComponent: 19,\n // Note: 20 is unused/reserved\n ScopeComponent: 21,\n OffscreenComponent: 22,\n LegacyHiddenComponent: 23,\n CacheComponent: 24,\n TracingMarkerComponent: 25,\n HostHoistable: 26,\n HostSingleton: 27,\n IncompleteFunctionComponent: 28,\n Throw: 29,\n ViewTransitionComponent: 30,\n ActivityComponent: 31,\n} as const;\n\n// =============================================================================\n// Default Filter Configuration\n// =============================================================================\n\n/**\n * Default exact names to always skip (React internals)\n */\nexport const DEFAULT_SKIP_EXACT = new Set([\n \"Component\",\n \"PureComponent\",\n \"Fragment\",\n \"Suspense\",\n \"Profiler\",\n \"StrictMode\",\n \"Routes\",\n \"Route\",\n \"Outlet\",\n // Framework internals - exact matches\n \"Root\",\n \"ErrorBoundaryHandler\",\n \"HotReload\",\n \"Hot\",\n]);\n\n/**\n * Default patterns for framework internals\n * Note: Patterns are designed to be specific to avoid false positives\n * (e.g., ServerStatus, ClientProfile should NOT be filtered)\n */\nexport const DEFAULT_SKIP_PATTERNS: RegExp[] = [\n /Boundary$/, // ErrorBoundary, RedirectBoundary\n /BoundaryHandler$/, // ErrorBoundaryHandler\n /Provider$/, // ThemeProvider, Context.Provider\n /Consumer$/, // Context.Consumer\n /^(Inner|Outer)/, // InnerLayoutRouter\n /Router$/, // AppRouter, BrowserRouter\n /^Client(Page|Segment|Root)/, // ClientPageRoot, ClientSegmentRoot\n /^Segment(ViewNode|Node)$/, // Next.js App Router internals\n /^LayoutSegment/, // Next.js layout segment wrappers\n /^Server(Root|Component|Render)/, // ServerRoot (not ServerStatus)\n /^RSC/, // RSCComponent\n /Context$/, // LayoutRouterContext\n /^Hot(Reload)?$/, // HotReload (exact match to avoid false positives)\n /^(Dev|React)(Overlay|Tools|Root)/, // DevTools, ReactDevOverlay\n /Overlay$/, // ReactDevOverlay, ErrorOverlay\n /Handler$/, // ScrollAndFocusHandler, ErrorBoundaryHandler\n /^With[A-Z]/, // withRouter, WithAuth (HOCs)\n /Wrapper$/, // Generic wrappers\n /^Root$/, // Generic Root component\n];\n\n/**\n * Patterns that indicate likely user-defined components\n * Used as fallback in 'smart' mode\n */\nconst DEFAULT_USER_PATTERNS: RegExp[] = [\n /Page$/, // HomePage, InstallPage\n /View$/, // ListView, DetailView\n /Screen$/, // HomeScreen\n /Section$/, // HeroSection\n /Card$/, // ProductCard\n /List$/, // UserList\n /Item$/, // ListItem, MenuItem\n /Form$/, // LoginForm\n /Modal$/, // ConfirmModal\n /Dialog$/, // AlertDialog\n /Button$/, // SubmitButton (but not all buttons)\n /Nav$/, // SideNav, TopNav\n /Header$/, // PageHeader\n /Footer$/, // PageFooter\n /Layout$/, // MainLayout (careful - could be framework)\n /Panel$/, // SidePanel\n /Tab$/, // SettingsTab\n /Menu$/, // DropdownMenu\n];\n\n// =============================================================================\n// Configuration Types\n// =============================================================================\n\nexport type ReactDetectionMode = \"all\" | \"filtered\" | \"smart\";\n\nexport interface ReactDetectionConfig {\n /**\n * How many component names to collect\n * @default 3\n */\n maxComponents?: number;\n\n /**\n * Maximum fiber depth to traverse\n * @default 25\n */\n maxDepth?: number;\n\n /**\n * Detection mode:\n * - 'smart': Only show components that correlate with DOM classes (strictest, most relevant)\n * - 'filtered': Skip known framework internals (default)\n * - 'all': Show all components (no filtering)\n * @default 'filtered'\n */\n mode?: ReactDetectionMode;\n\n /**\n * Additional exact names to skip (merged with defaults in 'filtered' mode)\n */\n skipExact?: Set<string> | string[];\n\n /**\n * Additional patterns to skip (merged with defaults in 'filtered' mode)\n */\n skipPatterns?: RegExp[];\n\n /**\n * Patterns for user components (used as fallback in 'smart' mode)\n */\n userPatterns?: RegExp[];\n\n /**\n * Custom filter function for full control\n * Return true to INCLUDE the component, false to skip\n */\n filter?: (name: string, depth: number) => boolean;\n}\n\n/**\n * Resolved configuration with all defaults applied\n */\ninterface ResolvedConfig {\n maxComponents: number;\n maxDepth: number;\n mode: ReactDetectionMode;\n skipExact: Set<string>;\n skipPatterns: RegExp[];\n userPatterns: RegExp[];\n filter?: (name: string, depth: number) => boolean;\n}\n\nfunction resolveConfig(config?: ReactDetectionConfig): ResolvedConfig {\n const mode = config?.mode ?? \"filtered\";\n\n // Convert skipExact to Set if array\n let skipExact = DEFAULT_SKIP_EXACT;\n if (config?.skipExact) {\n const additional =\n config.skipExact instanceof Set\n ? config.skipExact\n : new Set(config.skipExact);\n skipExact = new Set([...DEFAULT_SKIP_EXACT, ...additional]);\n }\n\n return {\n maxComponents: config?.maxComponents ?? 6,\n maxDepth: config?.maxDepth ?? 30,\n mode,\n skipExact,\n skipPatterns: config?.skipPatterns\n ? [...DEFAULT_SKIP_PATTERNS, ...config.skipPatterns]\n : DEFAULT_SKIP_PATTERNS,\n userPatterns: config?.userPatterns ?? DEFAULT_USER_PATTERNS,\n filter: config?.filter,\n };\n}\n\n// =============================================================================\n// Filter Logic\n// =============================================================================\n\n/**\n * Normalize a component name to match CSS class conventions\n * SideNav -> side-nav, LinkComponent -> link-component\n */\nfunction normalizeComponentName(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, \"$1-$2\")\n .replace(/([A-Z])([A-Z][a-z])/g, \"$1-$2\")\n .toLowerCase();\n}\n\n/**\n * Collect CSS classes from an element and its ancestors\n */\nfunction getAncestorClasses(element: HTMLElement, maxDepth = 10): Set<string> {\n const classes = new Set<string>();\n let current: HTMLElement | null = element;\n let depth = 0;\n\n while (current && depth < maxDepth) {\n if (current.className && typeof current.className === \"string\") {\n current.className.split(/\\s+/).forEach((cls) => {\n if (cls.length > 1) {\n // Normalize: remove CSS module hashes, convert to lowercase\n const normalized = cls\n .replace(/[_][a-zA-Z0-9]{5,}.*$/, \"\")\n .toLowerCase();\n if (normalized.length > 1) {\n classes.add(normalized);\n }\n }\n });\n }\n current = current.parentElement;\n depth++;\n }\n\n return classes;\n}\n\n/**\n * Check if a component name correlates with any DOM class\n */\nfunction componentCorrelatesWithDOM(\n componentName: string,\n domClasses: Set<string>,\n): boolean {\n const normalized = normalizeComponentName(componentName);\n\n for (const cls of domClasses) {\n // Exact match: SideNav -> side-nav\n if (cls === normalized) return true;\n\n // Contains match: LinkComponent -> nav-link contains \"link\"\n // Split both by hyphens and check for word overlaps\n const componentWords = normalized.split(\"-\").filter((w) => w.length > 2);\n const classWords = cls.split(\"-\").filter((w) => w.length > 2);\n\n for (const cWord of componentWords) {\n for (const dWord of classWords) {\n if (cWord === dWord || cWord.includes(dWord) || dWord.includes(cWord)) {\n return true;\n }\n }\n }\n }\n\n return false;\n}\n\nfunction shouldIncludeComponent(\n name: string,\n depth: number,\n config: ResolvedConfig,\n domClasses?: Set<string>,\n): boolean {\n // Custom filter takes precedence\n if (config.filter) {\n return config.filter(name, depth);\n }\n\n switch (config.mode) {\n case \"all\":\n // \"all\" mode shows everything - no filtering at all\n return true;\n\n case \"filtered\":\n // \"filtered\" mode skips framework internals\n if (config.skipExact.has(name)) {\n return false;\n }\n if (config.skipPatterns.some((p) => p.test(name))) {\n return false;\n }\n return true;\n\n case \"smart\":\n // \"smart\" mode: first apply framework filters, then require DOM correlation\n if (config.skipExact.has(name)) {\n return false;\n }\n if (config.skipPatterns.some((p) => p.test(name))) {\n return false;\n }\n // Must correlate with DOM classes OR match user patterns\n if (domClasses && componentCorrelatesWithDOM(name, domClasses)) {\n return true;\n }\n if (config.userPatterns.some((p) => p.test(name))) {\n return true;\n }\n // Skip components that don't correlate - this mode is intentionally strict\n return false;\n\n default:\n return true;\n }\n}\n\n// =============================================================================\n// React Detection\n// =============================================================================\n\nlet reactDetectionCache: boolean | null = null;\n\n// Only cache for 'all' mode - filtered modes should NOT cache because:\n// 1. Filter results depend on config that may change between calls\n// 2. Cached results from before filter changes would return stale/unfiltered data\n// 3. The cache lookup happens BEFORE filtering, so old cached data bypasses filters\n// Using WeakMap allows garbage collection when elements are removed from DOM.\nconst componentCacheAll = new WeakMap<HTMLElement, ReactComponentInfo>();\n\n/**\n * Checks if React is present on the page\n */\n/**\n * Check if an element has React fiber keys\n */\nfunction hasReactFiber(element: Element): boolean {\n return Object.keys(element).some(\n (key) =>\n key.startsWith(\"__reactFiber$\") ||\n key.startsWith(\"__reactInternalInstance$\") ||\n key.startsWith(\"__reactProps$\"),\n );\n}\n\n/**\n * Checks if React is present on the page.\n * Scans common React root containers since React typically mounts\n * to #root, #app, #__next, etc. rather than document.body directly.\n */\nexport function isReactPage(): boolean {\n if (reactDetectionCache !== null) {\n return reactDetectionCache;\n }\n\n if (typeof document === \"undefined\") {\n return false;\n }\n\n // Check body first (some apps mount directly to body)\n if (document.body && hasReactFiber(document.body)) {\n reactDetectionCache = true;\n return true;\n }\n\n // Check common React root containers\n const commonRoots = [\"#root\", \"#app\", \"#__next\", \"[data-reactroot]\"];\n for (const selector of commonRoots) {\n const el = document.querySelector(selector);\n if (el && hasReactFiber(el)) {\n reactDetectionCache = true;\n return true;\n }\n }\n\n // Scan immediate children of body as fallback\n if (document.body) {\n for (const child of document.body.children) {\n if (hasReactFiber(child)) {\n reactDetectionCache = true;\n return true;\n }\n }\n }\n\n reactDetectionCache = false;\n return false;\n}\n\n// Wrapper object to allow cache clearing (WeakMap has no clear() method)\nlet componentCacheAllRef = { map: componentCacheAll };\n\n/**\n * Clears the React detection cache\n * Note: Only 'all' mode uses caching; filtered modes don't cache to avoid stale filter results\n */\nexport function clearReactDetectionCache(): void {\n reactDetectionCache = null;\n componentCacheAllRef.map = new WeakMap<HTMLElement, ReactComponentInfo>();\n}\n\nfunction getReactFiberKey(element: HTMLElement): string | null {\n const keys = Object.keys(element);\n return (\n keys.find(\n (key) =>\n key.startsWith(\"__reactFiber$\") ||\n key.startsWith(\"__reactInternalInstance$\"),\n ) || null\n );\n}\n\nfunction getFiberFromElement(element: HTMLElement): ReactFiber | null {\n const key = getReactFiberKey(element);\n if (!key) return null;\n return (element as unknown as Record<string, unknown>)[\n key\n ] as ReactFiber | null;\n}\n\nfunction getComponentNameFromType(type: ComponentType | null): string | null {\n if (!type) return null;\n if (type.displayName) return type.displayName;\n if (type.name) return type.name;\n return null;\n}\n\nfunction getComponentNameFromFiber(fiber: ReactFiber): string | null {\n const { tag, type, elementType } = fiber;\n\n // Skip DOM elements and host types\n if (\n tag === FiberTags.HostComponent ||\n tag === FiberTags.HostText ||\n tag === FiberTags.HostHoistable ||\n tag === FiberTags.HostSingleton\n ) {\n return null;\n }\n\n // Skip Fragment, Mode, Profiler, and related internal types\n if (\n tag === FiberTags.Fragment ||\n tag === FiberTags.Mode ||\n tag === FiberTags.Profiler ||\n tag === FiberTags.DehydratedFragment\n ) {\n return null;\n }\n\n // Skip React internal infrastructure types (these are internal implementation details)\n if (\n tag === FiberTags.HostRoot ||\n tag === FiberTags.HostPortal ||\n tag === FiberTags.ScopeComponent ||\n tag === FiberTags.OffscreenComponent ||\n tag === FiberTags.LegacyHiddenComponent ||\n tag === FiberTags.CacheComponent ||\n tag === FiberTags.TracingMarkerComponent ||\n tag === FiberTags.Throw ||\n tag === FiberTags.ViewTransitionComponent ||\n tag === FiberTags.ActivityComponent\n ) {\n return null;\n }\n\n // Handle ForwardRef\n if (tag === FiberTags.ForwardRef) {\n const elType = elementType as ComponentType | null;\n if (elType?.render) {\n const innerName = getComponentNameFromType(elType.render);\n if (innerName) return innerName;\n }\n if (elType?.displayName) return elType.displayName;\n return getComponentNameFromType(type as ComponentType);\n }\n\n // Handle Memo\n if (\n tag === FiberTags.MemoComponent ||\n tag === FiberTags.SimpleMemoComponent\n ) {\n const elType = elementType as ComponentType | null;\n if (elType?.type) {\n const innerName = getComponentNameFromType(elType.type);\n if (innerName) return innerName;\n }\n if (elType?.displayName) return elType.displayName;\n return getComponentNameFromType(type as ComponentType);\n }\n\n // Handle Context Provider\n if (tag === FiberTags.ContextProvider) {\n const elType = type as ComponentType | null;\n if (elType?._context?.displayName) {\n return `${elType._context.displayName}.Provider`;\n }\n return null;\n }\n\n // Handle Context Consumer\n if (tag === FiberTags.ContextConsumer) {\n const elType = type as ComponentType | null;\n if (elType?.displayName) {\n return `${elType.displayName}.Consumer`;\n }\n return null;\n }\n\n // Handle Lazy\n if (tag === FiberTags.LazyComponent) {\n const elType = elementType as ComponentType | null;\n if (elType?._status === 1 && elType._result) {\n return getComponentNameFromType(elType._result);\n }\n return null;\n }\n\n // Handle Suspense and SuspenseList\n if (\n tag === FiberTags.SuspenseComponent ||\n tag === FiberTags.SuspenseListComponent\n ) {\n return null;\n }\n\n // Handle incomplete components (error states during rendering)\n if (\n tag === FiberTags.IncompleteClassComponent ||\n tag === FiberTags.IncompleteFunctionComponent\n ) {\n // These are components that errored during rendering\n // Try to get the name anyway for debugging purposes\n return getComponentNameFromType(type as ComponentType);\n }\n\n // Function and Class components\n if (\n tag === FiberTags.FunctionComponent ||\n tag === FiberTags.ClassComponent ||\n tag === FiberTags.IndeterminateComponent\n ) {\n return getComponentNameFromType(type as ComponentType);\n }\n\n return null;\n}\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Result from React component detection\n */\nexport interface ReactComponentInfo {\n /** Full component path like \"<App> <Layout> <Button>\" */\n path: string | null;\n /** Array of component names from innermost to outermost */\n components: string[];\n}\n\n/**\n * Check if a name looks like minified/production code (single letter or very short)\n */\nfunction isMinifiedName(name: string): boolean {\n // Single letter or two letters that look like minified (e.g., \"e\", \"t\", \"Zt\")\n if (name.length <= 2) return true;\n // All lowercase short names are likely minified\n if (name.length <= 3 && name === name.toLowerCase()) return true;\n return false;\n}\n\n/**\n * Walks up the fiber tree to collect React component names\n *\n * @param element - The DOM element to start from\n * @param config - Optional configuration\n * @returns ReactComponentInfo with component path and array\n */\nexport function getReactComponentName(\n element: HTMLElement,\n config?: ReactDetectionConfig,\n): ReactComponentInfo {\n const resolved = resolveConfig(config);\n\n // Only use cache for 'all' mode - filtered modes must NOT cache because:\n // - Cache lookup happens BEFORE filtering logic runs\n // - Cached results from before filter updates would bypass new filters\n // - This was causing \"Root\", \"ErrorBoundaryHandler\" to leak through\n const useCache = resolved.mode === \"all\";\n\n if (useCache) {\n const cached = componentCacheAllRef.map.get(element);\n if (cached !== undefined) {\n return cached;\n }\n }\n\n if (!isReactPage()) {\n const result: ReactComponentInfo = { path: null, components: [] };\n if (useCache) {\n componentCacheAllRef.map.set(element, result);\n }\n return result;\n }\n\n // Collect DOM classes for smart mode\n const domClasses =\n resolved.mode === \"smart\" ? getAncestorClasses(element) : undefined;\n\n const components: string[] = [];\n\n try {\n let fiber = getFiberFromElement(element);\n let depth = 0;\n\n while (\n fiber &&\n depth < resolved.maxDepth &&\n components.length < resolved.maxComponents\n ) {\n const name = getComponentNameFromFiber(fiber);\n\n // Skip minified names and apply filter\n if (\n name &&\n !isMinifiedName(name) &&\n shouldIncludeComponent(name, depth, resolved, domClasses)\n ) {\n components.push(name);\n }\n\n fiber = fiber.return;\n depth++;\n }\n } catch {\n // Fiber structure may be corrupted or inaccessible - return empty result\n const result: ReactComponentInfo = { path: null, components: [] };\n if (useCache) {\n componentCacheAllRef.map.set(element, result);\n }\n return result;\n }\n\n if (components.length === 0) {\n const result: ReactComponentInfo = { path: null, components: [] };\n if (useCache) {\n componentCacheAllRef.map.set(element, result);\n }\n return result;\n }\n\n // Build path from outermost to innermost: <App> <Layout> <Button>\n const path = components\n .slice()\n .reverse()\n .map((c) => `<${c}>`)\n .join(\" \");\n\n const result: ReactComponentInfo = { path, components };\n if (useCache) {\n componentCacheAllRef.map.set(element, result);\n }\n return result;\n}\n","import React from \"react\";\n\n// =============================================================================\n// Source Location Detection Utilities\n// =============================================================================\n//\n// This module provides utilities for detecting React source file locations from\n// DOM elements. It works by accessing React's internal fiber tree and extracting\n// _debugSource information that's available in development builds.\n//\n// Compatibility:\n// - React 16.8+ (Hooks era)\n// - React 17.x\n// - React 18.x\n// - React 19.x (with fallbacks for changed internals)\n//\n// Limitations:\n// - Only works in development builds (production builds strip _debugSource)\n// - Requires React DevTools-style fiber access\n// - Some bundlers may strip debug info even in development\n// =============================================================================\n\n/**\n * Source location information for a React component\n */\nexport interface SourceLocation {\n /** Absolute or relative file path */\n fileName: string;\n /** Line number (1-indexed) */\n lineNumber: number;\n /** Column number (0-indexed, may be undefined) */\n columnNumber?: number;\n /** Component display name if available */\n componentName?: string;\n /** React version detected */\n reactVersion?: string;\n}\n\n/**\n * Result of source location detection\n */\nexport interface SourceLocationResult {\n /** Whether source location was found */\n found: boolean;\n /** Source location data (if found) */\n source?: SourceLocation;\n /** Multiple source candidates from probe (production fallback) */\n sourceCandidates?: SourceLocation[];\n /** Reason if not found */\n reason?: SourceLocationNotFoundReason;\n /** Whether the app appears to be a React app */\n isReactApp: boolean;\n /** Whether running in production mode */\n isProduction: boolean;\n}\n\n/**\n * Reasons why source location might not be found\n */\nexport type SourceLocationNotFoundReason =\n | \"not-react-app\"\n | \"production-build\"\n | \"no-fiber\"\n | \"no-debug-source\"\n | \"react-19-changed\"\n | \"element-not-in-react-tree\"\n | \"unknown\";\n\n/**\n * React Fiber node structure (partial, for type safety)\n * Based on React's internal FiberNode type\n */\ninterface ReactFiber {\n // Debug source info (only in development)\n _debugSource?: {\n fileName: string;\n lineNumber: number;\n columnNumber?: number;\n };\n // Owner info (React 19 may use this differently)\n _debugOwner?: ReactFiber;\n // Component type\n type?: {\n name?: string;\n displayName?: string;\n // For class components\n prototype?: {\n isReactComponent?: boolean;\n };\n } | string | null;\n // Element type for built-in elements\n elementType?: unknown;\n // Tag indicating fiber type\n tag?: number;\n // Fiber tree navigation\n return?: ReactFiber | null;\n child?: ReactFiber | null;\n sibling?: ReactFiber | null;\n // Memoized props (for context)\n memoizedProps?: Record<string, unknown>;\n // State node for class components\n stateNode?: unknown;\n}\n\n/**\n * Extended HTMLElement with React fiber properties\n */\ninterface ReactDOMElement extends HTMLElement {\n // React 16-17 fiber key\n __reactFiber$?: string;\n // React 18+ fiber key pattern\n __reactFiber?: ReactFiber;\n // React internal instance (older pattern)\n __reactInternalInstance$?: string;\n // Alternative patterns\n _reactRootContainer?: unknown;\n}\n\n// React fiber tag constants (for reference)\nconst FIBER_TAGS = {\n FunctionComponent: 0,\n ClassComponent: 1,\n IndeterminateComponent: 2,\n HostRoot: 3,\n HostPortal: 4,\n HostComponent: 5,\n HostText: 6,\n Fragment: 7,\n Mode: 8,\n ContextConsumer: 9,\n ContextProvider: 10,\n ForwardRef: 11,\n Profiler: 12,\n SuspenseComponent: 13,\n MemoComponent: 14,\n SimpleMemoComponent: 15,\n LazyComponent: 16,\n} as const;\n\n/**\n * Checks if the page appears to be running a React application\n *\n * @returns Object with detection results\n */\nexport function detectReactApp(): {\n isReact: boolean;\n version?: string;\n isProduction: boolean;\n} {\n if (typeof window === \"undefined\") {\n return { isReact: false, isProduction: true };\n }\n\n // Check for React DevTools hook (most reliable)\n const devToolsHook = (window as unknown as Record<string, unknown>).__REACT_DEVTOOLS_GLOBAL_HOOK__;\n\n if (devToolsHook && typeof devToolsHook === \"object\") {\n const hook = devToolsHook as Record<string, unknown>;\n\n // Check for renderers (React 16+)\n const renderers = hook.renderers as Map<number, { version?: string }> | undefined;\n if (renderers && renderers.size > 0) {\n // Get version from first renderer\n const firstRenderer = renderers.values().next().value;\n const version = firstRenderer?.version;\n\n // Check for production mode via lack of development tools\n const isProduction = !hook.supportsFiber;\n\n return {\n isReact: true,\n version: version || \"unknown\",\n isProduction,\n };\n }\n }\n\n // Fallback: Check for React root markers on DOM\n const hasReactRoot = document.querySelector(\"[data-reactroot]\") !== null;\n const hasReactContainer = document.getElementById(\"root\")?._reactRootContainer !== undefined;\n\n // Check for fiber keys on body's children\n const bodyChildren = document.body.children;\n let hasFiberKey = false;\n\n for (let i = 0; i < bodyChildren.length && !hasFiberKey; i++) {\n const child = bodyChildren[i];\n const keys = Object.keys(child);\n hasFiberKey = keys.some(\n (key) => key.startsWith(\"__reactFiber$\") || key.startsWith(\"__reactInternalInstance$\")\n );\n }\n\n if (hasReactRoot || hasReactContainer || hasFiberKey) {\n return {\n isReact: true,\n version: \"unknown\",\n // Assume production if we can't detect dev tools\n isProduction: !devToolsHook,\n };\n }\n\n return { isReact: false, isProduction: true };\n}\n\n/**\n * Gets the React fiber node associated with a DOM element\n *\n * @param element - DOM element to get fiber for\n * @returns React fiber node or null if not found\n */\nexport function getFiberFromElement(element: HTMLElement): ReactFiber | null {\n if (!element || typeof element !== \"object\") {\n return null;\n }\n\n const keys = Object.keys(element);\n\n // React 18+ uses __reactFiber$ prefix\n const fiberKey = keys.find((key) => key.startsWith(\"__reactFiber$\"));\n if (fiberKey) {\n return (element as unknown as Record<string, ReactFiber>)[fiberKey] || null;\n }\n\n // React 16-17 uses __reactInternalInstance$ prefix\n const instanceKey = keys.find((key) => key.startsWith(\"__reactInternalInstance$\"));\n if (instanceKey) {\n return (element as unknown as Record<string, ReactFiber>)[instanceKey] || null;\n }\n\n // React 19 may use different patterns - check for any fiber-like object\n const possibleFiberKey = keys.find((key) => {\n if (!key.startsWith(\"__react\")) return false;\n const value = (element as unknown as Record<string, unknown>)[key];\n return value && typeof value === \"object\" && \"_debugSource\" in (value as object);\n });\n\n if (possibleFiberKey) {\n return (element as unknown as Record<string, ReactFiber>)[possibleFiberKey] || null;\n }\n\n return null;\n}\n\n/**\n * Gets the display name of a React component from its fiber\n *\n * @param fiber - React fiber node\n * @returns Component name or null\n */\nfunction getComponentName(fiber: ReactFiber): string | null {\n if (!fiber.type) {\n return null;\n }\n\n // String type means host component (div, span, etc.)\n if (typeof fiber.type === \"string\") {\n return null; // We want React component names, not HTML tags\n }\n\n // Function/class component\n if (typeof fiber.type === \"object\" || typeof fiber.type === \"function\") {\n const type = fiber.type as { displayName?: string; name?: string };\n\n // Prefer displayName (set by React DevTools or manually)\n if (type.displayName) {\n return type.displayName;\n }\n\n // Fall back to function/class name\n if (type.name) {\n return type.name;\n }\n }\n\n return null;\n}\n\n/**\n * Walks up the fiber tree to find the nearest component with _debugSource\n *\n * @param fiber - Starting fiber node\n * @param maxDepth - Maximum tree depth to traverse (default: 50)\n * @returns Object with source info and component name, or null\n */\nfunction findDebugSource(\n fiber: ReactFiber,\n maxDepth = 50\n): { source: ReactFiber[\"_debugSource\"]; componentName: string | null } | null {\n let current: ReactFiber | null | undefined = fiber;\n let depth = 0;\n\n while (current && depth < maxDepth) {\n // Check current fiber for debug source\n if (current._debugSource) {\n return {\n source: current._debugSource,\n componentName: getComponentName(current),\n };\n }\n\n // Check debug owner (for components that wrap the element)\n if (current._debugOwner?._debugSource) {\n return {\n source: current._debugOwner._debugSource,\n componentName: getComponentName(current._debugOwner),\n };\n }\n\n // Move up the tree\n current = current.return;\n depth++;\n }\n\n return null;\n}\n\n/**\n * Attempts to find source location using React 19's potentially different structure\n *\n * @param fiber - Starting fiber node\n * @returns Source location info or null\n */\nfunction findDebugSourceReact19(\n fiber: ReactFiber\n): { source: ReactFiber[\"_debugSource\"]; componentName: string | null } | null {\n // React 19 may store debug info differently\n // This is a forward-compatible attempt based on React 19 RFCs\n\n let current: ReactFiber | null | undefined = fiber;\n let depth = 0;\n const maxDepth = 50;\n\n while (current && depth < maxDepth) {\n // Check for new React 19 debug patterns\n const anyFiber = current as unknown as Record<string, unknown>;\n\n // Possible React 19 locations for debug info\n const possibleSourceKeys = [\n \"_debugSource\",\n \"__source\",\n \"_source\",\n \"debugSource\",\n ];\n\n for (const key of possibleSourceKeys) {\n const source = anyFiber[key];\n if (source && typeof source === \"object\" && \"fileName\" in source) {\n return {\n source: source as ReactFiber[\"_debugSource\"],\n componentName: getComponentName(current),\n };\n }\n }\n\n // Check if debug info is in the element itself\n if (current.memoizedProps) {\n const props = current.memoizedProps as Record<string, unknown>;\n if (props.__source && typeof props.__source === \"object\") {\n const source = props.__source as { fileName?: string; lineNumber?: number };\n if (source.fileName && source.lineNumber) {\n return {\n source: {\n fileName: source.fileName,\n lineNumber: source.lineNumber,\n columnNumber: (source as { columnNumber?: number }).columnNumber,\n },\n componentName: getComponentName(current),\n };\n }\n }\n }\n\n current = current.return;\n depth++;\n }\n\n return null;\n}\n\n// =============================================================================\n// Stack-Trace Fallback for Source File Detection\n// =============================================================================\n//\n// When _debugSource is unavailable (e.g. Next.js with SWC), we fall back to\n// invoking the component function with a throwing hooks dispatcher, parsing\n// the error stack trace, and stripping bundler URL prefixes. In dev mode,\n// stack frames already contain original source paths.\n// =============================================================================\n\n/** Cache: component function → probed SourceLocation (or null if unresolvable) */\nconst sourceProbeCache = new Map<Function, SourceLocation | null>();\n\n/**\n * Extract the callable function from a fiber, handling wrappers.\n * Returns null for class components, host elements, or unrecognized types.\n */\nfunction unwrapComponentType(fiber: ReactFiber): Function | null {\n const tag = fiber.tag;\n const type = fiber.type;\n const elementType = fiber.elementType as Record<string, unknown> | null | undefined;\n\n // Host elements (div, span, etc.)\n if (typeof type === \"string\" || type == null) return null;\n\n // Class components — skip (need `new`, different lifecycle)\n if (\n typeof type === \"function\" &&\n (type as { prototype?: { isReactComponent?: boolean } }).prototype?.isReactComponent\n ) {\n return null;\n }\n\n // FunctionComponent / IndeterminateComponent\n if (\n (tag === FIBER_TAGS.FunctionComponent || tag === FIBER_TAGS.IndeterminateComponent) &&\n typeof type === \"function\"\n ) {\n return type as Function;\n }\n\n // ForwardRef\n if (tag === FIBER_TAGS.ForwardRef && elementType) {\n const render = elementType.render;\n if (typeof render === \"function\") return render as Function;\n }\n\n // Memo / SimpleMemo\n if (\n (tag === FIBER_TAGS.MemoComponent || tag === FIBER_TAGS.SimpleMemoComponent) &&\n elementType\n ) {\n const inner = elementType.type;\n if (typeof inner === \"function\") return inner as Function;\n }\n\n // Generic fallback: if type is a plain function, use it\n if (typeof type === \"function\") return type as Function;\n\n return null;\n}\n\n/**\n * Access the React hooks dispatcher from React's module internals.\n * These are properties on the `react` module export, NOT on `window`.\n * Returns get/set helpers or null if not found.\n */\nfunction getReactDispatcher(): {\n get: () => unknown;\n set: (d: unknown) => void;\n} | null {\n // Access React internals from the imported module\n const reactModule = React as unknown as Record<string, unknown>;\n\n // React 19: __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE.H\n const r19 = reactModule.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE as\n | Record<string, unknown>\n | undefined;\n if (r19 && \"H\" in r19) {\n return {\n get: () => r19.H,\n set: (d: unknown) => { r19.H = d; },\n };\n }\n\n // React 16-18: __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher.current\n const r18 = reactModule.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as\n | Record<string, unknown>\n | undefined;\n if (r18) {\n const dispatcher = r18.ReactCurrentDispatcher as\n | { current: unknown }\n | undefined;\n if (dispatcher && \"current\" in dispatcher) {\n return {\n get: () => dispatcher.current,\n set: (d: unknown) => { dispatcher.current = d; },\n };\n }\n }\n\n return null;\n}\n\n/**\n * Parse the first non-internal frame from an error stack string.\n */\nfunction parseComponentFrame(\n stack: string\n): { fileName: string; line: number; column?: number } | null {\n const lines = stack.split(\"\\n\");\n\n // Patterns to always skip\n const skipPatterns = [\n /source-location/,\n /\\/dist\\/index\\./, // Our bundled output (dist/index.mjs, dist/index.js)\n /\\/dist\\/react\\./, // Our React bundled output\n /node_modules\\//, // Any package in node_modules (dev mode)\n /react-dom/,\n /react\\.development/,\n /react\\.production/,\n /chunk-[A-Z0-9]+/i,\n /react-stack-bottom-frame/,\n /react-reconciler/,\n /scheduler/,\n /at <anonymous>:/, // Standalone anonymous frames (proxy handler, eval)\n ];\n\n // V8 format: \" at FnName (file:line:col)\" or \" at file:line:col\"\n const v8Re = /^\\s*at\\s+(?:.*?\\s+\\()?(.+?):(\\d+):(\\d+)\\)?$/;\n // WebKit/Gecko: \"FnName@file:line:col\" or \"@file:line:col\"\n const webkitRe = /^[^@]*@(.+?):(\\d+):(\\d+)$/;\n\n // Probe 스택 구조 (위에서 아래로):\n // 0: Error message\n // 1: at Object.get (proxy trap) ← 우리 코드 — skip\n // 2: at r.useCallback (React hook) ← hook 내부 — skip\n // 3: at (component code) ← 여기!\n // 4+: React internals, event handlers...\n //\n // 전략: 첫 2개 유효 프레임(proxy get + hook)을 skip하고 3번째를 반환.\n // 이유: 컴포넌트가 hook을 호출 → hook이 proxy get 호출 → Error throw\n let validCount = 0;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n // Skip frames from internal files\n if (skipPatterns.some((p) => p.test(trimmed))) continue;\n\n const match = v8Re.exec(trimmed) || webkitRe.exec(trimmed);\n if (match) {\n validCount++;\n // 첫 2개 프레임은 proxy get trap + React hook 내부 → skip\n // 3번째 프레임이 컴포넌트 코드\n if (validCount >= 3) {\n return {\n fileName: match[1],\n line: parseInt(match[2], 10),\n column: parseInt(match[3], 10),\n };\n }\n }\n }\n\n return null;\n}\n\n/**\n * Strip bundler URL prefixes from a raw source path.\n */\nfunction cleanSourcePath(rawPath: string): string {\n let path = rawPath;\n\n // 1. Strip query params and hashes\n path = path.replace(/[?#].*$/, \"\");\n\n // 2. Turbopack project prefix\n path = path.replace(/^turbopack:\\/\\/\\/\\[project\\]\\//, \"\");\n\n // 3. webpack-internal\n path = path.replace(/^webpack-internal:\\/\\/\\/\\.\\//, \"\");\n path = path.replace(/^webpack-internal:\\/\\/\\//, \"\");\n\n // 4. webpack\n path = path.replace(/^webpack:\\/\\/\\/\\.\\//, \"\");\n path = path.replace(/^webpack:\\/\\/\\//, \"\");\n\n // 5. turbopack generic\n path = path.replace(/^turbopack:\\/\\/\\//, \"\");\n\n // 6. http(s)://host:port/\n path = path.replace(/^https?:\\/\\/[^/]+\\//, \"\");\n\n // 7. file:///\n path = path.replace(/^file:\\/\\/\\//, \"/\");\n\n // 8. Webpack chunk group prefixes like (app-pages-browser)/./\n path = path.replace(/^\\([^)]+\\)\\/\\.\\//, \"\");\n\n // 9. Leading ./\n path = path.replace(/^\\.\\//, \"\");\n\n return path;\n}\n\n/**\n * Probe a single fiber's component function by invoking it with a\n * throwing hooks dispatcher and parsing the resulting error stack.\n */\nfunction probeComponentSource(fiber: ReactFiber): SourceLocation | null {\n const fn = unwrapComponentType(fiber);\n if (!fn) return null;\n\n // Check cache\n if (sourceProbeCache.has(fn)) {\n return sourceProbeCache.get(fn)!;\n }\n\n const dispatcher = getReactDispatcher();\n if (!dispatcher) {\n sourceProbeCache.set(fn, null);\n return null;\n }\n\n const original = dispatcher.get();\n let result: SourceLocation | null = null;\n\n try {\n // Install a proxy dispatcher that throws an Error (with stack) on any hook access.\n // When the component calls useState/useEffect/etc., the proxy's get trap fires,\n // creating an Error whose stack trace includes the component's source location.\n const stackCapturingDispatcher = new Proxy(\n {},\n {\n get() {\n throw new Error(\"probe\");\n },\n }\n );\n dispatcher.set(stackCapturingDispatcher);\n\n try {\n // Invoke the component — it will either:\n // 1. Call a hook → throws Error with stack (ideal case)\n // 2. Have no hooks → runs to completion (harmless, discarded), no stack to parse\n fn({});\n } catch (e) {\n // \"probe\" = our proxy dispatcher threw, or React minified error = production hook call\n if (e instanceof Error && e.stack) {\n const frame = parseComponentFrame(e.stack);\n if (frame) {\n const cleaned = cleanSourcePath(frame.fileName);\n result = {\n fileName: cleaned,\n lineNumber: frame.line,\n columnNumber: frame.column,\n componentName: getComponentName(fiber) || undefined,\n };\n }\n }\n }\n } finally {\n dispatcher.set(original);\n }\n\n sourceProbeCache.set(fn, result);\n return result;\n}\n\n/**\n * Walk the fiber tree via .return, probing each fiber for source info.\n * Returns multiple candidates — different fibers may resolve to different chunks,\n * and some chunks may only contain node_modules code.\n */\nfunction probeSourceWalk(\n fiber: ReactFiber,\n maxDepth = 15\n): SourceLocation[] {\n const results: SourceLocation[] = [];\n const seenFileNames = new Set<string>();\n let current: ReactFiber | null | undefined = fiber;\n let depth = 0;\n\n while (current && depth < maxDepth) {\n const source = probeComponentSource(current);\n if (source && !seenFileNames.has(source.fileName)) {\n seenFileNames.add(source.fileName);\n results.push(source);\n }\n\n current = current.return;\n depth++;\n }\n\n return results;\n}\n\n/**\n * Gets the source file location for a DOM element in a React application\n *\n * This function attempts to extract the source file path and line number\n * where a React component is defined. This only works in development mode\n * as production builds strip debug information.\n *\n * @param element - DOM element to get source location for\n * @returns SourceLocationResult with location info or reason for failure\n *\n * @example\n * ```ts\n * const result = getSourceLocation(element);\n * if (result.found && result.source) {\n * console.log(`${result.source.fileName}:${result.source.lineNumber}`);\n * // Output: \"/src/components/Button.tsx:42\"\n * }\n * ```\n */\nexport function getSourceLocation(element: HTMLElement): SourceLocationResult {\n // Try to get fiber directly from the element (same approach as getReactComponentName)\n // This avoids detectReactApp() whose production heuristic can give false positives\n const fiber = getFiberFromElement(element);\n\n if (!fiber) {\n return {\n found: false,\n reason: \"no-fiber\",\n isReactApp: false,\n isProduction: false,\n };\n }\n\n // Try standard React 16-18 debug source finding\n let debugInfo = findDebugSource(fiber);\n\n // If not found, try React 19 patterns\n if (!debugInfo) {\n debugInfo = findDebugSourceReact19(fiber);\n }\n\n if (debugInfo?.source) {\n return {\n found: true,\n source: {\n fileName: debugInfo.source.fileName,\n lineNumber: debugInfo.source.lineNumber,\n columnNumber: debugInfo.source.columnNumber,\n componentName: debugInfo.componentName || undefined,\n },\n isReactApp: true,\n isProduction: false,\n };\n }\n\n // Fallback: probe component via stack trace\n const probedList = probeSourceWalk(fiber);\n if (probedList.length > 0) {\n return {\n found: true,\n source: probedList[0],\n sourceCandidates: probedList,\n isReactApp: true,\n isProduction: false,\n };\n }\n\n return {\n found: false,\n reason: \"no-debug-source\",\n isReactApp: true,\n isProduction: false,\n };\n}\n\n/**\n * Formats a source location as a clickable file path string\n *\n * @param source - Source location object\n * @param format - Output format: \"vscode\" for VSCode URL, \"path\" for file:line format\n * @returns Formatted string\n *\n * @example\n * ```ts\n * formatSourceLocation(source, \"path\")\n * // Returns: \"src/components/Button.tsx:42:8\"\n *\n * formatSourceLocation(source, \"vscode\")\n * // Returns: \"vscode://file/absolute/path/src/components/Button.tsx:42:8\"\n * ```\n */\nexport function formatSourceLocation(\n source: SourceLocation,\n format: \"path\" | \"vscode\" = \"path\"\n): string {\n const { fileName, lineNumber, columnNumber } = source;\n\n // Build line:column suffix\n let location = `${fileName}:${lineNumber}`;\n if (columnNumber !== undefined) {\n location += `:${columnNumber}`;\n }\n\n if (format === \"vscode\") {\n // VSCode can open files via URL protocol\n // Assumes fileName is absolute or can be resolved\n return `vscode://file${fileName.startsWith(\"/\") ? \"\" : \"/\"}${location}`;\n }\n\n return location;\n}\n\n/**\n * Gets source locations for multiple elements at once\n *\n * @param elements - Array of DOM elements\n * @returns Array of source location results\n */\nexport function getSourceLocations(elements: HTMLElement[]): SourceLocationResult[] {\n return elements.map((element) => getSourceLocation(element));\n}\n\n/**\n * Finds the nearest React component ancestor that has source info\n *\n * Useful when clicking on a deeply nested element (like text or an icon)\n * and wanting to find the component that contains it.\n *\n * @param element - Starting DOM element\n * @param maxAncestors - Maximum DOM ancestors to check (default: 10)\n * @returns Source location result\n */\nexport function findNearestComponentSource(\n element: HTMLElement,\n maxAncestors = 10\n): SourceLocationResult {\n let current: HTMLElement | null = element;\n let depth = 0;\n\n while (current && depth < maxAncestors) {\n const result = getSourceLocation(current);\n\n // Return first successful result\n if (result.found) {\n return result;\n }\n\n // If we found fiber but no source, keep looking up DOM\n // (might find a parent component with source info)\n current = current.parentElement;\n depth++;\n }\n\n // Return result for original element (will explain why not found)\n return getSourceLocation(element);\n}\n\n/**\n * Gets all component sources in the ancestor chain\n *\n * Useful for understanding the component hierarchy.\n *\n * @param element - Starting DOM element\n * @returns Array of unique source locations from element up to root\n */\nexport function getComponentHierarchy(element: HTMLElement): SourceLocation[] {\n const fiber = getFiberFromElement(element);\n if (!fiber) {\n return [];\n }\n\n const sources: SourceLocation[] = [];\n const seenFiles = new Set<string>();\n\n let current: ReactFiber | null | undefined = fiber;\n let depth = 0;\n const maxDepth = 100;\n\n while (current && depth < maxDepth) {\n if (current._debugSource) {\n const key = `${current._debugSource.fileName}:${current._debugSource.lineNumber}`;\n\n // Avoid duplicates\n if (!seenFiles.has(key)) {\n seenFiles.add(key);\n sources.push({\n fileName: current._debugSource.fileName,\n lineNumber: current._debugSource.lineNumber,\n columnNumber: current._debugSource.columnNumber,\n componentName: getComponentName(current) || undefined,\n });\n }\n }\n\n current = current.return;\n depth++;\n }\n\n return sources;\n}\n\n/**\n * Checks if source location detection is likely to work in the current environment\n *\n * @returns Object describing support status\n */\nexport function checkSourceLocationSupport(): {\n supported: boolean;\n reason: string;\n suggestions: string[];\n} {\n const reactInfo = detectReactApp();\n\n if (!reactInfo.isReact) {\n return {\n supported: false,\n reason: \"No React application detected on this page\",\n suggestions: [\n \"Ensure you're on a page built with React\",\n \"The page may use a different framework (Vue, Angular, etc.)\",\n ],\n };\n }\n\n if (reactInfo.isProduction) {\n return {\n supported: false,\n reason: \"Production build detected - source info is stripped\",\n suggestions: [\n \"Run the application in development mode\",\n \"Set NODE_ENV=development\",\n \"Ensure your bundler includes source info in development\",\n ],\n };\n }\n\n // Check for DevTools\n const hasDevTools = typeof window !== \"undefined\" &&\n !!(window as unknown as Record<string, unknown>).__REACT_DEVTOOLS_GLOBAL_HOOK__;\n\n if (!hasDevTools) {\n return {\n supported: true,\n reason: \"Development mode detected, but React DevTools not installed\",\n suggestions: [\n \"Install React DevTools browser extension for best results\",\n \"Source detection may still work without it\",\n ],\n };\n }\n\n return {\n supported: true,\n reason: `React ${reactInfo.version || \"unknown\"} development mode detected`,\n suggestions: [],\n };\n}\n","// =============================================================================\n// @impakers/debug — DOM Screenshot Utilities\n// =============================================================================\n// html2canvas-pro 사용 (oklab/oklch/lab/lch/color-mix 네이티브 지원)\n\n/**\n * DOM 요소를 JPEG base64 이미지로 캡처\n */\nexport async function captureElement(\n el: HTMLElement,\n options: { quality?: number; maxScale?: number } = {},\n): Promise<string> {\n const { quality = 0.7, maxScale = 2 } = options;\n const html2canvas = (await import(\"html2canvas-pro\")).default;\n const canvas = await html2canvas(el, {\n useCORS: true,\n allowTaint: true,\n scale: Math.min(window.devicePixelRatio, maxScale),\n logging: false,\n });\n return canvas.toDataURL(\"image/jpeg\", quality);\n}\n\n/**\n * 전체 화면(viewport)을 JPEG base64 이미지로 캡처\n * debug UI 요소를 숨긴 상태로 캡처\n */\nexport async function captureFullPage(\n options: { quality?: number; hideSelectors?: string[] } = {},\n): Promise<string | undefined> {\n const { quality = 0.5, hideSelectors = [] } = options;\n const defaultSelectors = [\"[data-impakers-debug]\", \"[data-annotation-popup]\", \"[data-annotation-marker]\"];\n const allSelectors = [...defaultSelectors, ...hideSelectors];\n const hiddenEls = document.querySelectorAll(allSelectors.join(\", \"));\n\n try {\n hiddenEls.forEach((el) => (el as HTMLElement).style.visibility = \"hidden\");\n\n const html2canvas = (await import(\"html2canvas-pro\")).default;\n const canvas = await html2canvas(document.body, {\n useCORS: true,\n allowTaint: true,\n scale: 1,\n logging: false,\n width: window.innerWidth,\n height: window.innerHeight,\n });\n return canvas.toDataURL(\"image/jpeg\", quality);\n } catch {\n return undefined;\n } finally {\n hiddenEls.forEach((el) => (el as HTMLElement).style.visibility = \"\");\n }\n}\n","// =============================================================================\n// @impakers/debug — Environment Info Collector\n// =============================================================================\n\nimport type { FeedbackMetadata, FeedbackUser } from \"./types\";\n\n// ---------------------------------------------------------------------------\n// Console capture (에러 최근 20개, 일반 로그 최근 50개)\n// ---------------------------------------------------------------------------\n\nconst MAX_ERRORS = 20;\nconst MAX_LOGS = 50;\nconst recentConsoleErrors: string[] = [];\nconst recentConsoleLogs: { level: string; message: string; timestamp: number }[] = [];\nlet consolePatched = false;\n\nfunction formatArgs(args: unknown[]): string {\n return args.map((a) => {\n if (a instanceof Error) return `${a.message}\\n${a.stack?.split(\"\\n\").slice(0, 3).join(\"\\n\")}`;\n if (typeof a === \"object\" && a !== null) {\n try { return JSON.stringify(a).slice(0, 300); } catch { return String(a); }\n }\n return String(a);\n }).join(\" \");\n}\n\nfunction pushLog(level: string, message: string) {\n recentConsoleLogs.push({ level, message: message.slice(0, 500), timestamp: Date.now() });\n if (recentConsoleLogs.length > MAX_LOGS) recentConsoleLogs.shift();\n}\n\nfunction installConsoleCapture() {\n if (consolePatched || typeof window === \"undefined\") return;\n consolePatched = true;\n\n const originalError = console.error;\n const originalWarn = console.warn;\n const originalLog = console.log;\n\n console.error = (...args: unknown[]) => {\n const msg = formatArgs(args);\n recentConsoleErrors.push(msg.slice(0, 500));\n if (recentConsoleErrors.length > MAX_ERRORS) recentConsoleErrors.shift();\n pushLog(\"error\", msg);\n originalError.apply(console, args);\n };\n\n console.warn = (...args: unknown[]) => {\n const msg = formatArgs(args);\n recentConsoleErrors.push(`[warn] ${msg}`.slice(0, 500));\n if (recentConsoleErrors.length > MAX_ERRORS) recentConsoleErrors.shift();\n pushLog(\"warn\", msg);\n originalWarn.apply(console, args);\n };\n\n console.log = (...args: unknown[]) => {\n pushLog(\"log\", formatArgs(args));\n originalLog.apply(console, args);\n };\n\n // 글로벌 에러도 캡처\n window.addEventListener(\"error\", (e) => {\n const msg = `${e.message} (${e.filename}:${e.lineno})`;\n recentConsoleErrors.push(msg.slice(0, 500));\n if (recentConsoleErrors.length > MAX_ERRORS) recentConsoleErrors.shift();\n pushLog(\"error\", msg);\n });\n\n window.addEventListener(\"unhandledrejection\", (e) => {\n const msg = `Unhandled Promise: ${e.reason}`;\n recentConsoleErrors.push(msg.slice(0, 500));\n if (recentConsoleErrors.length > MAX_ERRORS) recentConsoleErrors.shift();\n pushLog(\"error\", msg);\n });\n}\n\n// 모듈 로드 시 바로 설치\ninstallConsoleCapture();\n\n\n// ---------------------------------------------------------------------------\n// Browser parsing\n// ---------------------------------------------------------------------------\n\nfunction parseBrowser(ua: string): string {\n const edge = ua.match(/Edg\\/(\\d+[\\d.]*)/);\n if (edge) return `Edge ${edge[1]}`;\n\n const chrome = ua.match(/Chrome\\/(\\d+[\\d.]*)/);\n if (chrome && !ua.includes(\"Edg/\") && !ua.includes(\"OPR/\")) return `Chrome ${chrome[1]}`;\n\n const firefox = ua.match(/Firefox\\/(\\d+[\\d.]*)/);\n if (firefox) return `Firefox ${firefox[1]}`;\n\n const safari = ua.match(/Version\\/(\\d+[\\d.]*).*Safari/);\n if (safari) return `Safari ${safari[1]}`;\n\n const opera = ua.match(/OPR\\/(\\d+[\\d.]*)/);\n if (opera) return `Opera ${opera[1]}`;\n\n return ua;\n}\n\n// ---------------------------------------------------------------------------\n// Cookie parsing (민감 정보 필터링)\n// ---------------------------------------------------------------------------\n\nconst SENSITIVE_COOKIE_PATTERNS = [\n /session/i, /csrf/i, /xsrf/i, /secret/i, /password/i, /key/i,\n];\n\nfunction parseCookies(): Record<string, string> {\n if (typeof document === \"undefined\") return {};\n const cookies: Record<string, string> = {};\n try {\n document.cookie.split(\";\").forEach((c) => {\n const [key, ...rest] = c.trim().split(\"=\");\n if (!key) return;\n const name = key.trim();\n // 민감 쿠키는 값 마스킹\n const isSensitive = SENSITIVE_COOKIE_PATTERNS.some((p) => p.test(name));\n cookies[name] = isSensitive ? \"[masked]\" : decodeURIComponent(rest.join(\"=\")).slice(0, 200);\n });\n } catch {\n // cookie 접근 불가\n }\n return cookies;\n}\n\n// ---------------------------------------------------------------------------\n// JWT decode (클라이언트 프로젝트의 JWT 토큰을 찾아서 claims 추출)\n// ---------------------------------------------------------------------------\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return null;\n const payload = parts[1].replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = payload + \"==\".slice(0, (4 - (payload.length % 4)) % 4);\n return JSON.parse(atob(padded));\n } catch {\n return null;\n }\n}\n\nfunction findAndDecodeJwt(): Record<string, unknown> | null {\n if (typeof window === \"undefined\") return null;\n\n // localStorage에서 JWT 찾기 (일반적인 키 패턴)\n const jwtKeys = [\"token\", \"access_token\", \"accessToken\", \"auth_token\", \"authToken\", \"jwt\", \"id_token\", \"idToken\"];\n\n for (const key of jwtKeys) {\n try {\n const val = localStorage.getItem(key);\n if (val) {\n // JSON으로 감싸져 있을 수 있음\n const unwrapped = val.startsWith('\"') ? JSON.parse(val) : val;\n const decoded = decodeJwtPayload(unwrapped);\n if (decoded) {\n // 민감 정보 제거하고 안전한 claims만 반환\n const safe: Record<string, unknown> = {};\n const safeKeys = [\"sub\", \"email\", \"name\", \"role\", \"roles\", \"org\", \"iat\", \"exp\", \"aud\", \"iss\", \"user_id\", \"user_role\"];\n for (const k of safeKeys) {\n if (k in decoded) safe[k] = decoded[k];\n }\n return Object.keys(safe).length > 0 ? safe : null;\n }\n }\n } catch {\n continue;\n }\n }\n\n // 쿠키에서도 찾기\n try {\n const cookies = document.cookie.split(\";\");\n for (const c of cookies) {\n const [, ...rest] = c.trim().split(\"=\");\n const val = rest.join(\"=\");\n const decoded = decodeJwtPayload(val);\n if (decoded && decoded.sub) {\n const safe: Record<string, unknown> = {};\n const safeKeys = [\"sub\", \"email\", \"name\", \"role\", \"roles\", \"org\", \"iat\", \"exp\"];\n for (const k of safeKeys) {\n if (k in decoded) safe[k] = decoded[k];\n }\n return Object.keys(safe).length > 0 ? safe : null;\n }\n }\n } catch {\n // ignore\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Page performance\n// ---------------------------------------------------------------------------\n\nfunction safeRound(val: number): number | undefined {\n const n = Math.round(val);\n return isNaN(n) || !isFinite(n) ? undefined : n;\n}\n\nfunction getPagePerformance(): Record<string, number> {\n if (typeof performance === \"undefined\") return {};\n const metrics: Record<string, number> = {};\n\n try {\n const nav = performance.getEntriesByType(\"navigation\")[0] as PerformanceNavigationTiming | undefined;\n if (nav) {\n const pageLoad = safeRound(nav.loadEventEnd - nav.startTime);\n const domLoaded = safeRound(nav.domContentLoadedEventEnd - nav.startTime);\n const ttfb = safeRound(nav.responseStart - nav.requestStart);\n if (pageLoad) metrics.pageLoadTime = pageLoad;\n if (domLoaded) metrics.domContentLoaded = domLoaded;\n if (ttfb) metrics.ttfb = ttfb;\n }\n\n const fcp = performance.getEntriesByName(\"first-contentful-paint\")[0];\n if (fcp) {\n const v = safeRound(fcp.startTime);\n if (v) metrics.firstContentfulPaint = v;\n }\n\n const mem = (performance as any).memory;\n if (mem) {\n const used = safeRound(mem.usedJSHeapSize / 1024 / 1024);\n const total = safeRound(mem.totalJSHeapSize / 1024 / 1024);\n if (used) metrics.usedJSHeapMB = used;\n if (total) metrics.totalJSHeapMB = total;\n }\n } catch {\n // ignore\n }\n\n return metrics;\n}\n\n// ---------------------------------------------------------------------------\n// Main collector\n// ---------------------------------------------------------------------------\n\nexport function collectMetadata(\n getUser?: () => FeedbackUser | null,\n): FeedbackMetadata {\n const metadata: FeedbackMetadata = {\n url: window.location.href,\n timestamp: new Date().toISOString(),\n browser: parseBrowser(navigator.userAgent),\n userAgent: navigator.userAgent,\n viewport: `${window.innerWidth}x${window.innerHeight}`,\n pixelRatio: window.devicePixelRatio,\n language: navigator.language,\n referrer: document.referrer,\n cookies: parseCookies(),\n jwtClaims: findAndDecodeJwt() ?? undefined,\n consoleErrors: recentConsoleErrors.length > 0 ? [...recentConsoleErrors] : undefined,\n consoleLogs: recentConsoleLogs.length > 0 ? [...recentConsoleLogs] : undefined,\n performance: getPagePerformance(),\n };\n\n if (getUser) {\n try {\n const user = getUser();\n if (user) {\n // id를 항상 string으로 강제 (숫자 id 방어)\n metadata.user = {\n ...user,\n id: String(user.id),\n name: String(user.name || \"\"),\n };\n }\n } catch {\n // ignore\n }\n }\n\n return metadata;\n}\n","import type { DebugTarget, RouteDebugContext } from \"./types\";\n\nconst NEXT_ROUTE_MANIFEST_URL = \"/_next/static/chunks/impakers-debug-route-manifest.json\";\n\ntype RouteFileKind = \"page\" | \"layout\";\n\ninterface NextRouteManifestFile {\n kind: RouteFileKind;\n file: string;\n}\n\ninterface NextRouteManifestEntry {\n route: string;\n segments: string[];\n files: NextRouteManifestFile[];\n}\n\ninterface NextRouteManifest {\n version: 1;\n entries: NextRouteManifestEntry[];\n}\n\ninterface RouteMatchResult {\n targets: DebugTarget[];\n context: RouteDebugContext;\n}\n\nlet manifestPromise: Promise<NextRouteManifest | null> | null = null;\nlet manifestFailed = false;\n\nfunction normalizePathname(pathname: string): string {\n if (!pathname || pathname === \"/\") return \"/\";\n return pathname.endsWith(\"/\") ? pathname.slice(0, -1) || \"/\" : pathname;\n}\n\nfunction splitPathname(pathname: string): string[] {\n const normalized = normalizePathname(pathname);\n if (normalized === \"/\") return [];\n return normalized\n .slice(1)\n .split(\"/\")\n .map((segment) => decodeURIComponent(segment))\n .filter(Boolean);\n}\n\nfunction isDynamicSegment(segment: string): boolean {\n return /^\\[[^\\]]+\\]$/.test(segment);\n}\n\nfunction isCatchAllSegment(segment: string): boolean {\n return /^\\[\\.\\.\\.[^\\]]+\\]$/.test(segment);\n}\n\nfunction isOptionalCatchAllSegment(segment: string): boolean {\n return /^\\[\\[\\.\\.\\.[^\\]]+\\]\\]$/.test(segment);\n}\n\nfunction scoreRouteMatch(routeSegments: string[], pathnameSegments: string[]): number | null {\n let routeIndex = 0;\n let pathIndex = 0;\n let score = 0;\n\n while (routeIndex < routeSegments.length) {\n const routeSegment = routeSegments[routeIndex];\n\n if (isOptionalCatchAllSegment(routeSegment)) {\n score += 1;\n pathIndex = pathnameSegments.length;\n routeIndex += 1;\n break;\n }\n\n if (isCatchAllSegment(routeSegment)) {\n if (pathIndex >= pathnameSegments.length) return null;\n score += 2;\n pathIndex = pathnameSegments.length;\n routeIndex += 1;\n break;\n }\n\n const pathSegment = pathnameSegments[pathIndex];\n if (pathSegment === undefined) return null;\n\n if (isDynamicSegment(routeSegment)) {\n score += 5;\n routeIndex += 1;\n pathIndex += 1;\n continue;\n }\n\n if (routeSegment !== pathSegment) return null;\n\n score += 20;\n routeIndex += 1;\n pathIndex += 1;\n }\n\n if (routeIndex !== routeSegments.length) return null;\n if (pathIndex !== pathnameSegments.length) return null;\n\n return score;\n}\n\nasync function loadNextRouteManifest(): Promise<NextRouteManifest | null> {\n if (manifestFailed) return null;\n if (manifestPromise) return manifestPromise;\n\n manifestPromise = (async () => {\n try {\n const res = await fetch(NEXT_ROUTE_MANIFEST_URL, { cache: \"force-cache\" });\n if (!res.ok) {\n manifestFailed = true;\n return null;\n }\n const json = await res.json();\n if (!json || typeof json !== \"object\" || !Array.isArray((json as NextRouteManifest).entries)) {\n manifestFailed = true;\n return null;\n }\n return json as NextRouteManifest;\n } catch {\n manifestFailed = true;\n return null;\n }\n })();\n\n return manifestPromise;\n}\n\nfunction buildRouteTargets(entry: NextRouteManifestEntry): DebugTarget[] {\n const pageTarget = entry.files.find((file) => file.kind === \"page\");\n const layoutTargets = entry.files.filter((file) => file.kind === \"layout\");\n const targets: DebugTarget[] = [];\n\n if (pageTarget) {\n targets.push({\n kind: \"route-page\",\n file: pageTarget.file,\n label: \"Current page route\",\n confidence: 1,\n reason: \"matched-current-url\",\n });\n }\n\n layoutTargets.forEach((layout, index) => {\n targets.push({\n kind: \"route-layout\",\n file: layout.file,\n label: index === layoutTargets.length - 1 ? \"Nearest layout\" : \"Ancestor layout\",\n confidence: Math.max(0.7, 0.95 - index * 0.08),\n reason: \"matched-layout-chain\",\n });\n });\n\n return targets;\n}\n\nexport async function getRouteDebugTargets(pathname?: string): Promise<RouteMatchResult | null> {\n if (typeof window === \"undefined\") return null;\n const currentPathname = pathname ?? window.location.pathname;\n\n const manifest = await loadNextRouteManifest();\n if (!manifest) return null;\n\n const pathnameSegments = splitPathname(currentPathname);\n let bestEntry: NextRouteManifestEntry | null = null;\n let bestScore = -1;\n\n for (const entry of manifest.entries) {\n const score = scoreRouteMatch(entry.segments, pathnameSegments);\n if (score === null) continue;\n if (score > bestScore) {\n bestScore = score;\n bestEntry = entry;\n }\n }\n\n if (!bestEntry) return null;\n\n return {\n targets: buildRouteTargets(bestEntry),\n context: {\n pathname: normalizePathname(currentPathname),\n matchedRoute: bestEntry.route,\n source: \"next-route-manifest\",\n },\n };\n}\n\nexport function mergeDebugTargets(...groups: Array<DebugTarget[] | undefined>): DebugTarget[] {\n const merged: DebugTarget[] = [];\n const seen = new Set<string>();\n\n groups.forEach((group) => {\n group?.forEach((target) => {\n const key = `${target.kind}:${target.file}:${target.line ?? \"\"}:${target.column ?? \"\"}`;\n if (seen.has(key)) return;\n seen.add(key);\n merged.push(target);\n });\n });\n\n return merged.sort((a, b) => b.confidence - a.confidence);\n}\n","// =============================================================================\n// @impakers/debug — API Client with Cache\n// =============================================================================\n\nimport type { FeedbackPayload, FileUploadResult } from \"./types\";\nimport { loadToken } from \"./auth\";\n\nfunction getToken(): string {\n const token = loadToken();\n if (!token) throw new Error(\"인증이 필요합니다\");\n return token;\n}\n\nasync function apiFetch(url: string, options: RequestInit = {}): Promise<Response> {\n const token = getToken();\n const res = await fetch(url, {\n ...options,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n ...options.headers,\n },\n });\n\n if (!res.ok) {\n if (res.status === 401) throw new Error(\"인증이 만료되었습니다.\");\n const err = await res.json().catch(() => ({ error: \"요청 실패\" }));\n throw new Error(err.error || err.message || \"요청 실패\");\n }\n\n return res;\n}\n\n// =============================================================================\n// Cache\n// =============================================================================\n\ninterface CacheEntry<T> {\n data: T;\n timestamp: number;\n}\n\nconst cache = new Map<string, CacheEntry<unknown>>();\nconst inflightRequests = new Map<string, Promise<unknown>>();\nconst listeners = new Map<string, Set<(data: unknown) => void>>();\nconst CACHE_TTL = 30_000; // 30초\n\nexport interface CacheReadOptions {\n staleWhileRevalidate?: boolean;\n force?: boolean;\n}\n\nexport function getFeedbacksCacheKey(url: string): string {\n return `feedbacks:${url}`;\n}\n\nexport function getAllFeedbacksCacheKey(): string {\n return \"feedbacks:__all__\";\n}\n\nexport function getCommentsCacheKey(taskId: string): string {\n return `comments:${taskId}`;\n}\n\nfunction getCached<T>(key: string): T | null {\n const entry = cache.get(key);\n if (!entry) return null;\n if (Date.now() - entry.timestamp > CACHE_TTL) {\n cache.delete(key);\n return null;\n }\n return entry.data as T;\n}\n\nfunction setCache<T>(key: string, data: T): void {\n cache.set(key, { data, timestamp: Date.now() });\n const subs = listeners.get(key);\n if (!subs) return;\n subs.forEach((listener) => listener(data));\n}\n\nfunction peekCache<T>(key: string): T | null {\n const entry = cache.get(key);\n return (entry?.data as T | undefined) ?? null;\n}\n\nfunction isCacheFresh(key: string): boolean {\n const entry = cache.get(key);\n if (!entry) return false;\n return Date.now() - entry.timestamp <= CACHE_TTL;\n}\n\nfunction getMatchingKeys(pattern: string): string[] {\n return Array.from(cache.keys()).filter((key) => key.includes(pattern));\n}\n\nfunction snapshotCaches<T>(pattern: string): Map<string, T> {\n const snapshots = new Map<string, T>();\n for (const key of getMatchingKeys(pattern)) {\n const value = peekCache<T>(key);\n if (value !== null) snapshots.set(key, value);\n }\n return snapshots;\n}\n\nfunction restoreSnapshots<T>(snapshots: Map<string, T>): void {\n snapshots.forEach((value, key) => setCache(key, value));\n}\n\nfunction mutateCache<T>(key: string, updater: (current: T | null) => T): T {\n const next = updater(peekCache<T>(key));\n setCache(key, next);\n return next;\n}\n\nfunction mutateMatchingCaches<T>(pattern: string, updater: (current: T) => T): void {\n for (const key of getMatchingKeys(pattern)) {\n const current = peekCache<T>(key);\n if (current === null) continue;\n setCache(key, updater(current));\n }\n}\n\nasync function revalidateCache<T>(key: string, fetcher: () => Promise<T>): Promise<T> {\n const existing = inflightRequests.get(key) as Promise<T> | undefined;\n if (existing) return existing;\n\n const request = (async () => {\n try {\n const data = await fetcher();\n setCache(key, data);\n return data;\n } finally {\n inflightRequests.delete(key);\n }\n })();\n\n inflightRequests.set(key, request);\n return request;\n}\n\nasync function readWithCache<T>(\n key: string,\n fetcher: () => Promise<T>,\n options: CacheReadOptions = {},\n): Promise<T> {\n const cached = peekCache<T>(key);\n if (cached !== null && !options.force) {\n if (options.staleWhileRevalidate || !isCacheFresh(key)) {\n void revalidateCache(key, fetcher);\n }\n return cached;\n }\n return revalidateCache(key, fetcher);\n}\n\nexport function subscribeCache<T>(key: string, listener: (data: T) => void): () => void {\n const subs = listeners.get(key) || new Set<(data: unknown) => void>();\n subs.add(listener as (data: unknown) => void);\n listeners.set(key, subs);\n return () => {\n const current = listeners.get(key);\n if (!current) return;\n current.delete(listener as (data: unknown) => void);\n if (current.size === 0) listeners.delete(key);\n };\n}\n\nexport function getCachedSnapshot<T>(key: string): T | null {\n return peekCache<T>(key);\n}\n\n/** 특정 키 패턴의 캐시 무효화 */\nexport function invalidateCache(pattern?: string): void {\n if (!pattern) {\n cache.clear();\n return;\n }\n for (const key of cache.keys()) {\n if (key.includes(pattern)) cache.delete(key);\n }\n}\n\n// =============================================================================\n// 피드백 제출\n// =============================================================================\n\nexport async function submitFeedback(\n endpoint: string,\n payload: FeedbackPayload & {\n feedbackUrl?: string;\n feedbackMarker?: Record<string, unknown>;\n authorName?: string;\n debugInfo?: string;\n debug_info?: string;\n },\n): Promise<{ taskId?: string; taskNumber?: number }> {\n const tempTaskId = `temp-task-${Date.now()}`;\n const feedbackUrl = payload.feedbackUrl;\n const marker = payload.feedbackMarker as FeedbackTask[\"feedbackMarker\"] | undefined;\n const previousFeedbacks = feedbackUrl\n ? peekCache<FeedbackTask[]>(getFeedbacksCacheKey(feedbackUrl)) || []\n : null;\n const previousAll = peekCache<FeedbackTask[]>(getAllFeedbacksCacheKey());\n\n const optimisticTask: FeedbackTask | null = feedbackUrl ? {\n id: tempTaskId,\n taskNumber: 0,\n title: payload.title,\n status: \"todo\",\n priority: payload.priority,\n feedbackUrl,\n feedbackMarker: marker || null,\n createdAt: new Date().toISOString(),\n commentCount: 0,\n _optimistic: true,\n } : null;\n\n if (feedbackUrl && optimisticTask) {\n setCache(getFeedbacksCacheKey(feedbackUrl), [optimisticTask, ...previousFeedbacks]);\n if (previousAll) {\n setCache(getAllFeedbacksCacheKey(), [optimisticTask, ...previousAll]);\n }\n }\n\n try {\n const res = await apiFetch(endpoint, {\n method: \"POST\",\n body: JSON.stringify(payload),\n });\n const result = await res.json().catch(() => ({}));\n\n if (feedbackUrl && optimisticTask) {\n const finalTask: FeedbackTask = {\n ...optimisticTask,\n id: result.taskId || tempTaskId,\n taskNumber: result.taskNumber || 0,\n _optimistic: false,\n };\n\n mutateCache<FeedbackTask[]>(getFeedbacksCacheKey(feedbackUrl), (current) =>\n (current || []).map((item) => (item.id === tempTaskId ? finalTask : item)),\n );\n if (previousAll) {\n mutateCache<FeedbackTask[]>(getAllFeedbacksCacheKey(), (current) =>\n (current || []).map((item) => (item.id === tempTaskId ? finalTask : item)),\n );\n }\n void revalidateFeedbacks(endpoint, feedbackUrl).catch(() => {});\n if (previousAll) void revalidateAllFeedbacks(endpoint).catch(() => {});\n }\n\n return result;\n } catch (error) {\n if (feedbackUrl && previousFeedbacks) {\n setCache(getFeedbacksCacheKey(feedbackUrl), previousFeedbacks);\n }\n if (previousAll) {\n setCache(getAllFeedbacksCacheKey(), previousAll);\n }\n throw error;\n }\n}\n\n// =============================================================================\n// 피드백 목록 조회 (캐싱)\n// =============================================================================\n\nexport interface FeedbackTask {\n id: string;\n taskNumber: number;\n title: string;\n status: string;\n priority: string;\n feedbackUrl: string;\n feedbackMarker: {\n x: number;\n y: number;\n isFixed?: boolean;\n element?: string;\n boundingBox?: { x: number; y: number; width: number; height: number };\n } | null;\n authorName?: string | null;\n createdAt: string;\n commentCount: number;\n _optimistic?: boolean;\n}\n\nexport async function fetchFeedbacks(\n endpoint: string,\n url: string,\n options: CacheReadOptions = {},\n): Promise<FeedbackTask[]> {\n const cacheKey = getFeedbacksCacheKey(url);\n return readWithCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}?url=${encodeURIComponent(url)}`);\n const data = await res.json();\n return data.tasks || [];\n }, options);\n}\n\n/** 전체 피드백 조회 (url 필터 없이 — all 탭용) */\nexport async function fetchAllFeedbacks(\n endpoint: string,\n options: CacheReadOptions = {},\n): Promise<FeedbackTask[]> {\n const cacheKey = getAllFeedbacksCacheKey();\n return readWithCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}?url=__all__`);\n const data = await res.json();\n return data.tasks || [];\n }, options);\n}\n\nexport async function revalidateFeedbacks(endpoint: string, url: string): Promise<FeedbackTask[]> {\n const cacheKey = getFeedbacksCacheKey(url);\n return revalidateCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}?url=${encodeURIComponent(url)}`);\n const data = await res.json();\n return data.tasks || [];\n });\n}\n\nexport async function revalidateAllFeedbacks(endpoint: string): Promise<FeedbackTask[]> {\n const cacheKey = getAllFeedbacksCacheKey();\n return revalidateCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}?url=__all__`);\n const data = await res.json();\n return data.tasks || [];\n });\n}\n\n// =============================================================================\n// 코멘트 목록 조회 (캐싱)\n// =============================================================================\n\nexport interface FeedbackComment {\n id: string;\n content: string;\n authorName: string;\n authorId?: string;\n imageUrl?: string;\n fileUrl?: string;\n fileName?: string;\n fileType?: string;\n fileSize?: number;\n fileSource?: \"supabase\" | \"google_drive\";\n createdAt: string;\n}\n\nexport async function fetchComments(\n endpoint: string,\n taskId: string,\n options: CacheReadOptions = {},\n): Promise<FeedbackComment[]> {\n const cacheKey = getCommentsCacheKey(taskId);\n return readWithCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}/${taskId}/comments`);\n const data = await res.json();\n return data.comments || [];\n }, options);\n}\n\nexport async function revalidateComments(\n endpoint: string,\n taskId: string,\n): Promise<FeedbackComment[]> {\n const cacheKey = getCommentsCacheKey(taskId);\n return revalidateCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}/${taskId}/comments`);\n const data = await res.json();\n return data.comments || [];\n });\n}\n\nfunction incrementCommentCount(taskId: string, delta: number): void {\n mutateMatchingCaches<FeedbackTask[]>(\"feedbacks:\", (items) =>\n items.map((item) => (\n item.id === taskId\n ? { ...item, commentCount: Math.max(0, (item.commentCount || 0) + delta) }\n : item\n )),\n );\n}\n\nfunction revalidateCachedFeedbackLists(endpoint: string): void {\n const feedbackKeys = getMatchingKeys(\"feedbacks:\");\n feedbackKeys.forEach((key) => {\n const url = key.replace(\"feedbacks:\", \"\");\n if (url === \"__all__\") {\n void revalidateAllFeedbacks(endpoint).catch(() => {});\n } else {\n void revalidateFeedbacks(endpoint, url).catch(() => {});\n }\n });\n}\n\n// =============================================================================\n// 코멘트 추가 (캐시 낙관적 업데이트)\n// =============================================================================\n\nexport async function postComment(\n endpoint: string,\n taskId: string,\n content: string,\n authorName: string,\n authorId?: string,\n screenshot?: string,\n file?: FileUploadResult,\n): Promise<FeedbackComment> {\n const tempComment: FeedbackComment = {\n id: `temp-${Date.now()}`,\n content,\n authorName,\n authorId,\n imageUrl: screenshot || undefined,\n fileUrl: file?.url,\n fileName: file?.fileName,\n fileType: file?.fileType,\n fileSize: file?.fileSize,\n fileSource: file?.fileSource,\n createdAt: new Date().toISOString(),\n };\n const cacheKey = getCommentsCacheKey(taskId);\n const previousComments = peekCache<FeedbackComment[]>(cacheKey) || [];\n const feedbackSnapshots = snapshotCaches<FeedbackTask[]>(\"feedbacks:\");\n setCache(cacheKey, [...previousComments, tempComment]);\n incrementCommentCount(taskId, 1);\n\n try {\n const res = await apiFetch(`${endpoint}/${taskId}/comments`, {\n method: \"POST\",\n body: JSON.stringify({\n content,\n authorName,\n authorId,\n screenshot,\n ...(file && {\n fileUrl: file.url,\n fileName: file.fileName,\n fileType: file.fileType,\n fileSize: file.fileSize,\n fileSource: file.fileSource,\n }),\n }),\n });\n const data = await res.json();\n const serverComment = data.comment;\n\n mutateCache<FeedbackComment[]>(cacheKey, (current) =>\n (current || []).map((comment) => (\n comment.id === tempComment.id ? serverComment : comment\n )),\n );\n void revalidateComments(endpoint, taskId);\n revalidateCachedFeedbackLists(endpoint);\n return serverComment;\n } catch (error) {\n setCache(cacheKey, previousComments);\n restoreSnapshots(feedbackSnapshots);\n throw error;\n }\n}\n\n// =============================================================================\n// 파일 업로드 (multipart/form-data)\n// =============================================================================\n\nconst MAX_FILE_SIZE = 4.5 * 1024 * 1024; // 4.5MB (Vercel limit)\n\nexport async function uploadFile(\n endpoint: string,\n file: File,\n context: \"feedback\" | \"comment\",\n taskId?: string,\n): Promise<FileUploadResult> {\n if (file.size > MAX_FILE_SIZE) {\n throw new Error(`파일 크기가 4.5MB를 초과합니다. (${(file.size / 1024 / 1024).toFixed(1)}MB)`);\n }\n\n const token = getToken();\n const formData = new FormData();\n formData.append(\"file\", file);\n formData.append(\"context\", context);\n if (taskId) formData.append(\"taskId\", taskId);\n\n const res = await fetch(`${endpoint}/upload`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n // Content-Type은 FormData가 자동 설정 (boundary 포함)\n },\n body: formData,\n });\n\n if (!res.ok) {\n if (res.status === 401) throw new Error(\"인증이 만료되었습니다.\");\n if (res.status === 413) throw new Error(\"파일 크기가 4.5MB를 초과합니다.\");\n const err = await res.json().catch(() => ({ error: \"파일 업로드 실패\" }));\n throw new Error(err.error || \"파일 업로드 실패\");\n }\n\n return res.json();\n}\n\n// =============================================================================\n// 태스크 상태 변경\n// =============================================================================\n\nexport async function updateTaskStatus(\n endpoint: string,\n taskId: string,\n status: \"todo\" | \"in_progress\" | \"done\",\n): Promise<void> {\n const snapshots = snapshotCaches<FeedbackTask[]>(\"feedbacks:\");\n mutateMatchingCaches<FeedbackTask[]>(\"feedbacks:\", (items) =>\n items.map((item) => (item.id === taskId ? { ...item, status } : item)),\n );\n\n try {\n await apiFetch(`${endpoint}/${taskId}/status`, {\n method: \"PATCH\",\n body: JSON.stringify({ status }),\n });\n revalidateCachedFeedbackLists(endpoint);\n } catch (error) {\n restoreSnapshots(snapshots);\n throw error;\n }\n}\n","// =============================================================================\n// @impakers/debug — Runtime Source Map Resolver\n// =============================================================================\n//\n// 번들된 파일의 위치(line, column)를 소스맵을 통해 원본 소스 파일 경로로 변환.\n//\n// 조건: 클라이언트 프로젝트에서 nosources-source-map 또는\n// productionBrowserSourceMaps: true 설정이 필요.\n// nosources-source-map 권장 (소스코드 노출 없이 파일 경로+라인 resolve 가능)\n//\n// 플로우:\n// 1. 번들 파일 URL + line + column 받음\n// 2. {파일}.map 을 fetch (캐싱)\n// 3. @jridgewell/trace-mapping으로 원본 위치 resolve\n//\n\nimport { AnyMap, originalPositionFor } from \"@jridgewell/trace-mapping\";\n\n// 소스맵 캐시 (URL → TraceMap)\ntype SourceMapInstance = ReturnType<typeof AnyMap>;\nconst cache = new Map<string, SourceMapInstance | null>();\n// 실패한 URL은 재시도하지 않음\nconst failedUrls = new Set<string>();\n\n/**\n * JS 파일 내의 //# sourceMappingURL= 코멘트에서 소스맵 URL을 추출\n */\nasync function getSourceMapUrlFromBundle(bundleUrl: string): Promise<string | null> {\n try {\n const res = await fetch(bundleUrl, { cache: \"force-cache\" });\n if (!res.ok) return null;\n const text = await res.text();\n // 마지막 sourceMappingURL 코멘트 찾기\n const match = text.match(/\\/\\/[#@]\\s*sourceMappingURL\\s*=\\s*(\\S+)\\s*$/m);\n if (!match) return null;\n const mapRef = match[1];\n // 절대 URL이면 그대로, 상대 경로면 번들 URL 기준으로 resolve\n if (mapRef.startsWith(\"http\")) return mapRef;\n const base = bundleUrl.substring(0, bundleUrl.lastIndexOf(\"/\") + 1);\n return base + mapRef;\n } catch {\n return null;\n }\n}\n\n/**\n * 소스맵을 fetch하고 AnyMap으로 파싱 (캐싱)\n * Turbopack에서는 JS 파일명과 .map 파일명이 다를 수 있으므로\n * {파일}.map 실패 시 JS 내 sourceMappingURL 코멘트를 파싱하여 재시도\n */\nasync function loadSourceMap(bundleUrl: string): Promise<SourceMapInstance | null> {\n if (cache.has(bundleUrl)) return cache.get(bundleUrl) ?? null;\n if (failedUrls.has(bundleUrl)) return null;\n\n // 1차: {파일}.map 시도\n const directMapUrl = bundleUrl.endsWith(\".map\") ? bundleUrl : `${bundleUrl}.map`;\n try {\n const res = await fetch(directMapUrl, { cache: \"force-cache\" });\n if (res.ok) {\n const rawMap = await res.json();\n const traceMap = new AnyMap(rawMap);\n cache.set(bundleUrl, traceMap);\n return traceMap;\n }\n } catch {\n // 1차 실패 시 폴백\n }\n\n // 2차: JS 파일에서 sourceMappingURL 추출 (Turbopack은 .js와 .map 파일명이 다름)\n const actualMapUrl = await getSourceMapUrlFromBundle(bundleUrl);\n if (actualMapUrl) {\n try {\n const res = await fetch(actualMapUrl, { cache: \"force-cache\" });\n if (res.ok) {\n const rawMap = await res.json();\n const traceMap = new AnyMap(rawMap);\n cache.set(bundleUrl, traceMap);\n return traceMap;\n }\n } catch {\n // 2차 실패\n }\n }\n\n failedUrls.add(bundleUrl);\n cache.set(bundleUrl, null);\n return null;\n}\n\n/** resolve 결과 */\nexport interface ResolvedSource {\n /** 원본 소스 파일 경로 (예: src/components/Dashboard.tsx) */\n source: string;\n /** 원본 라인 번호 */\n line: number;\n /** 원본 컬럼 번호 */\n column: number;\n /** 원본 심볼 이름 (있으면) */\n name: string | null;\n}\n\n/**\n * 번들 파일의 위치를 원본 소스 위치로 변환\n *\n * @param bundlePath - 번들 파일 경로 (예: _next/static/chunks/app-layout_abc123.js)\n * @param line - 번들 파일의 라인 번호\n * @param column - 번들 파일의 컬럼 번호\n * @returns 원본 소스 위치 또는 null\n */\nexport async function resolveSourcePosition(\n bundlePath: string,\n line: number,\n column: number,\n): Promise<ResolvedSource | null> {\n // 상대 경로를 절대 URL로 변환\n let bundleUrl: string;\n try {\n if (bundlePath.startsWith(\"http\")) {\n bundleUrl = bundlePath;\n } else {\n bundleUrl = new URL(bundlePath, window.location.origin).href;\n }\n } catch {\n return null;\n }\n\n const traceMap = await loadSourceMap(bundleUrl);\n if (!traceMap) return null;\n\n try {\n const pos = originalPositionFor(traceMap, { line, column });\n if (!pos.source) return null;\n\n // webpack:///나 turbopack:/// 접두사 제거\n let source = pos.source;\n source = source.replace(/^webpack:\\/\\/\\//, \"\");\n source = source.replace(/^turbopack:\\/\\/\\//, \"\");\n source = source.replace(/^\\[project\\]\\//, \"\");\n source = source.replace(/^\\.\\//, \"\");\n\n // node_modules 경로는 무시\n if (source.includes(\"node_modules/\")) return null;\n\n return {\n source,\n line: pos.line ?? 0,\n column: pos.column ?? 0,\n name: pos.name ?? null,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * 소스 파일 문자열 (예: \"_next/static/chunks/app_abc.js:23484:23\")을 파싱하여\n * 원본 소스 위치로 resolve\n */\nexport async function resolveSourceString(\n sourceStr: string,\n): Promise<ResolvedSource | null> {\n if (!sourceStr) return null;\n\n // \"파일:라인:컬럼\" 형식 파싱\n const match = sourceStr.match(/^(.+):(\\d+):(\\d+)$/);\n if (!match) return null;\n\n const [, filePath, lineStr, colStr] = match;\n const line = parseInt(lineStr, 10);\n const column = parseInt(colStr, 10);\n\n if (isNaN(line) || isNaN(column)) return null;\n\n return resolveSourcePosition(filePath, line, column);\n}\n\n/**\n * 소스맵 사용 가능 여부를 확인 (첫 번째 청크 파일의 .map 존재 확인)\n */\nexport async function isSourceMapAvailable(): Promise<boolean> {\n if (typeof document === \"undefined\") return false;\n\n // 페이지의 script 태그에서 첫 번째 청크 파일 찾기\n const scripts = document.querySelectorAll(\"script[src]\");\n for (const script of scripts) {\n const src = (script as HTMLScriptElement).src;\n if (src.includes(\"/chunks/\") || src.includes(\"/_next/\")) {\n try {\n const res = await fetch(`${src}.map`, { method: \"HEAD\", cache: \"force-cache\" });\n return res.ok;\n } catch {\n continue;\n }\n }\n }\n\n return false;\n}\n","\nconst css = \"@keyframes styles-module__markerIn___7B1j9 {\\n from {\\n opacity: 0;\\n transform: translate(-50%, -50%) scale(0.3);\\n }\\n to {\\n opacity: 1;\\n transform: translate(-50%, -50%) scale(1);\\n }\\n}\\n@keyframes styles-module__tooltipIn___3o7t0 {\\n from {\\n opacity: 0;\\n transform: translateX(-50%) scale(0.95);\\n }\\n to {\\n opacity: 1;\\n transform: translateX(-50%) scale(1);\\n }\\n}\\n.styles-module__marker___7PVX9 {\\n position: absolute;\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n color: white;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 11px;\\n font-weight: 700;\\n transform: translate(-50%, -50%);\\n cursor: pointer;\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), inset 0 0 0 1px rgba(255, 255, 255, 0.2);\\n user-select: none;\\n z-index: 1;\\n transition: transform 0.12s, box-shadow 0.12s;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, sans-serif;\\n}\\n.styles-module__marker___7PVX9:hover {\\n z-index: 2;\\n transform: translate(-50%, -50%) scale(1.15);\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), inset 0 0 0 1px rgba(255, 255, 255, 0.3);\\n}\\n.styles-module__marker___7PVX9.styles-module__enter___V7KfW {\\n animation: styles-module__markerIn___7B1j9 0.25s cubic-bezier(0.22, 1, 0.36, 1) forwards;\\n}\\n.styles-module__marker___7PVX9.styles-module__hovered___ojzb7 {\\n transform: translate(-50%, -50%) scale(1.15);\\n}\\n.styles-module__marker___7PVX9.styles-module__done___J6WOE {\\n opacity: 0.55;\\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15), inset 0 0 0 1px rgba(255, 255, 255, 0.1);\\n}\\n\\n.styles-module__pending___qQbOR {\\n position: fixed;\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n color: white;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n transform: translate(-50%, -50%);\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), inset 0 0 0 1px rgba(255, 255, 255, 0.2);\\n z-index: 1;\\n pointer-events: none;\\n}\\n.styles-module__pending___qQbOR.styles-module__enter___V7KfW {\\n animation: styles-module__markerIn___7B1j9 0.25s cubic-bezier(0.22, 1, 0.36, 1) forwards;\\n}\\n\\n.styles-module__markerTooltip___ns-gQ {\\n position: absolute;\\n top: calc(100% + 8px);\\n left: 50%;\\n transform: translateX(-50%);\\n background: rgba(0, 0, 0, 0.88);\\n color: #fff;\\n padding: 6px 10px;\\n border-radius: 6px;\\n font-size: 11px;\\n white-space: nowrap;\\n max-width: 200px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n pointer-events: none;\\n z-index: 10;\\n}\\n.styles-module__markerTooltip___ns-gQ.styles-module__enter___V7KfW {\\n animation: styles-module__tooltipIn___3o7t0 0.1s ease-out forwards;\\n}\\n\\n.styles-module__markerQuote___1bRQp {\\n display: block;\\n font-weight: 500;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__markerNote___3iWm4 {\\n display: block;\\n color: rgba(255, 255, 255, 0.7);\\n margin-top: 2px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\";\nconst classNames = {\"marker\":\"styles-module__marker___7PVX9\",\"enter\":\"styles-module__enter___V7KfW\",\"markerIn\":\"styles-module__markerIn___7B1j9\",\"hovered\":\"styles-module__hovered___ojzb7\",\"done\":\"styles-module__done___J6WOE\",\"pending\":\"styles-module__pending___qQbOR\",\"markerTooltip\":\"styles-module__markerTooltip___ns-gQ\",\"tooltipIn\":\"styles-module__tooltipIn___3o7t0\",\"markerQuote\":\"styles-module__markerQuote___1bRQp\",\"markerNote\":\"styles-module__markerNote___3iWm4\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-annotation-marker-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-annotation-marker-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","import { Annotation } from \"../../types\";\nimport styles from \"./styles.module.scss\";\n\n// =============================================================================\n// AnnotationMarker\n// =============================================================================\n\n/** 상태별 마커 색상 */\nconst IN_PROGRESS_MARKER_COLOR = \"#3b82f6\"; // blue\nconst DONE_MARKER_COLOR = \"#9ca3af\"; // gray\n\ntype AnnotationMarkerProps = {\n annotation: Annotation;\n layerIndex: number;\n isAnimated: boolean;\n isHovered: boolean;\n accentColor: string;\n markerClickBehavior: \"edit\" | \"delete\";\n onHover: () => void;\n onHoverEnd: () => void;\n onClick: () => void;\n onContextMenu?: () => void;\n isDeleting?: boolean;\n};\n\nexport function AnnotationMarker({\n annotation,\n layerIndex,\n isAnimated,\n isHovered,\n accentColor,\n onHover,\n onHoverEnd,\n onClick,\n}: AnnotationMarkerProps) {\n const animClass = !isAnimated ? styles.enter : \"\";\n const isDone = annotation.status === \"done\" || annotation.status === \"resolved\";\n const isInProgress = annotation.status === \"in_progress\";\n const markerColor = isDone\n ? DONE_MARKER_COLOR\n : isInProgress\n ? IN_PROGRESS_MARKER_COLOR\n : accentColor;\n\n return (\n <div\n className={`${styles.marker} ${animClass} ${isHovered ? styles.hovered : \"\"} ${isDone ? styles.done : \"\"}`}\n data-annotation-marker\n style={{\n left: `${annotation.x}%`,\n top: annotation.y,\n backgroundColor: markerColor,\n animationDelay: `${layerIndex * 20}ms`,\n }}\n onMouseEnter={onHover}\n onMouseLeave={onHoverEnd}\n onClick={(e) => {\n e.stopPropagation();\n onClick();\n }}\n >\n <span>{layerIndex + 1}</span>\n\n {isHovered && (\n <div className={`${styles.markerTooltip} ${styles.enter}`}>\n <span className={styles.markerQuote}>{annotation.element}</span>\n {annotation.comment && (\n <span className={styles.markerNote}>{annotation.comment}</span>\n )}\n </div>\n )}\n </div>\n );\n}\n\n// =============================================================================\n// PendingMarker\n// =============================================================================\n\ntype PendingMarkerProps = {\n x: number;\n y: number;\n isMultiSelect: boolean;\n accentColor: string;\n};\n\nexport function PendingMarker({ x, y, accentColor }: PendingMarkerProps) {\n return (\n <div\n className={`${styles.pending} ${styles.enter}`}\n data-annotation-marker\n style={{\n left: `${x}%`,\n top: y,\n backgroundColor: accentColor,\n }}\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </div>\n );\n}\n","\"use client\";\n\nimport { useState, useRef, useEffect, useCallback } from \"react\";\nimport { captureElement } from \"../../utils/capture-element\";\nimport styles from \"./styles.module.scss\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface CommentData {\n id: string;\n content: string;\n authorName: string;\n authorId?: string;\n imageUrl?: string;\n fileUrl?: string;\n fileName?: string;\n fileType?: string;\n fileSize?: number;\n fileSource?: string;\n createdAt: string;\n}\n\nexport interface ThreadTask {\n id: string;\n taskNumber?: number;\n title: string;\n status: string;\n feedbackMarker?: { element?: string };\n authorName?: string;\n createdAt: string;\n comments: CommentData[];\n}\n\nexport interface CommentThreadProps {\n task: ThreadTask;\n currentUserName: string;\n currentUserId?: string;\n left: number;\n top?: number;\n bottom?: number;\n onClose: () => void;\n /** content, screenshot(base64), file(비이미지 파일) */\n onReply: (taskId: string, content: string, screenshot?: string, file?: File) => void;\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nfunction formatTime(dateStr: string): string {\n const date = new Date(dateStr);\n const diff = Date.now() - date.getTime();\n const pad = (n: number) => String(n).padStart(2, \"0\");\n const abs = `${pad(date.getMonth() + 1)}.${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;\n const m = Math.floor(diff / 60000);\n if (m < 1) return `${abs} (just now)`;\n if (m < 60) return `${abs} (${m}m)`;\n const h = Math.floor(m / 60);\n if (h < 24) return `${abs} (${h}h)`;\n const d = Math.floor(h / 24);\n return `${abs} (${d}d)`;\n}\n\nfunction getInitials(name: string): string {\n return name.slice(0, 1).toUpperCase();\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nfunction getFileIcon(mimeType: string): string {\n if (mimeType.includes(\"pdf\")) return \"PDF\";\n if (mimeType.includes(\"spreadsheet\") || mimeType.includes(\"excel\") || mimeType.includes(\"csv\")) return \"XLS\";\n if (mimeType.includes(\"presentation\") || mimeType.includes(\"powerpoint\")) return \"PPT\";\n if (mimeType.includes(\"document\") || mimeType.includes(\"word\")) return \"DOC\";\n if (mimeType.includes(\"zip\") || mimeType.includes(\"compressed\") || mimeType.includes(\"archive\")) return \"ZIP\";\n if (mimeType.includes(\"video\")) return \"VID\";\n if (mimeType.includes(\"audio\")) return \"AUD\";\n return \"FILE\";\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport function CommentThread({\n task,\n currentUserName,\n currentUserId,\n left,\n top,\n bottom,\n onClose,\n onReply,\n}: CommentThreadProps) {\n const [replyText, setReplyText] = useState(\"\");\n const [exiting, setExiting] = useState(false);\n const [pendingImage, setPendingImage] = useState<string | null>(null); // base64 미리보기\n const [pendingFile, setPendingFile] = useState<File | null>(null); // 비이미지 파일\n const [capturingDom, setCapturingDom] = useState(false);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const [lightboxSrc, setLightboxSrc] = useState<string | null>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (listRef.current) listRef.current.scrollTop = listRef.current.scrollHeight;\n textareaRef.current?.focus();\n }, [task.comments.length]);\n\n // 바깥 클릭 닫기 (DOM 캡처 모드일 때는 무시)\n useEffect(() => {\n if (capturingDom) return;\n const handler = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (target.closest(`.${styles.thread}`)) return;\n if (target.closest(\"[data-annotation-marker]\")) return;\n if (target.closest(\"[data-impakers-debug]\")) return;\n handleClose();\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [capturingDom]);\n\n const handleClose = useCallback(() => {\n setExiting(true);\n setTimeout(() => onClose(), 120);\n }, [onClose]);\n\n // -------------------------------------------------------------------------\n // Send reply (with optional image)\n // -------------------------------------------------------------------------\n const handleSend = useCallback(() => {\n if (!replyText.trim() && !pendingImage && !pendingFile) return;\n onReply(task.id, replyText.trim(), pendingImage || undefined, pendingFile || undefined);\n setReplyText(\"\");\n setPendingImage(null);\n setPendingFile(null);\n }, [replyText, pendingImage, pendingFile, task.id, onReply]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n e.stopPropagation();\n if (e.nativeEvent.isComposing) return;\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n if (e.key === \"Escape\") handleClose();\n },\n [handleClose, handleSend],\n );\n\n // -------------------------------------------------------------------------\n // 카메라: DOM 선택 → 스크린샷\n // -------------------------------------------------------------------------\n const startDomCapture = useCallback(() => {\n setCapturingDom(true);\n\n // 모든 debug UI 숨기기\n const debugEls = document.querySelectorAll(\"[data-impakers-debug], [data-annotation-marker]\");\n debugEls.forEach((el) => (el as HTMLElement).style.visibility = \"hidden\");\n\n // crosshair 커서 (CSS class 방식으로 전환 — 동적 DOM에도 적용)\n document.documentElement.classList.add(\"impakers-selecting\");\n\n let hoverBox: HTMLDivElement | null = null;\n\n const showHover = (rect: DOMRect) => {\n if (!hoverBox) {\n hoverBox = document.createElement(\"div\");\n hoverBox.style.cssText = `position:fixed;border:2px solid #3b82f6;background:rgba(59,130,246,0.05);border-radius:4px;pointer-events:none;z-index:999999;transition:all 0.08s ease`;\n document.body.appendChild(hoverBox);\n }\n hoverBox.style.left = `${rect.left}px`;\n hoverBox.style.top = `${rect.top}px`;\n hoverBox.style.width = `${rect.width}px`;\n hoverBox.style.height = `${rect.height}px`;\n };\n\n const cleanup = () => {\n document.removeEventListener(\"mousemove\", handleMove);\n document.removeEventListener(\"click\", handleClick, true);\n document.removeEventListener(\"keydown\", handleEsc);\n document.documentElement.classList.remove(\"impakers-selecting\");\n hoverBox?.remove();\n debugEls.forEach((el) => (el as HTMLElement).style.visibility = \"\");\n setCapturingDom(false);\n };\n\n const handleMove = (e: MouseEvent) => {\n const el = document.elementFromPoint(e.clientX, e.clientY) as HTMLElement;\n if (!el || el === hoverBox) return;\n showHover(el.getBoundingClientRect());\n };\n\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") { cleanup(); }\n };\n\n const handleClick = async (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation(); // 다른 핸들러(dropdown 닫기 등) 차단\n\n const targetEl = document.elementFromPoint(e.clientX, e.clientY) as HTMLElement;\n cleanup();\n\n if (!targetEl) return;\n\n try {\n const base64 = await captureElement(targetEl);\n setPendingImage(base64);\n } catch (err) {\n console.error(\"[@impakers/debug] DOM 스크린샷 실패:\", err);\n }\n\n textareaRef.current?.focus();\n };\n\n document.addEventListener(\"mousemove\", handleMove);\n document.addEventListener(\"click\", handleClick, true);\n document.addEventListener(\"keydown\", handleEsc);\n }, []);\n\n const handleCameraClick = useCallback(() => {\n startDomCapture();\n }, [startDomCapture]);\n\n // -------------------------------------------------------------------------\n // + 버튼: 파일 첨부\n // -------------------------------------------------------------------------\n const handleAttachClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n const handleFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n // 4.5MB 제한 체크\n if (file.size > 4.5 * 1024 * 1024) {\n console.warn(\"[@impakers/debug] 파일 크기가 4.5MB를 초과합니다.\");\n e.target.value = \"\";\n return;\n }\n\n if (file.type.startsWith(\"image/\")) {\n // 이미지: base64 미리보기\n setPendingFile(null);\n const reader = new FileReader();\n reader.onload = () => {\n setPendingImage(reader.result as string);\n };\n reader.readAsDataURL(file);\n } else {\n // 비이미지: File 객체 보관\n setPendingImage(null);\n setPendingFile(file);\n }\n\n // input 초기화 (같은 파일 다시 선택 가능)\n e.target.value = \"\";\n }, []);\n\n // -------------------------------------------------------------------------\n // Render\n // -------------------------------------------------------------------------\n const feedbackTitle = task.title.replace(/^\\[피드백\\]\\s*/, \"\");\n\n const positionStyle: React.CSSProperties = {\n left,\n ...(top !== undefined ? { top } : {}),\n ...(bottom !== undefined ? { bottom } : {}),\n };\n\n return (\n <div\n className={`${styles.thread} ${exiting ? styles.exiting : \"\"}`}\n style={positionStyle}\n data-impakers-debug=\"\"\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header — 피드백 생성자 이름 표시 */}\n <div className={styles.header}>\n <div className={styles.avatar}>{getInitials(task.authorName || currentUserName)}</div>\n <div className={styles.headerInfo}>\n <div className={styles.headerTop}>\n <span className={styles.authorName}>{task.authorName || currentUserName}</span>\n <span className={styles.timestamp}>{formatTime(task.createdAt)}</span>\n </div>\n <div className={styles.title}>{feedbackTitle}</div>\n </div>\n <div className={styles.headerActions}>\n <button className={styles.headerAction} onClick={handleClose} title=\"닫기\" type=\"button\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Comments list */}\n {task.comments.length > 0 && (\n <>\n <div className={styles.divider} />\n <div className={styles.commentsList} ref={listRef}>\n {task.comments.map((comment) => (\n <div key={comment.id} className={styles.comment}>\n <div className={styles.avatar} style={{ width: 22, height: 22, fontSize: 10 }}>\n {getInitials(comment.authorName)}\n </div>\n <div className={styles.commentContent}>\n <div className={styles.commentTop}>\n <span className={styles.commentAuthor}>{comment.authorName}</span>\n <span className={styles.commentTime}>{formatTime(comment.createdAt)}</span>\n </div>\n {comment.content && <div className={styles.commentText}>{comment.content}</div>}\n {comment.imageUrl && comment.imageUrl !== \"loading...\" && (\n <div\n className={styles.screenshot}\n onClick={() => setLightboxSrc(comment.imageUrl!)}\n style={{ cursor: \"pointer\" }}\n >\n <img src={comment.imageUrl} alt=\"screenshot\" />\n </div>\n )}\n {comment.fileUrl && (\n <a\n className={styles.fileCard}\n href={comment.fileUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={(e) => e.stopPropagation()}\n >\n <span className={styles.fileIcon}>{getFileIcon(comment.fileType || \"\")}</span>\n <span className={styles.fileInfo}>\n <span className={styles.fileCardName}>{comment.fileName || \"파일\"}</span>\n {comment.fileSize != null && (\n <span className={styles.fileCardSize}>{formatFileSize(comment.fileSize)}</span>\n )}\n </span>\n </a>\n )}\n </div>\n </div>\n ))}\n </div>\n </>\n )}\n\n {/* 첨부 이미지 미리보기 */}\n {pendingImage && (\n <div className={styles.pendingImage}>\n <img src={pendingImage} alt=\"pending\" />\n <button className={styles.pendingRemove} onClick={() => setPendingImage(null)} type=\"button\">&times;</button>\n </div>\n )}\n\n {/* 첨부 파일 미리보기 */}\n {pendingFile && (\n <div className={styles.pendingFile}>\n <span className={styles.fileIcon}>{getFileIcon(pendingFile.type)}</span>\n <span className={styles.fileInfo}>\n <span className={styles.fileCardName}>{pendingFile.name}</span>\n <span className={styles.fileCardSize}>{formatFileSize(pendingFile.size)}</span>\n </span>\n <button className={styles.pendingRemove} onClick={() => setPendingFile(null)} type=\"button\">&times;</button>\n </div>\n )}\n\n {/* Reply input */}\n <div className={styles.replyArea}>\n <textarea\n ref={textareaRef}\n className={styles.replyInput}\n placeholder=\"Reply...\"\n value={replyText}\n onChange={(e) => {\n setReplyText(e.target.value);\n const el = e.target;\n el.style.height = \"auto\";\n el.style.height = `${Math.min(el.scrollHeight, 120)}px`;\n }}\n onKeyDown={handleKeyDown}\n rows={2}\n />\n </div>\n <div className={styles.replyToolbar}>\n {/* + 파일 첨부 */}\n <button className={styles.replyTool} onClick={handleAttachClick} type=\"button\" title=\"파일 첨부\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" /><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </button>\n {/* 카메라 (DOM 스크린샷) */}\n <button className={styles.replyTool} onClick={handleCameraClick} type=\"button\" title=\"요소 스크린샷\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14.5 4h-5L7 7H4a2 2 0 00-2 2v9a2 2 0 002 2h16a2 2 0 002-2V9a2 2 0 00-2-2h-3l-2.5-3z\" />\n <circle cx=\"12\" cy=\"13\" r=\"3\" />\n </svg>\n </button>\n {/* 전송 */}\n <button\n className={`${styles.replySend} ${(replyText.trim() || pendingImage || pendingFile) ? styles.active : \"\"}`}\n onClick={handleSend}\n disabled={!replyText.trim() && !pendingImage && !pendingFile}\n type=\"button\"\n title=\"전송\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" /><polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n </button>\n </div>\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"*/*\"\n style={{ display: \"none\" }}\n onChange={handleFileChange}\n />\n\n {/* 이미지 확대 */}\n {lightboxSrc && (\n <div className={styles.lightbox} onClick={() => setLightboxSrc(null)} data-impakers-debug=\"\">\n <img src={lightboxSrc} alt=\"enlarged\" onClick={(e) => e.stopPropagation()} />\n <button className={styles.lightboxClose} onClick={() => setLightboxSrc(null)} type=\"button\">&times;</button>\n </div>\n )}\n </div>\n );\n}\n","\nconst css = \"@keyframes styles-module__threadIn___pBTFZ {\\n from {\\n opacity: 0;\\n transform: scale(0.96) translateY(4px);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1) translateY(0);\\n }\\n}\\n@keyframes styles-module__threadOut___-ccKh {\\n from {\\n opacity: 1;\\n transform: scale(1);\\n }\\n to {\\n opacity: 0;\\n transform: scale(0.96);\\n }\\n}\\n.styles-module__thread___ua2EO {\\n position: fixed;\\n width: 340px;\\n max-height: min(480px, 100vh - 40px);\\n background: #fff;\\n border-radius: 12px;\\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);\\n z-index: 100002;\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n font-size: 13px;\\n color: #1a1a1a;\\n animation: styles-module__threadIn___pBTFZ 0.15s ease-out;\\n -webkit-font-smoothing: antialiased;\\n}\\n.styles-module__thread___ua2EO.styles-module__exiting___RIPeX {\\n animation: styles-module__threadOut___-ccKh 0.12s ease-in forwards;\\n pointer-events: none;\\n}\\n\\n.styles-module__header___GiEBq {\\n padding: 14px 16px 10px;\\n display: flex;\\n align-items: flex-start;\\n gap: 10px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__avatar___JElAd {\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n background: #16a34a;\\n color: #fff;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 11px;\\n font-weight: 600;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__headerInfo___E8809 {\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__headerTop___eDiCd {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n margin-bottom: 4px;\\n}\\n\\n.styles-module__authorName___T1BfB {\\n font-size: 13px;\\n font-weight: 600;\\n color: #1a1a1a;\\n}\\n\\n.styles-module__timestamp___WusBf {\\n font-size: 12px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__headerActions___8FsMY {\\n display: flex;\\n align-items: center;\\n gap: 2px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__headerAction___Tinmq {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #9ca3af;\\n transition: background 0.12s, color 0.12s;\\n padding: 0;\\n}\\n.styles-module__headerAction___Tinmq:hover {\\n background: #f3f4f6;\\n color: #374151;\\n}\\n.styles-module__headerAction___Tinmq svg {\\n width: 16px;\\n height: 16px;\\n}\\n\\n.styles-module__title___qkfqY {\\n font-size: 13px;\\n color: #1a1a1a;\\n line-height: 1.5;\\n word-break: break-word;\\n}\\n\\n.styles-module__commentsList___kYqAR {\\n flex: 1;\\n min-height: 0;\\n overflow-y: auto;\\n padding: 0;\\n}\\n.styles-module__commentsList___kYqAR::-webkit-scrollbar {\\n width: 4px;\\n}\\n.styles-module__commentsList___kYqAR::-webkit-scrollbar-thumb {\\n background: #d1d5db;\\n border-radius: 2px;\\n}\\n\\n.styles-module__comment___pW3IO {\\n padding: 10px 16px;\\n display: flex;\\n align-items: flex-start;\\n gap: 10px;\\n}\\n.styles-module__comment___pW3IO:hover {\\n background: #f9fafb;\\n}\\n.styles-module__comment___pW3IO:hover .styles-module__commentActions___wO0fs {\\n opacity: 1;\\n}\\n\\n.styles-module__commentHighlight___EiTmx {\\n background: #eff6ff;\\n border-left: 2px solid #3b82f6;\\n padding-left: 14px;\\n}\\n\\n.styles-module__commentContent___RObGr {\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__commentTop___BbTF3 {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n margin-bottom: 2px;\\n}\\n\\n.styles-module__commentAuthor___tBjpl {\\n font-size: 13px;\\n font-weight: 600;\\n color: #1a1a1a;\\n}\\n\\n.styles-module__commentTime___0OLrz {\\n font-size: 12px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__commentActions___wO0fs {\\n display: flex;\\n gap: 2px;\\n opacity: 0;\\n transition: opacity 0.12s;\\n}\\n\\n.styles-module__commentText___ldy2V {\\n font-size: 13px;\\n color: #374151;\\n line-height: 1.5;\\n word-break: break-word;\\n white-space: pre-wrap;\\n}\\n\\n.styles-module__screenshot___jUqau {\\n margin-top: 8px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n overflow: hidden;\\n position: relative;\\n max-width: 200px;\\n}\\n.styles-module__screenshot___jUqau img {\\n width: 100%;\\n height: auto;\\n display: block;\\n}\\n.styles-module__screenshot___jUqau .styles-module__screenshotBadge___roEqY {\\n position: absolute;\\n top: 6px;\\n right: 6px;\\n background: rgba(0, 0, 0, 0.6);\\n color: #fff;\\n font-size: 10px;\\n padding: 2px 6px;\\n border-radius: 4px;\\n font-weight: 500;\\n}\\n\\n.styles-module__fileCard___-iOro {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n margin-top: 8px;\\n padding: 8px 10px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n background: #f9fafb;\\n text-decoration: none;\\n color: inherit;\\n cursor: pointer;\\n transition: background 0.12s;\\n max-width: 200px;\\n}\\n.styles-module__fileCard___-iOro:hover {\\n background: #f3f4f6;\\n}\\n\\n.styles-module__fileIcon___dNJMT {\\n width: 32px;\\n height: 32px;\\n border-radius: 6px;\\n background: #e5e7eb;\\n color: #374151;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 10px;\\n font-weight: 700;\\n flex-shrink: 0;\\n letter-spacing: 0.5px;\\n}\\n\\n.styles-module__fileInfo___dVrLV {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n}\\n\\n.styles-module__fileCardName___SHOj- {\\n font-size: 12px;\\n font-weight: 500;\\n color: #1a1a1a;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__fileCardSize___W53JL {\\n font-size: 11px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__pendingFile___-OSRs {\\n position: relative;\\n margin: 0 16px 8px;\\n padding: 8px 10px;\\n padding-right: 30px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n background: #f9fafb;\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__divider___kDjxN {\\n height: 1px;\\n background: #f3f4f6;\\n margin: 0;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__pendingImage___gHaF3 {\\n position: relative;\\n margin: 0 16px 8px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n overflow: hidden;\\n max-height: 120px;\\n flex-shrink: 0;\\n}\\n.styles-module__pendingImage___gHaF3 img {\\n width: 100%;\\n height: auto;\\n display: block;\\n object-fit: cover;\\n max-height: 120px;\\n}\\n\\n.styles-module__pendingRemove___FRL4h {\\n position: absolute;\\n top: 4px;\\n right: 4px;\\n width: 20px;\\n height: 20px;\\n border-radius: 50%;\\n background: rgba(0, 0, 0, 0.6);\\n color: #fff;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 14px;\\n line-height: 1;\\n padding: 0;\\n}\\n.styles-module__pendingRemove___FRL4h:hover {\\n background: rgba(0, 0, 0, 0.8);\\n}\\n\\n.styles-module__replyArea___VQn9b {\\n padding: 10px 16px 8px;\\n border-top: 1px solid #f3f4f6;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__replyInput___uZNBW {\\n width: 100%;\\n border: none;\\n outline: none;\\n font-size: 13px;\\n font-family: inherit;\\n color: #1a1a1a;\\n resize: none;\\n padding: 0;\\n min-height: 36px;\\n max-height: 120px;\\n line-height: 1.55;\\n transition: height 0.1s ease;\\n}\\n.styles-module__replyInput___uZNBW::placeholder {\\n color: #9ca3af;\\n}\\n\\n.styles-module__replyToolbar___fTFJU {\\n display: flex;\\n align-items: center;\\n padding: 4px 16px 10px;\\n gap: 4px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__replyTool___Ho-Rx {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #9ca3af;\\n transition: background 0.12s, color 0.12s;\\n padding: 0;\\n}\\n.styles-module__replyTool___Ho-Rx:hover {\\n background: #f3f4f6;\\n color: #374151;\\n}\\n.styles-module__replyTool___Ho-Rx svg {\\n width: 16px;\\n height: 16px;\\n}\\n\\n.styles-module__replySend___e0VSb {\\n margin-left: auto;\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #9ca3af;\\n transition: background 0.12s, color 0.12s;\\n padding: 0;\\n}\\n.styles-module__replySend___e0VSb:hover {\\n color: #3b82f6;\\n}\\n.styles-module__replySend___e0VSb.styles-module__active___R--Jj {\\n color: #3b82f6;\\n}\\n.styles-module__replySend___e0VSb svg {\\n width: 16px;\\n height: 16px;\\n}\\n\\n.styles-module__empty___XXGiw {\\n padding: 24px 16px;\\n text-align: center;\\n color: #9ca3af;\\n font-size: 13px;\\n}\\n\\n.styles-module__statusBadge___el8ml {\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n font-size: 11px;\\n font-weight: 500;\\n padding: 2px 8px;\\n border-radius: 10px;\\n margin-left: auto;\\n}\\n.styles-module__statusBadge___el8ml.styles-module__todo___rUWBr {\\n background: #fef3c7;\\n color: #92400e;\\n}\\n.styles-module__statusBadge___el8ml.styles-module__inProgress___HEWgU {\\n background: #dbeafe;\\n color: #1e40af;\\n}\\n.styles-module__statusBadge___el8ml.styles-module__done___zC12n {\\n background: #dcfce7;\\n color: #166534;\\n}\\n\\n.styles-module__lightbox___KoWEF {\\n position: fixed;\\n inset: 0;\\n z-index: 2147483647;\\n background: rgba(0, 0, 0, 0.8);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n cursor: zoom-out;\\n}\\n.styles-module__lightbox___KoWEF img {\\n max-width: 90vw;\\n max-height: 90vh;\\n border-radius: 8px;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\\n cursor: default;\\n}\\n\\n.styles-module__lightboxClose___tGZlm {\\n position: absolute;\\n top: 16px;\\n right: 16px;\\n width: 36px;\\n height: 36px;\\n border-radius: 50%;\\n background: rgba(255, 255, 255, 0.15);\\n color: #fff;\\n border: none;\\n cursor: pointer;\\n font-size: 20px;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.styles-module__lightboxClose___tGZlm:hover {\\n background: rgba(255, 255, 255, 0.25);\\n}\";\nconst classNames = {\"thread\":\"styles-module__thread___ua2EO\",\"threadIn\":\"styles-module__threadIn___pBTFZ\",\"exiting\":\"styles-module__exiting___RIPeX\",\"threadOut\":\"styles-module__threadOut___-ccKh\",\"header\":\"styles-module__header___GiEBq\",\"avatar\":\"styles-module__avatar___JElAd\",\"headerInfo\":\"styles-module__headerInfo___E8809\",\"headerTop\":\"styles-module__headerTop___eDiCd\",\"authorName\":\"styles-module__authorName___T1BfB\",\"timestamp\":\"styles-module__timestamp___WusBf\",\"headerActions\":\"styles-module__headerActions___8FsMY\",\"headerAction\":\"styles-module__headerAction___Tinmq\",\"title\":\"styles-module__title___qkfqY\",\"commentsList\":\"styles-module__commentsList___kYqAR\",\"comment\":\"styles-module__comment___pW3IO\",\"commentActions\":\"styles-module__commentActions___wO0fs\",\"commentHighlight\":\"styles-module__commentHighlight___EiTmx\",\"commentContent\":\"styles-module__commentContent___RObGr\",\"commentTop\":\"styles-module__commentTop___BbTF3\",\"commentAuthor\":\"styles-module__commentAuthor___tBjpl\",\"commentTime\":\"styles-module__commentTime___0OLrz\",\"commentText\":\"styles-module__commentText___ldy2V\",\"screenshot\":\"styles-module__screenshot___jUqau\",\"screenshotBadge\":\"styles-module__screenshotBadge___roEqY\",\"fileCard\":\"styles-module__fileCard___-iOro\",\"fileIcon\":\"styles-module__fileIcon___dNJMT\",\"fileInfo\":\"styles-module__fileInfo___dVrLV\",\"fileCardName\":\"styles-module__fileCardName___SHOj-\",\"fileCardSize\":\"styles-module__fileCardSize___W53JL\",\"pendingFile\":\"styles-module__pendingFile___-OSRs\",\"divider\":\"styles-module__divider___kDjxN\",\"pendingImage\":\"styles-module__pendingImage___gHaF3\",\"pendingRemove\":\"styles-module__pendingRemove___FRL4h\",\"replyArea\":\"styles-module__replyArea___VQn9b\",\"replyInput\":\"styles-module__replyInput___uZNBW\",\"replyToolbar\":\"styles-module__replyToolbar___fTFJU\",\"replyTool\":\"styles-module__replyTool___Ho-Rx\",\"replySend\":\"styles-module__replySend___e0VSb\",\"active\":\"styles-module__active___R--Jj\",\"empty\":\"styles-module__empty___XXGiw\",\"statusBadge\":\"styles-module__statusBadge___el8ml\",\"todo\":\"styles-module__todo___rUWBr\",\"inProgress\":\"styles-module__inProgress___HEWgU\",\"done\":\"styles-module__done___zC12n\",\"lightbox\":\"styles-module__lightbox___KoWEF\",\"lightboxClose\":\"styles-module__lightboxClose___tGZlm\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-comment-thread-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-comment-thread-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\"use client\";\n\nimport { useState, useRef, useCallback, useEffect } from \"react\";\nimport styles from \"./styles.module.scss\";\n\nexport interface FabMenuItem {\n id: string;\n icon: React.ReactNode;\n label: string;\n badge?: number;\n active?: boolean;\n}\n\nexport interface FabMenuProps {\n items: FabMenuItem[];\n onSelect: (id: string) => void;\n onHide?: () => void;\n /** FAB 더블클릭/더블탭 시 호출 (피드백 모드 바로 진입) */\n onDoubleTap?: () => void;\n}\n\nexport function FabMenu({ items, onSelect, onHide, onDoubleTap }: FabMenuProps) {\n const [expanded, setExpanded] = useState(false);\n const [closing, setClosing] = useState(false);\n const [position, setPosition] = useState({ right: 24, bottom: 24 });\n const [showContextMenu, setShowContextMenu] = useState<{ x: number; y: number } | null>(null);\n\n const fabRef = useRef<HTMLButtonElement>(null);\n const dragging = useRef(false);\n const dragStart = useRef({ x: 0, y: 0 });\n const dragOffset = useRef({ x: 0, y: 0 });\n const hasMoved = useRef(false);\n const lastTapTime = useRef(0);\n\n // Drag\n const handleFabPointerDown = useCallback((e: React.PointerEvent) => {\n if (e.button === 2) return;\n dragging.current = true;\n hasMoved.current = false;\n const btn = fabRef.current;\n if (!btn) return;\n btn.setPointerCapture(e.pointerId);\n const rect = btn.getBoundingClientRect();\n dragStart.current = { x: e.clientX, y: e.clientY };\n dragOffset.current = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n }, []);\n\n const handleFabPointerMove = useCallback((e: React.PointerEvent) => {\n if (!dragging.current) return;\n if (Math.abs(e.clientX - dragStart.current.x) > 3 || Math.abs(e.clientY - dragStart.current.y) > 3) {\n hasMoved.current = true;\n }\n if (!hasMoved.current) return;\n setPosition({\n right: Math.max(8, Math.min(window.innerWidth - e.clientX - (44 - dragOffset.current.x), window.innerWidth - 52)),\n bottom: Math.max(8, Math.min(window.innerHeight - e.clientY - (44 - dragOffset.current.y), window.innerHeight - 52)),\n });\n }, []);\n\n const handleFabPointerUp = useCallback((e: React.PointerEvent) => {\n if (!dragging.current) return;\n fabRef.current?.releasePointerCapture(e.pointerId);\n dragging.current = false;\n if (!hasMoved.current) {\n const now = Date.now();\n const isDoubleTap = now - lastTapTime.current < 350;\n lastTapTime.current = now;\n\n if (isDoubleTap && onDoubleTap) {\n // 더블탭 → 바로 피드백 모드 진입\n if (expanded) closeMenu();\n onDoubleTap();\n return;\n }\n\n if (expanded) {\n closeMenu();\n } else {\n setExpanded(true);\n }\n }\n }, [expanded, onDoubleTap]);\n\n const closeMenu = useCallback(() => {\n setClosing(true);\n setTimeout(() => { setExpanded(false); setClosing(false); }, 150);\n }, []);\n\n // Context menu\n const handleContextMenu = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setShowContextMenu({ x: e.clientX, y: e.clientY });\n }, []);\n\n // Outside click\n useEffect(() => {\n if (!expanded && !showContextMenu) return;\n const handler = (e: MouseEvent) => {\n if ((e.target as HTMLElement).closest(\"[data-impakers-fab]\")) return;\n if (showContextMenu) { setShowContextMenu(null); return; }\n if (expanded) closeMenu();\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [expanded, showContextMenu, closeMenu]);\n\n return (\n <>\n {/* 메뉴 아이템 — FAB 위에 고정 위치 */}\n {(expanded || closing) && (\n <div\n className={styles.menuItems}\n style={{\n position: \"fixed\",\n right: position.right + (44 - 40) / 2, // 메뉴(40px)를 FAB(44px) 가운데 정렬\n bottom: position.bottom + 44 + 8, // FAB 위로 8px gap\n }}\n data-impakers-debug=\"\"\n data-impakers-fab=\"\"\n >\n {[...items].reverse().map((item, i) => (\n <button\n key={item.id}\n className={`${styles.menuItem} ${item.active ? styles.active : \"\"} ${closing ? styles.menuItemClosing : \"\"}`}\n style={{ animationDelay: closing ? `${i * 30}ms` : `${(items.length - 1 - i) * 40}ms` }}\n onClick={(e) => { e.stopPropagation(); onSelect(item.id); closeMenu(); }}\n type=\"button\"\n data-impakers-fab=\"\"\n data-impakers-debug=\"\"\n >\n {item.icon}\n <span className={styles.tooltip}>{item.label}</span>\n {item.badge && item.badge > 0 ? (\n <span className={styles.badge}>{item.badge > 99 ? \"99+\" : item.badge}</span>\n ) : null}\n </button>\n ))}\n </div>\n )}\n\n {/* Main FAB — 항상 같은 위치 */}\n <button\n ref={fabRef}\n className={`${styles.fab} ${expanded ? styles.expanded : \"\"}`}\n style={{ position: \"fixed\", right: position.right, bottom: position.bottom }}\n onPointerDown={handleFabPointerDown}\n onPointerMove={handleFabPointerMove}\n onPointerUp={handleFabPointerUp}\n onContextMenu={handleContextMenu}\n type=\"button\"\n aria-label=\"피드백 메뉴\"\n data-impakers-debug=\"\"\n data-impakers-fab=\"\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </button>\n\n {/* Context menu */}\n {showContextMenu && (\n <div\n style={{ position: \"fixed\", inset: 0, zIndex: 2147483647 }}\n onMouseDown={() => setShowContextMenu(null)}\n data-impakers-debug=\"\"\n data-impakers-fab=\"\"\n >\n <div\n className={styles.contextMenu}\n style={{ position: \"fixed\", left: showContextMenu.x, top: showContextMenu.y, zIndex: 2147483647 }}\n onMouseDown={(e) => e.stopPropagation()}\n data-impakers-fab=\"\"\n >\n <button\n className={styles.contextMenuItem}\n onMouseDown={(e) => { e.stopPropagation(); setShowContextMenu(null); onHide?.(); }}\n type=\"button\"\n >\n 위젯 숨기기\n </button>\n </div>\n </div>\n )}\n </>\n );\n}\n","\nconst css = \"@keyframes styles-module__fabEnter___DMJoo {\\n from {\\n opacity: 0;\\n transform: scale(0.5);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n@keyframes styles-module__menuItemIn___GfmJ3 {\\n from {\\n opacity: 0;\\n transform: scale(0.3);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n@keyframes styles-module__menuItemOut___s0nQD {\\n from {\\n opacity: 1;\\n transform: scale(1);\\n }\\n to {\\n opacity: 0;\\n transform: scale(0.3);\\n }\\n}\\n.styles-module__fab___wShP- {\\n touch-action: none;\\n z-index: 99999;\\n width: 44px;\\n height: 44px;\\n border-radius: 50%;\\n background: #18181b;\\n color: white;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1);\\n transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;\\n animation: styles-module__fabEnter___DMJoo 0.3s cubic-bezier(0.22, 1, 0.36, 1);\\n position: relative;\\n}\\n.styles-module__fab___wShP- svg {\\n width: 20px;\\n height: 20px;\\n transition: transform 0.2s ease;\\n}\\n.styles-module__fab___wShP-:hover {\\n transform: scale(1.08);\\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2), 0 2px 4px rgba(0, 0, 0, 0.12);\\n}\\n.styles-module__fab___wShP-:active {\\n transform: scale(0.96);\\n}\\n.styles-module__fab___wShP-.styles-module__expanded___qyto6 svg {\\n transform: rotate(45deg);\\n}\\n\\n.styles-module__menuItems___1qNsE {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 8px;\\n z-index: 99999;\\n}\\n\\n.styles-module__menuItem___pB75H {\\n width: 40px;\\n height: 40px;\\n border-radius: 50%;\\n background: #fff;\\n color: #374151;\\n border: 1px solid #e5e7eb;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);\\n transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease, border-color 0.12s ease;\\n position: relative;\\n}\\n.styles-module__menuItem___pB75H svg {\\n width: 18px;\\n height: 18px;\\n}\\n.styles-module__menuItem___pB75H:hover {\\n transform: scale(1.08);\\n background: #f9fafb;\\n border-color: #d1d5db;\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\\n}\\n.styles-module__menuItem___pB75H:active {\\n transform: scale(0.96);\\n}\\n.styles-module__menuItem___pB75H.styles-module__active___7ktmc {\\n background: #18181b;\\n color: #fff;\\n border-color: #18181b;\\n}\\n\\n.styles-module__menuItem___pB75H:nth-child(1) {\\n animation: styles-module__menuItemIn___GfmJ3 0.15s cubic-bezier(0.22, 1, 0.36, 1) 0ms both;\\n}\\n\\n.styles-module__menuItem___pB75H:nth-child(2) {\\n animation: styles-module__menuItemIn___GfmJ3 0.15s cubic-bezier(0.22, 1, 0.36, 1) 40ms both;\\n}\\n\\n.styles-module__menuItem___pB75H:nth-child(3) {\\n animation: styles-module__menuItemIn___GfmJ3 0.15s cubic-bezier(0.22, 1, 0.36, 1) 80ms both;\\n}\\n\\n.styles-module__menuItem___pB75H:nth-child(4) {\\n animation: styles-module__menuItemIn___GfmJ3 0.15s cubic-bezier(0.22, 1, 0.36, 1) 120ms both;\\n}\\n\\n.styles-module__menuItemClosing___m4o-a:nth-child(1) {\\n animation: styles-module__menuItemOut___s0nQD 0.1s ease-in 40ms both;\\n}\\n\\n.styles-module__menuItemClosing___m4o-a:nth-child(2) {\\n animation: styles-module__menuItemOut___s0nQD 0.1s ease-in 0ms both;\\n}\\n\\n.styles-module__tooltip___Cy6kg {\\n position: absolute;\\n right: calc(100% + 10px);\\n white-space: nowrap;\\n background: rgba(0, 0, 0, 0.85);\\n color: #fff;\\n font-size: 12px;\\n font-weight: 500;\\n padding: 5px 10px;\\n border-radius: 6px;\\n pointer-events: none;\\n opacity: 0;\\n transition: opacity 0.12s ease;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n}\\n\\n.styles-module__menuItem___pB75H:hover .styles-module__tooltip___Cy6kg {\\n opacity: 1;\\n}\\n\\n.styles-module__contextMenu___A8fQt {\\n background: white;\\n border-radius: 8px;\\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.16), 0 1px 4px rgba(0, 0, 0, 0.08);\\n padding: 4px;\\n min-width: 140px;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n animation: styles-module__menuItemIn___GfmJ3 0.1s ease-out;\\n}\\n\\n.styles-module__contextMenuItem___1u9io {\\n display: block;\\n width: 100%;\\n padding: 8px 12px;\\n border: none;\\n background: none;\\n font-size: 13px;\\n color: #18181b;\\n text-align: left;\\n cursor: pointer;\\n border-radius: 6px;\\n font-family: inherit;\\n}\\n.styles-module__contextMenuItem___1u9io:hover {\\n background: #f4f4f5;\\n}\\n\\n.styles-module__badge___zmiZx {\\n position: absolute;\\n top: -4px;\\n right: -4px;\\n min-width: 16px;\\n height: 16px;\\n border-radius: 8px;\\n background: #ef4444;\\n color: #fff;\\n font-size: 10px;\\n font-weight: 600;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 0 4px;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n}\";\nconst classNames = {\"fab\":\"styles-module__fab___wShP-\",\"fabEnter\":\"styles-module__fabEnter___DMJoo\",\"expanded\":\"styles-module__expanded___qyto6\",\"menuItems\":\"styles-module__menuItems___1qNsE\",\"menuItem\":\"styles-module__menuItem___pB75H\",\"active\":\"styles-module__active___7ktmc\",\"menuItemIn\":\"styles-module__menuItemIn___GfmJ3\",\"menuItemClosing\":\"styles-module__menuItemClosing___m4o-a\",\"menuItemOut\":\"styles-module__menuItemOut___s0nQD\",\"tooltip\":\"styles-module__tooltip___Cy6kg\",\"contextMenu\":\"styles-module__contextMenu___A8fQt\",\"contextMenuItem\":\"styles-module__contextMenuItem___1u9io\",\"badge\":\"styles-module__badge___zmiZx\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-fab-menu-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-fab-menu-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\"use client\";\n\nimport { useState, useCallback, useEffect, useRef } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n fetchComments,\n postComment,\n getCachedSnapshot,\n subscribeCache,\n getCommentsCacheKey,\n type FeedbackComment,\n} from \"../../core/api\";\nimport styles from \"./styles.module.scss\";\n\n// 이미지 확대 모달\nfunction ImageLightbox({ src, onClose }: { src: string; onClose: () => void }) {\n useEffect(() => {\n const handler = (e: KeyboardEvent) => { if (e.key === \"Escape\") onClose(); };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [onClose]);\n\n return (\n <div className={styles.lightbox} onClick={onClose} data-impakers-debug=\"\">\n <img src={src} alt=\"enlarged\" onClick={(e) => e.stopPropagation()} />\n <button className={styles.lightboxClose} onClick={onClose} type=\"button\">&times;</button>\n </div>\n );\n}\n\n// =============================================================================\n// File preview helpers\n// =============================================================================\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nfunction getFileIcon(mimeType: string): string {\n if (mimeType.includes(\"pdf\")) return \"PDF\";\n if (mimeType.includes(\"spreadsheet\") || mimeType.includes(\"excel\") || mimeType.includes(\"csv\")) return \"XLS\";\n if (mimeType.includes(\"presentation\") || mimeType.includes(\"powerpoint\")) return \"PPT\";\n if (mimeType.includes(\"document\") || mimeType.includes(\"word\")) return \"DOC\";\n if (mimeType.includes(\"zip\") || mimeType.includes(\"compressed\") || mimeType.includes(\"archive\")) return \"ZIP\";\n if (mimeType.includes(\"video\")) return \"VID\";\n if (mimeType.includes(\"audio\")) return \"AUD\";\n return \"FILE\";\n}\n\n/** Google Drive URL에서 file ID 추출 */\nfunction extractDriveFileId(url: string): string | null {\n const match = url.match(/\\/d\\/([^/]+)/);\n return match ? match[1] : null;\n}\n\n/** 파일 타입에 따라 프리뷰 가능한 iframe src 반환 */\nfunction getPreviewSrc(fileUrl: string, fileType: string, fileSource?: string): string | null {\n // Office 파일 → Microsoft Office Online Viewer (공개 URL 필요)\n const isOffice = /\\.(pptx?|xlsx?|docx?)$/i.test(fileUrl) ||\n fileType.includes(\"presentation\") || fileType.includes(\"powerpoint\") ||\n fileType.includes(\"spreadsheet\") || fileType.includes(\"excel\") ||\n fileType.includes(\"document\") || fileType.includes(\"word\") || fileType.includes(\"msword\");\n\n if (fileSource === \"google_drive\") {\n const fileId = extractDriveFileId(fileUrl);\n if (fileId) return `https://drive.google.com/file/d/${fileId}/preview`;\n }\n\n if (isOffice && fileSource !== \"google_drive\") {\n return `https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(fileUrl)}`;\n }\n\n // PDF → 브라우저 내장\n if (fileType.includes(\"pdf\")) return fileUrl;\n\n return null;\n}\n\n// 파일 프리뷰 모달\nfunction FilePreviewModal({\n fileUrl, fileName, fileType, fileSource, onClose,\n}: {\n fileUrl: string; fileName: string; fileType: string; fileSource?: string; onClose: () => void;\n}) {\n useEffect(() => {\n const handler = (e: KeyboardEvent) => { if (e.key === \"Escape\") onClose(); };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [onClose]);\n\n const previewSrc = getPreviewSrc(fileUrl, fileType, fileSource);\n\n return (\n <div className={styles.filePreviewOverlay} onClick={onClose} data-impakers-debug=\"\">\n <div className={styles.filePreviewModal} onClick={(e) => e.stopPropagation()}>\n <div className={styles.filePreviewHeader}>\n <span className={styles.filePreviewName}>{fileName}</span>\n <div className={styles.filePreviewActions}>\n <a href={fileUrl} target=\"_blank\" rel=\"noopener noreferrer\" className={styles.filePreviewOpen}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"14\" height=\"14\">\n <path d=\"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n 열기\n </a>\n <button className={styles.filePreviewClose} onClick={onClose} type=\"button\">&times;</button>\n </div>\n </div>\n <div className={styles.filePreviewBody}>\n {previewSrc ? (\n <iframe src={previewSrc} className={styles.filePreviewIframe} title={fileName} />\n ) : (\n <div className={styles.filePreviewFallback}>\n <span className={styles.filePreviewFallbackIcon}>{getFileIcon(fileType)}</span>\n <span>미리보기를 지원하지 않는 파일 형식입니다</span>\n <a href={fileUrl} target=\"_blank\" rel=\"noopener noreferrer\">파일 열기</a>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface InboxItem {\n id: string;\n title: string;\n status: string;\n priority: string;\n authorName: string;\n feedbackUrl: string;\n createdAt: string;\n commentCount: number;\n screenshot?: string;\n}\n\nexport interface InboxPanelProps {\n pageItems: InboxItem[];\n allItems: InboxItem[];\n currentPath: string;\n serviceName?: string;\n endpoint: string;\n currentUserName: string;\n currentUserId?: string;\n onClose: () => void;\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nfunction formatTime(dateStr: string): string {\n const date = new Date(dateStr);\n const diff = Date.now() - date.getTime();\n const pad = (n: number) => String(n).padStart(2, \"0\");\n const abs = `${pad(date.getMonth() + 1)}.${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;\n const m = Math.floor(diff / 60000);\n if (m < 1) return `${abs} (just now)`;\n if (m < 60) return `${abs} (${m}m)`;\n const h = Math.floor(m / 60);\n if (h < 24) return `${abs} (${h}h)`;\n const d = Math.floor(h / 24);\n return `${abs} (${d}d)`;\n}\n\n/** 동적 세그먼트(숫자, UUID)를 무시하고 같은 라우트 패턴인지 비교 */\nfunction isSameRoutePattern(a: string, b: string): boolean {\n const normalize = (path: string) =>\n path.split(\"/\").map((seg) =>\n /^\\d+$/.test(seg) || /^[0-9a-f]{8}-[0-9a-f]{4}-/i.test(seg) ? \"*\" : seg\n ).join(\"/\");\n return normalize(a) === normalize(b);\n}\n\nfunction getInitials(name: string): string {\n return name.slice(0, 1).toUpperCase();\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport function InboxPanel({\n pageItems,\n allItems,\n currentPath,\n serviceName,\n endpoint,\n currentUserName,\n currentUserId,\n onClose,\n}: InboxPanelProps) {\n const [tab, setTab] = useState<\"page\" | \"all\">(\"page\");\n const [statusFilter, setStatusFilter] = useState<\"todo\" | \"in_progress\" | \"done\">(\"todo\");\n const [exiting, setExiting] = useState(false);\n const [selectedItem, setSelectedItem] = useState<InboxItem | null>(null);\n const [comments, setComments] = useState<FeedbackComment[]>([]);\n const [loadingComments, setLoadingComments] = useState(false);\n const [replyText, setReplyText] = useState(\"\");\n const [lightboxSrc, setLightboxSrc] = useState<string | null>(null);\n const [filePreview, setFilePreview] = useState<{ url: string; name: string; type: string; source?: string } | null>(null);\n const replyRef = useRef<HTMLTextAreaElement>(null);\n const commentsEndRef = useRef<HTMLDivElement>(null);\n\n const handleClose = useCallback(() => {\n if (selectedItem) {\n setSelectedItem(null);\n setComments([]);\n setReplyText(\"\");\n return;\n }\n setExiting(true);\n setTimeout(() => onClose(), 150);\n }, [onClose, selectedItem]);\n\n // 카드 클릭 → 항상 상세 뷰 (댓글 피드) 진입\n const handleItemClick = useCallback(async (item: InboxItem) => {\n\n setSelectedItem(item);\n const cached = getCachedSnapshot<FeedbackComment[]>(getCommentsCacheKey(item.id));\n setComments(cached || []);\n setLoadingComments(!cached);\n }, [endpoint]);\n\n useEffect(() => {\n if (!selectedItem) return;\n\n const cacheKey = getCommentsCacheKey(selectedItem.id);\n const cached = getCachedSnapshot<FeedbackComment[]>(cacheKey);\n if (cached) {\n setComments(cached);\n setLoadingComments(false);\n }\n\n const unsubscribe = subscribeCache<FeedbackComment[]>(cacheKey, (nextComments) => {\n setComments(nextComments);\n setLoadingComments(false);\n });\n\n fetchComments(endpoint, selectedItem.id, { staleWhileRevalidate: true })\n .then((data) => {\n setComments(data);\n setLoadingComments(false);\n })\n .catch(() => {\n setLoadingComments(false);\n });\n\n return unsubscribe;\n }, [selectedItem, endpoint]);\n\n // 댓글 로드 후 스크롤\n useEffect(() => {\n commentsEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [comments.length]);\n\n // 포커스\n useEffect(() => {\n if (selectedItem) replyRef.current?.focus();\n }, [selectedItem]);\n\n // 댓글 전송\n const handleSendReply = useCallback(async () => {\n if (!replyText.trim() || !selectedItem) return;\n const content = replyText.trim();\n setReplyText(\"\");\n\n try {\n await postComment(endpoint, selectedItem.id, content, currentUserName, currentUserId);\n } catch (err) {\n console.error(\"[@impakers/debug] 코멘트 전송 실패:\", err);\n }\n }, [replyText, selectedItem, endpoint, currentUserName, currentUserId]);\n\n const handleReplyKeyDown = useCallback((e: React.KeyboardEvent) => {\n e.stopPropagation();\n if (e.nativeEvent.isComposing) return;\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSendReply();\n }\n if (e.key === \"Escape\") handleClose();\n }, [handleSendReply, handleClose]);\n\n const rawItems = tab === \"page\" ? pageItems : allItems;\n const items = rawItems.filter((item) => item.status === statusFilter);\n const todoCount = rawItems.filter((item) => item.status === \"todo\").length;\n const inProgressCount = rawItems.filter((item) => item.status === \"in_progress\").length;\n const doneCount = rawItems.filter((item) => item.status === \"done\").length;\n\n if (typeof document === \"undefined\") return null;\n\n return createPortal(\n <div data-impakers-debug=\"\">\n <div className={styles.backdrop} onClick={handleClose} />\n\n <div className={`${styles.panel} ${exiting ? styles.exiting : \"\"}`} data-impakers-debug=\"\">\n {/* Header */}\n <div className={styles.header}>\n <div className={styles.headerLeft}>\n {selectedItem && (\n <button className={styles.backBtn} onClick={handleClose} type=\"button\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"16\" height=\"16\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n )}\n <span className={styles.headerTitle}>\n {selectedItem ? selectedItem.title.replace(/^\\[피드백\\]\\s*/, \"\") : (serviceName || \"Feedback\")}\n </span>\n </div>\n <button className={styles.closeBtn} onClick={() => { setExiting(true); setTimeout(() => onClose(), 150); }} type=\"button\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* === 상세 뷰 === */}\n {selectedItem ? (\n <div className={styles.detailView}>\n {/* 원본 피드백 */}\n <div className={styles.detailHeader}>\n <div className={styles.cardAvatar}>{getInitials(selectedItem.authorName)}</div>\n <div>\n <div className={styles.cardMeta}>\n <span className={styles.cardAuthor}>{selectedItem.authorName}</span>\n <span className={styles.cardTime}>{formatTime(selectedItem.createdAt)}</span>\n </div>\n <div className={styles.detailTitle}>\n {selectedItem.title.replace(/^\\[피드백\\]\\s*/, \"\")}\n </div>\n </div>\n </div>\n\n {selectedItem.screenshot && (\n <div className={styles.detailScreenshot}>\n <img src={selectedItem.screenshot} alt=\"screenshot\" />\n </div>\n )}\n\n {/* 댓글 목록 */}\n <div className={styles.commentsList}>\n {loadingComments && (\n <div className={styles.loadingComments}>댓글 로딩 중...</div>\n )}\n {!loadingComments && comments.length === 0 && (\n <div className={styles.noComments}>아직 댓글이 없습니다</div>\n )}\n {comments.map((c) => (\n <div key={c.id} className={styles.commentItem}>\n <div className={styles.commentAvatar} style={{ width: 22, height: 22, fontSize: 10 }}>\n {getInitials(c.authorName)}\n </div>\n <div className={styles.commentBody}>\n <div className={styles.commentMeta}>\n <span className={styles.commentAuthorName}>{c.authorName}</span>\n <span className={styles.commentTime}>{formatTime(c.createdAt)}</span>\n </div>\n {c.content && <div className={styles.commentContent}>{c.content}</div>}\n {c.imageUrl && (\n <div\n className={styles.commentImage}\n onClick={(e) => { e.stopPropagation(); setLightboxSrc(c.imageUrl!); }}\n >\n <img src={c.imageUrl} alt=\"attachment\" />\n </div>\n )}\n {c.fileUrl && (\n <div\n className={styles.commentFileCard}\n onClick={(e) => {\n e.stopPropagation();\n setFilePreview({\n url: c.fileUrl!,\n name: c.fileName || \"파일\",\n type: c.fileType || \"\",\n source: c.fileSource,\n });\n }}\n >\n <span className={styles.commentFileIcon}>{getFileIcon(c.fileType || \"\")}</span>\n <span className={styles.commentFileInfo}>\n <span className={styles.commentFileName}>{c.fileName || \"파일\"}</span>\n {c.fileSize != null && (\n <span className={styles.commentFileSize}>{formatFileSize(c.fileSize)}</span>\n )}\n </span>\n </div>\n )}\n </div>\n </div>\n ))}\n <div ref={commentsEndRef} />\n </div>\n\n {/* 댓글 입력 */}\n <div className={styles.replyBox}>\n <textarea\n ref={replyRef}\n className={styles.replyInput}\n placeholder=\"Reply...\"\n value={replyText}\n onChange={(e) => {\n setReplyText(e.target.value);\n const el = e.target;\n el.style.height = \"auto\";\n el.style.height = `${Math.min(el.scrollHeight, 120)}px`;\n }}\n onKeyDown={handleReplyKeyDown}\n rows={2}\n />\n <button\n className={`${styles.sendBtn} ${replyText.trim() ? styles.active : \"\"}`}\n onClick={handleSendReply}\n disabled={!replyText.trim()}\n type=\"button\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"16\" height=\"16\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" /><polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n </button>\n </div>\n </div>\n ) : (\n <>\n {/* === 리스트 뷰 === */}\n <div className={styles.tabs}>\n <button className={`${styles.tab} ${tab === \"page\" ? styles.active : \"\"}`} onClick={() => setTab(\"page\")} type=\"button\">\n This Page\n {pageItems.length > 0 && <span className={styles.tabBadge}>{pageItems.length}</span>}\n </button>\n <button className={`${styles.tab} ${tab === \"all\" ? styles.active : \"\"}`} onClick={() => setTab(\"all\")} type=\"button\">\n All\n {allItems.length > 0 && <span className={styles.tabBadge}>{allItems.length}</span>}\n </button>\n </div>\n\n <div className={styles.statusFilter}>\n <button\n className={`${styles.filterChip} ${statusFilter === \"todo\" ? styles.active : \"\"}`}\n onClick={() => setStatusFilter(\"todo\")}\n type=\"button\"\n >\n 진행전\n {todoCount > 0 && <span className={styles.filterCount}>{todoCount}</span>}\n </button>\n <button\n className={`${styles.filterChip} ${statusFilter === \"in_progress\" ? styles.active : \"\"}`}\n onClick={() => setStatusFilter(\"in_progress\")}\n type=\"button\"\n >\n 진행중\n {inProgressCount > 0 && <span className={styles.filterCount}>{inProgressCount}</span>}\n </button>\n <button\n className={`${styles.filterChip} ${statusFilter === \"done\" ? styles.active : \"\"}`}\n onClick={() => setStatusFilter(\"done\")}\n type=\"button\"\n >\n 완료\n {doneCount > 0 && <span className={styles.filterCount}>{doneCount}</span>}\n </button>\n </div>\n\n <div className={styles.content}>\n {items.length === 0 ? (\n <div className={styles.empty}>\n <div className={styles.emptyIcon}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z\" />\n </svg>\n </div>\n {tab === \"page\" ? \"이 페이지에 피드백이 없습니다\" : \"피드백이 없습니다\"}\n </div>\n ) : (\n items.map((item) => (\n <div key={item.id} className={`${styles.card} ${item.status === \"done\" ? styles.cardDone : \"\"}`} onClick={() => handleItemClick(item)}>\n <div className={styles.cardHeader}>\n <div className={styles.cardAvatar}>{getInitials(item.authorName)}</div>\n <div className={styles.cardInfo}>\n <div className={styles.cardMeta}>\n <span className={styles.cardAuthor}>{item.authorName}</span>\n <span className={styles.cardTime}>{formatTime(item.createdAt)}</span>\n </div>\n </div>\n </div>\n\n <div className={styles.cardTitle}>{item.title.replace(/^\\[피드백\\]\\s*/, \"\")}</div>\n\n {item.screenshot && (\n <div className={styles.cardScreenshot}>\n <img src={item.screenshot} alt=\"screenshot\" />\n </div>\n )}\n\n {tab === \"all\" && item.feedbackUrl && (\n <div\n className={styles.cardRoute}\n onClick={(e) => {\n e.stopPropagation();\n window.location.href = item.feedbackUrl;\n }}\n title=\"페이지로 이동\"\n >\n <span className={styles.cardRoutePath}>{item.feedbackUrl}</span>\n <svg className={styles.cardRouteIcon} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"12\" height=\"12\">\n <path d=\"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n </div>\n )}\n\n <div className={styles.cardFooter}>\n <span className={styles.cardReplyDot} />\n <span className={styles.cardReplyCount}>\n {item.commentCount} {item.commentCount === 1 ? \"Reply\" : \"Replies\"}\n </span>\n </div>\n </div>\n ))\n )}\n </div>\n </>\n )}\n </div>\n\n {/* 이미지 확대 모달 */}\n {lightboxSrc && (\n <ImageLightbox src={lightboxSrc} onClose={() => setLightboxSrc(null)} />\n )}\n\n {/* 파일 프리뷰 모달 */}\n {filePreview && (\n <FilePreviewModal\n fileUrl={filePreview.url}\n fileName={filePreview.name}\n fileType={filePreview.type}\n fileSource={filePreview.source}\n onClose={() => setFilePreview(null)}\n />\n )}\n </div>,\n document.body,\n );\n}\n","\nconst css = \"@keyframes styles-module__slideIn___0o0s- {\\n from {\\n transform: translateX(100%);\\n }\\n to {\\n transform: translateX(0);\\n }\\n}\\n@keyframes styles-module__slideOut___nKrBX {\\n from {\\n transform: translateX(0);\\n }\\n to {\\n transform: translateX(100%);\\n }\\n}\\n@keyframes styles-module__fadeIn___j09Ts {\\n from {\\n opacity: 0;\\n }\\n to {\\n opacity: 1;\\n }\\n}\\n.styles-module__backdrop___zYhcU {\\n position: fixed;\\n inset: 0;\\n z-index: 100003;\\n animation: styles-module__fadeIn___j09Ts 0.15s ease-out;\\n}\\n\\n.styles-module__panel___6YS8k {\\n position: fixed;\\n top: 0;\\n right: 0;\\n bottom: 0;\\n width: 420px;\\n max-width: 100vw;\\n background: #fafafa;\\n z-index: 100004;\\n display: flex;\\n flex-direction: column;\\n box-shadow: -4px 0 24px rgba(0, 0, 0, 0.08);\\n animation: styles-module__slideIn___0o0s- 0.2s ease-out;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n -webkit-font-smoothing: antialiased;\\n}\\n.styles-module__panel___6YS8k.styles-module__exiting___6A-Ag {\\n animation: styles-module__slideOut___nKrBX 0.15s ease-in forwards;\\n}\\n\\n.styles-module__header___fBbGz {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 16px 20px;\\n border-bottom: 1px solid #e5e7eb;\\n background: #fff;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__headerLeft___e0YLf {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n}\\n\\n.styles-module__headerTitle___oEPJa {\\n font-size: 14px;\\n font-weight: 600;\\n color: #18181b;\\n}\\n\\n.styles-module__closeBtn___-H8ra {\\n width: 32px;\\n height: 32px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #6b7280;\\n transition: background 0.12s, color 0.12s;\\n}\\n.styles-module__closeBtn___-H8ra:hover {\\n background: #f3f4f6;\\n color: #18181b;\\n}\\n.styles-module__closeBtn___-H8ra svg {\\n width: 18px;\\n height: 18px;\\n}\\n\\n.styles-module__tabs___nfuX7 {\\n display: flex;\\n padding: 0 20px;\\n gap: 0;\\n border-bottom: 1px solid #e5e7eb;\\n background: #fff;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__tab___Hc-jn {\\n padding: 10px 16px;\\n font-size: 13px;\\n font-weight: 500;\\n color: #6b7280;\\n border: none;\\n background: none;\\n cursor: pointer;\\n border-bottom: 2px solid transparent;\\n transition: color 0.12s, border-color 0.12s;\\n font-family: inherit;\\n}\\n.styles-module__tab___Hc-jn:hover {\\n color: #374151;\\n}\\n.styles-module__tab___Hc-jn.styles-module__active___ZQzA5 {\\n color: #18181b;\\n border-bottom-color: #18181b;\\n}\\n\\n.styles-module__tabBadge___IdFDQ {\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n min-width: 18px;\\n height: 18px;\\n border-radius: 9px;\\n background: #e5e7eb;\\n color: #374151;\\n font-size: 11px;\\n font-weight: 600;\\n padding: 0 5px;\\n margin-left: 6px;\\n}\\n\\n.styles-module__statusFilter___qtBXs {\\n display: flex;\\n gap: 6px;\\n padding: 10px 20px;\\n border-bottom: 1px solid #f3f4f6;\\n background: #fff;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__filterChip___l2s74 {\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n padding: 4px 10px;\\n font-size: 12px;\\n font-weight: 500;\\n color: #6b7280;\\n background: #f3f4f6;\\n border: 1px solid transparent;\\n border-radius: 16px;\\n cursor: pointer;\\n transition: all 0.12s;\\n font-family: inherit;\\n}\\n.styles-module__filterChip___l2s74:hover {\\n color: #374151;\\n background: #e5e7eb;\\n}\\n.styles-module__filterChip___l2s74.styles-module__active___ZQzA5 {\\n color: #18181b;\\n background: #fff;\\n border-color: #d1d5db;\\n}\\n\\n.styles-module__filterCount___KukiQ {\\n font-size: 11px;\\n font-weight: 600;\\n color: inherit;\\n opacity: 0.7;\\n}\\n\\n.styles-module__content___L2lRw {\\n flex: 1;\\n overflow-y: auto;\\n padding: 12px;\\n}\\n.styles-module__content___L2lRw::-webkit-scrollbar {\\n width: 4px;\\n}\\n.styles-module__content___L2lRw::-webkit-scrollbar-thumb {\\n background: #d1d5db;\\n border-radius: 2px;\\n}\\n\\n.styles-module__card___F8qwd {\\n background: #fff;\\n border-radius: 12px;\\n border: 1px solid #e5e7eb;\\n margin-bottom: 12px;\\n overflow: hidden;\\n transition: box-shadow 0.12s;\\n cursor: pointer;\\n}\\n.styles-module__card___F8qwd:hover {\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\\n}\\n\\n.styles-module__cardHeader___QOVGR {\\n padding: 14px 16px 8px;\\n display: flex;\\n align-items: flex-start;\\n gap: 10px;\\n}\\n\\n.styles-module__cardAvatar___FfKmW {\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n background: #16a34a;\\n color: #fff;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 11px;\\n font-weight: 600;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__cardInfo___BmrdF {\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__cardMeta___7p9KD {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n margin-bottom: 4px;\\n}\\n\\n.styles-module__cardAuthor___YvnuR {\\n font-size: 13px;\\n font-weight: 600;\\n color: #18181b;\\n}\\n\\n.styles-module__cardTime___N1Png {\\n font-size: 12px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__cardActions___7QF72 {\\n display: flex;\\n gap: 2px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__cardAction___t4b3V {\\n width: 26px;\\n height: 26px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 5px;\\n color: #9ca3af;\\n transition: background 0.12s, color 0.12s;\\n padding: 0;\\n}\\n.styles-module__cardAction___t4b3V:hover {\\n background: #f3f4f6;\\n color: #374151;\\n}\\n.styles-module__cardAction___t4b3V svg {\\n width: 14px;\\n height: 14px;\\n}\\n\\n.styles-module__cardTitle___xJxDN {\\n font-size: 13px;\\n color: #1a1a1a;\\n line-height: 1.5;\\n padding: 0 16px 8px;\\n}\\n\\n.styles-module__cardScreenshot___I5-QL {\\n margin: 0 16px 8px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n overflow: hidden;\\n position: relative;\\n max-height: 160px;\\n}\\n.styles-module__cardScreenshot___I5-QL img {\\n width: 100%;\\n height: auto;\\n display: block;\\n object-fit: cover;\\n}\\n\\n.styles-module__cardRoute___U4gB6 {\\n margin: 0 16px 10px;\\n padding: 8px 12px;\\n background: #f9fafb;\\n border: 1px solid #f3f4f6;\\n border-radius: 8px;\\n font-size: 12px;\\n color: #6b7280;\\n line-height: 1.4;\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n cursor: pointer;\\n transition: background 0.12s, border-color 0.12s;\\n}\\n.styles-module__cardRoute___U4gB6:hover {\\n background: #f3f4f6;\\n border-color: #d1d5db;\\n color: #3b82f6;\\n}\\n.styles-module__cardRoute___U4gB6:hover .styles-module__cardRoutePath___zP-fh {\\n color: #3b82f6;\\n}\\n.styles-module__cardRoute___U4gB6:hover .styles-module__cardRouteIcon___SBqGj {\\n color: #3b82f6;\\n}\\n\\n.styles-module__cardRouteName___BDH75 {\\n font-weight: 500;\\n color: #374151;\\n}\\n\\n.styles-module__cardRoutePath___zP-fh {\\n flex: 1;\\n min-width: 0;\\n color: #9ca3af;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n transition: color 0.12s;\\n}\\n\\n.styles-module__cardRouteIcon___SBqGj {\\n flex-shrink: 0;\\n color: #9ca3af;\\n transition: color 0.12s;\\n}\\n\\n.styles-module__cardFooter___wfPa4 {\\n padding: 8px 16px 12px;\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n}\\n\\n.styles-module__cardReplyDot___YnqzI {\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: #16a34a;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__cardReplyCount___O1khL {\\n font-size: 12px;\\n font-weight: 500;\\n color: #374151;\\n}\\n\\n.styles-module__statusDot___l4IHG {\\n width: 6px;\\n height: 6px;\\n border-radius: 50%;\\n flex-shrink: 0;\\n}\\n.styles-module__statusDot___l4IHG.styles-module__todo___894P6 {\\n background: #f59e0b;\\n}\\n.styles-module__statusDot___l4IHG.styles-module__inProgress___IZ1mJ {\\n background: #3b82f6;\\n}\\n.styles-module__statusDot___l4IHG.styles-module__done___n4cWP {\\n background: #16a34a;\\n}\\n\\n.styles-module__empty___IADrw {\\n text-align: center;\\n padding: 48px 20px;\\n color: #9ca3af;\\n font-size: 13px;\\n line-height: 1.6;\\n}\\n\\n.styles-module__emptyIcon___1x5wT {\\n width: 48px;\\n height: 48px;\\n border-radius: 50%;\\n background: #f3f4f6;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n margin: 0 auto 12px;\\n color: #9ca3af;\\n}\\n.styles-module__emptyIcon___1x5wT svg {\\n width: 24px;\\n height: 24px;\\n}\\n\\n.styles-module__checkBtn___KjHxm {\\n width: 28px;\\n height: 28px;\\n border: 2px solid #d1d5db;\\n border-radius: 50%;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n color: transparent;\\n transition: all 0.15s;\\n padding: 0;\\n flex-shrink: 0;\\n}\\n.styles-module__checkBtn___KjHxm svg {\\n width: 14px;\\n height: 14px;\\n}\\n.styles-module__checkBtn___KjHxm:hover {\\n border-color: #16a34a;\\n color: #16a34a;\\n}\\n.styles-module__checkBtn___KjHxm.styles-module__checked___8pype {\\n border-color: #16a34a;\\n background: #16a34a;\\n color: #fff;\\n}\\n\\n.styles-module__cardDone___-m4w- {\\n opacity: 0.6;\\n}\\n.styles-module__cardDone___-m4w- .styles-module__cardTitle___xJxDN {\\n text-decoration: line-through;\\n color: #9ca3af;\\n}\\n\\n.styles-module__backBtn___PTIAl {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #6b7280;\\n transition: background 0.12s, color 0.12s;\\n padding: 0;\\n flex-shrink: 0;\\n}\\n.styles-module__backBtn___PTIAl:hover {\\n background: #f3f4f6;\\n color: #18181b;\\n}\\n\\n.styles-module__detailView___36cvH {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n}\\n\\n.styles-module__detailHeader___Hepgq {\\n display: flex;\\n gap: 10px;\\n padding: 16px 20px;\\n border-bottom: 1px solid #f3f4f6;\\n}\\n\\n.styles-module__detailTitle___7TvrX {\\n font-size: 13px;\\n color: #1a1a1a;\\n line-height: 1.5;\\n margin-top: 4px;\\n}\\n\\n.styles-module__detailScreenshot___UPF0f {\\n margin: 0 20px 0;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n overflow: hidden;\\n max-height: 180px;\\n}\\n.styles-module__detailScreenshot___UPF0f img {\\n width: 100%;\\n height: auto;\\n display: block;\\n object-fit: cover;\\n}\\n\\n.styles-module__commentsList___5Uigg {\\n flex: 1;\\n overflow-y: auto;\\n padding: 8px 0;\\n}\\n.styles-module__commentsList___5Uigg::-webkit-scrollbar {\\n width: 4px;\\n}\\n.styles-module__commentsList___5Uigg::-webkit-scrollbar-thumb {\\n background: #d1d5db;\\n border-radius: 2px;\\n}\\n\\n.styles-module__commentItem___5u78u {\\n display: flex;\\n gap: 10px;\\n padding: 10px 20px;\\n}\\n.styles-module__commentItem___5u78u:hover {\\n background: #f9fafb;\\n}\\n\\n.styles-module__commentAvatar___OatKg {\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n background: #16a34a;\\n color: #fff;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 11px;\\n font-weight: 600;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__commentBody___gmv1J {\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__commentMeta___JNJa3 {\\n display: flex;\\n gap: 6px;\\n align-items: center;\\n margin-bottom: 2px;\\n}\\n\\n.styles-module__commentAuthorName___XNVRk {\\n font-size: 13px;\\n font-weight: 600;\\n color: #1a1a1a;\\n}\\n\\n.styles-module__commentTime___CokGf {\\n font-size: 12px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__commentContent___yMiLR {\\n font-size: 13px;\\n color: #374151;\\n line-height: 1.5;\\n white-space: pre-wrap;\\n word-break: break-word;\\n}\\n\\n.styles-module__loadingComments___zpATD, .styles-module__noComments___kvl90 {\\n text-align: center;\\n padding: 24px 20px;\\n color: #9ca3af;\\n font-size: 13px;\\n}\\n\\n.styles-module__replyBox___FO-XS {\\n display: flex;\\n align-items: flex-end;\\n gap: 8px;\\n padding: 12px 20px;\\n border-top: 1px solid #f3f4f6;\\n background: #fff;\\n}\\n\\n.styles-module__replyInput___k8C9e {\\n flex: 1;\\n border: 1px solid #e5e7eb;\\n border-radius: 8px;\\n padding: 8px 12px;\\n font-size: 13px;\\n font-family: inherit;\\n color: #1a1a1a;\\n resize: none;\\n outline: none;\\n min-height: 20px;\\n max-height: 80px;\\n line-height: 1.5;\\n transition: border-color 0.12s;\\n}\\n.styles-module__replyInput___k8C9e:focus {\\n border-color: #18181b;\\n}\\n.styles-module__replyInput___k8C9e::placeholder {\\n color: #9ca3af;\\n}\\n\\n.styles-module__sendBtn___pBzWa {\\n width: 32px;\\n height: 32px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #d1d5db;\\n transition: color 0.12s;\\n padding: 0;\\n flex-shrink: 0;\\n}\\n.styles-module__sendBtn___pBzWa.styles-module__active___ZQzA5 {\\n color: #3b82f6;\\n}\\n.styles-module__sendBtn___pBzWa:hover {\\n color: #3b82f6;\\n}\\n\\n.styles-module__commentImage___LuH8X {\\n margin-top: 6px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n overflow: hidden;\\n max-width: 240px;\\n cursor: pointer;\\n transition: opacity 0.12s;\\n}\\n.styles-module__commentImage___LuH8X:hover {\\n opacity: 0.9;\\n}\\n.styles-module__commentImage___LuH8X img {\\n width: 100%;\\n height: auto;\\n display: block;\\n}\\n\\n.styles-module__commentFileCard___XE44y {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n margin-top: 6px;\\n padding: 8px 10px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n background: #f9fafb;\\n cursor: pointer;\\n transition: background 0.12s;\\n max-width: 240px;\\n}\\n.styles-module__commentFileCard___XE44y:hover {\\n background: #f3f4f6;\\n}\\n\\n.styles-module__commentFileIcon___G58-y {\\n width: 32px;\\n height: 32px;\\n border-radius: 6px;\\n background: #e5e7eb;\\n color: #374151;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 10px;\\n font-weight: 700;\\n flex-shrink: 0;\\n letter-spacing: 0.5px;\\n}\\n\\n.styles-module__commentFileInfo___OFIhR {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n}\\n\\n.styles-module__commentFileName___NUoII {\\n font-size: 12px;\\n font-weight: 500;\\n color: #1a1a1a;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__commentFileSize___sokU8 {\\n font-size: 11px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__filePreviewOverlay___5RxYd {\\n position: fixed;\\n inset: 0;\\n z-index: 2147483647;\\n background: rgba(0, 0, 0, 0.6);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n\\n.styles-module__filePreviewModal___MGJLW {\\n width: 90vw;\\n max-width: 960px;\\n height: 80vh;\\n background: #fff;\\n border-radius: 12px;\\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n}\\n\\n.styles-module__filePreviewHeader___E9SWJ {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 12px 16px;\\n border-bottom: 1px solid #e5e7eb;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__filePreviewName___z8t-L {\\n font-size: 14px;\\n font-weight: 600;\\n color: #18181b;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__filePreviewActions___weizo {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__filePreviewOpen___JpaEs {\\n display: flex;\\n align-items: center;\\n gap: 4px;\\n font-size: 12px;\\n font-weight: 500;\\n color: #3b82f6;\\n text-decoration: none;\\n padding: 4px 8px;\\n border-radius: 6px;\\n transition: background 0.12s;\\n}\\n.styles-module__filePreviewOpen___JpaEs:hover {\\n background: #eff6ff;\\n}\\n\\n.styles-module__filePreviewClose___TFcbr {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #6b7280;\\n font-size: 18px;\\n transition: background 0.12s, color 0.12s;\\n}\\n.styles-module__filePreviewClose___TFcbr:hover {\\n background: #f3f4f6;\\n color: #18181b;\\n}\\n\\n.styles-module__filePreviewBody___gwg1S {\\n flex: 1;\\n overflow: hidden;\\n}\\n\\n.styles-module__filePreviewIframe___OQ3Oo {\\n width: 100%;\\n height: 100%;\\n border: none;\\n}\\n\\n.styles-module__filePreviewFallback___U1rB2 {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n height: 100%;\\n gap: 12px;\\n color: #6b7280;\\n font-size: 14px;\\n}\\n.styles-module__filePreviewFallback___U1rB2 a {\\n color: #3b82f6;\\n text-decoration: none;\\n font-weight: 500;\\n}\\n.styles-module__filePreviewFallback___U1rB2 a:hover {\\n text-decoration: underline;\\n}\\n\\n.styles-module__filePreviewFallbackIcon___0--41 {\\n width: 56px;\\n height: 56px;\\n border-radius: 12px;\\n background: #f3f4f6;\\n color: #6b7280;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 16px;\\n font-weight: 700;\\n}\\n\\n.styles-module__lightbox___8CDdt {\\n position: fixed;\\n inset: 0;\\n z-index: 2147483647;\\n background: rgba(0, 0, 0, 0.8);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n cursor: zoom-out;\\n}\\n.styles-module__lightbox___8CDdt img {\\n max-width: 90vw;\\n max-height: 90vh;\\n border-radius: 8px;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\\n cursor: default;\\n}\\n\\n.styles-module__lightboxClose___VGfjh {\\n position: absolute;\\n top: 16px;\\n right: 16px;\\n width: 36px;\\n height: 36px;\\n border-radius: 50%;\\n background: rgba(255, 255, 255, 0.15);\\n color: #fff;\\n border: none;\\n cursor: pointer;\\n font-size: 20px;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.styles-module__lightboxClose___VGfjh:hover {\\n background: rgba(255, 255, 255, 0.25);\\n}\";\nconst classNames = {\"backdrop\":\"styles-module__backdrop___zYhcU\",\"fadeIn\":\"styles-module__fadeIn___j09Ts\",\"panel\":\"styles-module__panel___6YS8k\",\"slideIn\":\"styles-module__slideIn___0o0s-\",\"exiting\":\"styles-module__exiting___6A-Ag\",\"slideOut\":\"styles-module__slideOut___nKrBX\",\"header\":\"styles-module__header___fBbGz\",\"headerLeft\":\"styles-module__headerLeft___e0YLf\",\"headerTitle\":\"styles-module__headerTitle___oEPJa\",\"closeBtn\":\"styles-module__closeBtn___-H8ra\",\"tabs\":\"styles-module__tabs___nfuX7\",\"tab\":\"styles-module__tab___Hc-jn\",\"active\":\"styles-module__active___ZQzA5\",\"tabBadge\":\"styles-module__tabBadge___IdFDQ\",\"statusFilter\":\"styles-module__statusFilter___qtBXs\",\"filterChip\":\"styles-module__filterChip___l2s74\",\"filterCount\":\"styles-module__filterCount___KukiQ\",\"content\":\"styles-module__content___L2lRw\",\"card\":\"styles-module__card___F8qwd\",\"cardHeader\":\"styles-module__cardHeader___QOVGR\",\"cardAvatar\":\"styles-module__cardAvatar___FfKmW\",\"cardInfo\":\"styles-module__cardInfo___BmrdF\",\"cardMeta\":\"styles-module__cardMeta___7p9KD\",\"cardAuthor\":\"styles-module__cardAuthor___YvnuR\",\"cardTime\":\"styles-module__cardTime___N1Png\",\"cardActions\":\"styles-module__cardActions___7QF72\",\"cardAction\":\"styles-module__cardAction___t4b3V\",\"cardTitle\":\"styles-module__cardTitle___xJxDN\",\"cardScreenshot\":\"styles-module__cardScreenshot___I5-QL\",\"cardRoute\":\"styles-module__cardRoute___U4gB6\",\"cardRoutePath\":\"styles-module__cardRoutePath___zP-fh\",\"cardRouteIcon\":\"styles-module__cardRouteIcon___SBqGj\",\"cardRouteName\":\"styles-module__cardRouteName___BDH75\",\"cardFooter\":\"styles-module__cardFooter___wfPa4\",\"cardReplyDot\":\"styles-module__cardReplyDot___YnqzI\",\"cardReplyCount\":\"styles-module__cardReplyCount___O1khL\",\"statusDot\":\"styles-module__statusDot___l4IHG\",\"todo\":\"styles-module__todo___894P6\",\"inProgress\":\"styles-module__inProgress___IZ1mJ\",\"done\":\"styles-module__done___n4cWP\",\"empty\":\"styles-module__empty___IADrw\",\"emptyIcon\":\"styles-module__emptyIcon___1x5wT\",\"checkBtn\":\"styles-module__checkBtn___KjHxm\",\"checked\":\"styles-module__checked___8pype\",\"cardDone\":\"styles-module__cardDone___-m4w-\",\"backBtn\":\"styles-module__backBtn___PTIAl\",\"detailView\":\"styles-module__detailView___36cvH\",\"detailHeader\":\"styles-module__detailHeader___Hepgq\",\"detailTitle\":\"styles-module__detailTitle___7TvrX\",\"detailScreenshot\":\"styles-module__detailScreenshot___UPF0f\",\"commentsList\":\"styles-module__commentsList___5Uigg\",\"commentItem\":\"styles-module__commentItem___5u78u\",\"commentAvatar\":\"styles-module__commentAvatar___OatKg\",\"commentBody\":\"styles-module__commentBody___gmv1J\",\"commentMeta\":\"styles-module__commentMeta___JNJa3\",\"commentAuthorName\":\"styles-module__commentAuthorName___XNVRk\",\"commentTime\":\"styles-module__commentTime___CokGf\",\"commentContent\":\"styles-module__commentContent___yMiLR\",\"loadingComments\":\"styles-module__loadingComments___zpATD\",\"noComments\":\"styles-module__noComments___kvl90\",\"replyBox\":\"styles-module__replyBox___FO-XS\",\"replyInput\":\"styles-module__replyInput___k8C9e\",\"sendBtn\":\"styles-module__sendBtn___pBzWa\",\"commentImage\":\"styles-module__commentImage___LuH8X\",\"commentFileCard\":\"styles-module__commentFileCard___XE44y\",\"commentFileIcon\":\"styles-module__commentFileIcon___G58-y\",\"commentFileInfo\":\"styles-module__commentFileInfo___OFIhR\",\"commentFileName\":\"styles-module__commentFileName___NUoII\",\"commentFileSize\":\"styles-module__commentFileSize___sokU8\",\"filePreviewOverlay\":\"styles-module__filePreviewOverlay___5RxYd\",\"filePreviewModal\":\"styles-module__filePreviewModal___MGJLW\",\"filePreviewHeader\":\"styles-module__filePreviewHeader___E9SWJ\",\"filePreviewName\":\"styles-module__filePreviewName___z8t-L\",\"filePreviewActions\":\"styles-module__filePreviewActions___weizo\",\"filePreviewOpen\":\"styles-module__filePreviewOpen___JpaEs\",\"filePreviewClose\":\"styles-module__filePreviewClose___TFcbr\",\"filePreviewBody\":\"styles-module__filePreviewBody___gwg1S\",\"filePreviewIframe\":\"styles-module__filePreviewIframe___OQ3Oo\",\"filePreviewFallback\":\"styles-module__filePreviewFallback___U1rB2\",\"filePreviewFallbackIcon\":\"styles-module__filePreviewFallbackIcon___0--41\",\"lightbox\":\"styles-module__lightbox___8CDdt\",\"lightboxClose\":\"styles-module__lightboxClose___VGfjh\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-inbox-panel-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-inbox-panel-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { DebugSettings } from \"../../core/settings\";\nimport { MARKER_COLORS } from \"../../core/settings\";\nimport styles from \"./styles.module.scss\";\n\nexport interface SettingsPanelProps {\n settings: DebugSettings;\n onChange: (settings: DebugSettings) => void;\n onClose: () => void;\n}\n\nexport function SettingsPanel({ settings, onChange, onClose }: SettingsPanelProps) {\n const handleToggleMarkers = useCallback(() => {\n onChange({ ...settings, markersVisible: !settings.markersVisible });\n }, [settings, onChange]);\n\n const handleToggleHideDone = useCallback(() => {\n onChange({ ...settings, hideDoneMarkers: !settings.hideDoneMarkers });\n }, [settings, onChange]);\n\n const handleToggleShowOnlyMine = useCallback(() => {\n onChange({ ...settings, showOnlyMine: !settings.showOnlyMine });\n }, [settings, onChange]);\n\n const handleColorChange = useCallback((color: string) => {\n onChange({ ...settings, markerColor: color });\n }, [settings, onChange]);\n\n if (typeof document === \"undefined\") return null;\n\n return createPortal(\n <div data-impakers-debug=\"\">\n <div className={styles.backdrop} onClick={onClose} />\n <div className={styles.panel} data-impakers-debug=\"\">\n <div className={styles.header}>\n <span className={styles.title}>설정</span>\n <button className={styles.closeBtn} onClick={onClose} type=\"button\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className={styles.body}>\n {/* 마커 표시 토글 */}\n <div className={styles.field}>\n <div className={styles.fieldLabel}>마커 표시</div>\n <button\n className={`${styles.toggle} ${settings.markersVisible ? styles.on : \"\"}`}\n onClick={handleToggleMarkers}\n type=\"button\"\n >\n <span className={styles.toggleThumb} />\n </button>\n </div>\n\n {/* 완료 핀 숨기기 */}\n <div className={styles.field}>\n <div className={styles.fieldLabel}>완료 핀 숨기기</div>\n <button\n className={`${styles.toggle} ${settings.hideDoneMarkers ? styles.on : \"\"}`}\n onClick={handleToggleHideDone}\n type=\"button\"\n >\n <span className={styles.toggleThumb} />\n </button>\n </div>\n\n {/* 내가 추가한 것만 보기 */}\n <div className={styles.field}>\n <div className={styles.fieldLabel}>내가 추가한 것만</div>\n <button\n className={`${styles.toggle} ${settings.showOnlyMine ? styles.on : \"\"}`}\n onClick={handleToggleShowOnlyMine}\n type=\"button\"\n >\n <span className={styles.toggleThumb} />\n </button>\n </div>\n\n {/* 마커 색상 */}\n <div className={styles.field}>\n <div className={styles.fieldLabel}>마커 색상</div>\n <div className={styles.colors}>\n {MARKER_COLORS.map((c) => (\n <button\n key={c.id}\n className={`${styles.colorBtn} ${settings.markerColor === c.value ? styles.selected : \"\"}`}\n style={{ background: c.value }}\n onClick={() => handleColorChange(c.value)}\n title={c.label}\n type=\"button\"\n />\n ))}\n </div>\n </div>\n </div>\n </div>\n </div>,\n document.body,\n );\n}\n","// =============================================================================\n// @impakers/debug — Widget Settings (localStorage)\n// =============================================================================\n\nconst SETTINGS_KEY = \"impakers-debug-settings\";\n\nexport interface DebugSettings {\n markerColor: string;\n markersVisible: boolean;\n hideDoneMarkers: boolean;\n showOnlyMine: boolean;\n}\n\nconst DEFAULTS: DebugSettings = {\n markerColor: \"#6366f1\",\n markersVisible: true,\n hideDoneMarkers: false,\n showOnlyMine: false,\n};\n\nexport function loadSettings(): DebugSettings {\n try {\n const stored = localStorage.getItem(SETTINGS_KEY);\n if (!stored) return { ...DEFAULTS };\n return { ...DEFAULTS, ...JSON.parse(stored) };\n } catch {\n return { ...DEFAULTS };\n }\n}\n\nexport function saveSettings(settings: DebugSettings): void {\n try {\n localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));\n } catch {\n // ignore\n }\n}\n\nexport const MARKER_COLORS = [\n { id: \"indigo\", label: \"인디고\", value: \"#6366f1\" },\n { id: \"blue\", label: \"블루\", value: \"#3b82f6\" },\n { id: \"red\", label: \"레드\", value: \"#ef4444\" },\n { id: \"green\", label: \"그린\", value: \"#16a34a\" },\n { id: \"orange\", label: \"오렌지\", value: \"#f97316\" },\n { id: \"pink\", label: \"핑크\", value: \"#ec4899\" },\n];\n","\nconst css = \"@keyframes styles-module__panelIn___SmRh6 {\\n from {\\n opacity: 0;\\n transform: translateY(8px) scale(0.96);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0) scale(1);\\n }\\n}\\n.styles-module__backdrop___--cMp {\\n position: fixed;\\n inset: 0;\\n z-index: 100005;\\n}\\n\\n.styles-module__panel___z6xiJ {\\n position: fixed;\\n bottom: 80px;\\n right: 24px;\\n width: 280px;\\n background: #fff;\\n border-radius: 12px;\\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);\\n z-index: 100006;\\n overflow: hidden;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n animation: styles-module__panelIn___SmRh6 0.15s ease-out;\\n -webkit-font-smoothing: antialiased;\\n}\\n\\n.styles-module__header___NkOur {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 14px 16px;\\n border-bottom: 1px solid #f3f4f6;\\n}\\n\\n.styles-module__title___tsKZw {\\n font-size: 14px;\\n font-weight: 600;\\n color: #18181b;\\n}\\n\\n.styles-module__closeBtn___-OQ4Y {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #6b7280;\\n}\\n.styles-module__closeBtn___-OQ4Y:hover {\\n background: #f3f4f6;\\n color: #18181b;\\n}\\n\\n.styles-module__body___9pyCP {\\n padding: 12px 16px 16px;\\n}\\n\\n.styles-module__field___vnQMl {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 8px 0;\\n}\\n\\n.styles-module__fieldLabel___2WUKB {\\n font-size: 13px;\\n font-weight: 500;\\n color: #374151;\\n}\\n\\n.styles-module__toggle___uWsqC {\\n width: 40px;\\n height: 22px;\\n border-radius: 11px;\\n background: #d1d5db;\\n border: none;\\n cursor: pointer;\\n position: relative;\\n transition: background 0.2s;\\n padding: 0;\\n}\\n.styles-module__toggle___uWsqC.styles-module__on___W27kf {\\n background: #18181b;\\n}\\n\\n.styles-module__toggleThumb___wyckC {\\n position: absolute;\\n top: 2px;\\n left: 2px;\\n width: 18px;\\n height: 18px;\\n border-radius: 50%;\\n background: #fff;\\n transition: transform 0.2s;\\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\\n}\\n.styles-module__on___W27kf .styles-module__toggleThumb___wyckC {\\n transform: translateX(18px);\\n}\\n\\n.styles-module__colors___vgFGZ {\\n display: flex;\\n gap: 6px;\\n}\\n\\n.styles-module__colorBtn___N7dGu {\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n border: 2px solid transparent;\\n cursor: pointer;\\n transition: transform 0.12s, border-color 0.12s;\\n padding: 0;\\n}\\n.styles-module__colorBtn___N7dGu:hover {\\n transform: scale(1.15);\\n}\\n.styles-module__colorBtn___N7dGu.styles-module__selected___0tVDH {\\n border-color: #18181b;\\n transform: scale(1.15);\\n}\";\nconst classNames = {\"backdrop\":\"styles-module__backdrop___--cMp\",\"panel\":\"styles-module__panel___z6xiJ\",\"panelIn\":\"styles-module__panelIn___SmRh6\",\"header\":\"styles-module__header___NkOur\",\"title\":\"styles-module__title___tsKZw\",\"closeBtn\":\"styles-module__closeBtn___-OQ4Y\",\"body\":\"styles-module__body___9pyCP\",\"field\":\"styles-module__field___vnQMl\",\"fieldLabel\":\"styles-module__fieldLabel___2WUKB\",\"toggle\":\"styles-module__toggle___uWsqC\",\"on\":\"styles-module__on___W27kf\",\"toggleThumb\":\"styles-module__toggleThumb___wyckC\",\"colors\":\"styles-module__colors___vgFGZ\",\"colorBtn\":\"styles-module__colorBtn___N7dGu\",\"selected\":\"styles-module__selected___0tVDH\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-settings-panel-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-settings-panel-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\nconst css = \".styles-module__markersLayer___VR1cD svg[fill=none],\\n.styles-module__fixedMarkersLayer___wBuxm svg[fill=none] {\\n fill: none !important;\\n}\\n.styles-module__markersLayer___VR1cD svg[fill=none] :not([fill]),\\n.styles-module__fixedMarkersLayer___wBuxm svg[fill=none] :not([fill]) {\\n fill: none !important;\\n}\\n\\n@keyframes styles-module__fadeIn___PpRqy {\\n from {\\n opacity: 0;\\n }\\n to {\\n opacity: 1;\\n }\\n}\\n@keyframes styles-module__fadeOut___tZb9S {\\n from {\\n opacity: 1;\\n }\\n to {\\n opacity: 0;\\n }\\n}\\n@keyframes styles-module__hoverHighlightIn___ljC4F {\\n from {\\n opacity: 0;\\n transform: scale(0.98);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n@keyframes styles-module__hoverTooltipIn___tncNM {\\n from {\\n opacity: 0;\\n transform: translateY(4px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n@keyframes styles-module__fabEnter___9koyT {\\n from {\\n opacity: 0;\\n transform: scale(0.5);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n.styles-module__fab___6FrCF {\\n position: fixed;\\n bottom: 24px;\\n right: 24px;\\n width: 44px;\\n height: 44px;\\n border-radius: 50%;\\n background: #18181b;\\n color: white;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1);\\n transition: transform 0.15s ease, box-shadow 0.15s ease;\\n z-index: 99999;\\n animation: styles-module__fabEnter___9koyT 0.3s cubic-bezier(0.22, 1, 0.36, 1);\\n touch-action: none;\\n}\\n.styles-module__fab___6FrCF svg {\\n width: 20px;\\n height: 20px;\\n}\\n.styles-module__fab___6FrCF:hover {\\n transform: scale(1.08);\\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2), 0 2px 4px rgba(0, 0, 0, 0.12);\\n}\\n.styles-module__fab___6FrCF:active {\\n transform: scale(0.96);\\n}\\n.styles-module__fab___6FrCF.styles-module__active___X5PRD {\\n background: #dc2626;\\n}\\n\\n.styles-module__hoverHighlight___9kGLL {\\n position: fixed;\\n border: 2px solid rgba(0, 136, 255, 0.5);\\n border-radius: 4px;\\n background-color: rgba(0, 136, 255, 0.04);\\n pointer-events: none !important;\\n box-sizing: border-box;\\n will-change: opacity;\\n z-index: 99997;\\n}\\n.styles-module__hoverHighlight___9kGLL.styles-module__enter___jAi-c {\\n animation: styles-module__hoverHighlightIn___ljC4F 0.12s ease-out forwards;\\n}\\n\\n.styles-module__singleSelectOutline___2meUm {\\n position: fixed;\\n border: 2px solid rgba(0, 136, 255, 0.6);\\n border-radius: 4px;\\n pointer-events: none !important;\\n background-color: rgba(0, 136, 255, 0.05);\\n box-sizing: border-box;\\n will-change: opacity;\\n z-index: 99997;\\n}\\n.styles-module__singleSelectOutline___2meUm.styles-module__enter___jAi-c {\\n animation: styles-module__fadeIn___PpRqy 0.15s ease-out forwards;\\n}\\n\\n.styles-module__hoverTooltip___JE1Bs {\\n position: fixed;\\n font-size: 0.6875rem;\\n font-weight: 500;\\n color: #fff;\\n background: rgba(0, 0, 0, 0.85);\\n padding: 0.35rem 0.6rem;\\n border-radius: 0.375rem;\\n pointer-events: none !important;\\n white-space: nowrap;\\n max-width: 280px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n z-index: 99999;\\n}\\n.styles-module__hoverTooltip___JE1Bs.styles-module__enter___jAi-c {\\n animation: styles-module__hoverTooltipIn___tncNM 0.1s ease-out forwards;\\n}\\n\\n.styles-module__hoverReactPath___wPGYi {\\n font-size: 0.625rem;\\n color: rgba(255, 255, 255, 0.6);\\n margin-bottom: 0.15rem;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__hoverElementName___lNqTP {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__markersLayer___VR1cD {\\n position: absolute;\\n top: 0;\\n left: 0;\\n right: 0;\\n height: 0;\\n z-index: 99998;\\n pointer-events: none;\\n}\\n.styles-module__markersLayer___VR1cD > * {\\n pointer-events: auto;\\n}\\n\\n.styles-module__fixedMarkersLayer___wBuxm {\\n position: fixed;\\n top: 0;\\n left: 0;\\n right: 0;\\n bottom: 0;\\n z-index: 99998;\\n pointer-events: none;\\n}\\n.styles-module__fixedMarkersLayer___wBuxm > * {\\n pointer-events: auto;\\n}\\n\\n.styles-module__contextMenu___nDXft {\\n position: fixed;\\n z-index: 2147483647;\\n background: white;\\n border-radius: 8px;\\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.16), 0 1px 4px rgba(0, 0, 0, 0.08);\\n padding: 4px;\\n min-width: 140px;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n animation: styles-module__fadeIn___PpRqy 0.1s ease-out;\\n}\\n\\n.styles-module__contextMenuItem___69GKu {\\n display: block;\\n width: 100%;\\n padding: 8px 12px;\\n border: none;\\n background: none;\\n font-size: 13px;\\n color: #18181b;\\n text-align: left;\\n cursor: pointer;\\n border-radius: 6px;\\n font-family: inherit;\\n}\\n.styles-module__contextMenuItem___69GKu:hover {\\n background: #f4f4f5;\\n}\\n\\n@keyframes styles-module__toastIn___V382h {\\n from {\\n opacity: 0;\\n transform: translateY(8px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n@keyframes styles-module__toastOut___zlqxG {\\n from {\\n opacity: 1;\\n }\\n to {\\n opacity: 0;\\n }\\n}\\n.styles-module__toast___gV3Sa {\\n position: fixed;\\n bottom: 80px;\\n right: 24px;\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n background: white;\\n border: 1px solid #e5e5e5;\\n border-radius: 8px;\\n padding: 10px 16px;\\n font-size: 13px;\\n font-weight: 500;\\n color: #18181b;\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\\n z-index: 100000;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n animation: styles-module__toastIn___V382h 0.2s ease-out, styles-module__toastOut___zlqxG 0.3s ease-in 2.7s forwards;\\n max-width: 320px;\\n overflow: hidden;\\n white-space: nowrap;\\n text-overflow: ellipsis;\\n}\\n.styles-module__toast___gV3Sa span {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n.styles-module__toast___gV3Sa.styles-module__toastError___Q-8dn {\\n border-color: #fecaca;\\n background: #fef2f2;\\n color: #991b1b;\\n animation: styles-module__toastIn___V382h 0.2s ease-out, styles-module__toastOut___zlqxG 0.3s ease-in 3.7s forwards;\\n}\\n\\n@keyframes styles-module__countdownPulse___ngZrL {\\n 0%, 100% {\\n transform: scale(1);\\n }\\n 50% {\\n transform: scale(1.15);\\n }\\n}\\n.styles-module__countdownOverlay___GruQJ {\\n position: fixed;\\n top: 50%;\\n left: 50%;\\n transform: translate(-50%, -50%);\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 8px;\\n z-index: 100002;\\n pointer-events: auto;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n animation: styles-module__fadeIn___PpRqy 0.2s ease-out;\\n}\\n\\n.styles-module__countdownNumber___VAmkI {\\n width: 72px;\\n height: 72px;\\n border-radius: 50%;\\n background: rgba(24, 24, 27, 0.9);\\n color: #fff;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 28px;\\n font-weight: 700;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\\n animation: styles-module__countdownPulse___ngZrL 1s ease-in-out infinite;\\n}\\n\\n.styles-module__countdownLabel___px-ao {\\n font-size: 13px;\\n font-weight: 500;\\n color: #18181b;\\n background: rgba(255, 255, 255, 0.95);\\n padding: 6px 14px;\\n border-radius: 8px;\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\\n}\\n\\n.styles-module__countdownCancel___8cRgZ {\\n font-size: 12px;\\n color: #6b7280;\\n background: rgba(255, 255, 255, 0.9);\\n border: 1px solid #d1d5db;\\n border-radius: 6px;\\n padding: 4px 12px;\\n cursor: pointer;\\n font-family: inherit;\\n transition: background 0.12s;\\n}\\n.styles-module__countdownCancel___8cRgZ:hover {\\n background: #f3f4f6;\\n}\\n\\nhtml.impakers-selecting {\\n cursor: crosshair !important;\\n}\\nhtml.impakers-selecting * {\\n cursor: crosshair !important;\\n}\";\nconst classNames = {\"markersLayer\":\"styles-module__markersLayer___VR1cD\",\"fixedMarkersLayer\":\"styles-module__fixedMarkersLayer___wBuxm\",\"fab\":\"styles-module__fab___6FrCF\",\"fabEnter\":\"styles-module__fabEnter___9koyT\",\"active\":\"styles-module__active___X5PRD\",\"hoverHighlight\":\"styles-module__hoverHighlight___9kGLL\",\"enter\":\"styles-module__enter___jAi-c\",\"hoverHighlightIn\":\"styles-module__hoverHighlightIn___ljC4F\",\"singleSelectOutline\":\"styles-module__singleSelectOutline___2meUm\",\"fadeIn\":\"styles-module__fadeIn___PpRqy\",\"hoverTooltip\":\"styles-module__hoverTooltip___JE1Bs\",\"hoverTooltipIn\":\"styles-module__hoverTooltipIn___tncNM\",\"hoverReactPath\":\"styles-module__hoverReactPath___wPGYi\",\"hoverElementName\":\"styles-module__hoverElementName___lNqTP\",\"contextMenu\":\"styles-module__contextMenu___nDXft\",\"contextMenuItem\":\"styles-module__contextMenuItem___69GKu\",\"toast\":\"styles-module__toast___gV3Sa\",\"toastIn\":\"styles-module__toastIn___V382h\",\"toastOut\":\"styles-module__toastOut___zlqxG\",\"toastError\":\"styles-module__toastError___Q-8dn\",\"countdownOverlay\":\"styles-module__countdownOverlay___GruQJ\",\"countdownNumber\":\"styles-module__countdownNumber___VAmkI\",\"countdownPulse\":\"styles-module__countdownPulse___ngZrL\",\"countdownLabel\":\"styles-module__countdownLabel___px-ao\",\"countdownCancel\":\"styles-module__countdownCancel___8cRgZ\",\"fadeOut\":\"styles-module__fadeOut___tZb9S\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-debug-widget-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-debug-widget-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\"use client\";\n\nimport React, { useState, useCallback } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { authenticate } from \"../core/auth\";\n\ninterface AuthPromptPortalProps {\n endpoint: string;\n onSuccess: (serviceName: string) => void;\n onClose: () => void;\n}\n\nexport function AuthPromptPortal({ endpoint, onSuccess, onClose }: AuthPromptPortalProps) {\n const [code, setCode] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n if (!code.trim() || loading) return;\n\n setLoading(true);\n setError(null);\n\n try {\n const result = await authenticate(endpoint, code.trim().toUpperCase());\n onSuccess(result.serviceName);\n } catch (err) {\n setError(err instanceof Error ? err.message : \"인증 실패\");\n } finally {\n setLoading(false);\n }\n },\n [code, endpoint, loading, onSuccess],\n );\n\n if (typeof document === \"undefined\") return null;\n\n return createPortal(\n <div data-impakers-debug=\"\" style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontFamily: \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif\",\n }}>\n {/* Backdrop */}\n <div\n onClick={onClose}\n style={{\n position: \"absolute\",\n inset: 0,\n background: \"rgba(0, 0, 0, 0.4)\",\n }}\n />\n\n {/* Modal */}\n <div style={{\n position: \"relative\",\n width: 360,\n background: \"white\",\n borderRadius: 12,\n boxShadow: \"0 16px 48px rgba(0,0,0,0.16)\",\n overflow: \"hidden\",\n }}>\n {/* Header */}\n <div style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: \"16px 20px\",\n borderBottom: \"1px solid #e5e5e5\",\n }}>\n <h3 style={{ fontSize: 15, fontWeight: 600, color: \"#18181b\", margin: 0 }}>\n 피드백 위젯 인증\n </h3>\n <button\n onClick={onClose}\n type=\"button\"\n style={{\n width: 28, height: 28, border: \"none\", background: \"none\",\n cursor: \"pointer\", display: \"flex\", alignItems: \"center\",\n justifyContent: \"center\", borderRadius: 6, color: \"#71717a\",\n }}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Body */}\n <div style={{ padding: 20 }}>\n <p style={{\n fontSize: 13, color: \"#71717a\", textAlign: \"center\",\n marginBottom: 16, lineHeight: 1.5,\n }}>\n 서비스 시크릿 코드를 입력해주세요.<br />\n 코드는 임패커스 OS에서 확인할 수 있습니다.\n </p>\n\n {error && (\n <div style={{\n background: \"#fef2f2\", border: \"1px solid #fecaca\",\n color: \"#dc2626\", padding: \"8px 12px\", borderRadius: 8,\n fontSize: 13, marginBottom: 12,\n }}>\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit}>\n <input\n type=\"text\"\n maxLength={6}\n placeholder=\"A3F9K2\"\n value={code}\n onChange={(e) => setCode(e.target.value.toUpperCase())}\n autoFocus\n autoComplete=\"off\"\n style={{\n width: \"100%\", padding: \"12px 16px\", border: \"1px solid #d4d4d8\",\n borderRadius: 8, fontSize: 24, fontWeight: 600,\n textAlign: \"center\", letterSpacing: 8, textTransform: \"uppercase\",\n outline: \"none\", boxSizing: \"border-box\", fontFamily: \"inherit\",\n color: \"#18181b\",\n }}\n />\n <button\n type=\"submit\"\n disabled={code.trim().length < 6 || loading}\n style={{\n width: \"100%\", marginTop: 16, padding: \"10px 16px\",\n border: \"none\", borderRadius: 8, fontSize: 14, fontWeight: 500,\n cursor: code.trim().length < 6 || loading ? \"not-allowed\" : \"pointer\",\n background: code.trim().length < 6 || loading ? \"#a1a1aa\" : \"#18181b\",\n color: \"white\", fontFamily: \"inherit\",\n }}\n >\n {loading ? \"인증 중...\" : \"인증하기\"}\n </button>\n </form>\n </div>\n </div>\n </div>,\n document.body,\n );\n}\n"],"mappings":"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","names":["useEffect","useState","useCallback","useState","useCallback","useEffect","useRef","createPortal","jsx","jsxs","AnnotationPopupCSS","result","getFiberFromElement","cache","css","classNames","styles_module_default","jsx","jsxs","styles_module_default","useState","useRef","useEffect","useCallback","css","classNames","styles_module_default","jsx","jsxs","useState","useRef","useEffect","styles_module_default","useCallback","useState","useRef","useCallback","useEffect","css","classNames","styles_module_default","Fragment","jsx","jsxs","useState","useRef","useCallback","useEffect","styles_module_default","useState","useCallback","useEffect","useRef","css","classNames","styles_module_default","Fragment","jsx","jsxs","useEffect","styles_module_default","formatFileSize","getFileIcon","formatTime","getInitials","useState","useRef","useCallback","useEffect","jsxs","jsx","styles_module_default","formatTime","getFileIcon","formatFileSize","Fragment","useCallback","createPortal","css","classNames","styles_module_default","jsx","jsxs","useCallback","createPortal","styles_module_default","css","classNames","styles_module_default","Fragment","jsx","jsxs","useState","useRef","useCallback","useEffect","createPortal","styles_module_default","task","useState","useCallback","createPortal","jsx","jsxs","useState","useCallback","createPortal","Fragment","jsx","jsxs","useState","useEffect","useCallback"]}
1
+ {"version":3,"sources":["../src/react.tsx","../src/core/auth.ts","../src/index.ts","../src/components/debug-widget/index.tsx","../src/components/annotation-popup-css/index.tsx","../src/components/annotation-popup-css/styles.module.scss","../src/components/icons.tsx","../src/utils/freeze-animations.ts","../src/utils/element-identification.ts","../src/utils/react-detection.ts","../src/utils/source-location.ts","../src/utils/capture-element.ts","../src/core/collector.ts","../src/core/debug-targets.ts","../src/core/api.ts","../src/core/sourcemap-resolver.ts","../src/components/annotation-marker/styles.module.scss","../src/components/annotation-marker/index.tsx","../src/components/comment-thread/index.tsx","../src/components/comment-thread/styles.module.scss","../src/components/fab-menu/index.tsx","../src/components/fab-menu/styles.module.scss","../src/components/inbox-panel/index.tsx","../src/components/inbox-panel/styles.module.scss","../src/components/settings-panel/index.tsx","../src/core/settings.ts","../src/components/settings-panel/styles.module.scss","../src/components/debug-widget/styles.module.scss","../src/ui/AuthPromptPortal.tsx"],"sourcesContent":["\"use client\";\n\n// =============================================================================\n// @impakers/debug — React Provider\n// =============================================================================\n//\n// Usage:\n// import { ImpakersDebugProvider } from '@impakers/debug/react'\n//\n// <ImpakersDebugProvider\n// endpoint=\"https://impakers-os.vercel.app/api/external/feedback\"\n// getUser={() => ({ id: user.id, name: user.name })}\n// />\n//\n\nimport React, { useEffect, useState, useCallback } from \"react\";\nimport type { ImpakersDebugConfig } from \"./core/types\";\nimport { isAuthenticated } from \"./core/auth\";\nimport { ImpakersDebug } from \"./index\";\nimport { DebugWidget } from \"./components/debug-widget\";\nimport { AuthPromptPortal } from \"./ui/AuthPromptPortal\";\n\n/**\n * React Provider — 클라이언트 프로젝트의 레이아웃에 추가\n *\n * 인증 전: Ctrl+Shift+. (Mac: Cmd+Shift+.) 으로 인증 프롬프트\n * 인증 후: 플로팅 버튼 + DOM 선택 → popover 피드백\n * 숨기기: FAB 우클릭 → \"위젯 숨기기\" / 다시 Ctrl+Shift+. 으로 복원\n */\nexport function ImpakersDebugProvider({ endpoint, getUser }: ImpakersDebugConfig) {\n const [authenticated, setAuthenticated] = useState(false);\n const [showAuth, setShowAuth] = useState(false);\n const [hidden, setHidden] = useState(() => {\n try { return localStorage.getItem(\"impakers-debug-hidden\") === \"1\"; } catch { return false; }\n });\n\n // 클라이언트에서만 인증 상태 확인\n useEffect(() => {\n setAuthenticated(isAuthenticated());\n }, []);\n\n // Vanilla API 이벤트 연결\n useEffect(() => {\n const unsubs = [\n ImpakersDebug._on(\"impakers-debug:show-auth\", () => {\n setShowAuth(true);\n setHidden(false);\n try { localStorage.removeItem(\"impakers-debug-hidden\"); } catch {}\n }),\n ImpakersDebug._on(\"impakers-debug:open\", () => {\n setHidden(false);\n try { localStorage.removeItem(\"impakers-debug-hidden\"); } catch {}\n }),\n ImpakersDebug._on(\"impakers-debug:deactivate\", () => {\n setAuthenticated(false);\n setShowAuth(false);\n }),\n ];\n return () => unsubs.forEach((fn) => fn());\n }, []);\n\n // Ctrl+Shift+. / Cmd+Shift+. 키보드 단축키\n useEffect(() => {\n function handleKeyDown(e: KeyboardEvent) {\n if ((e.ctrlKey || e.metaKey) && e.shiftKey && (e.key === \".\" || e.key === \">\" || e.code === \"Period\")) {\n e.preventDefault();\n\n // 숨겨진 상태면 다시 보이기\n if (hidden) {\n setHidden(false);\n try { localStorage.removeItem(\"impakers-debug-hidden\"); } catch {}\n return;\n }\n\n if (isAuthenticated()) {\n setAuthenticated(true);\n } else {\n setShowAuth((v) => !v);\n }\n }\n }\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [hidden]);\n\n const handleAuthSuccess = useCallback((_serviceName: string) => {\n setAuthenticated(true);\n setShowAuth(false);\n }, []);\n\n const handleAuthClose = useCallback(() => {\n setShowAuth(false);\n }, []);\n\n const handleHide = useCallback(() => {\n setHidden(true);\n try { localStorage.setItem(\"impakers-debug-hidden\", \"1\"); } catch {}\n }, []);\n\n return (\n <>\n {/* 인증된 상태 + 숨겨지지 않은 상태: DOM 선택 위젯 */}\n {authenticated && !hidden && (\n <DebugWidget endpoint={endpoint} getUser={getUser} onHide={handleHide} />\n )}\n\n {/* 미인증 상태: 인증 프롬프트 */}\n {showAuth && !authenticated && (\n <AuthPromptPortal\n endpoint={endpoint}\n onSuccess={handleAuthSuccess}\n onClose={handleAuthClose}\n />\n )}\n </>\n );\n}\n\nexport { ImpakersDebug } from \"./index\";\n","// =============================================================================\n// @impakers/debug — Authentication\n// =============================================================================\n//\n// 시크릿 코드 → JWT 토큰 인증 플로우\n// 토큰은 localStorage에 저장되며, 피드백 전송 시 Authorization 헤더로 전달\n//\n\nimport type { AuthResponse } from \"./types\";\n\nconst STORAGE_KEY = \"impakers-debug-token\";\nconst TOKEN_DATA_KEY = \"impakers-debug-token-data\";\n\n/** 저장된 토큰 데이터 */\ninterface StoredTokenData {\n token: string;\n serviceName: string;\n expiresAt: string;\n}\n\n/** 로컬스토리지에서 토큰 로드 */\nexport function loadToken(): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n const data = localStorage.getItem(TOKEN_DATA_KEY);\n if (!data) return null;\n\n const parsed: StoredTokenData = JSON.parse(data);\n\n // 만료 확인\n if (new Date(parsed.expiresAt) < new Date()) {\n clearToken();\n return null;\n }\n\n return parsed.token;\n } catch {\n return null;\n }\n}\n\n/** 토큰이 유효한지 확인 */\nexport function isAuthenticated(): boolean {\n return loadToken() !== null;\n}\n\n/** 저장된 서비스 이름 */\nexport function getServiceName(): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n const data = localStorage.getItem(TOKEN_DATA_KEY);\n if (!data) return null;\n const parsed: StoredTokenData = JSON.parse(data);\n return parsed.serviceName;\n } catch {\n return null;\n }\n}\n\n/** 인증 토큰 저장 */\nexport function saveToken(authResponse: AuthResponse): void {\n if (typeof window === \"undefined\") return;\n try {\n const data: StoredTokenData = {\n token: authResponse.token,\n serviceName: authResponse.serviceName,\n expiresAt: authResponse.expiresAt,\n };\n localStorage.setItem(TOKEN_DATA_KEY, JSON.stringify(data));\n localStorage.setItem(STORAGE_KEY, authResponse.token);\n } catch {\n // localStorage 불가\n }\n}\n\n/** 인증 토큰 삭제 */\nexport function clearToken(): void {\n if (typeof window === \"undefined\") return;\n try {\n localStorage.removeItem(TOKEN_DATA_KEY);\n localStorage.removeItem(STORAGE_KEY);\n } catch {\n // ignore\n }\n}\n\n/** 시크릿 코드로 인증 요청 */\nexport async function authenticate(\n endpoint: string,\n code: string,\n): Promise<AuthResponse> {\n const domain = window.location.hostname;\n\n const res = await fetch(`${endpoint}/auth`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ code, domain }),\n });\n\n if (!res.ok) {\n const error = await res.json().catch(() => ({ message: \"인증 실패\" }));\n throw new Error(error.message || \"인증 실패\");\n }\n\n const authResponse: AuthResponse = await res.json();\n saveToken(authResponse);\n return authResponse;\n}\n","// =============================================================================\n// @impakers/debug — Vanilla JS API\n// =============================================================================\n//\n// 프레임워크 없이 사용 가능한 정적 API.\n// React Provider를 사용하는 경우 이 모듈 대신 '@impakers/debug/react'를 사용.\n//\n// Usage:\n// import { ImpakersDebug } from '@impakers/debug'\n// ImpakersDebug.showAuth()\n// ImpakersDebug.isActive()\n// ImpakersDebug.deactivate()\n// ImpakersDebug.open()\n//\n\nimport { isAuthenticated, clearToken, loadToken } from \"./core/auth\";\n\nexport type { FeedbackUser, ImpakersDebugConfig } from \"./core/types\";\n\n/**\n * @impakers/debug Vanilla JS API\n *\n * React를 쓰지 않는 환경에서 사용하거나,\n * 프로그래밍 방식으로 위젯을 제어할 때 사용합니다.\n */\nexport class ImpakersDebug {\n private static _eventTarget = typeof EventTarget !== \"undefined\" ? new EventTarget() : null;\n\n /** 인증 프롬프트 띄우기 */\n static showAuth(): void {\n ImpakersDebug._eventTarget?.dispatchEvent(new CustomEvent(\"impakers-debug:show-auth\"));\n }\n\n /** 인증 상태 확인 */\n static isActive(): boolean {\n return isAuthenticated();\n }\n\n /** 로그아웃 (토큰 삭제 + UI 숨김) */\n static deactivate(): void {\n clearToken();\n ImpakersDebug._eventTarget?.dispatchEvent(new CustomEvent(\"impakers-debug:deactivate\"));\n }\n\n /** 피드백 폼 열기 (인증된 상태에서) */\n static open(): void {\n if (!isAuthenticated()) {\n ImpakersDebug.showAuth();\n return;\n }\n ImpakersDebug._eventTarget?.dispatchEvent(new CustomEvent(\"impakers-debug:open\"));\n }\n\n /** 내부 이벤트 리스너 등록 (React Provider에서 사용) */\n static _on(event: string, handler: EventListener): () => void {\n ImpakersDebug._eventTarget?.addEventListener(event, handler);\n return () => ImpakersDebug._eventTarget?.removeEventListener(event, handler);\n }\n}\n","\"use client\";\n\nimport { useState, useCallback, useEffect, useRef, useMemo } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport {\n AnnotationPopupCSS,\n AnnotationPopupCSSHandle,\n} from \"../annotation-popup-css\";\nimport {\n identifyElement,\n getNearbyText,\n getElementClasses,\n getDetailedComputedStyles,\n getForensicComputedStyles,\n getFullElementPath,\n getAccessibilityInfo,\n closestCrossingShadow,\n} from \"../../utils/element-identification\";\nimport { getReactComponentName } from \"../../utils/react-detection\";\nimport { getSourceLocation, findNearestComponentSource, formatSourceLocation } from \"../../utils/source-location\";\nimport { originalSetTimeout } from \"../../utils/freeze-animations\";\nimport { captureFullPage } from \"../../utils/capture-element\";\nimport { collectMetadata } from \"../../core/collector\";\nimport { getRouteDebugTargets, mergeDebugTargets } from \"../../core/debug-targets\";\nimport {\n submitFeedback,\n fetchFeedbacks,\n fetchAllFeedbacks,\n fetchComments,\n postComment,\n uploadFile,\n getCachedSnapshot,\n subscribeCache,\n getCommentsCacheKey,\n getFeedbacksCacheKey,\n getAllFeedbacksCacheKey,\n updateTaskStatus,\n type FeedbackTask,\n type FeedbackComment,\n} from \"../../core/api\";\nimport { resolveSourceString } from \"../../core/sourcemap-resolver\";\nimport type { DebugTarget, FeedbackUser } from \"../../core/types\";\nimport type { Annotation } from \"../../types\";\nimport { AnnotationMarker, PendingMarker } from \"../annotation-marker\";\nimport { CommentThread, type ThreadTask, type CommentData } from \"../comment-thread\";\nimport { FabMenu, type FabMenuItem } from \"../fab-menu\";\nimport { InboxPanel, type InboxItem } from \"../inbox-panel\";\nimport { SettingsPanel } from \"../settings-panel\";\nimport { getServiceName } from \"../../core/auth\";\nimport { loadSettings, saveSettings, type DebugSettings } from \"../../core/settings\";\nimport styles from \"./styles.module.scss\";\n\n// =============================================================================\n// Utils\n// =============================================================================\n\nfunction deepElementFromPoint(x: number, y: number): HTMLElement | null {\n let element = document.elementFromPoint(x, y) as HTMLElement | null;\n if (!element) return null;\n while (element?.shadowRoot) {\n const deeper = element.shadowRoot.elementFromPoint(x, y) as HTMLElement | null;\n if (!deeper || deeper === element) break;\n element = deeper;\n }\n return element;\n}\n\nfunction isElementFixed(element: HTMLElement): boolean {\n let current: HTMLElement | null = element;\n while (current && current !== document.body) {\n const style = window.getComputedStyle(current);\n if (style.position === \"fixed\" || style.position === \"sticky\") return true;\n current = current.parentElement;\n }\n return false;\n}\n\nfunction identifyElementWithReact(element: HTMLElement): {\n name: string;\n elementName: string;\n path: string;\n reactComponents: string | null;\n} {\n const { name: elementName, path } = identifyElement(element);\n const reactInfo = getReactComponentName(element, { mode: \"filtered\" });\n return {\n name: reactInfo.path ? `${reactInfo.path} ${elementName}` : elementName,\n elementName,\n path,\n reactComponents: reactInfo.path,\n };\n}\n\nfunction detectSourceFile(element: Element): string | undefined {\n const result = getSourceLocation(element as HTMLElement);\n const loc = result.found ? result : findNearestComponentSource(element as HTMLElement);\n if (loc.found && loc.source) {\n return formatSourceLocation(loc.source, \"path\");\n }\n return undefined;\n}\n\n/** 여러 소스 파일 후보를 반환 (프로덕션에서 첫 번째 청크가 node_modules일 수 있음) */\nfunction detectSourceFileCandidates(element: Element): string[] {\n const result = getSourceLocation(element as HTMLElement);\n const loc = result.found ? result : findNearestComponentSource(element as HTMLElement);\n if (loc.found && loc.sourceCandidates && loc.sourceCandidates.length > 0) {\n return loc.sourceCandidates.map((s) => formatSourceLocation(s, \"path\"));\n }\n if (loc.found && loc.source) {\n return [formatSourceLocation(loc.source, \"path\")];\n }\n return [];\n}\n\nfunction buildComponentDebugTarget(\n resolvedSource: string,\n componentName?: string | null,\n): DebugTarget | null {\n const match = resolvedSource.match(/^(.+):(\\d+)(?::(\\d+))?$/);\n if (!match) return null;\n\n const [, file, lineStr, columnStr] = match;\n const line = Number.parseInt(lineStr, 10);\n const column = columnStr ? Number.parseInt(columnStr, 10) : undefined;\n if (!file || Number.isNaN(line)) return null;\n\n return {\n kind: \"component\",\n file,\n line,\n column,\n label: componentName || \"Resolved component source\",\n confidence: 0.98,\n reason: \"resolved-from-source-map\",\n };\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\ntype HoverInfo = {\n element: string;\n elementName: string;\n elementPath: string;\n rect: DOMRect | null;\n reactComponents?: string | null;\n};\n\ntype PendingAnnotation = {\n x: number;\n y: number;\n clientY: number;\n element: string;\n elementPath: string;\n selectedText?: string;\n boundingBox?: { x: number; y: number; width: number; height: number };\n nearbyText?: string;\n cssClasses?: string;\n isFixed?: boolean;\n fullPath?: string;\n accessibility?: string;\n computedStyles?: string;\n computedStylesObj?: Record<string, string>;\n nearbyElements?: string;\n reactComponents?: string;\n sourceFile?: string;\n resolvedSource?: string;\n resolvedName?: string;\n targetElement?: HTMLElement;\n};\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport interface DebugWidgetProps {\n endpoint: string;\n getUser?: () => FeedbackUser | null;\n onHide?: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// 라우트별 마커 localStorage 저장/복원\n// ---------------------------------------------------------------------------\n\nconst STORAGE_PREFIX = \"impakers-debug-markers-\";\n\nfunction getRouteKey(): string {\n return STORAGE_PREFIX + window.location.pathname;\n}\n\nfunction loadRouteAnnotations(): Annotation[] {\n try {\n const stored = localStorage.getItem(getRouteKey());\n if (!stored) return [];\n return JSON.parse(stored);\n } catch {\n return [];\n }\n}\n\nfunction saveRouteAnnotations(annotations: Annotation[]): void {\n try {\n if (annotations.length === 0) {\n localStorage.removeItem(getRouteKey());\n } else {\n localStorage.setItem(getRouteKey(), JSON.stringify(annotations));\n }\n } catch {\n // ignore\n }\n}\n\nfunction taskToAnnotation(task: FeedbackTask): Annotation | null {\n if (!task.feedbackMarker) return null;\n return {\n id: task.id,\n x: task.feedbackMarker.x,\n y: task.feedbackMarker.y,\n comment: task.title.replace(/^\\[피드백\\]\\s*/, \"\"),\n element: task.feedbackMarker.element || \"\",\n elementPath: \"\",\n timestamp: new Date(task.createdAt).getTime(),\n isFixed: task.feedbackMarker.isFixed,\n boundingBox: task.feedbackMarker.boundingBox,\n status: task.status as Annotation[\"status\"],\n };\n}\n\nexport function DebugWidget({ endpoint, getUser, onHide }: DebugWidgetProps) {\n const [isActive, setIsActive] = useState(false);\n const [annotations, setAnnotations] = useState<Annotation[]>(() => loadRouteAnnotations());\n const [pendingAnnotation, setPendingAnnotation] = useState<PendingAnnotation | null>(null);\n const [pendingExiting, setPendingExiting] = useState(false);\n const [hoverInfo, setHoverInfo] = useState<HoverInfo | null>(null);\n const [hoverPosition, setHoverPosition] = useState({ x: 0, y: 0 });\n const [animatedMarkers, setAnimatedMarkers] = useState<Set<string>>(new Set());\n const [submitting, setSubmitting] = useState(false);\n const [hoveredMarkerId, setHoveredMarkerId] = useState<string | null>(null);\n const [hoveredTargetElement, setHoveredTargetElement] = useState<HTMLElement | null>(null);\n const [showToast, setShowToast] = useState(false);\n const [toastError, setToastError] = useState<string | null>(null);\n const [activeThread, setActiveThread] = useState<string | null>(null);\n const [threadComments, setThreadComments] = useState<Record<string, CommentData[]>>({});\n const [serverTasks, setServerTasks] = useState<FeedbackTask[]>([]);\n const [allServerTasks, setAllServerTasks] = useState<FeedbackTask[]>([]);\n const [showInbox, setShowInbox] = useState(false);\n const [showSettings, setShowSettings] = useState(false);\n const [settings, setSettings] = useState<DebugSettings>(() => loadSettings());\n const [routePath, setRoutePath] = useState(() => window.location.pathname);\n const [hasHydratedServerTasks, setHasHydratedServerTasks] = useState(false);\n\n const [delayCountdown, setDelayCountdown] = useState<number | null>(null);\n const delayTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const popupRef = useRef<AnnotationPopupCSSHandle>(null);\n const recentlyAddedIdRef = useRef<string | null>(null);\n const justSubmittedRef = useRef(false);\n\n // -------------------------------------------------------------------------\n // FAB menu handler\n // -------------------------------------------------------------------------\n const startDelayedCapture = useCallback(() => {\n setDelayCountdown(3);\n let count = 3;\n const tick = () => {\n count -= 1;\n if (count <= 0) {\n setDelayCountdown(null);\n // 딜레이 후 피드백 모드 활성화\n setIsActive(true);\n document.documentElement.classList.add(\"impakers-selecting\");\n } else {\n setDelayCountdown(count);\n delayTimerRef.current = setTimeout(tick, 1000);\n }\n };\n delayTimerRef.current = setTimeout(tick, 1000);\n }, []);\n\n const handleFabSelect = useCallback((id: string) => {\n if (id === \"comment\") {\n toggleActive();\n } else if (id === \"delay-capture\") {\n startDelayedCapture();\n } else if (id === \"inbox\") {\n setShowInbox(true);\n // All 탭용 전체 피드백 로드\n fetchAllFeedbacks(endpoint, { staleWhileRevalidate: true })\n .then(setAllServerTasks)\n .catch(() => {});\n if (isActive) {\n setIsActive(false);\n document.documentElement.classList.remove(\"impakers-selecting\");\n setHoverInfo(null);\n setPendingAnnotation(null);\n }\n } else if (id === \"settings\") {\n setShowSettings(true);\n }\n }, [isActive, startDelayedCapture]);\n\n const handleSettingsChange = useCallback((newSettings: DebugSettings) => {\n setSettings(newSettings);\n saveSettings(newSettings);\n }, []);\n\n // -------------------------------------------------------------------------\n // Toggle active state\n // -------------------------------------------------------------------------\n const toggleActive = useCallback(() => {\n setIsActive((prev) => {\n const next = !prev;\n if (next) {\n document.documentElement.classList.add(\"impakers-selecting\");\n } else {\n document.documentElement.classList.remove(\"impakers-selecting\");\n setHoverInfo(null);\n setPendingAnnotation(null);\n }\n return next;\n });\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n document.documentElement.classList.remove(\"impakers-selecting\");\n };\n }, []);\n\n // 라우트별 마커 로드 (마운트 시 + 라우트 변경 시)\n useEffect(() => {\n setAnnotations(loadRouteAnnotations());\n\n // SPA 라우트 변경 감지 (pushState/popstate)\n const handleRouteChange = () => {\n setRoutePath(window.location.pathname);\n setAnnotations(loadRouteAnnotations());\n setPendingAnnotation(null);\n setHoverInfo(null);\n };\n window.addEventListener(\"popstate\", handleRouteChange);\n\n // Next.js 등 pushState 감지를 위한 패치\n const originalPushState = history.pushState.bind(history);\n history.pushState = (...args) => {\n originalPushState(...args);\n // pushState 후 약간 딜레이를 줘야 pathname이 갱신됨\n setTimeout(handleRouteChange, 50);\n };\n\n return () => {\n window.removeEventListener(\"popstate\", handleRouteChange);\n history.pushState = originalPushState;\n };\n }, []);\n\n useEffect(() => {\n const cacheKey = getFeedbacksCacheKey(routePath);\n const cached = getCachedSnapshot<FeedbackTask[]>(cacheKey);\n if (cached) {\n setServerTasks(cached);\n setHasHydratedServerTasks(true);\n }\n\n const unsubscribe = subscribeCache<FeedbackTask[]>(cacheKey, (tasks) => {\n setServerTasks(tasks);\n setHasHydratedServerTasks(true);\n });\n\n fetchFeedbacks(endpoint, routePath, { staleWhileRevalidate: true })\n .then((tasks) => {\n setServerTasks(tasks);\n setHasHydratedServerTasks(true);\n })\n .catch(() => {\n // 서버 로드 실패 → localStorage fallback (이미 로드됨)\n });\n\n return unsubscribe;\n }, [endpoint, routePath]);\n\n useEffect(() => {\n if (!hasHydratedServerTasks) return;\n const serverAnnotations = serverTasks\n .map(taskToAnnotation)\n .filter((annotation): annotation is Annotation => annotation !== null);\n setAnnotations(serverAnnotations);\n saveRouteAnnotations(serverAnnotations);\n }, [serverTasks, hasHydratedServerTasks]);\n\n // annotations 변경 시 localStorage 저장 (초기 마운트 skip)\n const isInitialMount = useRef(true);\n useEffect(() => {\n if (isInitialMount.current) {\n isInitialMount.current = false;\n return;\n }\n saveRouteAnnotations(annotations);\n }, [annotations]);\n\n // Escape key: popover 닫기 → 선택모드 해제 (2단계)\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n\n // inbox 열려있으면 닫기\n if (showInbox) {\n setShowInbox(false);\n return;\n }\n\n // pending annotation 있으면 popover 닫기\n if (pendingAnnotation) {\n e.preventDefault();\n setPendingExiting(true);\n originalSetTimeout(() => {\n setPendingAnnotation(null);\n setPendingExiting(false);\n }, 150);\n return;\n }\n\n // 선택 모드면 해제\n if (isActive) {\n e.preventDefault();\n setIsActive(false);\n document.documentElement.classList.remove(\"impakers-selecting\");\n setHoverInfo(null);\n }\n };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [showInbox, pendingAnnotation, isActive]);\n\n // -------------------------------------------------------------------------\n // Mouse move — hover highlight\n // -------------------------------------------------------------------------\n useEffect(() => {\n if (!isActive || pendingAnnotation) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n const target = (e.composedPath()[0] || e.target) as HTMLElement;\n if (closestCrossingShadow(target, \"[data-impakers-debug]\")) {\n setHoverInfo(null);\n return;\n }\n\n const elementUnder = deepElementFromPoint(e.clientX, e.clientY);\n if (!elementUnder || closestCrossingShadow(elementUnder, \"[data-impakers-debug]\")) {\n setHoverInfo(null);\n return;\n }\n\n const { name, elementName, path, reactComponents } = identifyElementWithReact(elementUnder);\n const rect = elementUnder.getBoundingClientRect();\n\n setHoverInfo({ element: name, elementName, elementPath: path, rect, reactComponents });\n setHoverPosition({ x: e.clientX, y: e.clientY });\n };\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n return () => document.removeEventListener(\"mousemove\", handleMouseMove);\n }, [isActive, pendingAnnotation]);\n\n // -------------------------------------------------------------------------\n // Click — select element\n // -------------------------------------------------------------------------\n useEffect(() => {\n if (!isActive) return;\n\n const handleClick = (e: MouseEvent) => {\n if (justSubmittedRef.current) return;\n const target = (e.composedPath()[0] || e.target) as HTMLElement;\n\n // 우리 UI 요소 클릭은 무시 (FAB, popup, marker 등)\n if (closestCrossingShadow(target, \"[data-impakers-debug]\")) return;\n if (closestCrossingShadow(target, \"[data-annotation-popup]\")) return;\n if (closestCrossingShadow(target, \"[data-annotation-marker]\")) return;\n\n // 이미 pending annotation이 있으면 shake로 알림\n if (pendingAnnotation) {\n e.preventDefault();\n e.stopPropagation();\n popupRef.current?.shake();\n return;\n }\n\n // 인터랙티브 요소 클릭 차단 (피드백 모드에서 네비게이션 방지)\n e.preventDefault();\n e.stopPropagation();\n\n const elementUnder = deepElementFromPoint(e.clientX, e.clientY);\n if (!elementUnder) return;\n\n const { name, path, reactComponents } = identifyElementWithReact(elementUnder);\n const rect = elementUnder.getBoundingClientRect();\n const x = (e.clientX / window.innerWidth) * 100;\n const isFixed = isElementFixed(elementUnder);\n const y = isFixed ? e.clientY : e.clientY + window.scrollY;\n\n const selection = window.getSelection();\n let selectedText: string | undefined;\n if (selection && selection.toString().trim().length > 0) {\n selectedText = selection.toString().trim().slice(0, 500);\n }\n\n const computedStylesObj = getDetailedComputedStyles(elementUnder);\n const computedStylesStr = getForensicComputedStyles(elementUnder);\n\n setPendingAnnotation({\n x,\n y,\n clientY: e.clientY,\n element: name,\n elementPath: path,\n selectedText,\n boundingBox: {\n x: rect.left,\n y: isFixed ? rect.top : rect.top + window.scrollY,\n width: rect.width,\n height: rect.height,\n },\n nearbyText: getNearbyText(elementUnder),\n cssClasses: getElementClasses(elementUnder),\n isFixed,\n fullPath: getFullElementPath(elementUnder),\n accessibility: getAccessibilityInfo(elementUnder),\n computedStyles: computedStylesStr,\n computedStylesObj,\n reactComponents: reactComponents ?? undefined,\n sourceFile: detectSourceFile(elementUnder),\n targetElement: elementUnder,\n });\n setHoverInfo(null);\n\n // 비동기 소스맵 resolve (popover 표시 후 업데이트)\n // 여러 후보를 시도하여 node_modules가 아닌 결과를 찾음\n const candidates = detectSourceFileCandidates(elementUnder);\n const chunkCandidates = candidates.filter((c) => c.includes(\"/chunks/\"));\n if (chunkCandidates.length > 0) {\n (async () => {\n for (const candidate of chunkCandidates) {\n try {\n const resolved = await resolveSourceString(candidate);\n if (resolved) {\n setPendingAnnotation((prev) =>\n prev ? {\n ...prev,\n resolvedSource: `${resolved.source}:${resolved.line}`,\n resolvedName: resolved.name ?? undefined,\n } : prev\n );\n break; // 첫 성공에서 멈춤\n }\n } catch {\n // 다음 후보 시도\n }\n }\n })();\n }\n };\n\n // Capture phase로 인터셉트\n document.addEventListener(\"click\", handleClick, true);\n return () => document.removeEventListener(\"click\", handleClick, true);\n }, [isActive, pendingAnnotation]);\n\n const showErrorToast = useCallback((msg: string) => {\n setToastError(msg);\n originalSetTimeout(() => setToastError(null), 4000);\n }, []);\n\n // -------------------------------------------------------------------------\n // Submit feedback — annotation comment → server\n // -------------------------------------------------------------------------\n const addAnnotation = useCallback(\n async (comment: string) => {\n if (!pendingAnnotation || submitting) return;\n setSubmitting(true);\n\n try {\n const metadata = collectMetadata(getUser);\n\n // 스크린샷 캡처 (위젯 숨기고 캡처)\n const screenshot = await captureFullPage();\n\n // 소스맵으로 원본 소스 파일 resolve 시도\n // 비동기 resolve가 이미 완료됐으면 resolvedSource 사용\n let resolvedSource = pendingAnnotation.resolvedSource || pendingAnnotation.sourceFile || \"\";\n let resolvedName: string | null = pendingAnnotation.resolvedName || null;\n // 아직 resolve 안 됐으면 시도\n if (!pendingAnnotation.resolvedSource && pendingAnnotation.sourceFile?.includes(\"/chunks/\")) {\n try {\n const resolved = await resolveSourceString(pendingAnnotation.sourceFile);\n if (resolved) {\n resolvedSource = `${resolved.source}:${resolved.line}:${resolved.column}`;\n resolvedName = resolved.name;\n }\n } catch {\n // resolve 실패 시 원본 유지\n }\n }\n\n const routeMatch = await getRouteDebugTargets(window.location.pathname);\n const componentTarget = resolvedSource && !resolvedSource.includes(\"/chunks/\")\n ? buildComponentDebugTarget(resolvedSource, resolvedName)\n : null;\n const debugTargets = mergeDebugTargets(\n componentTarget ? [componentTarget] : undefined,\n routeMatch?.targets,\n );\n if (debugTargets.length > 0) {\n metadata.debugTargets = debugTargets;\n }\n if (routeMatch?.context) {\n metadata.routeDebug = routeMatch.context;\n }\n\n // debugInfo 조합 (별도 컬럼으로 저장 — 마크다운 형식)\n const debugParts: string[] = [];\n\n // 피드백 제목\n debugParts.push(`## 피드백 ${comment}`);\n\n // 디버깅 타겟 파일\n if (debugTargets.length > 0) {\n debugParts.push(\"\");\n debugParts.push(\"---\");\n debugParts.push(\"\");\n debugParts.push(\"**디버깅 타겟 파일**:\");\n debugTargets.forEach((target) => {\n const suffix = target.line ? `:${target.line}${typeof target.column === \"number\" ? `:${target.column}` : \"\"}` : \"\";\n debugParts.push(`- [${target.kind}] \\`${target.file}${suffix}\\` (${target.reason})`);\n });\n }\n\n // 요소 정보\n const elementInfo: string[] = [];\n if (pendingAnnotation.element) {\n elementInfo.push(`**선택된 요소**: ${pendingAnnotation.element}`);\n }\n if (pendingAnnotation.elementPath) {\n elementInfo.push(`**DOM 경로**: \\`${pendingAnnotation.elementPath}\\``);\n }\n if (pendingAnnotation.selectedText) {\n elementInfo.push(`**선택된 텍스트**: \"${pendingAnnotation.selectedText}\"`);\n }\n if (pendingAnnotation.reactComponents?.trim()) {\n elementInfo.push(`**React 컴포넌트**: ${pendingAnnotation.reactComponents}`);\n } else if (resolvedName) {\n elementInfo.push(`**컴포넌트/함수**: ${resolvedName}`);\n }\n if (resolvedSource && !resolvedSource.includes(\"/chunks/\")) {\n elementInfo.push(`**소스 파일**: \\`${resolvedSource}\\``);\n }\n if (pendingAnnotation.cssClasses) {\n elementInfo.push(`**CSS 클래스**: \\`${pendingAnnotation.cssClasses}\\``);\n }\n if (pendingAnnotation.nearbyText) {\n elementInfo.push(`**주변 텍스트**: ${pendingAnnotation.nearbyText}`);\n }\n if (pendingAnnotation.accessibility) {\n elementInfo.push(`**접근성**: ${pendingAnnotation.accessibility}`);\n }\n if (elementInfo.length > 0) {\n debugParts.push(\"\");\n debugParts.push(\"---\");\n debugParts.push(\"\");\n elementInfo.forEach((line) => debugParts.push(line));\n }\n\n // 에러 로그\n if (metadata.consoleErrors?.length) {\n debugParts.push(\"\");\n debugParts.push(\"---\");\n debugParts.push(\"\");\n debugParts.push(\"**최근 콘솔 에러**:\");\n metadata.consoleErrors.slice(-10).forEach((e) => debugParts.push(`- \\`${e.slice(0, 200)}\\``));\n }\n\n // 최근 콘솔 로그 (에러/경고)\n if (metadata.consoleLogs?.length) {\n const recentLogs = metadata.consoleLogs\n .filter((l) => l.level === \"error\" || l.level === \"warn\")\n .slice(-10);\n if (recentLogs.length > 0) {\n debugParts.push(\"\");\n debugParts.push(\"**최근 콘솔 로그**:\");\n recentLogs.forEach((l) => debugParts.push(`- [${l.level}] \\`${l.message.slice(0, 200)}\\``));\n }\n }\n\n // 환경 정보\n debugParts.push(\"\");\n debugParts.push(\"---\");\n debugParts.push(\"\");\n debugParts.push(\"## 환경 정보\");\n debugParts.push(\"\");\n debugParts.push(`- **URL**: ${metadata.url}`);\n debugParts.push(`- **시점**: ${new Date(metadata.timestamp).toLocaleString(\"ko-KR\")}`);\n debugParts.push(`- **브라우저**: ${metadata.browser}`);\n debugParts.push(`- **화면**: ${metadata.viewport} (@${metadata.pixelRatio}x)`);\n debugParts.push(`- **언어**: ${metadata.language}`);\n if (metadata.user?.name) {\n debugParts.push(`- **사용자**: ${metadata.user.name}`);\n }\n\n // 성능\n if (metadata.performance && Object.keys(metadata.performance).length > 0) {\n debugParts.push(\"\");\n debugParts.push(\"---\");\n debugParts.push(\"\");\n debugParts.push(\"## 성능\");\n debugParts.push(\"\");\n debugParts.push(\"| 항목 | 값 |\");\n debugParts.push(\"|------|-----|\");\n const perfLabels: Record<string, string> = {\n pageLoadTime: \"페이지 로딩\",\n domContentLoaded: \"DOM 로드\",\n ttfb: \"TTFB\",\n firstContentfulPaint: \"FCP\",\n usedJSHeapMB: \"메모리 사용\",\n totalJSHeapMB: \"메모리 전체\",\n };\n for (const [key, value] of Object.entries(metadata.performance)) {\n const label = perfLabels[key] || key;\n const unit = key.includes(\"Heap\") ? \"MB\" : \"ms\";\n debugParts.push(`| ${label} | ${value}${unit} |`);\n }\n }\n\n const debugInfoContent = debugParts.join(\"\\n\");\n\n const result = await submitFeedback(endpoint, {\n title: comment.slice(0, 100),\n description: \"\",\n priority: \"medium\",\n metadata,\n debugInfo: debugInfoContent,\n debug_info: debugInfoContent,\n screenshot,\n feedbackUrl: window.location.pathname,\n feedbackMarker: {\n x: pendingAnnotation.x,\n y: pendingAnnotation.y,\n isFixed: pendingAnnotation.isFixed || false,\n element: pendingAnnotation.element,\n boundingBox: pendingAnnotation.boundingBox,\n },\n authorName: getUser?.()?.name ? String(getUser()!.name) : undefined,\n });\n\n // 성공 토스트\n setShowToast(true);\n originalSetTimeout(() => setShowToast(false), 3000);\n\n const newTaskId = result.taskId || null;\n recentlyAddedIdRef.current = newTaskId;\n originalSetTimeout(() => {\n recentlyAddedIdRef.current = null;\n }, 300);\n originalSetTimeout(() => {\n if (!newTaskId) return;\n setAnimatedMarkers((prev) => new Set(prev).add(newTaskId));\n }, 250);\n\n setPendingExiting(true);\n originalSetTimeout(() => {\n setPendingAnnotation(null);\n setPendingExiting(false);\n // 피드백 제출 완료 → 선택 모드 해제\n setIsActive(false);\n document.documentElement.classList.remove(\"impakers-selecting\");\n justSubmittedRef.current = true;\n setTimeout(() => { justSubmittedRef.current = false; }, 300);\n }, 150);\n\n window.getSelection()?.removeAllRanges();\n } catch (err: any) {\n const msg = err?.message || \"피드백 전송 실패\";\n showErrorToast(msg);\n console.error(\"[@impakers/debug] 피드백 전송 실패:\", err);\n } finally {\n setSubmitting(false);\n }\n },\n [pendingAnnotation, submitting, endpoint, getUser, showErrorToast],\n );\n\n const cancelAnnotation = useCallback(() => {\n setPendingExiting(true);\n originalSetTimeout(() => {\n setPendingAnnotation(null);\n setPendingExiting(false);\n setIsActive(false);\n document.documentElement.classList.remove(\"impakers-selecting\");\n justSubmittedRef.current = true;\n setTimeout(() => { justSubmittedRef.current = false; }, 300);\n }, 150);\n }, []);\n\n // -------------------------------------------------------------------------\n // Marker click → open comment thread\n // -------------------------------------------------------------------------\n const handleMarkerClick = useCallback((annotation: Annotation) => {\n const newId = annotation.id;\n setActiveThread((prev) => {\n if (prev === newId) return null;\n return newId;\n });\n }, []);\n\n useEffect(() => {\n if (!activeThread) return;\n\n const cacheKey = getCommentsCacheKey(activeThread);\n const cached = getCachedSnapshot<FeedbackComment[]>(cacheKey);\n if (cached) {\n setThreadComments((prev) => ({ ...prev, [activeThread]: cached }));\n }\n\n const unsubscribe = subscribeCache<FeedbackComment[]>(cacheKey, (comments) => {\n setThreadComments((prev) => ({ ...prev, [activeThread]: comments }));\n });\n\n fetchComments(endpoint, activeThread, { staleWhileRevalidate: true }).catch(() => {});\n return unsubscribe;\n }, [activeThread, endpoint]);\n\n const handleThreadReply = useCallback(async (taskId: string, content: string, screenshot?: string, file?: File) => {\n const authorName = getUser?.()?.name ? String(getUser()!.name) : \"익명\";\n const authorId = getUser?.()?.id ? String(getUser()!.id) : undefined;\n\n try {\n let fileResult;\n if (file) {\n try {\n fileResult = await uploadFile(endpoint, file, \"comment\", taskId);\n } catch (uploadErr: any) {\n const msg = uploadErr?.message || \"파일 업로드 실패\";\n showErrorToast(msg);\n console.error(\"[@impakers/debug] 파일 업로드 실패:\", uploadErr);\n // 파일 업로드 실패해도 텍스트/스크린샷 코멘트는 전송\n }\n }\n\n await postComment(endpoint, taskId, content, authorName, authorId, screenshot, fileResult);\n } catch (err: any) {\n const msg = err?.message || \"코멘트 전송 실패\";\n showErrorToast(msg);\n console.error(\"[@impakers/debug] 코멘트 전송 실패:\", err);\n }\n }, [getUser, endpoint, showErrorToast]);\n\n const handleThreadClose = useCallback(() => {\n setActiveThread(null);\n }, []);\n\n // -------------------------------------------------------------------------\n // Marker hover — show element outline\n // -------------------------------------------------------------------------\n const handleMarkerHover = useCallback((annotation: Annotation | null) => {\n if (!annotation) {\n setHoveredMarkerId(null);\n setHoveredTargetElement(null);\n return;\n }\n setHoveredMarkerId(annotation.id);\n\n if (annotation.boundingBox) {\n const bb = annotation.boundingBox;\n const centerX = bb.x + bb.width / 2;\n const centerY = annotation.isFixed\n ? bb.y + bb.height / 2\n : bb.y + bb.height / 2 - window.scrollY;\n const el = deepElementFromPoint(centerX, centerY);\n if (el) {\n const elRect = el.getBoundingClientRect();\n const widthRatio = elRect.width / bb.width;\n const heightRatio = elRect.height / bb.height;\n if (widthRatio >= 0.5 && heightRatio >= 0.5) {\n setHoveredTargetElement(el);\n return;\n }\n }\n }\n setHoveredTargetElement(null);\n }, []);\n\n // -------------------------------------------------------------------------\n // Popup positioning\n // -------------------------------------------------------------------------\n const getPopupPosition = useCallback(() => {\n if (!pendingAnnotation) return { left: 0, top: 0 };\n\n const markerX = (pendingAnnotation.x / 100) * window.innerWidth;\n const markerY = pendingAnnotation.isFixed\n ? pendingAnnotation.y\n : pendingAnnotation.y - window.scrollY;\n\n const left = Math.max(160, Math.min(window.innerWidth - 160, markerX));\n\n if (markerY > window.innerHeight - 290) {\n return { left, bottom: window.innerHeight - markerY + 20 };\n }\n return { left, top: markerY + 20 };\n }, [pendingAnnotation]);\n\n // -------------------------------------------------------------------------\n // Render\n // -------------------------------------------------------------------------\n if (typeof document === \"undefined\") return null;\n\n const popupPos = getPopupPosition();\n const hoveredRect = hoveredTargetElement?.getBoundingClientRect();\n\n // FAB menu items\n const fabItems: FabMenuItem[] = [\n {\n id: \"comment\",\n label: \"피드백\",\n active: isActive,\n icon: (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z\" />\n </svg>\n ),\n },\n {\n id: \"delay-capture\",\n label: \"딜레이 캡처\",\n icon: (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 16 14\" />\n </svg>\n ),\n },\n {\n id: \"inbox\",\n label: \"Inbox\",\n badge: annotations.length || undefined,\n icon: (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"22 12 16 12 14 15 10 15 8 12 2 12\" />\n <path d=\"M5.45 5.11L2 12v6a2 2 0 002 2h16a2 2 0 002-2v-6l-3.45-6.89A2 2 0 0016.76 4H7.24a2 2 0 00-1.79 1.11z\" />\n </svg>\n ),\n },\n {\n id: \"settings\",\n label: \"설정\",\n icon: (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z\" />\n </svg>\n ),\n },\n ];\n\n // Inbox items from local annotations\n const currentPath = routePath;\n // 설정에 따라 마커 필터링\n const currentUserName = getUser?.()?.name ? String(getUser()!.name) : null;\n const visibleAnnotations = useMemo(() => {\n return annotations.filter((a) => {\n const task = serverTasks.find((t) => t.id === a.id);\n if (settings.hideDoneMarkers && (a.status === \"done\" || a.status === \"resolved\")) return false;\n if (settings.showOnlyMine && task?.authorName && currentUserName && task.authorName !== currentUserName) return false;\n return true;\n });\n }, [annotations, serverTasks, settings.hideDoneMarkers, settings.showOnlyMine, currentUserName]);\n\n const toInboxItem = (task: FeedbackTask, fallbackUrl: string): InboxItem => ({\n id: task.id,\n title: task.title || \"피드백\",\n status: task.status,\n priority: task.priority,\n authorName: task.authorName || \"익명\",\n feedbackUrl: task.feedbackUrl || fallbackUrl,\n createdAt: task.createdAt,\n startedAt: task.startedAt,\n completedAt: task.completedAt,\n commentCount: task.commentCount || 0,\n });\n\n const allInboxItems: InboxItem[] = serverTasks.map((t) => toInboxItem(t, currentPath));\n const allRouteItems: InboxItem[] = allServerTasks.map((t) => toInboxItem(t, \"\"));\n\n return createPortal(\n <div data-impakers-debug=\"\">\n {/* FAB Menu */}\n <FabMenu\n items={fabItems}\n onSelect={handleFabSelect}\n onHide={onHide}\n onDoubleTap={toggleActive}\n />\n\n {/* Inbox Panel */}\n {showInbox && (\n <InboxPanel\n pageItems={allInboxItems}\n allItems={allRouteItems}\n currentPath={currentPath}\n serviceName={getServiceName() || undefined}\n endpoint={endpoint}\n currentUserName={getUser?.()?.name ? String(getUser()!.name) : \"익명\"}\n currentUserId={getUser?.()?.id ? String(getUser()!.id) : undefined}\n onClose={() => setShowInbox(false)}\n />\n )}\n\n {/* Settings Panel */}\n {showSettings && (\n <SettingsPanel\n settings={settings}\n onChange={handleSettingsChange}\n onClose={() => setShowSettings(false)}\n />\n )}\n\n {/* Hover highlight + tooltip */}\n {isActive && (\n <>\n {/* Hover highlight box */}\n {hoverInfo?.rect && !pendingAnnotation && (\n <div\n className={`${styles.hoverHighlight} ${styles.enter}`}\n style={{\n left: hoverInfo.rect.left,\n top: hoverInfo.rect.top,\n width: hoverInfo.rect.width,\n height: hoverInfo.rect.height,\n }}\n />\n )}\n\n {/* Hover tooltip */}\n {hoverInfo && !pendingAnnotation && (\n <div\n className={`${styles.hoverTooltip} ${styles.enter}`}\n style={{\n left: Math.min(hoverPosition.x + 14, window.innerWidth - 200),\n top: hoverPosition.y + 14,\n }}\n >\n {hoverInfo.reactComponents && (\n <div className={styles.hoverReactPath}>{hoverInfo.reactComponents}</div>\n )}\n <div className={styles.hoverElementName}>{hoverInfo.elementName}</div>\n </div>\n )}\n\n {/* Selected element outline (when hovering marker) */}\n {hoveredRect && hoveredMarkerId && (\n <div\n className={`${styles.singleSelectOutline} ${styles.enter}`}\n style={{\n left: hoveredRect.left,\n top: hoveredRect.top,\n width: hoveredRect.width,\n height: hoveredRect.height,\n }}\n />\n )}\n\n {/* Pending annotation element outline */}\n {pendingAnnotation?.targetElement && (() => {\n const r = pendingAnnotation.targetElement!.getBoundingClientRect();\n return (\n <div\n className={`${styles.singleSelectOutline} ${styles.enter}`}\n style={{ left: r.left, top: r.top, width: r.width, height: r.height }}\n />\n );\n })()}\n </>\n )}\n\n {/* Markers layer (scroll with page) */}\n <div className={styles.markersLayer} data-impakers-debug=\"\" style={{ display: settings.markersVisible ? undefined : \"none\" }}>\n {visibleAnnotations\n .filter((a) => !a.isFixed)\n .map((annotation, i) => (\n <AnnotationMarker\n key={annotation.id}\n annotation={annotation}\n layerIndex={i}\n isAnimated={animatedMarkers.has(annotation.id)}\n isHovered={hoveredMarkerId === annotation.id}\n isDeleting={false}\n markerClickBehavior=\"edit\"\n accentColor={settings.markerColor}\n onHover={() => handleMarkerHover(annotation)}\n onHoverEnd={() => handleMarkerHover(null)}\n onClick={() => handleMarkerClick(annotation)}\n onContextMenu={() => {}}\n />\n ))}\n </div>\n\n {/* Fixed markers layer */}\n <div className={styles.fixedMarkersLayer} data-impakers-debug=\"\" style={{ display: settings.markersVisible ? undefined : \"none\" }}>\n {visibleAnnotations\n .filter((a) => a.isFixed)\n .map((annotation, i) => (\n <AnnotationMarker\n key={annotation.id}\n annotation={annotation}\n layerIndex={i}\n isAnimated={animatedMarkers.has(annotation.id)}\n isHovered={hoveredMarkerId === annotation.id}\n isDeleting={false}\n markerClickBehavior=\"edit\"\n accentColor={settings.markerColor}\n onHover={() => handleMarkerHover(annotation)}\n onHoverEnd={() => handleMarkerHover(null)}\n onClick={() => handleMarkerClick(annotation)}\n onContextMenu={() => {}}\n />\n ))}\n\n {/* Pending marker */}\n {pendingAnnotation && (\n <PendingMarker\n x={pendingAnnotation.x}\n y={pendingAnnotation.clientY}\n isMultiSelect={false}\n accentColor={settings.markerColor}\n />\n )}\n </div>\n\n {/* Annotation popup */}\n {pendingAnnotation && (\n <AnnotationPopupCSS\n ref={popupRef}\n element={pendingAnnotation.resolvedSource || pendingAnnotation.resolvedName || pendingAnnotation.element}\n selectedText={pendingAnnotation.selectedText}\n isExiting={pendingExiting}\n style={{\n position: \"fixed\",\n left: popupPos.left,\n ...(\"top\" in popupPos ? { top: popupPos.top } : {}),\n ...(\"bottom\" in popupPos ? { bottom: (popupPos as any).bottom } : {}),\n transform: \"translateX(-50%)\",\n zIndex: 100001,\n }}\n onSubmit={addAnnotation}\n onCancel={cancelAnnotation}\n />\n )}\n\n {/* Comment thread */}\n {activeThread && (() => {\n const annotation = annotations.find((a) => a.id === activeThread);\n const taskData = serverTasks.find((task) => task.id === activeThread);\n if (!annotation) return null;\n\n const markerX = (annotation.x / 100) * window.innerWidth;\n const markerY = annotation.isFixed\n ? annotation.y\n : annotation.y - window.scrollY;\n\n const threadLeft = Math.max(10, Math.min(markerX + 20, window.innerWidth - 360));\n const threadTop = Math.max(10, Math.min(markerY, window.innerHeight - 400));\n\n const task: ThreadTask = {\n id: annotation.id,\n title: taskData?.title || annotation.comment || \"피드백\",\n status: taskData?.status || \"todo\",\n authorName: taskData?.authorName || undefined,\n createdAt: taskData?.createdAt || new Date(annotation.timestamp).toISOString(),\n comments: threadComments[annotation.id] || [],\n };\n\n return (\n <CommentThread\n task={task}\n currentUserName={getUser?.()?.name ? String(getUser()!.name) : \"익명\"}\n currentUserId={getUser?.()?.id ? String(getUser()!.id) : undefined}\n left={threadLeft}\n top={threadTop}\n onClose={handleThreadClose}\n onReply={handleThreadReply}\n />\n );\n })()}\n\n {/* 딜레이 캡처 카운트다운 */}\n {delayCountdown !== null && (\n <div className={styles.countdownOverlay} data-impakers-debug=\"\">\n <div className={styles.countdownNumber}>{delayCountdown}</div>\n <div className={styles.countdownLabel}>피드백 모드 활성화까지...</div>\n <button\n className={styles.countdownCancel}\n onClick={() => {\n if (delayTimerRef.current) clearTimeout(delayTimerRef.current);\n setDelayCountdown(null);\n }}\n type=\"button\"\n >\n 취소\n </button>\n </div>\n )}\n\n {/* 성공 토스트 */}\n {showToast && (\n <div className={styles.toast} data-impakers-debug=\"\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#16a34a\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n <span>\n 태스크 생성이 완료되었습니다\n </span>\n </div>\n )}\n\n {/* 에러 토스트 */}\n {toastError && (\n <div className={`${styles.toast} ${styles.toastError}`} data-impakers-debug=\"\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ef4444\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\n </svg>\n <span>{toastError}</span>\n </div>\n )}\n </div>,\n document.body,\n );\n}\n","\"use client\";\n\nimport { useState, useRef, useEffect, useCallback, forwardRef, useImperativeHandle } from \"react\";\nimport styles from \"./styles.module.scss\";\nimport { IconTrash } from \"../icons\";\nimport { originalSetTimeout } from \"../../utils/freeze-animations\";\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\n/** Focus an element while temporarily blocking focus-trap libraries (e.g. Radix\n * FocusScope) from reclaiming focus via focusin/focusout handlers. */\nfunction focusBypassingTraps(el: HTMLElement | null) {\n if (!el) return;\n const trap = (e: Event) => e.stopImmediatePropagation();\n document.addEventListener(\"focusin\", trap, true);\n document.addEventListener(\"focusout\", trap, true);\n try {\n el.focus();\n } finally {\n document.removeEventListener(\"focusin\", trap, true);\n document.removeEventListener(\"focusout\", trap, true);\n }\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface AnnotationPopupCSSProps {\n /** Element name to display in header */\n element: string;\n /** Optional timestamp display (e.g., \"@ 1.23s\" for animation feedback) */\n timestamp?: string;\n /** Optional selected/highlighted text */\n selectedText?: string;\n /** Placeholder text for the textarea */\n placeholder?: string;\n /** Initial value for textarea (for edit mode) */\n initialValue?: string;\n /** Label for submit button (default: \"Add\") */\n submitLabel?: string;\n /** Called when annotation is submitted with text */\n onSubmit: (text: string) => void;\n /** Called when popup is cancelled/dismissed */\n onCancel: () => void;\n /** Called when delete button is clicked (only shown if provided) */\n onDelete?: () => void;\n /** Position styles (left, top) */\n style?: React.CSSProperties;\n /** Custom color for submit button and textarea focus (hex) */\n accentColor?: string;\n /** External exit state (parent controls exit animation) */\n isExiting?: boolean;\n /** Light mode styling */\n lightMode?: boolean;\n /** Computed styles for the selected element */\n computedStyles?: Record<string, string>;\n}\n\nexport interface AnnotationPopupCSSHandle {\n /** Shake the popup (e.g., when user clicks outside) */\n shake: () => void;\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport const AnnotationPopupCSS = forwardRef<AnnotationPopupCSSHandle, AnnotationPopupCSSProps>(\n function AnnotationPopupCSS(\n {\n element,\n timestamp,\n selectedText,\n placeholder = \"What should change?\",\n initialValue = \"\",\n submitLabel = \"Add\",\n onSubmit,\n onCancel,\n onDelete,\n style,\n accentColor = \"#3c82f7\",\n isExiting = false,\n lightMode = false,\n computedStyles,\n },\n ref\n ) {\n const [text, setText] = useState(initialValue);\n const [isShaking, setIsShaking] = useState(false);\n const [animState, setAnimState] = useState<\"initial\" | \"enter\" | \"entered\" | \"exit\">(\"initial\");\n const [isFocused, setIsFocused] = useState(false);\n const [isStylesExpanded, setIsStylesExpanded] = useState(false); // Computed styles accordion state\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const popupRef = useRef<HTMLDivElement>(null);\n const cancelTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const shakeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Sync with parent exit state\n useEffect(() => {\n if (isExiting && animState !== \"exit\") {\n setAnimState(\"exit\");\n }\n }, [isExiting, animState]);\n\n // Animate in on mount and focus textarea\n useEffect(() => {\n // Start enter animation (use originalSetTimeout to bypass freeze patch)\n originalSetTimeout(() => {\n setAnimState(\"enter\");\n }, 0);\n // Transition to entered state after animation completes\n const enterTimer = originalSetTimeout(() => {\n setAnimState(\"entered\");\n }, 200); // Match animation duration\n const focusTimer = originalSetTimeout(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n focusBypassingTraps(textarea);\n textarea.selectionStart = textarea.selectionEnd = textarea.value.length;\n textarea.scrollTop = textarea.scrollHeight;\n }\n }, 50);\n return () => {\n clearTimeout(enterTimer);\n clearTimeout(focusTimer);\n if (cancelTimerRef.current) clearTimeout(cancelTimerRef.current);\n if (shakeTimerRef.current) clearTimeout(shakeTimerRef.current);\n };\n }, []);\n\n // Shake animation\n const shake = useCallback(() => {\n if (shakeTimerRef.current) clearTimeout(shakeTimerRef.current);\n setIsShaking(true);\n shakeTimerRef.current = originalSetTimeout(() => {\n setIsShaking(false);\n focusBypassingTraps(textareaRef.current);\n }, 250);\n }, []);\n\n // Expose shake to parent via ref\n useImperativeHandle(ref, () => ({\n shake,\n }), [shake]);\n\n // Handle cancel with exit animation\n const handleCancel = useCallback(() => {\n setAnimState(\"exit\");\n cancelTimerRef.current = originalSetTimeout(() => {\n onCancel();\n }, 150); // Match exit animation duration\n }, [onCancel]);\n\n // Handle submit\n const handleSubmit = useCallback(() => {\n if (!text.trim()) return;\n onSubmit(text.trim());\n }, [text, onSubmit]);\n\n // Handle keyboard\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n e.stopPropagation();\n if (e.nativeEvent.isComposing) return;\n if (e.key === \"Enter\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n handleSubmit();\n }\n if (e.key === \"Escape\") {\n handleCancel();\n }\n },\n [handleSubmit, handleCancel]\n );\n\n const popupClassName = [\n styles.popup,\n lightMode ? styles.light : \"\",\n animState === \"enter\" ? styles.enter : \"\",\n animState === \"entered\" ? styles.entered : \"\",\n animState === \"exit\" ? styles.exit : \"\",\n isShaking ? styles.shake : \"\",\n ].filter(Boolean).join(\" \");\n\n return (\n <div\n ref={popupRef}\n className={popupClassName}\n data-annotation-popup\n style={style}\n onClick={(e) => e.stopPropagation()}\n >\n <div className={styles.header}>\n {computedStyles && Object.keys(computedStyles).length > 0 ? (\n <button\n className={styles.headerToggle}\n onClick={() => {\n const wasExpanded = isStylesExpanded;\n setIsStylesExpanded(!isStylesExpanded);\n if (wasExpanded) {\n // Refocus textarea when closing\n originalSetTimeout(() => focusBypassingTraps(textareaRef.current), 0);\n }\n }}\n type=\"button\"\n >\n <svg\n className={`${styles.chevron} ${isStylesExpanded ? styles.expanded : \"\"}`}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M5.5 10.25L9 7.25L5.75 4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span className={styles.element}>{element}</span>\n </button>\n ) : (\n <span className={styles.element}>{element}</span>\n )}\n {timestamp && <span className={styles.timestamp}>{timestamp}</span>}\n </div>\n\n {/* Collapsible computed styles section - uses grid-template-rows for smooth animation */}\n {computedStyles && Object.keys(computedStyles).length > 0 && (\n <div className={`${styles.stylesWrapper} ${isStylesExpanded ? styles.expanded : \"\"}`}>\n <div className={styles.stylesInner}>\n <div className={styles.stylesBlock}>\n {Object.entries(computedStyles).map(([key, value]) => (\n <div key={key} className={styles.styleLine}>\n <span className={styles.styleProperty}>\n {key.replace(/([A-Z])/g, \"-$1\").toLowerCase()}\n </span>\n : <span className={styles.styleValue}>{value}</span>;\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n\n {selectedText && (\n <div className={styles.quote}>\n &ldquo;{selectedText.slice(0, 80)}\n {selectedText.length > 80 ? \"...\" : \"\"}&rdquo;\n </div>\n )}\n\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n style={{ borderColor: isFocused ? accentColor : undefined }}\n placeholder={placeholder}\n value={text}\n onChange={(e) => {\n setText(e.target.value);\n // auto-resize\n const el = e.target;\n el.style.height = \"auto\";\n el.style.height = `${Math.min(el.scrollHeight, 200)}px`;\n }}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n rows={4}\n onKeyDown={handleKeyDown}\n />\n\n <div className={styles.actions}>\n {onDelete && (\n <div className={styles.deleteWrapper}>\n <button className={styles.deleteButton} onClick={onDelete} type=\"button\">\n <IconTrash size={22} />\n </button>\n </div>\n )}\n <button className={styles.cancel} onClick={handleCancel}>\n Cancel\n </button>\n <button\n className={styles.submit}\n style={{\n backgroundColor: accentColor,\n opacity: text.trim() ? 1 : 0.4,\n }}\n onClick={handleSubmit}\n disabled={!text.trim()}\n >\n {submitLabel}\n </button>\n </div>\n <div className={styles.shortcutHint}>\n {navigator?.platform?.includes(\"Mac\") ? \"⌘\" : \"Ctrl\"}+Enter to submit\n </div>\n </div>\n );\n }\n);\n\nexport default AnnotationPopupCSS;\n","\nconst css = \".styles-module__popup___IhzrD svg[fill=none] {\\n fill: none !important;\\n}\\n.styles-module__popup___IhzrD svg[fill=none] :not([fill]) {\\n fill: none !important;\\n}\\n\\n@keyframes styles-module__popupEnter___AuQDN {\\n from {\\n opacity: 0;\\n transform: translateX(-50%) scale(0.95) translateY(4px);\\n }\\n to {\\n opacity: 1;\\n transform: translateX(-50%) scale(1) translateY(0);\\n }\\n}\\n@keyframes styles-module__popupExit___JJKQX {\\n from {\\n opacity: 1;\\n transform: translateX(-50%) scale(1) translateY(0);\\n }\\n to {\\n opacity: 0;\\n transform: translateX(-50%) scale(0.95) translateY(4px);\\n }\\n}\\n@keyframes styles-module__shake___jdbWe {\\n 0%, 100% {\\n transform: translateX(-50%) scale(1) translateY(0) translateX(0);\\n }\\n 20% {\\n transform: translateX(-50%) scale(1) translateY(0) translateX(-3px);\\n }\\n 40% {\\n transform: translateX(-50%) scale(1) translateY(0) translateX(3px);\\n }\\n 60% {\\n transform: translateX(-50%) scale(1) translateY(0) translateX(-2px);\\n }\\n 80% {\\n transform: translateX(-50%) scale(1) translateY(0) translateX(2px);\\n }\\n}\\n.styles-module__popup___IhzrD {\\n position: fixed;\\n transform: translateX(-50%);\\n width: 280px;\\n padding: 0.75rem 1rem 14px;\\n background: #1a1a1a;\\n border-radius: 16px;\\n box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.08);\\n z-index: 100001;\\n font-family: system-ui, -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, sans-serif;\\n will-change: transform, opacity;\\n opacity: 0;\\n}\\n.styles-module__popup___IhzrD.styles-module__enter___L7U7N {\\n animation: styles-module__popupEnter___AuQDN 0.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;\\n}\\n.styles-module__popup___IhzrD.styles-module__entered___COX-w {\\n opacity: 1;\\n transform: translateX(-50%) scale(1) translateY(0);\\n}\\n.styles-module__popup___IhzrD.styles-module__exit___5eGjE {\\n animation: styles-module__popupExit___JJKQX 0.15s ease-in forwards;\\n}\\n.styles-module__popup___IhzrD.styles-module__entered___COX-w.styles-module__shake___jdbWe {\\n animation: styles-module__shake___jdbWe 0.25s ease-out;\\n}\\n\\n.styles-module__header___wWsSi {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n margin-bottom: 0.5625rem;\\n}\\n\\n.styles-module__element___fTV2z {\\n font-size: 0.75rem;\\n font-weight: 400;\\n color: rgba(255, 255, 255, 0.5);\\n max-width: 100%;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n flex: 1;\\n}\\n\\n.styles-module__headerToggle___WpW0b {\\n display: flex;\\n align-items: center;\\n gap: 0.25rem;\\n background: none;\\n border: none;\\n padding: 0;\\n cursor: pointer;\\n flex: 1;\\n min-width: 0;\\n text-align: left;\\n}\\n.styles-module__headerToggle___WpW0b .styles-module__element___fTV2z {\\n flex: 1;\\n}\\n\\n.styles-module__chevron___ZZJlR {\\n color: rgba(255, 255, 255, 0.5);\\n transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);\\n flex-shrink: 0;\\n}\\n.styles-module__chevron___ZZJlR.styles-module__expanded___2Hxgv {\\n transform: rotate(90deg);\\n}\\n\\n.styles-module__stylesWrapper___pnHgy {\\n display: grid;\\n grid-template-rows: 0fr;\\n transition: grid-template-rows 0.3s cubic-bezier(0.16, 1, 0.3, 1);\\n}\\n.styles-module__stylesWrapper___pnHgy.styles-module__expanded___2Hxgv {\\n grid-template-rows: 1fr;\\n}\\n\\n.styles-module__stylesInner___YYZe2 {\\n overflow: hidden;\\n}\\n\\n.styles-module__stylesBlock___VfQKn {\\n background: rgba(255, 255, 255, 0.05);\\n border-radius: 0.375rem;\\n padding: 0.5rem 0.625rem;\\n margin-bottom: 0.5rem;\\n font-family: ui-monospace, SFMono-Regular, \\\"SF Mono\\\", Menlo, Consolas, monospace;\\n font-size: 0.6875rem;\\n line-height: 1.5;\\n}\\n\\n.styles-module__styleLine___1YQiD {\\n color: rgba(255, 255, 255, 0.85);\\n word-break: break-word;\\n}\\n\\n.styles-module__styleProperty___84L1i {\\n color: #c792ea;\\n}\\n\\n.styles-module__styleValue___q51-h {\\n color: rgba(255, 255, 255, 0.85);\\n}\\n\\n.styles-module__timestamp___Dtpsv {\\n font-size: 0.625rem;\\n font-weight: 500;\\n color: rgba(255, 255, 255, 0.35);\\n font-variant-numeric: tabular-nums;\\n margin-left: 0.5rem;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__quote___mcMmQ {\\n font-size: 12px;\\n font-style: italic;\\n color: rgba(255, 255, 255, 0.6);\\n margin-bottom: 0.5rem;\\n padding: 0.4rem 0.5rem;\\n background: rgba(255, 255, 255, 0.05);\\n border-radius: 0.25rem;\\n line-height: 1.45;\\n}\\n\\n.styles-module__textarea___jrSae {\\n box-sizing: border-box;\\n width: 100%;\\n padding: 0.5rem 0.625rem;\\n font-size: 0.8125rem;\\n font-family: inherit;\\n line-height: 1.55;\\n background: rgba(255, 255, 255, 0.05);\\n color: #fff;\\n border: 1px solid rgba(255, 255, 255, 0.15);\\n border-radius: 8px;\\n resize: none;\\n outline: none;\\n min-height: 80px;\\n max-height: 200px;\\n transition: border-color 0.15s ease, height 0.1s ease;\\n}\\n.styles-module__textarea___jrSae:focus {\\n border-color: var(--agentation-color-blue);\\n}\\n.styles-module__textarea___jrSae.styles-module__green___99l3h:focus {\\n border-color: var(--agentation-color-green);\\n}\\n.styles-module__textarea___jrSae::placeholder {\\n color: rgba(255, 255, 255, 0.35);\\n}\\n.styles-module__textarea___jrSae::-webkit-scrollbar {\\n width: 6px;\\n}\\n.styles-module__textarea___jrSae::-webkit-scrollbar-track {\\n background: transparent;\\n}\\n.styles-module__textarea___jrSae::-webkit-scrollbar-thumb {\\n background: rgba(255, 255, 255, 0.2);\\n border-radius: 3px;\\n}\\n\\n.styles-module__actions___D6x3f {\\n display: flex;\\n justify-content: flex-end;\\n gap: 0.375rem;\\n margin-top: 0.5rem;\\n}\\n\\n.styles-module__cancel___hRjnL,\\n.styles-module__submit___K-mIR {\\n padding: 0.4rem 0.875rem;\\n font-size: 0.75rem;\\n font-weight: 500;\\n border-radius: 1rem;\\n border: none;\\n cursor: pointer;\\n transition: background-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;\\n}\\n\\n.styles-module__cancel___hRjnL {\\n background: transparent;\\n color: rgba(255, 255, 255, 0.5);\\n}\\n.styles-module__cancel___hRjnL:hover {\\n background: rgba(255, 255, 255, 0.1);\\n color: rgba(255, 255, 255, 0.8);\\n}\\n\\n.styles-module__submit___K-mIR {\\n color: white;\\n}\\n.styles-module__submit___K-mIR:hover:not(:disabled) {\\n filter: brightness(0.9);\\n}\\n.styles-module__submit___K-mIR:disabled {\\n cursor: not-allowed;\\n}\\n\\n.styles-module__shortcutHint___ihsrd {\\n text-align: right;\\n font-size: 11px;\\n color: #9ca3af;\\n padding: 2px 4px 0;\\n user-select: none;\\n}\\n\\n.styles-module__deleteWrapper___oSjdo {\\n margin-right: auto;\\n}\\n\\n.styles-module__deleteButton___4VuAE {\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n width: 28px;\\n height: 28px;\\n border-radius: 50%;\\n border: none;\\n background: transparent;\\n color: rgba(255, 255, 255, 0.4);\\n transition: background-color 0.15s ease, color 0.15s ease, transform 0.1s ease;\\n}\\n.styles-module__deleteButton___4VuAE:hover {\\n background-color: color-mix(in srgb, var(--agentation-color-red) 25%, transparent);\\n color: var(--agentation-color-red);\\n}\\n.styles-module__deleteButton___4VuAE:active {\\n transform: scale(0.92);\\n}\\n\\n.styles-module__light___6AaSQ.styles-module__popup___IhzrD {\\n background: #fff;\\n box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.06);\\n}\\n.styles-module__light___6AaSQ .styles-module__element___fTV2z {\\n color: rgba(0, 0, 0, 0.6);\\n}\\n.styles-module__light___6AaSQ .styles-module__timestamp___Dtpsv {\\n color: rgba(0, 0, 0, 0.4);\\n}\\n.styles-module__light___6AaSQ .styles-module__chevron___ZZJlR {\\n color: rgba(0, 0, 0, 0.4);\\n}\\n.styles-module__light___6AaSQ .styles-module__stylesBlock___VfQKn {\\n background: rgba(0, 0, 0, 0.03);\\n}\\n.styles-module__light___6AaSQ .styles-module__styleLine___1YQiD {\\n color: rgba(0, 0, 0, 0.75);\\n}\\n.styles-module__light___6AaSQ .styles-module__styleProperty___84L1i {\\n color: #7c3aed;\\n}\\n.styles-module__light___6AaSQ .styles-module__styleValue___q51-h {\\n color: rgba(0, 0, 0, 0.75);\\n}\\n.styles-module__light___6AaSQ .styles-module__quote___mcMmQ {\\n color: rgba(0, 0, 0, 0.55);\\n background: rgba(0, 0, 0, 0.04);\\n}\\n.styles-module__light___6AaSQ .styles-module__textarea___jrSae {\\n background: rgba(0, 0, 0, 0.03);\\n color: #1a1a1a;\\n border-color: rgba(0, 0, 0, 0.12);\\n}\\n.styles-module__light___6AaSQ .styles-module__textarea___jrSae::placeholder {\\n color: rgba(0, 0, 0, 0.4);\\n}\\n.styles-module__light___6AaSQ .styles-module__textarea___jrSae::-webkit-scrollbar-thumb {\\n background: rgba(0, 0, 0, 0.15);\\n}\\n.styles-module__light___6AaSQ .styles-module__cancel___hRjnL {\\n color: rgba(0, 0, 0, 0.5);\\n}\\n.styles-module__light___6AaSQ .styles-module__cancel___hRjnL:hover {\\n background: rgba(0, 0, 0, 0.06);\\n color: rgba(0, 0, 0, 0.75);\\n}\\n.styles-module__light___6AaSQ .styles-module__deleteButton___4VuAE {\\n color: rgba(0, 0, 0, 0.4);\\n}\\n.styles-module__light___6AaSQ .styles-module__deleteButton___4VuAE:hover {\\n background-color: color-mix(in srgb, var(--agentation-color-red) 25%, transparent);\\n color: var(--agentation-color-red);\\n}\";\nconst classNames = {\"popup\":\"styles-module__popup___IhzrD\",\"enter\":\"styles-module__enter___L7U7N\",\"popupEnter\":\"styles-module__popupEnter___AuQDN\",\"entered\":\"styles-module__entered___COX-w\",\"exit\":\"styles-module__exit___5eGjE\",\"popupExit\":\"styles-module__popupExit___JJKQX\",\"shake\":\"styles-module__shake___jdbWe\",\"header\":\"styles-module__header___wWsSi\",\"element\":\"styles-module__element___fTV2z\",\"headerToggle\":\"styles-module__headerToggle___WpW0b\",\"chevron\":\"styles-module__chevron___ZZJlR\",\"expanded\":\"styles-module__expanded___2Hxgv\",\"stylesWrapper\":\"styles-module__stylesWrapper___pnHgy\",\"stylesInner\":\"styles-module__stylesInner___YYZe2\",\"stylesBlock\":\"styles-module__stylesBlock___VfQKn\",\"styleLine\":\"styles-module__styleLine___1YQiD\",\"styleProperty\":\"styles-module__styleProperty___84L1i\",\"styleValue\":\"styles-module__styleValue___q51-h\",\"timestamp\":\"styles-module__timestamp___Dtpsv\",\"quote\":\"styles-module__quote___mcMmQ\",\"textarea\":\"styles-module__textarea___jrSae\",\"green\":\"styles-module__green___99l3h\",\"actions\":\"styles-module__actions___D6x3f\",\"cancel\":\"styles-module__cancel___hRjnL\",\"submit\":\"styles-module__submit___K-mIR\",\"shortcutHint\":\"styles-module__shortcutHint___ihsrd\",\"deleteWrapper\":\"styles-module__deleteWrapper___oSjdo\",\"deleteButton\":\"styles-module__deleteButton___4VuAE\",\"light\":\"styles-module__light___6AaSQ\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-annotation-popup-css-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-annotation-popup-css-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\"use client\";\n\nimport s from \"./icon-transitions.module.scss\";\n\n// =============================================================================\n// Icons\n// =============================================================================\n\n// Small X for marker delete\nexport const IconClose = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M4 4l8 8M12 4l-8 8\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Plus icon\nexport const IconPlus = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M8 3v10M3 8h10\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Checkmark icon\nexport const IconCheck = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\">\n <path\n d=\"M3 8l3.5 3.5L13 5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Checkbox checkmark (smaller, optimized for checkboxes)\nexport const IconCheckSmall = ({ size = 14 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 14 14\" fill=\"none\">\n <path\n d=\"M3.9375 7L6.125 9.1875L10.5 4.8125\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// List with sparkle icon\nexport const IconListSparkle = ({\n size = 24,\n style = {},\n}: {\n size?: number;\n style?: React.CSSProperties;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" style={style}>\n <g clipPath=\"url(#clip0_list_sparkle)\">\n <path\n d=\"M11.5 12L5.5 12\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M18.5 6.75L5.5 6.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M9.25 17.25L5.5 17.25\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M16 12.75L16.5179 13.9677C16.8078 14.6494 17.3506 15.1922 18.0323 15.4821L19.25 16L18.0323 16.5179C17.3506 16.8078 16.8078 17.3506 16.5179 18.0323L16 19.25L15.4821 18.0323C15.1922 17.3506 14.6494 16.8078 13.9677 16.5179L12.75 16L13.9677 15.4821C14.6494 15.1922 15.1922 14.6494 15.4821 13.9677L16 12.75Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_list_sparkle\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\n// Help/Question mark icon for tooltips\nexport const IconHelp = ({\n size = 20,\n ...props\n}: { size?: number } & React.SVGProps<SVGSVGElement>) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n {...props}\n >\n <circle\n cx=\"10\"\n cy=\"10\"\n r=\"5.375\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n />\n <path\n d=\"M8.5 8.5C8.73 7.85 9.31 7.49 10 7.5C10.86 7.51 11.5 8.13 11.5 9C11.5 10.08 10 10.5 10 10.5V10.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <circle cx=\"10\" cy=\"12.625\" r=\"0.625\" fill=\"currentColor\" />\n </svg>\n);\n\n// Animated checkmark with draw + bounce effect\nexport const IconCheckSmallAnimated = ({ size = 14 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 14 14\" fill=\"none\">\n <style>{`\n @keyframes checkDraw {\n 0% {\n stroke-dashoffset: 12;\n }\n 100% {\n stroke-dashoffset: 0;\n }\n }\n @keyframes checkBounce {\n 0% {\n transform: scale(0.5);\n opacity: 0;\n }\n 50% {\n transform: scale(1.12);\n opacity: 1;\n }\n 75% {\n transform: scale(0.95);\n }\n 100% {\n transform: scale(1);\n }\n }\n .check-path-animated {\n stroke-dasharray: 12;\n stroke-dashoffset: 0;\n transform-origin: center;\n animation: checkDraw 0.18s ease-out, checkBounce 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n `}</style>\n <path\n className=\"check-path-animated\"\n d=\"M3.9375 7L6.125 9.1875L10.5 4.8125\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// =============================================================================\n// New Icons from SVG files\n// =============================================================================\n\n// Copy icon (two overlapping rectangles)\nexport const IconCopyAlt = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M4.75 11.25C4.75 10.4216 5.42157 9.75 6.25 9.75H12.75C13.5784 9.75 14.25 10.4216 14.25 11.25V17.75C14.25 18.5784 13.5784 19.25 12.75 19.25H6.25C5.42157 19.25 4.75 18.5784 4.75 17.75V11.25Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M17.25 14.25H17.75C18.5784 14.25 19.25 13.5784 19.25 12.75V6.25C19.25 5.42157 18.5784 4.75 17.75 4.75H11.25C10.4216 4.75 9.75 5.42157 9.75 6.25V6.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Animated copy/checkmark icon\nexport const IconCopyAnimated = ({\n size = 24,\n copied = false,\n tint,\n}: {\n size?: number;\n copied?: boolean;\n tint?: string;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" style={tint ? { color: tint, transition: 'color 0.3s ease' } : undefined}>\n {/* Copy icon */}\n <g\n className={`${s.iconState} ${copied ? s.hiddenScaled : s.visibleScaled}`}\n >\n <path\n d=\"M4.75 11.25C4.75 10.4216 5.42157 9.75 6.25 9.75H12.75C13.5784 9.75 14.25 10.4216 14.25 11.25V17.75C14.25 18.5784 13.5784 19.25 12.75 19.25H6.25C5.42157 19.25 4.75 18.5784 4.75 17.75V11.25Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M17.25 14.25H17.75C18.5784 14.25 19.25 13.5784 19.25 12.75V6.25C19.25 5.42157 18.5784 4.75 17.75 4.75H11.25C10.4216 4.75 9.75 5.42157 9.75 6.25V6.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </g>\n {/* Checkmark circle */}\n <g\n className={`${s.iconState} ${copied ? s.visibleScaled : s.hiddenScaled}`}\n >\n <path\n d=\"M12 20C7.58172 20 4 16.4182 4 12C4 7.58172 7.58172 4 12 4C16.4182 4 20 7.58172 20 12C20 16.4182 16.4182 20 12 20Z\"\n stroke=\"var(--agentation-color-green)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M15 10L11 14.25L9.25 12.25\"\n stroke=\"var(--agentation-color-green)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n </svg>\n);\n\n// Animated send arrow icon (paper plane style with checkmark/error transition)\nexport const IconSendArrow = ({\n size = 24,\n state = \"idle\",\n}: {\n size?: number;\n state?: \"idle\" | \"sending\" | \"sent\" | \"failed\";\n}) => {\n const showArrow = state === \"idle\";\n const showCheck = state === \"sent\";\n const showError = state === \"failed\";\n const isSending = state === \"sending\";\n\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n {/* Send arrow */}\n <g\n className={`${s.iconStateFast} ${showArrow ? s.visibleScaled : isSending ? s.sending : s.hiddenScaled}`}\n >\n <path\n d=\"M9.875 14.125L12.3506 19.6951C12.7184 20.5227 13.9091 20.4741 14.2083 19.6193L18.8139 6.46032C19.0907 5.6695 18.3305 4.90933 17.5397 5.18611L4.38072 9.79174C3.52589 10.0909 3.47731 11.2816 4.30494 11.6494L9.875 14.125ZM9.875 14.125L13.375 10.625\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n {/* Green checkmark circle */}\n <g\n className={`${s.iconStateFast} ${showCheck ? s.visibleScaled : s.hiddenScaled}`}\n >\n <path\n d=\"M12 20C7.58172 20 4 16.4182 4 12C4 7.58172 7.58172 4 12 4C16.4182 4 20 7.58172 20 12C20 16.4182 16.4182 20 12 20Z\"\n stroke=\"var(--agentation-color-green)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M15 10L11 14.25L9.25 12.25\"\n stroke=\"var(--agentation-color-green)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n {/* Red error circle with exclamation */}\n <g\n className={`${s.iconStateFast} ${showError ? s.visibleScaled : s.hiddenScaled}`}\n >\n <path\n d=\"M12 20C7.58172 20 4 16.4182 4 12C4 7.58172 7.58172 4 12 4C16.4182 4 20 7.58172 20 12C20 16.4182 16.4182 20 12 20Z\"\n stroke=\"var(--agentation-color-red)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M12 8V12\"\n stroke=\"var(--agentation-color-red)\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <circle\n cx=\"12\"\n cy=\"15\"\n r=\"0.5\"\n fill=\"var(--agentation-color-red)\"\n stroke=\"var(--agentation-color-red)\"\n strokeWidth=\"1\"\n />\n </g>\n </svg>\n );\n};\n\n// Animated send/checkmark icon (for \"Send to Agent\" button)\nexport const IconSendAnimated = ({\n size = 24,\n sent = false,\n}: {\n size?: number;\n sent?: boolean;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 22 21\" fill=\"none\">\n {/* Send icon (document with arrow) */}\n <g className={`${s.iconState} ${sent ? s.hiddenScaled : s.visibleScaled}`}>\n <path\n d=\"M9.5 5H6.5C4.84315 5 3.5 6.34315 3.5 8V15C3.5 16.6569 4.84315 18 6.5 18H13.5C15.1569 18 16.5 16.6569 16.5 15V12\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M13.5 8.5L18.5 3.5M18.5 3.5L14.4524 3.5M18.5 3.5L18.5 7.54762\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M7.5 13.75H12.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M7.5 10.75H10.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </g>\n {/* Checkmark circle (success state) */}\n <g className={`${s.iconState} ${sent ? s.visibleScaled : s.hiddenScaled}`}>\n <path\n d=\"M11 19C6.58172 19 3 15.4182 3 11C3 6.58172 6.58172 3 11 3C15.4182 3 19 6.58172 19 11C19 15.4182 15.4182 19 11 19Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14 9L10 13.25L8.25 11.25\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n </svg>\n);\n\n// Eye icon (original)\nexport const IconEye = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M4.91516 12.7108C4.63794 12.2883 4.63705 11.7565 4.91242 11.3328C5.84146 9.9033 8.30909 6.74994 12 6.74994C15.6909 6.74994 18.1585 9.9033 19.0876 11.3328C19.3629 11.7565 19.3621 12.2883 19.0848 12.7108C18.1537 14.13 15.6873 17.2499 12 17.2499C8.31272 17.2499 5.8463 14.13 4.91516 12.7108Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M12 14.25C13.2426 14.25 14.25 13.2426 14.25 12C14.25 10.7574 13.2426 9.75 12 9.75C10.7574 9.75 9.75 10.7574 9.75 12C9.75 13.2426 10.7574 14.25 12 14.25Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Eye icon (alt version - larger pupil)\nexport const IconEyeAlt = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M3.91752 12.7539C3.65127 12.2996 3.65037 11.7515 3.9149 11.2962C4.9042 9.59346 7.72688 5.49994 12 5.49994C16.2731 5.49994 19.0958 9.59346 20.0851 11.2962C20.3496 11.7515 20.3487 12.2996 20.0825 12.7539C19.0908 14.4459 16.2694 18.4999 12 18.4999C7.73064 18.4999 4.90918 14.4459 3.91752 12.7539Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M12 14.8261C13.5608 14.8261 14.8261 13.5608 14.8261 12C14.8261 10.4392 13.5608 9.17392 12 9.17392C10.4392 9.17392 9.17391 10.4392 9.17391 12C9.17391 13.5608 10.4392 14.8261 12 14.8261Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Eye closed (with slash)\nexport const IconEyeClosed = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M18.6025 9.28503C18.9174 8.9701 19.4364 8.99481 19.7015 9.35271C20.1484 9.95606 20.4943 10.507 20.7342 10.9199C21.134 11.6086 21.1329 12.4454 20.7303 13.1328C20.2144 14.013 19.2151 15.5225 17.7723 16.8193C16.3293 18.1162 14.3852 19.2497 12.0008 19.25C11.4192 19.25 10.8638 19.1823 10.3355 19.0613C9.77966 18.934 9.63498 18.2525 10.0382 17.8493C10.2412 17.6463 10.5374 17.573 10.8188 17.6302C11.1993 17.7076 11.5935 17.75 12.0008 17.75C13.8848 17.7497 15.4867 16.8568 16.7693 15.7041C18.0522 14.5511 18.9606 13.1867 19.4363 12.375C19.5656 12.1543 19.5659 11.8943 19.4373 11.6729C19.2235 11.3049 18.921 10.8242 18.5364 10.3003C18.3085 9.98991 18.3302 9.5573 18.6025 9.28503ZM12.0008 4.75C12.5814 4.75006 13.1358 4.81803 13.6632 4.93953C14.2182 5.06741 14.362 5.74812 13.9593 6.15091C13.7558 6.35435 13.4589 6.42748 13.1771 6.36984C12.7983 6.29239 12.4061 6.25006 12.0008 6.25C10.1167 6.25 8.51415 7.15145 7.23028 8.31543C5.94678 9.47919 5.03918 10.8555 4.56426 11.6729C4.43551 11.8945 4.43582 12.1542 4.56524 12.375C4.77587 12.7343 5.07189 13.2012 5.44718 13.7105C5.67623 14.0213 5.65493 14.4552 5.38193 14.7282C5.0671 15.0431 4.54833 15.0189 4.28292 14.6614C3.84652 14.0736 3.50813 13.5369 3.27129 13.1328C2.86831 12.4451 2.86717 11.6088 3.26739 10.9199C3.78185 10.0345 4.77959 8.51239 6.22247 7.2041C7.66547 5.89584 9.61202 4.75 12.0008 4.75Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M5 19L19 5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Animated eye icon that transitions between open/closed states\nexport const IconEyeAnimated = ({\n size = 24,\n isOpen = true,\n}: {\n size?: number;\n isOpen?: boolean;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n {/* Open state - full outline + pupil */}\n <g className={`${s.iconFade} ${isOpen ? s.visible : s.hidden}`}>\n <path\n d=\"M3.91752 12.7539C3.65127 12.2996 3.65037 11.7515 3.9149 11.2962C4.9042 9.59346 7.72688 5.49994 12 5.49994C16.2731 5.49994 19.0958 9.59346 20.0851 11.2962C20.3496 11.7515 20.3487 12.2996 20.0825 12.7539C19.0908 14.4459 16.2694 18.4999 12 18.4999C7.73064 18.4999 4.90918 14.4459 3.91752 12.7539Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M12 14.8261C13.5608 14.8261 14.8261 13.5608 14.8261 12C14.8261 10.4392 13.5608 9.17392 12 9.17392C10.4392 9.17392 9.17391 10.4392 9.17391 12C9.17391 13.5608 10.4392 14.8261 12 14.8261Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n {/* Closed state - split outline + slash */}\n <g className={`${s.iconFade} ${isOpen ? s.hidden : s.visible}`}>\n <path\n d=\"M18.6025 9.28503C18.9174 8.9701 19.4364 8.99481 19.7015 9.35271C20.1484 9.95606 20.4943 10.507 20.7342 10.9199C21.134 11.6086 21.1329 12.4454 20.7303 13.1328C20.2144 14.013 19.2151 15.5225 17.7723 16.8193C16.3293 18.1162 14.3852 19.2497 12.0008 19.25C11.4192 19.25 10.8638 19.1823 10.3355 19.0613C9.77966 18.934 9.63498 18.2525 10.0382 17.8493C10.2412 17.6463 10.5374 17.573 10.8188 17.6302C11.1993 17.7076 11.5935 17.75 12.0008 17.75C13.8848 17.7497 15.4867 16.8568 16.7693 15.7041C18.0522 14.5511 18.9606 13.1867 19.4363 12.375C19.5656 12.1543 19.5659 11.8943 19.4373 11.6729C19.2235 11.3049 18.921 10.8242 18.5364 10.3003C18.3085 9.98991 18.3302 9.5573 18.6025 9.28503ZM12.0008 4.75C12.5814 4.75006 13.1358 4.81803 13.6632 4.93953C14.2182 5.06741 14.362 5.74812 13.9593 6.15091C13.7558 6.35435 13.4589 6.42748 13.1771 6.36984C12.7983 6.29239 12.4061 6.25006 12.0008 6.25C10.1167 6.25 8.51415 7.15145 7.23028 8.31543C5.94678 9.47919 5.03918 10.8555 4.56426 11.6729C4.43551 11.8945 4.43582 12.1542 4.56524 12.375C4.77587 12.7343 5.07189 13.2012 5.44718 13.7105C5.67623 14.0213 5.65493 14.4552 5.38193 14.7282C5.0671 15.0431 4.54833 15.0189 4.28292 14.6614C3.84652 14.0736 3.50813 13.5369 3.27129 13.1328C2.86831 12.4451 2.86717 11.6088 3.26739 10.9199C3.78185 10.0345 4.77959 8.51239 6.22247 7.2041C7.66547 5.89584 9.61202 4.75 12.0008 4.75Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M5 19L19 5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </g>\n </svg>\n);\n\n// Animated pause/play icon that transitions between states\nexport const IconPausePlayAnimated = ({\n size = 24,\n isPaused = false,\n}: {\n size?: number;\n isPaused?: boolean;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n {/* Pause bars - visible when not paused */}\n <g className={`${s.iconFadeFast} ${isPaused ? s.hidden : s.visible}`}>\n <path\n d=\"M8 6L8 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M16 18L16 6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </g>\n {/* Play triangle - visible when paused */}\n <path\n className={`${s.iconFadeFast} ${isPaused ? s.visible : s.hidden}`}\n d=\"M17.75 10.701C18.75 11.2783 18.75 12.7217 17.75 13.299L8.75 18.4952C7.75 19.0725 6.5 18.3509 6.5 17.1962L6.5 6.80384C6.5 5.64914 7.75 4.92746 8.75 5.50481L17.75 10.701Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n\n// Eye with minus (hidden/collapsed state)\nexport const IconEyeMinus = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M4.91516 12.7108C4.63794 12.2883 4.63705 11.7565 4.91242 11.3328C5.84146 9.9033 8.30909 6.74994 12 6.74994C15.6909 6.74994 18.1585 9.9033 19.0876 11.3328C19.3629 11.7565 19.3621 12.2883 19.0848 12.7108C18.1537 14.13 15.6873 17.2499 12 17.2499C8.31272 17.2499 5.8463 14.13 4.91516 12.7108Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M9 12H15\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Gear icon\nexport const IconGear = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M10.6504 5.81117C10.9939 4.39628 13.0061 4.39628 13.3496 5.81117C13.5715 6.72517 14.6187 7.15891 15.4219 6.66952C16.6652 5.91193 18.0881 7.33479 17.3305 8.57815C16.8411 9.38134 17.2748 10.4285 18.1888 10.6504C19.6037 10.9939 19.6037 13.0061 18.1888 13.3496C17.2748 13.5715 16.8411 14.6187 17.3305 15.4219C18.0881 16.6652 16.6652 18.0881 15.4219 17.3305C14.6187 16.8411 13.5715 17.2748 13.3496 18.1888C13.0061 19.6037 10.9939 19.6037 10.6504 18.1888C10.4285 17.2748 9.38135 16.8411 8.57815 17.3305C7.33479 18.0881 5.91193 16.6652 6.66952 15.4219C7.15891 14.6187 6.72517 13.5715 5.81117 13.3496C4.39628 13.0061 4.39628 10.9939 5.81117 10.6504C6.72517 10.4285 7.15891 9.38134 6.66952 8.57815C5.91193 7.33479 7.33479 5.91192 8.57815 6.66952C9.38135 7.15891 10.4285 6.72517 10.6504 5.81117Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <circle cx=\"12\" cy=\"12\" r=\"2.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n </svg>\n);\n\n// Pause icon (two vertical bars - original)\nexport const IconPauseAlt = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M9.25 5.75C9.80228 5.75 10.25 6.19772 10.25 6.75L10.25 17.25C10.25 17.8023 9.80228 18.25 9.25 18.25L6.75 18.25C6.19772 18.25 5.75 17.8023 5.75 17.25L5.75 6.75C5.75 6.19772 6.19772 5.75 6.75 5.75L9.25 5.75Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M17.25 5.75C17.8023 5.75 18.25 6.19772 18.25 6.75L18.25 17.25C18.25 17.8023 17.8023 18.25 17.25 18.25L14.75 18.25C14.1977 18.25 13.75 17.8023 13.75 17.25L13.75 6.75C13.75 6.19772 14.1977 5.75 14.75 5.75L17.25 5.75Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n\n// Pause icon (simple lines)\nexport const IconPause = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M8 6L8 18\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n <path\n d=\"M16 18L16 6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\n// Play icon (triangle pointing right)\nexport const IconPlayAlt = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M17.75 10.701C18.75 11.2783 18.75 12.7217 17.75 13.299L8.75 18.4952C7.75 19.0725 6.5 18.3509 6.5 17.1962L6.5 6.80384C6.5 5.64914 7.75 4.92746 8.75 5.50481L17.75 10.701Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n\n// Trash can icon (filled)\nexport const IconTrashAlt = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M13.5 4C14.7426 4 15.75 5.00736 15.75 6.25V7H18.5C18.9142 7 19.25 7.33579 19.25 7.75C19.25 8.16421 18.9142 8.5 18.5 8.5H17.9678L17.6328 16.2217C17.61 16.7475 17.5912 17.1861 17.5469 17.543C17.5015 17.9087 17.4225 18.2506 17.2461 18.5723C16.9747 19.0671 16.5579 19.4671 16.0518 19.7168C15.7227 19.8791 15.3772 19.9422 15.0098 19.9717C14.6514 20.0004 14.2126 20 13.6865 20H10.3135C9.78735 20 9.34856 20.0004 8.99023 19.9717C8.62278 19.9422 8.27729 19.8791 7.94824 19.7168C7.44205 19.4671 7.02532 19.0671 6.75391 18.5723C6.57751 18.2506 6.49853 17.9087 6.45312 17.543C6.40883 17.1861 6.39005 16.7475 6.36719 16.2217L6.03223 8.5H5.5C5.08579 8.5 4.75 8.16421 4.75 7.75C4.75 7.33579 5.08579 7 5.5 7H8.25V6.25C8.25 5.00736 9.25736 4 10.5 4H13.5ZM7.86621 16.1562C7.89013 16.7063 7.90624 17.0751 7.94141 17.3584C7.97545 17.6326 8.02151 17.7644 8.06934 17.8516C8.19271 18.0763 8.38239 18.2577 8.6123 18.3711C8.70153 18.4151 8.83504 18.4545 9.11035 18.4766C9.39482 18.4994 9.76335 18.5 10.3135 18.5H13.6865C14.2367 18.5 14.6052 18.4994 14.8896 18.4766C15.165 18.4545 15.2985 18.4151 15.3877 18.3711C15.6176 18.2577 15.8073 18.0763 15.9307 17.8516C15.9785 17.7644 16.0245 17.6326 16.0586 17.3584C16.0938 17.0751 16.1099 16.7063 16.1338 16.1562L16.4668 8.5H7.5332L7.86621 16.1562ZM9.97656 10.75C10.3906 10.7371 10.7371 11.0626 10.75 11.4766L10.875 15.4766C10.8879 15.8906 10.5624 16.2371 10.1484 16.25C9.73443 16.2629 9.38794 15.9374 9.375 15.5234L9.25 11.5234C9.23706 11.1094 9.56255 10.7629 9.97656 10.75ZM14.0244 10.75C14.4384 10.7635 14.7635 11.1105 14.75 11.5244L14.6201 15.5244C14.6066 15.9384 14.2596 16.2634 13.8457 16.25C13.4317 16.2365 13.1067 15.8896 13.1201 15.4756L13.251 11.4756C13.2645 11.0617 13.6105 10.7366 14.0244 10.75ZM10.5 5.5C10.0858 5.5 9.75 5.83579 9.75 6.25V7H14.25V6.25C14.25 5.83579 13.9142 5.5 13.5 5.5H10.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\n// Chat bubble with ellipsis\nexport const IconChatEllipsis = ({\n size = 16,\n style = {},\n}: {\n size?: number;\n style?: React.CSSProperties;\n}) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" style={style}>\n <path\n d=\"M18.8875 19.25L19.6112 19.0533C19.6823 19.3148 19.6068 19.5943 19.4137 19.7844C19.2206 19.9746 18.9399 20.0457 18.6795 19.9706L18.8875 19.25ZM14.9631 18.244L15.263 18.9314L14.9631 18.244ZM18.0914 15.6309L17.4669 15.2156L18.0914 15.6309ZM4.75 11.8041H5.5C5.5 15.2664 8.39065 18.1081 12 18.1081V18.8581V19.6081C7.60123 19.6081 4 16.1334 4 11.8041H4.75ZM19.25 11.8041H18.5C18.5 8.34166 15.6094 5.5 12 5.5V4.75V4C16.3988 4 20 7.47476 20 11.8041H19.25ZM12 4.75V5.5C8.39065 5.5 5.5 8.34166 5.5 11.8041H4.75H4C4 7.47476 7.60123 4 12 4V4.75ZM18.0914 15.6309L17.4669 15.2156C18.1213 14.2315 18.5 13.0612 18.5 11.8041H19.25H20C20 13.3681 19.5276 14.8257 18.716 16.0462L18.0914 15.6309ZM18.8875 19.25L18.1638 19.4467L17.2953 16.2517L18.019 16.055L18.7428 15.8583L19.6112 19.0533L18.8875 19.25ZM12 18.8581V18.1081C12.9509 18.1081 13.8518 17.9105 14.6632 17.5565L14.9631 18.244L15.263 18.9314C14.2652 19.3667 13.1603 19.6081 12 19.6081V18.8581ZM15.3144 18.2188L15.5224 17.4982L19.0955 18.5294L18.8875 19.25L18.6795 19.9706L15.1064 18.9394L15.3144 18.2188ZM14.9631 18.244L14.6632 17.5565C14.925 17.4423 15.2286 17.4134 15.5224 17.4982L15.3144 18.2188L15.1064 18.9394C15.1677 18.957 15.223 18.9489 15.263 18.9314L14.9631 18.244ZM18.0914 15.6309L18.716 16.0462C18.7451 16.0024 18.7636 15.9351 18.7428 15.8583L18.019 16.055L17.2953 16.2517C17.1957 15.8853 17.2716 15.5093 17.4669 15.2156L18.0914 15.6309Z\"\n fill=\"currentColor\"\n />\n <circle cx=\"15\" cy=\"11.75\" r=\"1\" fill=\"currentColor\" />\n <circle cx=\"12\" cy=\"11.75\" r=\"1\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"11.75\" r=\"1\" fill=\"currentColor\" />\n </svg>\n);\n\n// Checkmark icon\nexport const IconCheckmark = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <g clipPath=\"url(#clip0_2_45)\">\n <path\n d=\"M16.25 8.75L10 15.25L7.25 12.25\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_2_45\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\n// Large checkmark icon\nexport const IconCheckmarkLarge = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <g clipPath=\"url(#clip0_2_37)\">\n <path\n d=\"M17.5962 7.75L9.42308 16.25L6.15385 12.6538\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_2_37\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\n// Checkmark in circle icon\nexport const IconCheckmarkCircle = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <g clipPath=\"url(#clip0_checkmark_circle)\">\n <path\n d=\"M12 20C7.58172 20 4 16.4182 4 12C4 7.58172 7.58172 4 12 4C16.4182 4 20 7.58172 20 12C20 16.4182 16.4182 20 12 20Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M15 10L11 14.25L9.25 12.25\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_checkmark_circle\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\n// X mark / close icon\nexport const IconXmark = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <g clipPath=\"url(#clip0_2_53)\">\n <path\n d=\"M16.25 16.25L7.75 7.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M7.75 16.25L16.25 7.75\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_2_53\">\n <rect width=\"24\" height=\"24\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n);\n\n// X mark large / close icon (larger variant)\nexport const IconXmarkLarge = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <path\n d=\"M16.7198 6.21973C17.0127 5.92683 17.4874 5.92683 17.7803 6.21973C18.0732 6.51262 18.0732 6.9874 17.7803 7.28027L13.0606 12L17.7803 16.7197C18.0732 17.0126 18.0732 17.4874 17.7803 17.7803C17.4875 18.0731 17.0127 18.0731 16.7198 17.7803L12.0001 13.0605L7.28033 17.7803C6.98746 18.0731 6.51268 18.0731 6.21979 17.7803C5.92689 17.4874 5.92689 17.0126 6.21979 16.7197L10.9395 12L6.21979 7.28027C5.92689 6.98738 5.92689 6.51262 6.21979 6.21973C6.51268 5.92683 6.98744 5.92683 7.28033 6.21973L12.0001 10.9395L16.7198 6.21973Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\n// Sun icon (light mode)\nexport const IconSun = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M9.99999 12.7082C11.4958 12.7082 12.7083 11.4956 12.7083 9.99984C12.7083 8.50407 11.4958 7.2915 9.99999 7.2915C8.50422 7.2915 7.29166 8.50407 7.29166 9.99984C7.29166 11.4956 8.50422 12.7082 9.99999 12.7082Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M10 3.9585V5.05698\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M10 14.9429V16.0414\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M5.7269 5.72656L6.50682 6.50649\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M13.4932 13.4932L14.2731 14.2731\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M3.95834 10H5.05683\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M14.9432 10H16.0417\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M5.7269 14.2731L6.50682 13.4932\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M13.4932 6.50649L14.2731 5.72656\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Moon icon (dark mode)\nexport const IconMoon = ({ size = 16 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 20 20\" fill=\"none\">\n <path\n d=\"M15.5 10.4955C15.4037 11.5379 15.0124 12.5314 14.3721 13.3596C13.7317 14.1878 12.8688 14.8165 11.8841 15.1722C10.8995 15.5278 9.83397 15.5957 8.81217 15.3679C7.79038 15.1401 6.8546 14.6259 6.11434 13.8857C5.37408 13.1454 4.85995 12.2096 4.63211 11.1878C4.40427 10.166 4.47215 9.10048 4.82781 8.11585C5.18346 7.13123 5.81218 6.26825 6.64039 5.62791C7.4686 4.98756 8.46206 4.59634 9.5045 4.5C8.89418 5.32569 8.60049 6.34302 8.67685 7.36695C8.75321 8.39087 9.19454 9.35339 9.92058 10.0794C10.6466 10.8055 11.6091 11.2468 12.6331 11.3231C13.657 11.3995 14.6743 11.1058 15.5 10.4955Z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.13793\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Edit/pencil icon for marker hover\nexport const IconEdit = ({ size = 16 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M11.3799 6.9572L9.05645 4.63375M11.3799 6.9572L6.74949 11.5699C6.61925 11.6996 6.45577 11.791 6.277 11.8339L4.29549 12.3092C3.93194 12.3964 3.60478 12.0683 3.69297 11.705L4.16585 9.75693C4.20893 9.57947 4.29978 9.4172 4.42854 9.28771L9.05645 4.63375M11.3799 6.9572L12.3455 5.98759C12.9839 5.34655 12.9839 4.31002 12.3455 3.66897C11.7033 3.02415 10.6594 3.02415 10.0172 3.66897L9.06126 4.62892L9.05645 4.63375\"\n stroke=\"currentColor\"\n strokeWidth=\"0.9\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Trash icon for delete button in edit panel\nexport const IconTrash = ({ size = 24 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M13.5 4C14.7426 4 15.75 5.00736 15.75 6.25V7H18.5C18.9142 7 19.25 7.33579 19.25 7.75C19.25 8.16421 18.9142 8.5 18.5 8.5H17.9678L17.6328 16.2217C17.61 16.7475 17.5912 17.1861 17.5469 17.543C17.5015 17.9087 17.4225 18.2506 17.2461 18.5723C16.9747 19.0671 16.5579 19.4671 16.0518 19.7168C15.7227 19.8791 15.3772 19.9422 15.0098 19.9717C14.6514 20.0004 14.2126 20 13.6865 20H10.3135C9.78735 20 9.34856 20.0004 8.99023 19.9717C8.62278 19.9422 8.27729 19.8791 7.94824 19.7168C7.44205 19.4671 7.02532 19.0671 6.75391 18.5723C6.57751 18.2506 6.49853 17.9087 6.45312 17.543C6.40883 17.1861 6.39005 16.7475 6.36719 16.2217L6.03223 8.5H5.5C5.08579 8.5 4.75 8.16421 4.75 7.75C4.75 7.33579 5.08579 7 5.5 7H8.25V6.25C8.25 5.00736 9.25736 4 10.5 4H13.5ZM7.86621 16.1562C7.89013 16.7063 7.90624 17.0751 7.94141 17.3584C7.97545 17.6326 8.02151 17.7644 8.06934 17.8516C8.19271 18.0763 8.38239 18.2577 8.6123 18.3711C8.70153 18.4151 8.83504 18.4545 9.11035 18.4766C9.39482 18.4994 9.76335 18.5 10.3135 18.5H13.6865C14.2367 18.5 14.6052 18.4994 14.8896 18.4766C15.165 18.4545 15.2985 18.4151 15.3877 18.3711C15.6176 18.2577 15.8073 18.0763 15.9307 17.8516C15.9785 17.7644 16.0245 17.6326 16.0586 17.3584C16.0938 17.0751 16.1099 16.7063 16.1338 16.1562L16.4668 8.5H7.5332L7.86621 16.1562ZM9.97656 10.75C10.3906 10.7371 10.7371 11.0626 10.75 11.4766L10.875 15.4766C10.8879 15.8906 10.5624 16.2371 10.1484 16.25C9.73443 16.2629 9.38794 15.9374 9.375 15.5234L9.25 11.5234C9.23706 11.1094 9.56255 10.7629 9.97656 10.75ZM14.0244 10.75C14.4383 10.7635 14.7635 11.1105 14.75 11.5244L14.6201 15.5244C14.6066 15.9384 14.2596 16.2634 13.8457 16.25C13.4317 16.2365 13.1067 15.8896 13.1201 15.4756L13.251 11.4756C13.2645 11.0617 13.6105 10.7366 14.0244 10.75ZM10.5 5.5C10.0858 5.5 9.75 5.83579 9.75 6.25V7H14.25V6.25C14.25 5.83579 13.9142 5.5 13.5 5.5H10.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n\n// Chevron icons for navigation\nexport const IconChevronLeft = ({ size = 16 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8.5 3.5L4 8L8.5 12.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const IconChevronRight = ({ size = 16 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M8.5 11.5L12 8L8.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n// Animated Bunny mascot\nexport const AnimatedBunny = ({\n size = 20,\n color = \"#4C74FF\",\n}: {\n size?: number;\n color?: string;\n}) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 28 28\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <style>{`\n @keyframes bunnyEnterEar {\n 0% { opacity: 0; transform: scale(0.8); }\n 100% { opacity: 1; transform: scale(1); }\n }\n @keyframes bunnyEnterFace {\n 0% { opacity: 0; transform: scale(0.9); }\n 100% { opacity: 1; transform: scale(1); }\n }\n @keyframes bunnyEnterEye {\n 0% { opacity: 0; transform: scale(0.5); }\n 100% { opacity: 1; transform: scale(1); }\n }\n @keyframes leftEyeLook {\n 0%, 8% { transform: translate(0, 0); }\n 10%, 18% { transform: translate(1.5px, 0); }\n 20%, 22% { transform: translate(1.5px, 0) scaleY(0.1); }\n 24%, 32% { transform: translate(1.5px, 0); }\n 35%, 48% { transform: translate(-0.8px, -0.6px); }\n 52%, 54% { transform: translate(0, 0) scaleY(0.1); }\n 56%, 68% { transform: translate(0, 0); }\n 72%, 82% { transform: translate(-0.5px, 0.5px); }\n 85%, 100% { transform: translate(0, 0); }\n }\n @keyframes rightEyeLook {\n 0%, 8% { transform: translate(0, 0); }\n 10%, 18% { transform: translate(0.8px, 0); }\n 20%, 22% { transform: translate(0.8px, 0) scaleY(0.1); }\n 24%, 32% { transform: translate(0.8px, 0); }\n 35%, 48% { transform: translate(-1.5px, -0.6px); }\n 52%, 54% { transform: translate(0, 0) scaleY(0.1); }\n 56%, 68% { transform: translate(0, 0); }\n 72%, 82% { transform: translate(-1.2px, 0.5px); }\n 85%, 100% { transform: translate(0, 0); }\n }\n @keyframes leftEarTwitch {\n 0%, 9% { transform: rotate(0deg); }\n 12% { transform: rotate(-8deg); }\n 16%, 34% { transform: rotate(0deg); }\n 38% { transform: rotate(-12deg); }\n 42% { transform: rotate(-6deg); }\n 48%, 100% { transform: rotate(0deg); }\n }\n @keyframes rightEarTwitch {\n 0%, 9% { transform: rotate(0deg); }\n 12% { transform: rotate(6deg); }\n 16%, 34% { transform: rotate(0deg); }\n 38% { transform: rotate(10deg); }\n 42% { transform: rotate(4deg); }\n 48%, 71% { transform: rotate(0deg); }\n 74% { transform: rotate(8deg); }\n 78%, 100% { transform: rotate(0deg); }\n }\n .bunny-eye-left {\n opacity: 0;\n animation: bunnyEnterEye 0.3s ease-out 0.35s forwards, leftEyeLook 5s ease-in-out 0.65s infinite;\n transform-origin: center;\n transform-box: fill-box;\n }\n .bunny-eye-right {\n opacity: 0;\n animation: bunnyEnterEye 0.3s ease-out 0.4s forwards, rightEyeLook 5s ease-in-out 0.7s infinite;\n transform-origin: center;\n transform-box: fill-box;\n }\n .bunny-ear-left {\n opacity: 0;\n animation: bunnyEnterEar 0.3s ease-out 0.1s forwards, leftEarTwitch 5s ease-in-out 0.4s infinite;\n transform-origin: bottom center;\n transform-box: fill-box;\n }\n .bunny-ear-right {\n opacity: 0;\n animation: bunnyEnterEar 0.3s ease-out 0.15s forwards, rightEarTwitch 5s ease-in-out 0.45s infinite;\n transform-origin: bottom center;\n transform-box: fill-box;\n }\n .bunny-face {\n opacity: 0;\n animation: bunnyEnterFace 0.3s ease-out 0.25s forwards;\n transform-origin: center;\n transform-box: fill-box;\n }\n svg:hover .bunny-eye-left,\n svg:hover .bunny-eye-right {\n opacity: 0;\n transition: opacity 0.2s ease;\n }\n .bunny-happy-face {\n opacity: 0;\n transition: opacity 0.2s ease;\n }\n svg:hover .bunny-happy-face {\n opacity: 1;\n }\n `}</style>\n {/* Invisible hover area to catch all hover events */}\n <rect width=\"28\" height=\"28\" fill=\"transparent\" />\n {/* Left ear */}\n <path\n className=\"bunny-ear-left\"\n d=\"M3.738 10.2164L7.224 2.007H9.167L5.676 10.2164H3.738ZM10.791 6.42705C10.791 5.90346 10.726 5.42764 10.596 4.99959C10.47 4.57155 10.292 4.16643 10.063 3.78425C9.833 3.39825 9.56 3.01797 9.243 2.64343C8.926 2.26507 8.767 2.07589 8.767 2.07589L10.24 0.957996C10.24 0.957996 10.433 1.17203 10.819 1.60007C11.209 2.0243 11.559 2.49056 11.869 2.99886C12.178 3.50717 12.413 4.04222 12.574 4.60403C12.734 5.16584 12.814 5.77352 12.814 6.42705C12.814 7.10734 12.73 7.7303 12.562 8.29593C12.394 8.85774 12.153 9.3966 11.84 9.9126C11.526 10.4247 11.181 10.8833 10.802 11.2884C10.428 11.6974 10.24 11.9018 10.24 11.9018L8.767 10.7839C8.767 10.7839 8.924 10.5948 9.237 10.2164C9.554 9.8419 9.83 9.4597 10.063 9.06985C10.3 8.6762 10.479 8.26726 10.602 7.84304C10.728 7.41499 10.791 6.943 10.791 6.42705Z\"\n fill={color}\n />\n {/* Right ear */}\n <path\n className=\"bunny-ear-right\"\n d=\"M15.003 10.2164L18.489 2.007H20.432L16.941 10.2164H15.003ZM22.056 6.42705C22.056 5.90346 21.991 5.42764 21.861 4.99959C21.735 4.57155 21.557 4.16643 21.328 3.78425C21.098 3.39825 20.825 3.01797 20.508 2.64343C20.191 2.26507 20.032 2.07589 20.032 2.07589L21.505 0.957996C21.505 0.957996 21.698 1.17203 22.084 1.60007C22.474 2.0243 22.824 2.49056 23.133 2.99886C23.443 3.50717 23.678 4.04222 23.839 4.60403C23.999 5.16584 24.079 5.77352 24.079 6.42705C24.079 7.10734 23.995 7.7303 23.827 8.29593C23.659 8.85774 23.418 9.3966 23.105 9.9126C22.791 10.4247 22.445 10.8833 22.067 11.2884C21.693 11.6974 21.505 11.9018 21.505 11.9018L20.032 10.7839C20.032 10.7839 20.189 10.5948 20.502 10.2164C20.819 9.8419 21.094 9.4597 21.328 9.06985C21.565 8.6762 21.744 8.26726 21.866 7.84304C21.993 7.41499 22.056 6.943 22.056 6.42705Z\"\n fill={color}\n />\n {/* Face outline */}\n <path\n className=\"bunny-face\"\n d=\"M2.03 20.4328C2.03 20.9564 2.093 21.4322 2.219 21.8602C2.345 22.2883 2.523 22.6953 2.752 23.0813C2.981 23.4635 3.254 23.8419 3.572 24.2164C3.889 24.5948 4.047 24.7839 4.047 24.7839L2.574 25.9018C2.574 25.9018 2.379 25.6878 1.989 25.2598C1.603 24.8355 1.256 24.3693 0.946 23.861C0.636 23.3527 0.401 22.8176 0.241 22.2558C0.08 21.694 0 21.0863 0 20.4328C0 19.7525 0.084 19.1314 0.252 18.5696C0.421 18.004 0.661 17.4651 0.975 16.953C1.288 16.4371 1.632 15.9765 2.007 15.5714C2.385 15.1625 2.574 14.958 2.574 14.958L4.047 16.0759C4.047 16.0759 3.889 16.2651 3.572 16.6434C3.258 17.018 2.983 17.4021 2.746 17.7957C2.513 18.1855 2.335 18.5945 2.213 19.0225C2.091 19.4467 2.03 19.9168 2.03 20.4328ZM23.687 20.4271C23.687 19.9035 23.622 19.4276 23.492 18.9996C23.366 18.5715 23.188 18.1664 22.959 17.7843C22.729 17.3982 22.456 17.018 22.139 16.6434C21.822 16.2651 21.663 16.0759 21.663 16.0759L23.136 14.958C23.136 14.958 23.329 15.172 23.715 15.6001C24.105 16.0243 24.455 16.4906 24.765 16.9989C25.074 17.5072 25.309 18.0422 25.47 18.604C25.63 19.1658 25.71 19.7735 25.71 20.4271C25.71 21.1073 25.626 21.7303 25.458 22.2959C25.29 22.8577 25.049 23.3966 24.736 23.9126C24.422 24.4247 24.077 24.8833 23.698 25.2884C23.324 25.6974 23.136 25.9018 23.136 25.9018L21.663 24.7839C21.663 24.7839 21.82 24.5948 22.133 24.2164C22.45 23.8419 22.726 23.4597 22.959 23.0698C23.196 22.6762 23.375 22.2673 23.498 21.843C23.624 21.415 23.687 20.943 23.687 20.4271Z\"\n fill={color}\n />\n {/* Animated bunny eyes */}\n <circle\n className=\"bunny-eye-left\"\n cx=\"8.277\"\n cy=\"20.466\"\n r=\"1.8\"\n fill={color}\n />\n <circle\n className=\"bunny-eye-right\"\n cx=\"19.878\"\n cy=\"20.466\"\n r=\"1.8\"\n fill={color}\n />\n {/* Happy face on hover */}\n <text\n className=\"bunny-happy-face\"\n x=\"14\"\n y=\"26\"\n textAnchor=\"middle\"\n fontSize=\"12\"\n fontWeight=\"bold\"\n fill={color}\n fontFamily=\"system-ui, -apple-system, sans-serif\"\n >\n ˃ ᵕ ˂\n </text>\n </svg>\n);\n\n// Layout / grid icon for layout mode\nexport const IconLayout = ({ size = 24 }: { size?: number }) => (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\">\n <rect\n x=\"3\"\n y=\"3\"\n width=\"18\"\n height=\"18\"\n rx=\"2\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <line\n x1=\"3\"\n y1=\"9\"\n x2=\"21\"\n y2=\"9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <line\n x1=\"9\"\n y1=\"9\"\n x2=\"9\"\n y2=\"21\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n","// =============================================================================\n// Freeze Animations\n// =============================================================================\n//\n// Monkey-patches setTimeout, setInterval, and requestAnimationFrame so that\n// callbacks are silently skipped while frozen. Also injects CSS to pause\n// CSS animations/transitions, pauses WAAPI animations, and pauses videos.\n//\n// Toolbar/popup code must import `originalSetTimeout` etc. to bypass the patch.\n//\n// Patches are installed as a side effect of importing this module.\n// =============================================================================\n\n// Exclude selectors — agentation UI elements should never be frozen\nconst EXCLUDE_ATTRS = [\n \"data-feedback-toolbar\",\n \"data-annotation-popup\",\n \"data-annotation-marker\",\n];\nconst NOT_SELECTORS = EXCLUDE_ATTRS\n .flatMap((a) => [`:not([${a}])`, `:not([${a}] *)`])\n .join(\"\");\n\nconst STYLE_ID = \"feedback-freeze-styles\";\nconst STATE_KEY = \"__agentation_freeze\";\n\n// ---------------------------------------------------------------------------\n// Shared mutable state on window (survives HMR module re-execution)\n// ---------------------------------------------------------------------------\ninterface FreezeState {\n frozen: boolean;\n installed: boolean;\n origSetTimeout: typeof setTimeout;\n origSetInterval: typeof setInterval;\n origRAF: typeof requestAnimationFrame;\n // Queues live on window so they survive HMR module re-execution\n pausedAnimations: Animation[];\n frozenTimeoutQueue: Array<() => void>;\n frozenRAFQueue: FrameRequestCallback[];\n}\n\nfunction getState(): FreezeState {\n if (typeof window === \"undefined\") {\n // SSR stub\n return {\n frozen: false,\n installed: true, // prevent patching on server\n origSetTimeout: setTimeout,\n origSetInterval: setInterval,\n origRAF: (cb: FrameRequestCallback) => 0 as any,\n pausedAnimations: [],\n frozenTimeoutQueue: [],\n frozenRAFQueue: [],\n };\n }\n const w = window as any;\n if (!w[STATE_KEY]) {\n w[STATE_KEY] = {\n frozen: false,\n installed: false,\n origSetTimeout: null,\n origSetInterval: null,\n origRAF: null,\n pausedAnimations: [],\n frozenTimeoutQueue: [],\n frozenRAFQueue: [],\n };\n }\n return w[STATE_KEY];\n}\n\nconst _s = getState();\n\n// ---------------------------------------------------------------------------\n// Install patches (once — survives HMR because `installed` lives on window)\n// ---------------------------------------------------------------------------\nif (typeof window !== \"undefined\" && !_s.installed) {\n // Save the real functions\n _s.origSetTimeout = window.setTimeout.bind(window);\n _s.origSetInterval = window.setInterval.bind(window);\n _s.origRAF = window.requestAnimationFrame.bind(window);\n\n // Patch setTimeout — queue callback when frozen (replayed on unfreeze)\n (window as any).setTimeout = (\n handler: TimerHandler,\n timeout?: number,\n ...args: any[]\n ): ReturnType<typeof setTimeout> => {\n if (typeof handler === \"string\") {\n return _s.origSetTimeout(handler, timeout);\n }\n return _s.origSetTimeout(\n (...a: any[]) => {\n if (_s.frozen) {\n _s.frozenTimeoutQueue.push(() => (handler as Function)(...a));\n } else {\n (handler as Function)(...a);\n }\n },\n timeout,\n ...args,\n );\n };\n\n // Patch setInterval — skip callback when frozen\n (window as any).setInterval = (\n handler: TimerHandler,\n timeout?: number,\n ...args: any[]\n ): ReturnType<typeof setInterval> => {\n if (typeof handler === \"string\") {\n return _s.origSetInterval(handler, timeout);\n }\n return _s.origSetInterval(\n (...a: any[]) => {\n if (!_s.frozen) (handler as Function)(...a);\n },\n timeout,\n ...args,\n );\n };\n\n // Patch requestAnimationFrame — queue callback when frozen (no CPU spin)\n // The wrapper fires once on the next frame; if still frozen the callback\n // is stored in _s.frozenRAFQueue and replayed on unfreeze.\n (window as any).requestAnimationFrame = (\n callback: FrameRequestCallback,\n ): number => {\n return _s.origRAF((timestamp: number) => {\n if (_s.frozen) {\n _s.frozenRAFQueue.push(callback);\n } else {\n callback(timestamp);\n }\n });\n };\n\n _s.installed = true;\n}\n\n// ---------------------------------------------------------------------------\n// Exports — original (unpatched) timing functions for toolbar/popup use\n// ---------------------------------------------------------------------------\nexport const originalSetTimeout = _s.origSetTimeout;\nexport const originalSetInterval = _s.origSetInterval;\nexport const originalRequestAnimationFrame = _s.origRAF;\n\n// ---------------------------------------------------------------------------\n// Freeze / Unfreeze\n// ---------------------------------------------------------------------------\n\nfunction isAgentationElement(el: Element | null): boolean {\n if (!el) return false;\n return EXCLUDE_ATTRS.some((attr) => !!el.closest?.(`[${attr}]`));\n}\n\nexport function freeze(): void {\n if (typeof document === \"undefined\") return;\n if (_s.frozen) return;\n _s.frozen = true;\n _s.frozenTimeoutQueue = [];\n _s.frozenRAFQueue = [];\n\n // CSS injection — pause CSS animations and kill transitions\n let style = document.getElementById(STYLE_ID);\n if (!style) {\n style = document.createElement(\"style\");\n style.id = STYLE_ID;\n }\n style.textContent = `\n *${NOT_SELECTORS},\n *${NOT_SELECTORS}::before,\n *${NOT_SELECTORS}::after {\n animation-play-state: paused !important;\n transition: none !important;\n }\n `;\n document.head.appendChild(style);\n\n // WAAPI — pause only RUNNING non-agentation animations and store references\n // (pausing finished animations would restart them on play(), breaking entrance anims)\n _s.pausedAnimations = [];\n try {\n document.getAnimations().forEach((anim) => {\n if (anim.playState !== \"running\") return;\n const target = (anim.effect as KeyframeEffect)?.target as Element | null;\n if (!isAgentationElement(target)) {\n anim.pause();\n _s.pausedAnimations.push(anim);\n }\n });\n } catch {\n // getAnimations may not be available in all environments\n }\n\n // Pause videos\n document.querySelectorAll(\"video\").forEach((video) => {\n if (!video.paused) {\n video.dataset.wasPaused = \"false\";\n video.pause();\n }\n });\n}\n\nexport function unfreeze(): void {\n if (typeof document === \"undefined\") return;\n if (!_s.frozen) return;\n _s.frozen = false;\n\n // Replay queued setTimeout callbacks asynchronously (resolves stuck delay()\n // Promises, restarts animation loops interrupted by visibilitychange, etc.)\n // Using origSetTimeout(cb, 0) avoids blocking the main thread in one go.\n // Re-check _s.frozen before executing — if freeze() was called again between\n // scheduling and execution, re-queue the callback instead of running it.\n const timeoutQueue = _s.frozenTimeoutQueue;\n _s.frozenTimeoutQueue = [];\n for (const cb of timeoutQueue) {\n _s.origSetTimeout(() => {\n if (_s.frozen) {\n _s.frozenTimeoutQueue.push(cb);\n return;\n }\n try {\n cb();\n } catch (e) {\n console.warn(\"[agentation] Error replaying queued timeout:\", e);\n }\n }, 0);\n }\n\n // Schedule queued rAF callbacks for the next frame.\n // Re-check _s.frozen — if re-frozen before the frame fires, re-queue.\n const rafQueue = _s.frozenRAFQueue;\n _s.frozenRAFQueue = [];\n for (const cb of rafQueue) {\n _s.origRAF((ts: number) => {\n if (_s.frozen) {\n _s.frozenRAFQueue.push(cb);\n return;\n }\n cb(ts);\n });\n }\n\n // WAAPI — resume the exact animations we paused BEFORE removing CSS\n // (removing CSS first can cause the browser to replace animation objects)\n for (const anim of _s.pausedAnimations) {\n try {\n anim.play();\n } catch (e) {\n console.warn(\"[agentation] Error resuming animation:\", e);\n }\n }\n _s.pausedAnimations = [];\n\n // Now remove CSS injection\n document.getElementById(STYLE_ID)?.remove();\n\n // Resume videos\n document.querySelectorAll(\"video\").forEach((video) => {\n if (video.dataset.wasPaused === \"false\") {\n video.play().catch(() => {});\n delete video.dataset.wasPaused;\n }\n });\n}\n","// =============================================================================\n// Element Identification Utilities\n// =============================================================================\n\n// =============================================================================\n// Shadow DOM Helpers\n// =============================================================================\n\n/**\n * Gets the parent element, crossing shadow DOM boundaries.\n * When inside a shadow root with no parentElement, returns the shadow host.\n */\nfunction getParentElement(element: Element): Element | null {\n if (element.parentElement) {\n return element.parentElement;\n }\n const root = element.getRootNode();\n if (root instanceof ShadowRoot) {\n return root.host;\n }\n return null;\n}\n\n/**\n * Finds the closest ancestor matching a selector, crossing shadow DOM boundaries.\n */\nexport function closestCrossingShadow(element: Element, selector: string): Element | null {\n let current: Element | null = element;\n while (current) {\n if (current.matches(selector)) return current;\n current = getParentElement(current);\n }\n return null;\n}\n\n/**\n * Checks if an element is inside a shadow DOM\n */\nexport function isInShadowDOM(element: Element): boolean {\n return element.getRootNode() instanceof ShadowRoot;\n}\n\n/**\n * Gets the shadow host for an element, or null if not in shadow DOM\n */\nexport function getShadowHost(element: Element): Element | null {\n const root = element.getRootNode();\n if (root instanceof ShadowRoot) {\n return root.host;\n }\n return null;\n}\n\n// =============================================================================\n// Element Path Utilities\n// =============================================================================\n\n/**\n * Gets a readable path for an element (e.g., \"article > section > p\")\n * Supports elements inside shadow DOM by crossing shadow boundaries.\n */\nexport function getElementPath(target: HTMLElement, maxDepth = 4): string {\n const parts: string[] = [];\n let current: HTMLElement | null = target;\n let depth = 0;\n\n while (current && depth < maxDepth) {\n const tag = current.tagName.toLowerCase();\n\n // Skip generic wrappers\n if (tag === \"html\" || tag === \"body\") break;\n\n // Get identifier\n let identifier = tag;\n if (current.id) {\n identifier = `#${current.id}`;\n } else if (current.className && typeof current.className === \"string\") {\n const meaningfulClass = current.className\n .split(/\\s+/)\n .find(c => c.length > 2 && !c.match(/^[a-z]{1,2}$/) && !c.match(/[A-Z0-9]{5,}/));\n if (meaningfulClass) {\n identifier = `.${meaningfulClass.split(\"_\")[0]}`;\n }\n }\n\n // Mark shadow boundary crossings\n const nextParent = getParentElement(current);\n if (!current.parentElement && nextParent) {\n identifier = `⟨shadow⟩ ${identifier}`;\n }\n\n parts.unshift(identifier);\n current = nextParent as HTMLElement | null;\n depth++;\n }\n\n return parts.join(\" > \");\n}\n\n/**\n * Identifies an element and returns a human-readable name + path\n */\nexport function identifyElement(target: HTMLElement): { name: string; path: string } {\n const path = getElementPath(target);\n\n if (target.dataset.element) {\n return { name: target.dataset.element, path };\n }\n\n const tag = target.tagName.toLowerCase();\n\n // SVG elements\n if ([\"path\", \"circle\", \"rect\", \"line\", \"g\"].includes(tag)) {\n // Try to find parent SVG context (crossing shadow boundaries)\n const svg = closestCrossingShadow(target, \"svg\");\n if (svg) {\n const parent = getParentElement(svg);\n if (parent instanceof HTMLElement) {\n const parentName = identifyElement(parent).name;\n return { name: `graphic in ${parentName}`, path };\n }\n }\n return { name: \"graphic element\", path };\n }\n if (tag === \"svg\") {\n const parent = getParentElement(target);\n if (parent?.tagName.toLowerCase() === \"button\") {\n const btnText = parent.textContent?.trim();\n return { name: btnText ? `icon in \"${btnText}\" button` : \"button icon\", path };\n }\n return { name: \"icon\", path };\n }\n\n // Interactive elements\n if (tag === \"button\") {\n const text = target.textContent?.trim();\n const ariaLabel = target.getAttribute(\"aria-label\");\n if (ariaLabel) return { name: `button [${ariaLabel}]`, path };\n return { name: text ? `button \"${text.slice(0, 25)}\"` : \"button\", path };\n }\n if (tag === \"a\") {\n const text = target.textContent?.trim();\n const href = target.getAttribute(\"href\");\n if (text) return { name: `link \"${text.slice(0, 25)}\"`, path };\n if (href) return { name: `link to ${href.slice(0, 30)}`, path };\n return { name: \"link\", path };\n }\n if (tag === \"input\") {\n const type = target.getAttribute(\"type\") || \"text\";\n const placeholder = target.getAttribute(\"placeholder\");\n const name = target.getAttribute(\"name\");\n if (placeholder) return { name: `input \"${placeholder}\"`, path };\n if (name) return { name: `input [${name}]`, path };\n return { name: `${type} input`, path };\n }\n\n // Headings\n if ([\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\"].includes(tag)) {\n const text = target.textContent?.trim();\n return { name: text ? `${tag} \"${text.slice(0, 35)}\"` : tag, path };\n }\n\n // Text elements\n if (tag === \"p\") {\n const text = target.textContent?.trim();\n if (text) return { name: `paragraph: \"${text.slice(0, 40)}${text.length > 40 ? '...' : ''}\"`, path };\n return { name: \"paragraph\", path };\n }\n if (tag === \"span\" || tag === \"label\") {\n const text = target.textContent?.trim();\n if (text && text.length < 40) return { name: `\"${text}\"`, path };\n return { name: tag, path };\n }\n if (tag === \"li\") {\n const text = target.textContent?.trim();\n if (text && text.length < 40) return { name: `list item: \"${text.slice(0, 35)}\"`, path };\n return { name: \"list item\", path };\n }\n if (tag === \"blockquote\") return { name: \"blockquote\", path };\n if (tag === \"code\") {\n const text = target.textContent?.trim();\n if (text && text.length < 30) return { name: `code: \\`${text}\\``, path };\n return { name: \"code\", path };\n }\n if (tag === \"pre\") return { name: \"code block\", path };\n\n // Media\n if (tag === \"img\") {\n const alt = target.getAttribute(\"alt\");\n return { name: alt ? `image \"${alt.slice(0, 30)}\"` : \"image\", path };\n }\n if (tag === \"video\") return { name: \"video\", path };\n\n // Containers - try to infer meaningful name\n if ([\"div\", \"section\", \"article\", \"nav\", \"header\", \"footer\", \"aside\", \"main\"].includes(tag)) {\n const className = target.className;\n const role = target.getAttribute(\"role\");\n const ariaLabel = target.getAttribute(\"aria-label\");\n\n if (ariaLabel) return { name: `${tag} [${ariaLabel}]`, path };\n if (role) return { name: `${role}`, path };\n\n if (typeof className === \"string\" && className) {\n const words = className\n .split(/[\\s_-]+/)\n .map((c) => c.replace(/[A-Z0-9]{5,}.*$/, \"\")) // Remove CSS module hashes\n .filter((c) => c.length > 2 && !/^[a-z]{1,2}$/.test(c))\n .slice(0, 2);\n if (words.length > 0) return { name: words.join(\" \"), path };\n }\n\n return { name: tag === \"div\" ? \"container\" : tag, path };\n }\n\n return { name: tag, path };\n}\n\n/**\n * Gets text content from element and siblings for context\n */\nexport function getNearbyText(element: HTMLElement): string {\n const texts: string[] = [];\n\n // Own text\n const ownText = element.textContent?.trim();\n if (ownText && ownText.length < 100) {\n texts.push(ownText);\n }\n\n // Previous sibling text\n const prev = element.previousElementSibling;\n if (prev) {\n const prevText = prev.textContent?.trim();\n if (prevText && prevText.length < 50) {\n texts.unshift(`[before: \"${prevText.slice(0, 40)}\"]`);\n }\n }\n\n // Next sibling text\n const next = element.nextElementSibling;\n if (next) {\n const nextText = next.textContent?.trim();\n if (nextText && nextText.length < 50) {\n texts.push(`[after: \"${nextText.slice(0, 40)}\"]`);\n }\n }\n\n return texts.join(\" \");\n}\n\n/**\n * Simplified element identifier for animation feedback (less verbose)\n */\nexport function identifyAnimationElement(target: HTMLElement): string {\n // Allow explicit labeling via data attribute\n if (target.dataset.element) return target.dataset.element;\n\n const tag = target.tagName.toLowerCase();\n\n // SVG elements\n if (tag === \"path\") return \"path\";\n if (tag === \"circle\") return \"circle\";\n if (tag === \"rect\") return \"rectangle\";\n if (tag === \"line\") return \"line\";\n if (tag === \"ellipse\") return \"ellipse\";\n if (tag === \"polygon\") return \"polygon\";\n if (tag === \"g\") return \"group\";\n if (tag === \"svg\") return \"svg\";\n\n // Interactive elements\n if (tag === \"button\") {\n const text = target.textContent?.trim();\n return text ? `button \"${text}\"` : \"button\";\n }\n if (tag === \"input\") {\n const type = target.getAttribute(\"type\") || \"text\";\n return `input (${type})`;\n }\n\n // Text elements\n if (tag === \"span\" || tag === \"p\" || tag === \"label\") {\n const text = target.textContent?.trim();\n if (text && text.length < 30) return `\"${text}\"`;\n return \"text\";\n }\n\n // Containers - try to infer purpose from class name\n if (tag === \"div\") {\n const className = target.className;\n if (typeof className === \"string\" && className) {\n const words = className\n .split(/[\\s_-]+/)\n .map(c => c.replace(/[A-Z0-9]{5,}.*$/, \"\"))\n .filter(c => c.length > 2 && !/^[a-z]{1,2}$/.test(c))\n .slice(0, 2);\n if (words.length > 0) {\n return words.join(\" \");\n }\n }\n return \"container\";\n }\n\n return tag;\n}\n\n/**\n * Gets nearby sibling elements for structural context.\n * Supports elements inside shadow DOM.\n */\nexport function getNearbyElements(element: HTMLElement): string {\n const parent = getParentElement(element);\n if (!parent) return \"\";\n\n // Get siblings from the correct source\n const elementRoot = element.getRootNode();\n const children = (elementRoot instanceof ShadowRoot && element.parentElement)\n ? Array.from(element.parentElement.children)\n : Array.from(parent.children);\n\n const siblings = children.filter(\n (child) => child !== element && child instanceof HTMLElement\n ) as HTMLElement[];\n\n if (siblings.length === 0) return \"\";\n\n // Get concise identifiers for up to 4 nearby siblings\n const siblingIds = siblings.slice(0, 4).map((sib) => {\n const tag = sib.tagName.toLowerCase();\n const className = sib.className;\n\n // Get first meaningful class\n let cls = \"\";\n if (typeof className === \"string\" && className) {\n const meaningful = className\n .split(/\\s+/)\n .map((c) => c.replace(/[_][a-zA-Z0-9]{5,}.*$/, \"\")) // Remove module hashes\n .find((c) => c.length > 2 && !/^[a-z]{1,2}$/.test(c));\n if (meaningful) cls = `.${meaningful}`;\n }\n\n // For buttons/links, include short text\n if (tag === \"button\" || tag === \"a\") {\n const text = sib.textContent?.trim().slice(0, 15);\n if (text) return `${tag}${cls} \"${text}\"`;\n }\n\n return `${tag}${cls}`;\n });\n\n // Add parent context\n const parentTag = parent.tagName.toLowerCase();\n let parentId = parentTag;\n if (typeof parent.className === \"string\" && parent.className) {\n const parentCls = parent.className\n .split(/\\s+/)\n .map((c) => c.replace(/[_][a-zA-Z0-9]{5,}.*$/, \"\"))\n .find((c) => c.length > 2 && !/^[a-z]{1,2}$/.test(c));\n if (parentCls) parentId = `.${parentCls}`;\n }\n\n const total = parent.children.length;\n const suffix = total > siblingIds.length + 1 ? ` (${total} total in ${parentId})` : \"\";\n\n return siblingIds.join(\", \") + suffix;\n}\n\n/**\n * Gets CSS class names from an element (cleaned of module hashes)\n */\nexport function getElementClasses(target: HTMLElement): string {\n const className = target.className;\n if (typeof className !== \"string\" || !className) return \"\";\n\n // Split and clean class names (remove module hashes like _abc123)\n const classes = className\n .split(/\\s+/)\n .filter(c => c.length > 0)\n .map(c => {\n // Keep the meaningful part before the hash\n const match = c.match(/^([a-zA-Z][a-zA-Z0-9_-]*?)(?:_[a-zA-Z0-9]{5,})?$/);\n return match ? match[1] : c;\n })\n .filter((c, i, arr) => arr.indexOf(c) === i); // dedupe\n\n return classes.join(\", \");\n}\n\n/**\n * Gets key computed styles for an element (useful for styling issues)\n */\nexport function getComputedStylesSnapshot(target: HTMLElement): string {\n if (typeof window === \"undefined\") return \"\";\n\n const styles = window.getComputedStyle(target);\n const parts: string[] = [];\n\n // Color & text\n const color = styles.color;\n const bg = styles.backgroundColor;\n if (color && color !== \"rgb(0, 0, 0)\") parts.push(`color: ${color}`);\n if (bg && bg !== \"rgba(0, 0, 0, 0)\" && bg !== \"transparent\") parts.push(`bg: ${bg}`);\n\n // Typography\n const fontSize = styles.fontSize;\n const fontWeight = styles.fontWeight;\n if (fontSize) parts.push(`font: ${fontSize}`);\n if (fontWeight && fontWeight !== \"400\" && fontWeight !== \"normal\") parts.push(`weight: ${fontWeight}`);\n\n // Spacing\n const padding = styles.padding;\n const margin = styles.margin;\n if (padding && padding !== \"0px\") parts.push(`padding: ${padding}`);\n if (margin && margin !== \"0px\") parts.push(`margin: ${margin}`);\n\n // Layout\n const display = styles.display;\n const position = styles.position;\n if (display && display !== \"block\" && display !== \"inline\") parts.push(`display: ${display}`);\n if (position && position !== \"static\") parts.push(`position: ${position}`);\n\n // Border\n const borderRadius = styles.borderRadius;\n if (borderRadius && borderRadius !== \"0px\") parts.push(`radius: ${borderRadius}`);\n\n return parts.join(\", \");\n}\n\n// Values to filter out when collecting computed styles (browser defaults / uninteresting)\nconst DEFAULT_STYLE_VALUES = new Set([\n \"none\", \"normal\", \"auto\", \"0px\", \"rgba(0, 0, 0, 0)\", \"transparent\", \"static\", \"visible\"\n]);\n\n// Element type categories for style property selection\nconst TEXT_ELEMENTS = new Set([\n \"p\", \"span\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"label\", \"li\", \"td\", \"th\",\n \"blockquote\", \"figcaption\", \"caption\", \"legend\", \"dt\", \"dd\", \"pre\", \"code\",\n \"em\", \"strong\", \"b\", \"i\", \"a\", \"time\", \"cite\", \"q\"\n]);\nconst FORM_INPUT_ELEMENTS = new Set([\"input\", \"textarea\", \"select\"]);\nconst MEDIA_ELEMENTS = new Set([\"img\", \"video\", \"canvas\", \"svg\"]);\nconst CONTAINER_ELEMENTS = new Set([\n \"div\", \"section\", \"article\", \"nav\", \"header\", \"footer\", \"aside\", \"main\",\n \"ul\", \"ol\", \"form\", \"fieldset\"\n]);\n\n/**\n * Gets key computed styles for the annotation popup display.\n * Returns different properties based on element type to show the most relevant\n * CSS properties for debugging (e.g., typography for text, layout for containers).\n */\nexport function getDetailedComputedStyles(target: HTMLElement): Record<string, string> {\n if (typeof window === \"undefined\") return {};\n\n const styles = window.getComputedStyle(target);\n const result: Record<string, string> = {};\n const tag = target.tagName.toLowerCase();\n\n // Select relevant properties based on element type\n let properties: string[];\n\n if (TEXT_ELEMENTS.has(tag)) {\n // Typography-focused for text elements\n properties = [\"color\", \"fontSize\", \"fontWeight\", \"fontFamily\", \"lineHeight\"];\n } else if (tag === \"button\" || (tag === \"a\" && target.getAttribute(\"role\") === \"button\")) {\n // Appearance and spacing for interactive elements\n properties = [\"backgroundColor\", \"color\", \"padding\", \"borderRadius\", \"fontSize\"];\n } else if (FORM_INPUT_ELEMENTS.has(tag)) {\n // Form styling\n properties = [\"backgroundColor\", \"color\", \"padding\", \"borderRadius\", \"fontSize\"];\n } else if (MEDIA_ELEMENTS.has(tag)) {\n // Dimensions for media\n properties = [\"width\", \"height\", \"objectFit\", \"borderRadius\"];\n } else if (CONTAINER_ELEMENTS.has(tag)) {\n // Layout-focused for containers\n properties = [\"display\", \"padding\", \"margin\", \"gap\", \"backgroundColor\"];\n } else {\n // Default fallback\n properties = [\"color\", \"fontSize\", \"margin\", \"padding\", \"backgroundColor\"];\n }\n\n for (const prop of properties) {\n const cssPropertyName = prop.replace(/([A-Z])/g, \"-$1\").toLowerCase();\n const value = styles.getPropertyValue(cssPropertyName);\n if (value && !DEFAULT_STYLE_VALUES.has(value)) {\n result[prop] = value;\n }\n }\n\n return result;\n}\n\n// Comprehensive list of CSS properties for forensic output\nconst FORENSIC_PROPERTIES = [\n // Colors\n \"color\", \"backgroundColor\", \"borderColor\",\n // Typography\n \"fontSize\", \"fontWeight\", \"fontFamily\", \"lineHeight\", \"letterSpacing\", \"textAlign\",\n // Box model\n \"width\", \"height\", \"padding\", \"margin\", \"border\", \"borderRadius\",\n // Layout & positioning\n \"display\", \"position\", \"top\", \"right\", \"bottom\", \"left\", \"zIndex\",\n \"flexDirection\", \"justifyContent\", \"alignItems\", \"gap\",\n // Visual effects\n \"opacity\", \"visibility\", \"overflow\", \"boxShadow\",\n // Transform\n \"transform\",\n];\n\n/**\n * Gets full computed styles for forensic output.\n * Returns a comprehensive semicolon-separated string of all relevant CSS properties\n * for maximum debugging detail in the forensic output format.\n */\nexport function getForensicComputedStyles(target: HTMLElement): string {\n if (typeof window === \"undefined\") return \"\";\n\n const styles = window.getComputedStyle(target);\n const parts: string[] = [];\n\n for (const prop of FORENSIC_PROPERTIES) {\n const cssPropertyName = prop.replace(/([A-Z])/g, \"-$1\").toLowerCase();\n const value = styles.getPropertyValue(cssPropertyName);\n if (value && !DEFAULT_STYLE_VALUES.has(value)) {\n parts.push(`${cssPropertyName}: ${value}`);\n }\n }\n\n return parts.join(\"; \");\n}\n\n/**\n * Parses a forensic computed styles string back into a Record.\n * Inverse of getForensicComputedStyles - used when editing annotations.\n */\nexport function parseComputedStylesString(\n stylesStr: string | undefined,\n): Record<string, string> | undefined {\n if (!stylesStr) return undefined;\n\n const result: Record<string, string> = {};\n const parts = stylesStr.split(\";\").map((p) => p.trim()).filter(Boolean);\n\n for (const part of parts) {\n const colonIndex = part.indexOf(\":\");\n if (colonIndex > 0) {\n const key = part.slice(0, colonIndex).trim();\n const value = part.slice(colonIndex + 1).trim();\n if (key && value) {\n result[key] = value;\n }\n }\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\n/**\n * Gets accessibility information for an element\n */\nexport function getAccessibilityInfo(target: HTMLElement): string {\n const parts: string[] = [];\n\n const role = target.getAttribute(\"role\");\n const ariaLabel = target.getAttribute(\"aria-label\");\n const ariaDescribedBy = target.getAttribute(\"aria-describedby\");\n const tabIndex = target.getAttribute(\"tabindex\");\n const ariaHidden = target.getAttribute(\"aria-hidden\");\n\n if (role) parts.push(`role=\"${role}\"`);\n if (ariaLabel) parts.push(`aria-label=\"${ariaLabel}\"`);\n if (ariaDescribedBy) parts.push(`aria-describedby=\"${ariaDescribedBy}\"`);\n if (tabIndex) parts.push(`tabindex=${tabIndex}`);\n if (ariaHidden === \"true\") parts.push(\"aria-hidden\");\n\n // Check focusability\n const focusable = target.matches(\"a, button, input, select, textarea, [tabindex]\");\n if (focusable) parts.push(\"focusable\");\n\n return parts.join(\", \");\n}\n\n/**\n * Gets full DOM ancestry path (for forensic mode).\n * Supports elements inside shadow DOM by marking shadow boundary crossings.\n */\nexport function getFullElementPath(target: HTMLElement): string {\n const parts: string[] = [];\n let current: HTMLElement | null = target;\n\n while (current && current.tagName.toLowerCase() !== \"html\") {\n const tag = current.tagName.toLowerCase();\n let identifier = tag;\n\n if (current.id) {\n identifier = `${tag}#${current.id}`;\n } else if (current.className && typeof current.className === \"string\") {\n const cls = current.className\n .split(/\\s+/)\n .map(c => c.replace(/[_][a-zA-Z0-9]{5,}.*$/, \"\"))\n .find(c => c.length > 2);\n if (cls) identifier = `${tag}.${cls}`;\n }\n\n // Mark shadow boundary crossings\n const nextParent = getParentElement(current);\n if (!current.parentElement && nextParent) {\n identifier = `⟨shadow⟩ ${identifier}`;\n }\n\n parts.unshift(identifier);\n current = nextParent as HTMLElement | null;\n }\n\n return parts.join(\" > \");\n}\n","// =============================================================================\n// React Component Name Detection\n// Uses React DevTools techniques to extract component names from fiber nodes\n// =============================================================================\n\n/**\n * React Fiber node type (minimal subset we care about)\n * Based on React internal structure\n */\ninterface ReactFiber {\n tag: number;\n type: ComponentType | string | null;\n elementType: ComponentType | null;\n return: ReactFiber | null;\n}\n\ninterface ComponentType {\n name?: string;\n displayName?: string;\n render?: { name?: string; displayName?: string };\n type?: ComponentType;\n _context?: { displayName?: string };\n _status?: number;\n _result?: ComponentType;\n $$typeof?: symbol;\n}\n\n/**\n * Fiber tags from React source (stable across versions)\n * https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactWorkTags.js\n */\nconst FiberTags = {\n FunctionComponent: 0,\n ClassComponent: 1,\n IndeterminateComponent: 2,\n HostRoot: 3,\n HostPortal: 4,\n HostComponent: 5, // DOM elements like <div>\n HostText: 6,\n Fragment: 7,\n Mode: 8,\n ContextConsumer: 9,\n ContextProvider: 10,\n ForwardRef: 11,\n Profiler: 12,\n SuspenseComponent: 13,\n MemoComponent: 14,\n SimpleMemoComponent: 15,\n LazyComponent: 16,\n // React 18/19 additions\n IncompleteClassComponent: 17,\n DehydratedFragment: 18,\n SuspenseListComponent: 19,\n // Note: 20 is unused/reserved\n ScopeComponent: 21,\n OffscreenComponent: 22,\n LegacyHiddenComponent: 23,\n CacheComponent: 24,\n TracingMarkerComponent: 25,\n HostHoistable: 26,\n HostSingleton: 27,\n IncompleteFunctionComponent: 28,\n Throw: 29,\n ViewTransitionComponent: 30,\n ActivityComponent: 31,\n} as const;\n\n// =============================================================================\n// Default Filter Configuration\n// =============================================================================\n\n/**\n * Default exact names to always skip (React internals)\n */\nexport const DEFAULT_SKIP_EXACT = new Set([\n \"Component\",\n \"PureComponent\",\n \"Fragment\",\n \"Suspense\",\n \"Profiler\",\n \"StrictMode\",\n \"Routes\",\n \"Route\",\n \"Outlet\",\n // Framework internals - exact matches\n \"Root\",\n \"ErrorBoundaryHandler\",\n \"HotReload\",\n \"Hot\",\n]);\n\n/**\n * Default patterns for framework internals\n * Note: Patterns are designed to be specific to avoid false positives\n * (e.g., ServerStatus, ClientProfile should NOT be filtered)\n */\nexport const DEFAULT_SKIP_PATTERNS: RegExp[] = [\n /Boundary$/, // ErrorBoundary, RedirectBoundary\n /BoundaryHandler$/, // ErrorBoundaryHandler\n /Provider$/, // ThemeProvider, Context.Provider\n /Consumer$/, // Context.Consumer\n /^(Inner|Outer)/, // InnerLayoutRouter\n /Router$/, // AppRouter, BrowserRouter\n /^Client(Page|Segment|Root)/, // ClientPageRoot, ClientSegmentRoot\n /^Segment(ViewNode|Node)$/, // Next.js App Router internals\n /^LayoutSegment/, // Next.js layout segment wrappers\n /^Server(Root|Component|Render)/, // ServerRoot (not ServerStatus)\n /^RSC/, // RSCComponent\n /Context$/, // LayoutRouterContext\n /^Hot(Reload)?$/, // HotReload (exact match to avoid false positives)\n /^(Dev|React)(Overlay|Tools|Root)/, // DevTools, ReactDevOverlay\n /Overlay$/, // ReactDevOverlay, ErrorOverlay\n /Handler$/, // ScrollAndFocusHandler, ErrorBoundaryHandler\n /^With[A-Z]/, // withRouter, WithAuth (HOCs)\n /Wrapper$/, // Generic wrappers\n /^Root$/, // Generic Root component\n];\n\n/**\n * Patterns that indicate likely user-defined components\n * Used as fallback in 'smart' mode\n */\nconst DEFAULT_USER_PATTERNS: RegExp[] = [\n /Page$/, // HomePage, InstallPage\n /View$/, // ListView, DetailView\n /Screen$/, // HomeScreen\n /Section$/, // HeroSection\n /Card$/, // ProductCard\n /List$/, // UserList\n /Item$/, // ListItem, MenuItem\n /Form$/, // LoginForm\n /Modal$/, // ConfirmModal\n /Dialog$/, // AlertDialog\n /Button$/, // SubmitButton (but not all buttons)\n /Nav$/, // SideNav, TopNav\n /Header$/, // PageHeader\n /Footer$/, // PageFooter\n /Layout$/, // MainLayout (careful - could be framework)\n /Panel$/, // SidePanel\n /Tab$/, // SettingsTab\n /Menu$/, // DropdownMenu\n];\n\n// =============================================================================\n// Configuration Types\n// =============================================================================\n\nexport type ReactDetectionMode = \"all\" | \"filtered\" | \"smart\";\n\nexport interface ReactDetectionConfig {\n /**\n * How many component names to collect\n * @default 3\n */\n maxComponents?: number;\n\n /**\n * Maximum fiber depth to traverse\n * @default 25\n */\n maxDepth?: number;\n\n /**\n * Detection mode:\n * - 'smart': Only show components that correlate with DOM classes (strictest, most relevant)\n * - 'filtered': Skip known framework internals (default)\n * - 'all': Show all components (no filtering)\n * @default 'filtered'\n */\n mode?: ReactDetectionMode;\n\n /**\n * Additional exact names to skip (merged with defaults in 'filtered' mode)\n */\n skipExact?: Set<string> | string[];\n\n /**\n * Additional patterns to skip (merged with defaults in 'filtered' mode)\n */\n skipPatterns?: RegExp[];\n\n /**\n * Patterns for user components (used as fallback in 'smart' mode)\n */\n userPatterns?: RegExp[];\n\n /**\n * Custom filter function for full control\n * Return true to INCLUDE the component, false to skip\n */\n filter?: (name: string, depth: number) => boolean;\n}\n\n/**\n * Resolved configuration with all defaults applied\n */\ninterface ResolvedConfig {\n maxComponents: number;\n maxDepth: number;\n mode: ReactDetectionMode;\n skipExact: Set<string>;\n skipPatterns: RegExp[];\n userPatterns: RegExp[];\n filter?: (name: string, depth: number) => boolean;\n}\n\nfunction resolveConfig(config?: ReactDetectionConfig): ResolvedConfig {\n const mode = config?.mode ?? \"filtered\";\n\n // Convert skipExact to Set if array\n let skipExact = DEFAULT_SKIP_EXACT;\n if (config?.skipExact) {\n const additional =\n config.skipExact instanceof Set\n ? config.skipExact\n : new Set(config.skipExact);\n skipExact = new Set([...DEFAULT_SKIP_EXACT, ...additional]);\n }\n\n return {\n maxComponents: config?.maxComponents ?? 6,\n maxDepth: config?.maxDepth ?? 30,\n mode,\n skipExact,\n skipPatterns: config?.skipPatterns\n ? [...DEFAULT_SKIP_PATTERNS, ...config.skipPatterns]\n : DEFAULT_SKIP_PATTERNS,\n userPatterns: config?.userPatterns ?? DEFAULT_USER_PATTERNS,\n filter: config?.filter,\n };\n}\n\n// =============================================================================\n// Filter Logic\n// =============================================================================\n\n/**\n * Normalize a component name to match CSS class conventions\n * SideNav -> side-nav, LinkComponent -> link-component\n */\nfunction normalizeComponentName(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, \"$1-$2\")\n .replace(/([A-Z])([A-Z][a-z])/g, \"$1-$2\")\n .toLowerCase();\n}\n\n/**\n * Collect CSS classes from an element and its ancestors\n */\nfunction getAncestorClasses(element: HTMLElement, maxDepth = 10): Set<string> {\n const classes = new Set<string>();\n let current: HTMLElement | null = element;\n let depth = 0;\n\n while (current && depth < maxDepth) {\n if (current.className && typeof current.className === \"string\") {\n current.className.split(/\\s+/).forEach((cls) => {\n if (cls.length > 1) {\n // Normalize: remove CSS module hashes, convert to lowercase\n const normalized = cls\n .replace(/[_][a-zA-Z0-9]{5,}.*$/, \"\")\n .toLowerCase();\n if (normalized.length > 1) {\n classes.add(normalized);\n }\n }\n });\n }\n current = current.parentElement;\n depth++;\n }\n\n return classes;\n}\n\n/**\n * Check if a component name correlates with any DOM class\n */\nfunction componentCorrelatesWithDOM(\n componentName: string,\n domClasses: Set<string>,\n): boolean {\n const normalized = normalizeComponentName(componentName);\n\n for (const cls of domClasses) {\n // Exact match: SideNav -> side-nav\n if (cls === normalized) return true;\n\n // Contains match: LinkComponent -> nav-link contains \"link\"\n // Split both by hyphens and check for word overlaps\n const componentWords = normalized.split(\"-\").filter((w) => w.length > 2);\n const classWords = cls.split(\"-\").filter((w) => w.length > 2);\n\n for (const cWord of componentWords) {\n for (const dWord of classWords) {\n if (cWord === dWord || cWord.includes(dWord) || dWord.includes(cWord)) {\n return true;\n }\n }\n }\n }\n\n return false;\n}\n\nfunction shouldIncludeComponent(\n name: string,\n depth: number,\n config: ResolvedConfig,\n domClasses?: Set<string>,\n): boolean {\n // Custom filter takes precedence\n if (config.filter) {\n return config.filter(name, depth);\n }\n\n switch (config.mode) {\n case \"all\":\n // \"all\" mode shows everything - no filtering at all\n return true;\n\n case \"filtered\":\n // \"filtered\" mode skips framework internals\n if (config.skipExact.has(name)) {\n return false;\n }\n if (config.skipPatterns.some((p) => p.test(name))) {\n return false;\n }\n return true;\n\n case \"smart\":\n // \"smart\" mode: first apply framework filters, then require DOM correlation\n if (config.skipExact.has(name)) {\n return false;\n }\n if (config.skipPatterns.some((p) => p.test(name))) {\n return false;\n }\n // Must correlate with DOM classes OR match user patterns\n if (domClasses && componentCorrelatesWithDOM(name, domClasses)) {\n return true;\n }\n if (config.userPatterns.some((p) => p.test(name))) {\n return true;\n }\n // Skip components that don't correlate - this mode is intentionally strict\n return false;\n\n default:\n return true;\n }\n}\n\n// =============================================================================\n// React Detection\n// =============================================================================\n\nlet reactDetectionCache: boolean | null = null;\n\n// Only cache for 'all' mode - filtered modes should NOT cache because:\n// 1. Filter results depend on config that may change between calls\n// 2. Cached results from before filter changes would return stale/unfiltered data\n// 3. The cache lookup happens BEFORE filtering, so old cached data bypasses filters\n// Using WeakMap allows garbage collection when elements are removed from DOM.\nconst componentCacheAll = new WeakMap<HTMLElement, ReactComponentInfo>();\n\n/**\n * Checks if React is present on the page\n */\n/**\n * Check if an element has React fiber keys\n */\nfunction hasReactFiber(element: Element): boolean {\n return Object.keys(element).some(\n (key) =>\n key.startsWith(\"__reactFiber$\") ||\n key.startsWith(\"__reactInternalInstance$\") ||\n key.startsWith(\"__reactProps$\"),\n );\n}\n\n/**\n * Checks if React is present on the page.\n * Scans common React root containers since React typically mounts\n * to #root, #app, #__next, etc. rather than document.body directly.\n */\nexport function isReactPage(): boolean {\n if (reactDetectionCache !== null) {\n return reactDetectionCache;\n }\n\n if (typeof document === \"undefined\") {\n return false;\n }\n\n // Check body first (some apps mount directly to body)\n if (document.body && hasReactFiber(document.body)) {\n reactDetectionCache = true;\n return true;\n }\n\n // Check common React root containers\n const commonRoots = [\"#root\", \"#app\", \"#__next\", \"[data-reactroot]\"];\n for (const selector of commonRoots) {\n const el = document.querySelector(selector);\n if (el && hasReactFiber(el)) {\n reactDetectionCache = true;\n return true;\n }\n }\n\n // Scan immediate children of body as fallback\n if (document.body) {\n for (const child of document.body.children) {\n if (hasReactFiber(child)) {\n reactDetectionCache = true;\n return true;\n }\n }\n }\n\n reactDetectionCache = false;\n return false;\n}\n\n// Wrapper object to allow cache clearing (WeakMap has no clear() method)\nlet componentCacheAllRef = { map: componentCacheAll };\n\n/**\n * Clears the React detection cache\n * Note: Only 'all' mode uses caching; filtered modes don't cache to avoid stale filter results\n */\nexport function clearReactDetectionCache(): void {\n reactDetectionCache = null;\n componentCacheAllRef.map = new WeakMap<HTMLElement, ReactComponentInfo>();\n}\n\nfunction getReactFiberKey(element: HTMLElement): string | null {\n const keys = Object.keys(element);\n return (\n keys.find(\n (key) =>\n key.startsWith(\"__reactFiber$\") ||\n key.startsWith(\"__reactInternalInstance$\"),\n ) || null\n );\n}\n\nfunction getFiberFromElement(element: HTMLElement): ReactFiber | null {\n const key = getReactFiberKey(element);\n if (!key) return null;\n return (element as unknown as Record<string, unknown>)[\n key\n ] as ReactFiber | null;\n}\n\nfunction getComponentNameFromType(type: ComponentType | null): string | null {\n if (!type) return null;\n if (type.displayName) return type.displayName;\n if (type.name) return type.name;\n return null;\n}\n\nfunction getComponentNameFromFiber(fiber: ReactFiber): string | null {\n const { tag, type, elementType } = fiber;\n\n // Skip DOM elements and host types\n if (\n tag === FiberTags.HostComponent ||\n tag === FiberTags.HostText ||\n tag === FiberTags.HostHoistable ||\n tag === FiberTags.HostSingleton\n ) {\n return null;\n }\n\n // Skip Fragment, Mode, Profiler, and related internal types\n if (\n tag === FiberTags.Fragment ||\n tag === FiberTags.Mode ||\n tag === FiberTags.Profiler ||\n tag === FiberTags.DehydratedFragment\n ) {\n return null;\n }\n\n // Skip React internal infrastructure types (these are internal implementation details)\n if (\n tag === FiberTags.HostRoot ||\n tag === FiberTags.HostPortal ||\n tag === FiberTags.ScopeComponent ||\n tag === FiberTags.OffscreenComponent ||\n tag === FiberTags.LegacyHiddenComponent ||\n tag === FiberTags.CacheComponent ||\n tag === FiberTags.TracingMarkerComponent ||\n tag === FiberTags.Throw ||\n tag === FiberTags.ViewTransitionComponent ||\n tag === FiberTags.ActivityComponent\n ) {\n return null;\n }\n\n // Handle ForwardRef\n if (tag === FiberTags.ForwardRef) {\n const elType = elementType as ComponentType | null;\n if (elType?.render) {\n const innerName = getComponentNameFromType(elType.render);\n if (innerName) return innerName;\n }\n if (elType?.displayName) return elType.displayName;\n return getComponentNameFromType(type as ComponentType);\n }\n\n // Handle Memo\n if (\n tag === FiberTags.MemoComponent ||\n tag === FiberTags.SimpleMemoComponent\n ) {\n const elType = elementType as ComponentType | null;\n if (elType?.type) {\n const innerName = getComponentNameFromType(elType.type);\n if (innerName) return innerName;\n }\n if (elType?.displayName) return elType.displayName;\n return getComponentNameFromType(type as ComponentType);\n }\n\n // Handle Context Provider\n if (tag === FiberTags.ContextProvider) {\n const elType = type as ComponentType | null;\n if (elType?._context?.displayName) {\n return `${elType._context.displayName}.Provider`;\n }\n return null;\n }\n\n // Handle Context Consumer\n if (tag === FiberTags.ContextConsumer) {\n const elType = type as ComponentType | null;\n if (elType?.displayName) {\n return `${elType.displayName}.Consumer`;\n }\n return null;\n }\n\n // Handle Lazy\n if (tag === FiberTags.LazyComponent) {\n const elType = elementType as ComponentType | null;\n if (elType?._status === 1 && elType._result) {\n return getComponentNameFromType(elType._result);\n }\n return null;\n }\n\n // Handle Suspense and SuspenseList\n if (\n tag === FiberTags.SuspenseComponent ||\n tag === FiberTags.SuspenseListComponent\n ) {\n return null;\n }\n\n // Handle incomplete components (error states during rendering)\n if (\n tag === FiberTags.IncompleteClassComponent ||\n tag === FiberTags.IncompleteFunctionComponent\n ) {\n // These are components that errored during rendering\n // Try to get the name anyway for debugging purposes\n return getComponentNameFromType(type as ComponentType);\n }\n\n // Function and Class components\n if (\n tag === FiberTags.FunctionComponent ||\n tag === FiberTags.ClassComponent ||\n tag === FiberTags.IndeterminateComponent\n ) {\n return getComponentNameFromType(type as ComponentType);\n }\n\n return null;\n}\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Result from React component detection\n */\nexport interface ReactComponentInfo {\n /** Full component path like \"<App> <Layout> <Button>\" */\n path: string | null;\n /** Array of component names from innermost to outermost */\n components: string[];\n}\n\n/**\n * Check if a name looks like minified/production code (single letter or very short)\n */\nfunction isMinifiedName(name: string): boolean {\n // Single letter or two letters that look like minified (e.g., \"e\", \"t\", \"Zt\")\n if (name.length <= 2) return true;\n // All lowercase short names are likely minified\n if (name.length <= 3 && name === name.toLowerCase()) return true;\n return false;\n}\n\n/**\n * Walks up the fiber tree to collect React component names\n *\n * @param element - The DOM element to start from\n * @param config - Optional configuration\n * @returns ReactComponentInfo with component path and array\n */\nexport function getReactComponentName(\n element: HTMLElement,\n config?: ReactDetectionConfig,\n): ReactComponentInfo {\n const resolved = resolveConfig(config);\n\n // Only use cache for 'all' mode - filtered modes must NOT cache because:\n // - Cache lookup happens BEFORE filtering logic runs\n // - Cached results from before filter updates would bypass new filters\n // - This was causing \"Root\", \"ErrorBoundaryHandler\" to leak through\n const useCache = resolved.mode === \"all\";\n\n if (useCache) {\n const cached = componentCacheAllRef.map.get(element);\n if (cached !== undefined) {\n return cached;\n }\n }\n\n if (!isReactPage()) {\n const result: ReactComponentInfo = { path: null, components: [] };\n if (useCache) {\n componentCacheAllRef.map.set(element, result);\n }\n return result;\n }\n\n // Collect DOM classes for smart mode\n const domClasses =\n resolved.mode === \"smart\" ? getAncestorClasses(element) : undefined;\n\n const components: string[] = [];\n\n try {\n let fiber = getFiberFromElement(element);\n let depth = 0;\n\n while (\n fiber &&\n depth < resolved.maxDepth &&\n components.length < resolved.maxComponents\n ) {\n const name = getComponentNameFromFiber(fiber);\n\n // Skip minified names and apply filter\n if (\n name &&\n !isMinifiedName(name) &&\n shouldIncludeComponent(name, depth, resolved, domClasses)\n ) {\n components.push(name);\n }\n\n fiber = fiber.return;\n depth++;\n }\n } catch {\n // Fiber structure may be corrupted or inaccessible - return empty result\n const result: ReactComponentInfo = { path: null, components: [] };\n if (useCache) {\n componentCacheAllRef.map.set(element, result);\n }\n return result;\n }\n\n if (components.length === 0) {\n const result: ReactComponentInfo = { path: null, components: [] };\n if (useCache) {\n componentCacheAllRef.map.set(element, result);\n }\n return result;\n }\n\n // Build path from outermost to innermost: <App> <Layout> <Button>\n const path = components\n .slice()\n .reverse()\n .map((c) => `<${c}>`)\n .join(\" \");\n\n const result: ReactComponentInfo = { path, components };\n if (useCache) {\n componentCacheAllRef.map.set(element, result);\n }\n return result;\n}\n","import React from \"react\";\n\n// =============================================================================\n// Source Location Detection Utilities\n// =============================================================================\n//\n// This module provides utilities for detecting React source file locations from\n// DOM elements. It works by accessing React's internal fiber tree and extracting\n// _debugSource information that's available in development builds.\n//\n// Compatibility:\n// - React 16.8+ (Hooks era)\n// - React 17.x\n// - React 18.x\n// - React 19.x (with fallbacks for changed internals)\n//\n// Limitations:\n// - Only works in development builds (production builds strip _debugSource)\n// - Requires React DevTools-style fiber access\n// - Some bundlers may strip debug info even in development\n// =============================================================================\n\n/**\n * Source location information for a React component\n */\nexport interface SourceLocation {\n /** Absolute or relative file path */\n fileName: string;\n /** Line number (1-indexed) */\n lineNumber: number;\n /** Column number (0-indexed, may be undefined) */\n columnNumber?: number;\n /** Component display name if available */\n componentName?: string;\n /** React version detected */\n reactVersion?: string;\n}\n\n/**\n * Result of source location detection\n */\nexport interface SourceLocationResult {\n /** Whether source location was found */\n found: boolean;\n /** Source location data (if found) */\n source?: SourceLocation;\n /** Multiple source candidates from probe (production fallback) */\n sourceCandidates?: SourceLocation[];\n /** Reason if not found */\n reason?: SourceLocationNotFoundReason;\n /** Whether the app appears to be a React app */\n isReactApp: boolean;\n /** Whether running in production mode */\n isProduction: boolean;\n}\n\n/**\n * Reasons why source location might not be found\n */\nexport type SourceLocationNotFoundReason =\n | \"not-react-app\"\n | \"production-build\"\n | \"no-fiber\"\n | \"no-debug-source\"\n | \"react-19-changed\"\n | \"element-not-in-react-tree\"\n | \"unknown\";\n\n/**\n * React Fiber node structure (partial, for type safety)\n * Based on React's internal FiberNode type\n */\ninterface ReactFiber {\n // Debug source info (only in development)\n _debugSource?: {\n fileName: string;\n lineNumber: number;\n columnNumber?: number;\n };\n // Owner info (React 19 may use this differently)\n _debugOwner?: ReactFiber;\n // Component type\n type?: {\n name?: string;\n displayName?: string;\n // For class components\n prototype?: {\n isReactComponent?: boolean;\n };\n } | string | null;\n // Element type for built-in elements\n elementType?: unknown;\n // Tag indicating fiber type\n tag?: number;\n // Fiber tree navigation\n return?: ReactFiber | null;\n child?: ReactFiber | null;\n sibling?: ReactFiber | null;\n // Memoized props (for context)\n memoizedProps?: Record<string, unknown>;\n // State node for class components\n stateNode?: unknown;\n}\n\n/**\n * Extended HTMLElement with React fiber properties\n */\ninterface ReactDOMElement extends HTMLElement {\n // React 16-17 fiber key\n __reactFiber$?: string;\n // React 18+ fiber key pattern\n __reactFiber?: ReactFiber;\n // React internal instance (older pattern)\n __reactInternalInstance$?: string;\n // Alternative patterns\n _reactRootContainer?: unknown;\n}\n\n// React fiber tag constants (for reference)\nconst FIBER_TAGS = {\n FunctionComponent: 0,\n ClassComponent: 1,\n IndeterminateComponent: 2,\n HostRoot: 3,\n HostPortal: 4,\n HostComponent: 5,\n HostText: 6,\n Fragment: 7,\n Mode: 8,\n ContextConsumer: 9,\n ContextProvider: 10,\n ForwardRef: 11,\n Profiler: 12,\n SuspenseComponent: 13,\n MemoComponent: 14,\n SimpleMemoComponent: 15,\n LazyComponent: 16,\n} as const;\n\n/**\n * Checks if the page appears to be running a React application\n *\n * @returns Object with detection results\n */\nexport function detectReactApp(): {\n isReact: boolean;\n version?: string;\n isProduction: boolean;\n} {\n if (typeof window === \"undefined\") {\n return { isReact: false, isProduction: true };\n }\n\n // Check for React DevTools hook (most reliable)\n const devToolsHook = (window as unknown as Record<string, unknown>).__REACT_DEVTOOLS_GLOBAL_HOOK__;\n\n if (devToolsHook && typeof devToolsHook === \"object\") {\n const hook = devToolsHook as Record<string, unknown>;\n\n // Check for renderers (React 16+)\n const renderers = hook.renderers as Map<number, { version?: string }> | undefined;\n if (renderers && renderers.size > 0) {\n // Get version from first renderer\n const firstRenderer = renderers.values().next().value;\n const version = firstRenderer?.version;\n\n // Check for production mode via lack of development tools\n const isProduction = !hook.supportsFiber;\n\n return {\n isReact: true,\n version: version || \"unknown\",\n isProduction,\n };\n }\n }\n\n // Fallback: Check for React root markers on DOM\n const hasReactRoot = document.querySelector(\"[data-reactroot]\") !== null;\n const hasReactContainer = document.getElementById(\"root\")?._reactRootContainer !== undefined;\n\n // Check for fiber keys on body's children\n const bodyChildren = document.body.children;\n let hasFiberKey = false;\n\n for (let i = 0; i < bodyChildren.length && !hasFiberKey; i++) {\n const child = bodyChildren[i];\n const keys = Object.keys(child);\n hasFiberKey = keys.some(\n (key) => key.startsWith(\"__reactFiber$\") || key.startsWith(\"__reactInternalInstance$\")\n );\n }\n\n if (hasReactRoot || hasReactContainer || hasFiberKey) {\n return {\n isReact: true,\n version: \"unknown\",\n // Assume production if we can't detect dev tools\n isProduction: !devToolsHook,\n };\n }\n\n return { isReact: false, isProduction: true };\n}\n\n/**\n * Gets the React fiber node associated with a DOM element\n *\n * @param element - DOM element to get fiber for\n * @returns React fiber node or null if not found\n */\nexport function getFiberFromElement(element: HTMLElement): ReactFiber | null {\n if (!element || typeof element !== \"object\") {\n return null;\n }\n\n const keys = Object.keys(element);\n\n // React 18+ uses __reactFiber$ prefix\n const fiberKey = keys.find((key) => key.startsWith(\"__reactFiber$\"));\n if (fiberKey) {\n return (element as unknown as Record<string, ReactFiber>)[fiberKey] || null;\n }\n\n // React 16-17 uses __reactInternalInstance$ prefix\n const instanceKey = keys.find((key) => key.startsWith(\"__reactInternalInstance$\"));\n if (instanceKey) {\n return (element as unknown as Record<string, ReactFiber>)[instanceKey] || null;\n }\n\n // React 19 may use different patterns - check for any fiber-like object\n const possibleFiberKey = keys.find((key) => {\n if (!key.startsWith(\"__react\")) return false;\n const value = (element as unknown as Record<string, unknown>)[key];\n return value && typeof value === \"object\" && \"_debugSource\" in (value as object);\n });\n\n if (possibleFiberKey) {\n return (element as unknown as Record<string, ReactFiber>)[possibleFiberKey] || null;\n }\n\n return null;\n}\n\n/**\n * Gets the display name of a React component from its fiber\n *\n * @param fiber - React fiber node\n * @returns Component name or null\n */\nfunction getComponentName(fiber: ReactFiber): string | null {\n if (!fiber.type) {\n return null;\n }\n\n // String type means host component (div, span, etc.)\n if (typeof fiber.type === \"string\") {\n return null; // We want React component names, not HTML tags\n }\n\n // Function/class component\n if (typeof fiber.type === \"object\" || typeof fiber.type === \"function\") {\n const type = fiber.type as { displayName?: string; name?: string };\n\n // Prefer displayName (set by React DevTools or manually)\n if (type.displayName) {\n return type.displayName;\n }\n\n // Fall back to function/class name\n if (type.name) {\n return type.name;\n }\n }\n\n return null;\n}\n\n/**\n * Walks up the fiber tree to find the nearest component with _debugSource\n *\n * @param fiber - Starting fiber node\n * @param maxDepth - Maximum tree depth to traverse (default: 50)\n * @returns Object with source info and component name, or null\n */\nfunction findDebugSource(\n fiber: ReactFiber,\n maxDepth = 50\n): { source: ReactFiber[\"_debugSource\"]; componentName: string | null } | null {\n let current: ReactFiber | null | undefined = fiber;\n let depth = 0;\n\n while (current && depth < maxDepth) {\n // Check current fiber for debug source\n if (current._debugSource) {\n return {\n source: current._debugSource,\n componentName: getComponentName(current),\n };\n }\n\n // Check debug owner (for components that wrap the element)\n if (current._debugOwner?._debugSource) {\n return {\n source: current._debugOwner._debugSource,\n componentName: getComponentName(current._debugOwner),\n };\n }\n\n // Move up the tree\n current = current.return;\n depth++;\n }\n\n return null;\n}\n\n/**\n * Attempts to find source location using React 19's potentially different structure\n *\n * @param fiber - Starting fiber node\n * @returns Source location info or null\n */\nfunction findDebugSourceReact19(\n fiber: ReactFiber\n): { source: ReactFiber[\"_debugSource\"]; componentName: string | null } | null {\n // React 19 may store debug info differently\n // This is a forward-compatible attempt based on React 19 RFCs\n\n let current: ReactFiber | null | undefined = fiber;\n let depth = 0;\n const maxDepth = 50;\n\n while (current && depth < maxDepth) {\n // Check for new React 19 debug patterns\n const anyFiber = current as unknown as Record<string, unknown>;\n\n // Possible React 19 locations for debug info\n const possibleSourceKeys = [\n \"_debugSource\",\n \"__source\",\n \"_source\",\n \"debugSource\",\n ];\n\n for (const key of possibleSourceKeys) {\n const source = anyFiber[key];\n if (source && typeof source === \"object\" && \"fileName\" in source) {\n return {\n source: source as ReactFiber[\"_debugSource\"],\n componentName: getComponentName(current),\n };\n }\n }\n\n // Check if debug info is in the element itself\n if (current.memoizedProps) {\n const props = current.memoizedProps as Record<string, unknown>;\n if (props.__source && typeof props.__source === \"object\") {\n const source = props.__source as { fileName?: string; lineNumber?: number };\n if (source.fileName && source.lineNumber) {\n return {\n source: {\n fileName: source.fileName,\n lineNumber: source.lineNumber,\n columnNumber: (source as { columnNumber?: number }).columnNumber,\n },\n componentName: getComponentName(current),\n };\n }\n }\n }\n\n current = current.return;\n depth++;\n }\n\n return null;\n}\n\n// =============================================================================\n// Stack-Trace Fallback for Source File Detection\n// =============================================================================\n//\n// When _debugSource is unavailable (e.g. Next.js with SWC), we fall back to\n// invoking the component function with a throwing hooks dispatcher, parsing\n// the error stack trace, and stripping bundler URL prefixes. In dev mode,\n// stack frames already contain original source paths.\n// =============================================================================\n\n/** Cache: component function → probed SourceLocation (or null if unresolvable) */\nconst sourceProbeCache = new Map<Function, SourceLocation | null>();\n\n/**\n * Extract the callable function from a fiber, handling wrappers.\n * Returns null for class components, host elements, or unrecognized types.\n */\nfunction unwrapComponentType(fiber: ReactFiber): Function | null {\n const tag = fiber.tag;\n const type = fiber.type;\n const elementType = fiber.elementType as Record<string, unknown> | null | undefined;\n\n // Host elements (div, span, etc.)\n if (typeof type === \"string\" || type == null) return null;\n\n // Class components — skip (need `new`, different lifecycle)\n if (\n typeof type === \"function\" &&\n (type as { prototype?: { isReactComponent?: boolean } }).prototype?.isReactComponent\n ) {\n return null;\n }\n\n // FunctionComponent / IndeterminateComponent\n if (\n (tag === FIBER_TAGS.FunctionComponent || tag === FIBER_TAGS.IndeterminateComponent) &&\n typeof type === \"function\"\n ) {\n return type as Function;\n }\n\n // ForwardRef\n if (tag === FIBER_TAGS.ForwardRef && elementType) {\n const render = elementType.render;\n if (typeof render === \"function\") return render as Function;\n }\n\n // Memo / SimpleMemo\n if (\n (tag === FIBER_TAGS.MemoComponent || tag === FIBER_TAGS.SimpleMemoComponent) &&\n elementType\n ) {\n const inner = elementType.type;\n if (typeof inner === \"function\") return inner as Function;\n }\n\n // Generic fallback: if type is a plain function, use it\n if (typeof type === \"function\") return type as Function;\n\n return null;\n}\n\n/**\n * Access the React hooks dispatcher from React's module internals.\n * These are properties on the `react` module export, NOT on `window`.\n * Returns get/set helpers or null if not found.\n */\nfunction getReactDispatcher(): {\n get: () => unknown;\n set: (d: unknown) => void;\n} | null {\n // Access React internals from the imported module\n const reactModule = React as unknown as Record<string, unknown>;\n\n // React 19: __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE.H\n const r19 = reactModule.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE as\n | Record<string, unknown>\n | undefined;\n if (r19 && \"H\" in r19) {\n return {\n get: () => r19.H,\n set: (d: unknown) => { r19.H = d; },\n };\n }\n\n // React 16-18: __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher.current\n const r18 = reactModule.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as\n | Record<string, unknown>\n | undefined;\n if (r18) {\n const dispatcher = r18.ReactCurrentDispatcher as\n | { current: unknown }\n | undefined;\n if (dispatcher && \"current\" in dispatcher) {\n return {\n get: () => dispatcher.current,\n set: (d: unknown) => { dispatcher.current = d; },\n };\n }\n }\n\n return null;\n}\n\n/**\n * Parse the first non-internal frame from an error stack string.\n */\nfunction parseComponentFrame(\n stack: string\n): { fileName: string; line: number; column?: number } | null {\n const lines = stack.split(\"\\n\");\n\n // Patterns to always skip\n const skipPatterns = [\n /source-location/,\n /\\/dist\\/index\\./, // Our bundled output (dist/index.mjs, dist/index.js)\n /\\/dist\\/react\\./, // Our React bundled output\n /node_modules\\//, // Any package in node_modules (dev mode)\n /react-dom/,\n /react\\.development/,\n /react\\.production/,\n /chunk-[A-Z0-9]+/i,\n /react-stack-bottom-frame/,\n /react-reconciler/,\n /scheduler/,\n /at <anonymous>:/, // Standalone anonymous frames (proxy handler, eval)\n ];\n\n // V8 format: \" at FnName (file:line:col)\" or \" at file:line:col\"\n const v8Re = /^\\s*at\\s+(?:.*?\\s+\\()?(.+?):(\\d+):(\\d+)\\)?$/;\n // WebKit/Gecko: \"FnName@file:line:col\" or \"@file:line:col\"\n const webkitRe = /^[^@]*@(.+?):(\\d+):(\\d+)$/;\n\n // Probe 스택 구조 (위에서 아래로):\n // 0: Error message\n // 1: at Object.get (proxy trap) ← 우리 코드 — skip\n // 2: at r.useCallback (React hook) ← hook 내부 — skip\n // 3: at (component code) ← 여기!\n // 4+: React internals, event handlers...\n //\n // 전략: 첫 2개 유효 프레임(proxy get + hook)을 skip하고 3번째를 반환.\n // 이유: 컴포넌트가 hook을 호출 → hook이 proxy get 호출 → Error throw\n let validCount = 0;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n // Skip frames from internal files\n if (skipPatterns.some((p) => p.test(trimmed))) continue;\n\n const match = v8Re.exec(trimmed) || webkitRe.exec(trimmed);\n if (match) {\n validCount++;\n // 첫 2개 프레임은 proxy get trap + React hook 내부 → skip\n // 3번째 프레임이 컴포넌트 코드\n if (validCount >= 3) {\n return {\n fileName: match[1],\n line: parseInt(match[2], 10),\n column: parseInt(match[3], 10),\n };\n }\n }\n }\n\n return null;\n}\n\n/**\n * Strip bundler URL prefixes from a raw source path.\n */\nfunction cleanSourcePath(rawPath: string): string {\n let path = rawPath;\n\n // 1. Strip query params and hashes\n path = path.replace(/[?#].*$/, \"\");\n\n // 2. Turbopack project prefix\n path = path.replace(/^turbopack:\\/\\/\\/\\[project\\]\\//, \"\");\n\n // 3. webpack-internal\n path = path.replace(/^webpack-internal:\\/\\/\\/\\.\\//, \"\");\n path = path.replace(/^webpack-internal:\\/\\/\\//, \"\");\n\n // 4. webpack\n path = path.replace(/^webpack:\\/\\/\\/\\.\\//, \"\");\n path = path.replace(/^webpack:\\/\\/\\//, \"\");\n\n // 5. turbopack generic\n path = path.replace(/^turbopack:\\/\\/\\//, \"\");\n\n // 6. http(s)://host:port/\n path = path.replace(/^https?:\\/\\/[^/]+\\//, \"\");\n\n // 7. file:///\n path = path.replace(/^file:\\/\\/\\//, \"/\");\n\n // 8. Webpack chunk group prefixes like (app-pages-browser)/./\n path = path.replace(/^\\([^)]+\\)\\/\\.\\//, \"\");\n\n // 9. Leading ./\n path = path.replace(/^\\.\\//, \"\");\n\n return path;\n}\n\n/**\n * Probe a single fiber's component function by invoking it with a\n * throwing hooks dispatcher and parsing the resulting error stack.\n */\nfunction probeComponentSource(fiber: ReactFiber): SourceLocation | null {\n const fn = unwrapComponentType(fiber);\n if (!fn) return null;\n\n // Check cache\n if (sourceProbeCache.has(fn)) {\n return sourceProbeCache.get(fn)!;\n }\n\n const dispatcher = getReactDispatcher();\n if (!dispatcher) {\n sourceProbeCache.set(fn, null);\n return null;\n }\n\n const original = dispatcher.get();\n let result: SourceLocation | null = null;\n\n try {\n // Install a proxy dispatcher that throws an Error (with stack) on any hook access.\n // When the component calls useState/useEffect/etc., the proxy's get trap fires,\n // creating an Error whose stack trace includes the component's source location.\n const stackCapturingDispatcher = new Proxy(\n {},\n {\n get() {\n throw new Error(\"probe\");\n },\n }\n );\n dispatcher.set(stackCapturingDispatcher);\n\n try {\n // Invoke the component — it will either:\n // 1. Call a hook → throws Error with stack (ideal case)\n // 2. Have no hooks → runs to completion (harmless, discarded), no stack to parse\n fn({});\n } catch (e) {\n // \"probe\" = our proxy dispatcher threw, or React minified error = production hook call\n if (e instanceof Error && e.stack) {\n const frame = parseComponentFrame(e.stack);\n if (frame) {\n const cleaned = cleanSourcePath(frame.fileName);\n result = {\n fileName: cleaned,\n lineNumber: frame.line,\n columnNumber: frame.column,\n componentName: getComponentName(fiber) || undefined,\n };\n }\n }\n }\n } finally {\n dispatcher.set(original);\n }\n\n sourceProbeCache.set(fn, result);\n return result;\n}\n\n/**\n * Walk the fiber tree via .return, probing each fiber for source info.\n * Returns multiple candidates — different fibers may resolve to different chunks,\n * and some chunks may only contain node_modules code.\n */\nfunction probeSourceWalk(\n fiber: ReactFiber,\n maxDepth = 15\n): SourceLocation[] {\n const results: SourceLocation[] = [];\n const seenFileNames = new Set<string>();\n let current: ReactFiber | null | undefined = fiber;\n let depth = 0;\n\n while (current && depth < maxDepth) {\n const source = probeComponentSource(current);\n if (source && !seenFileNames.has(source.fileName)) {\n seenFileNames.add(source.fileName);\n results.push(source);\n }\n\n current = current.return;\n depth++;\n }\n\n return results;\n}\n\n/**\n * Gets the source file location for a DOM element in a React application\n *\n * This function attempts to extract the source file path and line number\n * where a React component is defined. This only works in development mode\n * as production builds strip debug information.\n *\n * @param element - DOM element to get source location for\n * @returns SourceLocationResult with location info or reason for failure\n *\n * @example\n * ```ts\n * const result = getSourceLocation(element);\n * if (result.found && result.source) {\n * console.log(`${result.source.fileName}:${result.source.lineNumber}`);\n * // Output: \"/src/components/Button.tsx:42\"\n * }\n * ```\n */\nexport function getSourceLocation(element: HTMLElement): SourceLocationResult {\n // Try to get fiber directly from the element (same approach as getReactComponentName)\n // This avoids detectReactApp() whose production heuristic can give false positives\n const fiber = getFiberFromElement(element);\n\n if (!fiber) {\n return {\n found: false,\n reason: \"no-fiber\",\n isReactApp: false,\n isProduction: false,\n };\n }\n\n // Try standard React 16-18 debug source finding\n let debugInfo = findDebugSource(fiber);\n\n // If not found, try React 19 patterns\n if (!debugInfo) {\n debugInfo = findDebugSourceReact19(fiber);\n }\n\n if (debugInfo?.source) {\n return {\n found: true,\n source: {\n fileName: debugInfo.source.fileName,\n lineNumber: debugInfo.source.lineNumber,\n columnNumber: debugInfo.source.columnNumber,\n componentName: debugInfo.componentName || undefined,\n },\n isReactApp: true,\n isProduction: false,\n };\n }\n\n // Fallback: probe component via stack trace\n const probedList = probeSourceWalk(fiber);\n if (probedList.length > 0) {\n return {\n found: true,\n source: probedList[0],\n sourceCandidates: probedList,\n isReactApp: true,\n isProduction: false,\n };\n }\n\n return {\n found: false,\n reason: \"no-debug-source\",\n isReactApp: true,\n isProduction: false,\n };\n}\n\n/**\n * Formats a source location as a clickable file path string\n *\n * @param source - Source location object\n * @param format - Output format: \"vscode\" for VSCode URL, \"path\" for file:line format\n * @returns Formatted string\n *\n * @example\n * ```ts\n * formatSourceLocation(source, \"path\")\n * // Returns: \"src/components/Button.tsx:42:8\"\n *\n * formatSourceLocation(source, \"vscode\")\n * // Returns: \"vscode://file/absolute/path/src/components/Button.tsx:42:8\"\n * ```\n */\nexport function formatSourceLocation(\n source: SourceLocation,\n format: \"path\" | \"vscode\" = \"path\"\n): string {\n const { fileName, lineNumber, columnNumber } = source;\n\n // Build line:column suffix\n let location = `${fileName}:${lineNumber}`;\n if (columnNumber !== undefined) {\n location += `:${columnNumber}`;\n }\n\n if (format === \"vscode\") {\n // VSCode can open files via URL protocol\n // Assumes fileName is absolute or can be resolved\n return `vscode://file${fileName.startsWith(\"/\") ? \"\" : \"/\"}${location}`;\n }\n\n return location;\n}\n\n/**\n * Gets source locations for multiple elements at once\n *\n * @param elements - Array of DOM elements\n * @returns Array of source location results\n */\nexport function getSourceLocations(elements: HTMLElement[]): SourceLocationResult[] {\n return elements.map((element) => getSourceLocation(element));\n}\n\n/**\n * Finds the nearest React component ancestor that has source info\n *\n * Useful when clicking on a deeply nested element (like text or an icon)\n * and wanting to find the component that contains it.\n *\n * @param element - Starting DOM element\n * @param maxAncestors - Maximum DOM ancestors to check (default: 10)\n * @returns Source location result\n */\nexport function findNearestComponentSource(\n element: HTMLElement,\n maxAncestors = 10\n): SourceLocationResult {\n let current: HTMLElement | null = element;\n let depth = 0;\n\n while (current && depth < maxAncestors) {\n const result = getSourceLocation(current);\n\n // Return first successful result\n if (result.found) {\n return result;\n }\n\n // If we found fiber but no source, keep looking up DOM\n // (might find a parent component with source info)\n current = current.parentElement;\n depth++;\n }\n\n // Return result for original element (will explain why not found)\n return getSourceLocation(element);\n}\n\n/**\n * Gets all component sources in the ancestor chain\n *\n * Useful for understanding the component hierarchy.\n *\n * @param element - Starting DOM element\n * @returns Array of unique source locations from element up to root\n */\nexport function getComponentHierarchy(element: HTMLElement): SourceLocation[] {\n const fiber = getFiberFromElement(element);\n if (!fiber) {\n return [];\n }\n\n const sources: SourceLocation[] = [];\n const seenFiles = new Set<string>();\n\n let current: ReactFiber | null | undefined = fiber;\n let depth = 0;\n const maxDepth = 100;\n\n while (current && depth < maxDepth) {\n if (current._debugSource) {\n const key = `${current._debugSource.fileName}:${current._debugSource.lineNumber}`;\n\n // Avoid duplicates\n if (!seenFiles.has(key)) {\n seenFiles.add(key);\n sources.push({\n fileName: current._debugSource.fileName,\n lineNumber: current._debugSource.lineNumber,\n columnNumber: current._debugSource.columnNumber,\n componentName: getComponentName(current) || undefined,\n });\n }\n }\n\n current = current.return;\n depth++;\n }\n\n return sources;\n}\n\n/**\n * Checks if source location detection is likely to work in the current environment\n *\n * @returns Object describing support status\n */\nexport function checkSourceLocationSupport(): {\n supported: boolean;\n reason: string;\n suggestions: string[];\n} {\n const reactInfo = detectReactApp();\n\n if (!reactInfo.isReact) {\n return {\n supported: false,\n reason: \"No React application detected on this page\",\n suggestions: [\n \"Ensure you're on a page built with React\",\n \"The page may use a different framework (Vue, Angular, etc.)\",\n ],\n };\n }\n\n if (reactInfo.isProduction) {\n return {\n supported: false,\n reason: \"Production build detected - source info is stripped\",\n suggestions: [\n \"Run the application in development mode\",\n \"Set NODE_ENV=development\",\n \"Ensure your bundler includes source info in development\",\n ],\n };\n }\n\n // Check for DevTools\n const hasDevTools = typeof window !== \"undefined\" &&\n !!(window as unknown as Record<string, unknown>).__REACT_DEVTOOLS_GLOBAL_HOOK__;\n\n if (!hasDevTools) {\n return {\n supported: true,\n reason: \"Development mode detected, but React DevTools not installed\",\n suggestions: [\n \"Install React DevTools browser extension for best results\",\n \"Source detection may still work without it\",\n ],\n };\n }\n\n return {\n supported: true,\n reason: `React ${reactInfo.version || \"unknown\"} development mode detected`,\n suggestions: [],\n };\n}\n","// =============================================================================\n// @impakers/debug — DOM Screenshot Utilities\n// =============================================================================\n// html2canvas-pro 사용 (oklab/oklch/lab/lch/color-mix 네이티브 지원)\n\n/**\n * DOM 요소를 JPEG base64 이미지로 캡처\n */\nexport async function captureElement(\n el: HTMLElement,\n options: { quality?: number; maxScale?: number } = {},\n): Promise<string> {\n const { quality = 0.7, maxScale = 2 } = options;\n const html2canvas = (await import(\"html2canvas-pro\")).default;\n const canvas = await html2canvas(el, {\n useCORS: true,\n allowTaint: true,\n scale: Math.min(window.devicePixelRatio, maxScale),\n logging: false,\n });\n return canvas.toDataURL(\"image/jpeg\", quality);\n}\n\n/**\n * 전체 화면(viewport)을 JPEG base64 이미지로 캡처\n * debug UI 요소를 숨긴 상태로 캡처\n */\nexport async function captureFullPage(\n options: { quality?: number; hideSelectors?: string[] } = {},\n): Promise<string | undefined> {\n const { quality = 0.5, hideSelectors = [] } = options;\n const defaultSelectors = [\"[data-impakers-debug]\", \"[data-annotation-popup]\", \"[data-annotation-marker]\"];\n const allSelectors = [...defaultSelectors, ...hideSelectors];\n const hiddenEls = document.querySelectorAll(allSelectors.join(\", \"));\n\n try {\n hiddenEls.forEach((el) => (el as HTMLElement).style.visibility = \"hidden\");\n\n const html2canvas = (await import(\"html2canvas-pro\")).default;\n const canvas = await html2canvas(document.body, {\n useCORS: true,\n allowTaint: true,\n scale: 1,\n logging: false,\n width: window.innerWidth,\n height: window.innerHeight,\n });\n return canvas.toDataURL(\"image/jpeg\", quality);\n } catch {\n return undefined;\n } finally {\n hiddenEls.forEach((el) => (el as HTMLElement).style.visibility = \"\");\n }\n}\n","// =============================================================================\n// @impakers/debug — Environment Info Collector\n// =============================================================================\n\nimport type { FeedbackMetadata, FeedbackUser } from \"./types\";\n\n// ---------------------------------------------------------------------------\n// Console capture (에러 최근 20개, 일반 로그 최근 50개)\n// ---------------------------------------------------------------------------\n\nconst MAX_ERRORS = 20;\nconst MAX_LOGS = 50;\nconst recentConsoleErrors: string[] = [];\nconst recentConsoleLogs: { level: string; message: string; timestamp: number }[] = [];\nlet consolePatched = false;\n\nfunction formatArgs(args: unknown[]): string {\n return args.map((a) => {\n if (a instanceof Error) return `${a.message}\\n${a.stack?.split(\"\\n\").slice(0, 3).join(\"\\n\")}`;\n if (typeof a === \"object\" && a !== null) {\n try { return JSON.stringify(a).slice(0, 300); } catch { return String(a); }\n }\n return String(a);\n }).join(\" \");\n}\n\nfunction pushLog(level: string, message: string) {\n recentConsoleLogs.push({ level, message: message.slice(0, 500), timestamp: Date.now() });\n if (recentConsoleLogs.length > MAX_LOGS) recentConsoleLogs.shift();\n}\n\nfunction installConsoleCapture() {\n if (consolePatched || typeof window === \"undefined\") return;\n consolePatched = true;\n\n const originalError = console.error;\n const originalWarn = console.warn;\n const originalLog = console.log;\n\n console.error = (...args: unknown[]) => {\n const msg = formatArgs(args);\n recentConsoleErrors.push(msg.slice(0, 500));\n if (recentConsoleErrors.length > MAX_ERRORS) recentConsoleErrors.shift();\n pushLog(\"error\", msg);\n originalError.apply(console, args);\n };\n\n console.warn = (...args: unknown[]) => {\n const msg = formatArgs(args);\n recentConsoleErrors.push(`[warn] ${msg}`.slice(0, 500));\n if (recentConsoleErrors.length > MAX_ERRORS) recentConsoleErrors.shift();\n pushLog(\"warn\", msg);\n originalWarn.apply(console, args);\n };\n\n console.log = (...args: unknown[]) => {\n pushLog(\"log\", formatArgs(args));\n originalLog.apply(console, args);\n };\n\n // 글로벌 에러도 캡처\n window.addEventListener(\"error\", (e) => {\n const msg = `${e.message} (${e.filename}:${e.lineno})`;\n recentConsoleErrors.push(msg.slice(0, 500));\n if (recentConsoleErrors.length > MAX_ERRORS) recentConsoleErrors.shift();\n pushLog(\"error\", msg);\n });\n\n window.addEventListener(\"unhandledrejection\", (e) => {\n const msg = `Unhandled Promise: ${e.reason}`;\n recentConsoleErrors.push(msg.slice(0, 500));\n if (recentConsoleErrors.length > MAX_ERRORS) recentConsoleErrors.shift();\n pushLog(\"error\", msg);\n });\n}\n\n// 모듈 로드 시 바로 설치\ninstallConsoleCapture();\n\n\n// ---------------------------------------------------------------------------\n// Browser parsing\n// ---------------------------------------------------------------------------\n\nfunction parseBrowser(ua: string): string {\n const edge = ua.match(/Edg\\/(\\d+[\\d.]*)/);\n if (edge) return `Edge ${edge[1]}`;\n\n const chrome = ua.match(/Chrome\\/(\\d+[\\d.]*)/);\n if (chrome && !ua.includes(\"Edg/\") && !ua.includes(\"OPR/\")) return `Chrome ${chrome[1]}`;\n\n const firefox = ua.match(/Firefox\\/(\\d+[\\d.]*)/);\n if (firefox) return `Firefox ${firefox[1]}`;\n\n const safari = ua.match(/Version\\/(\\d+[\\d.]*).*Safari/);\n if (safari) return `Safari ${safari[1]}`;\n\n const opera = ua.match(/OPR\\/(\\d+[\\d.]*)/);\n if (opera) return `Opera ${opera[1]}`;\n\n return ua;\n}\n\n// ---------------------------------------------------------------------------\n// Cookie parsing (민감 정보 필터링)\n// ---------------------------------------------------------------------------\n\nconst SENSITIVE_COOKIE_PATTERNS = [\n /session/i, /csrf/i, /xsrf/i, /secret/i, /password/i, /key/i,\n];\n\nfunction parseCookies(): Record<string, string> {\n if (typeof document === \"undefined\") return {};\n const cookies: Record<string, string> = {};\n try {\n document.cookie.split(\";\").forEach((c) => {\n const [key, ...rest] = c.trim().split(\"=\");\n if (!key) return;\n const name = key.trim();\n // 민감 쿠키는 값 마스킹\n const isSensitive = SENSITIVE_COOKIE_PATTERNS.some((p) => p.test(name));\n cookies[name] = isSensitive ? \"[masked]\" : decodeURIComponent(rest.join(\"=\")).slice(0, 200);\n });\n } catch {\n // cookie 접근 불가\n }\n return cookies;\n}\n\n// ---------------------------------------------------------------------------\n// JWT decode (클라이언트 프로젝트의 JWT 토큰을 찾아서 claims 추출)\n// ---------------------------------------------------------------------------\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return null;\n const payload = parts[1].replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = payload + \"==\".slice(0, (4 - (payload.length % 4)) % 4);\n return JSON.parse(atob(padded));\n } catch {\n return null;\n }\n}\n\nfunction findAndDecodeJwt(): Record<string, unknown> | null {\n if (typeof window === \"undefined\") return null;\n\n // localStorage에서 JWT 찾기 (일반적인 키 패턴)\n const jwtKeys = [\"token\", \"access_token\", \"accessToken\", \"auth_token\", \"authToken\", \"jwt\", \"id_token\", \"idToken\"];\n\n for (const key of jwtKeys) {\n try {\n const val = localStorage.getItem(key);\n if (val) {\n // JSON으로 감싸져 있을 수 있음\n const unwrapped = val.startsWith('\"') ? JSON.parse(val) : val;\n const decoded = decodeJwtPayload(unwrapped);\n if (decoded) {\n // 민감 정보 제거하고 안전한 claims만 반환\n const safe: Record<string, unknown> = {};\n const safeKeys = [\"sub\", \"email\", \"name\", \"role\", \"roles\", \"org\", \"iat\", \"exp\", \"aud\", \"iss\", \"user_id\", \"user_role\"];\n for (const k of safeKeys) {\n if (k in decoded) safe[k] = decoded[k];\n }\n return Object.keys(safe).length > 0 ? safe : null;\n }\n }\n } catch {\n continue;\n }\n }\n\n // 쿠키에서도 찾기\n try {\n const cookies = document.cookie.split(\";\");\n for (const c of cookies) {\n const [, ...rest] = c.trim().split(\"=\");\n const val = rest.join(\"=\");\n const decoded = decodeJwtPayload(val);\n if (decoded && decoded.sub) {\n const safe: Record<string, unknown> = {};\n const safeKeys = [\"sub\", \"email\", \"name\", \"role\", \"roles\", \"org\", \"iat\", \"exp\"];\n for (const k of safeKeys) {\n if (k in decoded) safe[k] = decoded[k];\n }\n return Object.keys(safe).length > 0 ? safe : null;\n }\n }\n } catch {\n // ignore\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Page performance\n// ---------------------------------------------------------------------------\n\nfunction safeRound(val: number): number | undefined {\n const n = Math.round(val);\n return isNaN(n) || !isFinite(n) ? undefined : n;\n}\n\nfunction getPagePerformance(): Record<string, number> {\n if (typeof performance === \"undefined\") return {};\n const metrics: Record<string, number> = {};\n\n try {\n const nav = performance.getEntriesByType(\"navigation\")[0] as PerformanceNavigationTiming | undefined;\n if (nav) {\n const pageLoad = safeRound(nav.loadEventEnd - nav.startTime);\n const domLoaded = safeRound(nav.domContentLoadedEventEnd - nav.startTime);\n const ttfb = safeRound(nav.responseStart - nav.requestStart);\n if (pageLoad) metrics.pageLoadTime = pageLoad;\n if (domLoaded) metrics.domContentLoaded = domLoaded;\n if (ttfb) metrics.ttfb = ttfb;\n }\n\n const fcp = performance.getEntriesByName(\"first-contentful-paint\")[0];\n if (fcp) {\n const v = safeRound(fcp.startTime);\n if (v) metrics.firstContentfulPaint = v;\n }\n\n const mem = (performance as any).memory;\n if (mem) {\n const used = safeRound(mem.usedJSHeapSize / 1024 / 1024);\n const total = safeRound(mem.totalJSHeapSize / 1024 / 1024);\n if (used) metrics.usedJSHeapMB = used;\n if (total) metrics.totalJSHeapMB = total;\n }\n } catch {\n // ignore\n }\n\n return metrics;\n}\n\n// ---------------------------------------------------------------------------\n// Main collector\n// ---------------------------------------------------------------------------\n\nexport function collectMetadata(\n getUser?: () => FeedbackUser | null,\n): FeedbackMetadata {\n const metadata: FeedbackMetadata = {\n url: window.location.href,\n timestamp: new Date().toISOString(),\n browser: parseBrowser(navigator.userAgent),\n userAgent: navigator.userAgent,\n viewport: `${window.innerWidth}x${window.innerHeight}`,\n pixelRatio: window.devicePixelRatio,\n language: navigator.language,\n referrer: document.referrer,\n cookies: parseCookies(),\n jwtClaims: findAndDecodeJwt() ?? undefined,\n consoleErrors: recentConsoleErrors.length > 0 ? [...recentConsoleErrors] : undefined,\n consoleLogs: recentConsoleLogs.length > 0 ? [...recentConsoleLogs] : undefined,\n performance: getPagePerformance(),\n };\n\n if (getUser) {\n try {\n const user = getUser();\n if (user) {\n // id를 항상 string으로 강제 (숫자 id 방어)\n metadata.user = {\n ...user,\n id: String(user.id),\n name: String(user.name || \"\"),\n };\n }\n } catch {\n // ignore\n }\n }\n\n return metadata;\n}\n","import type { DebugTarget, RouteDebugContext } from \"./types\";\n\nconst NEXT_ROUTE_MANIFEST_URL = \"/_next/static/chunks/impakers-debug-route-manifest.json\";\n\ntype RouteFileKind = \"page\" | \"layout\";\n\ninterface NextRouteManifestFile {\n kind: RouteFileKind;\n file: string;\n}\n\ninterface NextRouteManifestEntry {\n route: string;\n segments: string[];\n files: NextRouteManifestFile[];\n}\n\ninterface NextRouteManifest {\n version: 1;\n entries: NextRouteManifestEntry[];\n}\n\ninterface RouteMatchResult {\n targets: DebugTarget[];\n context: RouteDebugContext;\n}\n\nlet manifestPromise: Promise<NextRouteManifest | null> | null = null;\nlet manifestFailed = false;\n\nfunction normalizePathname(pathname: string): string {\n if (!pathname || pathname === \"/\") return \"/\";\n return pathname.endsWith(\"/\") ? pathname.slice(0, -1) || \"/\" : pathname;\n}\n\nfunction splitPathname(pathname: string): string[] {\n const normalized = normalizePathname(pathname);\n if (normalized === \"/\") return [];\n return normalized\n .slice(1)\n .split(\"/\")\n .map((segment) => decodeURIComponent(segment))\n .filter(Boolean);\n}\n\nfunction isDynamicSegment(segment: string): boolean {\n return /^\\[[^\\]]+\\]$/.test(segment);\n}\n\nfunction isCatchAllSegment(segment: string): boolean {\n return /^\\[\\.\\.\\.[^\\]]+\\]$/.test(segment);\n}\n\nfunction isOptionalCatchAllSegment(segment: string): boolean {\n return /^\\[\\[\\.\\.\\.[^\\]]+\\]\\]$/.test(segment);\n}\n\nfunction scoreRouteMatch(routeSegments: string[], pathnameSegments: string[]): number | null {\n let routeIndex = 0;\n let pathIndex = 0;\n let score = 0;\n\n while (routeIndex < routeSegments.length) {\n const routeSegment = routeSegments[routeIndex];\n\n if (isOptionalCatchAllSegment(routeSegment)) {\n score += 1;\n pathIndex = pathnameSegments.length;\n routeIndex += 1;\n break;\n }\n\n if (isCatchAllSegment(routeSegment)) {\n if (pathIndex >= pathnameSegments.length) return null;\n score += 2;\n pathIndex = pathnameSegments.length;\n routeIndex += 1;\n break;\n }\n\n const pathSegment = pathnameSegments[pathIndex];\n if (pathSegment === undefined) return null;\n\n if (isDynamicSegment(routeSegment)) {\n score += 5;\n routeIndex += 1;\n pathIndex += 1;\n continue;\n }\n\n if (routeSegment !== pathSegment) return null;\n\n score += 20;\n routeIndex += 1;\n pathIndex += 1;\n }\n\n if (routeIndex !== routeSegments.length) return null;\n if (pathIndex !== pathnameSegments.length) return null;\n\n return score;\n}\n\nasync function loadNextRouteManifest(): Promise<NextRouteManifest | null> {\n if (manifestFailed) return null;\n if (manifestPromise) return manifestPromise;\n\n manifestPromise = (async () => {\n try {\n const res = await fetch(NEXT_ROUTE_MANIFEST_URL, { cache: \"force-cache\" });\n if (!res.ok) {\n manifestFailed = true;\n return null;\n }\n const json = await res.json();\n if (!json || typeof json !== \"object\" || !Array.isArray((json as NextRouteManifest).entries)) {\n manifestFailed = true;\n return null;\n }\n return json as NextRouteManifest;\n } catch {\n manifestFailed = true;\n return null;\n }\n })();\n\n return manifestPromise;\n}\n\nfunction buildRouteTargets(entry: NextRouteManifestEntry): DebugTarget[] {\n const pageTarget = entry.files.find((file) => file.kind === \"page\");\n const layoutTargets = entry.files.filter((file) => file.kind === \"layout\");\n const targets: DebugTarget[] = [];\n\n if (pageTarget) {\n targets.push({\n kind: \"route-page\",\n file: pageTarget.file,\n label: \"Current page route\",\n confidence: 1,\n reason: \"matched-current-url\",\n });\n }\n\n layoutTargets.forEach((layout, index) => {\n targets.push({\n kind: \"route-layout\",\n file: layout.file,\n label: index === layoutTargets.length - 1 ? \"Nearest layout\" : \"Ancestor layout\",\n confidence: Math.max(0.7, 0.95 - index * 0.08),\n reason: \"matched-layout-chain\",\n });\n });\n\n return targets;\n}\n\nexport async function getRouteDebugTargets(pathname?: string): Promise<RouteMatchResult | null> {\n if (typeof window === \"undefined\") return null;\n const currentPathname = pathname ?? window.location.pathname;\n\n const manifest = await loadNextRouteManifest();\n if (!manifest) return null;\n\n const pathnameSegments = splitPathname(currentPathname);\n let bestEntry: NextRouteManifestEntry | null = null;\n let bestScore = -1;\n\n for (const entry of manifest.entries) {\n const score = scoreRouteMatch(entry.segments, pathnameSegments);\n if (score === null) continue;\n if (score > bestScore) {\n bestScore = score;\n bestEntry = entry;\n }\n }\n\n if (!bestEntry) return null;\n\n return {\n targets: buildRouteTargets(bestEntry),\n context: {\n pathname: normalizePathname(currentPathname),\n matchedRoute: bestEntry.route,\n source: \"next-route-manifest\",\n },\n };\n}\n\nexport function mergeDebugTargets(...groups: Array<DebugTarget[] | undefined>): DebugTarget[] {\n const merged: DebugTarget[] = [];\n const seen = new Set<string>();\n\n groups.forEach((group) => {\n group?.forEach((target) => {\n const key = `${target.kind}:${target.file}:${target.line ?? \"\"}:${target.column ?? \"\"}`;\n if (seen.has(key)) return;\n seen.add(key);\n merged.push(target);\n });\n });\n\n return merged.sort((a, b) => b.confidence - a.confidence);\n}\n","// =============================================================================\n// @impakers/debug — API Client with Cache\n// =============================================================================\n\nimport type { FeedbackPayload, FileUploadResult } from \"./types\";\nimport { loadToken } from \"./auth\";\n\nfunction getToken(): string {\n const token = loadToken();\n if (!token) throw new Error(\"인증이 필요합니다\");\n return token;\n}\n\nasync function apiFetch(url: string, options: RequestInit = {}): Promise<Response> {\n const token = getToken();\n const res = await fetch(url, {\n ...options,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${token}`,\n ...options.headers,\n },\n });\n\n if (!res.ok) {\n if (res.status === 401) throw new Error(\"인증이 만료되었습니다.\");\n const err = await res.json().catch(() => ({ error: \"요청 실패\" }));\n throw new Error(err.error || err.message || \"요청 실패\");\n }\n\n return res;\n}\n\n// =============================================================================\n// Cache\n// =============================================================================\n\ninterface CacheEntry<T> {\n data: T;\n timestamp: number;\n}\n\nconst cache = new Map<string, CacheEntry<unknown>>();\nconst inflightRequests = new Map<string, Promise<unknown>>();\nconst listeners = new Map<string, Set<(data: unknown) => void>>();\nconst CACHE_TTL = 30_000; // 30초\n\nexport interface CacheReadOptions {\n staleWhileRevalidate?: boolean;\n force?: boolean;\n}\n\nexport function getFeedbacksCacheKey(url: string): string {\n return `feedbacks:${url}`;\n}\n\nexport function getAllFeedbacksCacheKey(): string {\n return \"feedbacks:__all__\";\n}\n\nexport function getCommentsCacheKey(taskId: string): string {\n return `comments:${taskId}`;\n}\n\nfunction getCached<T>(key: string): T | null {\n const entry = cache.get(key);\n if (!entry) return null;\n if (Date.now() - entry.timestamp > CACHE_TTL) {\n cache.delete(key);\n return null;\n }\n return entry.data as T;\n}\n\nfunction setCache<T>(key: string, data: T): void {\n cache.set(key, { data, timestamp: Date.now() });\n const subs = listeners.get(key);\n if (!subs) return;\n subs.forEach((listener) => listener(data));\n}\n\nfunction peekCache<T>(key: string): T | null {\n const entry = cache.get(key);\n return (entry?.data as T | undefined) ?? null;\n}\n\nfunction isCacheFresh(key: string): boolean {\n const entry = cache.get(key);\n if (!entry) return false;\n return Date.now() - entry.timestamp <= CACHE_TTL;\n}\n\nfunction getMatchingKeys(pattern: string): string[] {\n return Array.from(cache.keys()).filter((key) => key.includes(pattern));\n}\n\nfunction snapshotCaches<T>(pattern: string): Map<string, T> {\n const snapshots = new Map<string, T>();\n for (const key of getMatchingKeys(pattern)) {\n const value = peekCache<T>(key);\n if (value !== null) snapshots.set(key, value);\n }\n return snapshots;\n}\n\nfunction restoreSnapshots<T>(snapshots: Map<string, T>): void {\n snapshots.forEach((value, key) => setCache(key, value));\n}\n\nfunction mutateCache<T>(key: string, updater: (current: T | null) => T): T {\n const next = updater(peekCache<T>(key));\n setCache(key, next);\n return next;\n}\n\nfunction mutateMatchingCaches<T>(pattern: string, updater: (current: T) => T): void {\n for (const key of getMatchingKeys(pattern)) {\n const current = peekCache<T>(key);\n if (current === null) continue;\n setCache(key, updater(current));\n }\n}\n\nasync function revalidateCache<T>(key: string, fetcher: () => Promise<T>): Promise<T> {\n const existing = inflightRequests.get(key) as Promise<T> | undefined;\n if (existing) return existing;\n\n const request = (async () => {\n try {\n const data = await fetcher();\n setCache(key, data);\n return data;\n } finally {\n inflightRequests.delete(key);\n }\n })();\n\n inflightRequests.set(key, request);\n return request;\n}\n\nasync function readWithCache<T>(\n key: string,\n fetcher: () => Promise<T>,\n options: CacheReadOptions = {},\n): Promise<T> {\n const cached = peekCache<T>(key);\n if (cached !== null && !options.force) {\n if (options.staleWhileRevalidate || !isCacheFresh(key)) {\n void revalidateCache(key, fetcher);\n }\n return cached;\n }\n return revalidateCache(key, fetcher);\n}\n\nexport function subscribeCache<T>(key: string, listener: (data: T) => void): () => void {\n const subs = listeners.get(key) || new Set<(data: unknown) => void>();\n subs.add(listener as (data: unknown) => void);\n listeners.set(key, subs);\n return () => {\n const current = listeners.get(key);\n if (!current) return;\n current.delete(listener as (data: unknown) => void);\n if (current.size === 0) listeners.delete(key);\n };\n}\n\nexport function getCachedSnapshot<T>(key: string): T | null {\n return peekCache<T>(key);\n}\n\n/** 특정 키 패턴의 캐시 무효화 */\nexport function invalidateCache(pattern?: string): void {\n if (!pattern) {\n cache.clear();\n return;\n }\n for (const key of cache.keys()) {\n if (key.includes(pattern)) cache.delete(key);\n }\n}\n\n// =============================================================================\n// 피드백 제출\n// =============================================================================\n\nexport async function submitFeedback(\n endpoint: string,\n payload: FeedbackPayload & {\n feedbackUrl?: string;\n feedbackMarker?: Record<string, unknown>;\n authorName?: string;\n debugInfo?: string;\n debug_info?: string;\n },\n): Promise<{ taskId?: string; taskNumber?: number }> {\n const tempTaskId = `temp-task-${Date.now()}`;\n const feedbackUrl = payload.feedbackUrl;\n const marker = payload.feedbackMarker as FeedbackTask[\"feedbackMarker\"] | undefined;\n const previousFeedbacks = feedbackUrl\n ? peekCache<FeedbackTask[]>(getFeedbacksCacheKey(feedbackUrl)) || []\n : null;\n const previousAll = peekCache<FeedbackTask[]>(getAllFeedbacksCacheKey());\n\n const optimisticTask: FeedbackTask | null = feedbackUrl ? {\n id: tempTaskId,\n taskNumber: 0,\n title: payload.title,\n status: \"todo\",\n priority: payload.priority,\n feedbackUrl,\n feedbackMarker: marker || null,\n createdAt: new Date().toISOString(),\n commentCount: 0,\n _optimistic: true,\n } : null;\n\n if (feedbackUrl && optimisticTask) {\n setCache(getFeedbacksCacheKey(feedbackUrl), [optimisticTask, ...previousFeedbacks]);\n if (previousAll) {\n setCache(getAllFeedbacksCacheKey(), [optimisticTask, ...previousAll]);\n }\n }\n\n try {\n const res = await apiFetch(endpoint, {\n method: \"POST\",\n body: JSON.stringify(payload),\n });\n const result = await res.json().catch(() => ({}));\n\n if (feedbackUrl && optimisticTask) {\n const finalTask: FeedbackTask = {\n ...optimisticTask,\n id: result.taskId || tempTaskId,\n taskNumber: result.taskNumber || 0,\n _optimistic: false,\n };\n\n mutateCache<FeedbackTask[]>(getFeedbacksCacheKey(feedbackUrl), (current) =>\n (current || []).map((item) => (item.id === tempTaskId ? finalTask : item)),\n );\n if (previousAll) {\n mutateCache<FeedbackTask[]>(getAllFeedbacksCacheKey(), (current) =>\n (current || []).map((item) => (item.id === tempTaskId ? finalTask : item)),\n );\n }\n void revalidateFeedbacks(endpoint, feedbackUrl).catch(() => {});\n if (previousAll) void revalidateAllFeedbacks(endpoint).catch(() => {});\n }\n\n return result;\n } catch (error) {\n if (feedbackUrl && previousFeedbacks) {\n setCache(getFeedbacksCacheKey(feedbackUrl), previousFeedbacks);\n }\n if (previousAll) {\n setCache(getAllFeedbacksCacheKey(), previousAll);\n }\n throw error;\n }\n}\n\n// =============================================================================\n// 피드백 목록 조회 (캐싱)\n// =============================================================================\n\nexport interface FeedbackTask {\n id: string;\n taskNumber: number;\n title: string;\n status: string;\n priority: string;\n feedbackUrl: string;\n feedbackMarker: {\n x: number;\n y: number;\n isFixed?: boolean;\n element?: string;\n boundingBox?: { x: number; y: number; width: number; height: number };\n } | null;\n authorName?: string | null;\n createdAt: string;\n startedAt?: string | null;\n completedAt?: string | null;\n commentCount: number;\n _optimistic?: boolean;\n}\n\nexport async function fetchFeedbacks(\n endpoint: string,\n url: string,\n options: CacheReadOptions = {},\n): Promise<FeedbackTask[]> {\n const cacheKey = getFeedbacksCacheKey(url);\n return readWithCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}?url=${encodeURIComponent(url)}`);\n const data = await res.json();\n return data.tasks || [];\n }, options);\n}\n\n/** 전체 피드백 조회 (url 필터 없이 — all 탭용) */\nexport async function fetchAllFeedbacks(\n endpoint: string,\n options: CacheReadOptions = {},\n): Promise<FeedbackTask[]> {\n const cacheKey = getAllFeedbacksCacheKey();\n return readWithCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}?url=__all__`);\n const data = await res.json();\n return data.tasks || [];\n }, options);\n}\n\nexport async function revalidateFeedbacks(endpoint: string, url: string): Promise<FeedbackTask[]> {\n const cacheKey = getFeedbacksCacheKey(url);\n return revalidateCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}?url=${encodeURIComponent(url)}`);\n const data = await res.json();\n return data.tasks || [];\n });\n}\n\nexport async function revalidateAllFeedbacks(endpoint: string): Promise<FeedbackTask[]> {\n const cacheKey = getAllFeedbacksCacheKey();\n return revalidateCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}?url=__all__`);\n const data = await res.json();\n return data.tasks || [];\n });\n}\n\n// =============================================================================\n// 코멘트 목록 조회 (캐싱)\n// =============================================================================\n\nexport interface FeedbackComment {\n id: string;\n content: string;\n authorName: string;\n authorId?: string;\n imageUrl?: string;\n fileUrl?: string;\n fileName?: string;\n fileType?: string;\n fileSize?: number;\n fileSource?: \"supabase\" | \"google_drive\";\n createdAt: string;\n}\n\nexport async function fetchComments(\n endpoint: string,\n taskId: string,\n options: CacheReadOptions = {},\n): Promise<FeedbackComment[]> {\n const cacheKey = getCommentsCacheKey(taskId);\n return readWithCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}/${taskId}/comments`);\n const data = await res.json();\n return data.comments || [];\n }, options);\n}\n\nexport async function revalidateComments(\n endpoint: string,\n taskId: string,\n): Promise<FeedbackComment[]> {\n const cacheKey = getCommentsCacheKey(taskId);\n return revalidateCache(cacheKey, async () => {\n const res = await apiFetch(`${endpoint}/${taskId}/comments`);\n const data = await res.json();\n return data.comments || [];\n });\n}\n\nfunction incrementCommentCount(taskId: string, delta: number): void {\n mutateMatchingCaches<FeedbackTask[]>(\"feedbacks:\", (items) =>\n items.map((item) => (\n item.id === taskId\n ? { ...item, commentCount: Math.max(0, (item.commentCount || 0) + delta) }\n : item\n )),\n );\n}\n\nfunction revalidateCachedFeedbackLists(endpoint: string): void {\n const feedbackKeys = getMatchingKeys(\"feedbacks:\");\n feedbackKeys.forEach((key) => {\n const url = key.replace(\"feedbacks:\", \"\");\n if (url === \"__all__\") {\n void revalidateAllFeedbacks(endpoint).catch(() => {});\n } else {\n void revalidateFeedbacks(endpoint, url).catch(() => {});\n }\n });\n}\n\n// =============================================================================\n// 코멘트 추가 (캐시 낙관적 업데이트)\n// =============================================================================\n\nexport async function postComment(\n endpoint: string,\n taskId: string,\n content: string,\n authorName: string,\n authorId?: string,\n screenshot?: string,\n file?: FileUploadResult,\n): Promise<FeedbackComment> {\n const tempComment: FeedbackComment = {\n id: `temp-${Date.now()}`,\n content,\n authorName,\n authorId,\n imageUrl: screenshot || undefined,\n fileUrl: file?.url,\n fileName: file?.fileName,\n fileType: file?.fileType,\n fileSize: file?.fileSize,\n fileSource: file?.fileSource,\n createdAt: new Date().toISOString(),\n };\n const cacheKey = getCommentsCacheKey(taskId);\n const previousComments = peekCache<FeedbackComment[]>(cacheKey) || [];\n const feedbackSnapshots = snapshotCaches<FeedbackTask[]>(\"feedbacks:\");\n setCache(cacheKey, [...previousComments, tempComment]);\n incrementCommentCount(taskId, 1);\n\n try {\n const res = await apiFetch(`${endpoint}/${taskId}/comments`, {\n method: \"POST\",\n body: JSON.stringify({\n content,\n authorName,\n authorId,\n screenshot,\n ...(file && {\n fileUrl: file.url,\n fileName: file.fileName,\n fileType: file.fileType,\n fileSize: file.fileSize,\n fileSource: file.fileSource,\n }),\n }),\n });\n const data = await res.json();\n const serverComment = data.comment;\n\n mutateCache<FeedbackComment[]>(cacheKey, (current) =>\n (current || []).map((comment) => (\n comment.id === tempComment.id ? serverComment : comment\n )),\n );\n void revalidateComments(endpoint, taskId);\n revalidateCachedFeedbackLists(endpoint);\n return serverComment;\n } catch (error) {\n setCache(cacheKey, previousComments);\n restoreSnapshots(feedbackSnapshots);\n throw error;\n }\n}\n\n// =============================================================================\n// 파일 업로드 (multipart/form-data)\n// =============================================================================\n\nconst MAX_FILE_SIZE = 4.5 * 1024 * 1024; // 4.5MB (Vercel limit)\n\nexport async function uploadFile(\n endpoint: string,\n file: File,\n context: \"feedback\" | \"comment\",\n taskId?: string,\n): Promise<FileUploadResult> {\n if (file.size > MAX_FILE_SIZE) {\n throw new Error(`파일 크기가 4.5MB를 초과합니다. (${(file.size / 1024 / 1024).toFixed(1)}MB)`);\n }\n\n const token = getToken();\n const formData = new FormData();\n formData.append(\"file\", file);\n formData.append(\"context\", context);\n if (taskId) formData.append(\"taskId\", taskId);\n\n const res = await fetch(`${endpoint}/upload`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n // Content-Type은 FormData가 자동 설정 (boundary 포함)\n },\n body: formData,\n });\n\n if (!res.ok) {\n if (res.status === 401) throw new Error(\"인증이 만료되었습니다.\");\n if (res.status === 413) throw new Error(\"파일 크기가 4.5MB를 초과합니다.\");\n const err = await res.json().catch(() => ({ error: \"파일 업로드 실패\" }));\n throw new Error(err.error || \"파일 업로드 실패\");\n }\n\n return res.json();\n}\n\n// =============================================================================\n// 태스크 상태 변경\n// =============================================================================\n\nexport async function updateTaskStatus(\n endpoint: string,\n taskId: string,\n status: \"todo\" | \"in_progress\" | \"done\",\n): Promise<void> {\n const snapshots = snapshotCaches<FeedbackTask[]>(\"feedbacks:\");\n mutateMatchingCaches<FeedbackTask[]>(\"feedbacks:\", (items) =>\n items.map((item) => (item.id === taskId ? { ...item, status } : item)),\n );\n\n try {\n await apiFetch(`${endpoint}/${taskId}/status`, {\n method: \"PATCH\",\n body: JSON.stringify({ status }),\n });\n revalidateCachedFeedbackLists(endpoint);\n } catch (error) {\n restoreSnapshots(snapshots);\n throw error;\n }\n}\n","// =============================================================================\n// @impakers/debug — Runtime Source Map Resolver\n// =============================================================================\n//\n// 번들된 파일의 위치(line, column)를 소스맵을 통해 원본 소스 파일 경로로 변환.\n//\n// 조건: 클라이언트 프로젝트에서 nosources-source-map 또는\n// productionBrowserSourceMaps: true 설정이 필요.\n// nosources-source-map 권장 (소스코드 노출 없이 파일 경로+라인 resolve 가능)\n//\n// 플로우:\n// 1. 번들 파일 URL + line + column 받음\n// 2. {파일}.map 을 fetch (캐싱)\n// 3. @jridgewell/trace-mapping으로 원본 위치 resolve\n//\n\nimport { AnyMap, originalPositionFor } from \"@jridgewell/trace-mapping\";\n\n// 소스맵 캐시 (URL → TraceMap)\ntype SourceMapInstance = ReturnType<typeof AnyMap>;\nconst cache = new Map<string, SourceMapInstance | null>();\n// 실패한 URL은 재시도하지 않음\nconst failedUrls = new Set<string>();\n\n/**\n * JS 파일 내의 //# sourceMappingURL= 코멘트에서 소스맵 URL을 추출\n */\nasync function getSourceMapUrlFromBundle(bundleUrl: string): Promise<string | null> {\n try {\n const res = await fetch(bundleUrl, { cache: \"force-cache\" });\n if (!res.ok) return null;\n const text = await res.text();\n // 마지막 sourceMappingURL 코멘트 찾기\n const match = text.match(/\\/\\/[#@]\\s*sourceMappingURL\\s*=\\s*(\\S+)\\s*$/m);\n if (!match) return null;\n const mapRef = match[1];\n // 절대 URL이면 그대로, 상대 경로면 번들 URL 기준으로 resolve\n if (mapRef.startsWith(\"http\")) return mapRef;\n const base = bundleUrl.substring(0, bundleUrl.lastIndexOf(\"/\") + 1);\n return base + mapRef;\n } catch {\n return null;\n }\n}\n\n/**\n * 소스맵을 fetch하고 AnyMap으로 파싱 (캐싱)\n * Turbopack에서는 JS 파일명과 .map 파일명이 다를 수 있으므로\n * {파일}.map 실패 시 JS 내 sourceMappingURL 코멘트를 파싱하여 재시도\n */\nasync function loadSourceMap(bundleUrl: string): Promise<SourceMapInstance | null> {\n if (cache.has(bundleUrl)) return cache.get(bundleUrl) ?? null;\n if (failedUrls.has(bundleUrl)) return null;\n\n // 1차: {파일}.map 시도\n const directMapUrl = bundleUrl.endsWith(\".map\") ? bundleUrl : `${bundleUrl}.map`;\n try {\n const res = await fetch(directMapUrl, { cache: \"force-cache\" });\n if (res.ok) {\n const rawMap = await res.json();\n const traceMap = new AnyMap(rawMap);\n cache.set(bundleUrl, traceMap);\n return traceMap;\n }\n } catch {\n // 1차 실패 시 폴백\n }\n\n // 2차: JS 파일에서 sourceMappingURL 추출 (Turbopack은 .js와 .map 파일명이 다름)\n const actualMapUrl = await getSourceMapUrlFromBundle(bundleUrl);\n if (actualMapUrl) {\n try {\n const res = await fetch(actualMapUrl, { cache: \"force-cache\" });\n if (res.ok) {\n const rawMap = await res.json();\n const traceMap = new AnyMap(rawMap);\n cache.set(bundleUrl, traceMap);\n return traceMap;\n }\n } catch {\n // 2차 실패\n }\n }\n\n failedUrls.add(bundleUrl);\n cache.set(bundleUrl, null);\n return null;\n}\n\n/** resolve 결과 */\nexport interface ResolvedSource {\n /** 원본 소스 파일 경로 (예: src/components/Dashboard.tsx) */\n source: string;\n /** 원본 라인 번호 */\n line: number;\n /** 원본 컬럼 번호 */\n column: number;\n /** 원본 심볼 이름 (있으면) */\n name: string | null;\n}\n\n/**\n * 번들 파일의 위치를 원본 소스 위치로 변환\n *\n * @param bundlePath - 번들 파일 경로 (예: _next/static/chunks/app-layout_abc123.js)\n * @param line - 번들 파일의 라인 번호\n * @param column - 번들 파일의 컬럼 번호\n * @returns 원본 소스 위치 또는 null\n */\nexport async function resolveSourcePosition(\n bundlePath: string,\n line: number,\n column: number,\n): Promise<ResolvedSource | null> {\n // 상대 경로를 절대 URL로 변환\n let bundleUrl: string;\n try {\n if (bundlePath.startsWith(\"http\")) {\n bundleUrl = bundlePath;\n } else {\n bundleUrl = new URL(bundlePath, window.location.origin).href;\n }\n } catch {\n return null;\n }\n\n const traceMap = await loadSourceMap(bundleUrl);\n if (!traceMap) return null;\n\n try {\n const pos = originalPositionFor(traceMap, { line, column });\n if (!pos.source) return null;\n\n // webpack:///나 turbopack:/// 접두사 제거\n let source = pos.source;\n source = source.replace(/^webpack:\\/\\/\\//, \"\");\n source = source.replace(/^turbopack:\\/\\/\\//, \"\");\n source = source.replace(/^\\[project\\]\\//, \"\");\n source = source.replace(/^\\.\\//, \"\");\n\n // node_modules 경로는 무시\n if (source.includes(\"node_modules/\")) return null;\n\n return {\n source,\n line: pos.line ?? 0,\n column: pos.column ?? 0,\n name: pos.name ?? null,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * 소스 파일 문자열 (예: \"_next/static/chunks/app_abc.js:23484:23\")을 파싱하여\n * 원본 소스 위치로 resolve\n */\nexport async function resolveSourceString(\n sourceStr: string,\n): Promise<ResolvedSource | null> {\n if (!sourceStr) return null;\n\n // \"파일:라인:컬럼\" 형식 파싱\n const match = sourceStr.match(/^(.+):(\\d+):(\\d+)$/);\n if (!match) return null;\n\n const [, filePath, lineStr, colStr] = match;\n const line = parseInt(lineStr, 10);\n const column = parseInt(colStr, 10);\n\n if (isNaN(line) || isNaN(column)) return null;\n\n return resolveSourcePosition(filePath, line, column);\n}\n\n/**\n * 소스맵 사용 가능 여부를 확인 (첫 번째 청크 파일의 .map 존재 확인)\n */\nexport async function isSourceMapAvailable(): Promise<boolean> {\n if (typeof document === \"undefined\") return false;\n\n // 페이지의 script 태그에서 첫 번째 청크 파일 찾기\n const scripts = document.querySelectorAll(\"script[src]\");\n for (const script of scripts) {\n const src = (script as HTMLScriptElement).src;\n if (src.includes(\"/chunks/\") || src.includes(\"/_next/\")) {\n try {\n const res = await fetch(`${src}.map`, { method: \"HEAD\", cache: \"force-cache\" });\n return res.ok;\n } catch {\n continue;\n }\n }\n }\n\n return false;\n}\n","\nconst css = \"@keyframes styles-module__markerIn___7B1j9 {\\n from {\\n opacity: 0;\\n transform: translate(-50%, -50%) scale(0.3);\\n }\\n to {\\n opacity: 1;\\n transform: translate(-50%, -50%) scale(1);\\n }\\n}\\n@keyframes styles-module__tooltipIn___3o7t0 {\\n from {\\n opacity: 0;\\n transform: translateX(-50%) scale(0.95);\\n }\\n to {\\n opacity: 1;\\n transform: translateX(-50%) scale(1);\\n }\\n}\\n.styles-module__marker___7PVX9 {\\n position: absolute;\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n color: white;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 11px;\\n font-weight: 700;\\n transform: translate(-50%, -50%);\\n cursor: pointer;\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), inset 0 0 0 1px rgba(255, 255, 255, 0.2);\\n user-select: none;\\n z-index: 1;\\n transition: transform 0.12s, box-shadow 0.12s;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, sans-serif;\\n}\\n.styles-module__marker___7PVX9:hover {\\n z-index: 2;\\n transform: translate(-50%, -50%) scale(1.15);\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), inset 0 0 0 1px rgba(255, 255, 255, 0.3);\\n}\\n.styles-module__marker___7PVX9.styles-module__enter___V7KfW {\\n animation: styles-module__markerIn___7B1j9 0.25s cubic-bezier(0.22, 1, 0.36, 1) forwards;\\n}\\n.styles-module__marker___7PVX9.styles-module__hovered___ojzb7 {\\n transform: translate(-50%, -50%) scale(1.15);\\n}\\n.styles-module__marker___7PVX9.styles-module__done___J6WOE {\\n opacity: 0.55;\\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15), inset 0 0 0 1px rgba(255, 255, 255, 0.1);\\n}\\n\\n.styles-module__pending___qQbOR {\\n position: fixed;\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n color: white;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n transform: translate(-50%, -50%);\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25), inset 0 0 0 1px rgba(255, 255, 255, 0.2);\\n z-index: 1;\\n pointer-events: none;\\n}\\n.styles-module__pending___qQbOR.styles-module__enter___V7KfW {\\n animation: styles-module__markerIn___7B1j9 0.25s cubic-bezier(0.22, 1, 0.36, 1) forwards;\\n}\\n\\n.styles-module__markerTooltip___ns-gQ {\\n position: absolute;\\n top: calc(100% + 8px);\\n left: 50%;\\n transform: translateX(-50%);\\n background: rgba(0, 0, 0, 0.88);\\n color: #fff;\\n padding: 6px 10px;\\n border-radius: 6px;\\n font-size: 11px;\\n white-space: nowrap;\\n max-width: 200px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n pointer-events: none;\\n z-index: 10;\\n}\\n.styles-module__markerTooltip___ns-gQ.styles-module__enter___V7KfW {\\n animation: styles-module__tooltipIn___3o7t0 0.1s ease-out forwards;\\n}\\n\\n.styles-module__markerQuote___1bRQp {\\n display: block;\\n font-weight: 500;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__markerNote___3iWm4 {\\n display: block;\\n color: rgba(255, 255, 255, 0.7);\\n margin-top: 2px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\";\nconst classNames = {\"marker\":\"styles-module__marker___7PVX9\",\"enter\":\"styles-module__enter___V7KfW\",\"markerIn\":\"styles-module__markerIn___7B1j9\",\"hovered\":\"styles-module__hovered___ojzb7\",\"done\":\"styles-module__done___J6WOE\",\"pending\":\"styles-module__pending___qQbOR\",\"markerTooltip\":\"styles-module__markerTooltip___ns-gQ\",\"tooltipIn\":\"styles-module__tooltipIn___3o7t0\",\"markerQuote\":\"styles-module__markerQuote___1bRQp\",\"markerNote\":\"styles-module__markerNote___3iWm4\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-annotation-marker-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-annotation-marker-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","import { Annotation } from \"../../types\";\nimport styles from \"./styles.module.scss\";\n\n// =============================================================================\n// AnnotationMarker\n// =============================================================================\n\n/** 상태별 마커 색상 */\nconst IN_PROGRESS_MARKER_COLOR = \"#3b82f6\"; // blue\nconst DONE_MARKER_COLOR = \"#9ca3af\"; // gray\n\ntype AnnotationMarkerProps = {\n annotation: Annotation;\n layerIndex: number;\n isAnimated: boolean;\n isHovered: boolean;\n accentColor: string;\n markerClickBehavior: \"edit\" | \"delete\";\n onHover: () => void;\n onHoverEnd: () => void;\n onClick: () => void;\n onContextMenu?: () => void;\n isDeleting?: boolean;\n};\n\nexport function AnnotationMarker({\n annotation,\n layerIndex,\n isAnimated,\n isHovered,\n accentColor,\n onHover,\n onHoverEnd,\n onClick,\n}: AnnotationMarkerProps) {\n const animClass = !isAnimated ? styles.enter : \"\";\n const isDone = annotation.status === \"done\" || annotation.status === \"resolved\";\n const isInProgress = annotation.status === \"in_progress\";\n const markerColor = isDone\n ? DONE_MARKER_COLOR\n : isInProgress\n ? IN_PROGRESS_MARKER_COLOR\n : accentColor;\n\n return (\n <div\n className={`${styles.marker} ${animClass} ${isHovered ? styles.hovered : \"\"} ${isDone ? styles.done : \"\"}`}\n data-annotation-marker\n style={{\n left: `${annotation.x}%`,\n top: annotation.y,\n backgroundColor: markerColor,\n animationDelay: `${layerIndex * 20}ms`,\n }}\n onMouseEnter={onHover}\n onMouseLeave={onHoverEnd}\n onClick={(e) => {\n e.stopPropagation();\n onClick();\n }}\n >\n <span>{layerIndex + 1}</span>\n\n {isHovered && (\n <div className={`${styles.markerTooltip} ${styles.enter}`}>\n <span className={styles.markerQuote}>{annotation.element}</span>\n {annotation.comment && (\n <span className={styles.markerNote}>{annotation.comment}</span>\n )}\n </div>\n )}\n </div>\n );\n}\n\n// =============================================================================\n// PendingMarker\n// =============================================================================\n\ntype PendingMarkerProps = {\n x: number;\n y: number;\n isMultiSelect: boolean;\n accentColor: string;\n};\n\nexport function PendingMarker({ x, y, accentColor }: PendingMarkerProps) {\n return (\n <div\n className={`${styles.pending} ${styles.enter}`}\n data-annotation-marker\n style={{\n left: `${x}%`,\n top: y,\n backgroundColor: accentColor,\n }}\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </div>\n );\n}\n","\"use client\";\n\nimport { useState, useRef, useEffect, useCallback } from \"react\";\nimport { captureElement } from \"../../utils/capture-element\";\nimport styles from \"./styles.module.scss\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface CommentData {\n id: string;\n content: string;\n authorName: string;\n authorId?: string;\n imageUrl?: string;\n fileUrl?: string;\n fileName?: string;\n fileType?: string;\n fileSize?: number;\n fileSource?: string;\n createdAt: string;\n}\n\nexport interface ThreadTask {\n id: string;\n taskNumber?: number;\n title: string;\n status: string;\n feedbackMarker?: { element?: string };\n authorName?: string;\n createdAt: string;\n comments: CommentData[];\n}\n\nexport interface CommentThreadProps {\n task: ThreadTask;\n currentUserName: string;\n currentUserId?: string;\n left: number;\n top?: number;\n bottom?: number;\n onClose: () => void;\n /** content, screenshot(base64), file(비이미지 파일) */\n onReply: (taskId: string, content: string, screenshot?: string, file?: File) => void;\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nfunction formatTime(dateStr: string): string {\n const date = new Date(dateStr);\n const diff = Date.now() - date.getTime();\n const pad = (n: number) => String(n).padStart(2, \"0\");\n const abs = `${date.getMonth() + 1}/${date.getDate()} ${pad(date.getHours())}:${pad(date.getMinutes())}`;\n const m = Math.floor(diff / 60000);\n if (m < 1) return `${abs} (방금)`;\n if (m < 60) return `${abs} (${m}분 전)`;\n const h = Math.floor(m / 60);\n if (h < 24) return `${abs} (${h}시간 전)`;\n const d = Math.floor(h / 24);\n return `${abs} (${d}일 전)`;\n}\n\nfunction getInitials(name: string): string {\n return name.slice(0, 1).toUpperCase();\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nfunction getFileIcon(mimeType: string): string {\n if (mimeType.includes(\"pdf\")) return \"PDF\";\n if (mimeType.includes(\"spreadsheet\") || mimeType.includes(\"excel\") || mimeType.includes(\"csv\")) return \"XLS\";\n if (mimeType.includes(\"presentation\") || mimeType.includes(\"powerpoint\")) return \"PPT\";\n if (mimeType.includes(\"document\") || mimeType.includes(\"word\")) return \"DOC\";\n if (mimeType.includes(\"zip\") || mimeType.includes(\"compressed\") || mimeType.includes(\"archive\")) return \"ZIP\";\n if (mimeType.includes(\"video\")) return \"VID\";\n if (mimeType.includes(\"audio\")) return \"AUD\";\n return \"FILE\";\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport function CommentThread({\n task,\n currentUserName,\n currentUserId,\n left,\n top,\n bottom,\n onClose,\n onReply,\n}: CommentThreadProps) {\n const [replyText, setReplyText] = useState(\"\");\n const [exiting, setExiting] = useState(false);\n const [pendingImage, setPendingImage] = useState<string | null>(null); // base64 미리보기\n const [pendingFile, setPendingFile] = useState<File | null>(null); // 비이미지 파일\n const [capturingDom, setCapturingDom] = useState(false);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const [lightboxSrc, setLightboxSrc] = useState<string | null>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (listRef.current) listRef.current.scrollTop = listRef.current.scrollHeight;\n textareaRef.current?.focus();\n }, [task.comments.length]);\n\n // 바깥 클릭 닫기 (DOM 캡처 모드일 때는 무시)\n useEffect(() => {\n if (capturingDom) return;\n const handler = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (target.closest(`.${styles.thread}`)) return;\n if (target.closest(\"[data-annotation-marker]\")) return;\n if (target.closest(\"[data-impakers-debug]\")) return;\n handleClose();\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [capturingDom]);\n\n const handleClose = useCallback(() => {\n setExiting(true);\n setTimeout(() => onClose(), 120);\n }, [onClose]);\n\n // -------------------------------------------------------------------------\n // Send reply (with optional image)\n // -------------------------------------------------------------------------\n const handleSend = useCallback(() => {\n if (!replyText.trim() && !pendingImage && !pendingFile) return;\n onReply(task.id, replyText.trim(), pendingImage || undefined, pendingFile || undefined);\n setReplyText(\"\");\n setPendingImage(null);\n setPendingFile(null);\n }, [replyText, pendingImage, pendingFile, task.id, onReply]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n e.stopPropagation();\n if (e.nativeEvent.isComposing) return;\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n if (e.key === \"Escape\") handleClose();\n },\n [handleClose, handleSend],\n );\n\n // -------------------------------------------------------------------------\n // 카메라: DOM 선택 → 스크린샷\n // -------------------------------------------------------------------------\n const startDomCapture = useCallback(() => {\n setCapturingDom(true);\n\n // 모든 debug UI 숨기기\n const debugEls = document.querySelectorAll(\"[data-impakers-debug], [data-annotation-marker]\");\n debugEls.forEach((el) => (el as HTMLElement).style.visibility = \"hidden\");\n\n // crosshair 커서 (CSS class 방식으로 전환 — 동적 DOM에도 적용)\n document.documentElement.classList.add(\"impakers-selecting\");\n\n let hoverBox: HTMLDivElement | null = null;\n\n const showHover = (rect: DOMRect) => {\n if (!hoverBox) {\n hoverBox = document.createElement(\"div\");\n hoverBox.style.cssText = `position:fixed;border:2px solid #3b82f6;background:rgba(59,130,246,0.05);border-radius:4px;pointer-events:none;z-index:999999;transition:all 0.08s ease`;\n document.body.appendChild(hoverBox);\n }\n hoverBox.style.left = `${rect.left}px`;\n hoverBox.style.top = `${rect.top}px`;\n hoverBox.style.width = `${rect.width}px`;\n hoverBox.style.height = `${rect.height}px`;\n };\n\n const cleanup = () => {\n document.removeEventListener(\"mousemove\", handleMove);\n document.removeEventListener(\"click\", handleClick, true);\n document.removeEventListener(\"keydown\", handleEsc);\n document.documentElement.classList.remove(\"impakers-selecting\");\n hoverBox?.remove();\n debugEls.forEach((el) => (el as HTMLElement).style.visibility = \"\");\n setCapturingDom(false);\n };\n\n const handleMove = (e: MouseEvent) => {\n const el = document.elementFromPoint(e.clientX, e.clientY) as HTMLElement;\n if (!el || el === hoverBox) return;\n showHover(el.getBoundingClientRect());\n };\n\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") { cleanup(); }\n };\n\n const handleClick = async (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation(); // 다른 핸들러(dropdown 닫기 등) 차단\n\n const targetEl = document.elementFromPoint(e.clientX, e.clientY) as HTMLElement;\n cleanup();\n\n if (!targetEl) return;\n\n try {\n const base64 = await captureElement(targetEl);\n setPendingImage(base64);\n } catch (err) {\n console.error(\"[@impakers/debug] DOM 스크린샷 실패:\", err);\n }\n\n textareaRef.current?.focus();\n };\n\n document.addEventListener(\"mousemove\", handleMove);\n document.addEventListener(\"click\", handleClick, true);\n document.addEventListener(\"keydown\", handleEsc);\n }, []);\n\n const handleCameraClick = useCallback(() => {\n startDomCapture();\n }, [startDomCapture]);\n\n // -------------------------------------------------------------------------\n // + 버튼: 파일 첨부\n // -------------------------------------------------------------------------\n const handleAttachClick = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n const handleFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n // 4.5MB 제한 체크\n if (file.size > 4.5 * 1024 * 1024) {\n console.warn(\"[@impakers/debug] 파일 크기가 4.5MB를 초과합니다.\");\n e.target.value = \"\";\n return;\n }\n\n if (file.type.startsWith(\"image/\")) {\n // 이미지: base64 미리보기\n setPendingFile(null);\n const reader = new FileReader();\n reader.onload = () => {\n setPendingImage(reader.result as string);\n };\n reader.readAsDataURL(file);\n } else {\n // 비이미지: File 객체 보관\n setPendingImage(null);\n setPendingFile(file);\n }\n\n // input 초기화 (같은 파일 다시 선택 가능)\n e.target.value = \"\";\n }, []);\n\n // -------------------------------------------------------------------------\n // Render\n // -------------------------------------------------------------------------\n const feedbackTitle = task.title.replace(/^\\[피드백\\]\\s*/, \"\");\n\n const positionStyle: React.CSSProperties = {\n left,\n ...(top !== undefined ? { top } : {}),\n ...(bottom !== undefined ? { bottom } : {}),\n };\n\n return (\n <div\n className={`${styles.thread} ${exiting ? styles.exiting : \"\"}`}\n style={positionStyle}\n data-impakers-debug=\"\"\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header — 피드백 생성자 이름 표시 */}\n <div className={styles.header}>\n <div className={styles.avatar}>{getInitials(task.authorName || currentUserName)}</div>\n <div className={styles.headerInfo}>\n <div className={styles.headerTop}>\n <span className={styles.authorName}>{task.authorName || currentUserName}</span>\n <span className={styles.timestamp}>{formatTime(task.createdAt)}</span>\n </div>\n <div className={styles.title}>{feedbackTitle}</div>\n </div>\n <div className={styles.headerActions}>\n <button className={styles.headerAction} onClick={handleClose} title=\"닫기\" type=\"button\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n\n {/* Comments list */}\n {task.comments.length > 0 && (\n <>\n <div className={styles.divider} />\n <div className={styles.commentsList} ref={listRef}>\n {task.comments.map((comment) => (\n <div key={comment.id} className={styles.comment}>\n <div className={styles.avatar} style={{ width: 22, height: 22, fontSize: 10 }}>\n {getInitials(comment.authorName)}\n </div>\n <div className={styles.commentContent}>\n <div className={styles.commentTop}>\n <span className={styles.commentAuthor}>{comment.authorName}</span>\n <span className={styles.commentTime}>{formatTime(comment.createdAt)}</span>\n </div>\n {comment.content && <div className={styles.commentText}>{comment.content}</div>}\n {comment.imageUrl && comment.imageUrl !== \"loading...\" && (\n <div\n className={styles.screenshot}\n onClick={() => setLightboxSrc(comment.imageUrl!)}\n style={{ cursor: \"pointer\" }}\n >\n <img src={comment.imageUrl} alt=\"screenshot\" />\n </div>\n )}\n {comment.fileUrl && (\n <a\n className={styles.fileCard}\n href={comment.fileUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={(e) => e.stopPropagation()}\n >\n <span className={styles.fileIcon}>{getFileIcon(comment.fileType || \"\")}</span>\n <span className={styles.fileInfo}>\n <span className={styles.fileCardName}>{comment.fileName || \"파일\"}</span>\n {comment.fileSize != null && (\n <span className={styles.fileCardSize}>{formatFileSize(comment.fileSize)}</span>\n )}\n </span>\n </a>\n )}\n </div>\n </div>\n ))}\n </div>\n </>\n )}\n\n {/* 첨부 이미지 미리보기 */}\n {pendingImage && (\n <div className={styles.pendingImage}>\n <img src={pendingImage} alt=\"pending\" />\n <button className={styles.pendingRemove} onClick={() => setPendingImage(null)} type=\"button\">&times;</button>\n </div>\n )}\n\n {/* 첨부 파일 미리보기 */}\n {pendingFile && (\n <div className={styles.pendingFile}>\n <span className={styles.fileIcon}>{getFileIcon(pendingFile.type)}</span>\n <span className={styles.fileInfo}>\n <span className={styles.fileCardName}>{pendingFile.name}</span>\n <span className={styles.fileCardSize}>{formatFileSize(pendingFile.size)}</span>\n </span>\n <button className={styles.pendingRemove} onClick={() => setPendingFile(null)} type=\"button\">&times;</button>\n </div>\n )}\n\n {/* Reply input */}\n <div className={styles.replyArea}>\n <textarea\n ref={textareaRef}\n className={styles.replyInput}\n placeholder=\"Reply...\"\n value={replyText}\n onChange={(e) => {\n setReplyText(e.target.value);\n const el = e.target;\n el.style.height = \"auto\";\n el.style.height = `${Math.min(el.scrollHeight, 120)}px`;\n }}\n onKeyDown={handleKeyDown}\n rows={2}\n />\n </div>\n <div className={styles.replyToolbar}>\n {/* + 파일 첨부 */}\n <button className={styles.replyTool} onClick={handleAttachClick} type=\"button\" title=\"파일 첨부\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" /><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </button>\n {/* 카메라 (DOM 스크린샷) */}\n <button className={styles.replyTool} onClick={handleCameraClick} type=\"button\" title=\"요소 스크린샷\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14.5 4h-5L7 7H4a2 2 0 00-2 2v9a2 2 0 002 2h16a2 2 0 002-2V9a2 2 0 00-2-2h-3l-2.5-3z\" />\n <circle cx=\"12\" cy=\"13\" r=\"3\" />\n </svg>\n </button>\n {/* 전송 */}\n <button\n className={`${styles.replySend} ${(replyText.trim() || pendingImage || pendingFile) ? styles.active : \"\"}`}\n onClick={handleSend}\n disabled={!replyText.trim() && !pendingImage && !pendingFile}\n type=\"button\"\n title=\"전송\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" /><polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n </button>\n </div>\n\n {/* Hidden file input */}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"*/*\"\n style={{ display: \"none\" }}\n onChange={handleFileChange}\n />\n\n {/* 이미지 확대 */}\n {lightboxSrc && (\n <div className={styles.lightbox} onClick={() => setLightboxSrc(null)} data-impakers-debug=\"\">\n <img src={lightboxSrc} alt=\"enlarged\" onClick={(e) => e.stopPropagation()} />\n <button className={styles.lightboxClose} onClick={() => setLightboxSrc(null)} type=\"button\">&times;</button>\n </div>\n )}\n </div>\n );\n}\n","\nconst css = \"@keyframes styles-module__threadIn___pBTFZ {\\n from {\\n opacity: 0;\\n transform: scale(0.96) translateY(4px);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1) translateY(0);\\n }\\n}\\n@keyframes styles-module__threadOut___-ccKh {\\n from {\\n opacity: 1;\\n transform: scale(1);\\n }\\n to {\\n opacity: 0;\\n transform: scale(0.96);\\n }\\n}\\n.styles-module__thread___ua2EO {\\n position: fixed;\\n width: 340px;\\n max-height: min(480px, 100vh - 40px);\\n background: #fff;\\n border-radius: 12px;\\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);\\n z-index: 100002;\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n font-size: 13px;\\n color: #1a1a1a;\\n animation: styles-module__threadIn___pBTFZ 0.15s ease-out;\\n -webkit-font-smoothing: antialiased;\\n}\\n.styles-module__thread___ua2EO.styles-module__exiting___RIPeX {\\n animation: styles-module__threadOut___-ccKh 0.12s ease-in forwards;\\n pointer-events: none;\\n}\\n\\n.styles-module__header___GiEBq {\\n padding: 14px 16px 10px;\\n display: flex;\\n align-items: flex-start;\\n gap: 10px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__avatar___JElAd {\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n background: #16a34a;\\n color: #fff;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 11px;\\n font-weight: 600;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__headerInfo___E8809 {\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__headerTop___eDiCd {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n margin-bottom: 4px;\\n}\\n\\n.styles-module__authorName___T1BfB {\\n font-size: 13px;\\n font-weight: 600;\\n color: #1a1a1a;\\n}\\n\\n.styles-module__timestamp___WusBf {\\n font-size: 12px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__headerActions___8FsMY {\\n display: flex;\\n align-items: center;\\n gap: 2px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__headerAction___Tinmq {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #9ca3af;\\n transition: background 0.12s, color 0.12s;\\n padding: 0;\\n}\\n.styles-module__headerAction___Tinmq:hover {\\n background: #f3f4f6;\\n color: #374151;\\n}\\n.styles-module__headerAction___Tinmq svg {\\n width: 16px;\\n height: 16px;\\n}\\n\\n.styles-module__title___qkfqY {\\n font-size: 13px;\\n color: #1a1a1a;\\n line-height: 1.5;\\n word-break: break-word;\\n}\\n\\n.styles-module__commentsList___kYqAR {\\n flex: 1;\\n min-height: 0;\\n overflow-y: auto;\\n padding: 0;\\n}\\n.styles-module__commentsList___kYqAR::-webkit-scrollbar {\\n width: 4px;\\n}\\n.styles-module__commentsList___kYqAR::-webkit-scrollbar-thumb {\\n background: #d1d5db;\\n border-radius: 2px;\\n}\\n\\n.styles-module__comment___pW3IO {\\n padding: 10px 16px;\\n display: flex;\\n align-items: flex-start;\\n gap: 10px;\\n}\\n.styles-module__comment___pW3IO:hover {\\n background: #f9fafb;\\n}\\n.styles-module__comment___pW3IO:hover .styles-module__commentActions___wO0fs {\\n opacity: 1;\\n}\\n\\n.styles-module__commentHighlight___EiTmx {\\n background: #eff6ff;\\n border-left: 2px solid #3b82f6;\\n padding-left: 14px;\\n}\\n\\n.styles-module__commentContent___RObGr {\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__commentTop___BbTF3 {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n margin-bottom: 2px;\\n}\\n\\n.styles-module__commentAuthor___tBjpl {\\n font-size: 13px;\\n font-weight: 600;\\n color: #1a1a1a;\\n}\\n\\n.styles-module__commentTime___0OLrz {\\n font-size: 12px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__commentActions___wO0fs {\\n display: flex;\\n gap: 2px;\\n opacity: 0;\\n transition: opacity 0.12s;\\n}\\n\\n.styles-module__commentText___ldy2V {\\n font-size: 13px;\\n color: #374151;\\n line-height: 1.5;\\n word-break: break-word;\\n white-space: pre-wrap;\\n}\\n\\n.styles-module__screenshot___jUqau {\\n margin-top: 8px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n overflow: hidden;\\n position: relative;\\n max-width: 200px;\\n}\\n.styles-module__screenshot___jUqau img {\\n width: 100%;\\n height: auto;\\n display: block;\\n}\\n.styles-module__screenshot___jUqau .styles-module__screenshotBadge___roEqY {\\n position: absolute;\\n top: 6px;\\n right: 6px;\\n background: rgba(0, 0, 0, 0.6);\\n color: #fff;\\n font-size: 10px;\\n padding: 2px 6px;\\n border-radius: 4px;\\n font-weight: 500;\\n}\\n\\n.styles-module__fileCard___-iOro {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n margin-top: 8px;\\n padding: 8px 10px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n background: #f9fafb;\\n text-decoration: none;\\n color: inherit;\\n cursor: pointer;\\n transition: background 0.12s;\\n max-width: 200px;\\n}\\n.styles-module__fileCard___-iOro:hover {\\n background: #f3f4f6;\\n}\\n\\n.styles-module__fileIcon___dNJMT {\\n width: 32px;\\n height: 32px;\\n border-radius: 6px;\\n background: #e5e7eb;\\n color: #374151;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 10px;\\n font-weight: 700;\\n flex-shrink: 0;\\n letter-spacing: 0.5px;\\n}\\n\\n.styles-module__fileInfo___dVrLV {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n}\\n\\n.styles-module__fileCardName___SHOj- {\\n font-size: 12px;\\n font-weight: 500;\\n color: #1a1a1a;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__fileCardSize___W53JL {\\n font-size: 11px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__pendingFile___-OSRs {\\n position: relative;\\n margin: 0 16px 8px;\\n padding: 8px 10px;\\n padding-right: 30px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n background: #f9fafb;\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__divider___kDjxN {\\n height: 1px;\\n background: #f3f4f6;\\n margin: 0;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__pendingImage___gHaF3 {\\n position: relative;\\n margin: 0 16px 8px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n overflow: hidden;\\n max-height: 120px;\\n flex-shrink: 0;\\n}\\n.styles-module__pendingImage___gHaF3 img {\\n width: 100%;\\n height: auto;\\n display: block;\\n object-fit: cover;\\n max-height: 120px;\\n}\\n\\n.styles-module__pendingRemove___FRL4h {\\n position: absolute;\\n top: 4px;\\n right: 4px;\\n width: 20px;\\n height: 20px;\\n border-radius: 50%;\\n background: rgba(0, 0, 0, 0.6);\\n color: #fff;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 14px;\\n line-height: 1;\\n padding: 0;\\n}\\n.styles-module__pendingRemove___FRL4h:hover {\\n background: rgba(0, 0, 0, 0.8);\\n}\\n\\n.styles-module__replyArea___VQn9b {\\n padding: 10px 16px 8px;\\n border-top: 1px solid #f3f4f6;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__replyInput___uZNBW {\\n width: 100%;\\n border: none;\\n outline: none;\\n font-size: 13px;\\n font-family: inherit;\\n color: #1a1a1a;\\n resize: none;\\n padding: 0;\\n min-height: 36px;\\n max-height: 120px;\\n line-height: 1.55;\\n transition: height 0.1s ease;\\n}\\n.styles-module__replyInput___uZNBW::placeholder {\\n color: #9ca3af;\\n}\\n\\n.styles-module__replyToolbar___fTFJU {\\n display: flex;\\n align-items: center;\\n padding: 4px 16px 10px;\\n gap: 4px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__replyTool___Ho-Rx {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #9ca3af;\\n transition: background 0.12s, color 0.12s;\\n padding: 0;\\n}\\n.styles-module__replyTool___Ho-Rx:hover {\\n background: #f3f4f6;\\n color: #374151;\\n}\\n.styles-module__replyTool___Ho-Rx svg {\\n width: 16px;\\n height: 16px;\\n}\\n\\n.styles-module__replySend___e0VSb {\\n margin-left: auto;\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #9ca3af;\\n transition: background 0.12s, color 0.12s;\\n padding: 0;\\n}\\n.styles-module__replySend___e0VSb:hover {\\n color: #3b82f6;\\n}\\n.styles-module__replySend___e0VSb.styles-module__active___R--Jj {\\n color: #3b82f6;\\n}\\n.styles-module__replySend___e0VSb svg {\\n width: 16px;\\n height: 16px;\\n}\\n\\n.styles-module__empty___XXGiw {\\n padding: 24px 16px;\\n text-align: center;\\n color: #9ca3af;\\n font-size: 13px;\\n}\\n\\n.styles-module__statusBadge___el8ml {\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n font-size: 11px;\\n font-weight: 500;\\n padding: 2px 8px;\\n border-radius: 10px;\\n margin-left: auto;\\n}\\n.styles-module__statusBadge___el8ml.styles-module__todo___rUWBr {\\n background: #fef3c7;\\n color: #92400e;\\n}\\n.styles-module__statusBadge___el8ml.styles-module__inProgress___HEWgU {\\n background: #dbeafe;\\n color: #1e40af;\\n}\\n.styles-module__statusBadge___el8ml.styles-module__done___zC12n {\\n background: #dcfce7;\\n color: #166534;\\n}\\n\\n.styles-module__lightbox___KoWEF {\\n position: fixed;\\n inset: 0;\\n z-index: 2147483647;\\n background: rgba(0, 0, 0, 0.8);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n cursor: zoom-out;\\n}\\n.styles-module__lightbox___KoWEF img {\\n max-width: 90vw;\\n max-height: 90vh;\\n border-radius: 8px;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\\n cursor: default;\\n}\\n\\n.styles-module__lightboxClose___tGZlm {\\n position: absolute;\\n top: 16px;\\n right: 16px;\\n width: 36px;\\n height: 36px;\\n border-radius: 50%;\\n background: rgba(255, 255, 255, 0.15);\\n color: #fff;\\n border: none;\\n cursor: pointer;\\n font-size: 20px;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.styles-module__lightboxClose___tGZlm:hover {\\n background: rgba(255, 255, 255, 0.25);\\n}\";\nconst classNames = {\"thread\":\"styles-module__thread___ua2EO\",\"threadIn\":\"styles-module__threadIn___pBTFZ\",\"exiting\":\"styles-module__exiting___RIPeX\",\"threadOut\":\"styles-module__threadOut___-ccKh\",\"header\":\"styles-module__header___GiEBq\",\"avatar\":\"styles-module__avatar___JElAd\",\"headerInfo\":\"styles-module__headerInfo___E8809\",\"headerTop\":\"styles-module__headerTop___eDiCd\",\"authorName\":\"styles-module__authorName___T1BfB\",\"timestamp\":\"styles-module__timestamp___WusBf\",\"headerActions\":\"styles-module__headerActions___8FsMY\",\"headerAction\":\"styles-module__headerAction___Tinmq\",\"title\":\"styles-module__title___qkfqY\",\"commentsList\":\"styles-module__commentsList___kYqAR\",\"comment\":\"styles-module__comment___pW3IO\",\"commentActions\":\"styles-module__commentActions___wO0fs\",\"commentHighlight\":\"styles-module__commentHighlight___EiTmx\",\"commentContent\":\"styles-module__commentContent___RObGr\",\"commentTop\":\"styles-module__commentTop___BbTF3\",\"commentAuthor\":\"styles-module__commentAuthor___tBjpl\",\"commentTime\":\"styles-module__commentTime___0OLrz\",\"commentText\":\"styles-module__commentText___ldy2V\",\"screenshot\":\"styles-module__screenshot___jUqau\",\"screenshotBadge\":\"styles-module__screenshotBadge___roEqY\",\"fileCard\":\"styles-module__fileCard___-iOro\",\"fileIcon\":\"styles-module__fileIcon___dNJMT\",\"fileInfo\":\"styles-module__fileInfo___dVrLV\",\"fileCardName\":\"styles-module__fileCardName___SHOj-\",\"fileCardSize\":\"styles-module__fileCardSize___W53JL\",\"pendingFile\":\"styles-module__pendingFile___-OSRs\",\"divider\":\"styles-module__divider___kDjxN\",\"pendingImage\":\"styles-module__pendingImage___gHaF3\",\"pendingRemove\":\"styles-module__pendingRemove___FRL4h\",\"replyArea\":\"styles-module__replyArea___VQn9b\",\"replyInput\":\"styles-module__replyInput___uZNBW\",\"replyToolbar\":\"styles-module__replyToolbar___fTFJU\",\"replyTool\":\"styles-module__replyTool___Ho-Rx\",\"replySend\":\"styles-module__replySend___e0VSb\",\"active\":\"styles-module__active___R--Jj\",\"empty\":\"styles-module__empty___XXGiw\",\"statusBadge\":\"styles-module__statusBadge___el8ml\",\"todo\":\"styles-module__todo___rUWBr\",\"inProgress\":\"styles-module__inProgress___HEWgU\",\"done\":\"styles-module__done___zC12n\",\"lightbox\":\"styles-module__lightbox___KoWEF\",\"lightboxClose\":\"styles-module__lightboxClose___tGZlm\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-comment-thread-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-comment-thread-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\"use client\";\n\nimport { useState, useRef, useCallback, useEffect } from \"react\";\nimport styles from \"./styles.module.scss\";\n\nexport interface FabMenuItem {\n id: string;\n icon: React.ReactNode;\n label: string;\n badge?: number;\n active?: boolean;\n}\n\nexport interface FabMenuProps {\n items: FabMenuItem[];\n onSelect: (id: string) => void;\n onHide?: () => void;\n /** FAB 더블클릭/더블탭 시 호출 (피드백 모드 바로 진입) */\n onDoubleTap?: () => void;\n}\n\nexport function FabMenu({ items, onSelect, onHide, onDoubleTap }: FabMenuProps) {\n const [expanded, setExpanded] = useState(false);\n const [closing, setClosing] = useState(false);\n const [position, setPosition] = useState({ right: 24, bottom: 24 });\n const [showContextMenu, setShowContextMenu] = useState<{ x: number; y: number } | null>(null);\n\n const fabRef = useRef<HTMLButtonElement>(null);\n const dragging = useRef(false);\n const dragStart = useRef({ x: 0, y: 0 });\n const dragOffset = useRef({ x: 0, y: 0 });\n const hasMoved = useRef(false);\n const lastTapTime = useRef(0);\n\n // Drag\n const handleFabPointerDown = useCallback((e: React.PointerEvent) => {\n if (e.button === 2) return;\n dragging.current = true;\n hasMoved.current = false;\n const btn = fabRef.current;\n if (!btn) return;\n btn.setPointerCapture(e.pointerId);\n const rect = btn.getBoundingClientRect();\n dragStart.current = { x: e.clientX, y: e.clientY };\n dragOffset.current = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n }, []);\n\n const handleFabPointerMove = useCallback((e: React.PointerEvent) => {\n if (!dragging.current) return;\n if (Math.abs(e.clientX - dragStart.current.x) > 3 || Math.abs(e.clientY - dragStart.current.y) > 3) {\n hasMoved.current = true;\n }\n if (!hasMoved.current) return;\n setPosition({\n right: Math.max(8, Math.min(window.innerWidth - e.clientX - (44 - dragOffset.current.x), window.innerWidth - 52)),\n bottom: Math.max(8, Math.min(window.innerHeight - e.clientY - (44 - dragOffset.current.y), window.innerHeight - 52)),\n });\n }, []);\n\n const handleFabPointerUp = useCallback((e: React.PointerEvent) => {\n if (!dragging.current) return;\n fabRef.current?.releasePointerCapture(e.pointerId);\n dragging.current = false;\n if (!hasMoved.current) {\n const now = Date.now();\n const isDoubleTap = now - lastTapTime.current < 350;\n lastTapTime.current = now;\n\n if (isDoubleTap && onDoubleTap) {\n // 더블탭 → 바로 피드백 모드 진입\n if (expanded) closeMenu();\n onDoubleTap();\n return;\n }\n\n if (expanded) {\n closeMenu();\n } else {\n setExpanded(true);\n }\n }\n }, [expanded, onDoubleTap]);\n\n const closeMenu = useCallback(() => {\n setClosing(true);\n setTimeout(() => { setExpanded(false); setClosing(false); }, 150);\n }, []);\n\n // Context menu\n const handleContextMenu = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setShowContextMenu({ x: e.clientX, y: e.clientY });\n }, []);\n\n // Outside click\n useEffect(() => {\n if (!expanded && !showContextMenu) return;\n const handler = (e: MouseEvent) => {\n if ((e.target as HTMLElement).closest(\"[data-impakers-fab]\")) return;\n if (showContextMenu) { setShowContextMenu(null); return; }\n if (expanded) closeMenu();\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [expanded, showContextMenu, closeMenu]);\n\n return (\n <>\n {/* 메뉴 아이템 — FAB 위에 고정 위치 */}\n {(expanded || closing) && (\n <div\n className={styles.menuItems}\n style={{\n position: \"fixed\",\n right: position.right + (44 - 40) / 2, // 메뉴(40px)를 FAB(44px) 가운데 정렬\n bottom: position.bottom + 44 + 8, // FAB 위로 8px gap\n }}\n data-impakers-debug=\"\"\n data-impakers-fab=\"\"\n >\n {[...items].reverse().map((item, i) => (\n <button\n key={item.id}\n className={`${styles.menuItem} ${item.active ? styles.active : \"\"} ${closing ? styles.menuItemClosing : \"\"}`}\n style={{ animationDelay: closing ? `${i * 30}ms` : `${(items.length - 1 - i) * 40}ms` }}\n onClick={(e) => { e.stopPropagation(); onSelect(item.id); closeMenu(); }}\n type=\"button\"\n data-impakers-fab=\"\"\n data-impakers-debug=\"\"\n >\n {item.icon}\n <span className={styles.tooltip}>{item.label}</span>\n {item.badge && item.badge > 0 ? (\n <span className={styles.badge}>{item.badge > 99 ? \"99+\" : item.badge}</span>\n ) : null}\n </button>\n ))}\n </div>\n )}\n\n {/* Main FAB — 항상 같은 위치 */}\n <button\n ref={fabRef}\n className={`${styles.fab} ${expanded ? styles.expanded : \"\"}`}\n style={{ position: \"fixed\", right: position.right, bottom: position.bottom }}\n onPointerDown={handleFabPointerDown}\n onPointerMove={handleFabPointerMove}\n onPointerUp={handleFabPointerUp}\n onContextMenu={handleContextMenu}\n type=\"button\"\n aria-label=\"피드백 메뉴\"\n data-impakers-debug=\"\"\n data-impakers-fab=\"\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </button>\n\n {/* Context menu */}\n {showContextMenu && (\n <div\n style={{ position: \"fixed\", inset: 0, zIndex: 2147483647 }}\n onMouseDown={() => setShowContextMenu(null)}\n data-impakers-debug=\"\"\n data-impakers-fab=\"\"\n >\n <div\n className={styles.contextMenu}\n style={{ position: \"fixed\", left: showContextMenu.x, top: showContextMenu.y, zIndex: 2147483647 }}\n onMouseDown={(e) => e.stopPropagation()}\n data-impakers-fab=\"\"\n >\n <button\n className={styles.contextMenuItem}\n onMouseDown={(e) => { e.stopPropagation(); setShowContextMenu(null); onHide?.(); }}\n type=\"button\"\n >\n 위젯 숨기기\n </button>\n </div>\n </div>\n )}\n </>\n );\n}\n","\nconst css = \"@keyframes styles-module__fabEnter___DMJoo {\\n from {\\n opacity: 0;\\n transform: scale(0.5);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n@keyframes styles-module__menuItemIn___GfmJ3 {\\n from {\\n opacity: 0;\\n transform: scale(0.3);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n@keyframes styles-module__menuItemOut___s0nQD {\\n from {\\n opacity: 1;\\n transform: scale(1);\\n }\\n to {\\n opacity: 0;\\n transform: scale(0.3);\\n }\\n}\\n.styles-module__fab___wShP- {\\n touch-action: none;\\n z-index: 99999;\\n width: 44px;\\n height: 44px;\\n border-radius: 50%;\\n background: #18181b;\\n color: white;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1);\\n transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;\\n animation: styles-module__fabEnter___DMJoo 0.3s cubic-bezier(0.22, 1, 0.36, 1);\\n position: relative;\\n}\\n.styles-module__fab___wShP- svg {\\n width: 20px;\\n height: 20px;\\n transition: transform 0.2s ease;\\n}\\n.styles-module__fab___wShP-:hover {\\n transform: scale(1.08);\\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2), 0 2px 4px rgba(0, 0, 0, 0.12);\\n}\\n.styles-module__fab___wShP-:active {\\n transform: scale(0.96);\\n}\\n.styles-module__fab___wShP-.styles-module__expanded___qyto6 svg {\\n transform: rotate(45deg);\\n}\\n\\n.styles-module__menuItems___1qNsE {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 8px;\\n z-index: 99999;\\n}\\n\\n.styles-module__menuItem___pB75H {\\n width: 40px;\\n height: 40px;\\n border-radius: 50%;\\n background: #fff;\\n color: #374151;\\n border: 1px solid #e5e7eb;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);\\n transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease, border-color 0.12s ease;\\n position: relative;\\n}\\n.styles-module__menuItem___pB75H svg {\\n width: 18px;\\n height: 18px;\\n}\\n.styles-module__menuItem___pB75H:hover {\\n transform: scale(1.08);\\n background: #f9fafb;\\n border-color: #d1d5db;\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\\n}\\n.styles-module__menuItem___pB75H:active {\\n transform: scale(0.96);\\n}\\n.styles-module__menuItem___pB75H.styles-module__active___7ktmc {\\n background: #18181b;\\n color: #fff;\\n border-color: #18181b;\\n}\\n\\n.styles-module__menuItem___pB75H:nth-child(1) {\\n animation: styles-module__menuItemIn___GfmJ3 0.15s cubic-bezier(0.22, 1, 0.36, 1) 0ms both;\\n}\\n\\n.styles-module__menuItem___pB75H:nth-child(2) {\\n animation: styles-module__menuItemIn___GfmJ3 0.15s cubic-bezier(0.22, 1, 0.36, 1) 40ms both;\\n}\\n\\n.styles-module__menuItem___pB75H:nth-child(3) {\\n animation: styles-module__menuItemIn___GfmJ3 0.15s cubic-bezier(0.22, 1, 0.36, 1) 80ms both;\\n}\\n\\n.styles-module__menuItem___pB75H:nth-child(4) {\\n animation: styles-module__menuItemIn___GfmJ3 0.15s cubic-bezier(0.22, 1, 0.36, 1) 120ms both;\\n}\\n\\n.styles-module__menuItemClosing___m4o-a:nth-child(1) {\\n animation: styles-module__menuItemOut___s0nQD 0.1s ease-in 40ms both;\\n}\\n\\n.styles-module__menuItemClosing___m4o-a:nth-child(2) {\\n animation: styles-module__menuItemOut___s0nQD 0.1s ease-in 0ms both;\\n}\\n\\n.styles-module__tooltip___Cy6kg {\\n position: absolute;\\n right: calc(100% + 10px);\\n white-space: nowrap;\\n background: rgba(0, 0, 0, 0.85);\\n color: #fff;\\n font-size: 12px;\\n font-weight: 500;\\n padding: 5px 10px;\\n border-radius: 6px;\\n pointer-events: none;\\n opacity: 0;\\n transition: opacity 0.12s ease;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n}\\n\\n.styles-module__menuItem___pB75H:hover .styles-module__tooltip___Cy6kg {\\n opacity: 1;\\n}\\n\\n.styles-module__contextMenu___A8fQt {\\n background: white;\\n border-radius: 8px;\\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.16), 0 1px 4px rgba(0, 0, 0, 0.08);\\n padding: 4px;\\n min-width: 140px;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n animation: styles-module__menuItemIn___GfmJ3 0.1s ease-out;\\n}\\n\\n.styles-module__contextMenuItem___1u9io {\\n display: block;\\n width: 100%;\\n padding: 8px 12px;\\n border: none;\\n background: none;\\n font-size: 13px;\\n color: #18181b;\\n text-align: left;\\n cursor: pointer;\\n border-radius: 6px;\\n font-family: inherit;\\n}\\n.styles-module__contextMenuItem___1u9io:hover {\\n background: #f4f4f5;\\n}\\n\\n.styles-module__badge___zmiZx {\\n position: absolute;\\n top: -4px;\\n right: -4px;\\n min-width: 16px;\\n height: 16px;\\n border-radius: 8px;\\n background: #ef4444;\\n color: #fff;\\n font-size: 10px;\\n font-weight: 600;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 0 4px;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n}\";\nconst classNames = {\"fab\":\"styles-module__fab___wShP-\",\"fabEnter\":\"styles-module__fabEnter___DMJoo\",\"expanded\":\"styles-module__expanded___qyto6\",\"menuItems\":\"styles-module__menuItems___1qNsE\",\"menuItem\":\"styles-module__menuItem___pB75H\",\"active\":\"styles-module__active___7ktmc\",\"menuItemIn\":\"styles-module__menuItemIn___GfmJ3\",\"menuItemClosing\":\"styles-module__menuItemClosing___m4o-a\",\"menuItemOut\":\"styles-module__menuItemOut___s0nQD\",\"tooltip\":\"styles-module__tooltip___Cy6kg\",\"contextMenu\":\"styles-module__contextMenu___A8fQt\",\"contextMenuItem\":\"styles-module__contextMenuItem___1u9io\",\"badge\":\"styles-module__badge___zmiZx\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-fab-menu-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-fab-menu-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\"use client\";\n\nimport { useState, useCallback, useEffect, useRef, useMemo } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n fetchComments,\n postComment,\n getCachedSnapshot,\n subscribeCache,\n getCommentsCacheKey,\n type FeedbackComment,\n} from \"../../core/api\";\nimport styles from \"./styles.module.scss\";\n\n// 이미지 확대 모달\nfunction ImageLightbox({ src, onClose }: { src: string; onClose: () => void }) {\n useEffect(() => {\n const handler = (e: KeyboardEvent) => { if (e.key === \"Escape\") onClose(); };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [onClose]);\n\n return (\n <div className={styles.lightbox} onClick={onClose} data-impakers-debug=\"\">\n <img src={src} alt=\"enlarged\" onClick={(e) => e.stopPropagation()} />\n <button className={styles.lightboxClose} onClick={onClose} type=\"button\">&times;</button>\n </div>\n );\n}\n\n// =============================================================================\n// File preview helpers\n// =============================================================================\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nfunction getFileIcon(mimeType: string): string {\n if (mimeType.includes(\"pdf\")) return \"PDF\";\n if (mimeType.includes(\"spreadsheet\") || mimeType.includes(\"excel\") || mimeType.includes(\"csv\")) return \"XLS\";\n if (mimeType.includes(\"presentation\") || mimeType.includes(\"powerpoint\")) return \"PPT\";\n if (mimeType.includes(\"document\") || mimeType.includes(\"word\")) return \"DOC\";\n if (mimeType.includes(\"zip\") || mimeType.includes(\"compressed\") || mimeType.includes(\"archive\")) return \"ZIP\";\n if (mimeType.includes(\"video\")) return \"VID\";\n if (mimeType.includes(\"audio\")) return \"AUD\";\n return \"FILE\";\n}\n\n/** Google Drive URL에서 file ID 추출 */\nfunction extractDriveFileId(url: string): string | null {\n const match = url.match(/\\/d\\/([^/]+)/);\n return match ? match[1] : null;\n}\n\n/** 파일 타입에 따라 프리뷰 가능한 iframe src 반환 */\nfunction getPreviewSrc(fileUrl: string, fileType: string, fileSource?: string): string | null {\n // Office 파일 → Microsoft Office Online Viewer (공개 URL 필요)\n const isOffice = /\\.(pptx?|xlsx?|docx?)$/i.test(fileUrl) ||\n fileType.includes(\"presentation\") || fileType.includes(\"powerpoint\") ||\n fileType.includes(\"spreadsheet\") || fileType.includes(\"excel\") ||\n fileType.includes(\"document\") || fileType.includes(\"word\") || fileType.includes(\"msword\");\n\n if (fileSource === \"google_drive\") {\n const fileId = extractDriveFileId(fileUrl);\n if (fileId) return `https://drive.google.com/file/d/${fileId}/preview`;\n }\n\n if (isOffice && fileSource !== \"google_drive\") {\n return `https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(fileUrl)}`;\n }\n\n // PDF → 브라우저 내장\n if (fileType.includes(\"pdf\")) return fileUrl;\n\n return null;\n}\n\n// 파일 프리뷰 모달\nfunction FilePreviewModal({\n fileUrl, fileName, fileType, fileSource, onClose,\n}: {\n fileUrl: string; fileName: string; fileType: string; fileSource?: string; onClose: () => void;\n}) {\n useEffect(() => {\n const handler = (e: KeyboardEvent) => { if (e.key === \"Escape\") onClose(); };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [onClose]);\n\n const previewSrc = getPreviewSrc(fileUrl, fileType, fileSource);\n\n return (\n <div className={styles.filePreviewOverlay} onClick={onClose} data-impakers-debug=\"\">\n <div className={styles.filePreviewModal} onClick={(e) => e.stopPropagation()}>\n <div className={styles.filePreviewHeader}>\n <span className={styles.filePreviewName}>{fileName}</span>\n <div className={styles.filePreviewActions}>\n <a href={fileUrl} target=\"_blank\" rel=\"noopener noreferrer\" className={styles.filePreviewOpen}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"14\" height=\"14\">\n <path d=\"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n 열기\n </a>\n <button className={styles.filePreviewClose} onClick={onClose} type=\"button\">&times;</button>\n </div>\n </div>\n <div className={styles.filePreviewBody}>\n {previewSrc ? (\n <iframe src={previewSrc} className={styles.filePreviewIframe} title={fileName} />\n ) : (\n <div className={styles.filePreviewFallback}>\n <span className={styles.filePreviewFallbackIcon}>{getFileIcon(fileType)}</span>\n <span>미리보기를 지원하지 않는 파일 형식입니다</span>\n <a href={fileUrl} target=\"_blank\" rel=\"noopener noreferrer\">파일 열기</a>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface InboxItem {\n id: string;\n title: string;\n status: string;\n priority: string;\n authorName: string;\n feedbackUrl: string;\n createdAt: string;\n startedAt?: string | null;\n completedAt?: string | null;\n commentCount: number;\n screenshot?: string;\n}\n\nexport interface InboxPanelProps {\n pageItems: InboxItem[];\n allItems: InboxItem[];\n currentPath: string;\n serviceName?: string;\n endpoint: string;\n currentUserName: string;\n currentUserId?: string;\n onClose: () => void;\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nfunction formatTime(dateStr: string): string {\n const date = new Date(dateStr);\n const diff = Date.now() - date.getTime();\n const pad = (n: number) => String(n).padStart(2, \"0\");\n const abs = `${date.getMonth() + 1}/${date.getDate()} ${pad(date.getHours())}:${pad(date.getMinutes())}`;\n const m = Math.floor(diff / 60000);\n if (m < 1) return `${abs} (방금)`;\n if (m < 60) return `${abs} (${m}분 전)`;\n const h = Math.floor(m / 60);\n if (h < 24) return `${abs} (${h}시간 전)`;\n const d = Math.floor(h / 24);\n return `${abs} (${d}일 전)`;\n}\n\n/** 동적 세그먼트(숫자, UUID)를 무시하고 같은 라우트 패턴인지 비교 */\nfunction isSameRoutePattern(a: string, b: string): boolean {\n const normalize = (path: string) =>\n path.split(\"/\").map((seg) =>\n /^\\d+$/.test(seg) || /^[0-9a-f]{8}-[0-9a-f]{4}-/i.test(seg) ? \"*\" : seg\n ).join(\"/\");\n return normalize(a) === normalize(b);\n}\n\nfunction getInitials(name: string): string {\n return name.slice(0, 1).toUpperCase();\n}\n\n// =============================================================================\n// Component\n// =============================================================================\n\nexport function InboxPanel({\n pageItems,\n allItems,\n currentPath,\n serviceName,\n endpoint,\n currentUserName,\n currentUserId,\n onClose,\n}: InboxPanelProps) {\n const [tab, setTab] = useState<\"page\" | \"all\" | \"history\">(\"page\");\n const [statusFilter, setStatusFilter] = useState<\"todo\" | \"in_progress\" | \"done\">(\"todo\");\n const [historyDate, setHistoryDate] = useState<string>(\"\"); // YYYY-MM-DD or empty for all\n const [showDatePicker, setShowDatePicker] = useState(false);\n const datePickerRef = useRef<HTMLDivElement>(null);\n const [exiting, setExiting] = useState(false);\n const [selectedItem, setSelectedItem] = useState<InboxItem | null>(null);\n const [comments, setComments] = useState<FeedbackComment[]>([]);\n const [loadingComments, setLoadingComments] = useState(false);\n const [replyText, setReplyText] = useState(\"\");\n const [lightboxSrc, setLightboxSrc] = useState<string | null>(null);\n const [filePreview, setFilePreview] = useState<{ url: string; name: string; type: string; source?: string } | null>(null);\n const replyRef = useRef<HTMLTextAreaElement>(null);\n const commentsEndRef = useRef<HTMLDivElement>(null);\n\n const handleClose = useCallback(() => {\n if (selectedItem) {\n setSelectedItem(null);\n setComments([]);\n setReplyText(\"\");\n return;\n }\n setExiting(true);\n setTimeout(() => onClose(), 150);\n }, [onClose, selectedItem]);\n\n // 카드 클릭 → 항상 상세 뷰 (댓글 피드) 진입\n const handleItemClick = useCallback(async (item: InboxItem) => {\n\n setSelectedItem(item);\n const cached = getCachedSnapshot<FeedbackComment[]>(getCommentsCacheKey(item.id));\n setComments(cached || []);\n setLoadingComments(!cached);\n }, [endpoint]);\n\n useEffect(() => {\n if (!selectedItem) return;\n\n const cacheKey = getCommentsCacheKey(selectedItem.id);\n const cached = getCachedSnapshot<FeedbackComment[]>(cacheKey);\n if (cached) {\n setComments(cached);\n setLoadingComments(false);\n }\n\n const unsubscribe = subscribeCache<FeedbackComment[]>(cacheKey, (nextComments) => {\n setComments(nextComments);\n setLoadingComments(false);\n });\n\n fetchComments(endpoint, selectedItem.id, { staleWhileRevalidate: true })\n .then((data) => {\n setComments(data);\n setLoadingComments(false);\n })\n .catch(() => {\n setLoadingComments(false);\n });\n\n return unsubscribe;\n }, [selectedItem, endpoint]);\n\n // 댓글 로드 후 스크롤\n useEffect(() => {\n commentsEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [comments.length]);\n\n // 날짜 피커 바깥 클릭 닫기\n useEffect(() => {\n if (!showDatePicker) return;\n const handler = (e: MouseEvent) => {\n if (datePickerRef.current && !datePickerRef.current.contains(e.target as Node)) {\n setShowDatePicker(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [showDatePicker]);\n\n // 포커스\n useEffect(() => {\n if (selectedItem) replyRef.current?.focus();\n }, [selectedItem]);\n\n // 댓글 전송\n const handleSendReply = useCallback(async () => {\n if (!replyText.trim() || !selectedItem) return;\n const content = replyText.trim();\n setReplyText(\"\");\n\n try {\n await postComment(endpoint, selectedItem.id, content, currentUserName, currentUserId);\n } catch (err) {\n console.error(\"[@impakers/debug] 코멘트 전송 실패:\", err);\n }\n }, [replyText, selectedItem, endpoint, currentUserName, currentUserId]);\n\n const handleReplyKeyDown = useCallback((e: React.KeyboardEvent) => {\n e.stopPropagation();\n if (e.nativeEvent.isComposing) return;\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSendReply();\n }\n if (e.key === \"Escape\") handleClose();\n }, [handleSendReply, handleClose]);\n\n const rawItems = tab === \"page\" ? pageItems : tab === \"all\" ? allItems : [];\n const items = rawItems.filter((item) => item.status === statusFilter);\n const todoCount = rawItems.filter((item) => item.status === \"todo\").length;\n const inProgressCount = rawItems.filter((item) => item.status === \"in_progress\").length;\n const doneCount = rawItems.filter((item) => item.status === \"done\").length;\n\n // History: 상태 변경 이벤트를 시간순으로 (최신 먼저)\n const historyEvents = useMemo(() => {\n const allSrc = allItems.length > 0 ? allItems : pageItems;\n const events: { id: string; title: string; authorName: string; event: string; timestamp: string; feedbackUrl: string }[] = [];\n for (const item of allSrc) {\n events.push({\n id: item.id,\n title: item.title,\n authorName: item.authorName,\n event: \"created\",\n timestamp: item.createdAt,\n feedbackUrl: item.feedbackUrl,\n });\n if (item.startedAt) {\n events.push({\n id: item.id,\n title: item.title,\n authorName: item.authorName,\n event: \"started\",\n timestamp: item.startedAt,\n feedbackUrl: item.feedbackUrl,\n });\n }\n if (item.completedAt) {\n events.push({\n id: item.id,\n title: item.title,\n authorName: item.authorName,\n event: \"completed\",\n timestamp: item.completedAt,\n feedbackUrl: item.feedbackUrl,\n });\n }\n }\n const sorted = events.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());\n if (!historyDate) return sorted;\n return sorted.filter((ev) => ev.timestamp.startsWith(historyDate));\n }, [allItems, pageItems, historyDate]);\n\n if (typeof document === \"undefined\") return null;\n\n return createPortal(\n <div data-impakers-debug=\"\">\n <div className={styles.backdrop} onClick={handleClose} />\n\n <div className={`${styles.panel} ${exiting ? styles.exiting : \"\"}`} data-impakers-debug=\"\">\n {/* Header */}\n <div className={styles.header}>\n <div className={styles.headerLeft}>\n {selectedItem && (\n <button className={styles.backBtn} onClick={handleClose} type=\"button\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"16\" height=\"16\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n )}\n <span className={styles.headerTitle}>\n {selectedItem ? selectedItem.title.replace(/^\\[피드백\\]\\s*/, \"\") : (serviceName || \"Feedback\")}\n </span>\n </div>\n <button className={styles.closeBtn} onClick={() => { setExiting(true); setTimeout(() => onClose(), 150); }} type=\"button\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* === 상세 뷰 === */}\n {selectedItem ? (\n <div className={styles.detailView}>\n {/* 원본 피드백 */}\n <div className={styles.detailHeader}>\n <div className={styles.cardAvatar}>{getInitials(selectedItem.authorName)}</div>\n <div>\n <div className={styles.cardMeta}>\n <span className={styles.cardAuthor}>{selectedItem.authorName}</span>\n <span className={styles.cardTime}>{formatTime(selectedItem.createdAt)}</span>\n </div>\n <div className={styles.detailTitle}>\n {selectedItem.title.replace(/^\\[피드백\\]\\s*/, \"\")}\n </div>\n </div>\n </div>\n\n {selectedItem.screenshot && (\n <div className={styles.detailScreenshot}>\n <img src={selectedItem.screenshot} alt=\"screenshot\" />\n </div>\n )}\n\n {/* 댓글 목록 */}\n <div className={styles.commentsList}>\n {loadingComments && (\n <div className={styles.loadingComments}>댓글 로딩 중...</div>\n )}\n {!loadingComments && comments.length === 0 && (\n <div className={styles.noComments}>아직 댓글이 없습니다</div>\n )}\n {comments.map((c) => (\n <div key={c.id} className={styles.commentItem}>\n <div className={styles.commentAvatar} style={{ width: 22, height: 22, fontSize: 10 }}>\n {getInitials(c.authorName)}\n </div>\n <div className={styles.commentBody}>\n <div className={styles.commentMeta}>\n <span className={styles.commentAuthorName}>{c.authorName}</span>\n <span className={styles.commentTime}>{formatTime(c.createdAt)}</span>\n </div>\n {c.content && <div className={styles.commentContent}>{c.content}</div>}\n {c.imageUrl && (\n <div\n className={styles.commentImage}\n onClick={(e) => { e.stopPropagation(); setLightboxSrc(c.imageUrl!); }}\n >\n <img src={c.imageUrl} alt=\"attachment\" />\n </div>\n )}\n {c.fileUrl && (\n <div\n className={styles.commentFileCard}\n onClick={(e) => {\n e.stopPropagation();\n setFilePreview({\n url: c.fileUrl!,\n name: c.fileName || \"파일\",\n type: c.fileType || \"\",\n source: c.fileSource,\n });\n }}\n >\n <span className={styles.commentFileIcon}>{getFileIcon(c.fileType || \"\")}</span>\n <span className={styles.commentFileInfo}>\n <span className={styles.commentFileName}>{c.fileName || \"파일\"}</span>\n {c.fileSize != null && (\n <span className={styles.commentFileSize}>{formatFileSize(c.fileSize)}</span>\n )}\n </span>\n </div>\n )}\n </div>\n </div>\n ))}\n <div ref={commentsEndRef} />\n </div>\n\n {/* 댓글 입력 */}\n <div className={styles.replyBox}>\n <textarea\n ref={replyRef}\n className={styles.replyInput}\n placeholder=\"Reply...\"\n value={replyText}\n onChange={(e) => {\n setReplyText(e.target.value);\n const el = e.target;\n el.style.height = \"auto\";\n el.style.height = `${Math.min(el.scrollHeight, 120)}px`;\n }}\n onKeyDown={handleReplyKeyDown}\n rows={2}\n />\n <button\n className={`${styles.sendBtn} ${replyText.trim() ? styles.active : \"\"}`}\n onClick={handleSendReply}\n disabled={!replyText.trim()}\n type=\"button\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"16\" height=\"16\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" /><polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n </button>\n </div>\n </div>\n ) : (\n <>\n {/* === 리스트 뷰 === */}\n <div className={styles.tabs}>\n <button className={`${styles.tab} ${tab === \"page\" ? styles.active : \"\"}`} onClick={() => setTab(\"page\")} type=\"button\">\n This Page\n {pageItems.length > 0 && <span className={styles.tabBadge}>{pageItems.length}</span>}\n </button>\n <button className={`${styles.tab} ${tab === \"all\" ? styles.active : \"\"}`} onClick={() => setTab(\"all\")} type=\"button\">\n All\n {allItems.length > 0 && <span className={styles.tabBadge}>{allItems.length}</span>}\n </button>\n <button className={`${styles.tab} ${tab === \"history\" ? styles.active : \"\"}`} onClick={() => setTab(\"history\")} type=\"button\">\n History\n </button>\n </div>\n\n {tab === \"history\" ? (\n /* === History 뷰 === */\n <>\n <div className={styles.historyFilter}>\n <div className={styles.historyDateWrap} ref={datePickerRef}>\n <button\n className={`${styles.filterChip} ${historyDate ? styles.active : \"\"}`}\n onClick={() => setShowDatePicker((v) => !v)}\n type=\"button\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"13\" height=\"13\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\" />\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\" />\n <line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\" />\n </svg>\n {historyDate\n ? `${new Date(historyDate).getMonth() + 1}/${new Date(historyDate).getDate()}`\n : \"날짜\"}\n </button>\n {showDatePicker && (\n <div className={styles.datePopover}>\n <input\n type=\"date\"\n value={historyDate}\n onChange={(e) => {\n setHistoryDate(e.target.value);\n setShowDatePicker(false);\n }}\n className={styles.dateInput}\n autoFocus\n />\n </div>\n )}\n </div>\n {historyDate && (\n <button\n className={styles.filterChipClear}\n onClick={() => setHistoryDate(\"\")}\n type=\"button\"\n title=\"필터 초기화\"\n >\n &times;\n </button>\n )}\n </div>\n <div className={styles.content}>\n {historyEvents.length === 0 ? (\n <div className={styles.empty}>\n <div className={styles.emptyIcon}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <polyline points=\"12 6 12 12 16 14\" />\n </svg>\n </div>\n 히스토리가 없습니다\n </div>\n ) : (\n historyEvents.map((ev, i) => (\n <div key={`${ev.id}-${ev.event}-${i}`} className={styles.historyItem}>\n <div className={`${styles.historyDot} ${styles[`historyDot_${ev.event}`]}`} />\n <div className={styles.historyBody}>\n <div className={styles.historyMeta}>\n <span className={styles.historyEvent}>\n {ev.event === \"created\" && \"피드백 생성\"}\n {ev.event === \"started\" && \"진행 시작\"}\n {ev.event === \"completed\" && \"완료 처리\"}\n </span>\n <span className={styles.historyTime}>{formatTime(ev.timestamp)}</span>\n </div>\n <div className={styles.historyTitle}>{ev.title.replace(/^\\[피드백\\]\\s*/, \"\")}</div>\n {ev.feedbackUrl && (\n <div className={styles.historyUrl}>{ev.feedbackUrl}</div>\n )}\n </div>\n </div>\n ))\n )}\n </div>\n </>\n ) : (\n <>\n <div className={styles.statusFilter}>\n <button\n className={`${styles.filterChip} ${statusFilter === \"todo\" ? styles.active : \"\"}`}\n onClick={() => setStatusFilter(\"todo\")}\n type=\"button\"\n >\n 진행전\n {todoCount > 0 && <span className={styles.filterCount}>{todoCount}</span>}\n </button>\n <button\n className={`${styles.filterChip} ${statusFilter === \"in_progress\" ? styles.active : \"\"}`}\n onClick={() => setStatusFilter(\"in_progress\")}\n type=\"button\"\n >\n 진행중\n {inProgressCount > 0 && <span className={styles.filterCount}>{inProgressCount}</span>}\n </button>\n <button\n className={`${styles.filterChip} ${statusFilter === \"done\" ? styles.active : \"\"}`}\n onClick={() => setStatusFilter(\"done\")}\n type=\"button\"\n >\n 완료\n {doneCount > 0 && <span className={styles.filterCount}>{doneCount}</span>}\n </button>\n </div>\n\n <div className={styles.content}>\n {items.length === 0 ? (\n <div className={styles.empty}>\n <div className={styles.emptyIcon}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z\" />\n </svg>\n </div>\n {tab === \"page\" ? \"이 페이지에 피드백이 없습니다\" : \"피드백이 없습니다\"}\n </div>\n ) : (\n items.map((item) => (\n <div key={item.id} className={`${styles.card} ${item.status === \"done\" ? styles.cardDone : \"\"}`} onClick={() => handleItemClick(item)}>\n <div className={styles.cardHeader}>\n <div className={styles.cardAvatar}>{getInitials(item.authorName)}</div>\n <div className={styles.cardInfo}>\n <div className={styles.cardMeta}>\n <span className={styles.cardAuthor}>{item.authorName}</span>\n <span className={styles.cardTime}>{formatTime(item.createdAt)}</span>\n </div>\n </div>\n </div>\n\n <div className={styles.cardTitle}>{item.title.replace(/^\\[피드백\\]\\s*/, \"\")}</div>\n\n {item.screenshot && (\n <div className={styles.cardScreenshot}>\n <img src={item.screenshot} alt=\"screenshot\" />\n </div>\n )}\n\n {tab === \"all\" && item.feedbackUrl && (\n <div\n className={styles.cardRoute}\n onClick={(e) => {\n e.stopPropagation();\n window.location.href = item.feedbackUrl;\n }}\n title=\"페이지로 이동\"\n >\n <span className={styles.cardRoutePath}>{item.feedbackUrl}</span>\n <svg className={styles.cardRouteIcon} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"12\" height=\"12\">\n <path d=\"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n </div>\n )}\n\n {/* 상태별 시간 */}\n {(item.startedAt || item.completedAt) && (\n <div className={styles.cardStatusTime}>\n {item.startedAt && item.status !== \"todo\" && (\n <span>진행 시작: {formatTime(item.startedAt)}</span>\n )}\n {item.completedAt && item.status === \"done\" && (\n <span>완료: {formatTime(item.completedAt)}</span>\n )}\n </div>\n )}\n\n <div className={styles.cardFooter}>\n <span className={styles.cardReplyDot} />\n <span className={styles.cardReplyCount}>\n {item.commentCount} {item.commentCount === 1 ? \"Reply\" : \"Replies\"}\n </span>\n </div>\n </div>\n ))\n )}\n </div>\n </>\n )}\n </>\n )}\n </div>\n\n {/* 이미지 확대 모달 */}\n {lightboxSrc && (\n <ImageLightbox src={lightboxSrc} onClose={() => setLightboxSrc(null)} />\n )}\n\n {/* 파일 프리뷰 모달 */}\n {filePreview && (\n <FilePreviewModal\n fileUrl={filePreview.url}\n fileName={filePreview.name}\n fileType={filePreview.type}\n fileSource={filePreview.source}\n onClose={() => setFilePreview(null)}\n />\n )}\n </div>,\n document.body,\n );\n}\n","\nconst css = \"@keyframes styles-module__slideIn___0o0s- {\\n from {\\n transform: translateX(100%);\\n }\\n to {\\n transform: translateX(0);\\n }\\n}\\n@keyframes styles-module__slideOut___nKrBX {\\n from {\\n transform: translateX(0);\\n }\\n to {\\n transform: translateX(100%);\\n }\\n}\\n@keyframes styles-module__fadeIn___j09Ts {\\n from {\\n opacity: 0;\\n }\\n to {\\n opacity: 1;\\n }\\n}\\n.styles-module__backdrop___zYhcU {\\n position: fixed;\\n inset: 0;\\n z-index: 100003;\\n animation: styles-module__fadeIn___j09Ts 0.15s ease-out;\\n}\\n\\n.styles-module__panel___6YS8k {\\n position: fixed;\\n top: 0;\\n right: 0;\\n bottom: 0;\\n width: 420px;\\n max-width: 100vw;\\n background: #fafafa;\\n z-index: 100004;\\n display: flex;\\n flex-direction: column;\\n box-shadow: -4px 0 24px rgba(0, 0, 0, 0.08);\\n animation: styles-module__slideIn___0o0s- 0.2s ease-out;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n -webkit-font-smoothing: antialiased;\\n}\\n.styles-module__panel___6YS8k.styles-module__exiting___6A-Ag {\\n animation: styles-module__slideOut___nKrBX 0.15s ease-in forwards;\\n}\\n\\n.styles-module__header___fBbGz {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 16px 20px;\\n border-bottom: 1px solid #e5e7eb;\\n background: #fff;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__headerLeft___e0YLf {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n}\\n\\n.styles-module__headerTitle___oEPJa {\\n font-size: 14px;\\n font-weight: 600;\\n color: #18181b;\\n}\\n\\n.styles-module__closeBtn___-H8ra {\\n width: 32px;\\n height: 32px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #6b7280;\\n transition: background 0.12s, color 0.12s;\\n}\\n.styles-module__closeBtn___-H8ra:hover {\\n background: #f3f4f6;\\n color: #18181b;\\n}\\n.styles-module__closeBtn___-H8ra svg {\\n width: 18px;\\n height: 18px;\\n}\\n\\n.styles-module__tabs___nfuX7 {\\n display: flex;\\n padding: 0 20px;\\n gap: 0;\\n border-bottom: 1px solid #e5e7eb;\\n background: #fff;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__tab___Hc-jn {\\n padding: 10px 16px;\\n font-size: 13px;\\n font-weight: 500;\\n color: #6b7280;\\n border: none;\\n background: none;\\n cursor: pointer;\\n border-bottom: 2px solid transparent;\\n transition: color 0.12s, border-color 0.12s;\\n font-family: inherit;\\n}\\n.styles-module__tab___Hc-jn:hover {\\n color: #374151;\\n}\\n.styles-module__tab___Hc-jn.styles-module__active___ZQzA5 {\\n color: #18181b;\\n border-bottom-color: #18181b;\\n}\\n\\n.styles-module__tabBadge___IdFDQ {\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n min-width: 18px;\\n height: 18px;\\n border-radius: 9px;\\n background: #e5e7eb;\\n color: #374151;\\n font-size: 11px;\\n font-weight: 600;\\n padding: 0 5px;\\n margin-left: 6px;\\n}\\n\\n.styles-module__statusFilter___qtBXs {\\n display: flex;\\n gap: 6px;\\n padding: 10px 20px;\\n border-bottom: 1px solid #f3f4f6;\\n background: #fff;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__filterChip___l2s74 {\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n padding: 4px 10px;\\n font-size: 12px;\\n font-weight: 500;\\n color: #6b7280;\\n background: #f3f4f6;\\n border: 1px solid transparent;\\n border-radius: 16px;\\n cursor: pointer;\\n transition: all 0.12s;\\n font-family: inherit;\\n}\\n.styles-module__filterChip___l2s74:hover {\\n color: #374151;\\n background: #e5e7eb;\\n}\\n.styles-module__filterChip___l2s74.styles-module__active___ZQzA5 {\\n color: #18181b;\\n background: #fff;\\n border-color: #d1d5db;\\n}\\n\\n.styles-module__filterCount___KukiQ {\\n font-size: 11px;\\n font-weight: 600;\\n color: inherit;\\n opacity: 0.7;\\n}\\n\\n.styles-module__content___L2lRw {\\n flex: 1;\\n overflow-y: auto;\\n padding: 12px;\\n}\\n.styles-module__content___L2lRw::-webkit-scrollbar {\\n width: 4px;\\n}\\n.styles-module__content___L2lRw::-webkit-scrollbar-thumb {\\n background: #d1d5db;\\n border-radius: 2px;\\n}\\n\\n.styles-module__card___F8qwd {\\n background: #fff;\\n border-radius: 12px;\\n border: 1px solid #e5e7eb;\\n margin-bottom: 12px;\\n overflow: hidden;\\n transition: box-shadow 0.12s;\\n cursor: pointer;\\n}\\n.styles-module__card___F8qwd:hover {\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\\n}\\n\\n.styles-module__cardHeader___QOVGR {\\n padding: 14px 16px 8px;\\n display: flex;\\n align-items: flex-start;\\n gap: 10px;\\n}\\n\\n.styles-module__cardAvatar___FfKmW {\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n background: #16a34a;\\n color: #fff;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 11px;\\n font-weight: 600;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__cardInfo___BmrdF {\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__cardMeta___7p9KD {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n margin-bottom: 4px;\\n}\\n\\n.styles-module__cardAuthor___YvnuR {\\n font-size: 13px;\\n font-weight: 600;\\n color: #18181b;\\n}\\n\\n.styles-module__cardTime___N1Png {\\n font-size: 12px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__cardActions___7QF72 {\\n display: flex;\\n gap: 2px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__cardAction___t4b3V {\\n width: 26px;\\n height: 26px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 5px;\\n color: #9ca3af;\\n transition: background 0.12s, color 0.12s;\\n padding: 0;\\n}\\n.styles-module__cardAction___t4b3V:hover {\\n background: #f3f4f6;\\n color: #374151;\\n}\\n.styles-module__cardAction___t4b3V svg {\\n width: 14px;\\n height: 14px;\\n}\\n\\n.styles-module__cardTitle___xJxDN {\\n font-size: 13px;\\n color: #1a1a1a;\\n line-height: 1.5;\\n padding: 0 16px 8px;\\n}\\n\\n.styles-module__cardScreenshot___I5-QL {\\n margin: 0 16px 8px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n overflow: hidden;\\n position: relative;\\n max-height: 160px;\\n}\\n.styles-module__cardScreenshot___I5-QL img {\\n width: 100%;\\n height: auto;\\n display: block;\\n object-fit: cover;\\n}\\n\\n.styles-module__cardRoute___U4gB6 {\\n margin: 0 16px 10px;\\n padding: 8px 12px;\\n background: #f9fafb;\\n border: 1px solid #f3f4f6;\\n border-radius: 8px;\\n font-size: 12px;\\n color: #6b7280;\\n line-height: 1.4;\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n cursor: pointer;\\n transition: background 0.12s, border-color 0.12s;\\n}\\n.styles-module__cardRoute___U4gB6:hover {\\n background: #f3f4f6;\\n border-color: #d1d5db;\\n color: #3b82f6;\\n}\\n.styles-module__cardRoute___U4gB6:hover .styles-module__cardRoutePath___zP-fh {\\n color: #3b82f6;\\n}\\n.styles-module__cardRoute___U4gB6:hover .styles-module__cardRouteIcon___SBqGj {\\n color: #3b82f6;\\n}\\n\\n.styles-module__cardRouteName___BDH75 {\\n font-weight: 500;\\n color: #374151;\\n}\\n\\n.styles-module__cardRoutePath___zP-fh {\\n flex: 1;\\n min-width: 0;\\n color: #9ca3af;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n transition: color 0.12s;\\n}\\n\\n.styles-module__cardRouteIcon___SBqGj {\\n flex-shrink: 0;\\n color: #9ca3af;\\n transition: color 0.12s;\\n}\\n\\n.styles-module__cardStatusTime___S62W1 {\\n padding: 0 16px 6px;\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n}\\n.styles-module__cardStatusTime___S62W1 span {\\n font-size: 11px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__cardFooter___wfPa4 {\\n padding: 8px 16px 12px;\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n}\\n\\n.styles-module__cardReplyDot___YnqzI {\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: #16a34a;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__cardReplyCount___O1khL {\\n font-size: 12px;\\n font-weight: 500;\\n color: #374151;\\n}\\n\\n.styles-module__statusDot___l4IHG {\\n width: 6px;\\n height: 6px;\\n border-radius: 50%;\\n flex-shrink: 0;\\n}\\n.styles-module__statusDot___l4IHG.styles-module__todo___894P6 {\\n background: #f59e0b;\\n}\\n.styles-module__statusDot___l4IHG.styles-module__inProgress___IZ1mJ {\\n background: #3b82f6;\\n}\\n.styles-module__statusDot___l4IHG.styles-module__done___n4cWP {\\n background: #16a34a;\\n}\\n\\n.styles-module__empty___IADrw {\\n text-align: center;\\n padding: 48px 20px;\\n color: #9ca3af;\\n font-size: 13px;\\n line-height: 1.6;\\n}\\n\\n.styles-module__emptyIcon___1x5wT {\\n width: 48px;\\n height: 48px;\\n border-radius: 50%;\\n background: #f3f4f6;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n margin: 0 auto 12px;\\n color: #9ca3af;\\n}\\n.styles-module__emptyIcon___1x5wT svg {\\n width: 24px;\\n height: 24px;\\n}\\n\\n.styles-module__checkBtn___KjHxm {\\n width: 28px;\\n height: 28px;\\n border: 2px solid #d1d5db;\\n border-radius: 50%;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n color: transparent;\\n transition: all 0.15s;\\n padding: 0;\\n flex-shrink: 0;\\n}\\n.styles-module__checkBtn___KjHxm svg {\\n width: 14px;\\n height: 14px;\\n}\\n.styles-module__checkBtn___KjHxm:hover {\\n border-color: #16a34a;\\n color: #16a34a;\\n}\\n.styles-module__checkBtn___KjHxm.styles-module__checked___8pype {\\n border-color: #16a34a;\\n background: #16a34a;\\n color: #fff;\\n}\\n\\n.styles-module__cardDone___-m4w- {\\n opacity: 0.6;\\n}\\n.styles-module__cardDone___-m4w- .styles-module__cardTitle___xJxDN {\\n text-decoration: line-through;\\n color: #9ca3af;\\n}\\n\\n.styles-module__backBtn___PTIAl {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #6b7280;\\n transition: background 0.12s, color 0.12s;\\n padding: 0;\\n flex-shrink: 0;\\n}\\n.styles-module__backBtn___PTIAl:hover {\\n background: #f3f4f6;\\n color: #18181b;\\n}\\n\\n.styles-module__detailView___36cvH {\\n flex: 1;\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n}\\n\\n.styles-module__detailHeader___Hepgq {\\n display: flex;\\n gap: 10px;\\n padding: 16px 20px;\\n border-bottom: 1px solid #f3f4f6;\\n}\\n\\n.styles-module__detailTitle___7TvrX {\\n font-size: 13px;\\n color: #1a1a1a;\\n line-height: 1.5;\\n margin-top: 4px;\\n}\\n\\n.styles-module__detailScreenshot___UPF0f {\\n margin: 0 20px 0;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n overflow: hidden;\\n max-height: 180px;\\n}\\n.styles-module__detailScreenshot___UPF0f img {\\n width: 100%;\\n height: auto;\\n display: block;\\n object-fit: cover;\\n}\\n\\n.styles-module__commentsList___5Uigg {\\n flex: 1;\\n overflow-y: auto;\\n padding: 8px 0;\\n}\\n.styles-module__commentsList___5Uigg::-webkit-scrollbar {\\n width: 4px;\\n}\\n.styles-module__commentsList___5Uigg::-webkit-scrollbar-thumb {\\n background: #d1d5db;\\n border-radius: 2px;\\n}\\n\\n.styles-module__commentItem___5u78u {\\n display: flex;\\n gap: 10px;\\n padding: 10px 20px;\\n}\\n.styles-module__commentItem___5u78u:hover {\\n background: #f9fafb;\\n}\\n\\n.styles-module__commentAvatar___OatKg {\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n background: #16a34a;\\n color: #fff;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 11px;\\n font-weight: 600;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__commentBody___gmv1J {\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__commentMeta___JNJa3 {\\n display: flex;\\n gap: 6px;\\n align-items: center;\\n margin-bottom: 2px;\\n}\\n\\n.styles-module__commentAuthorName___XNVRk {\\n font-size: 13px;\\n font-weight: 600;\\n color: #1a1a1a;\\n}\\n\\n.styles-module__commentTime___CokGf {\\n font-size: 12px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__commentContent___yMiLR {\\n font-size: 13px;\\n color: #374151;\\n line-height: 1.5;\\n white-space: pre-wrap;\\n word-break: break-word;\\n}\\n\\n.styles-module__loadingComments___zpATD, .styles-module__noComments___kvl90 {\\n text-align: center;\\n padding: 24px 20px;\\n color: #9ca3af;\\n font-size: 13px;\\n}\\n\\n.styles-module__replyBox___FO-XS {\\n display: flex;\\n align-items: flex-end;\\n gap: 8px;\\n padding: 12px 20px;\\n border-top: 1px solid #f3f4f6;\\n background: #fff;\\n}\\n\\n.styles-module__replyInput___k8C9e {\\n flex: 1;\\n border: 1px solid #e5e7eb;\\n border-radius: 8px;\\n padding: 8px 12px;\\n font-size: 13px;\\n font-family: inherit;\\n color: #1a1a1a;\\n resize: none;\\n outline: none;\\n min-height: 20px;\\n max-height: 80px;\\n line-height: 1.5;\\n transition: border-color 0.12s;\\n}\\n.styles-module__replyInput___k8C9e:focus {\\n border-color: #18181b;\\n}\\n.styles-module__replyInput___k8C9e::placeholder {\\n color: #9ca3af;\\n}\\n\\n.styles-module__sendBtn___pBzWa {\\n width: 32px;\\n height: 32px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #d1d5db;\\n transition: color 0.12s;\\n padding: 0;\\n flex-shrink: 0;\\n}\\n.styles-module__sendBtn___pBzWa.styles-module__active___ZQzA5 {\\n color: #3b82f6;\\n}\\n.styles-module__sendBtn___pBzWa:hover {\\n color: #3b82f6;\\n}\\n\\n.styles-module__commentImage___LuH8X {\\n margin-top: 6px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n overflow: hidden;\\n max-width: 240px;\\n cursor: pointer;\\n transition: opacity 0.12s;\\n}\\n.styles-module__commentImage___LuH8X:hover {\\n opacity: 0.9;\\n}\\n.styles-module__commentImage___LuH8X img {\\n width: 100%;\\n height: auto;\\n display: block;\\n}\\n\\n.styles-module__commentFileCard___XE44y {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n margin-top: 6px;\\n padding: 8px 10px;\\n border-radius: 8px;\\n border: 1px solid #e5e7eb;\\n background: #f9fafb;\\n cursor: pointer;\\n transition: background 0.12s;\\n max-width: 240px;\\n}\\n.styles-module__commentFileCard___XE44y:hover {\\n background: #f3f4f6;\\n}\\n\\n.styles-module__commentFileIcon___G58-y {\\n width: 32px;\\n height: 32px;\\n border-radius: 6px;\\n background: #e5e7eb;\\n color: #374151;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 10px;\\n font-weight: 700;\\n flex-shrink: 0;\\n letter-spacing: 0.5px;\\n}\\n\\n.styles-module__commentFileInfo___OFIhR {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n}\\n\\n.styles-module__commentFileName___NUoII {\\n font-size: 12px;\\n font-weight: 500;\\n color: #1a1a1a;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__commentFileSize___sokU8 {\\n font-size: 11px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__filePreviewOverlay___5RxYd {\\n position: fixed;\\n inset: 0;\\n z-index: 2147483647;\\n background: rgba(0, 0, 0, 0.6);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n\\n.styles-module__filePreviewModal___MGJLW {\\n width: 90vw;\\n max-width: 960px;\\n height: 80vh;\\n background: #fff;\\n border-radius: 12px;\\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n}\\n\\n.styles-module__filePreviewHeader___E9SWJ {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 12px 16px;\\n border-bottom: 1px solid #e5e7eb;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__filePreviewName___z8t-L {\\n font-size: 14px;\\n font-weight: 600;\\n color: #18181b;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__filePreviewActions___weizo {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__filePreviewOpen___JpaEs {\\n display: flex;\\n align-items: center;\\n gap: 4px;\\n font-size: 12px;\\n font-weight: 500;\\n color: #3b82f6;\\n text-decoration: none;\\n padding: 4px 8px;\\n border-radius: 6px;\\n transition: background 0.12s;\\n}\\n.styles-module__filePreviewOpen___JpaEs:hover {\\n background: #eff6ff;\\n}\\n\\n.styles-module__filePreviewClose___TFcbr {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #6b7280;\\n font-size: 18px;\\n transition: background 0.12s, color 0.12s;\\n}\\n.styles-module__filePreviewClose___TFcbr:hover {\\n background: #f3f4f6;\\n color: #18181b;\\n}\\n\\n.styles-module__filePreviewBody___gwg1S {\\n flex: 1;\\n overflow: hidden;\\n}\\n\\n.styles-module__filePreviewIframe___OQ3Oo {\\n width: 100%;\\n height: 100%;\\n border: none;\\n}\\n\\n.styles-module__filePreviewFallback___U1rB2 {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n height: 100%;\\n gap: 12px;\\n color: #6b7280;\\n font-size: 14px;\\n}\\n.styles-module__filePreviewFallback___U1rB2 a {\\n color: #3b82f6;\\n text-decoration: none;\\n font-weight: 500;\\n}\\n.styles-module__filePreviewFallback___U1rB2 a:hover {\\n text-decoration: underline;\\n}\\n\\n.styles-module__filePreviewFallbackIcon___0--41 {\\n width: 56px;\\n height: 56px;\\n border-radius: 12px;\\n background: #f3f4f6;\\n color: #6b7280;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 16px;\\n font-weight: 700;\\n}\\n\\n.styles-module__lightbox___8CDdt {\\n position: fixed;\\n inset: 0;\\n z-index: 2147483647;\\n background: rgba(0, 0, 0, 0.8);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n cursor: zoom-out;\\n}\\n.styles-module__lightbox___8CDdt img {\\n max-width: 90vw;\\n max-height: 90vh;\\n border-radius: 8px;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\\n cursor: default;\\n}\\n\\n.styles-module__lightboxClose___VGfjh {\\n position: absolute;\\n top: 16px;\\n right: 16px;\\n width: 36px;\\n height: 36px;\\n border-radius: 50%;\\n background: rgba(255, 255, 255, 0.15);\\n color: #fff;\\n border: none;\\n cursor: pointer;\\n font-size: 20px;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.styles-module__lightboxClose___VGfjh:hover {\\n background: rgba(255, 255, 255, 0.25);\\n}\\n\\n.styles-module__historyFilter___IoWL4 {\\n display: flex;\\n align-items: center;\\n gap: 4px;\\n padding: 10px 20px;\\n border-bottom: 1px solid #f3f4f6;\\n background: #fff;\\n flex-shrink: 0;\\n}\\n\\n.styles-module__historyDateWrap___reBzb {\\n position: relative;\\n}\\n\\n.styles-module__filterChipClear___Sx4c3 {\\n width: 22px;\\n height: 22px;\\n border: none;\\n background: #e5e7eb;\\n border-radius: 50%;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 13px;\\n color: #6b7280;\\n line-height: 1;\\n transition: background 0.12s;\\n font-family: inherit;\\n}\\n.styles-module__filterChipClear___Sx4c3:hover {\\n background: #d1d5db;\\n}\\n\\n.styles-module__datePopover___AYzLr {\\n position: absolute;\\n top: calc(100% + 4px);\\n left: 0;\\n z-index: 10;\\n background: #fff;\\n border: 1px solid #e5e7eb;\\n border-radius: 10px;\\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\\n padding: 8px;\\n}\\n\\n.styles-module__dateInput___Ofr3Y {\\n border: 1px solid #e5e7eb;\\n border-radius: 6px;\\n padding: 6px 10px;\\n font-size: 13px;\\n font-family: inherit;\\n color: #1a1a1a;\\n outline: none;\\n cursor: pointer;\\n}\\n.styles-module__dateInput___Ofr3Y:focus {\\n border-color: #18181b;\\n}\\n\\n.styles-module__historyItem___G4kbt {\\n display: flex;\\n gap: 12px;\\n padding: 12px 20px;\\n position: relative;\\n transition: background 0.12s;\\n}\\n.styles-module__historyItem___G4kbt:hover {\\n background: #f9fafb;\\n}\\n.styles-module__historyItem___G4kbt:not(:last-child)::before {\\n content: \\\"\\\";\\n position: absolute;\\n left: 29px;\\n top: 24px;\\n bottom: -12px;\\n width: 1px;\\n background: #e5e7eb;\\n}\\n\\n.styles-module__historyDot___0z439 {\\n width: 10px;\\n height: 10px;\\n border-radius: 50%;\\n flex-shrink: 0;\\n margin-top: 4px;\\n background: #d1d5db;\\n}\\n\\n.styles-module__historyDot_created___G-qjM {\\n background: #6366f1;\\n}\\n\\n.styles-module__historyDot_started___0FJa0 {\\n background: #3b82f6;\\n}\\n\\n.styles-module__historyDot_completed___q-WGH {\\n background: #16a34a;\\n}\\n\\n.styles-module__historyBody___i-k1p {\\n flex: 1;\\n min-width: 0;\\n}\\n\\n.styles-module__historyMeta___khk0e {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n margin-bottom: 2px;\\n}\\n\\n.styles-module__historyEvent___P6rQ5 {\\n font-size: 12px;\\n font-weight: 600;\\n color: #374151;\\n}\\n\\n.styles-module__historyTime___bWpM4 {\\n font-size: 11px;\\n color: #9ca3af;\\n}\\n\\n.styles-module__historyTitle___gUvXd {\\n font-size: 13px;\\n color: #1a1a1a;\\n line-height: 1.4;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__historyUrl___5xfKq {\\n font-size: 11px;\\n color: #9ca3af;\\n margin-top: 2px;\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\";\nconst classNames = {\"backdrop\":\"styles-module__backdrop___zYhcU\",\"fadeIn\":\"styles-module__fadeIn___j09Ts\",\"panel\":\"styles-module__panel___6YS8k\",\"slideIn\":\"styles-module__slideIn___0o0s-\",\"exiting\":\"styles-module__exiting___6A-Ag\",\"slideOut\":\"styles-module__slideOut___nKrBX\",\"header\":\"styles-module__header___fBbGz\",\"headerLeft\":\"styles-module__headerLeft___e0YLf\",\"headerTitle\":\"styles-module__headerTitle___oEPJa\",\"closeBtn\":\"styles-module__closeBtn___-H8ra\",\"tabs\":\"styles-module__tabs___nfuX7\",\"tab\":\"styles-module__tab___Hc-jn\",\"active\":\"styles-module__active___ZQzA5\",\"tabBadge\":\"styles-module__tabBadge___IdFDQ\",\"statusFilter\":\"styles-module__statusFilter___qtBXs\",\"filterChip\":\"styles-module__filterChip___l2s74\",\"filterCount\":\"styles-module__filterCount___KukiQ\",\"content\":\"styles-module__content___L2lRw\",\"card\":\"styles-module__card___F8qwd\",\"cardHeader\":\"styles-module__cardHeader___QOVGR\",\"cardAvatar\":\"styles-module__cardAvatar___FfKmW\",\"cardInfo\":\"styles-module__cardInfo___BmrdF\",\"cardMeta\":\"styles-module__cardMeta___7p9KD\",\"cardAuthor\":\"styles-module__cardAuthor___YvnuR\",\"cardTime\":\"styles-module__cardTime___N1Png\",\"cardActions\":\"styles-module__cardActions___7QF72\",\"cardAction\":\"styles-module__cardAction___t4b3V\",\"cardTitle\":\"styles-module__cardTitle___xJxDN\",\"cardScreenshot\":\"styles-module__cardScreenshot___I5-QL\",\"cardRoute\":\"styles-module__cardRoute___U4gB6\",\"cardRoutePath\":\"styles-module__cardRoutePath___zP-fh\",\"cardRouteIcon\":\"styles-module__cardRouteIcon___SBqGj\",\"cardRouteName\":\"styles-module__cardRouteName___BDH75\",\"cardStatusTime\":\"styles-module__cardStatusTime___S62W1\",\"cardFooter\":\"styles-module__cardFooter___wfPa4\",\"cardReplyDot\":\"styles-module__cardReplyDot___YnqzI\",\"cardReplyCount\":\"styles-module__cardReplyCount___O1khL\",\"statusDot\":\"styles-module__statusDot___l4IHG\",\"todo\":\"styles-module__todo___894P6\",\"inProgress\":\"styles-module__inProgress___IZ1mJ\",\"done\":\"styles-module__done___n4cWP\",\"empty\":\"styles-module__empty___IADrw\",\"emptyIcon\":\"styles-module__emptyIcon___1x5wT\",\"checkBtn\":\"styles-module__checkBtn___KjHxm\",\"checked\":\"styles-module__checked___8pype\",\"cardDone\":\"styles-module__cardDone___-m4w-\",\"backBtn\":\"styles-module__backBtn___PTIAl\",\"detailView\":\"styles-module__detailView___36cvH\",\"detailHeader\":\"styles-module__detailHeader___Hepgq\",\"detailTitle\":\"styles-module__detailTitle___7TvrX\",\"detailScreenshot\":\"styles-module__detailScreenshot___UPF0f\",\"commentsList\":\"styles-module__commentsList___5Uigg\",\"commentItem\":\"styles-module__commentItem___5u78u\",\"commentAvatar\":\"styles-module__commentAvatar___OatKg\",\"commentBody\":\"styles-module__commentBody___gmv1J\",\"commentMeta\":\"styles-module__commentMeta___JNJa3\",\"commentAuthorName\":\"styles-module__commentAuthorName___XNVRk\",\"commentTime\":\"styles-module__commentTime___CokGf\",\"commentContent\":\"styles-module__commentContent___yMiLR\",\"loadingComments\":\"styles-module__loadingComments___zpATD\",\"noComments\":\"styles-module__noComments___kvl90\",\"replyBox\":\"styles-module__replyBox___FO-XS\",\"replyInput\":\"styles-module__replyInput___k8C9e\",\"sendBtn\":\"styles-module__sendBtn___pBzWa\",\"commentImage\":\"styles-module__commentImage___LuH8X\",\"commentFileCard\":\"styles-module__commentFileCard___XE44y\",\"commentFileIcon\":\"styles-module__commentFileIcon___G58-y\",\"commentFileInfo\":\"styles-module__commentFileInfo___OFIhR\",\"commentFileName\":\"styles-module__commentFileName___NUoII\",\"commentFileSize\":\"styles-module__commentFileSize___sokU8\",\"filePreviewOverlay\":\"styles-module__filePreviewOverlay___5RxYd\",\"filePreviewModal\":\"styles-module__filePreviewModal___MGJLW\",\"filePreviewHeader\":\"styles-module__filePreviewHeader___E9SWJ\",\"filePreviewName\":\"styles-module__filePreviewName___z8t-L\",\"filePreviewActions\":\"styles-module__filePreviewActions___weizo\",\"filePreviewOpen\":\"styles-module__filePreviewOpen___JpaEs\",\"filePreviewClose\":\"styles-module__filePreviewClose___TFcbr\",\"filePreviewBody\":\"styles-module__filePreviewBody___gwg1S\",\"filePreviewIframe\":\"styles-module__filePreviewIframe___OQ3Oo\",\"filePreviewFallback\":\"styles-module__filePreviewFallback___U1rB2\",\"filePreviewFallbackIcon\":\"styles-module__filePreviewFallbackIcon___0--41\",\"lightbox\":\"styles-module__lightbox___8CDdt\",\"lightboxClose\":\"styles-module__lightboxClose___VGfjh\",\"historyFilter\":\"styles-module__historyFilter___IoWL4\",\"historyDateWrap\":\"styles-module__historyDateWrap___reBzb\",\"filterChipClear\":\"styles-module__filterChipClear___Sx4c3\",\"datePopover\":\"styles-module__datePopover___AYzLr\",\"dateInput\":\"styles-module__dateInput___Ofr3Y\",\"historyItem\":\"styles-module__historyItem___G4kbt\",\"historyDot\":\"styles-module__historyDot___0z439\",\"historyDot_created\":\"styles-module__historyDot_created___G-qjM\",\"historyDot_started\":\"styles-module__historyDot_started___0FJa0\",\"historyDot_completed\":\"styles-module__historyDot_completed___q-WGH\",\"historyBody\":\"styles-module__historyBody___i-k1p\",\"historyMeta\":\"styles-module__historyMeta___khk0e\",\"historyEvent\":\"styles-module__historyEvent___P6rQ5\",\"historyTime\":\"styles-module__historyTime___bWpM4\",\"historyTitle\":\"styles-module__historyTitle___gUvXd\",\"historyUrl\":\"styles-module__historyUrl___5xfKq\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-inbox-panel-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-inbox-panel-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type { DebugSettings } from \"../../core/settings\";\nimport { MARKER_COLORS } from \"../../core/settings\";\nimport styles from \"./styles.module.scss\";\n\nexport interface SettingsPanelProps {\n settings: DebugSettings;\n onChange: (settings: DebugSettings) => void;\n onClose: () => void;\n}\n\nexport function SettingsPanel({ settings, onChange, onClose }: SettingsPanelProps) {\n const handleToggleMarkers = useCallback(() => {\n onChange({ ...settings, markersVisible: !settings.markersVisible });\n }, [settings, onChange]);\n\n const handleToggleHideDone = useCallback(() => {\n onChange({ ...settings, hideDoneMarkers: !settings.hideDoneMarkers });\n }, [settings, onChange]);\n\n const handleToggleShowOnlyMine = useCallback(() => {\n onChange({ ...settings, showOnlyMine: !settings.showOnlyMine });\n }, [settings, onChange]);\n\n const handleColorChange = useCallback((color: string) => {\n onChange({ ...settings, markerColor: color });\n }, [settings, onChange]);\n\n if (typeof document === \"undefined\") return null;\n\n return createPortal(\n <div data-impakers-debug=\"\">\n <div className={styles.backdrop} onClick={onClose} />\n <div className={styles.panel} data-impakers-debug=\"\">\n <div className={styles.header}>\n <span className={styles.title}>설정</span>\n <button className={styles.closeBtn} onClick={onClose} type=\"button\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className={styles.body}>\n {/* 마커 표시 토글 */}\n <div className={styles.field}>\n <div className={styles.fieldLabel}>마커 표시</div>\n <button\n className={`${styles.toggle} ${settings.markersVisible ? styles.on : \"\"}`}\n onClick={handleToggleMarkers}\n type=\"button\"\n >\n <span className={styles.toggleThumb} />\n </button>\n </div>\n\n {/* 완료 핀 숨기기 */}\n <div className={styles.field}>\n <div className={styles.fieldLabel}>완료 핀 숨기기</div>\n <button\n className={`${styles.toggle} ${settings.hideDoneMarkers ? styles.on : \"\"}`}\n onClick={handleToggleHideDone}\n type=\"button\"\n >\n <span className={styles.toggleThumb} />\n </button>\n </div>\n\n {/* 내가 추가한 것만 보기 */}\n <div className={styles.field}>\n <div className={styles.fieldLabel}>내가 추가한 것만</div>\n <button\n className={`${styles.toggle} ${settings.showOnlyMine ? styles.on : \"\"}`}\n onClick={handleToggleShowOnlyMine}\n type=\"button\"\n >\n <span className={styles.toggleThumb} />\n </button>\n </div>\n\n {/* 마커 색상 */}\n <div className={styles.field}>\n <div className={styles.fieldLabel}>마커 색상</div>\n <div className={styles.colors}>\n {MARKER_COLORS.map((c) => (\n <button\n key={c.id}\n className={`${styles.colorBtn} ${settings.markerColor === c.value ? styles.selected : \"\"}`}\n style={{ background: c.value }}\n onClick={() => handleColorChange(c.value)}\n title={c.label}\n type=\"button\"\n />\n ))}\n </div>\n </div>\n </div>\n </div>\n </div>,\n document.body,\n );\n}\n","// =============================================================================\n// @impakers/debug — Widget Settings (localStorage)\n// =============================================================================\n\nconst SETTINGS_KEY = \"impakers-debug-settings\";\n\nexport interface DebugSettings {\n markerColor: string;\n markersVisible: boolean;\n hideDoneMarkers: boolean;\n showOnlyMine: boolean;\n}\n\nconst DEFAULTS: DebugSettings = {\n markerColor: \"#6366f1\",\n markersVisible: true,\n hideDoneMarkers: false,\n showOnlyMine: false,\n};\n\nexport function loadSettings(): DebugSettings {\n try {\n const stored = localStorage.getItem(SETTINGS_KEY);\n if (!stored) return { ...DEFAULTS };\n return { ...DEFAULTS, ...JSON.parse(stored) };\n } catch {\n return { ...DEFAULTS };\n }\n}\n\nexport function saveSettings(settings: DebugSettings): void {\n try {\n localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));\n } catch {\n // ignore\n }\n}\n\nexport const MARKER_COLORS = [\n { id: \"indigo\", label: \"인디고\", value: \"#6366f1\" },\n { id: \"blue\", label: \"블루\", value: \"#3b82f6\" },\n { id: \"red\", label: \"레드\", value: \"#ef4444\" },\n { id: \"green\", label: \"그린\", value: \"#16a34a\" },\n { id: \"orange\", label: \"오렌지\", value: \"#f97316\" },\n { id: \"pink\", label: \"핑크\", value: \"#ec4899\" },\n];\n","\nconst css = \"@keyframes styles-module__panelIn___SmRh6 {\\n from {\\n opacity: 0;\\n transform: translateY(8px) scale(0.96);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0) scale(1);\\n }\\n}\\n.styles-module__backdrop___--cMp {\\n position: fixed;\\n inset: 0;\\n z-index: 100005;\\n}\\n\\n.styles-module__panel___z6xiJ {\\n position: fixed;\\n bottom: 80px;\\n right: 24px;\\n width: 280px;\\n background: #fff;\\n border-radius: 12px;\\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);\\n z-index: 100006;\\n overflow: hidden;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n animation: styles-module__panelIn___SmRh6 0.15s ease-out;\\n -webkit-font-smoothing: antialiased;\\n}\\n\\n.styles-module__header___NkOur {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 14px 16px;\\n border-bottom: 1px solid #f3f4f6;\\n}\\n\\n.styles-module__title___tsKZw {\\n font-size: 14px;\\n font-weight: 600;\\n color: #18181b;\\n}\\n\\n.styles-module__closeBtn___-OQ4Y {\\n width: 28px;\\n height: 28px;\\n border: none;\\n background: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n border-radius: 6px;\\n color: #6b7280;\\n}\\n.styles-module__closeBtn___-OQ4Y:hover {\\n background: #f3f4f6;\\n color: #18181b;\\n}\\n\\n.styles-module__body___9pyCP {\\n padding: 12px 16px 16px;\\n}\\n\\n.styles-module__field___vnQMl {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 8px 0;\\n}\\n\\n.styles-module__fieldLabel___2WUKB {\\n font-size: 13px;\\n font-weight: 500;\\n color: #374151;\\n}\\n\\n.styles-module__toggle___uWsqC {\\n width: 40px;\\n height: 22px;\\n border-radius: 11px;\\n background: #d1d5db;\\n border: none;\\n cursor: pointer;\\n position: relative;\\n transition: background 0.2s;\\n padding: 0;\\n}\\n.styles-module__toggle___uWsqC.styles-module__on___W27kf {\\n background: #18181b;\\n}\\n\\n.styles-module__toggleThumb___wyckC {\\n position: absolute;\\n top: 2px;\\n left: 2px;\\n width: 18px;\\n height: 18px;\\n border-radius: 50%;\\n background: #fff;\\n transition: transform 0.2s;\\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);\\n}\\n.styles-module__on___W27kf .styles-module__toggleThumb___wyckC {\\n transform: translateX(18px);\\n}\\n\\n.styles-module__colors___vgFGZ {\\n display: flex;\\n gap: 6px;\\n}\\n\\n.styles-module__colorBtn___N7dGu {\\n width: 24px;\\n height: 24px;\\n border-radius: 50%;\\n border: 2px solid transparent;\\n cursor: pointer;\\n transition: transform 0.12s, border-color 0.12s;\\n padding: 0;\\n}\\n.styles-module__colorBtn___N7dGu:hover {\\n transform: scale(1.15);\\n}\\n.styles-module__colorBtn___N7dGu.styles-module__selected___0tVDH {\\n border-color: #18181b;\\n transform: scale(1.15);\\n}\";\nconst classNames = {\"backdrop\":\"styles-module__backdrop___--cMp\",\"panel\":\"styles-module__panel___z6xiJ\",\"panelIn\":\"styles-module__panelIn___SmRh6\",\"header\":\"styles-module__header___NkOur\",\"title\":\"styles-module__title___tsKZw\",\"closeBtn\":\"styles-module__closeBtn___-OQ4Y\",\"body\":\"styles-module__body___9pyCP\",\"field\":\"styles-module__field___vnQMl\",\"fieldLabel\":\"styles-module__fieldLabel___2WUKB\",\"toggle\":\"styles-module__toggle___uWsqC\",\"on\":\"styles-module__on___W27kf\",\"toggleThumb\":\"styles-module__toggleThumb___wyckC\",\"colors\":\"styles-module__colors___vgFGZ\",\"colorBtn\":\"styles-module__colorBtn___N7dGu\",\"selected\":\"styles-module__selected___0tVDH\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-settings-panel-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-settings-panel-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\nconst css = \".styles-module__markersLayer___VR1cD svg[fill=none],\\n.styles-module__fixedMarkersLayer___wBuxm svg[fill=none] {\\n fill: none !important;\\n}\\n.styles-module__markersLayer___VR1cD svg[fill=none] :not([fill]),\\n.styles-module__fixedMarkersLayer___wBuxm svg[fill=none] :not([fill]) {\\n fill: none !important;\\n}\\n\\n@keyframes styles-module__fadeIn___PpRqy {\\n from {\\n opacity: 0;\\n }\\n to {\\n opacity: 1;\\n }\\n}\\n@keyframes styles-module__fadeOut___tZb9S {\\n from {\\n opacity: 1;\\n }\\n to {\\n opacity: 0;\\n }\\n}\\n@keyframes styles-module__hoverHighlightIn___ljC4F {\\n from {\\n opacity: 0;\\n transform: scale(0.98);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n@keyframes styles-module__hoverTooltipIn___tncNM {\\n from {\\n opacity: 0;\\n transform: translateY(4px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n@keyframes styles-module__fabEnter___9koyT {\\n from {\\n opacity: 0;\\n transform: scale(0.5);\\n }\\n to {\\n opacity: 1;\\n transform: scale(1);\\n }\\n}\\n.styles-module__fab___6FrCF {\\n position: fixed;\\n bottom: 24px;\\n right: 24px;\\n width: 44px;\\n height: 44px;\\n border-radius: 50%;\\n background: #18181b;\\n color: white;\\n border: none;\\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1);\\n transition: transform 0.15s ease, box-shadow 0.15s ease;\\n z-index: 99999;\\n animation: styles-module__fabEnter___9koyT 0.3s cubic-bezier(0.22, 1, 0.36, 1);\\n touch-action: none;\\n}\\n.styles-module__fab___6FrCF svg {\\n width: 20px;\\n height: 20px;\\n}\\n.styles-module__fab___6FrCF:hover {\\n transform: scale(1.08);\\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2), 0 2px 4px rgba(0, 0, 0, 0.12);\\n}\\n.styles-module__fab___6FrCF:active {\\n transform: scale(0.96);\\n}\\n.styles-module__fab___6FrCF.styles-module__active___X5PRD {\\n background: #dc2626;\\n}\\n\\n.styles-module__hoverHighlight___9kGLL {\\n position: fixed;\\n border: 2px solid rgba(0, 136, 255, 0.5);\\n border-radius: 4px;\\n background-color: rgba(0, 136, 255, 0.04);\\n pointer-events: none !important;\\n box-sizing: border-box;\\n will-change: opacity;\\n z-index: 99997;\\n}\\n.styles-module__hoverHighlight___9kGLL.styles-module__enter___jAi-c {\\n animation: styles-module__hoverHighlightIn___ljC4F 0.12s ease-out forwards;\\n}\\n\\n.styles-module__singleSelectOutline___2meUm {\\n position: fixed;\\n border: 2px solid rgba(0, 136, 255, 0.6);\\n border-radius: 4px;\\n pointer-events: none !important;\\n background-color: rgba(0, 136, 255, 0.05);\\n box-sizing: border-box;\\n will-change: opacity;\\n z-index: 99997;\\n}\\n.styles-module__singleSelectOutline___2meUm.styles-module__enter___jAi-c {\\n animation: styles-module__fadeIn___PpRqy 0.15s ease-out forwards;\\n}\\n\\n.styles-module__hoverTooltip___JE1Bs {\\n position: fixed;\\n font-size: 0.6875rem;\\n font-weight: 500;\\n color: #fff;\\n background: rgba(0, 0, 0, 0.85);\\n padding: 0.35rem 0.6rem;\\n border-radius: 0.375rem;\\n pointer-events: none !important;\\n white-space: nowrap;\\n max-width: 280px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n z-index: 99999;\\n}\\n.styles-module__hoverTooltip___JE1Bs.styles-module__enter___jAi-c {\\n animation: styles-module__hoverTooltipIn___tncNM 0.1s ease-out forwards;\\n}\\n\\n.styles-module__hoverReactPath___wPGYi {\\n font-size: 0.625rem;\\n color: rgba(255, 255, 255, 0.6);\\n margin-bottom: 0.15rem;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__hoverElementName___lNqTP {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.styles-module__markersLayer___VR1cD {\\n position: absolute;\\n top: 0;\\n left: 0;\\n right: 0;\\n height: 0;\\n z-index: 99998;\\n pointer-events: none;\\n}\\n.styles-module__markersLayer___VR1cD > * {\\n pointer-events: auto;\\n}\\n\\n.styles-module__fixedMarkersLayer___wBuxm {\\n position: fixed;\\n top: 0;\\n left: 0;\\n right: 0;\\n bottom: 0;\\n z-index: 99998;\\n pointer-events: none;\\n}\\n.styles-module__fixedMarkersLayer___wBuxm > * {\\n pointer-events: auto;\\n}\\n\\n.styles-module__contextMenu___nDXft {\\n position: fixed;\\n z-index: 2147483647;\\n background: white;\\n border-radius: 8px;\\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.16), 0 1px 4px rgba(0, 0, 0, 0.08);\\n padding: 4px;\\n min-width: 140px;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n animation: styles-module__fadeIn___PpRqy 0.1s ease-out;\\n}\\n\\n.styles-module__contextMenuItem___69GKu {\\n display: block;\\n width: 100%;\\n padding: 8px 12px;\\n border: none;\\n background: none;\\n font-size: 13px;\\n color: #18181b;\\n text-align: left;\\n cursor: pointer;\\n border-radius: 6px;\\n font-family: inherit;\\n}\\n.styles-module__contextMenuItem___69GKu:hover {\\n background: #f4f4f5;\\n}\\n\\n@keyframes styles-module__toastIn___V382h {\\n from {\\n opacity: 0;\\n transform: translateY(8px);\\n }\\n to {\\n opacity: 1;\\n transform: translateY(0);\\n }\\n}\\n@keyframes styles-module__toastOut___zlqxG {\\n from {\\n opacity: 1;\\n }\\n to {\\n opacity: 0;\\n }\\n}\\n.styles-module__toast___gV3Sa {\\n position: fixed;\\n bottom: 80px;\\n right: 24px;\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n background: white;\\n border: 1px solid #e5e5e5;\\n border-radius: 8px;\\n padding: 10px 16px;\\n font-size: 13px;\\n font-weight: 500;\\n color: #18181b;\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\\n z-index: 100000;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n animation: styles-module__toastIn___V382h 0.2s ease-out, styles-module__toastOut___zlqxG 0.3s ease-in 2.7s forwards;\\n max-width: 320px;\\n overflow: hidden;\\n white-space: nowrap;\\n text-overflow: ellipsis;\\n}\\n.styles-module__toast___gV3Sa span {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n.styles-module__toast___gV3Sa.styles-module__toastError___Q-8dn {\\n border-color: #fecaca;\\n background: #fef2f2;\\n color: #991b1b;\\n animation: styles-module__toastIn___V382h 0.2s ease-out, styles-module__toastOut___zlqxG 0.3s ease-in 3.7s forwards;\\n}\\n\\n@keyframes styles-module__countdownPulse___ngZrL {\\n 0%, 100% {\\n transform: scale(1);\\n }\\n 50% {\\n transform: scale(1.15);\\n }\\n}\\n.styles-module__countdownOverlay___GruQJ {\\n position: fixed;\\n top: 50%;\\n left: 50%;\\n transform: translate(-50%, -50%);\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 8px;\\n z-index: 100002;\\n pointer-events: auto;\\n font-family: -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, \\\"Helvetica Neue\\\", Arial, sans-serif;\\n animation: styles-module__fadeIn___PpRqy 0.2s ease-out;\\n}\\n\\n.styles-module__countdownNumber___VAmkI {\\n width: 72px;\\n height: 72px;\\n border-radius: 50%;\\n background: rgba(24, 24, 27, 0.9);\\n color: #fff;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 28px;\\n font-weight: 700;\\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\\n animation: styles-module__countdownPulse___ngZrL 1s ease-in-out infinite;\\n}\\n\\n.styles-module__countdownLabel___px-ao {\\n font-size: 13px;\\n font-weight: 500;\\n color: #18181b;\\n background: rgba(255, 255, 255, 0.95);\\n padding: 6px 14px;\\n border-radius: 8px;\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\\n}\\n\\n.styles-module__countdownCancel___8cRgZ {\\n font-size: 12px;\\n color: #6b7280;\\n background: rgba(255, 255, 255, 0.9);\\n border: 1px solid #d1d5db;\\n border-radius: 6px;\\n padding: 4px 12px;\\n cursor: pointer;\\n font-family: inherit;\\n transition: background 0.12s;\\n}\\n.styles-module__countdownCancel___8cRgZ:hover {\\n background: #f3f4f6;\\n}\\n\\nhtml.impakers-selecting {\\n cursor: crosshair !important;\\n}\\nhtml.impakers-selecting * {\\n cursor: crosshair !important;\\n}\";\nconst classNames = {\"markersLayer\":\"styles-module__markersLayer___VR1cD\",\"fixedMarkersLayer\":\"styles-module__fixedMarkersLayer___wBuxm\",\"fab\":\"styles-module__fab___6FrCF\",\"fabEnter\":\"styles-module__fabEnter___9koyT\",\"active\":\"styles-module__active___X5PRD\",\"hoverHighlight\":\"styles-module__hoverHighlight___9kGLL\",\"enter\":\"styles-module__enter___jAi-c\",\"hoverHighlightIn\":\"styles-module__hoverHighlightIn___ljC4F\",\"singleSelectOutline\":\"styles-module__singleSelectOutline___2meUm\",\"fadeIn\":\"styles-module__fadeIn___PpRqy\",\"hoverTooltip\":\"styles-module__hoverTooltip___JE1Bs\",\"hoverTooltipIn\":\"styles-module__hoverTooltipIn___tncNM\",\"hoverReactPath\":\"styles-module__hoverReactPath___wPGYi\",\"hoverElementName\":\"styles-module__hoverElementName___lNqTP\",\"contextMenu\":\"styles-module__contextMenu___nDXft\",\"contextMenuItem\":\"styles-module__contextMenuItem___69GKu\",\"toast\":\"styles-module__toast___gV3Sa\",\"toastIn\":\"styles-module__toastIn___V382h\",\"toastOut\":\"styles-module__toastOut___zlqxG\",\"toastError\":\"styles-module__toastError___Q-8dn\",\"countdownOverlay\":\"styles-module__countdownOverlay___GruQJ\",\"countdownNumber\":\"styles-module__countdownNumber___VAmkI\",\"countdownPulse\":\"styles-module__countdownPulse___ngZrL\",\"countdownLabel\":\"styles-module__countdownLabel___px-ao\",\"countdownCancel\":\"styles-module__countdownCancel___8cRgZ\",\"fadeOut\":\"styles-module__fadeOut___tZb9S\"};\n\nif (typeof document !== 'undefined') {\n let style = document.getElementById('impakers-debug-styles-debug-widget-styles');\n if (!style) {\n style = document.createElement('style');\n style.id = 'impakers-debug-styles-debug-widget-styles';\n document.head.appendChild(style);\n }\n style.textContent = css;\n}\n\nexport default classNames;\n","\"use client\";\n\nimport React, { useState, useCallback } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { authenticate } from \"../core/auth\";\n\ninterface AuthPromptPortalProps {\n endpoint: string;\n onSuccess: (serviceName: string) => void;\n onClose: () => void;\n}\n\nexport function AuthPromptPortal({ endpoint, onSuccess, onClose }: AuthPromptPortalProps) {\n const [code, setCode] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n if (!code.trim() || loading) return;\n\n setLoading(true);\n setError(null);\n\n try {\n const result = await authenticate(endpoint, code.trim().toUpperCase());\n onSuccess(result.serviceName);\n } catch (err) {\n setError(err instanceof Error ? err.message : \"인증 실패\");\n } finally {\n setLoading(false);\n }\n },\n [code, endpoint, loading, onSuccess],\n );\n\n if (typeof document === \"undefined\") return null;\n\n return createPortal(\n <div data-impakers-debug=\"\" style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontFamily: \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif\",\n }}>\n {/* Backdrop */}\n <div\n onClick={onClose}\n style={{\n position: \"absolute\",\n inset: 0,\n background: \"rgba(0, 0, 0, 0.4)\",\n }}\n />\n\n {/* Modal */}\n <div style={{\n position: \"relative\",\n width: 360,\n background: \"white\",\n borderRadius: 12,\n boxShadow: \"0 16px 48px rgba(0,0,0,0.16)\",\n overflow: \"hidden\",\n }}>\n {/* Header */}\n <div style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: \"16px 20px\",\n borderBottom: \"1px solid #e5e5e5\",\n }}>\n <h3 style={{ fontSize: 15, fontWeight: 600, color: \"#18181b\", margin: 0 }}>\n 피드백 위젯 인증\n </h3>\n <button\n onClick={onClose}\n type=\"button\"\n style={{\n width: 28, height: 28, border: \"none\", background: \"none\",\n cursor: \"pointer\", display: \"flex\", alignItems: \"center\",\n justifyContent: \"center\", borderRadius: 6, color: \"#71717a\",\n }}\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Body */}\n <div style={{ padding: 20 }}>\n <p style={{\n fontSize: 13, color: \"#71717a\", textAlign: \"center\",\n marginBottom: 16, lineHeight: 1.5,\n }}>\n 서비스 시크릿 코드를 입력해주세요.<br />\n 코드는 임패커스 OS에서 확인할 수 있습니다.\n </p>\n\n {error && (\n <div style={{\n background: \"#fef2f2\", border: \"1px solid #fecaca\",\n color: \"#dc2626\", padding: \"8px 12px\", borderRadius: 8,\n fontSize: 13, marginBottom: 12,\n }}>\n {error}\n </div>\n )}\n\n <form onSubmit={handleSubmit}>\n <input\n type=\"text\"\n maxLength={6}\n placeholder=\"A3F9K2\"\n value={code}\n onChange={(e) => setCode(e.target.value.toUpperCase())}\n autoFocus\n autoComplete=\"off\"\n style={{\n width: \"100%\", padding: \"12px 16px\", border: \"1px solid #d4d4d8\",\n borderRadius: 8, fontSize: 24, fontWeight: 600,\n textAlign: \"center\", letterSpacing: 8, textTransform: \"uppercase\",\n outline: \"none\", boxSizing: \"border-box\", fontFamily: \"inherit\",\n color: \"#18181b\",\n }}\n />\n <button\n type=\"submit\"\n disabled={code.trim().length < 6 || loading}\n style={{\n width: \"100%\", marginTop: 16, padding: \"10px 16px\",\n border: \"none\", borderRadius: 8, fontSize: 14, fontWeight: 500,\n cursor: code.trim().length < 6 || loading ? \"not-allowed\" : \"pointer\",\n background: code.trim().length < 6 || loading ? \"#a1a1aa\" : \"#18181b\",\n color: \"white\", fontFamily: \"inherit\",\n }}\n >\n {loading ? \"인증 중...\" : \"인증하기\"}\n </button>\n </form>\n </div>\n </div>\n </div>,\n document.body,\n );\n}\n"],"mappings":"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","names":["useEffect","useState","useCallback","useState","useCallback","useEffect","useRef","useMemo","createPortal","jsx","jsxs","AnnotationPopupCSS","result","getFiberFromElement","cache","css","classNames","styles_module_default","jsx","jsxs","styles_module_default","useState","useRef","useEffect","useCallback","css","classNames","styles_module_default","jsx","jsxs","useState","useRef","useEffect","styles_module_default","useCallback","useState","useRef","useCallback","useEffect","css","classNames","styles_module_default","Fragment","jsx","jsxs","useState","useRef","useCallback","useEffect","styles_module_default","useState","useCallback","useEffect","useRef","css","classNames","styles_module_default","Fragment","jsx","jsxs","useEffect","styles_module_default","formatFileSize","getFileIcon","formatTime","getInitials","useState","useRef","useCallback","useEffect","jsxs","jsx","styles_module_default","formatTime","getFileIcon","formatFileSize","Fragment","useCallback","createPortal","css","classNames","styles_module_default","jsx","jsxs","useCallback","createPortal","styles_module_default","css","classNames","styles_module_default","Fragment","jsx","jsxs","useState","useRef","useCallback","useEffect","useMemo","createPortal","styles_module_default","task","useState","useCallback","createPortal","jsx","jsxs","useState","useCallback","createPortal","Fragment","jsx","jsxs","useState","useEffect","useCallback"]}